#include <linux/serio.h>
#include <linux/workqueue.h>
#include <linux/libps2.h>
+#include <linux/mutex.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
module_param_named(softraw, atkbd_softraw, bool, 0);
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
-static int atkbd_scroll;
+static int atkbd_scroll = 0;
module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
* are loadable via an userland utility.
*/
-#if defined(__hppa__)
-#include "hpps2atkbd.h"
-#else
-
static unsigned char atkbd_set2_keycode[512] = {
+#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
+
+/* XXX: need a more general approach */
+
+#include "hpps2atkbd.h" /* include the keyboard scancodes */
+
+#else
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
0, 0, 0, 65, 99,
-};
-
#endif
+};
static unsigned char atkbd_set3_keycode[512] = {
#define ATKBD_CMD_EX_SETLEDS 0x20eb
#define ATKBD_CMD_OK_GETID 0x02e8
-
#define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe
#define ATKBD_RET_BAT 0xaa
#define ATKBD_SCR_4 252
#define ATKBD_SCR_8 251
#define ATKBD_SCR_CLICK 250
-
-#define ATKBD_SPECIAL 250
-
-static unsigned char atkbd_scroll_keys[5][2] = {
- { ATKBD_SCR_1, 0x45 },
- { ATKBD_SCR_2, 0x29 },
- { ATKBD_SCR_4, 0x36 },
- { ATKBD_SCR_8, 0x27 },
- { ATKBD_SCR_CLICK, 0x60 },
+#define ATKBD_SCR_LEFT 249
+#define ATKBD_SCR_RIGHT 248
+
+#define ATKBD_SPECIAL 248
+
+#define ATKBD_LED_EVENT_BIT 0
+#define ATKBD_REP_EVENT_BIT 1
+
+static struct {
+ unsigned char keycode;
+ unsigned char set2;
+} atkbd_scroll_keys[] = {
+ { ATKBD_SCR_1, 0xc5 },
+ { ATKBD_SCR_2, 0x9d },
+ { ATKBD_SCR_4, 0xa4 },
+ { ATKBD_SCR_8, 0x9b },
+ { ATKBD_SCR_CLICK, 0xe0 },
+ { ATKBD_SCR_LEFT, 0xcb },
+ { ATKBD_SCR_RIGHT, 0xd2 },
};
/*
struct atkbd {
- struct ps2dev ps2dev;
+ struct ps2dev ps2dev;
+ struct input_dev *dev;
/* Written only during init */
char name[64];
char phys[32];
- struct input_dev dev;
unsigned short id;
unsigned char keycode[512];
unsigned char resend;
unsigned char release;
unsigned char bat_xl;
+ unsigned char err_xl;
unsigned int last;
unsigned long time;
+
+ struct work_struct event_work;
+ struct mutex event_mutex;
+ unsigned long event_mask;
};
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
#define ATKBD_DEFINE_ATTR(_name) \
static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
-static ssize_t atkbd_do_show_##_name(struct device *d, char *b) \
+static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \
{ \
return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
} \
-static ssize_t atkbd_do_set_##_name(struct device *d, const char *b, size_t s) \
+static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \
{ \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
-static struct device_attribute atkbd_attr_##_name = \
+static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
- struct atkbd *atkbd = serio->private;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
unsigned int code = data;
- int scroll = 0, click = -1;
+ int scroll = 0, hscroll = 0, click = -1;
int value;
#ifdef ATKBD_DEBUG
if (!atkbd->enabled)
goto out;
- input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
+ input_event(atkbd->dev, EV_MSC, MSC_RAW, code);
if (atkbd->translated) {
if (atkbd->emul ||
- !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
- code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
- code == ATKBD_RET_ERR ||
- (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
+ (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 &&
+ code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA &&
+ (code != ATKBD_RET_ERR || atkbd->err_xl) &&
+ (code != ATKBD_RET_BAT || atkbd->bat_xl))) {
atkbd->release = code >> 7;
code &= 0x7f;
}
- if (!atkbd->emul &&
- (code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
- atkbd->bat_xl = !atkbd->release;
+ if (!atkbd->emul) {
+ if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
+ atkbd->bat_xl = !(data >> 7);
+ if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
+ atkbd->err_xl = !(data >> 7);
+ }
}
switch (code) {
case ATKBD_RET_BAT:
atkbd->enabled = 0;
- serio_rescan(atkbd->ps2dev.serio);
+ serio_reconnect(atkbd->ps2dev.serio);
goto out;
case ATKBD_RET_EMUL0:
atkbd->emul = 1;
atkbd->release = 1;
goto out;
case ATKBD_RET_HANGUEL:
- atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3);
+ atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3);
goto out;
case ATKBD_RET_HANJA:
- atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3);
+ atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
goto out;
case ATKBD_RET_ERR:
- printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
+// printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
goto out;
}
}
if (atkbd->keycode[code] != ATKBD_KEY_NULL)
- input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code);
+ input_event(atkbd->dev, EV_MSC, MSC_SCAN, code);
switch (atkbd->keycode[code]) {
case ATKBD_KEY_NULL:
break;
case ATKBD_KEY_UNKNOWN:
if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
+#if 0
+/* Quite a few key switchers and other tools trigger this and it confuses
+ people who can do nothing about it */
printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
"like XFree86, might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
+#endif
} else {
printk(KERN_WARNING "atkbd.c: Unknown key %s "
"(%s set %d, code %#x on %s).\n",
"to make it known.\n",
code & 0x80 ? "e0" : "", code & 0x7f);
}
- input_sync(&atkbd->dev);
+ input_sync(atkbd->dev);
break;
case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2;
case ATKBD_SCR_CLICK:
click = !atkbd->release;
break;
+ case ATKBD_SCR_LEFT:
+ hscroll = -1;
+ break;
+ case ATKBD_SCR_RIGHT:
+ hscroll = 1;
+ break;
default:
value = atkbd->release ? 0 :
- (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
+ (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key)));
- switch (value) { /* Workaround Toshiba laptop multiple keypress */
+ switch (value) { /* Workaround Toshiba laptop multiple keypress */
case 0:
atkbd->last = 0;
break;
case 1:
atkbd->last = code;
- atkbd->time = jiffies + (atkbd->dev.rep[REP_DELAY] * HZ + 500) / 1000 / 2;
+ atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2;
break;
case 2:
if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
break;
}
- atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
+ atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value);
}
- if (scroll || click != -1) {
- input_regs(&atkbd->dev, regs);
- input_report_key(&atkbd->dev, BTN_MIDDLE, click);
- input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
- input_sync(&atkbd->dev);
+ if (atkbd->scroll) {
+ input_regs(atkbd->dev, regs);
+ if (click != -1)
+ input_report_key(atkbd->dev, BTN_MIDDLE, click);
+ input_report_rel(atkbd->dev, REL_WHEEL, scroll);
+ input_report_rel(atkbd->dev, REL_HWHEEL, hscroll);
+ input_sync(atkbd->dev);
}
atkbd->release = 0;
return IRQ_HANDLED;
}
-
/*
- * Event callback from the input module. Events that change the state of
- * the hardware are processed here.
+ * atkbd_event_work() is used to complete processing of events that
+ * can not be processed by input_event() which is often called from
+ * interrupt context.
*/
-static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static void atkbd_event_work(void *data)
{
- struct atkbd *atkbd = dev->private;
const short period[32] =
{ 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
const short delay[4] =
{ 250, 500, 750, 1000 };
+
+ struct atkbd *atkbd = data;
+ struct input_dev *dev = atkbd->dev;
unsigned char param[2];
int i, j;
+ mutex_lock(&atkbd->event_mutex);
+
+ if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
+ param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+ | (test_bit(LED_NUML, dev->led) ? 2 : 0)
+ | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
+ ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
+
+ if (atkbd->extra) {
+ param[0] = 0;
+ param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+ | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
+ | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+ | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
+ | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
+ ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
+ }
+ }
+
+ if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) {
+ i = j = 0;
+ while (i < 31 && period[i] < dev->rep[REP_PERIOD])
+ i++;
+ while (j < 3 && delay[j] < dev->rep[REP_DELAY])
+ j++;
+ dev->rep[REP_PERIOD] = period[i];
+ dev->rep[REP_DELAY] = delay[j];
+ param[0] = i | (j << 5);
+ ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
+ }
+
+ mutex_unlock(&atkbd->event_mutex);
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here. If action can not be performed in
+ * interrupt context it is offloaded to atkbd_event_work.
+ */
+
+static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct atkbd *atkbd = dev->private;
+
if (!atkbd->write)
return -1;
switch (type) {
case EV_LED:
-
- param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
- | (test_bit(LED_NUML, dev->led) ? 2 : 0)
- | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
- ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
-
- if (atkbd->extra) {
- param[0] = 0;
- param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
- | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
- | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
- | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
- | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
- ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
- }
-
+ set_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask);
+ wmb();
+ schedule_work(&atkbd->event_work);
return 0;
-
case EV_REP:
- if (atkbd->softrepeat) return 0;
-
- i = j = 0;
- while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
- while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++;
- dev->rep[REP_PERIOD] = period[i];
- dev->rep[REP_DELAY] = delay[j];
- param[0] = i | (j << 5);
- ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
+ if (!atkbd->softrepeat) {
+ set_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask);
+ wmb();
+ schedule_work(&atkbd->event_work);
+ }
return 0;
}
static void atkbd_cleanup(struct serio *serio)
{
- struct atkbd *atkbd = serio->private;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
}
static void atkbd_disconnect(struct serio *serio)
{
- struct atkbd *atkbd = serio->private;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
atkbd_disable(atkbd);
/* make sure we don't have a command in flight */
- synchronize_kernel();
+ synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
flush_scheduled_work();
device_remove_file(&serio->dev, &atkbd_attr_extra);
device_remove_file(&serio->dev, &atkbd_attr_softrepeat);
device_remove_file(&serio->dev, &atkbd_attr_softraw);
- input_unregister_device(&atkbd->dev);
+ input_unregister_device(atkbd->dev);
serio_close(serio);
+ serio_set_drvdata(serio, NULL);
kfree(atkbd);
}
/*
- * atkbd_set_device_attrs() initializes keyboard's keycode table
+ * atkbd_set_keycode_table() initializes keyboard's keycode table
* according to the selected scancode set
*/
atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
if (atkbd->scroll)
- for (j = 0; i < 5; i++) {
- if (atkbd_unxlate_table[i] == atkbd_scroll_keys[j][1])
- atkbd->keycode[i] = atkbd_scroll_keys[j][0];
- if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j][1])
- atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j][0];
- }
+ for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
+ if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
+ atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
}
} else if (atkbd->set == 3) {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
if (atkbd->scroll)
- for (i = 0; i < 5; i++)
- atkbd->keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+ for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
+ atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
}
}
static void atkbd_set_device_attrs(struct atkbd *atkbd)
{
+ struct input_dev *input_dev = atkbd->dev;
int i;
- memset(&atkbd->dev, 0, sizeof(struct input_dev));
+ if (atkbd->extra)
+ sprintf(atkbd->name, "AT Set 2 Extra keyboard");
+ else
+ sprintf(atkbd->name, "AT %s Set %d keyboard",
+ atkbd->translated ? "Translated" : "Raw", atkbd->set);
- init_input_dev(&atkbd->dev);
+ sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys);
- atkbd->dev.name = atkbd->name;
- atkbd->dev.phys = atkbd->phys;
- atkbd->dev.id.bustype = BUS_I8042;
- atkbd->dev.id.vendor = 0x0001;
- atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set;
- atkbd->dev.id.version = atkbd->id;
- atkbd->dev.event = atkbd_event;
- atkbd->dev.private = atkbd;
- atkbd->dev.dev = &atkbd->ps2dev.serio->dev;
+ input_dev->name = atkbd->name;
+ input_dev->phys = atkbd->phys;
+ input_dev->id.bustype = BUS_I8042;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
+ input_dev->id.version = atkbd->id;
+ input_dev->event = atkbd_event;
+ input_dev->private = atkbd;
+ input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
- atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
if (atkbd->write) {
- atkbd->dev.evbit[0] |= BIT(EV_LED);
- atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ input_dev->evbit[0] |= BIT(EV_LED);
+ input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
}
if (atkbd->extra)
- atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
+ input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
if (!atkbd->softrepeat) {
- atkbd->dev.rep[REP_DELAY] = 250;
- atkbd->dev.rep[REP_PERIOD] = 33;
+ input_dev->rep[REP_DELAY] = 250;
+ input_dev->rep[REP_PERIOD] = 33;
}
- atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+ input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
if (atkbd->scroll) {
- atkbd->dev.evbit[0] |= BIT(EV_REL);
- atkbd->dev.relbit[0] = BIT(REL_WHEEL);
- set_bit(BTN_MIDDLE, atkbd->dev.keybit);
+ input_dev->evbit[0] |= BIT(EV_REL);
+ input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL);
+ set_bit(BTN_MIDDLE, input_dev->keybit);
}
- atkbd->dev.keycode = atkbd->keycode;
- atkbd->dev.keycodesize = sizeof(unsigned char);
- atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
+ input_dev->keycode = atkbd->keycode;
+ input_dev->keycodesize = sizeof(unsigned char);
+ input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
for (i = 0; i < 512; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
- set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+ set_bit(atkbd->keycode[i], input_dev->keybit);
}
/*
- * atkbd_connect() is called when the serio module finds and interface
+ * atkbd_connect() is called when the serio module finds an interface
* that isn't handled yet by an appropriate device driver. We check if
* there is an AT keyboard out there and if yes, we register ourselves
* to the input module.
*/
-static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
{
struct atkbd *atkbd;
+ struct input_dev *dev;
+ int err = -ENOMEM;
- if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
- return;
- memset(atkbd, 0, sizeof(struct atkbd));
+ atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
+ dev = input_allocate_device();
+ if (!atkbd || !dev)
+ goto fail;
+ atkbd->dev = dev;
ps2_init(&atkbd->ps2dev, serio);
+ INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd);
+ mutex_init(&atkbd->event_mutex);
- switch (serio->type & SERIO_TYPE) {
+ switch (serio->id.type) {
case SERIO_8042_XL:
atkbd->translated = 1;
if (serio->write)
atkbd->write = 1;
break;
- case SERIO_RS232:
- if ((serio->type & SERIO_PROTO) == SERIO_PS2SER)
- break;
- default:
- kfree(atkbd);
- return;
}
atkbd->softraw = atkbd_softraw;
atkbd->softrepeat = atkbd_softrepeat;
atkbd->scroll = atkbd_scroll;
- if (!atkbd->write)
- atkbd->softrepeat = 1;
-
if (atkbd->softrepeat)
atkbd->softraw = 1;
- serio->private = atkbd;
+ serio_set_drvdata(serio, atkbd);
- if (serio_open(serio, drv)) {
- kfree(atkbd);
- return;
- }
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail;
if (atkbd->write) {
if (atkbd_probe(atkbd)) {
serio_close(serio);
- serio->private = NULL;
- kfree(atkbd);
- return;
+ err = -ENODEV;
+ goto fail;
}
atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
atkbd->id = 0xab00;
}
- if (atkbd->extra)
- sprintf(atkbd->name, "AT Set 2 Extra keyboard");
- else
- sprintf(atkbd->name, "AT %s Set %d keyboard",
- atkbd->translated ? "Translated" : "Raw", atkbd->set);
-
- sprintf(atkbd->phys, "%s/input0", serio->phys);
-
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
-
device_create_file(&serio->dev, &atkbd_attr_extra);
device_create_file(&serio->dev, &atkbd_attr_scroll);
device_create_file(&serio->dev, &atkbd_attr_set);
atkbd_enable(atkbd);
- printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+ input_register_device(atkbd->dev);
+
+ return 0;
+
+ fail: serio_set_drvdata(serio, NULL);
+ input_free_device(dev);
+ kfree(atkbd);
+ return err;
}
/*
static int atkbd_reconnect(struct serio *serio)
{
- struct atkbd *atkbd = serio->private;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv;
unsigned char param[1];
atkbd_disable(atkbd);
if (atkbd->write) {
- param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
- | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
- | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
+ param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0)
+ | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0)
+ | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0);
if (atkbd_probe(atkbd))
return -1;
return 0;
}
+static struct serio_device_id atkbd_serio_ids[] = {
+ {
+ .type = SERIO_8042,
+ .proto = SERIO_ANY,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ {
+ .type = SERIO_8042_XL,
+ .proto = SERIO_ANY,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_PS2SER,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
+
static struct serio_driver atkbd_drv = {
.driver = {
.name = "atkbd",
},
.description = DRIVER_DESC,
+ .id_table = atkbd_serio_ids,
.interrupt = atkbd_interrupt,
.connect = atkbd_connect,
.reconnect = atkbd_reconnect,
goto out;
}
- retval = handler((struct atkbd *)serio->private, buf);
+ retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
out:
serio_unpin_driver(serio);
goto out;
}
- atkbd = serio->private;
+ atkbd = serio_get_drvdata(serio);
atkbd_disable(atkbd);
retval = handler(atkbd, buf, count);
atkbd_enable(atkbd);
static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
{
+ struct input_dev *new_dev;
unsigned long value;
char *rest;
return -EINVAL;
if (atkbd->extra != value) {
- /* unregister device as it's properties will change */
- input_unregister_device(&atkbd->dev);
+ /*
+ * Since device's properties will change we need to
+ * unregister old device. But allocate new one first
+ * to make sure we have it.
+ */
+ if (!(new_dev = input_allocate_device()))
+ return -ENOMEM;
+ input_unregister_device(atkbd->dev);
+ atkbd->dev = new_dev;
atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
atkbd_activate(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
+ input_register_device(atkbd->dev);
}
return count;
}
static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
{
+ struct input_dev *new_dev;
unsigned long value;
char *rest;
return -EINVAL;
if (atkbd->scroll != value) {
- /* unregister device as it's properties will change */
- input_unregister_device(&atkbd->dev);
+ if (!(new_dev = input_allocate_device()))
+ return -ENOMEM;
+ input_unregister_device(atkbd->dev);
+ atkbd->dev = new_dev;
atkbd->scroll = value;
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
+ input_register_device(atkbd->dev);
}
return count;
}
static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
{
+ struct input_dev *new_dev;
unsigned long value;
char *rest;
return -EINVAL;
if (atkbd->set != value) {
- /* unregister device as it's properties will change */
- input_unregister_device(&atkbd->dev);
+ if (!(new_dev = input_allocate_device()))
+ return -ENOMEM;
+ input_unregister_device(atkbd->dev);
+ atkbd->dev = new_dev;
atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
atkbd_activate(atkbd);
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
+ input_register_device(atkbd->dev);
}
return count;
}
static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
{
+ struct input_dev *new_dev;
unsigned long value;
char *rest;
return -EINVAL;
if (atkbd->softrepeat != value) {
- /* unregister device as it's properties will change */
- input_unregister_device(&atkbd->dev);
+ if (!(new_dev = input_allocate_device()))
+ return -ENOMEM;
+ input_unregister_device(atkbd->dev);
+ atkbd->dev = new_dev;
atkbd->softrepeat = value;
if (atkbd->softrepeat)
atkbd->softraw = 1;
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
+ input_register_device(atkbd->dev);
}
-
return count;
}
static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
{
+ struct input_dev *new_dev;
unsigned long value;
char *rest;
return -EINVAL;
if (atkbd->softraw != value) {
- /* unregister device as it's properties will change */
- input_unregister_device(&atkbd->dev);
+ if (!(new_dev = input_allocate_device()))
+ return -ENOMEM;
+ input_unregister_device(atkbd->dev);
+ atkbd->dev = new_dev;
atkbd->softraw = value;
atkbd_set_device_attrs(atkbd);
- input_register_device(&atkbd->dev);
+ input_register_device(atkbd->dev);
}
return count;
}
-int __init atkbd_init(void)
+static int __init atkbd_init(void)
{
serio_register_driver(&atkbd_drv);
return 0;
}
-void __exit atkbd_exit(void)
+static void __exit atkbd_exit(void)
{
serio_unregister_driver(&atkbd_drv);
}