Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Stowaway keyboard driver for Linux
0004  */
0005 
0006 /*
0007  *  Copyright (c) 2006 Marek Vasut
0008  *
0009  *  Based on Newton keyboard driver for Linux
0010  *  by Justin Cormack
0011  */
0012 
0013 /*
0014  */
0015 
0016 #include <linux/slab.h>
0017 #include <linux/module.h>
0018 #include <linux/input.h>
0019 #include <linux/serio.h>
0020 
0021 #define DRIVER_DESC "Stowaway keyboard driver"
0022 
0023 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
0024 MODULE_DESCRIPTION(DRIVER_DESC);
0025 MODULE_LICENSE("GPL");
0026 
0027 #define SKBD_KEY_MASK   0x7f
0028 #define SKBD_RELEASE    0x80
0029 
0030 static unsigned char skbd_keycode[128] = {
0031     KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7,
0032     0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE,
0033     KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE,
0034     KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0,
0035     0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0,
0036     0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N,
0037     KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC,
0038     KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P,
0039     KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
0040     KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT,
0041     KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT,  0, 0, 0,
0042     KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0,
0043     0, 0, 0, 0, 0, 0, 0, 0,
0044     0, 0, 0, 0, 0, 0, 0, 0,
0045     0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7,
0046     KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0
0047 };
0048 
0049 struct skbd {
0050     unsigned char keycode[128];
0051     struct input_dev *dev;
0052     struct serio *serio;
0053     char phys[32];
0054 };
0055 
0056 static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data,
0057                   unsigned int flags)
0058 {
0059     struct skbd *skbd = serio_get_drvdata(serio);
0060     struct input_dev *dev = skbd->dev;
0061 
0062     if (skbd->keycode[data & SKBD_KEY_MASK]) {
0063         input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK],
0064                  !(data & SKBD_RELEASE));
0065         input_sync(dev);
0066     }
0067 
0068     return IRQ_HANDLED;
0069 }
0070 
0071 static int skbd_connect(struct serio *serio, struct serio_driver *drv)
0072 {
0073     struct skbd *skbd;
0074     struct input_dev *input_dev;
0075     int err = -ENOMEM;
0076     int i;
0077 
0078     skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL);
0079     input_dev = input_allocate_device();
0080     if (!skbd || !input_dev)
0081         goto fail1;
0082 
0083     skbd->serio = serio;
0084     skbd->dev = input_dev;
0085     snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys);
0086     memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode));
0087 
0088     input_dev->name = "Stowaway Keyboard";
0089     input_dev->phys = skbd->phys;
0090     input_dev->id.bustype = BUS_RS232;
0091     input_dev->id.vendor = SERIO_STOWAWAY;
0092     input_dev->id.product = 0x0001;
0093     input_dev->id.version = 0x0100;
0094     input_dev->dev.parent = &serio->dev;
0095 
0096     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
0097     input_dev->keycode = skbd->keycode;
0098     input_dev->keycodesize = sizeof(unsigned char);
0099     input_dev->keycodemax = ARRAY_SIZE(skbd_keycode);
0100     for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++)
0101         set_bit(skbd_keycode[i], input_dev->keybit);
0102     clear_bit(0, input_dev->keybit);
0103 
0104     serio_set_drvdata(serio, skbd);
0105 
0106     err = serio_open(serio, drv);
0107     if (err)
0108         goto fail2;
0109 
0110     err = input_register_device(skbd->dev);
0111     if (err)
0112         goto fail3;
0113 
0114     return 0;
0115 
0116  fail3: serio_close(serio);
0117  fail2: serio_set_drvdata(serio, NULL);
0118  fail1: input_free_device(input_dev);
0119     kfree(skbd);
0120     return err;
0121 }
0122 
0123 static void skbd_disconnect(struct serio *serio)
0124 {
0125     struct skbd *skbd = serio_get_drvdata(serio);
0126 
0127     serio_close(serio);
0128     serio_set_drvdata(serio, NULL);
0129     input_unregister_device(skbd->dev);
0130     kfree(skbd);
0131 }
0132 
0133 static const struct serio_device_id skbd_serio_ids[] = {
0134     {
0135         .type   = SERIO_RS232,
0136         .proto  = SERIO_STOWAWAY,
0137         .id = SERIO_ANY,
0138         .extra  = SERIO_ANY,
0139     },
0140     { 0 }
0141 };
0142 
0143 MODULE_DEVICE_TABLE(serio, skbd_serio_ids);
0144 
0145 static struct serio_driver skbd_drv = {
0146     .driver     = {
0147         .name   = "stowaway",
0148     },
0149     .description    = DRIVER_DESC,
0150     .id_table   = skbd_serio_ids,
0151     .interrupt  = skbd_interrupt,
0152     .connect    = skbd_connect,
0153     .disconnect = skbd_disconnect,
0154 };
0155 
0156 module_serio_driver(skbd_drv);