<?xml version="1.0"?>
<!DOCTYPE webpage
 PUBLIC "-//NetBSD//DTD Website-based NetBSD Extension//EN"
        "http://www.NetBSD.org/XML/htdocs/lang/share/xml/website-netbsd.dtd">

<webpage id="docs-Hardware-Machines-DEC-lk201">
<config param="desc" value="LK201 Keyboard Interface"/>
<config param="cvstag" value="$NetBSD: lk201.xml,v 1.1 2007/06/09 11:33:15 dsieger Exp $"/>
<config param="rcsdate" value="$Date: 2007/06/09 11:33:15 $"/>
<head>

<!-- Copyright (c) 2002-2005
     The NetBSD Foundation, Inc.  ALL RIGHTS RESERVED. -->

<title>LK201 Interface</title>
</head>

<sect1 role="toc">
<title>LK201 Keyboard Interface</title>

<sect2>
<title>Overview</title>

<sect3 id="introduction">
<title>Introduction and Purpose</title>

<para>This page is intended to detail the DEC LK201 keyboard interface.
If anything on this page is unclear or incorrect, please contact <ulink
url="mailto:dmcmahill@NetBSD.org">me</ulink> and I will do my best to
clarify and/or correct the document.</para>

</sect3>
</sect2>

<sect2>
<title>Electrical Interface</title>

<sect3 id="electrical">
<title>Electrical Specifications</title>

<para>This section describes the electrical interface between the LK201
Keyboard and the computer.  Some of these specifications came from
publication EK-366AA-OG-002 "DECstation 5000, Model 200 Hardware 
Operator's Guide, April 1990".  The rest of the items in this section
were experimentally determined (like the pin outs).</para>

<para>The LK201 is powered from a 12 Volt supply generated by the
computer. The keyboard and the computer communicate via a fairly
standard serial interface.  The key specifications are listed
here:</para>

<itemizedlist>
<listitem>Bidirectional asynchronous serial communication: 4800 baud, 8N1.</listitem>
<listitem>Serial interface levels:  EIA RS 423 (ie signals swing +/- 5 Volts).</listitem>
<listitem>Power input:  4.2 Watts Max.  350 mA @ 11.8 Volts +/- 6%.  (NOTE:  This is the
    value quoted in the manual, but I measured 30 mA on a working LK201.
    Perhaps the 350 mA is the maximum the computer can supply?)</listitem>
</itemizedlist>

</sect3>

<sect3 id="pinout">
<title>Connector Pinout</title>

<para>The pinout of the connector on the LK201 and on the computer in jpeg and
postscript form are linked below.</para>

<itemizedlist>
<listitem><ulink url="LK201_connector.jpg">LK201 Connector Diagram (jpeg 29k)</ulink></listitem>
<listitem><ulink url="LK201_connector.ps">LK201 Connector Diagram (postscript 12k)</ulink></listitem>
</itemizedlist>

<programlisting>

    |----- data -&lt; -------------------------------------------|
    |    |-------- &gt;- Power -----------------------------|    |
    |    |    |------------- GND -------------------|    |    |
    |    |    |    |------------- &lt;- data -----|    |    |    |
   -------------------                        -------------------
  | "    "    "    "  |                      | "    "    "    "  |
  | L    V    G    D  |                      | D    G    V    L  |
  | K    +    N    E  |                      | E    N    +    K  |
  | -&gt;        D    C  |                      | C    D         -&gt; |
  | D             -&gt;  |                      | -&gt;             D  |
  | E              L  |                      | L              E  |
  | C              K  |                      | K              C  |
   --               --                        --               --
     |             |                            |             |
      --         --                              --         --
        |       |                                  |       |
         -------                                    -------

     Looking into the                       Looking into the DECstation
     LK201 Connector                                 Connector
   (Socket on keyboard)                        (Socket on DECstation)

</programlisting>

</sect3>
</sect2>

<sect2>
<title>Communications from the Keyboard to the Computer</title>

<sect3 id="lk2dec">
<title>Overview</title>

<para>The next two sections will refer to the following table and/or
diagram:</para>

<itemizedlist>
<listitem><ulink url="lk201_keycodes.html">LK201 Keycode and Keyboard Division Table (html)</ulink></listitem>
<listitem><ulink url="LK201_large_keycodes.jpg">LK201 Keycode and Keyboard Division Chart (in color) (jpg 67k)</ulink></listitem>
<listitem><ulink url="LK201_keycode.ps">LK201 Keycode and Keyboard Division Chart (postscript 136k)</ulink></listitem>
</itemizedlist>

<para>(I had a hard time getting a jpeg version which was legible so
please bear with me on the postscript format for now.)</para>

</sect3>

<sect3 id="kbdmodes">
<title>Keyboard Modes</title>

<para>The LK201 keyboard has its keys divided into 14 distinct groups. 
These groups are indicated on the  <ulink url="#lk2dec">LK201 Keycode
and Keyboard Division Chart/Table</ulink>. Each of the groups is
separately programmed for its behaviour with respect to  keycode
generation.  There are three operating modes to select from.</para>

<itemizedlist>
<listitem><code>LK_DOWN</code> mode:  In this mode, the code indicated on the keycode chart
    is transmitted by the keyboard when the corresponding key is pressed.  If held
    down, the key does <emphasis>not</emphasis> repeat and no further codes are generated.</listitem>

<listitem><code>LK_AUTODOWN</code> mode:  In this mode, the code indicated on the keycode chart
    is transmitted by the keyboard when the corresponding key is pressed.  If held down
    the LK201 transmits the <code>LK_REPEAT</code> value, <code>0xB4</code>,repeatedly
    at the key repeat rate.  It is up to the computer to know what key is being
    repeated.</listitem>

<listitem><code>LK_UPDOWN</code> mode:  In this mode, the code indicated on the keycode chart
    is transmitted by the keyboard when the corresponding key is pressed.  In addition,
    a code is generated when the key is released.  The release code is determined by the
    following rule.  If no other keys in <code>LK_UPDOWN</code> mode are pressed in addition
    to the one being released, the <code>LK_ALLUP</code>, <code>0xB3</code> is generated.
    If there is another key currently pressed which has been programmed for 
    <code>LK_UPDOWN</code> mode, the code indicated on the keycode chart is used for
    the key release code.   If held, the key does <emphasis>not</emphasis> repeat.  
    <code>LK_UPDOWN</code> mode is used for keys such as <emphasis>SHIFT</emphasis>, and
    <emphasis>CONTROL</emphasis>.  The computer recognizes that the <emphasis>SHIFT</emphasis> (or other 
    "modifying" key) has been pressed and not released.  In this manner, the computer
    knows to use the shifted character set.  Once released, the computer sees the
    release code and switches back to the normal character set.</listitem>
</itemizedlist>

</sect3>
</sect2>

<sect2>
<title>Communications from the Computer to the Keyboard</title>

<sect3 id="dec2lk">
<title>Overview</title>

<para>The LK201 accepts a handful of commands from the computer.  These
commands include programming the operational mode of each of the 14
groups of keys, control of the 4 LED's, control of the bell, and control
of keyclicks.</para>

<para>Commands are send to the keyboard as either single byte commands
or as a command byte followed by one data byte.  Once again, the
communication is 4800 baud serial.</para>

</sect3>

<sect3 id="led_control">
<title>LED Control</title>

<para>The 4 LED's on the LK201 are controlled by the computer.
Either the command <code>LK_LED_ENABLE</code> or
<code>LK_LED_DISABLE</code> is sent followed by 1 byte
which indicates which of the 4 LED's are affected.  The
lower 4 bits of the data byte correspond to the 4 LED's.
For example, to turn on the caps lock LED, the following
two bytes would be sent:</para>

<code>
LK_LED_ENABLE LED_LOCK
</code>

<para>A sample code fragment which defines the LED control codes
is shown here.</para>

<programlisting>
/* requires LED number data */ 
#define LK_LED_ENABLE   0x13            /* light LED        */ 
#define LK_LED_DISABLE  0x11            /* turn off LED     */ 

#define LED_WAIT        0x81            /* Wait LED         */ 
#define LED_COMP        0x82            /* Compose LED      */ 
#define LED_LOCK        0x84            /* Lock LED         */ 
#define LED_HOLD        0x88            /* Hold Screen LED  */ 
#define LED_ALL         0x8F            /* All LED's        */
</programlisting>

</sect3>

<sect3 id="click_control">
<title>Key Click Control</title>

<para>The LK201 accepts several commands relating to key clicks.</para>

<programlisting>
/* Requires volume data byte */
#define LK_CL_ENABLE    0x1B   /* keyclick enable.  Requires volume   */
                               /* byte.  This does not affect the     */
			       /* SHIFT key.  The CTRL key requires   */
                               /* LK_CL_ENABLE and LK_CCL_ENABLE to   */
			       /* have been sent before it clicks.    */
			       /* All other keys are only controlled  */    
			       /* by LK_CL_ENABLE.                    */
     
#define LK_CCL_ENABLE   0xBB   /* Enable keyclicks for the CTRL key.  */
                               /* The CTRL keyclick volume is set to  */
			       /* be the same as the rest of the keys */
			       /* LK_CCL_ENABLE sets a flag in the    */
			       /* keyboard with is logically AND'ed   */
			       /* with the LK_CL_ENABLE flag to enable*/
			       /* CTRL key keyclicks.                 */

#define LK_CL_DISABLE   0x99   /* keyclick disable                    */
#define LK_CCL_DISABLE  0xB9   /* CTRL key keyclick disable           */

#define LK_SOUND_CLICK  0x9F   /* causes the LK201 to sound a keyclick*/

/* max volume is 0, lowest is 0x7 */
#define LK_PARAM_VOLUME(v)              (0x80|((v)&amp;0x7))
</programlisting>

<para>For example, to enable keyclicks at full volume, the following data would
be sent to the keyboard:</para>

<code>
LK_CL_ENABLE LK_PARAM_VOLUME(0x00)
</code>

</sect3>

<sect3 id="bell_control">
<title> Bell Control</title>

<para>The keyboard bell control commands work in the same manner as the keyclick
commands.  The keyboard never generates a bell sound on its own.  A bell
sound is always at the command of the computer.</para>

<programlisting>
/* requires bell volume data */ 
#define LK_BELL_ENABLE  0x23   /* enable the keyboard bell.  Requires */
                               /* volume data byte.                   */

#define LK_BELL_DISABLE 0xA1   /* disable the keyboard bell.          */

#define LK_RING_BELL    0xA7   /* ring the keyboard bell              */ 

/* max volume is 0, lowest is 0x7 */ 
#define LK_PARAM_VOLUME(v)              (0x80|((v)&amp;0x7))
</programlisting>

</sect3>

<sect3 id="key_control">
<title>Key Control</title>

<para>The LK201 provides 3 different operating modes for the keys.  In
addition, the keyboard is divided into 14 different groups which
are shown in the
<ulink url="LK201_keycode.ps">LK201 Keycode and Keyboard Division Chart (postscript 136k)</ulink>
and also in the
<ulink url="lk201_keycodes.html">LK201 Keycode and Keyboard Division Table (html)</ulink>.
The three operating modes are discussed in 
<ulink url="#lk2dec">2.  Communications from the Keyboard to the Computer</ulink>.</para>

<para>Programming of the keyboard mode is accomplished via 1 byte per group of keys
on the keyboard.  The macro <code>LK_CMD_MODE()</code> is used to form the
command.  For example, to set division 2 (the numeric keypad) to LK_AUTODOWN mode,
we would transmit:</para>

<code>LK_CMD_MODE(LK_AUTODOWN,2)</code>

<para>Upon successful receipt of the command, the LK201 responds with 
<code>LK_MODECHG_ACK</code>.  The macros and constants used for key mode
programming are listed below.</para>

<para>The details of the meaning of each bit in the mode command are
listed below.</para>

<programlisting>
bit 7:      PARAM bit.
            1 = no parameter to follow
            0 = parameter will follow

bits 3-6:   keyboard division

bits 1-2:   mode  (00 = down, 01=autodown, 11=updown)

bit 0:      "type"  don't know what that means, but should be set to 0.
</programlisting>

<para>In the examples below, the PARAM bit is set to 1 meaning that no
parameter will follow.</para>

<programlisting>
#define LK_UPDOWN           0x86 
#define LK_AUTODOWN         0x82 
#define LK_DOWN             0x80 

#define LK_CMD_MODE(m,div)  ((m)|((div)&lt;&lt;3)) 

#define LK_MODECHG_ACK      0xBA    /* sent by the keyboard to acknowledge a  */
                                    /* successful mode change.                */


#define LK_PFX_KEYDOWN      0xB9    /* indicates that the next byte is a key- */
                                    /* code for a key already down in a       */
                                    /* division that has been changed to      */
                                    /* LK_UPDOWN.  I think this means that if */
                                    /* for example, the 'a' key is in LK_DOWN */
                                    /* mode and the key is being held down and*/
                                    /* division 1 is switched to LK_UPDOWN    */
                                    /* mode, the keyboard will produce the    */
                                    /* byte LK_PFX_KEYDOWN followed by 0xC2   */
                                    /* (KEY_A).                               */

#define LK_CMD_RPT_TO_DOWN  0xD9    /* This command causes all divisions which */
                                    /* are programmed for LK_AUTODOWN mode to  */
                                    /* be switched to LK_DOWN mode.            */


#define LK_CMD_ENB_RPT      0xE3    /* enables auto repeat on the keys         */
                                    /* which are in LK_AUTODOWN mode           */

#define LK_CMD_DIS_RPT      0xE1    /* disables auto repeat on all keys, but   */
                                    /* does not change the mode that the       */
                                    /* divisions are programmed to.            */

#define LK_CMD_TMP_NORPT    0xD1    /* temporary auto repeat disable.  This    */
                                    /* command disables auto repeat for the key*/
                                    /* which is currently pressed down.  Auto  */
                                    /* repeat is re-enabled when another key is*/
                                    /* pressed.                                */


#define LK_INPUT_ERROR      0xB6    /* sent by the keyboard if it receives an  */
                                    /* invalid command.                        */
</programlisting>

<para>The LK201 contains 4 autorepeat registers.  Each autorepeat
register controls how quickly keys repeat and if repeating is enabled. 
The 4 autorepeat registers are independent.  Each keyboard division can
be associated with 1 of the 4 registers.  To associate a keyboard
division with a particular autorepeat register, use the same command as
setting the key division mode except set the PARAM bit to 0 and send a
second byte which controls which autorepeat register is selected.  The
format of the second byte is:</para>

<programlisting>
bit7:      1

bits 2-6:  0

bits 0-1:  number of the autorepeat register 00,01,10,11
</programlisting>

<para>For example, to set division 2 (the numeric keypad) to LK_AUTODOWN
mode, and associate it with autorepeat register number 2, we would
transmit: <code>LK_CMD_MODE_AR(LK_AUTODOWN,2) 0x82</code> where the
macro <code>LK_CMD_MODE_AR</code> is defined below.</para>

<programlisting>
#define LK_CMD_MODE_AR(m,div,arreg)  (0x7F &amp; ((m)|((div)&lt;&lt;3)) )
</programlisting>

</sect3>

<sect3 id="ar_control">
<title>Autorepeat Control</title>

<para>The autorepeat rate is programmed by a 3 byte command.</para>

<programlisting>
first byte:
bit7:      0  (means more bytes to come after this one)

bits 3-6:  1 (means we're calling the rate change command)

bits 1-2:  number of autorepeat register (00,01,10,11)

bit 0:     "type" set to 0

second byte:

bit7:      0  (more bytes to come after this one)

bits0-6:   time out value (how long to wait before beginning to autorepeat)
           this is in 5 ms increments.  allowed range is 5 ms-630 ms.  

note:  don't send 635ms, 0111 1111 is a reserved for internal use code.
note:  don't send 0ms,   0000 0000 is illegal.

third byte:

bit7:      1 (no more bytes after this one)

bits0-6:   autorepeat rate in number of generated key presses/second.
           lowest rate is 12 Hz.  

note:  125Hz  (1111 1101) must not be sent (its identical to the powerup
       command)
</programlisting>

</sect3>

<sect3 id="power_up">
<title>Power-Up and Self Test</title>

<para>This section details the self test features and the power up
sequence of the keyboard.  Upon power-up, the keyboard performs a self
test in 70 ms or less.  The results are sent to the computer.  The
power-up self test results consist of 4 bytes.</para>

<programlisting>
Byte 1:    Keyboard ID stored in the keyboard firmware.  On
           my LK201, this is 0x01.

Byte 2:    Keyboard ID read from hardware jumpers.  The documentation
           I have doesn't seem to quite match my keyboard (the docs say
           that the keyboard uses an 8051 microcontroller while mine
           uses a 68HC05C4).  Anyway, the docs and my keyboard both say
           the result is 0x00.

Byte 3:    Error code.  This byte indicates the result of the self test.
           Possible values are:

                               0x00    No Error
#define    LK_KDOWN_ERROR      0x3D    /* Key down on powerup error     */
#define    LK_POWER_ERROR      0x3E    /* Keyboard failure on pwrup tst */

Byte 4:    Keycode.  This byte contains the keycode of which key (if any)
           was pressed down on powerup.  If no keys were pressed, this
           byte is 0x00.
</programlisting>

<para>If the keyboard passes all power up tests with no error, the resulting
sequence sent to the computer is:</para>

<programlisting>0x01 0x00 0x00 0x00 </programlisting>

<para>If the keyboard finds a key down on the first scan, it continues
to look for an all up condition.  When all keys are released, the
keyboard transmits the correct 4 byte sequence (0x01 0x00 0x00
0x00).</para>

<para>Additional test commands are listed below.</para>

<programlisting>
#define LK_CMD_POWER_UP     0xFD    /* This command initiates the keyboard    */
                                    /* power up sequence.                     */ 

#define LK_CMD_REQ_ID       0xAB    /* This command requests the 2 byte       */
                                    /* keyboard ID.  The keyboard responds    */
                                    /* with the same Byte1 and Byte2 as in    */
                                    /* the power up self test.                */

#define LK_CMD_SET_DEFAULTS 0xD3    /* Restores the keyboard to its default   */
                                    /* state.  This command sets the:         */
                                    /* division mode settings,                */
                                    /* auto-repeat interval and timeout rate, */
                                    /* auto-repeat buffer selections,         */
                                    /* audio volume,                          */
                                    /* ctrl key keyclick setting,             */
                                    /* to their power up defaults.            */

#define LK_CMD_TEST_MODE    0xCB    /* causes the keyboard to enter the       */
                                    /* factory test mode.  This command       */
                                    /* should not be used.  If received, the  */
                                    /* keyboard responds with LK_TESTMODE_ACK */
                                    /* By sending a 0x80, the keyboard will   */
                                    /* leave factory test mode and jump to the*/
                                    /* power up sequence.                     */

#define LK_TESTMODE_ACK     0xB8    /* sent by the keyboard in response to    */
                                    /* the LK_CMD_TEST_MODE command.          */
</programlisting>

<para id="mystery">The following are some additional keyboard
control commands which didn't seem to fit anywhere else.</para>

<programlisting>
#define LK_CMD_INHIBIT      0xB9    /* This command suspends transmission     */
                                    /* the keyboard to the computer.  The     */
                                    /* keyboard responds with LK_KBDLOCK_ACK  */
                                    /* and turns on the LOCK LED.             */

#define LK_KDBLOCK_ACK      0xB7    /* send by the keyboard in response to    */
                                    /* the LK_CMD_INHIBIT command.            */

#define LK_CMD_RESUME       0x8B    /* Resumes normal keyboard operation after*/
                                    /* the LK_CMD_INHIBIT command.            */

#define LK_OUTPUT_ERROR     0xB5    /* If any keystrokes were lost while the  */
                                    /* keyboard was locked (LK_CMD_INHIBIT),  */
                                    /* then LK_OUTPUT_ERROR is generated by   */
                                    /* the keyboard when LK_CMD_RESUME is     */
                                    /* received.                              */
</programlisting>

</sect3>
</sect2>

<sect2>
<title>References</title>

<sect3 id="references">
<title> Sources of this Information</title>

<para>Much of this information came from NetBSD sources from mid-March,
1998.  In particular, the files <code>lk201.h</code> and
<code>lk201.c</code> from <code>src/sys/arch/pmax/dev/</code> is the
source of most of the code fragments on this page.  Additional hints
came from the X11R5 Xserver code for <ulink
url="http://www.openbsd.org">OpenBSD</ulink> (I think the OpenBSD and
NetBSD Xserver's are largely the same, at least with respect to the
keyboard stuff).  I also got some good hints and a few 
<code>#define</code>'s from an unknown version of Mach from Carnegie
Mellon. The files in the Mach source I looked at were also called
<code>lk201.h</code> and <code>lk201.c</code>, but were not the same as
the NetBSD files of the same names.</para>

<para>In addition to poking around the various pieces of code mentioned
above, I  hooked an LK201 up to the serial port on a NetBSD/mac68k
machine and  spent some time experimenting with the keyboard and the
various control sequences.  This is how I convinced myself of what the
14 keyboard divisions are.  This test setup was invaluable for seeing
exactly what the keyboard produces and how it reacts to known
commands.</para>

<para>The text version of the keycodes and keyboard divisions was sent
to me by <ulink url="mailto:djv@bedford.net">Dave</ulink>. My brother,
<ulink url="http://www.cs.cmu.edu/~jmcm/">Jeff</ulink>, was also a big
help in answering many <code>C</code> questions and pointing me towards
the Mach code.</para>

<para>In addition, I got a copy rather late in the writing of this page
of what could be considered the "real" document for all this stuff.
"VCB02 Video Subsystem Technical Manual" DEC Educational Services,
AZ-GLGAB-MN, February 1986 The appendix of this document cleaned out
most of the remaining mysteries.</para>

</sect3>
</sect2>

<sect2>
<title>DISCLAIMER</title>

<sect3 id="nosmoke">
<title>No Fault</title>

<para>Any software and documentation here is provided "as is", no
warranty, use at your own risk.  Please do not hook up your LK201 and/or
computer backwards and blame me!</para>

</sect3>
</sect2>

</sect1>
</webpage>

