Commit 4918451f authored by Jan-Benedict Glaw's avatar Jan-Benedict Glaw Committed by Linus Torvalds

[PATCH] lkkbd: Current version

This updates the lkkbd driver to it's current version.

It also incorporates two patches suggested on LKML (fixing
some leading whitespace and an unneccessary check).
parent 35eea7a3
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
* and VAXstations, but can also be used on any standard RS232 with an * and VAXstations, but can also be used on any standard RS232 with an
* adaptor). * adaptor).
* *
* DISCLAUNER: This works for _me_. If you break anything by using the * DISCLAIMER: This works for _me_. If you break anything by using the
* information given below, I will _not_ be lieable! * information given below, I will _not_ be liable!
* *
* RJ11 pinout: To DB9: Or DB25: * RJ11 pinout: To DB9: Or DB25:
* 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
...@@ -34,23 +34,32 @@ ...@@ -34,23 +34,32 @@
* Additionally, you have to get +12V from somewhere. * Additionally, you have to get +12V from somewhere.
* Most easily, you'll get that from a floppy or HDD power connector. * Most easily, you'll get that from a floppy or HDD power connector.
* It's the yellow cable there (black is ground and red is +5V). * It's the yellow cable there (black is ground and red is +5V).
*
* The keyboard and all the commands it understands are documented in
* "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This
* document is LK201 specific, but LK401 is mostly compatible. It comes
* up in LK201 mode and doesn't report any of the additional keys it
* has. These need to be switched on with the LK_CMD_ENABLE_LK401
* command. You'll find this document (scanned .pdf file) on MANX,
* a search engine specific to DEC documentation. Try
* http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1
*/ */
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Should you need to contact me, the author, you can do so either by * Should you need to contact me, the author, you can do so either by
* email or by paper mail: * email or by paper mail:
* Jan-Benedict Glaw, Lilienstrae 16, 33790 Hrste (near Halle/Westf.), * Jan-Benedict Glaw, Lilienstrae 16, 33790 Hrste (near Halle/Westf.),
...@@ -67,8 +76,7 @@ ...@@ -67,8 +76,7 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_AUTHOR ("Jan-Benedict Glaw <jblaw@lug-owl.de>");
MODULE_DESCRIPTION ("LK keyboard driver"); MODULE_DESCRIPTION ("LK keyboard driver");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
...@@ -92,6 +100,11 @@ static int ctrlclick_volume = 100; /* % */ ...@@ -92,6 +100,11 @@ static int ctrlclick_volume = 100; /* % */
module_param (ctrlclick_volume, int, 0); module_param (ctrlclick_volume, int, 0);
MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
static int lk201_compose_is_alt = 0;
module_param (lk201_compose_is_alt, int, 0);
MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
"will act as an Alt key");
#undef LKKBD_DEBUG #undef LKKBD_DEBUG
...@@ -126,8 +139,11 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); ...@@ -126,8 +139,11 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
#define LK_CMD_SET_DEFAULTS 0xd3 #define LK_CMD_SET_DEFAULTS 0xd3
#define LK_CMD_POWERCYCLE_RESET 0xfd #define LK_CMD_POWERCYCLE_RESET 0xfd
#define LK_CMD_ENABLE_LK401 0xe9 #define LK_CMD_ENABLE_LK401 0xe9
#define LK_CMD_REQUEST_ID 0xab
/* Misc responses from keyboard */ /* Misc responses from keyboard */
#define LK_STUCK_KEY 0x3d
#define LK_SELFTEST_FAILED 0x3e
#define LK_ALL_KEYS_UP 0xb3 #define LK_ALL_KEYS_UP 0xb3
#define LK_METRONOME 0xb4 #define LK_METRONOME 0xb4
#define LK_OUTPUT_ERROR 0xb5 #define LK_OUTPUT_ERROR 0xb5
...@@ -139,6 +155,7 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); ...@@ -139,6 +155,7 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
#define LK_RESPONSE_RESERVED 0xbb #define LK_RESPONSE_RESERVED 0xbb
#define LK_NUM_KEYCODES 256 #define LK_NUM_KEYCODES 256
#define LK_NUM_IGNORE_BYTES 6
typedef u_int16_t lk_keycode_t; typedef u_int16_t lk_keycode_t;
...@@ -267,6 +284,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { ...@@ -267,6 +284,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
struct lkkbd { struct lkkbd {
lk_keycode_t keycode[LK_NUM_KEYCODES]; lk_keycode_t keycode[LK_NUM_KEYCODES];
int ignore_bytes; int ignore_bytes;
unsigned char id[LK_NUM_IGNORE_BYTES];
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct work_struct tq; struct work_struct tq;
...@@ -313,6 +331,82 @@ volume_to_hw (int volume_percent) ...@@ -313,6 +331,82 @@ volume_to_hw (int volume_percent)
return ret; return ret;
} }
static void
lkkbd_detection_done (struct lkkbd *lk)
{
int i;
/*
* Reset setting for Compose key. Let Compose be KEY_COMPOSE.
*/
lk->keycode[0xb1] = KEY_COMPOSE;
/*
* Print keyboard name and modify Compose=Alt on user's request.
*/
switch (lk->id[4]) {
case 1:
sprintf (lk->name, "DEC LK201 keyboard");
if (lk201_compose_is_alt)
lk->keycode[0xb1] = KEY_LEFTALT;
break;
case 2:
sprintf (lk->name, "DEC LK401 keyboard");
break;
default:
sprintf (lk->name, "Unknown DEC keyboard");
printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
"please report to Jan-Benedict Glaw "
"<jbglaw@lug-owl.de>\n", lk->phys);
printk (KERN_ERR "lkkbd: keyboard ID'ed as:");
for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
printk (" 0x%02x", lk->id[i]);
printk ("\n");
break;
}
printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
lk->phys, lk->name);
/*
* Report errors during keyboard boot-up.
*/
switch (lk->id[2]) {
case 0x00:
/* All okay */
break;
case LK_STUCK_KEY:
printk (KERN_ERR "lkkbd: Stuck key on keyboard at "
"%s\n", lk->phys);
break;
case LK_SELFTEST_FAILED:
printk (KERN_ERR "lkkbd: Selftest failed on keyboard "
"at %s, keyboard may not work "
"properly\n", lk->phys);
break;
default:
printk (KERN_ERR "lkkbd: Unknown error %02x on "
"keyboard at %s\n", lk->id[2],
lk->phys);
break;
}
/*
* Try to hint user if there's a stuck key.
*/
if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0)
printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode "
"is 0x%04x\n", lk->id[3],
lk->keycode[lk->id[3]]);
return;
}
/* /*
* lkkbd_interrupt() is called by the low level driver when a character * lkkbd_interrupt() is called by the low level driver when a character
* is received. * is received.
...@@ -329,7 +423,11 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, ...@@ -329,7 +423,11 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
if (lk->ignore_bytes > 0) { if (lk->ignore_bytes > 0) {
DBG (KERN_INFO "Ignoring a byte on %s\n", DBG (KERN_INFO "Ignoring a byte on %s\n",
lk->name); lk->name);
lk->ignore_bytes--; lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
if (lk->ignore_bytes == 0)
lkkbd_detection_done (lk);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -375,7 +473,8 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, ...@@ -375,7 +473,8 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
break; break;
case 0x01: case 0x01:
DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n");
lk->ignore_bytes = 3; lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
schedule_work (&lk->tq); schedule_work (&lk->tq);
break; break;
...@@ -389,7 +488,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, ...@@ -389,7 +488,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
input_sync (&lk->dev); input_sync (&lk->dev);
} else } else
printk (KERN_WARNING "%s: Unknown key with " printk (KERN_WARNING "%s: Unknown key with "
"scancode %02x on %s.\n", "scancode 0x%02x on %s.\n",
__FILE__, data, lk->name); __FILE__, data, lk->name);
} }
...@@ -467,6 +566,9 @@ lkkbd_reinit (void *data) ...@@ -467,6 +566,9 @@ lkkbd_reinit (void *data)
unsigned char leds_on = 0; unsigned char leds_on = 0;
unsigned char leds_off = 0; unsigned char leds_off = 0;
/* Ask for ID */
lk->serio->write (lk->serio, LK_CMD_REQUEST_ID);
/* Reset parameters */ /* Reset parameters */
lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS);
...@@ -527,9 +629,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) ...@@ -527,9 +629,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev)
if ((serio->type & SERIO_TYPE) != SERIO_RS232) if ((serio->type & SERIO_TYPE) != SERIO_RS232)
return; return;
if (!(serio->type & SERIO_PROTO)) if ((serio->type & SERIO_PROTO) != SERIO_LKKBD)
return;
if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD)
return; return;
if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL)))
...@@ -537,10 +637,16 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) ...@@ -537,10 +637,16 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev)
memset (lk, 0, sizeof (struct lkkbd)); memset (lk, 0, sizeof (struct lkkbd));
init_input_dev (&lk->dev); init_input_dev (&lk->dev);
set_bit (EV_KEY, lk->dev.evbit);
lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP); set_bit (EV_LED, lk->dev.evbit);
lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP); set_bit (EV_SND, lk->dev.evbit);
lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL); set_bit (EV_REP, lk->dev.evbit);
set_bit (LED_CAPSL, lk->dev.ledbit);
set_bit (LED_SLEEP, lk->dev.ledbit);
set_bit (LED_COMPOSE, lk->dev.ledbit);
set_bit (LED_SCROLLL, lk->dev.ledbit);
set_bit (SND_BELL, lk->dev.sndbit);
set_bit (SND_CLICK, lk->dev.sndbit);
lk->serio = serio; lk->serio = serio;
...@@ -564,14 +670,13 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) ...@@ -564,14 +670,13 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev)
return; return;
} }
sprintf (lk->name, "LK keyboard"); sprintf (lk->name, "DEC LK keyboard");
sprintf (lk->phys, "%s/input0", serio->phys);
memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES);
for (i = 0; i < LK_NUM_KEYCODES; i++) for (i = 0; i < LK_NUM_KEYCODES; i++)
set_bit (lk->keycode[i], lk->dev.keybit); set_bit (lk->keycode[i], lk->dev.keybit);
sprintf (lk->name, "%s/input0", serio->phys);
lk->dev.name = lk->name; lk->dev.name = lk->name;
lk->dev.phys = lk->phys; lk->dev.phys = lk->phys;
lk->dev.id.bustype = BUS_RS232; lk->dev.id.bustype = BUS_RS232;
...@@ -599,9 +704,9 @@ lkkbd_disconnect (struct serio *serio) ...@@ -599,9 +704,9 @@ lkkbd_disconnect (struct serio *serio)
} }
static struct serio_dev lkkbd_dev = { static struct serio_dev lkkbd_dev = {
.interrupt = lkkbd_interrupt,
.connect = lkkbd_connect, .connect = lkkbd_connect,
.disconnect = lkkbd_disconnect, .disconnect = lkkbd_disconnect,
.interrupt = lkkbd_interrupt,
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment