linux/drivers/input/keyboard/newtonkbd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) 2000 Justin Cormack
   4 */
   5
   6/*
   7 * Newton keyboard driver for Linux
   8 */
   9
  10/*
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/module.h>
  15#include <linux/input.h>
  16#include <linux/serio.h>
  17
  18#define DRIVER_DESC     "Newton keyboard driver"
  19
  20MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
  21MODULE_DESCRIPTION(DRIVER_DESC);
  22MODULE_LICENSE("GPL");
  23
  24#define NKBD_KEY        0x7f
  25#define NKBD_PRESS      0x80
  26
  27static unsigned char nkbd_keycode[128] = {
  28        KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
  29        KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
  30        KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
  31        KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O,
  32        KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE,
  33        KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT,
  34        KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA,
  35        KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0,
  36        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  37        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  38        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  39        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  40        KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
  41};
  42
  43struct nkbd {
  44        unsigned char keycode[128];
  45        struct input_dev *dev;
  46        struct serio *serio;
  47        char phys[32];
  48};
  49
  50static irqreturn_t nkbd_interrupt(struct serio *serio,
  51                unsigned char data, unsigned int flags)
  52{
  53        struct nkbd *nkbd = serio_get_drvdata(serio);
  54
  55        /* invalid scan codes are probably the init sequence, so we ignore them */
  56        if (nkbd->keycode[data & NKBD_KEY]) {
  57                input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
  58                input_sync(nkbd->dev);
  59        }
  60
  61        else if (data == 0xe7) /* end of init sequence */
  62                printk(KERN_INFO "input: %s on %s\n", nkbd->dev->name, serio->phys);
  63        return IRQ_HANDLED;
  64
  65}
  66
  67static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
  68{
  69        struct nkbd *nkbd;
  70        struct input_dev *input_dev;
  71        int err = -ENOMEM;
  72        int i;
  73
  74        nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL);
  75        input_dev = input_allocate_device();
  76        if (!nkbd || !input_dev)
  77                goto fail1;
  78
  79        nkbd->serio = serio;
  80        nkbd->dev = input_dev;
  81        snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys);
  82        memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
  83
  84        input_dev->name = "Newton Keyboard";
  85        input_dev->phys = nkbd->phys;
  86        input_dev->id.bustype = BUS_RS232;
  87        input_dev->id.vendor = SERIO_NEWTON;
  88        input_dev->id.product = 0x0001;
  89        input_dev->id.version = 0x0100;
  90        input_dev->dev.parent = &serio->dev;
  91
  92        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
  93        input_dev->keycode = nkbd->keycode;
  94        input_dev->keycodesize = sizeof(unsigned char);
  95        input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode);
  96        for (i = 0; i < 128; i++)
  97                set_bit(nkbd->keycode[i], input_dev->keybit);
  98        clear_bit(0, input_dev->keybit);
  99
 100        serio_set_drvdata(serio, nkbd);
 101
 102        err = serio_open(serio, drv);
 103        if (err)
 104                goto fail2;
 105
 106        err = input_register_device(nkbd->dev);
 107        if (err)
 108                goto fail3;
 109
 110        return 0;
 111
 112 fail3: serio_close(serio);
 113 fail2: serio_set_drvdata(serio, NULL);
 114 fail1: input_free_device(input_dev);
 115        kfree(nkbd);
 116        return err;
 117}
 118
 119static void nkbd_disconnect(struct serio *serio)
 120{
 121        struct nkbd *nkbd = serio_get_drvdata(serio);
 122
 123        serio_close(serio);
 124        serio_set_drvdata(serio, NULL);
 125        input_unregister_device(nkbd->dev);
 126        kfree(nkbd);
 127}
 128
 129static const struct serio_device_id nkbd_serio_ids[] = {
 130        {
 131                .type   = SERIO_RS232,
 132                .proto  = SERIO_NEWTON,
 133                .id     = SERIO_ANY,
 134                .extra  = SERIO_ANY,
 135        },
 136        { 0 }
 137};
 138
 139MODULE_DEVICE_TABLE(serio, nkbd_serio_ids);
 140
 141static struct serio_driver nkbd_drv = {
 142        .driver         = {
 143                .name   = "newtonkbd",
 144        },
 145        .description    = DRIVER_DESC,
 146        .id_table       = nkbd_serio_ids,
 147        .interrupt      = nkbd_interrupt,
 148        .connect        = nkbd_connect,
 149        .disconnect     = nkbd_disconnect,
 150};
 151
 152module_serio_driver(nkbd_drv);
 153