root/drivers/input/keyboard/sunkbd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sunkbd_interrupt
  2. sunkbd_event
  3. sunkbd_initialize
  4. sunkbd_reinit
  5. sunkbd_enable
  6. sunkbd_connect
  7. sunkbd_disconnect

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) 1999-2001 Vojtech Pavlik
   4  */
   5 
   6 /*
   7  * Sun keyboard driver for Linux
   8  */
   9 
  10 /*
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/sched.h>
  15 #include <linux/slab.h>
  16 #include <linux/module.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/input.h>
  19 #include <linux/serio.h>
  20 #include <linux/workqueue.h>
  21 
  22 #define DRIVER_DESC     "Sun keyboard driver"
  23 
  24 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  25 MODULE_DESCRIPTION(DRIVER_DESC);
  26 MODULE_LICENSE("GPL");
  27 
  28 static unsigned char sunkbd_keycode[128] = {
  29           0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
  30          65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106,  1,  2,  3,
  31           4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
  32         116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
  33          26, 27,111,127, 71, 72, 73, 74,134,135,107,  0, 29, 30, 31, 32,
  34          33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
  35         104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
  36          79, 80, 81,  0,  0,  0,138, 58,125, 57,126,109, 86, 78
  37 };
  38 
  39 #define SUNKBD_CMD_RESET        0x1
  40 #define SUNKBD_CMD_BELLON       0x2
  41 #define SUNKBD_CMD_BELLOFF      0x3
  42 #define SUNKBD_CMD_CLICK        0xa
  43 #define SUNKBD_CMD_NOCLICK      0xb
  44 #define SUNKBD_CMD_SETLED       0xe
  45 #define SUNKBD_CMD_LAYOUT       0xf
  46 
  47 #define SUNKBD_RET_RESET        0xff
  48 #define SUNKBD_RET_ALLUP        0x7f
  49 #define SUNKBD_RET_LAYOUT       0xfe
  50 
  51 #define SUNKBD_LAYOUT_5_MASK    0x20
  52 #define SUNKBD_RELEASE          0x80
  53 #define SUNKBD_KEY              0x7f
  54 
  55 /*
  56  * Per-keyboard data.
  57  */
  58 
  59 struct sunkbd {
  60         unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
  61         struct input_dev *dev;
  62         struct serio *serio;
  63         struct work_struct tq;
  64         wait_queue_head_t wait;
  65         char name[64];
  66         char phys[32];
  67         char type;
  68         bool enabled;
  69         volatile s8 reset;
  70         volatile s8 layout;
  71 };
  72 
  73 /*
  74  * sunkbd_interrupt() is called by the low level driver when a character
  75  * is received.
  76  */
  77 
  78 static irqreturn_t sunkbd_interrupt(struct serio *serio,
  79                 unsigned char data, unsigned int flags)
  80 {
  81         struct sunkbd *sunkbd = serio_get_drvdata(serio);
  82 
  83         if (sunkbd->reset <= -1) {
  84                 /*
  85                  * If cp[i] is 0xff, sunkbd->reset will stay -1.
  86                  * The keyboard sends 0xff 0xff 0xID on powerup.
  87                  */
  88                 sunkbd->reset = data;
  89                 wake_up_interruptible(&sunkbd->wait);
  90                 goto out;
  91         }
  92 
  93         if (sunkbd->layout == -1) {
  94                 sunkbd->layout = data;
  95                 wake_up_interruptible(&sunkbd->wait);
  96                 goto out;
  97         }
  98 
  99         switch (data) {
 100 
 101         case SUNKBD_RET_RESET:
 102                 schedule_work(&sunkbd->tq);
 103                 sunkbd->reset = -1;
 104                 break;
 105 
 106         case SUNKBD_RET_LAYOUT:
 107                 sunkbd->layout = -1;
 108                 break;
 109 
 110         case SUNKBD_RET_ALLUP: /* All keys released */
 111                 break;
 112 
 113         default:
 114                 if (!sunkbd->enabled)
 115                         break;
 116 
 117                 if (sunkbd->keycode[data & SUNKBD_KEY]) {
 118                         input_report_key(sunkbd->dev,
 119                                          sunkbd->keycode[data & SUNKBD_KEY],
 120                                          !(data & SUNKBD_RELEASE));
 121                         input_sync(sunkbd->dev);
 122                 } else {
 123                         printk(KERN_WARNING
 124                                 "sunkbd.c: Unknown key (scancode %#x) %s.\n",
 125                                 data & SUNKBD_KEY,
 126                                 data & SUNKBD_RELEASE ? "released" : "pressed");
 127                 }
 128         }
 129 out:
 130         return IRQ_HANDLED;
 131 }
 132 
 133 /*
 134  * sunkbd_event() handles events from the input module.
 135  */
 136 
 137 static int sunkbd_event(struct input_dev *dev,
 138                         unsigned int type, unsigned int code, int value)
 139 {
 140         struct sunkbd *sunkbd = input_get_drvdata(dev);
 141 
 142         switch (type) {
 143 
 144         case EV_LED:
 145 
 146                 serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
 147                 serio_write(sunkbd->serio,
 148                         (!!test_bit(LED_CAPSL,   dev->led) << 3) |
 149                         (!!test_bit(LED_SCROLLL, dev->led) << 2) |
 150                         (!!test_bit(LED_COMPOSE, dev->led) << 1) |
 151                          !!test_bit(LED_NUML,    dev->led));
 152                 return 0;
 153 
 154         case EV_SND:
 155 
 156                 switch (code) {
 157 
 158                 case SND_CLICK:
 159                         serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
 160                         return 0;
 161 
 162                 case SND_BELL:
 163                         serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
 164                         return 0;
 165                 }
 166 
 167                 break;
 168         }
 169 
 170         return -1;
 171 }
 172 
 173 /*
 174  * sunkbd_initialize() checks for a Sun keyboard attached, and determines
 175  * its type.
 176  */
 177 
 178 static int sunkbd_initialize(struct sunkbd *sunkbd)
 179 {
 180         sunkbd->reset = -2;
 181         serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
 182         wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 183         if (sunkbd->reset < 0)
 184                 return -1;
 185 
 186         sunkbd->type = sunkbd->reset;
 187 
 188         if (sunkbd->type == 4) {        /* Type 4 keyboard */
 189                 sunkbd->layout = -2;
 190                 serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
 191                 wait_event_interruptible_timeout(sunkbd->wait,
 192                                                  sunkbd->layout >= 0, HZ / 4);
 193                 if (sunkbd->layout < 0)
 194                         return -1;
 195                 if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
 196                         sunkbd->type = 5;
 197         }
 198 
 199         return 0;
 200 }
 201 
 202 /*
 203  * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
 204  * were in.
 205  */
 206 
 207 static void sunkbd_reinit(struct work_struct *work)
 208 {
 209         struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
 210 
 211         wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 212 
 213         serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
 214         serio_write(sunkbd->serio,
 215                 (!!test_bit(LED_CAPSL,   sunkbd->dev->led) << 3) |
 216                 (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
 217                 (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
 218                  !!test_bit(LED_NUML,    sunkbd->dev->led));
 219         serio_write(sunkbd->serio,
 220                 SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
 221         serio_write(sunkbd->serio,
 222                 SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
 223 }
 224 
 225 static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
 226 {
 227         serio_pause_rx(sunkbd->serio);
 228         sunkbd->enabled = enable;
 229         serio_continue_rx(sunkbd->serio);
 230 }
 231 
 232 /*
 233  * sunkbd_connect() probes for a Sun keyboard and fills the necessary
 234  * structures.
 235  */
 236 
 237 static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
 238 {
 239         struct sunkbd *sunkbd;
 240         struct input_dev *input_dev;
 241         int err = -ENOMEM;
 242         int i;
 243 
 244         sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
 245         input_dev = input_allocate_device();
 246         if (!sunkbd || !input_dev)
 247                 goto fail1;
 248 
 249         sunkbd->serio = serio;
 250         sunkbd->dev = input_dev;
 251         init_waitqueue_head(&sunkbd->wait);
 252         INIT_WORK(&sunkbd->tq, sunkbd_reinit);
 253         snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
 254 
 255         serio_set_drvdata(serio, sunkbd);
 256 
 257         err = serio_open(serio, drv);
 258         if (err)
 259                 goto fail2;
 260 
 261         if (sunkbd_initialize(sunkbd) < 0) {
 262                 err = -ENODEV;
 263                 goto fail3;
 264         }
 265 
 266         snprintf(sunkbd->name, sizeof(sunkbd->name),
 267                  "Sun Type %d keyboard", sunkbd->type);
 268         memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
 269 
 270         input_dev->name = sunkbd->name;
 271         input_dev->phys = sunkbd->phys;
 272         input_dev->id.bustype = BUS_RS232;
 273         input_dev->id.vendor  = SERIO_SUNKBD;
 274         input_dev->id.product = sunkbd->type;
 275         input_dev->id.version = 0x0100;
 276         input_dev->dev.parent = &serio->dev;
 277 
 278         input_set_drvdata(input_dev, sunkbd);
 279 
 280         input_dev->event = sunkbd_event;
 281 
 282         input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
 283                 BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
 284         input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
 285                 BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
 286         input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
 287 
 288         input_dev->keycode = sunkbd->keycode;
 289         input_dev->keycodesize = sizeof(unsigned char);
 290         input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
 291         for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
 292                 __set_bit(sunkbd->keycode[i], input_dev->keybit);
 293         __clear_bit(KEY_RESERVED, input_dev->keybit);
 294 
 295         sunkbd_enable(sunkbd, true);
 296 
 297         err = input_register_device(sunkbd->dev);
 298         if (err)
 299                 goto fail4;
 300 
 301         return 0;
 302 
 303  fail4: sunkbd_enable(sunkbd, false);
 304  fail3: serio_close(serio);
 305  fail2: serio_set_drvdata(serio, NULL);
 306  fail1: input_free_device(input_dev);
 307         kfree(sunkbd);
 308         return err;
 309 }
 310 
 311 /*
 312  * sunkbd_disconnect() unregisters and closes behind us.
 313  */
 314 
 315 static void sunkbd_disconnect(struct serio *serio)
 316 {
 317         struct sunkbd *sunkbd = serio_get_drvdata(serio);
 318 
 319         sunkbd_enable(sunkbd, false);
 320         input_unregister_device(sunkbd->dev);
 321         serio_close(serio);
 322         serio_set_drvdata(serio, NULL);
 323         kfree(sunkbd);
 324 }
 325 
 326 static const struct serio_device_id sunkbd_serio_ids[] = {
 327         {
 328                 .type   = SERIO_RS232,
 329                 .proto  = SERIO_SUNKBD,
 330                 .id     = SERIO_ANY,
 331                 .extra  = SERIO_ANY,
 332         },
 333         {
 334                 .type   = SERIO_RS232,
 335                 .proto  = SERIO_UNKNOWN, /* sunkbd does probe */
 336                 .id     = SERIO_ANY,
 337                 .extra  = SERIO_ANY,
 338         },
 339         { 0 }
 340 };
 341 
 342 MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
 343 
 344 static struct serio_driver sunkbd_drv = {
 345         .driver         = {
 346                 .name   = "sunkbd",
 347         },
 348         .description    = DRIVER_DESC,
 349         .id_table       = sunkbd_serio_ids,
 350         .interrupt      = sunkbd_interrupt,
 351         .connect        = sunkbd_connect,
 352         .disconnect     = sunkbd_disconnect,
 353 };
 354 
 355 module_serio_driver(sunkbd_drv);

/* [<][>][^][v][top][bottom][index][help] */