Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 1999-2001 Vojtech Pavlik
0004  */
0005 
0006 /*
0007  * Sun keyboard driver for Linux
0008  */
0009 
0010 /*
0011  */
0012 
0013 #include <linux/delay.h>
0014 #include <linux/sched.h>
0015 #include <linux/slab.h>
0016 #include <linux/module.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/input.h>
0019 #include <linux/serio.h>
0020 #include <linux/workqueue.h>
0021 
0022 #define DRIVER_DESC "Sun keyboard driver"
0023 
0024 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0025 MODULE_DESCRIPTION(DRIVER_DESC);
0026 MODULE_LICENSE("GPL");
0027 
0028 static unsigned char sunkbd_keycode[128] = {
0029       0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
0030      65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106,  1,  2,  3,
0031       4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
0032     116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
0033      26, 27,111,127, 71, 72, 73, 74,134,135,107,  0, 29, 30, 31, 32,
0034      33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
0035     104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
0036      79, 80, 81,  0,  0,  0,138, 58,125, 57,126,109, 86, 78
0037 };
0038 
0039 #define SUNKBD_CMD_RESET    0x1
0040 #define SUNKBD_CMD_BELLON   0x2
0041 #define SUNKBD_CMD_BELLOFF  0x3
0042 #define SUNKBD_CMD_CLICK    0xa
0043 #define SUNKBD_CMD_NOCLICK  0xb
0044 #define SUNKBD_CMD_SETLED   0xe
0045 #define SUNKBD_CMD_LAYOUT   0xf
0046 
0047 #define SUNKBD_RET_RESET    0xff
0048 #define SUNKBD_RET_ALLUP    0x7f
0049 #define SUNKBD_RET_LAYOUT   0xfe
0050 
0051 #define SUNKBD_LAYOUT_5_MASK    0x20
0052 #define SUNKBD_RELEASE      0x80
0053 #define SUNKBD_KEY      0x7f
0054 
0055 /*
0056  * Per-keyboard data.
0057  */
0058 
0059 struct sunkbd {
0060     unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
0061     struct input_dev *dev;
0062     struct serio *serio;
0063     struct work_struct tq;
0064     wait_queue_head_t wait;
0065     char name[64];
0066     char phys[32];
0067     char type;
0068     bool enabled;
0069     volatile s8 reset;
0070     volatile s8 layout;
0071 };
0072 
0073 /*
0074  * sunkbd_interrupt() is called by the low level driver when a character
0075  * is received.
0076  */
0077 
0078 static irqreturn_t sunkbd_interrupt(struct serio *serio,
0079         unsigned char data, unsigned int flags)
0080 {
0081     struct sunkbd *sunkbd = serio_get_drvdata(serio);
0082 
0083     if (sunkbd->reset <= -1) {
0084         /*
0085          * If cp[i] is 0xff, sunkbd->reset will stay -1.
0086          * The keyboard sends 0xff 0xff 0xID on powerup.
0087          */
0088         sunkbd->reset = data;
0089         wake_up_interruptible(&sunkbd->wait);
0090         goto out;
0091     }
0092 
0093     if (sunkbd->layout == -1) {
0094         sunkbd->layout = data;
0095         wake_up_interruptible(&sunkbd->wait);
0096         goto out;
0097     }
0098 
0099     switch (data) {
0100 
0101     case SUNKBD_RET_RESET:
0102         if (sunkbd->enabled)
0103             schedule_work(&sunkbd->tq);
0104         sunkbd->reset = -1;
0105         break;
0106 
0107     case SUNKBD_RET_LAYOUT:
0108         sunkbd->layout = -1;
0109         break;
0110 
0111     case SUNKBD_RET_ALLUP: /* All keys released */
0112         break;
0113 
0114     default:
0115         if (!sunkbd->enabled)
0116             break;
0117 
0118         if (sunkbd->keycode[data & SUNKBD_KEY]) {
0119             input_report_key(sunkbd->dev,
0120                      sunkbd->keycode[data & SUNKBD_KEY],
0121                      !(data & SUNKBD_RELEASE));
0122             input_sync(sunkbd->dev);
0123         } else {
0124             printk(KERN_WARNING
0125                 "sunkbd.c: Unknown key (scancode %#x) %s.\n",
0126                 data & SUNKBD_KEY,
0127                 data & SUNKBD_RELEASE ? "released" : "pressed");
0128         }
0129     }
0130 out:
0131     return IRQ_HANDLED;
0132 }
0133 
0134 /*
0135  * sunkbd_event() handles events from the input module.
0136  */
0137 
0138 static int sunkbd_event(struct input_dev *dev,
0139             unsigned int type, unsigned int code, int value)
0140 {
0141     struct sunkbd *sunkbd = input_get_drvdata(dev);
0142 
0143     switch (type) {
0144 
0145     case EV_LED:
0146 
0147         serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
0148         serio_write(sunkbd->serio,
0149             (!!test_bit(LED_CAPSL,   dev->led) << 3) |
0150             (!!test_bit(LED_SCROLLL, dev->led) << 2) |
0151             (!!test_bit(LED_COMPOSE, dev->led) << 1) |
0152              !!test_bit(LED_NUML,    dev->led));
0153         return 0;
0154 
0155     case EV_SND:
0156 
0157         switch (code) {
0158 
0159         case SND_CLICK:
0160             serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
0161             return 0;
0162 
0163         case SND_BELL:
0164             serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
0165             return 0;
0166         }
0167 
0168         break;
0169     }
0170 
0171     return -1;
0172 }
0173 
0174 /*
0175  * sunkbd_initialize() checks for a Sun keyboard attached, and determines
0176  * its type.
0177  */
0178 
0179 static int sunkbd_initialize(struct sunkbd *sunkbd)
0180 {
0181     sunkbd->reset = -2;
0182     serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
0183     wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
0184     if (sunkbd->reset < 0)
0185         return -1;
0186 
0187     sunkbd->type = sunkbd->reset;
0188 
0189     if (sunkbd->type == 4) {    /* Type 4 keyboard */
0190         sunkbd->layout = -2;
0191         serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
0192         wait_event_interruptible_timeout(sunkbd->wait,
0193                          sunkbd->layout >= 0, HZ / 4);
0194         if (sunkbd->layout < 0)
0195             return -1;
0196         if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
0197             sunkbd->type = 5;
0198     }
0199 
0200     return 0;
0201 }
0202 
0203 /*
0204  * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers
0205  * they were in.
0206  */
0207 
0208 static void sunkbd_set_leds_beeps(struct sunkbd *sunkbd)
0209 {
0210     serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
0211     serio_write(sunkbd->serio,
0212         (!!test_bit(LED_CAPSL,   sunkbd->dev->led) << 3) |
0213         (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
0214         (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
0215          !!test_bit(LED_NUML,    sunkbd->dev->led));
0216     serio_write(sunkbd->serio,
0217         SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
0218     serio_write(sunkbd->serio,
0219         SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
0220 }
0221 
0222 
0223 /*
0224  * sunkbd_reinit() wait for the keyboard reset to complete and restores state
0225  * of leds and beeps.
0226  */
0227 
0228 static void sunkbd_reinit(struct work_struct *work)
0229 {
0230     struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
0231 
0232     /*
0233      * It is OK that we check sunkbd->enabled without pausing serio,
0234      * as we only want to catch true->false transition that will
0235      * happen once and we will be woken up for it.
0236      */
0237     wait_event_interruptible_timeout(sunkbd->wait,
0238                      sunkbd->reset >= 0 || !sunkbd->enabled,
0239                      HZ);
0240 
0241     if (sunkbd->reset >= 0 && sunkbd->enabled)
0242         sunkbd_set_leds_beeps(sunkbd);
0243 }
0244 
0245 static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
0246 {
0247     serio_pause_rx(sunkbd->serio);
0248     sunkbd->enabled = enable;
0249     serio_continue_rx(sunkbd->serio);
0250 
0251     if (!enable) {
0252         wake_up_interruptible(&sunkbd->wait);
0253         cancel_work_sync(&sunkbd->tq);
0254     }
0255 }
0256 
0257 /*
0258  * sunkbd_connect() probes for a Sun keyboard and fills the necessary
0259  * structures.
0260  */
0261 
0262 static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
0263 {
0264     struct sunkbd *sunkbd;
0265     struct input_dev *input_dev;
0266     int err = -ENOMEM;
0267     int i;
0268 
0269     sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
0270     input_dev = input_allocate_device();
0271     if (!sunkbd || !input_dev)
0272         goto fail1;
0273 
0274     sunkbd->serio = serio;
0275     sunkbd->dev = input_dev;
0276     init_waitqueue_head(&sunkbd->wait);
0277     INIT_WORK(&sunkbd->tq, sunkbd_reinit);
0278     snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
0279 
0280     serio_set_drvdata(serio, sunkbd);
0281 
0282     err = serio_open(serio, drv);
0283     if (err)
0284         goto fail2;
0285 
0286     if (sunkbd_initialize(sunkbd) < 0) {
0287         err = -ENODEV;
0288         goto fail3;
0289     }
0290 
0291     snprintf(sunkbd->name, sizeof(sunkbd->name),
0292          "Sun Type %d keyboard", sunkbd->type);
0293     memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
0294 
0295     input_dev->name = sunkbd->name;
0296     input_dev->phys = sunkbd->phys;
0297     input_dev->id.bustype = BUS_RS232;
0298     input_dev->id.vendor  = SERIO_SUNKBD;
0299     input_dev->id.product = sunkbd->type;
0300     input_dev->id.version = 0x0100;
0301     input_dev->dev.parent = &serio->dev;
0302 
0303     input_set_drvdata(input_dev, sunkbd);
0304 
0305     input_dev->event = sunkbd_event;
0306 
0307     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
0308         BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
0309     input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
0310         BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
0311     input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
0312 
0313     input_dev->keycode = sunkbd->keycode;
0314     input_dev->keycodesize = sizeof(unsigned char);
0315     input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
0316     for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
0317         __set_bit(sunkbd->keycode[i], input_dev->keybit);
0318     __clear_bit(KEY_RESERVED, input_dev->keybit);
0319 
0320     sunkbd_enable(sunkbd, true);
0321 
0322     err = input_register_device(sunkbd->dev);
0323     if (err)
0324         goto fail4;
0325 
0326     return 0;
0327 
0328  fail4: sunkbd_enable(sunkbd, false);
0329  fail3: serio_close(serio);
0330  fail2: serio_set_drvdata(serio, NULL);
0331  fail1: input_free_device(input_dev);
0332     kfree(sunkbd);
0333     return err;
0334 }
0335 
0336 /*
0337  * sunkbd_disconnect() unregisters and closes behind us.
0338  */
0339 
0340 static void sunkbd_disconnect(struct serio *serio)
0341 {
0342     struct sunkbd *sunkbd = serio_get_drvdata(serio);
0343 
0344     sunkbd_enable(sunkbd, false);
0345     input_unregister_device(sunkbd->dev);
0346     serio_close(serio);
0347     serio_set_drvdata(serio, NULL);
0348     kfree(sunkbd);
0349 }
0350 
0351 static const struct serio_device_id sunkbd_serio_ids[] = {
0352     {
0353         .type   = SERIO_RS232,
0354         .proto  = SERIO_SUNKBD,
0355         .id = SERIO_ANY,
0356         .extra  = SERIO_ANY,
0357     },
0358     {
0359         .type   = SERIO_RS232,
0360         .proto  = SERIO_UNKNOWN, /* sunkbd does probe */
0361         .id = SERIO_ANY,
0362         .extra  = SERIO_ANY,
0363     },
0364     { 0 }
0365 };
0366 
0367 MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
0368 
0369 static struct serio_driver sunkbd_drv = {
0370     .driver     = {
0371         .name   = "sunkbd",
0372     },
0373     .description    = DRIVER_DESC,
0374     .id_table   = sunkbd_serio_ids,
0375     .interrupt  = sunkbd_interrupt,
0376     .connect    = sunkbd_connect,
0377     .disconnect = sunkbd_disconnect,
0378 };
0379 
0380 module_serio_driver(sunkbd_drv);