diff options
Diffstat (limited to 'drivers/input/keyboard/sunkbd.c')
| -rw-r--r-- | drivers/input/keyboard/sunkbd.c | 264 |
1 files changed, 141 insertions, 123 deletions
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 596964ceb96..dc6bb9d5b4f 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -1,6 +1,4 @@ /* - * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik */ @@ -29,10 +27,10 @@ */ #include <linux/delay.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/workqueue.h> @@ -44,7 +42,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { - 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, + 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112, 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, @@ -75,14 +73,15 @@ static unsigned char sunkbd_keycode[128] = { */ struct sunkbd { - unsigned char keycode[128]; - struct input_dev dev; + unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)]; + struct input_dev *dev; struct serio *serio; struct work_struct tq; wait_queue_head_t wait; char name[64]; char phys[32]; char type; + bool enabled; volatile s8 reset; volatile s8 layout; }; @@ -93,12 +92,16 @@ struct sunkbd { */ static irqreturn_t sunkbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { - struct sunkbd* sunkbd = serio_get_drvdata(serio); + struct sunkbd *sunkbd = serio_get_drvdata(serio); - if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ - sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + if (sunkbd->reset <= -1) { + /* + * If cp[i] is 0xff, sunkbd->reset will stay -1. + * The keyboard sends 0xff 0xff 0xID on powerup. + */ + sunkbd->reset = data; wake_up_interruptible(&sunkbd->wait); goto out; } @@ -111,27 +114,33 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, switch (data) { - case SUNKBD_RET_RESET: - schedule_work(&sunkbd->tq); - sunkbd->reset = -1; - break; + case SUNKBD_RET_RESET: + schedule_work(&sunkbd->tq); + sunkbd->reset = -1; + break; - case SUNKBD_RET_LAYOUT: - sunkbd->layout = -1; - break; + case SUNKBD_RET_LAYOUT: + sunkbd->layout = -1; + break; + + case SUNKBD_RET_ALLUP: /* All keys released */ + break; - case SUNKBD_RET_ALLUP: /* All keys released */ + default: + if (!sunkbd->enabled) break; - default: - if (sunkbd->keycode[data & SUNKBD_KEY]) { - input_regs(&sunkbd->dev, regs); - input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); - input_sync(&sunkbd->dev); - } else { - printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", - data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); - } + if (sunkbd->keycode[data & SUNKBD_KEY]) { + input_report_key(sunkbd->dev, + sunkbd->keycode[data & SUNKBD_KEY], + !(data & SUNKBD_RELEASE)); + input_sync(sunkbd->dev); + } else { + printk(KERN_WARNING + "sunkbd.c: Unknown key (scancode %#x) %s.\n", + data & SUNKBD_KEY, + data & SUNKBD_RELEASE ? "released" : "pressed"); + } } out: return IRQ_HANDLED; @@ -141,34 +150,37 @@ out: * sunkbd_event() handles events from the input module. */ -static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int sunkbd_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) { - struct sunkbd *sunkbd = dev->private; + struct sunkbd *sunkbd = input_get_drvdata(dev); switch (type) { - case EV_LED: + case EV_LED: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | - (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); - return 0; + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | + (!!test_bit(LED_COMPOSE, dev->led) << 1) | + !!test_bit(LED_NUML, dev->led)); + return 0; - case EV_SND: + case EV_SND: - switch (code) { + switch (code) { - case SND_CLICK: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); - return 0; + case SND_CLICK: + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + return 0; - case SND_BELL: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); - return 0; - } + case SND_BELL: + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + return 0; + } - break; + break; } return -1; @@ -182,19 +194,22 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c static int sunkbd_initialize(struct sunkbd *sunkbd) { sunkbd->reset = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); + serio_write(sunkbd->serio, SUNKBD_CMD_RESET); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - if (sunkbd->reset <0) + if (sunkbd->reset < 0) return -1; sunkbd->type = sunkbd->reset; if (sunkbd->type == 4) { /* Type 4 keyboard */ sunkbd->layout = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); - wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); - if (sunkbd->layout < 0) return -1; - if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; + serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT); + wait_event_interruptible_timeout(sunkbd->wait, + sunkbd->layout >= 0, HZ / 4); + if (sunkbd->layout < 0) + return -1; + if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) + sunkbd->type = 5; } return 0; @@ -205,91 +220,108 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) * were in. */ -static void sunkbd_reinit(void *data) +static void sunkbd_reinit(struct work_struct *work) { - struct sunkbd *sunkbd = data; + struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | - (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | + (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | + !!test_bit(LED_NUML, sunkbd->dev->led)); + serio_write(sunkbd->serio, + SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + serio_write(sunkbd->serio, + SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); +} + +static void sunkbd_enable(struct sunkbd *sunkbd, bool enable) +{ + serio_pause_rx(sunkbd->serio); + sunkbd->enabled = enable; + serio_continue_rx(sunkbd->serio); } /* - * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. + * sunkbd_connect() probes for a Sun keyboard and fills the necessary + * structures. */ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - - if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) - return -ENOMEM; - memset(sunkbd, 0, sizeof(struct sunkbd)); - - init_input_dev(&sunkbd->dev); - init_waitqueue_head(&sunkbd->wait); - - sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); - sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); - sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sunkbd || !input_dev) + goto fail1; sunkbd->serio = serio; - - INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); - - sunkbd->dev.keycode = sunkbd->keycode; - sunkbd->dev.keycodesize = sizeof(unsigned char); - sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode); - - sunkbd->dev.event = sunkbd_event; - sunkbd->dev.private = sunkbd; + sunkbd->dev = input_dev; + init_waitqueue_head(&sunkbd->wait); + INIT_WORK(&sunkbd->tq, sunkbd_reinit); + snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys); serio_set_drvdata(serio, sunkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return err; - } + if (err) + goto fail2; if (sunkbd_initialize(sunkbd) < 0) { - serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return -ENODEV; + err = -ENODEV; + goto fail3; } - sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); - + snprintf(sunkbd->name, sizeof(sunkbd->name), + "Sun Type %d keyboard", sunkbd->type); memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); - for (i = 0; i < 128; i++) - set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); - clear_bit(0, sunkbd->dev.keybit); - sprintf(sunkbd->phys, "%s/input0", serio->phys); + input_dev->name = sunkbd->name; + input_dev->phys = sunkbd->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SUNKBD; + input_dev->id.product = sunkbd->type; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &serio->dev; + + input_set_drvdata(input_dev, sunkbd); + + input_dev->event = sunkbd_event; - sunkbd->dev.name = sunkbd->name; - sunkbd->dev.phys = sunkbd->phys; - sunkbd->dev.id.bustype = BUS_RS232; - sunkbd->dev.id.vendor = SERIO_SUNKBD; - sunkbd->dev.id.product = sunkbd->type; - sunkbd->dev.id.version = 0x0100; - sunkbd->dev.dev = &serio->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | + BIT_MASK(EV_SND) | BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) | + BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML); + input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL); - input_register_device(&sunkbd->dev); + input_dev->keycode = sunkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode); + for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++) + __set_bit(sunkbd->keycode[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); - printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); + sunkbd_enable(sunkbd, true); + + err = input_register_device(sunkbd->dev); + if (err) + goto fail4; return 0; + + fail4: sunkbd_enable(sunkbd, false); + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(sunkbd); + return err; } /* @@ -299,7 +331,9 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio_get_drvdata(serio); - input_unregister_device(&sunkbd->dev); + + sunkbd_enable(sunkbd, false); + input_unregister_device(sunkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(sunkbd); @@ -334,20 +368,4 @@ static struct serio_driver sunkbd_drv = { .disconnect = sunkbd_disconnect, }; -/* - * The functions for insering/removing us as a module. - */ - -static int __init sunkbd_init(void) -{ - serio_register_driver(&sunkbd_drv); - return 0; -} - -static void __exit sunkbd_exit(void) -{ - serio_unregister_driver(&sunkbd_drv); -} - -module_init(sunkbd_init); -module_exit(sunkbd_exit); +module_serio_driver(sunkbd_drv); |
