xref: /freebsd/sys/dev/adb/adb_kbd.c (revision b4dbc59983da8183f4903279f079a2ad354a1011)
1b4dbc599SNathan Whitehorn /*-
2b4dbc599SNathan Whitehorn  * Copyright (C) 2008 Nathan Whitehorn
3b4dbc599SNathan Whitehorn  * All rights reserved.
4b4dbc599SNathan Whitehorn  *
5b4dbc599SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
6b4dbc599SNathan Whitehorn  * modification, are permitted provided that the following conditions
7b4dbc599SNathan Whitehorn  * are met:
8b4dbc599SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
9b4dbc599SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
10b4dbc599SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
11b4dbc599SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
12b4dbc599SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
13b4dbc599SNathan Whitehorn  *
14b4dbc599SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15b4dbc599SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16b4dbc599SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17b4dbc599SNathan Whitehorn  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18b4dbc599SNathan Whitehorn  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19b4dbc599SNathan Whitehorn  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20b4dbc599SNathan Whitehorn  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21b4dbc599SNathan Whitehorn  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22b4dbc599SNathan Whitehorn  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23b4dbc599SNathan Whitehorn  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24b4dbc599SNathan Whitehorn  *
25b4dbc599SNathan Whitehorn  * $FreeBSD$
26b4dbc599SNathan Whitehorn  */
27b4dbc599SNathan Whitehorn 
28b4dbc599SNathan Whitehorn #include <sys/cdefs.h>
29b4dbc599SNathan Whitehorn #include <sys/param.h>
30b4dbc599SNathan Whitehorn #include <sys/systm.h>
31b4dbc599SNathan Whitehorn #include <sys/module.h>
32b4dbc599SNathan Whitehorn #include <sys/bus.h>
33b4dbc599SNathan Whitehorn #include <sys/conf.h>
34b4dbc599SNathan Whitehorn #include <sys/kbio.h>
35b4dbc599SNathan Whitehorn #include <sys/condvar.h>
36b4dbc599SNathan Whitehorn #include <sys/callout.h>
37b4dbc599SNathan Whitehorn #include <sys/kernel.h>
38b4dbc599SNathan Whitehorn 
39b4dbc599SNathan Whitehorn #include <machine/bus.h>
40b4dbc599SNathan Whitehorn 
41b4dbc599SNathan Whitehorn #include "opt_kbd.h"
42b4dbc599SNathan Whitehorn #include <dev/kbd/kbdreg.h>
43b4dbc599SNathan Whitehorn #include <dev/kbd/kbdtables.h>
44b4dbc599SNathan Whitehorn 
45b4dbc599SNathan Whitehorn #include <vm/vm.h>
46b4dbc599SNathan Whitehorn #include <vm/pmap.h>
47b4dbc599SNathan Whitehorn 
48b4dbc599SNathan Whitehorn #include "adb.h"
49b4dbc599SNathan Whitehorn 
50b4dbc599SNathan Whitehorn #define KBD_DRIVER_NAME "akbd"
51b4dbc599SNathan Whitehorn 
52b4dbc599SNathan Whitehorn #define AKBD_EMULATE_ATKBD 1
53b4dbc599SNathan Whitehorn 
54b4dbc599SNathan Whitehorn static int adb_kbd_probe(device_t dev);
55b4dbc599SNathan Whitehorn static int adb_kbd_attach(device_t dev);
56b4dbc599SNathan Whitehorn static int adb_kbd_detach(device_t dev);
57b4dbc599SNathan Whitehorn static void akbd_repeat(void *xsc);
58b4dbc599SNathan Whitehorn 
59b4dbc599SNathan Whitehorn static u_int adb_kbd_receive_packet(device_t dev, u_char status,
60b4dbc599SNathan Whitehorn 	u_char command, u_char reg, int len, u_char *data);
61b4dbc599SNathan Whitehorn 
62b4dbc599SNathan Whitehorn struct adb_kbd_softc {
63b4dbc599SNathan Whitehorn 	keyboard_t sc_kbd;
64b4dbc599SNathan Whitehorn 
65b4dbc599SNathan Whitehorn 	device_t sc_dev;
66b4dbc599SNathan Whitehorn 	struct mtx sc_mutex;
67b4dbc599SNathan Whitehorn 	struct cv  sc_cv;
68b4dbc599SNathan Whitehorn 
69b4dbc599SNathan Whitehorn 	int sc_mode;
70b4dbc599SNathan Whitehorn 	int sc_state;
71b4dbc599SNathan Whitehorn 
72b4dbc599SNathan Whitehorn 	int have_led_control;
73b4dbc599SNathan Whitehorn 
74b4dbc599SNathan Whitehorn 	uint8_t buffer[8];
75b4dbc599SNathan Whitehorn 	volatile int buffers;
76b4dbc599SNathan Whitehorn 
77b4dbc599SNathan Whitehorn 	struct callout sc_repeater;
78b4dbc599SNathan Whitehorn 	int sc_repeatstart;
79b4dbc599SNathan Whitehorn 	int sc_repeatcontinue;
80b4dbc599SNathan Whitehorn 	uint8_t last_press;
81b4dbc599SNathan Whitehorn };
82b4dbc599SNathan Whitehorn 
83b4dbc599SNathan Whitehorn static device_method_t adb_kbd_methods[] = {
84b4dbc599SNathan Whitehorn 	/* Device interface */
85b4dbc599SNathan Whitehorn 	DEVMETHOD(device_probe,         adb_kbd_probe),
86b4dbc599SNathan Whitehorn         DEVMETHOD(device_attach,        adb_kbd_attach),
87b4dbc599SNathan Whitehorn         DEVMETHOD(device_detach,        adb_kbd_detach),
88b4dbc599SNathan Whitehorn         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
89b4dbc599SNathan Whitehorn         DEVMETHOD(device_suspend,       bus_generic_suspend),
90b4dbc599SNathan Whitehorn         DEVMETHOD(device_resume,        bus_generic_resume),
91b4dbc599SNathan Whitehorn 
92b4dbc599SNathan Whitehorn 	/* ADB interface */
93b4dbc599SNathan Whitehorn 	DEVMETHOD(adb_receive_packet,	adb_kbd_receive_packet),
94b4dbc599SNathan Whitehorn 
95b4dbc599SNathan Whitehorn 	{ 0, 0 }
96b4dbc599SNathan Whitehorn };
97b4dbc599SNathan Whitehorn 
98b4dbc599SNathan Whitehorn static driver_t adb_kbd_driver = {
99b4dbc599SNathan Whitehorn 	"akbd",
100b4dbc599SNathan Whitehorn 	adb_kbd_methods,
101b4dbc599SNathan Whitehorn 	sizeof(struct adb_kbd_softc),
102b4dbc599SNathan Whitehorn };
103b4dbc599SNathan Whitehorn 
104b4dbc599SNathan Whitehorn static devclass_t adb_kbd_devclass;
105b4dbc599SNathan Whitehorn 
106b4dbc599SNathan Whitehorn DRIVER_MODULE(akbd, adb, adb_kbd_driver, adb_kbd_devclass, 0, 0);
107b4dbc599SNathan Whitehorn 
108b4dbc599SNathan Whitehorn static const uint8_t adb_to_at_scancode_map[128] = { 30, 31, 32, 33, 35, 34,
109b4dbc599SNathan Whitehorn 	44, 45, 46, 47, 0, 48, 16, 17, 18, 19, 21, 20, 2, 3, 4, 5, 7, 6, 13,
110b4dbc599SNathan Whitehorn 	10, 8, 12, 9, 11, 27, 24, 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43,
111b4dbc599SNathan Whitehorn 	51, 53, 49, 50, 52, 15, 57, 41, 14, 0, 1, 29, 0, 42, 58, 56, 97, 98,
112b4dbc599SNathan Whitehorn 	100, 95, 0, 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 91, 89, 0, 74, 13, 0,
113b4dbc599SNathan Whitehorn 	0, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73, 0, 0, 0, 63, 64, 65, 61,
114b4dbc599SNathan Whitehorn 	66, 67, 0, 87, 0, 105, 0, 70, 0, 68, 0, 88, 0, 107, 102, 94, 96, 103,
115b4dbc599SNathan Whitehorn 	62, 99, 60, 101, 59, 54, 93, 90, 0, 0 };
116b4dbc599SNathan Whitehorn 
117b4dbc599SNathan Whitehorn /* keyboard driver declaration */
118b4dbc599SNathan Whitehorn static int              akbd_configure(int flags);
119b4dbc599SNathan Whitehorn static kbd_probe_t      akbd_probe;
120b4dbc599SNathan Whitehorn static kbd_init_t       akbd_init;
121b4dbc599SNathan Whitehorn static kbd_term_t       akbd_term;
122b4dbc599SNathan Whitehorn static kbd_intr_t       akbd_interrupt;
123b4dbc599SNathan Whitehorn static kbd_test_if_t    akbd_test_if;
124b4dbc599SNathan Whitehorn static kbd_enable_t     akbd_enable;
125b4dbc599SNathan Whitehorn static kbd_disable_t    akbd_disable;
126b4dbc599SNathan Whitehorn static kbd_read_t       akbd_read;
127b4dbc599SNathan Whitehorn static kbd_check_t      akbd_check;
128b4dbc599SNathan Whitehorn static kbd_read_char_t  akbd_read_char;
129b4dbc599SNathan Whitehorn static kbd_check_char_t akbd_check_char;
130b4dbc599SNathan Whitehorn static kbd_ioctl_t      akbd_ioctl;
131b4dbc599SNathan Whitehorn static kbd_lock_t       akbd_lock;
132b4dbc599SNathan Whitehorn static kbd_clear_state_t akbd_clear_state;
133b4dbc599SNathan Whitehorn static kbd_get_state_t  akbd_get_state;
134b4dbc599SNathan Whitehorn static kbd_set_state_t  akbd_set_state;
135b4dbc599SNathan Whitehorn static kbd_poll_mode_t  akbd_poll;
136b4dbc599SNathan Whitehorn 
137b4dbc599SNathan Whitehorn keyboard_switch_t akbdsw = {
138b4dbc599SNathan Whitehorn         akbd_probe,
139b4dbc599SNathan Whitehorn         akbd_init,
140b4dbc599SNathan Whitehorn         akbd_term,
141b4dbc599SNathan Whitehorn         akbd_interrupt,
142b4dbc599SNathan Whitehorn         akbd_test_if,
143b4dbc599SNathan Whitehorn         akbd_enable,
144b4dbc599SNathan Whitehorn         akbd_disable,
145b4dbc599SNathan Whitehorn         akbd_read,
146b4dbc599SNathan Whitehorn         akbd_check,
147b4dbc599SNathan Whitehorn         akbd_read_char,
148b4dbc599SNathan Whitehorn         akbd_check_char,
149b4dbc599SNathan Whitehorn         akbd_ioctl,
150b4dbc599SNathan Whitehorn         akbd_lock,
151b4dbc599SNathan Whitehorn         akbd_clear_state,
152b4dbc599SNathan Whitehorn         akbd_get_state,
153b4dbc599SNathan Whitehorn         akbd_set_state,
154b4dbc599SNathan Whitehorn         genkbd_get_fkeystr,
155b4dbc599SNathan Whitehorn         akbd_poll,
156b4dbc599SNathan Whitehorn         genkbd_diag,
157b4dbc599SNathan Whitehorn };
158b4dbc599SNathan Whitehorn 
159b4dbc599SNathan Whitehorn KEYBOARD_DRIVER(akbd, akbdsw, akbd_configure);
160b4dbc599SNathan Whitehorn 
161b4dbc599SNathan Whitehorn static int
162b4dbc599SNathan Whitehorn adb_kbd_probe(device_t dev)
163b4dbc599SNathan Whitehorn {
164b4dbc599SNathan Whitehorn 	uint8_t type;
165b4dbc599SNathan Whitehorn 
166b4dbc599SNathan Whitehorn 	type = adb_get_device_type(dev);
167b4dbc599SNathan Whitehorn 
168b4dbc599SNathan Whitehorn 	if (type != ADB_DEVICE_KEYBOARD)
169b4dbc599SNathan Whitehorn 		return (ENXIO);
170b4dbc599SNathan Whitehorn 
171b4dbc599SNathan Whitehorn 	switch(adb_get_device_handler(dev)) {
172b4dbc599SNathan Whitehorn 	case 1:
173b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Standard Keyboard");
174b4dbc599SNathan Whitehorn 		break;
175b4dbc599SNathan Whitehorn 	case 2:
176b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Extended Keyboard");
177b4dbc599SNathan Whitehorn 		break;
178b4dbc599SNathan Whitehorn 	case 4:
179b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple ISO Keyboard");
180b4dbc599SNathan Whitehorn 		break;
181b4dbc599SNathan Whitehorn 	case 5:
182b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Extended ISO Keyboard");
183b4dbc599SNathan Whitehorn 		break;
184b4dbc599SNathan Whitehorn 	case 8:
185b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Keyboard II");
186b4dbc599SNathan Whitehorn 		break;
187b4dbc599SNathan Whitehorn 	case 9:
188b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple ISO Keyboard II");
189b4dbc599SNathan Whitehorn 		break;
190b4dbc599SNathan Whitehorn 	case 12:
191b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook Keyboard");
192b4dbc599SNathan Whitehorn 		break;
193b4dbc599SNathan Whitehorn 	case 13:
194b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook ISO Keyboard");
195b4dbc599SNathan Whitehorn 		break;
196b4dbc599SNathan Whitehorn 	case 24:
197b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook Extended Keyboard");
198b4dbc599SNathan Whitehorn 		break;
199b4dbc599SNathan Whitehorn 	case 27:
200b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Design Keyboard");
201b4dbc599SNathan Whitehorn 		break;
202b4dbc599SNathan Whitehorn 	case 195:
203b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook G3 Keyboard");
204b4dbc599SNathan Whitehorn 		break;
205b4dbc599SNathan Whitehorn 	case 196:
206b4dbc599SNathan Whitehorn 		device_set_desc(dev,"iBook Keyboard");
207b4dbc599SNathan Whitehorn 		break;
208b4dbc599SNathan Whitehorn 	default:
209b4dbc599SNathan Whitehorn 		device_set_desc(dev,"ADB Keyboard");
210b4dbc599SNathan Whitehorn 		break;
211b4dbc599SNathan Whitehorn 	}
212b4dbc599SNathan Whitehorn 
213b4dbc599SNathan Whitehorn 	return (0);
214b4dbc599SNathan Whitehorn }
215b4dbc599SNathan Whitehorn 
216b4dbc599SNathan Whitehorn static int
217b4dbc599SNathan Whitehorn ms_to_ticks(int ms)
218b4dbc599SNathan Whitehorn {
219b4dbc599SNathan Whitehorn 	if (hz > 1000)
220b4dbc599SNathan Whitehorn 		return ms*(hz/1000);
221b4dbc599SNathan Whitehorn 
222b4dbc599SNathan Whitehorn 	return ms/(1000/hz);
223b4dbc599SNathan Whitehorn }
224b4dbc599SNathan Whitehorn 
225b4dbc599SNathan Whitehorn static int
226b4dbc599SNathan Whitehorn adb_kbd_attach(device_t dev)
227b4dbc599SNathan Whitehorn {
228b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
229b4dbc599SNathan Whitehorn 	keyboard_switch_t *sw;
230b4dbc599SNathan Whitehorn 
231b4dbc599SNathan Whitehorn 	sw = kbd_get_switch(KBD_DRIVER_NAME);
232b4dbc599SNathan Whitehorn 	if (sw == NULL) {
233b4dbc599SNathan Whitehorn 		return ENXIO;
234b4dbc599SNathan Whitehorn 	}
235b4dbc599SNathan Whitehorn 
236b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
237b4dbc599SNathan Whitehorn 	sc->sc_dev = dev;
238b4dbc599SNathan Whitehorn 	sc->sc_mode = K_RAW;
239b4dbc599SNathan Whitehorn 	sc->sc_state = 0;
240b4dbc599SNathan Whitehorn 	sc->have_led_control = 0;
241b4dbc599SNathan Whitehorn 	sc->buffers = 0;
242b4dbc599SNathan Whitehorn 
243b4dbc599SNathan Whitehorn 	/* Try stepping forward to the extended keyboard protocol */
244b4dbc599SNathan Whitehorn 	adb_set_device_handler(dev,3);
245b4dbc599SNathan Whitehorn 
246b4dbc599SNathan Whitehorn 	mtx_init(&sc->sc_mutex,KBD_DRIVER_NAME,MTX_DEF,0);
247b4dbc599SNathan Whitehorn 	cv_init(&sc->sc_cv,KBD_DRIVER_NAME);
248b4dbc599SNathan Whitehorn 	callout_init(&sc->sc_repeater, 0);
249b4dbc599SNathan Whitehorn 
250b4dbc599SNathan Whitehorn #ifdef AKBD_EMULATE_ATKBD
251b4dbc599SNathan Whitehorn 	kbd_init_struct(&sc->sc_kbd, KBD_DRIVER_NAME, KB_101, 0, 0, 0, 0);
252b4dbc599SNathan Whitehorn 	kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab,
253b4dbc599SNathan Whitehorn             sizeof(fkey_tab) / sizeof(fkey_tab[0]));
254b4dbc599SNathan Whitehorn #else
255b4dbc599SNathan Whitehorn 	#error ADB raw mode not implemented
256b4dbc599SNathan Whitehorn #endif
257b4dbc599SNathan Whitehorn 
258b4dbc599SNathan Whitehorn 	KBD_FOUND_DEVICE(&sc->sc_kbd);
259b4dbc599SNathan Whitehorn 	KBD_PROBE_DONE(&sc->sc_kbd);
260b4dbc599SNathan Whitehorn 	KBD_INIT_DONE(&sc->sc_kbd);
261b4dbc599SNathan Whitehorn 	KBD_CONFIG_DONE(&sc->sc_kbd);
262b4dbc599SNathan Whitehorn 
263b4dbc599SNathan Whitehorn 	(*sw->enable)(&sc->sc_kbd);
264b4dbc599SNathan Whitehorn 
265b4dbc599SNathan Whitehorn 	kbd_register(&sc->sc_kbd);
266b4dbc599SNathan Whitehorn 
267b4dbc599SNathan Whitehorn #ifdef KBD_INSTALL_CDEV
268b4dbc599SNathan Whitehorn 	if (kbd_attach(&sc->sc_kbd)) {
269b4dbc599SNathan Whitehorn 		adb_kbd_detach(dev);
270b4dbc599SNathan Whitehorn 		return ENXIO;
271b4dbc599SNathan Whitehorn 	}
272b4dbc599SNathan Whitehorn #endif
273b4dbc599SNathan Whitehorn 
274b4dbc599SNathan Whitehorn 	adb_set_autopoll(dev,1);
275b4dbc599SNathan Whitehorn 
276b4dbc599SNathan Whitehorn 	/* Check (asynchronously) if we can read out the LED state from
277b4dbc599SNathan Whitehorn 	   this keyboard by reading the key state register */
278b4dbc599SNathan Whitehorn 	adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL);
279b4dbc599SNathan Whitehorn 
280b4dbc599SNathan Whitehorn 	return (0);
281b4dbc599SNathan Whitehorn }
282b4dbc599SNathan Whitehorn 
283b4dbc599SNathan Whitehorn static int
284b4dbc599SNathan Whitehorn adb_kbd_detach(device_t dev)
285b4dbc599SNathan Whitehorn {
286b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
287b4dbc599SNathan Whitehorn 	keyboard_t *kbd;
288b4dbc599SNathan Whitehorn 
289b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
290b4dbc599SNathan Whitehorn 
291b4dbc599SNathan Whitehorn 	adb_set_autopoll(dev,0);
292b4dbc599SNathan Whitehorn 	callout_stop(&sc->sc_repeater);
293b4dbc599SNathan Whitehorn 
294b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
295b4dbc599SNathan Whitehorn 
296b4dbc599SNathan Whitehorn 	kbd = kbd_get_keyboard(kbd_find_keyboard(KBD_DRIVER_NAME,
297b4dbc599SNathan Whitehorn 	          device_get_unit(dev)));
298b4dbc599SNathan Whitehorn 
299b4dbc599SNathan Whitehorn 	kbdd_disable(kbd);
300b4dbc599SNathan Whitehorn 
301b4dbc599SNathan Whitehorn #ifdef KBD_INSTALL_CDEV
302b4dbc599SNathan Whitehorn 	kbd_detach(kbd);
303b4dbc599SNathan Whitehorn #endif
304b4dbc599SNathan Whitehorn 
305b4dbc599SNathan Whitehorn 	kbdd_term(kbd);
306b4dbc599SNathan Whitehorn 
307b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
308b4dbc599SNathan Whitehorn 
309b4dbc599SNathan Whitehorn 	mtx_destroy(&sc->sc_mutex);
310b4dbc599SNathan Whitehorn 	cv_destroy(&sc->sc_cv);
311b4dbc599SNathan Whitehorn 
312b4dbc599SNathan Whitehorn 	return (0);
313b4dbc599SNathan Whitehorn }
314b4dbc599SNathan Whitehorn 
315b4dbc599SNathan Whitehorn static u_int
316b4dbc599SNathan Whitehorn adb_kbd_receive_packet(device_t dev, u_char status,
317b4dbc599SNathan Whitehorn     u_char command, u_char reg, int len, u_char *data)
318b4dbc599SNathan Whitehorn {
319b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
320b4dbc599SNathan Whitehorn 
321b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
322b4dbc599SNathan Whitehorn 
323b4dbc599SNathan Whitehorn 	if (command != ADB_COMMAND_TALK)
324b4dbc599SNathan Whitehorn 		return 0;
325b4dbc599SNathan Whitehorn 
326b4dbc599SNathan Whitehorn 	if (reg == 2 && len == 2) {
327b4dbc599SNathan Whitehorn 		sc->have_led_control = 1;
328b4dbc599SNathan Whitehorn 		return 0;
329b4dbc599SNathan Whitehorn 	}
330b4dbc599SNathan Whitehorn 
331b4dbc599SNathan Whitehorn 	if (reg != 0 || len != 2)
332b4dbc599SNathan Whitehorn 		return (0);
333b4dbc599SNathan Whitehorn 
334b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
335b4dbc599SNathan Whitehorn 		if ((data[0] & 0x7f) == 57 && sc->buffers < 7) {
336b4dbc599SNathan Whitehorn 			/* Fake the down/up cycle for caps lock */
337b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[0] & 0x7f;
338b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = (data[0] & 0x7f) | (1 << 7);
339b4dbc599SNathan Whitehorn 		} else {
340b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[0];
341b4dbc599SNathan Whitehorn 		}
342b4dbc599SNathan Whitehorn 
343b4dbc599SNathan Whitehorn 		if (sc->buffer[sc->buffers-1] < 0xff)
344b4dbc599SNathan Whitehorn 			sc->last_press = sc->buffer[sc->buffers-1];
345b4dbc599SNathan Whitehorn 
346b4dbc599SNathan Whitehorn 		if ((data[1] & 0x7f) == 57 && sc->buffers < 7) {
347b4dbc599SNathan Whitehorn 			/* Fake the down/up cycle for caps lock */
348b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[1] & 0x7f;
349b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = (data[1] & 0x7f) | (1 << 7);
350b4dbc599SNathan Whitehorn 		} else {
351b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[1];
352b4dbc599SNathan Whitehorn 		}
353b4dbc599SNathan Whitehorn 
354b4dbc599SNathan Whitehorn 		if (sc->buffer[sc->buffers-1] < 0xff)
355b4dbc599SNathan Whitehorn 			sc->last_press = sc->buffer[sc->buffers-1];
356b4dbc599SNathan Whitehorn 
357b4dbc599SNathan Whitehorn 		/* Stop any existing key repeating */
358b4dbc599SNathan Whitehorn 		callout_stop(&sc->sc_repeater);
359b4dbc599SNathan Whitehorn 
360b4dbc599SNathan Whitehorn 		/* Schedule a repeat callback on keydown */
361b4dbc599SNathan Whitehorn 		if (!(sc->last_press & (1 << 7))) {
362b4dbc599SNathan Whitehorn 			callout_reset(&sc->sc_repeater,
363b4dbc599SNathan Whitehorn 			    ms_to_ticks(sc->sc_kbd.kb_delay1), akbd_repeat, sc);
364b4dbc599SNathan Whitehorn 		}
365b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
366b4dbc599SNathan Whitehorn 
367b4dbc599SNathan Whitehorn 	cv_broadcast(&sc->sc_cv);
368b4dbc599SNathan Whitehorn 
369b4dbc599SNathan Whitehorn 	if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
370b4dbc599SNathan Whitehorn 		sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
371b4dbc599SNathan Whitehorn 			 KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
372b4dbc599SNathan Whitehorn 	}
373b4dbc599SNathan Whitehorn 
374b4dbc599SNathan Whitehorn 	return (0);
375b4dbc599SNathan Whitehorn }
376b4dbc599SNathan Whitehorn 
377b4dbc599SNathan Whitehorn static void
378b4dbc599SNathan Whitehorn akbd_repeat(void *xsc) {
379b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc = xsc;
380b4dbc599SNathan Whitehorn 	int notify_kbd = 0;
381b4dbc599SNathan Whitehorn 
382b4dbc599SNathan Whitehorn 	/* Fake an up/down key repeat so long as we have the
383b4dbc599SNathan Whitehorn 	   free buffers */
384b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
385b4dbc599SNathan Whitehorn 		if (sc->buffers < 7) {
386b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = sc->last_press | (1 << 7);
387b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = sc->last_press;
388b4dbc599SNathan Whitehorn 
389b4dbc599SNathan Whitehorn 			notify_kbd = 1;
390b4dbc599SNathan Whitehorn 		}
391b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
392b4dbc599SNathan Whitehorn 
393b4dbc599SNathan Whitehorn 	if (notify_kbd && KBD_IS_ACTIVE(&sc->sc_kbd)
394b4dbc599SNathan Whitehorn 	    && KBD_IS_BUSY(&sc->sc_kbd)) {
395b4dbc599SNathan Whitehorn 		sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
396b4dbc599SNathan Whitehorn 		    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
397b4dbc599SNathan Whitehorn 	}
398b4dbc599SNathan Whitehorn 
399b4dbc599SNathan Whitehorn 	/* Reschedule the callout */
400b4dbc599SNathan Whitehorn 	callout_reset(&sc->sc_repeater, ms_to_ticks(sc->sc_kbd.kb_delay2),
401b4dbc599SNathan Whitehorn 	    akbd_repeat, sc);
402b4dbc599SNathan Whitehorn }
403b4dbc599SNathan Whitehorn 
404b4dbc599SNathan Whitehorn static int
405b4dbc599SNathan Whitehorn akbd_configure(int flags)
406b4dbc599SNathan Whitehorn {
407b4dbc599SNathan Whitehorn 	return 0;
408b4dbc599SNathan Whitehorn }
409b4dbc599SNathan Whitehorn 
410b4dbc599SNathan Whitehorn static int
411b4dbc599SNathan Whitehorn akbd_probe(int unit, void *arg, int flags)
412b4dbc599SNathan Whitehorn {
413b4dbc599SNathan Whitehorn 	return 0;
414b4dbc599SNathan Whitehorn }
415b4dbc599SNathan Whitehorn 
416b4dbc599SNathan Whitehorn static int
417b4dbc599SNathan Whitehorn akbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
418b4dbc599SNathan Whitehorn {
419b4dbc599SNathan Whitehorn 	return 0;
420b4dbc599SNathan Whitehorn }
421b4dbc599SNathan Whitehorn 
422b4dbc599SNathan Whitehorn static int
423b4dbc599SNathan Whitehorn akbd_term(keyboard_t *kbd)
424b4dbc599SNathan Whitehorn {
425b4dbc599SNathan Whitehorn 	return 0;
426b4dbc599SNathan Whitehorn }
427b4dbc599SNathan Whitehorn 
428b4dbc599SNathan Whitehorn static int
429b4dbc599SNathan Whitehorn akbd_interrupt(keyboard_t *kbd, void *arg)
430b4dbc599SNathan Whitehorn {
431b4dbc599SNathan Whitehorn 	return 0;
432b4dbc599SNathan Whitehorn }
433b4dbc599SNathan Whitehorn 
434b4dbc599SNathan Whitehorn static int
435b4dbc599SNathan Whitehorn akbd_test_if(keyboard_t *kbd)
436b4dbc599SNathan Whitehorn {
437b4dbc599SNathan Whitehorn 	return 0;
438b4dbc599SNathan Whitehorn }
439b4dbc599SNathan Whitehorn 
440b4dbc599SNathan Whitehorn static int
441b4dbc599SNathan Whitehorn akbd_enable(keyboard_t *kbd)
442b4dbc599SNathan Whitehorn {
443b4dbc599SNathan Whitehorn 	KBD_ACTIVATE(kbd);
444b4dbc599SNathan Whitehorn 	return (0);
445b4dbc599SNathan Whitehorn }
446b4dbc599SNathan Whitehorn 
447b4dbc599SNathan Whitehorn static int
448b4dbc599SNathan Whitehorn akbd_disable(keyboard_t *kbd)
449b4dbc599SNathan Whitehorn {
450b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
451b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
452b4dbc599SNathan Whitehorn 
453b4dbc599SNathan Whitehorn 	callout_stop(&sc->sc_repeater);
454b4dbc599SNathan Whitehorn 	KBD_DEACTIVATE(kbd);
455b4dbc599SNathan Whitehorn 	return (0);
456b4dbc599SNathan Whitehorn }
457b4dbc599SNathan Whitehorn 
458b4dbc599SNathan Whitehorn static int
459b4dbc599SNathan Whitehorn akbd_read(keyboard_t *kbd, int wait)
460b4dbc599SNathan Whitehorn {
461b4dbc599SNathan Whitehorn 	return (0);
462b4dbc599SNathan Whitehorn }
463b4dbc599SNathan Whitehorn 
464b4dbc599SNathan Whitehorn static int
465b4dbc599SNathan Whitehorn akbd_check(keyboard_t *kbd)
466b4dbc599SNathan Whitehorn {
467b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
468b4dbc599SNathan Whitehorn 
469b4dbc599SNathan Whitehorn 	if (!KBD_IS_ACTIVE(kbd))
470b4dbc599SNathan Whitehorn 		return (FALSE);
471b4dbc599SNathan Whitehorn 
472b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
473b4dbc599SNathan Whitehorn 
474b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
475b4dbc599SNathan Whitehorn 		if (sc->buffers > 0) {
476b4dbc599SNathan Whitehorn 			mtx_unlock(&sc->sc_mutex);
477b4dbc599SNathan Whitehorn 			return (TRUE);
478b4dbc599SNathan Whitehorn 		}
479b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
480b4dbc599SNathan Whitehorn 
481b4dbc599SNathan Whitehorn 	return (FALSE);
482b4dbc599SNathan Whitehorn }
483b4dbc599SNathan Whitehorn 
484b4dbc599SNathan Whitehorn static u_int
485b4dbc599SNathan Whitehorn akbd_read_char(keyboard_t *kbd, int wait)
486b4dbc599SNathan Whitehorn {
487b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
488b4dbc599SNathan Whitehorn 	uint8_t adb_code, final_scancode;
489b4dbc599SNathan Whitehorn 	int i;
490b4dbc599SNathan Whitehorn 
491b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
492b4dbc599SNathan Whitehorn 
493b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
494b4dbc599SNathan Whitehorn 		if (!sc->buffers && wait)
495b4dbc599SNathan Whitehorn 			cv_wait(&sc->sc_cv,&sc->sc_mutex);
496b4dbc599SNathan Whitehorn 
497b4dbc599SNathan Whitehorn 		if (!sc->buffers) {
498b4dbc599SNathan Whitehorn 			mtx_unlock(&sc->sc_mutex);
499b4dbc599SNathan Whitehorn 			return (0);
500b4dbc599SNathan Whitehorn 		}
501b4dbc599SNathan Whitehorn 
502b4dbc599SNathan Whitehorn 		adb_code = sc->buffer[0];
503b4dbc599SNathan Whitehorn 
504b4dbc599SNathan Whitehorn 		for (i = 1; i < sc->buffers; i++)
505b4dbc599SNathan Whitehorn 			sc->buffer[i-1] = sc->buffer[i];
506b4dbc599SNathan Whitehorn 
507b4dbc599SNathan Whitehorn 		sc->buffers--;
508b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
509b4dbc599SNathan Whitehorn 
510b4dbc599SNathan Whitehorn 	#ifdef AKBD_EMULATE_ATKBD
511b4dbc599SNathan Whitehorn 		final_scancode = adb_to_at_scancode_map[adb_code & 0x7f];
512b4dbc599SNathan Whitehorn 		final_scancode |= adb_code & 0x80;
513b4dbc599SNathan Whitehorn 	#else
514b4dbc599SNathan Whitehorn 		final_scancode = adb_code;
515b4dbc599SNathan Whitehorn 	#endif
516b4dbc599SNathan Whitehorn 
517b4dbc599SNathan Whitehorn 	return (final_scancode);
518b4dbc599SNathan Whitehorn }
519b4dbc599SNathan Whitehorn 
520b4dbc599SNathan Whitehorn static int
521b4dbc599SNathan Whitehorn akbd_check_char(keyboard_t *kbd)
522b4dbc599SNathan Whitehorn {
523b4dbc599SNathan Whitehorn 	if (!KBD_IS_ACTIVE(kbd))
524b4dbc599SNathan Whitehorn 		return (FALSE);
525b4dbc599SNathan Whitehorn 
526b4dbc599SNathan Whitehorn 	return (akbd_check(kbd));
527b4dbc599SNathan Whitehorn }
528b4dbc599SNathan Whitehorn 
529b4dbc599SNathan Whitehorn static int
530b4dbc599SNathan Whitehorn set_typematic(keyboard_t *kbd, int code)
531b4dbc599SNathan Whitehorn {
532b4dbc599SNathan Whitehorn 	/* These numbers are in microseconds, so convert to ticks */
533b4dbc599SNathan Whitehorn 
534b4dbc599SNathan Whitehorn 	static int delays[] = { 250, 500, 750, 1000 };
535b4dbc599SNathan Whitehorn 	static int rates[] = {  34,  38,  42,  46,  50,  55,  59,  63,
536b4dbc599SNathan Whitehorn 				68,  76,  84,  92, 100, 110, 118, 126,
537b4dbc599SNathan Whitehorn 				136, 152, 168, 184, 200, 220, 236, 252,
538b4dbc599SNathan Whitehorn 				272, 304, 336, 368, 400, 440, 472, 504 };
539b4dbc599SNathan Whitehorn 
540b4dbc599SNathan Whitehorn 	if (code & ~0x7f)
541b4dbc599SNathan Whitehorn 		return EINVAL;
542b4dbc599SNathan Whitehorn 	kbd->kb_delay1 = delays[(code >> 5) & 3];
543b4dbc599SNathan Whitehorn 	kbd->kb_delay2 = rates[code & 0x1f];
544b4dbc599SNathan Whitehorn 	return 0;
545b4dbc599SNathan Whitehorn }
546b4dbc599SNathan Whitehorn 
547b4dbc599SNathan Whitehorn static int akbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
548b4dbc599SNathan Whitehorn {
549b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
550b4dbc599SNathan Whitehorn 	uint16_t r2;
551b4dbc599SNathan Whitehorn 	int error;
552b4dbc599SNathan Whitehorn 
553b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
554b4dbc599SNathan Whitehorn 	error = 0;
555b4dbc599SNathan Whitehorn 
556b4dbc599SNathan Whitehorn 	switch (cmd) {
557b4dbc599SNathan Whitehorn 	case KDGKBMODE:
558b4dbc599SNathan Whitehorn 		*(int *)data = sc->sc_mode;
559b4dbc599SNathan Whitehorn 		break;
560b4dbc599SNathan Whitehorn 	case KDSKBMODE:
561b4dbc599SNathan Whitehorn 		switch (*(int *)data) {
562b4dbc599SNathan Whitehorn 		case K_XLATE:
563b4dbc599SNathan Whitehorn 			if (sc->sc_mode != K_XLATE) {
564b4dbc599SNathan Whitehorn 				/* make lock key state and LED state match */
565b4dbc599SNathan Whitehorn 				sc->sc_state &= ~LOCK_MASK;
566b4dbc599SNathan Whitehorn 				sc->sc_state |= KBD_LED_VAL(kbd);
567b4dbc599SNathan Whitehorn 			}
568b4dbc599SNathan Whitehorn 			/* FALLTHROUGH */
569b4dbc599SNathan Whitehorn 		case K_RAW:
570b4dbc599SNathan Whitehorn 		case K_CODE:
571b4dbc599SNathan Whitehorn 			if (sc->sc_mode != *(int *)data)
572b4dbc599SNathan Whitehorn 				sc->sc_mode = *(int *)data;
573b4dbc599SNathan Whitehorn 			break;
574b4dbc599SNathan Whitehorn 		default:
575b4dbc599SNathan Whitehorn 			error = EINVAL;
576b4dbc599SNathan Whitehorn 			break;
577b4dbc599SNathan Whitehorn 		}
578b4dbc599SNathan Whitehorn 
579b4dbc599SNathan Whitehorn 		break;
580b4dbc599SNathan Whitehorn 
581b4dbc599SNathan Whitehorn 	case KDGETLED:
582b4dbc599SNathan Whitehorn 		*(int *)data = KBD_LED_VAL(kbd);
583b4dbc599SNathan Whitehorn 		break;
584b4dbc599SNathan Whitehorn 
585b4dbc599SNathan Whitehorn 	case KDSKBSTATE:
586b4dbc599SNathan Whitehorn 		if (*(int *)data & ~LOCK_MASK) {
587b4dbc599SNathan Whitehorn 			error = EINVAL;
588b4dbc599SNathan Whitehorn 			break;
589b4dbc599SNathan Whitehorn 		}
590b4dbc599SNathan Whitehorn 		sc->sc_state &= ~LOCK_MASK;
591b4dbc599SNathan Whitehorn 		sc->sc_state |= *(int *)data;
592b4dbc599SNathan Whitehorn 
593b4dbc599SNathan Whitehorn 		/* FALLTHROUGH */
594b4dbc599SNathan Whitehorn 
595b4dbc599SNathan Whitehorn 	case KDSETLED:
596b4dbc599SNathan Whitehorn 		KBD_LED_VAL(kbd) = *(int *)data;
597b4dbc599SNathan Whitehorn 
598b4dbc599SNathan Whitehorn 		if (!sc->have_led_control)
599b4dbc599SNathan Whitehorn 			break;
600b4dbc599SNathan Whitehorn 
601b4dbc599SNathan Whitehorn 		r2 = (~0 & 0x04) | 3;
602b4dbc599SNathan Whitehorn 
603b4dbc599SNathan Whitehorn 		if (*(int *)data & NLKED)
604b4dbc599SNathan Whitehorn 			r2 &= ~1;
605b4dbc599SNathan Whitehorn 		if (*(int *)data & CLKED)
606b4dbc599SNathan Whitehorn 			r2 &= ~2;
607b4dbc599SNathan Whitehorn 		if (*(int *)data & SLKED)
608b4dbc599SNathan Whitehorn 			r2 &= ~4;
609b4dbc599SNathan Whitehorn 
610b4dbc599SNathan Whitehorn 		adb_send_packet(sc->sc_dev,ADB_COMMAND_LISTEN,2,
611b4dbc599SNathan Whitehorn 			sizeof(uint16_t),(u_char *)&r2);
612b4dbc599SNathan Whitehorn 
613b4dbc599SNathan Whitehorn 		break;
614b4dbc599SNathan Whitehorn 
615b4dbc599SNathan Whitehorn 	case KDGKBSTATE:
616b4dbc599SNathan Whitehorn 		*(int *)data = sc->sc_state & LOCK_MASK;
617b4dbc599SNathan Whitehorn 		break;
618b4dbc599SNathan Whitehorn 
619b4dbc599SNathan Whitehorn 	case KDSETREPEAT:
620b4dbc599SNathan Whitehorn 		if (!KBD_HAS_DEVICE(kbd))
621b4dbc599SNathan Whitehorn 			return 0;
622b4dbc599SNathan Whitehorn 		if (((int *)data)[1] < 0)
623b4dbc599SNathan Whitehorn 			return EINVAL;
624b4dbc599SNathan Whitehorn 		if (((int *)data)[0] < 0)
625b4dbc599SNathan Whitehorn 			return EINVAL;
626b4dbc599SNathan Whitehorn 		else if (((int *)data)[0] == 0)  /* fastest possible value */
627b4dbc599SNathan Whitehorn 			kbd->kb_delay1 = 200;
628b4dbc599SNathan Whitehorn 		else
629b4dbc599SNathan Whitehorn 			kbd->kb_delay1 = ((int *)data)[0];
630b4dbc599SNathan Whitehorn 		kbd->kb_delay2 = ((int *)data)[1];
631b4dbc599SNathan Whitehorn 
632b4dbc599SNathan Whitehorn 		break;
633b4dbc599SNathan Whitehorn 
634b4dbc599SNathan Whitehorn 	case KDSETRAD:
635b4dbc599SNathan Whitehorn 		error = set_typematic(kbd, *(int *)data);
636b4dbc599SNathan Whitehorn 		break;
637b4dbc599SNathan Whitehorn 
638b4dbc599SNathan Whitehorn 	case PIO_KEYMAP:
639b4dbc599SNathan Whitehorn 	case PIO_KEYMAPENT:
640b4dbc599SNathan Whitehorn 	case PIO_DEADKEYMAP:
641b4dbc599SNathan Whitehorn 	default:
642b4dbc599SNathan Whitehorn 		return (genkbd_commonioctl(kbd, cmd, data));
643b4dbc599SNathan Whitehorn 	}
644b4dbc599SNathan Whitehorn 
645b4dbc599SNathan Whitehorn 	return (error);
646b4dbc599SNathan Whitehorn }
647b4dbc599SNathan Whitehorn 
648b4dbc599SNathan Whitehorn static int akbd_lock(keyboard_t *kbd, int lock)
649b4dbc599SNathan Whitehorn {
650b4dbc599SNathan Whitehorn 	return (0);
651b4dbc599SNathan Whitehorn }
652b4dbc599SNathan Whitehorn 
653b4dbc599SNathan Whitehorn static void akbd_clear_state(keyboard_t *kbd)
654b4dbc599SNathan Whitehorn {
655b4dbc599SNathan Whitehorn }
656b4dbc599SNathan Whitehorn 
657b4dbc599SNathan Whitehorn static int akbd_get_state(keyboard_t *kbd, void *buf, size_t len)
658b4dbc599SNathan Whitehorn {
659b4dbc599SNathan Whitehorn 	return (0);
660b4dbc599SNathan Whitehorn }
661b4dbc599SNathan Whitehorn 
662b4dbc599SNathan Whitehorn static int akbd_set_state(keyboard_t *kbd, void *buf, size_t len)
663b4dbc599SNathan Whitehorn {
664b4dbc599SNathan Whitehorn 	return (0);
665b4dbc599SNathan Whitehorn }
666b4dbc599SNathan Whitehorn 
667b4dbc599SNathan Whitehorn static int akbd_poll(keyboard_t *kbd, int on)
668b4dbc599SNathan Whitehorn {
669b4dbc599SNathan Whitehorn 	return (0);
670b4dbc599SNathan Whitehorn }
671b4dbc599SNathan Whitehorn 
672b4dbc599SNathan Whitehorn static int
673b4dbc599SNathan Whitehorn akbd_modevent(module_t mod, int type, void *data)
674b4dbc599SNathan Whitehorn {
675b4dbc599SNathan Whitehorn 	switch (type) {
676b4dbc599SNathan Whitehorn 	case MOD_LOAD:
677b4dbc599SNathan Whitehorn 		kbd_add_driver(&akbd_kbd_driver);
678b4dbc599SNathan Whitehorn 		break;
679b4dbc599SNathan Whitehorn 
680b4dbc599SNathan Whitehorn 	case MOD_UNLOAD:
681b4dbc599SNathan Whitehorn 		kbd_delete_driver(&akbd_kbd_driver);
682b4dbc599SNathan Whitehorn 		break;
683b4dbc599SNathan Whitehorn 
684b4dbc599SNathan Whitehorn 	default:
685b4dbc599SNathan Whitehorn 		return (EOPNOTSUPP);
686b4dbc599SNathan Whitehorn 	}
687b4dbc599SNathan Whitehorn 
688b4dbc599SNathan Whitehorn 	return (0);
689b4dbc599SNathan Whitehorn }
690b4dbc599SNathan Whitehorn 
691b4dbc599SNathan Whitehorn DEV_MODULE(akbd, akbd_modevent, NULL);
692b4dbc599SNathan Whitehorn 
693