1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SEGA Dreamcast keyboard driver
4 * Based on drivers/usb/usbkbd.c
5 * Copyright (c) YAEGASHI Takeshi, 2001
6 * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11 #include <linux/input.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/timer.h>
15 #include <linux/maple.h>
17 /* Very simple mutex to ensure proper cleanup */
18 static DEFINE_MUTEX(maple_keyb_mutex
);
20 #define NR_SCANCODES 256
22 MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk");
23 MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
24 MODULE_LICENSE("GPL");
27 struct input_dev
*dev
;
28 unsigned short keycode
[NR_SCANCODES
];
33 static const unsigned short dc_kbd_keycode
[NR_SCANCODES
] = {
34 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_A
, KEY_B
,
35 KEY_C
, KEY_D
, KEY_E
, KEY_F
, KEY_G
, KEY_H
, KEY_I
, KEY_J
, KEY_K
, KEY_L
,
36 KEY_M
, KEY_N
, KEY_O
, KEY_P
, KEY_Q
, KEY_R
, KEY_S
, KEY_T
, KEY_U
, KEY_V
,
37 KEY_W
, KEY_X
, KEY_Y
, KEY_Z
, KEY_1
, KEY_2
, KEY_3
, KEY_4
, KEY_5
, KEY_6
,
38 KEY_7
, KEY_8
, KEY_9
, KEY_0
, KEY_ENTER
, KEY_ESC
, KEY_BACKSPACE
,
39 KEY_TAB
, KEY_SPACE
, KEY_MINUS
, KEY_EQUAL
, KEY_LEFTBRACE
,
40 KEY_RIGHTBRACE
, KEY_BACKSLASH
, KEY_BACKSLASH
, KEY_SEMICOLON
,
41 KEY_APOSTROPHE
, KEY_GRAVE
, KEY_COMMA
, KEY_DOT
, KEY_SLASH
,
42 KEY_CAPSLOCK
, KEY_F1
, KEY_F2
, KEY_F3
, KEY_F4
, KEY_F5
, KEY_F6
,
43 KEY_F7
, KEY_F8
, KEY_F9
, KEY_F10
, KEY_F11
, KEY_F12
, KEY_SYSRQ
,
44 KEY_SCROLLLOCK
, KEY_PAUSE
, KEY_INSERT
, KEY_HOME
, KEY_PAGEUP
,
45 KEY_DELETE
, KEY_END
, KEY_PAGEDOWN
, KEY_RIGHT
, KEY_LEFT
, KEY_DOWN
,
46 KEY_UP
, KEY_NUMLOCK
, KEY_KPSLASH
, KEY_KPASTERISK
, KEY_KPMINUS
,
47 KEY_KPPLUS
, KEY_KPENTER
, KEY_KP1
, KEY_KP2
, KEY_KP3
, KEY_KP4
, KEY_KP5
,
48 KEY_KP6
, KEY_KP7
, KEY_KP8
, KEY_KP9
, KEY_KP0
, KEY_KPDOT
, KEY_102ND
,
49 KEY_COMPOSE
, KEY_POWER
, KEY_KPEQUAL
, KEY_F13
, KEY_F14
, KEY_F15
,
50 KEY_F16
, KEY_F17
, KEY_F18
, KEY_F19
, KEY_F20
, KEY_F21
, KEY_F22
,
51 KEY_F23
, KEY_F24
, KEY_OPEN
, KEY_HELP
, KEY_PROPS
, KEY_FRONT
, KEY_STOP
,
52 KEY_AGAIN
, KEY_UNDO
, KEY_CUT
, KEY_COPY
, KEY_PASTE
, KEY_FIND
, KEY_MUTE
,
53 KEY_VOLUMEUP
, KEY_VOLUMEDOWN
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
54 KEY_KPCOMMA
, KEY_RESERVED
, KEY_RO
, KEY_KATAKANAHIRAGANA
, KEY_YEN
,
55 KEY_HENKAN
, KEY_MUHENKAN
, KEY_KPJPCOMMA
, KEY_RESERVED
, KEY_RESERVED
,
56 KEY_RESERVED
, KEY_HANGEUL
, KEY_HANJA
, KEY_KATAKANA
, KEY_HIRAGANA
,
57 KEY_ZENKAKUHANKAKU
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
58 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
59 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
60 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
61 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
62 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
63 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
64 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
65 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
66 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
67 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
68 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
69 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
70 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
71 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
72 KEY_RESERVED
, KEY_RESERVED
, KEY_LEFTCTRL
, KEY_LEFTSHIFT
, KEY_LEFTALT
,
73 KEY_LEFTMETA
, KEY_RIGHTCTRL
, KEY_RIGHTSHIFT
, KEY_RIGHTALT
,
74 KEY_RIGHTMETA
, KEY_PLAYPAUSE
, KEY_STOPCD
, KEY_PREVIOUSSONG
,
75 KEY_NEXTSONG
, KEY_EJECTCD
, KEY_VOLUMEUP
, KEY_VOLUMEDOWN
, KEY_MUTE
,
76 KEY_WWW
, KEY_BACK
, KEY_FORWARD
, KEY_STOP
, KEY_FIND
, KEY_SCROLLUP
,
77 KEY_SCROLLDOWN
, KEY_EDIT
, KEY_SLEEP
, KEY_SCREENLOCK
, KEY_REFRESH
,
78 KEY_CALC
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
81 static void dc_scan_kbd(struct dc_kbd
*kbd
)
83 struct input_dev
*dev
= kbd
->dev
;
88 for (i
= 0; i
< 8; i
++) {
90 keycode
= kbd
->keycode
[code
];
91 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
92 input_report_key(dev
, keycode
, (kbd
->new[0] >> i
) & 1);
95 for (i
= 2; i
< 8; i
++) {
96 ptr
= memchr(kbd
->new + 2, kbd
->old
[i
], 6);
98 if (code
> 3 && ptr
== NULL
) {
99 keycode
= kbd
->keycode
[code
];
101 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
102 input_report_key(dev
, keycode
, 0);
105 "Unknown key (scancode %#x) released.",
108 ptr
= memchr(kbd
->old
+ 2, kbd
->new[i
], 6);
110 if (code
> 3 && ptr
) {
111 keycode
= kbd
->keycode
[code
];
113 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
114 input_report_key(dev
, keycode
, 1);
117 "Unknown key (scancode %#x) pressed.",
122 memcpy(kbd
->old
, kbd
->new, 8);
125 static void dc_kbd_callback(struct mapleq
*mq
)
127 struct maple_device
*mapledev
= mq
->dev
;
128 struct dc_kbd
*kbd
= maple_get_drvdata(mapledev
);
129 unsigned long *buf
= (unsigned long *)(mq
->recvbuf
->buf
);
132 * We should always get the lock because the only
133 * time it may be locked is if the driver is in the cleanup phase.
135 scoped_guard(mutex_try
, &maple_keyb_mutex
) {
136 if (buf
[1] == mapledev
->function
) {
137 memcpy(kbd
->new, buf
+ 2, 8);
143 static int probe_maple_kbd(struct device
*dev
)
145 struct maple_device
*mdev
;
146 struct maple_driver
*mdrv
;
149 struct input_dev
*idev
;
151 mdev
= to_maple_dev(dev
);
152 mdrv
= to_maple_driver(dev
->driver
);
154 kbd
= kzalloc(sizeof(*kbd
), GFP_KERNEL
);
160 idev
= input_allocate_device();
163 goto fail_idev_alloc
;
167 memcpy(kbd
->keycode
, dc_kbd_keycode
, sizeof(kbd
->keycode
));
169 idev
->name
= mdev
->product_name
;
170 idev
->evbit
[0] = BIT(EV_KEY
) | BIT(EV_REP
);
171 idev
->keycode
= kbd
->keycode
;
172 idev
->keycodesize
= sizeof(unsigned short);
173 idev
->keycodemax
= ARRAY_SIZE(kbd
->keycode
);
174 idev
->id
.bustype
= BUS_HOST
;
175 idev
->dev
.parent
= &mdev
->dev
;
177 for (i
= 0; i
< NR_SCANCODES
; i
++)
178 __set_bit(dc_kbd_keycode
[i
], idev
->keybit
);
179 __clear_bit(KEY_RESERVED
, idev
->keybit
);
181 input_set_capability(idev
, EV_MSC
, MSC_SCAN
);
183 error
= input_register_device(idev
);
187 /* Maple polling is locked to VBLANK - which may be just 50/s */
188 maple_getcond_callback(mdev
, dc_kbd_callback
, HZ
/50,
189 MAPLE_FUNC_KEYBOARD
);
193 maple_set_drvdata(mdev
, kbd
);
198 maple_set_drvdata(mdev
, NULL
);
199 input_free_device(idev
);
206 static int remove_maple_kbd(struct device
*dev
)
208 struct maple_device
*mdev
= to_maple_dev(dev
);
209 struct dc_kbd
*kbd
= maple_get_drvdata(mdev
);
211 guard(mutex
)(&maple_keyb_mutex
);
213 input_unregister_device(kbd
->dev
);
216 maple_set_drvdata(mdev
, NULL
);
220 static struct maple_driver dc_kbd_driver
= {
221 .function
= MAPLE_FUNC_KEYBOARD
,
223 .name
= "Dreamcast_keyboard",
224 .probe
= probe_maple_kbd
,
225 .remove
= remove_maple_kbd
,
229 static int __init
dc_kbd_init(void)
231 return maple_driver_register(&dc_kbd_driver
);
234 static void __exit
dc_kbd_exit(void)
236 maple_driver_unregister(&dc_kbd_driver
);
239 module_init(dc_kbd_init
);
240 module_exit(dc_kbd_exit
);