OSDN Git Service

x68k: Add keyboard driver.
authorYoshinori Sato <ysato@users.sourceforge.jp>
Thu, 11 Feb 2016 17:27:27 +0000 (02:27 +0900)
committerYoshinori Sato <yo-satoh@sios.com>
Thu, 23 Jan 2020 03:39:35 +0000 (12:39 +0900)
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/x68kkbd.c [new file with mode: 0644]
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/x68kmfp.c [new file with mode: 0644]
include/uapi/linux/serio.h

index 8911bc2..14bd45e 100644 (file)
@@ -775,4 +775,13 @@ config KEYBOARD_MTK_PMIC
          To compile this driver as a module, choose M here: the
          module will be called pmic-keys.
 
+config KEYBOARD_X68000
+       tristate "X68000 keyboard"
+       default y
+       depends on X68000
+       select SERIO
+       
+       help
+         Say Y here if you want to use a X68000 keyboard.
+       
 endif
index 9510325..e9cd818 100644 (file)
@@ -68,3 +68,4 @@ obj-$(CONFIG_KEYBOARD_TEGRA)          += tegra-kbc.o
 obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY)    += tm2-touchkey.o
 obj-$(CONFIG_KEYBOARD_TWL4030)         += twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
+obj-$(CONFIG_KEYBOARD_X68000)          += x68kkbd.o
diff --git a/drivers/input/keyboard/x68kkbd.c b/drivers/input/keyboard/x68kkbd.c
new file mode 100644 (file)
index 0000000..8ed30a6
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  Copyright (C) 2016 Yoshinori Sato
+ *
+ *  Based on amikbd.c
+ */
+
+/*
+ * X68000 keyboard driver for Linux/m68k
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#define X68KKBD_LED_EVENT_BIT  0
+#define X68KKBD_REP_EVENT_BIT  1
+
+#define DRIVER_DESC    "X68000 keyboard driver"
+
+MODULE_AUTHOR("Yoshinori Sato <ysato@users.sourceforge.jp>");
+MODULE_DESCRIPTION("X68000 keyboard driver");
+MODULE_LICENSE("GPL");
+
+static const unsigned char x68kkbd_keycode[0x73] = {
+       [1]      = KEY_ESC,
+       [2]      = KEY_1,
+       [3]      = KEY_2,
+       [4]      = KEY_3,
+       [5]      = KEY_4,
+       [6]      = KEY_5,
+       [7]      = KEY_6,
+       [8]      = KEY_7,
+       [9]      = KEY_8,
+       [10]     = KEY_9,
+       [11]     = KEY_0,
+       [12]     = KEY_MINUS,
+       [13]     = KEY_GRAVE,
+       [14]     = KEY_BACKSLASH,
+       [15]     = KEY_BACKSPACE,
+       [16]     = KEY_TAB,
+       [17]     = KEY_Q,
+       [18]     = KEY_W,
+       [19]     = KEY_E,
+       [20]     = KEY_R,
+       [21]     = KEY_T,
+       [22]     = KEY_Y,
+       [23]     = KEY_U,
+       [24]     = KEY_I,
+       [25]     = KEY_O,
+       [26]     = KEY_P,
+       [27]     = KEY_LEFTBRACE,
+       [28]     = KEY_RIGHTBRACE,
+       [29]     = KEY_ENTER,
+       [30]     = KEY_A,
+       [31]     = KEY_S,
+       [32]     = KEY_D,
+       [33]     = KEY_F,
+       [34]     = KEY_G,
+       [35]     = KEY_H,
+       [36]     = KEY_J,
+       [37]     = KEY_K,
+       [38]     = KEY_L,
+       [39]     = KEY_SEMICOLON,
+       [40]     = KEY_APOSTROPHE,
+       [42]     = KEY_Z,
+       [43]     = KEY_X,
+       [44]     = KEY_C,
+       [45]     = KEY_V,
+       [46]     = KEY_B,
+       [47]     = KEY_N,
+       [48]     = KEY_M,
+       [49]     = KEY_COMMA,
+       [50]     = KEY_DOT,
+       [51]     = KEY_SLASH,
+       [53]     = KEY_SPACE,
+       [54]     = KEY_HOME,
+       [55]     = KEY_DELETE,
+       [56]     = KEY_PAGEDOWN,
+       [57]     = KEY_PAGEUP,
+       [58]     = KEY_END,
+       [59]     = KEY_RIGHT,
+       [60]     = KEY_UP,
+       [61]     = KEY_RIGHT,
+       [62]     = KEY_DOWN,
+       [64]     = KEY_KPSLASH,
+       [65]     = KEY_KPASTERISK,
+       [66]     = KEY_KPMINUS,
+       [67]     = KEY_KP7,
+       [68]     = KEY_KP8,
+       [69]     = KEY_KP9,
+       [70]     = KEY_KPPLUS,
+       [71]     = KEY_KP4,
+       [72]     = KEY_KP5,
+       [73]     = KEY_KP6,
+       [74]     = KEY_KPEQUAL,
+       [75]     = KEY_KP1,
+       [76]     = KEY_KP2,
+       [77]     = KEY_KP3,
+       [78]     = KEY_KPENTER,
+       [79]     = KEY_KP0,
+       [80]     = KEY_KPCOMMA,
+       [81]     = KEY_KPDOT,
+       [86]     = KEY_LEFTALT,
+       [87]     = KEY_RIGHTALT,
+       [90]     = KEY_F11,
+       [91]     = KEY_F12,
+       [94]     = KEY_INSERT,
+       [97]     = KEY_PAUSE,
+       [98]     = KEY_SYSRQ,
+       [99]     = KEY_F1,
+       [100]    = KEY_F2,
+       [101]    = KEY_F3,
+       [102]    = KEY_F4,
+       [103]    = KEY_F5,
+       [104]    = KEY_F6,
+       [105]    = KEY_F7,
+       [106]    = KEY_F8,
+       [107]    = KEY_F9,
+       [108]    = KEY_F10,
+       [112]    = KEY_LEFTSHIFT,
+       [113]    = KEY_LEFTCTRL,
+};
+
+struct x68kkbd {
+       struct serio *serio;
+       struct input_dev *dev;
+
+       /* Written only during init */
+       char name[64];
+       char phys[32];
+
+       unsigned short id;
+       DECLARE_BITMAP(force_release_mask, 0x80);
+       unsigned char set;
+       bool translated;
+       bool extra;
+       bool write;
+       bool softrepeat;
+       bool softraw;
+       bool scroll;
+       bool enabled;
+
+       /* Accessed only from interrupt */
+       unsigned char emul;
+       bool resend;
+       bool release;
+       unsigned long xl_bit;
+       unsigned int last;
+       unsigned long time;
+       unsigned long err_count;
+
+       struct delayed_work event_work;
+       unsigned long event_jiffies;
+       unsigned long event_mask;
+
+       /* Serializes reconnect(), attr->set() and event work */
+       struct mutex mutex;
+};
+
+static irqreturn_t x68kkbd_interrupt(struct serio *serio, unsigned char data,
+                                  unsigned int flags)
+{
+       struct x68kkbd *x68kkbd = serio_get_drvdata(serio);
+       struct input_dev *dev = x68kkbd->dev;
+       unsigned char scancode, down;
+
+       scancode = data;
+       down = !(scancode & 0x80);
+       scancode &= 0x7f;
+
+       if (scancode < 0x73) {
+               input_report_key(dev, x68kkbd_keycode[scancode], down);
+               if (data & 0x80)
+                       input_sync(dev);
+       }
+       return IRQ_HANDLED;
+}
+
+static void x68kkbd_command(struct serio *serio, unsigned char cmd)
+{
+       if (serio->write)
+               serio->write(serio, cmd);
+}
+
+static int x68kkbd_set_repeat_rate(struct x68kkbd *x68kkbd)
+{
+       const short period[32] =
+               {  30,  35,  50,  75,  110,  155,  210,  275, 350, 435, 530,
+                  635, 750, 875, 1010, 1155};
+       const short delay[] =
+               { 200, 300, 400, 500, 600, 700, 800, 900,
+                 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700 };
+
+       struct input_dev *dev = x68kkbd->dev;
+       int i = 0, j = 0;
+
+       while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
+               i++;
+       dev->rep[REP_PERIOD] = period[i];
+       x68kkbd_command(x68kkbd->serio, 0x70 | i); 
+
+       while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
+               j++;
+       dev->rep[REP_DELAY] = delay[j];
+
+       x68kkbd_command(x68kkbd->serio, 0x60 | j);
+       return 0;
+}
+
+static int x68kkbd_set_leds(struct x68kkbd *x68kkbd)
+{
+       struct input_dev *dev = x68kkbd->dev;
+       unsigned char led;
+
+       led =  (test_bit(LED_CAPSL,   dev->led) ? 8 : 0);
+       x68kkbd_command(x68kkbd->serio, 0x80 | led);
+       return 0;
+}
+
+static void x68kkbd_event_work(struct work_struct *work)
+{
+       struct x68kkbd *x68kkbd = container_of(work, struct x68kkbd, event_work.work);
+
+       mutex_lock(&x68kkbd->mutex);
+
+       if (test_and_clear_bit(X68KKBD_LED_EVENT_BIT, &x68kkbd->event_mask))
+               x68kkbd_set_leds(x68kkbd);
+
+       if (test_and_clear_bit(X68KKBD_REP_EVENT_BIT, &x68kkbd->event_mask))
+               x68kkbd_set_repeat_rate(x68kkbd);
+
+       mutex_unlock(&x68kkbd->mutex);
+}
+
+static int x68kkbd_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct x68kkbd *x68kkbd;
+       struct input_dev *dev;
+       int err = -ENOMEM;
+       int i;
+
+       x68kkbd = kzalloc(sizeof(struct x68kkbd), GFP_KERNEL);
+       dev = input_allocate_device();
+       if (!x68kkbd || !dev)
+               goto fail1;
+
+       x68kkbd->dev = dev;
+       x68kkbd->serio = serio;
+       x68kkbd->dev->name = "X68000 Keyboard";
+       INIT_DELAYED_WORK(&x68kkbd->event_work, x68kkbd_event_work);
+       mutex_init(&x68kkbd->mutex);
+       dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       for (i = 0; i < sizeof(x68kkbd_keycode); i++)
+               if (x68kkbd_keycode[i])
+                       set_bit(i, dev->keybit);
+
+       serio_set_drvdata(serio, x68kkbd);
+
+       err = serio_open(serio, drv);
+       if (err)
+               goto fail2;
+
+       err = input_register_device(x68kkbd->dev);
+       if (err)
+               goto fail3;
+
+       return 0;
+
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(dev);
+       kfree(x68kkbd);
+       return err;
+}
+
+static struct serio_device_id x68kkbd_serio_ids[] = {
+       {
+               .type   = SERIO_X68K_MFP,
+               .proto  = SERIO_ANY,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { }
+};
+
+MODULE_DEVICE_TABLE(serio, x68kkbd_serio_ids);
+
+static struct serio_driver x68kkbd_drv = {
+       .driver         = {
+               .name   = "x68kkbd",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = x68kkbd_serio_ids,
+       .interrupt      = x68kkbd_interrupt,
+       .connect        = x68kkbd_connect,
+};
+
+static int __init x68kkbd_init(void)
+{
+       return serio_register_driver(&x68kkbd_drv);
+}
+
+static void __exit x68kkbd_exit(void)
+{
+       serio_unregister_driver(&x68kkbd_drv);
+}
+
+module_init(x68kkbd_init);
+module_exit(x68kkbd_exit);
index f3e18f8..10da0a4 100644 (file)
@@ -308,4 +308,11 @@ config USERIO
 
          If you are unsure, say N.
 
+config SERIO_X68K_MFP
+       tristate "SHARP X68000 MFP serial support"
+       depends on X68000 || COMPILE_TEST
+       help
+         This selects support for the MFP serial on
+         SHARP X68000.
+
 endif
index 67950a5..a0579b7 100644 (file)
@@ -32,3 +32,4 @@ obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
 obj-$(CONFIG_SERIO_SUN4I_PS2)  += sun4i-ps2.o
 obj-$(CONFIG_SERIO_GPIO_PS2)   += ps2-gpio.o
 obj-$(CONFIG_USERIO)           += userio.o
+obj-$(CONFIG_SERIO_X68K_MFP)   += x68kmfp.o
diff --git a/drivers/input/serio/x68kmfp.c b/drivers/input/serio/x68kmfp.c
new file mode 100644 (file)
index 0000000..0695faa
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *  X68000 68901 serial driver for Linux
+ *
+ *  Copyright (c) 2016 Yoshinori Sato
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/err.h>
+#include <linux/rcupdate.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+MODULE_AUTHOR("Yoshinori Sato <ysato@users.sourceforge.jp>");
+MODULE_DESCRIPTION("X68000 MFP serial driver");
+MODULE_LICENSE("GPL");
+
+#define MFP_USART (void *)0xe88027
+#define MFP_CSR (MFP_USART + 0)
+#define MFP_UCR (MFP_USART + 2)
+#define MFP_RSR (MFP_USART + 4)
+#define MFP_TSR (MFP_USART + 6)
+#define MFP_UDR (MFP_USART + 8)
+
+#define MFP_RSR_BF     (0x80)
+#define MFP_RSR_OE     (0x40)
+#define MFP_RSR_PE     (0x20)
+#define MFP_RSR_FE     (0x10)
+#define MFP_TSR_BE     (0x80)
+
+#define MFP_CTL_TIMEOUT        1000
+#define MFP_KBD_PHYS_DESC "X68Kbus/serio"
+#define MFP_KBD_IRQ 0x4c
+
+/*
+ * mfp_lock protects serialization between mfp_command and
+ * the interrupt handler.
+ */
+static DEFINE_SPINLOCK(mfp_lock);
+
+/*
+ * Writers to AUX and KBD ports as well as users issuing mfp_command
+ * directly should acquire mfp_mutex (by means of calling
+ * mfp_lock_chip() and mfp_unlock_ship() helpers) to ensure that
+ * they do not disturb each other (unfortunately in many mfp
+ * implementations write to one of the ports will immediately abort
+ * command that is being processed by another port).
+ */
+static DEFINE_MUTEX(mfp_mutex);
+
+struct mfp_port {
+       struct serio *serio;
+       int irq;
+       bool exists;
+       bool driver_bound;
+} mfp_port;
+
+static bool mfp_kbd_irq_registered;
+static struct platform_device *mfp_platform_device;
+static struct notifier_block mfp_kbd_bind_notifier_block;
+
+static irqreturn_t mfp_interrupt(int irq, void *dev_id);
+/*
+ * The mfp_wait_read() and mfp_wait_write functions wait for the mfp to
+ * be ready for reading values from it / writing values to it.
+ * Called always with mfp_lock held.
+ */
+
+static int mfp_wait_write(void)
+{
+       int i = 0;
+
+       while (!(__raw_readb(MFP_TSR) & MFP_TSR_BE) && (i < MFP_CTL_TIMEOUT)) {
+               udelay(50);
+               i++;
+       }
+       return -(i == MFP_CTL_TIMEOUT);
+}
+
+static int mfp_write(struct serio *port, unsigned char c)
+{
+       unsigned long flags;
+       int retval = 0;
+
+       spin_lock_irqsave(&mfp_lock, flags);
+
+       if (!(retval = mfp_wait_write())) {
+               __raw_writeb(c, MFP_UDR);
+       }
+
+       spin_unlock_irqrestore(&mfp_lock, flags);
+
+       return retval;
+}
+
+/*
+ * mfp_interrupt() is the most important function in this driver -
+ * it handles the interrupts from the mfp, and sends incoming bytes
+ * to the upper layers.
+ */
+
+static irqreturn_t mfp_interrupt(int irq, void *dev_id)
+{
+       unsigned long flags;
+       unsigned char rsr, data;
+       unsigned int dfl;
+
+       spin_lock_irqsave(&mfp_lock, flags);
+
+       rsr = __raw_readb(MFP_RSR);
+       data = __raw_readb(MFP_UDR);
+
+
+       dfl = (rsr & (MFP_RSR_PE | MFP_RSR_OE | MFP_RSR_FE));
+
+       spin_unlock_irqrestore(&mfp_lock, flags);
+
+       serio_interrupt(mfp_port.serio, data, dfl);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * mfp_panic_blink() will turn the keyboard LEDs on or off and is called
+ * when kernel panics. Flashing LEDs is useful for users running X who may
+ * not see the console and will help distinguishing panics from "real"
+ * lockups.
+ *
+ * Note that DELAY has a limit of 10ms so we will not get stuck here
+ * waiting for KBC to free up even if KBD interrupt is off
+ */
+
+#define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
+
+static long mfp_panic_blink(int state)
+{
+       long delay = 0;
+       char led;
+
+       led = (state) ? 0x01 | 0xff : 0x80;
+       while (!(__raw_readb(MFP_TSR) & MFP_TSR_BE))
+               DELAY;
+       __raw_writeb(0x80, MFP_UDR);
+       DELAY;
+       while (!(__raw_readb(MFP_TSR) & MFP_TSR_BE))
+               DELAY;
+       DELAY;
+       __raw_writeb(led, MFP_UDR);
+       DELAY;
+       return delay;
+}
+
+#undef DELAY
+
+static int __init mfp_create_kbd_port(void)
+{
+       struct serio *serio;
+
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!serio)
+               return -ENOMEM;
+
+       serio->id.type          = SERIO_X68K_MFP;
+       serio->write            = mfp_write;
+       serio->port_data        = &mfp_port;
+       serio->dev.parent       = &mfp_platform_device->dev;
+       strlcpy(serio->name, "X68000 MFP serial", sizeof(serio->name));
+       strlcpy(serio->phys, MFP_KBD_PHYS_DESC, sizeof(serio->phys));
+
+       mfp_port.serio = serio;
+       mfp_port.irq = MFP_KBD_IRQ;
+
+       return 0;
+}
+
+static void __init mfp_free_kbd_port(void)
+{
+       kfree(mfp_port.serio);
+       mfp_port.serio = NULL;
+}
+
+static void __init mfp_register_ports(void)
+{
+       struct serio *serio = mfp_port.serio;
+
+       if (serio) {
+               printk(KERN_INFO "serio: %s at %#lx irq %d\n",
+                      serio->name,
+                      (unsigned long) MFP_UDR,
+                      mfp_port.irq);
+               serio_register_port(serio);
+               device_set_wakeup_capable(&serio->dev, true);
+       }
+}
+
+static void mfp_unregister_ports(void)
+{
+       if (mfp_port.serio) {
+               serio_unregister_port(mfp_port.serio);
+               mfp_port.serio = NULL;
+       }
+}
+
+static void mfp_free_irqs(void)
+{
+       if (mfp_kbd_irq_registered)
+               free_irq(MFP_KBD_IRQ, mfp_platform_device);
+
+       mfp_kbd_irq_registered = false;
+}
+
+static int __init mfp_setup_kbd(void)
+{
+       int error;
+
+       error = mfp_create_kbd_port();
+       if (error)
+               return error;
+
+       error = request_irq(MFP_KBD_IRQ, mfp_interrupt, IRQF_SHARED,
+                           "mfp-serial", mfp_platform_device);
+       if (error)
+               goto err_free_port;
+
+       mfp_kbd_irq_registered = true;
+       return 0;
+
+ err_free_port:
+       mfp_free_kbd_port();
+       return error;
+}
+
+static int mfp_kbd_bind_notifier(struct notifier_block *nb,
+                                  unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct serio *serio = to_serio_port(dev);
+       struct mfp_port *port = serio->port_data;
+
+       if (serio != mfp_port.serio)
+               return 0;
+
+       switch (action) {
+       case BUS_NOTIFY_BOUND_DRIVER:
+               port->driver_bound = true;
+               break;
+
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               port->driver_bound = false;
+               break;
+       }
+
+       return 0;
+}
+
+static int __init mfp_probe(struct platform_device *dev)
+{
+       int error;
+
+       mfp_platform_device = dev;
+
+       error = mfp_setup_kbd();
+       if (error)
+               goto out_fail;
+/*
+ * Ok, everything is ready, let's register all serio ports
+ */
+       mfp_register_ports();
+
+       return 0;
+
+ out_fail:
+       mfp_free_irqs();
+       mfp_platform_device = NULL;
+
+       return error;
+}
+
+static int mfp_remove(struct platform_device *dev)
+{
+       mfp_unregister_ports();
+       mfp_free_irqs();
+       mfp_platform_device = NULL;
+
+       return 0;
+}
+
+static struct platform_driver mfp_driver = {
+       .driver         = {
+               .name   = "X68K-mfp",
+       },
+       .remove         = mfp_remove,
+};
+
+static struct notifier_block mfp_kbd_bind_notifier_block = {
+       .notifier_call = mfp_kbd_bind_notifier,
+};
+
+static int __init mfp_init(void)
+{
+       struct platform_device *pdev;
+       int err;
+
+       pdev = platform_create_bundle(&mfp_driver, mfp_probe, NULL, 0, NULL, 0);
+       if (IS_ERR(pdev)) {
+               err = PTR_ERR(pdev);
+               goto err_platform_exit;
+       }
+
+       bus_register_notifier(&serio_bus, &mfp_kbd_bind_notifier_block);
+       panic_blink = mfp_panic_blink;
+
+       return 0;
+
+ err_platform_exit:
+       return err;
+}
+
+static void __exit mfp_exit(void)
+{
+       platform_device_unregister(mfp_platform_device);
+       platform_driver_unregister(&mfp_driver);
+
+       bus_unregister_notifier(&serio_bus, &mfp_kbd_bind_notifier_block);
+       panic_blink = NULL;
+}
+
+module_init(mfp_init);
+module_exit(mfp_exit);
index 50e9919..0b576b4 100644 (file)
@@ -83,5 +83,6 @@
 #define SERIO_PULSE8_CEC       0x40
 #define SERIO_RAINSHADOW_CEC   0x41
 #define SERIO_FSIA6B   0x42
+#define SERIO_X68K_MFP 0x43
 
 #endif /* _UAPI_SERIO_H */