From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- drivers/input/keyboard/maple_keyb.c | 260 ++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 drivers/input/keyboard/maple_keyb.c (limited to 'drivers/input/keyboard/maple_keyb.c') diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 000000000..5aa2361ae --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c @@ -0,0 +1,260 @@ +/* + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + * Copyright (c) YAEGASHI Takeshi, 2001 + * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009 + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Very simple mutex to ensure proper cleanup */ +static DEFINE_MUTEX(maple_keyb_mutex); + +#define NR_SCANCODES 256 + +MODULE_AUTHOR("Adrian McMenamin dev; + void *ptr; + int code, keycode; + int i; + + for (i = 0; i < 8; i++) { + code = i + 224; + keycode = kbd->keycode[code]; + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, (kbd->new[0] >> i) & 1); + } + + for (i = 2; i < 8; i++) { + ptr = memchr(kbd->new + 2, kbd->old[i], 6); + code = kbd->old[i]; + if (code > 3 && ptr == NULL) { + keycode = kbd->keycode[code]; + if (keycode) { + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, 0); + } else + dev_dbg(&dev->dev, + "Unknown key (scancode %#x) released.", + code); + } + ptr = memchr(kbd->old + 2, kbd->new[i], 6); + code = kbd->new[i]; + if (code > 3 && ptr) { + keycode = kbd->keycode[code]; + if (keycode) { + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, 1); + } else + dev_dbg(&dev->dev, + "Unknown key (scancode %#x) pressed.", + code); + } + } + input_sync(dev); + memcpy(kbd->old, kbd->new, 8); +} + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = maple_get_drvdata(mapledev); + unsigned long *buf = (unsigned long *)(mq->recvbuf->buf); + + /* + * We should always get the lock because the only + * time it may be locked is if the driver is in the cleanup phase. + */ + if (likely(mutex_trylock(&maple_keyb_mutex))) { + + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf + 2, 8); + dc_scan_kbd(kbd); + } + + mutex_unlock(&maple_keyb_mutex); + } +} + +static int probe_maple_kbd(struct device *dev) +{ + struct maple_device *mdev; + struct maple_driver *mdrv; + int i, error; + struct dc_kbd *kbd; + struct input_dev *idev; + + mdev = to_maple_dev(dev); + mdrv = to_maple_driver(dev->driver); + + kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + if (!kbd) { + error = -ENOMEM; + goto fail; + } + + idev = input_allocate_device(); + if (!idev) { + error = -ENOMEM; + goto fail_idev_alloc; + } + + kbd->dev = idev; + memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); + + idev->name = mdev->product_name; + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + idev->keycode = kbd->keycode; + idev->keycodesize = sizeof(unsigned short); + idev->keycodemax = ARRAY_SIZE(kbd->keycode); + idev->id.bustype = BUS_HOST; + idev->dev.parent = &mdev->dev; + + for (i = 0; i < NR_SCANCODES; i++) + __set_bit(dc_kbd_keycode[i], idev->keybit); + __clear_bit(KEY_RESERVED, idev->keybit); + + input_set_capability(idev, EV_MSC, MSC_SCAN); + input_set_drvdata(idev, kbd); + + error = input_register_device(idev); + if (error) + goto fail_register; + + /* Maple polling is locked to VBLANK - which may be just 50/s */ + maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, + MAPLE_FUNC_KEYBOARD); + + mdev->driver = mdrv; + + maple_set_drvdata(mdev, kbd); + + return error; + +fail_register: + maple_set_drvdata(mdev, NULL); + input_free_device(idev); +fail_idev_alloc: + kfree(kbd); +fail: + return error; +} + +static int remove_maple_kbd(struct device *dev) +{ + struct maple_device *mdev = to_maple_dev(dev); + struct dc_kbd *kbd = maple_get_drvdata(mdev); + + mutex_lock(&maple_keyb_mutex); + + input_unregister_device(kbd->dev); + kfree(kbd); + + maple_set_drvdata(mdev, NULL); + + mutex_unlock(&maple_keyb_mutex); + return 0; +} + +static struct maple_driver dc_kbd_driver = { + .function = MAPLE_FUNC_KEYBOARD, + .drv = { + .name = "Dreamcast_keyboard", + .probe = probe_maple_kbd, + .remove = remove_maple_kbd, + }, +}; + +static int __init dc_kbd_init(void) +{ + return maple_driver_register(&dc_kbd_driver); +} + +static void __exit dc_kbd_exit(void) +{ + maple_driver_unregister(&dc_kbd_driver); +} + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); -- cgit v1.2.3-54-g00ecf