162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SEGA Dreamcast keyboard driver 462306a36Sopenharmony_ci * Based on drivers/usb/usbkbd.c 562306a36Sopenharmony_ci * Copyright (c) YAEGASHI Takeshi, 2001 662306a36Sopenharmony_ci * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/input.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/timer.h> 1562306a36Sopenharmony_ci#include <linux/maple.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Very simple mutex to ensure proper cleanup */ 1862306a36Sopenharmony_cistatic DEFINE_MUTEX(maple_keyb_mutex); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define NR_SCANCODES 256 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciMODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk"); 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); 2462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct dc_kbd { 2762306a36Sopenharmony_ci struct input_dev *dev; 2862306a36Sopenharmony_ci unsigned short keycode[NR_SCANCODES]; 2962306a36Sopenharmony_ci unsigned char new[8]; 3062306a36Sopenharmony_ci unsigned char old[8]; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const unsigned short dc_kbd_keycode[NR_SCANCODES] = { 3462306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, 3562306a36Sopenharmony_ci KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, 3662306a36Sopenharmony_ci KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, 3762306a36Sopenharmony_ci KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, 3862306a36Sopenharmony_ci KEY_7, KEY_8, KEY_9, KEY_0, KEY_ENTER, KEY_ESC, KEY_BACKSPACE, 3962306a36Sopenharmony_ci KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, 4062306a36Sopenharmony_ci KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, 4162306a36Sopenharmony_ci KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH, 4262306a36Sopenharmony_ci KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, 4362306a36Sopenharmony_ci KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, 4462306a36Sopenharmony_ci KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, 4562306a36Sopenharmony_ci KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, 4662306a36Sopenharmony_ci KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, 4762306a36Sopenharmony_ci KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, 4862306a36Sopenharmony_ci KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, KEY_102ND, 4962306a36Sopenharmony_ci KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, 5062306a36Sopenharmony_ci KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, 5162306a36Sopenharmony_ci KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, KEY_STOP, 5262306a36Sopenharmony_ci KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, 5362306a36Sopenharmony_ci KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 5462306a36Sopenharmony_ci KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, 5562306a36Sopenharmony_ci KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, 5662306a36Sopenharmony_ci KEY_RESERVED, KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, 5762306a36Sopenharmony_ci KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 5862306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 5962306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6062306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6162306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6262306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6362306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6462306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6562306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6662306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6762306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6862306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 6962306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 7062306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 7162306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 7262306a36Sopenharmony_ci KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, 7362306a36Sopenharmony_ci KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, 7462306a36Sopenharmony_ci KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, 7562306a36Sopenharmony_ci KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, 7662306a36Sopenharmony_ci KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, 7762306a36Sopenharmony_ci KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_SCREENLOCK, KEY_REFRESH, 7862306a36Sopenharmony_ci KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void dc_scan_kbd(struct dc_kbd *kbd) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct input_dev *dev = kbd->dev; 8462306a36Sopenharmony_ci void *ptr; 8562306a36Sopenharmony_ci int code, keycode; 8662306a36Sopenharmony_ci int i; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 8962306a36Sopenharmony_ci code = i + 224; 9062306a36Sopenharmony_ci keycode = kbd->keycode[code]; 9162306a36Sopenharmony_ci input_event(dev, EV_MSC, MSC_SCAN, code); 9262306a36Sopenharmony_ci input_report_key(dev, keycode, (kbd->new[0] >> i) & 1); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (i = 2; i < 8; i++) { 9662306a36Sopenharmony_ci ptr = memchr(kbd->new + 2, kbd->old[i], 6); 9762306a36Sopenharmony_ci code = kbd->old[i]; 9862306a36Sopenharmony_ci if (code > 3 && ptr == NULL) { 9962306a36Sopenharmony_ci keycode = kbd->keycode[code]; 10062306a36Sopenharmony_ci if (keycode) { 10162306a36Sopenharmony_ci input_event(dev, EV_MSC, MSC_SCAN, code); 10262306a36Sopenharmony_ci input_report_key(dev, keycode, 0); 10362306a36Sopenharmony_ci } else 10462306a36Sopenharmony_ci dev_dbg(&dev->dev, 10562306a36Sopenharmony_ci "Unknown key (scancode %#x) released.", 10662306a36Sopenharmony_ci code); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci ptr = memchr(kbd->old + 2, kbd->new[i], 6); 10962306a36Sopenharmony_ci code = kbd->new[i]; 11062306a36Sopenharmony_ci if (code > 3 && ptr) { 11162306a36Sopenharmony_ci keycode = kbd->keycode[code]; 11262306a36Sopenharmony_ci if (keycode) { 11362306a36Sopenharmony_ci input_event(dev, EV_MSC, MSC_SCAN, code); 11462306a36Sopenharmony_ci input_report_key(dev, keycode, 1); 11562306a36Sopenharmony_ci } else 11662306a36Sopenharmony_ci dev_dbg(&dev->dev, 11762306a36Sopenharmony_ci "Unknown key (scancode %#x) pressed.", 11862306a36Sopenharmony_ci code); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci input_sync(dev); 12262306a36Sopenharmony_ci memcpy(kbd->old, kbd->new, 8); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void dc_kbd_callback(struct mapleq *mq) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct maple_device *mapledev = mq->dev; 12862306a36Sopenharmony_ci struct dc_kbd *kbd = maple_get_drvdata(mapledev); 12962306a36Sopenharmony_ci unsigned long *buf = (unsigned long *)(mq->recvbuf->buf); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * We should always get the lock because the only 13362306a36Sopenharmony_ci * time it may be locked is if the driver is in the cleanup phase. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci if (likely(mutex_trylock(&maple_keyb_mutex))) { 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (buf[1] == mapledev->function) { 13862306a36Sopenharmony_ci memcpy(kbd->new, buf + 2, 8); 13962306a36Sopenharmony_ci dc_scan_kbd(kbd); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci mutex_unlock(&maple_keyb_mutex); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int probe_maple_kbd(struct device *dev) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct maple_device *mdev; 14962306a36Sopenharmony_ci struct maple_driver *mdrv; 15062306a36Sopenharmony_ci int i, error; 15162306a36Sopenharmony_ci struct dc_kbd *kbd; 15262306a36Sopenharmony_ci struct input_dev *idev; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mdev = to_maple_dev(dev); 15562306a36Sopenharmony_ci mdrv = to_maple_driver(dev->driver); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); 15862306a36Sopenharmony_ci if (!kbd) { 15962306a36Sopenharmony_ci error = -ENOMEM; 16062306a36Sopenharmony_ci goto fail; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci idev = input_allocate_device(); 16462306a36Sopenharmony_ci if (!idev) { 16562306a36Sopenharmony_ci error = -ENOMEM; 16662306a36Sopenharmony_ci goto fail_idev_alloc; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci kbd->dev = idev; 17062306a36Sopenharmony_ci memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci idev->name = mdev->product_name; 17362306a36Sopenharmony_ci idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); 17462306a36Sopenharmony_ci idev->keycode = kbd->keycode; 17562306a36Sopenharmony_ci idev->keycodesize = sizeof(unsigned short); 17662306a36Sopenharmony_ci idev->keycodemax = ARRAY_SIZE(kbd->keycode); 17762306a36Sopenharmony_ci idev->id.bustype = BUS_HOST; 17862306a36Sopenharmony_ci idev->dev.parent = &mdev->dev; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci for (i = 0; i < NR_SCANCODES; i++) 18162306a36Sopenharmony_ci __set_bit(dc_kbd_keycode[i], idev->keybit); 18262306a36Sopenharmony_ci __clear_bit(KEY_RESERVED, idev->keybit); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci input_set_capability(idev, EV_MSC, MSC_SCAN); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci error = input_register_device(idev); 18762306a36Sopenharmony_ci if (error) 18862306a36Sopenharmony_ci goto fail_register; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Maple polling is locked to VBLANK - which may be just 50/s */ 19162306a36Sopenharmony_ci maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, 19262306a36Sopenharmony_ci MAPLE_FUNC_KEYBOARD); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci mdev->driver = mdrv; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci maple_set_drvdata(mdev, kbd); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return error; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cifail_register: 20162306a36Sopenharmony_ci maple_set_drvdata(mdev, NULL); 20262306a36Sopenharmony_ci input_free_device(idev); 20362306a36Sopenharmony_cifail_idev_alloc: 20462306a36Sopenharmony_ci kfree(kbd); 20562306a36Sopenharmony_cifail: 20662306a36Sopenharmony_ci return error; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int remove_maple_kbd(struct device *dev) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct maple_device *mdev = to_maple_dev(dev); 21262306a36Sopenharmony_ci struct dc_kbd *kbd = maple_get_drvdata(mdev); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mutex_lock(&maple_keyb_mutex); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci input_unregister_device(kbd->dev); 21762306a36Sopenharmony_ci kfree(kbd); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci maple_set_drvdata(mdev, NULL); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mutex_unlock(&maple_keyb_mutex); 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic struct maple_driver dc_kbd_driver = { 22662306a36Sopenharmony_ci .function = MAPLE_FUNC_KEYBOARD, 22762306a36Sopenharmony_ci .drv = { 22862306a36Sopenharmony_ci .name = "Dreamcast_keyboard", 22962306a36Sopenharmony_ci .probe = probe_maple_kbd, 23062306a36Sopenharmony_ci .remove = remove_maple_kbd, 23162306a36Sopenharmony_ci }, 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int __init dc_kbd_init(void) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return maple_driver_register(&dc_kbd_driver); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void __exit dc_kbd_exit(void) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci maple_driver_unregister(&dc_kbd_driver); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cimodule_init(dc_kbd_init); 24562306a36Sopenharmony_cimodule_exit(dc_kbd_exit); 246