2 * SEGA Dreamcast keyboard driver
3 * Based on drivers/usb/usbkbd.c
4 * Copyright (c) YAEGASHI Takeshi, 2001
5 * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <linux/kernel.h>
24 #include <linux/slab.h>
25 #include <linux/input.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/timer.h>
29 #include <linux/maple.h>
31 /* Very simple mutex to ensure proper cleanup */
32 static DEFINE_MUTEX(maple_keyb_mutex
);
34 #define NR_SCANCODES 256
36 MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk");
37 MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
38 MODULE_LICENSE("GPL");
41 struct input_dev
*dev
;
42 unsigned short keycode
[NR_SCANCODES
];
47 static const unsigned short dc_kbd_keycode
[NR_SCANCODES
] = {
48 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_A
, KEY_B
,
49 KEY_C
, KEY_D
, KEY_E
, KEY_F
, KEY_G
, KEY_H
, KEY_I
, KEY_J
, KEY_K
, KEY_L
,
50 KEY_M
, KEY_N
, KEY_O
, KEY_P
, KEY_Q
, KEY_R
, KEY_S
, KEY_T
, KEY_U
, KEY_V
,
51 KEY_W
, KEY_X
, KEY_Y
, KEY_Z
, KEY_1
, KEY_2
, KEY_3
, KEY_4
, KEY_5
, KEY_6
,
52 KEY_7
, KEY_8
, KEY_9
, KEY_0
, KEY_ENTER
, KEY_ESC
, KEY_BACKSPACE
,
53 KEY_TAB
, KEY_SPACE
, KEY_MINUS
, KEY_EQUAL
, KEY_LEFTBRACE
,
54 KEY_RIGHTBRACE
, KEY_BACKSLASH
, KEY_BACKSLASH
, KEY_SEMICOLON
,
55 KEY_APOSTROPHE
, KEY_GRAVE
, KEY_COMMA
, KEY_DOT
, KEY_SLASH
,
56 KEY_CAPSLOCK
, KEY_F1
, KEY_F2
, KEY_F3
, KEY_F4
, KEY_F5
, KEY_F6
,
57 KEY_F7
, KEY_F8
, KEY_F9
, KEY_F10
, KEY_F11
, KEY_F12
, KEY_SYSRQ
,
58 KEY_SCROLLLOCK
, KEY_PAUSE
, KEY_INSERT
, KEY_HOME
, KEY_PAGEUP
,
59 KEY_DELETE
, KEY_END
, KEY_PAGEDOWN
, KEY_RIGHT
, KEY_LEFT
, KEY_DOWN
,
60 KEY_UP
, KEY_NUMLOCK
, KEY_KPSLASH
, KEY_KPASTERISK
, KEY_KPMINUS
,
61 KEY_KPPLUS
, KEY_KPENTER
, KEY_KP1
, KEY_KP2
, KEY_KP3
, KEY_KP4
, KEY_KP5
,
62 KEY_KP6
, KEY_KP7
, KEY_KP8
, KEY_KP9
, KEY_KP0
, KEY_KPDOT
, KEY_102ND
,
63 KEY_COMPOSE
, KEY_POWER
, KEY_KPEQUAL
, KEY_F13
, KEY_F14
, KEY_F15
,
64 KEY_F16
, KEY_F17
, KEY_F18
, KEY_F19
, KEY_F20
, KEY_F21
, KEY_F22
,
65 KEY_F23
, KEY_F24
, KEY_OPEN
, KEY_HELP
, KEY_PROPS
, KEY_FRONT
, KEY_STOP
,
66 KEY_AGAIN
, KEY_UNDO
, KEY_CUT
, KEY_COPY
, KEY_PASTE
, KEY_FIND
, KEY_MUTE
,
67 KEY_VOLUMEUP
, KEY_VOLUMEDOWN
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
68 KEY_KPCOMMA
, KEY_RESERVED
, KEY_RO
, KEY_KATAKANAHIRAGANA
, KEY_YEN
,
69 KEY_HENKAN
, KEY_MUHENKAN
, KEY_KPJPCOMMA
, KEY_RESERVED
, KEY_RESERVED
,
70 KEY_RESERVED
, KEY_HANGEUL
, KEY_HANJA
, KEY_KATAKANA
, KEY_HIRAGANA
,
71 KEY_ZENKAKUHANKAKU
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
72 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
73 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
74 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
75 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
76 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
77 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
78 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
79 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
80 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
81 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
82 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
83 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
84 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
85 KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
,
86 KEY_RESERVED
, KEY_RESERVED
, KEY_LEFTCTRL
, KEY_LEFTSHIFT
, KEY_LEFTALT
,
87 KEY_LEFTMETA
, KEY_RIGHTCTRL
, KEY_RIGHTSHIFT
, KEY_RIGHTALT
,
88 KEY_RIGHTMETA
, KEY_PLAYPAUSE
, KEY_STOPCD
, KEY_PREVIOUSSONG
,
89 KEY_NEXTSONG
, KEY_EJECTCD
, KEY_VOLUMEUP
, KEY_VOLUMEDOWN
, KEY_MUTE
,
90 KEY_WWW
, KEY_BACK
, KEY_FORWARD
, KEY_STOP
, KEY_FIND
, KEY_SCROLLUP
,
91 KEY_SCROLLDOWN
, KEY_EDIT
, KEY_SLEEP
, KEY_SCREENLOCK
, KEY_REFRESH
,
92 KEY_CALC
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
, KEY_RESERVED
95 static void dc_scan_kbd(struct dc_kbd
*kbd
)
97 struct input_dev
*dev
= kbd
->dev
;
102 for (i
= 0; i
< 8; i
++) {
104 keycode
= kbd
->keycode
[code
];
105 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
106 input_report_key(dev
, keycode
, (kbd
->new[0] >> i
) & 1);
109 for (i
= 2; i
< 8; i
++) {
110 ptr
= memchr(kbd
->new + 2, kbd
->old
[i
], 6);
112 if (code
> 3 && ptr
== NULL
) {
113 keycode
= kbd
->keycode
[code
];
115 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
116 input_report_key(dev
, keycode
, 0);
119 "Unknown key (scancode %#x) released.",
122 ptr
= memchr(kbd
->old
+ 2, kbd
->new[i
], 6);
124 if (code
> 3 && ptr
) {
125 keycode
= kbd
->keycode
[code
];
127 input_event(dev
, EV_MSC
, MSC_SCAN
, code
);
128 input_report_key(dev
, keycode
, 1);
131 "Unknown key (scancode %#x) pressed.",
136 memcpy(kbd
->old
, kbd
->new, 8);
139 static void dc_kbd_callback(struct mapleq
*mq
)
141 struct maple_device
*mapledev
= mq
->dev
;
142 struct dc_kbd
*kbd
= maple_get_drvdata(mapledev
);
143 unsigned long *buf
= (unsigned long *)(mq
->recvbuf
->buf
);
146 * We should always get the lock because the only
147 * time it may be locked is if the driver is in the cleanup phase.
149 if (likely(mutex_trylock(&maple_keyb_mutex
))) {
151 if (buf
[1] == mapledev
->function
) {
152 memcpy(kbd
->new, buf
+ 2, 8);
156 mutex_unlock(&maple_keyb_mutex
);
160 static int probe_maple_kbd(struct device
*dev
)
162 struct maple_device
*mdev
;
163 struct maple_driver
*mdrv
;
166 struct input_dev
*idev
;
168 mdev
= to_maple_dev(dev
);
169 mdrv
= to_maple_driver(dev
->driver
);
171 kbd
= kzalloc(sizeof(struct dc_kbd
), GFP_KERNEL
);
177 idev
= input_allocate_device();
180 goto fail_idev_alloc
;
184 memcpy(kbd
->keycode
, dc_kbd_keycode
, sizeof(kbd
->keycode
));
186 idev
->name
= mdev
->product_name
;
187 idev
->evbit
[0] = BIT(EV_KEY
) | BIT(EV_REP
);
188 idev
->keycode
= kbd
->keycode
;
189 idev
->keycodesize
= sizeof(unsigned short);
190 idev
->keycodemax
= ARRAY_SIZE(kbd
->keycode
);
191 idev
->id
.bustype
= BUS_HOST
;
192 idev
->dev
.parent
= &mdev
->dev
;
194 for (i
= 0; i
< NR_SCANCODES
; i
++)
195 __set_bit(dc_kbd_keycode
[i
], idev
->keybit
);
196 __clear_bit(KEY_RESERVED
, idev
->keybit
);
198 input_set_capability(idev
, EV_MSC
, MSC_SCAN
);
200 error
= input_register_device(idev
);
204 /* Maple polling is locked to VBLANK - which may be just 50/s */
205 maple_getcond_callback(mdev
, dc_kbd_callback
, HZ
/50,
206 MAPLE_FUNC_KEYBOARD
);
210 maple_set_drvdata(mdev
, kbd
);
215 maple_set_drvdata(mdev
, NULL
);
216 input_free_device(idev
);
223 static int remove_maple_kbd(struct device
*dev
)
225 struct maple_device
*mdev
= to_maple_dev(dev
);
226 struct dc_kbd
*kbd
= maple_get_drvdata(mdev
);
228 mutex_lock(&maple_keyb_mutex
);
230 input_unregister_device(kbd
->dev
);
233 maple_set_drvdata(mdev
, NULL
);
235 mutex_unlock(&maple_keyb_mutex
);
239 static struct maple_driver dc_kbd_driver
= {
240 .function
= MAPLE_FUNC_KEYBOARD
,
242 .name
= "Dreamcast_keyboard",
243 .probe
= probe_maple_kbd
,
244 .remove
= remove_maple_kbd
,
248 static int __init
dc_kbd_init(void)
250 return maple_driver_register(&dc_kbd_driver
);
253 static void __exit
dc_kbd_exit(void)
255 maple_driver_unregister(&dc_kbd_driver
);
258 module_init(dc_kbd_init
);
259 module_exit(dc_kbd_exit
);