xref: /freebsd/sys/dev/adb/adb_kbd.c (revision f20058955c9d1041a5a09cd02a27babda7e34dc8)
1b4dbc599SNathan Whitehorn /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
4b4dbc599SNathan Whitehorn  * Copyright (C) 2008 Nathan Whitehorn
5b4dbc599SNathan Whitehorn  * All rights reserved.
6b4dbc599SNathan Whitehorn  *
7b4dbc599SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
8b4dbc599SNathan Whitehorn  * modification, are permitted provided that the following conditions
9b4dbc599SNathan Whitehorn  * are met:
10b4dbc599SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
11b4dbc599SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
12b4dbc599SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
13b4dbc599SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
14b4dbc599SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
15b4dbc599SNathan Whitehorn  *
16b4dbc599SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b4dbc599SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b4dbc599SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b4dbc599SNathan Whitehorn  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20b4dbc599SNathan Whitehorn  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21b4dbc599SNathan Whitehorn  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22b4dbc599SNathan Whitehorn  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23b4dbc599SNathan Whitehorn  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24b4dbc599SNathan Whitehorn  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25b4dbc599SNathan Whitehorn  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b4dbc599SNathan Whitehorn  *
27b4dbc599SNathan Whitehorn  * $FreeBSD$
28b4dbc599SNathan Whitehorn  */
29b4dbc599SNathan Whitehorn 
30b4dbc599SNathan Whitehorn #include <sys/cdefs.h>
31b4dbc599SNathan Whitehorn #include <sys/param.h>
32b4dbc599SNathan Whitehorn #include <sys/systm.h>
33e2e050c8SConrad Meyer #include <sys/lock.h>
34b4dbc599SNathan Whitehorn #include <sys/module.h>
35e2e050c8SConrad Meyer #include <sys/mutex.h>
36b4dbc599SNathan Whitehorn #include <sys/bus.h>
37b4dbc599SNathan Whitehorn #include <sys/conf.h>
38b4dbc599SNathan Whitehorn #include <sys/kbio.h>
39b4dbc599SNathan Whitehorn #include <sys/condvar.h>
40b4dbc599SNathan Whitehorn #include <sys/callout.h>
41b4dbc599SNathan Whitehorn #include <sys/kernel.h>
42b6faf3cfSNathan Whitehorn #include <sys/sysctl.h>
43b4dbc599SNathan Whitehorn 
44b4dbc599SNathan Whitehorn #include <machine/bus.h>
45b4dbc599SNathan Whitehorn 
46b4dbc599SNathan Whitehorn #include "opt_kbd.h"
47b4dbc599SNathan Whitehorn #include <dev/kbd/kbdreg.h>
48b4dbc599SNathan Whitehorn #include <dev/kbd/kbdtables.h>
49b6faf3cfSNathan Whitehorn #include <dev/ofw/openfirm.h>
50b6faf3cfSNathan Whitehorn #include <dev/ofw/ofw_bus.h>
51b4dbc599SNathan Whitehorn 
52b4dbc599SNathan Whitehorn #include <vm/vm.h>
53b4dbc599SNathan Whitehorn #include <vm/pmap.h>
54b4dbc599SNathan Whitehorn 
55b4dbc599SNathan Whitehorn #include "adb.h"
56b4dbc599SNathan Whitehorn 
57b4dbc599SNathan Whitehorn #define KBD_DRIVER_NAME "akbd"
58b4dbc599SNathan Whitehorn 
59b4dbc599SNathan Whitehorn #define AKBD_EMULATE_ATKBD 1
60b4dbc599SNathan Whitehorn 
61b4dbc599SNathan Whitehorn static int adb_kbd_probe(device_t dev);
62b4dbc599SNathan Whitehorn static int adb_kbd_attach(device_t dev);
63b4dbc599SNathan Whitehorn static int adb_kbd_detach(device_t dev);
64b4dbc599SNathan Whitehorn static void akbd_repeat(void *xsc);
65b6faf3cfSNathan Whitehorn static int adb_fn_keys(SYSCTL_HANDLER_ARGS);
66b4dbc599SNathan Whitehorn 
67b4dbc599SNathan Whitehorn static u_int adb_kbd_receive_packet(device_t dev, u_char status,
68b4dbc599SNathan Whitehorn 	u_char command, u_char reg, int len, u_char *data);
69b4dbc599SNathan Whitehorn 
70b4dbc599SNathan Whitehorn struct adb_kbd_softc {
71b4dbc599SNathan Whitehorn 	keyboard_t sc_kbd;
72b4dbc599SNathan Whitehorn 
73b4dbc599SNathan Whitehorn 	device_t sc_dev;
74b4dbc599SNathan Whitehorn 	struct mtx sc_mutex;
75b4dbc599SNathan Whitehorn 	struct cv  sc_cv;
76b4dbc599SNathan Whitehorn 
77b4dbc599SNathan Whitehorn 	int sc_mode;
78b4dbc599SNathan Whitehorn 	int sc_state;
79b4dbc599SNathan Whitehorn 
80b4dbc599SNathan Whitehorn 	int have_led_control;
81b4dbc599SNathan Whitehorn 
82b4dbc599SNathan Whitehorn 	uint8_t buffer[8];
834fb52093SNathan Whitehorn #ifdef AKBD_EMULATE_ATKBD
844fb52093SNathan Whitehorn 	uint8_t at_buffered_char[2];
854fb52093SNathan Whitehorn #endif
86b4dbc599SNathan Whitehorn 	volatile int buffers;
87b4dbc599SNathan Whitehorn 
88b4dbc599SNathan Whitehorn 	struct callout sc_repeater;
89b4dbc599SNathan Whitehorn 	int sc_repeatstart;
90b4dbc599SNathan Whitehorn 	int sc_repeatcontinue;
91b4dbc599SNathan Whitehorn 	uint8_t last_press;
92b4dbc599SNathan Whitehorn };
93b4dbc599SNathan Whitehorn 
94b4dbc599SNathan Whitehorn static device_method_t adb_kbd_methods[] = {
95b4dbc599SNathan Whitehorn 	/* Device interface */
96b4dbc599SNathan Whitehorn 	DEVMETHOD(device_probe,         adb_kbd_probe),
97b4dbc599SNathan Whitehorn         DEVMETHOD(device_attach,        adb_kbd_attach),
98b4dbc599SNathan Whitehorn         DEVMETHOD(device_detach,        adb_kbd_detach),
99b4dbc599SNathan Whitehorn         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
100b4dbc599SNathan Whitehorn         DEVMETHOD(device_suspend,       bus_generic_suspend),
101b4dbc599SNathan Whitehorn         DEVMETHOD(device_resume,        bus_generic_resume),
102b4dbc599SNathan Whitehorn 
103b4dbc599SNathan Whitehorn 	/* ADB interface */
104b4dbc599SNathan Whitehorn 	DEVMETHOD(adb_receive_packet,	adb_kbd_receive_packet),
105b4dbc599SNathan Whitehorn 	{ 0, 0 }
106b4dbc599SNathan Whitehorn };
107b4dbc599SNathan Whitehorn 
108b4dbc599SNathan Whitehorn static driver_t adb_kbd_driver = {
109b4dbc599SNathan Whitehorn 	"akbd",
110b4dbc599SNathan Whitehorn 	adb_kbd_methods,
111b4dbc599SNathan Whitehorn 	sizeof(struct adb_kbd_softc),
112b4dbc599SNathan Whitehorn };
113b4dbc599SNathan Whitehorn 
114c46fd018SJohn Baldwin DRIVER_MODULE(akbd, adb, adb_kbd_driver, 0, 0);
115b4dbc599SNathan Whitehorn 
1164fb52093SNathan Whitehorn #ifdef AKBD_EMULATE_ATKBD
1174fb52093SNathan Whitehorn 
1184fb52093SNathan Whitehorn #define	SCAN_PRESS		0x000
1194fb52093SNathan Whitehorn #define	SCAN_RELEASE		0x080
1204fb52093SNathan Whitehorn #define	SCAN_PREFIX_E0		0x100
1214fb52093SNathan Whitehorn #define	SCAN_PREFIX_E1		0x200
1224fb52093SNathan Whitehorn #define	SCAN_PREFIX_CTL		0x400
1234fb52093SNathan Whitehorn #define	SCAN_PREFIX_SHIFT	0x800
1244fb52093SNathan Whitehorn #define	SCAN_PREFIX		(SCAN_PREFIX_E0 | SCAN_PREFIX_E1 |	\
1254fb52093SNathan Whitehorn 				SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT)
1264fb52093SNathan Whitehorn 
127b4dbc599SNathan Whitehorn static const uint8_t adb_to_at_scancode_map[128] = { 30, 31, 32, 33, 35, 34,
128b4dbc599SNathan Whitehorn 	44, 45, 46, 47, 0, 48, 16, 17, 18, 19, 21, 20, 2, 3, 4, 5, 7, 6, 13,
129b4dbc599SNathan Whitehorn 	10, 8, 12, 9, 11, 27, 24, 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43,
130b4dbc599SNathan Whitehorn 	51, 53, 49, 50, 52, 15, 57, 41, 14, 0, 1, 29, 0, 42, 58, 56, 97, 98,
131b4dbc599SNathan Whitehorn 	100, 95, 0, 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 91, 89, 0, 74, 13, 0,
132b4dbc599SNathan Whitehorn 	0, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73, 0, 0, 0, 63, 64, 65, 61,
133b4dbc599SNathan Whitehorn 	66, 67, 0, 87, 0, 105, 0, 70, 0, 68, 0, 88, 0, 107, 102, 94, 96, 103,
134b4dbc599SNathan Whitehorn 	62, 99, 60, 101, 59, 54, 93, 90, 0, 0 };
135b4dbc599SNathan Whitehorn 
1364fb52093SNathan Whitehorn static int
1374fb52093SNathan Whitehorn keycode2scancode(int keycode, int shift, int up)
1384fb52093SNathan Whitehorn {
1394fb52093SNathan Whitehorn 	static const int scan[] = {
1404fb52093SNathan Whitehorn 		/* KP enter, right ctrl, KP divide */
1414fb52093SNathan Whitehorn 		0x1c , 0x1d , 0x35 ,
1424fb52093SNathan Whitehorn 		/* print screen */
1434fb52093SNathan Whitehorn 		0x37 | SCAN_PREFIX_SHIFT,
1444fb52093SNathan Whitehorn 		/* right alt, home, up, page up, left, right, end */
1454fb52093SNathan Whitehorn 		0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f,
1464fb52093SNathan Whitehorn 		/* down, page down, insert, delete */
1474fb52093SNathan Whitehorn 		0x50, 0x51, 0x52, 0x53,
1484fb52093SNathan Whitehorn 		/* pause/break (see also below) */
1494fb52093SNathan Whitehorn 		0x46,
1504fb52093SNathan Whitehorn 		/*
1514fb52093SNathan Whitehorn 		 * MS: left window, right window, menu
1524fb52093SNathan Whitehorn 		 * also Sun: left meta, right meta, compose
1534fb52093SNathan Whitehorn 		 */
1544fb52093SNathan Whitehorn 		0x5b, 0x5c, 0x5d,
1554fb52093SNathan Whitehorn 		/* Sun type 6 USB */
1564fb52093SNathan Whitehorn 		/* help, stop, again, props, undo, front, copy */
1574fb52093SNathan Whitehorn 		0x68, 0x5e, 0x5f, 0x60,	0x61, 0x62, 0x63,
1584fb52093SNathan Whitehorn 		/* open, paste, find, cut, audiomute, audiolower, audioraise */
1594fb52093SNathan Whitehorn 		0x64, 0x65, 0x66, 0x67, 0x25, 0x1f, 0x1e,
1604fb52093SNathan Whitehorn 		/* power */
1614fb52093SNathan Whitehorn 		0x20
1624fb52093SNathan Whitehorn 	};
1634fb52093SNathan Whitehorn 	int scancode;
1644fb52093SNathan Whitehorn 
1654fb52093SNathan Whitehorn 	scancode = keycode;
16673a1170aSPedro F. Giffuni 	if ((keycode >= 89) && (keycode < 89 + nitems(scan)))
1674fb52093SNathan Whitehorn 	scancode = scan[keycode - 89] | SCAN_PREFIX_E0;
1684fb52093SNathan Whitehorn 	/* pause/break */
1694fb52093SNathan Whitehorn 	if ((keycode == 104) && !(shift & CTLS))
1704fb52093SNathan Whitehorn 		scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL;
1714fb52093SNathan Whitehorn 	if (shift & SHIFTS)
1724fb52093SNathan Whitehorn 		scancode &= ~SCAN_PREFIX_SHIFT;
1734fb52093SNathan Whitehorn 	return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS));
1744fb52093SNathan Whitehorn }
1754fb52093SNathan Whitehorn #endif
1764fb52093SNathan Whitehorn 
177b4dbc599SNathan Whitehorn /* keyboard driver declaration */
178b4dbc599SNathan Whitehorn static int              akbd_configure(int flags);
179b4dbc599SNathan Whitehorn static kbd_probe_t      akbd_probe;
180b4dbc599SNathan Whitehorn static kbd_init_t       akbd_init;
181b4dbc599SNathan Whitehorn static kbd_term_t       akbd_term;
182b4dbc599SNathan Whitehorn static kbd_intr_t       akbd_interrupt;
183b4dbc599SNathan Whitehorn static kbd_test_if_t    akbd_test_if;
184b4dbc599SNathan Whitehorn static kbd_enable_t     akbd_enable;
185b4dbc599SNathan Whitehorn static kbd_disable_t    akbd_disable;
186b4dbc599SNathan Whitehorn static kbd_read_t       akbd_read;
187b4dbc599SNathan Whitehorn static kbd_check_t      akbd_check;
188b4dbc599SNathan Whitehorn static kbd_read_char_t  akbd_read_char;
189b4dbc599SNathan Whitehorn static kbd_check_char_t akbd_check_char;
190b4dbc599SNathan Whitehorn static kbd_ioctl_t      akbd_ioctl;
191b4dbc599SNathan Whitehorn static kbd_lock_t       akbd_lock;
192b4dbc599SNathan Whitehorn static kbd_clear_state_t akbd_clear_state;
193b4dbc599SNathan Whitehorn static kbd_get_state_t  akbd_get_state;
194b4dbc599SNathan Whitehorn static kbd_set_state_t  akbd_set_state;
195b4dbc599SNathan Whitehorn static kbd_poll_mode_t  akbd_poll;
196b4dbc599SNathan Whitehorn 
197b4dbc599SNathan Whitehorn keyboard_switch_t akbdsw = {
1981c5c067aSKyle Evans         .probe =	akbd_probe,
1991c5c067aSKyle Evans         .init =		akbd_init,
2001c5c067aSKyle Evans         .term =		akbd_term,
2011c5c067aSKyle Evans         .intr =		akbd_interrupt,
2021c5c067aSKyle Evans         .test_if =	akbd_test_if,
2031c5c067aSKyle Evans         .enable =	akbd_enable,
2041c5c067aSKyle Evans         .disable =	akbd_disable,
2051c5c067aSKyle Evans         .read =		akbd_read,
2061c5c067aSKyle Evans         .check =	akbd_check,
2071c5c067aSKyle Evans         .read_char =	akbd_read_char,
2081c5c067aSKyle Evans         .check_char =	akbd_check_char,
2091c5c067aSKyle Evans         .ioctl =	akbd_ioctl,
2101c5c067aSKyle Evans         .lock =		akbd_lock,
2111c5c067aSKyle Evans         .clear_state =	akbd_clear_state,
2121c5c067aSKyle Evans         .get_state =	akbd_get_state,
2131c5c067aSKyle Evans         .set_state =	akbd_set_state,
2141c5c067aSKyle Evans         .poll =		akbd_poll,
215b4dbc599SNathan Whitehorn };
216b4dbc599SNathan Whitehorn 
217b4dbc599SNathan Whitehorn KEYBOARD_DRIVER(akbd, akbdsw, akbd_configure);
218b4dbc599SNathan Whitehorn 
219b4dbc599SNathan Whitehorn static int
220b4dbc599SNathan Whitehorn adb_kbd_probe(device_t dev)
221b4dbc599SNathan Whitehorn {
222b4dbc599SNathan Whitehorn 	uint8_t type;
223b4dbc599SNathan Whitehorn 
224b4dbc599SNathan Whitehorn 	type = adb_get_device_type(dev);
225b4dbc599SNathan Whitehorn 
226b4dbc599SNathan Whitehorn 	if (type != ADB_DEVICE_KEYBOARD)
227b4dbc599SNathan Whitehorn 		return (ENXIO);
228b4dbc599SNathan Whitehorn 
229b4dbc599SNathan Whitehorn 	switch(adb_get_device_handler(dev)) {
230b4dbc599SNathan Whitehorn 	case 1:
231b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Standard Keyboard");
232b4dbc599SNathan Whitehorn 		break;
233b4dbc599SNathan Whitehorn 	case 2:
234b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Extended Keyboard");
235b4dbc599SNathan Whitehorn 		break;
236b4dbc599SNathan Whitehorn 	case 4:
237b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple ISO Keyboard");
238b4dbc599SNathan Whitehorn 		break;
239b4dbc599SNathan Whitehorn 	case 5:
240b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Extended ISO Keyboard");
241b4dbc599SNathan Whitehorn 		break;
242b4dbc599SNathan Whitehorn 	case 8:
243b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Keyboard II");
244b4dbc599SNathan Whitehorn 		break;
245b4dbc599SNathan Whitehorn 	case 9:
246b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple ISO Keyboard II");
247b4dbc599SNathan Whitehorn 		break;
248b4dbc599SNathan Whitehorn 	case 12:
249b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook Keyboard");
250b4dbc599SNathan Whitehorn 		break;
251b4dbc599SNathan Whitehorn 	case 13:
252b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook ISO Keyboard");
253b4dbc599SNathan Whitehorn 		break;
254b4dbc599SNathan Whitehorn 	case 24:
255b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook Extended Keyboard");
256b4dbc599SNathan Whitehorn 		break;
257b4dbc599SNathan Whitehorn 	case 27:
258b4dbc599SNathan Whitehorn 		device_set_desc(dev,"Apple Design Keyboard");
259b4dbc599SNathan Whitehorn 		break;
260b4dbc599SNathan Whitehorn 	case 195:
261b4dbc599SNathan Whitehorn 		device_set_desc(dev,"PowerBook G3 Keyboard");
262b4dbc599SNathan Whitehorn 		break;
263b4dbc599SNathan Whitehorn 	case 196:
264b4dbc599SNathan Whitehorn 		device_set_desc(dev,"iBook Keyboard");
265b4dbc599SNathan Whitehorn 		break;
266b4dbc599SNathan Whitehorn 	default:
267b4dbc599SNathan Whitehorn 		device_set_desc(dev,"ADB Keyboard");
268b4dbc599SNathan Whitehorn 		break;
269b4dbc599SNathan Whitehorn 	}
270b4dbc599SNathan Whitehorn 
271b4dbc599SNathan Whitehorn 	return (0);
272b4dbc599SNathan Whitehorn }
273b4dbc599SNathan Whitehorn 
274b4dbc599SNathan Whitehorn static int
275b4dbc599SNathan Whitehorn ms_to_ticks(int ms)
276b4dbc599SNathan Whitehorn {
277b4dbc599SNathan Whitehorn 	if (hz > 1000)
278b4dbc599SNathan Whitehorn 		return ms*(hz/1000);
279b4dbc599SNathan Whitehorn 
280b4dbc599SNathan Whitehorn 	return ms/(1000/hz);
281b4dbc599SNathan Whitehorn }
282b4dbc599SNathan Whitehorn 
283b4dbc599SNathan Whitehorn static int
284b4dbc599SNathan Whitehorn adb_kbd_attach(device_t dev)
285b4dbc599SNathan Whitehorn {
286b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
287b4dbc599SNathan Whitehorn 	keyboard_switch_t *sw;
288b6faf3cfSNathan Whitehorn 	uint32_t fkeys;
289b6faf3cfSNathan Whitehorn 	phandle_t handle;
290b4dbc599SNathan Whitehorn 
291b4dbc599SNathan Whitehorn 	sw = kbd_get_switch(KBD_DRIVER_NAME);
292b4dbc599SNathan Whitehorn 	if (sw == NULL) {
293b4dbc599SNathan Whitehorn 		return ENXIO;
294b4dbc599SNathan Whitehorn 	}
295b4dbc599SNathan Whitehorn 
296b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
297b4dbc599SNathan Whitehorn 	sc->sc_dev = dev;
298b4dbc599SNathan Whitehorn 	sc->sc_mode = K_RAW;
299b4dbc599SNathan Whitehorn 	sc->sc_state = 0;
300b4dbc599SNathan Whitehorn 	sc->have_led_control = 0;
301b4dbc599SNathan Whitehorn 	sc->buffers = 0;
302b4dbc599SNathan Whitehorn 
303b4dbc599SNathan Whitehorn 	/* Try stepping forward to the extended keyboard protocol */
304b4dbc599SNathan Whitehorn 	adb_set_device_handler(dev,3);
305b4dbc599SNathan Whitehorn 
306c821b482SJustin Hibbits 	mtx_init(&sc->sc_mutex, KBD_DRIVER_NAME, NULL, MTX_DEF);
307b4dbc599SNathan Whitehorn 	cv_init(&sc->sc_cv,KBD_DRIVER_NAME);
308b4dbc599SNathan Whitehorn 	callout_init(&sc->sc_repeater, 0);
309b4dbc599SNathan Whitehorn 
310b4dbc599SNathan Whitehorn #ifdef AKBD_EMULATE_ATKBD
311b4dbc599SNathan Whitehorn 	kbd_init_struct(&sc->sc_kbd, KBD_DRIVER_NAME, KB_101, 0, 0, 0, 0);
312b4dbc599SNathan Whitehorn 	kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab,
313b4dbc599SNathan Whitehorn             sizeof(fkey_tab) / sizeof(fkey_tab[0]));
314b4dbc599SNathan Whitehorn #else
315b4dbc599SNathan Whitehorn 	#error ADB raw mode not implemented
316b4dbc599SNathan Whitehorn #endif
317b4dbc599SNathan Whitehorn 
318b4dbc599SNathan Whitehorn 	KBD_FOUND_DEVICE(&sc->sc_kbd);
319b4dbc599SNathan Whitehorn 	KBD_PROBE_DONE(&sc->sc_kbd);
320b4dbc599SNathan Whitehorn 	KBD_INIT_DONE(&sc->sc_kbd);
321b4dbc599SNathan Whitehorn 	KBD_CONFIG_DONE(&sc->sc_kbd);
322b4dbc599SNathan Whitehorn 
323b4dbc599SNathan Whitehorn 	(*sw->enable)(&sc->sc_kbd);
324b4dbc599SNathan Whitehorn 
325b4dbc599SNathan Whitehorn 	kbd_register(&sc->sc_kbd);
326b4dbc599SNathan Whitehorn 
327b4dbc599SNathan Whitehorn #ifdef KBD_INSTALL_CDEV
328b4dbc599SNathan Whitehorn 	if (kbd_attach(&sc->sc_kbd)) {
329b4dbc599SNathan Whitehorn 		adb_kbd_detach(dev);
330b4dbc599SNathan Whitehorn 		return ENXIO;
331b4dbc599SNathan Whitehorn 	}
332b4dbc599SNathan Whitehorn #endif
333b4dbc599SNathan Whitehorn 
334582434bdSNathan Whitehorn 	/* Check if we can read out the LED state from
335b4dbc599SNathan Whitehorn 	   this keyboard by reading the key state register */
336582434bdSNathan Whitehorn 	if (adb_read_register(dev, 2, NULL) == 2)
337582434bdSNathan Whitehorn 		sc->have_led_control = 1;
338582434bdSNathan Whitehorn 
339582434bdSNathan Whitehorn 	adb_set_autopoll(dev,1);
340b4dbc599SNathan Whitehorn 
341b6faf3cfSNathan Whitehorn 	handle = OF_finddevice("mac-io/via-pmu/adb/keyboard");
342b6faf3cfSNathan Whitehorn 	if (handle != -1 && OF_getprop(handle, "AAPL,has-embedded-fn-keys",
343b6faf3cfSNathan Whitehorn 	    &fkeys, sizeof(fkeys)) != -1) {
344b6faf3cfSNathan Whitehorn 		static const char *key_names[] = {"F1", "F2", "F3", "F4", "F5",
345b6faf3cfSNathan Whitehorn 		    "F6", "F7", "F8", "F9", "F10", "F11", "F12"};
346b6faf3cfSNathan Whitehorn 		struct sysctl_ctx_list *ctx;
347b6faf3cfSNathan Whitehorn 		struct sysctl_oid *tree;
348b6faf3cfSNathan Whitehorn 		int i;
349b6faf3cfSNathan Whitehorn 
350b6faf3cfSNathan Whitehorn 		if (bootverbose)
351b6faf3cfSNathan Whitehorn 			device_printf(dev, "Keyboard has embedded Fn keys\n");
352b6faf3cfSNathan Whitehorn 
353b6faf3cfSNathan Whitehorn 		for (i = 0; i < 12; i++) {
354b6faf3cfSNathan Whitehorn 			uint32_t keyval;
355b6faf3cfSNathan Whitehorn 			char buf[3];
356b6faf3cfSNathan Whitehorn 			if (OF_getprop(handle, key_names[i], &keyval,
357b6faf3cfSNathan Whitehorn 			    sizeof(keyval)) < 0)
358b6faf3cfSNathan Whitehorn 				continue;
359b6faf3cfSNathan Whitehorn 			buf[0] = 1;
360b6faf3cfSNathan Whitehorn 			buf[1] = i+1;
361b6faf3cfSNathan Whitehorn 			buf[2] = keyval;
362b6faf3cfSNathan Whitehorn 			adb_write_register(dev, 0, 3, buf);
363b6faf3cfSNathan Whitehorn 		}
364b6faf3cfSNathan Whitehorn 		adb_write_register(dev, 1, 2, &(uint16_t){0});
365b6faf3cfSNathan Whitehorn 
366b6faf3cfSNathan Whitehorn 		ctx = device_get_sysctl_ctx(dev);
367b6faf3cfSNathan Whitehorn 		tree = device_get_sysctl_tree(dev);
368b6faf3cfSNathan Whitehorn 
369b6faf3cfSNathan Whitehorn 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
3707029da5cSPawel Biernacki 		    "fn_keys_function_as_primary",
3717029da5cSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,
372b6faf3cfSNathan Whitehorn 		    0, adb_fn_keys, "I",
373b6faf3cfSNathan Whitehorn 		    "Set the Fn keys to be their F-key type as default");
374b6faf3cfSNathan Whitehorn 	}
375b6faf3cfSNathan Whitehorn 
376b4dbc599SNathan Whitehorn 	return (0);
377b4dbc599SNathan Whitehorn }
378b4dbc599SNathan Whitehorn 
379b4dbc599SNathan Whitehorn static int
380b4dbc599SNathan Whitehorn adb_kbd_detach(device_t dev)
381b4dbc599SNathan Whitehorn {
382b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
383b4dbc599SNathan Whitehorn 	keyboard_t *kbd;
384b4dbc599SNathan Whitehorn 
385b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
386b4dbc599SNathan Whitehorn 
387b4dbc599SNathan Whitehorn 	adb_set_autopoll(dev,0);
388b4dbc599SNathan Whitehorn 	callout_stop(&sc->sc_repeater);
389b4dbc599SNathan Whitehorn 
390b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
391b4dbc599SNathan Whitehorn 
392b4dbc599SNathan Whitehorn 	kbd = kbd_get_keyboard(kbd_find_keyboard(KBD_DRIVER_NAME,
393b4dbc599SNathan Whitehorn 	          device_get_unit(dev)));
394b4dbc599SNathan Whitehorn 
395b4dbc599SNathan Whitehorn 	kbdd_disable(kbd);
396b4dbc599SNathan Whitehorn 
397b4dbc599SNathan Whitehorn #ifdef KBD_INSTALL_CDEV
398b4dbc599SNathan Whitehorn 	kbd_detach(kbd);
399b4dbc599SNathan Whitehorn #endif
400b4dbc599SNathan Whitehorn 
401b4dbc599SNathan Whitehorn 	kbdd_term(kbd);
402b4dbc599SNathan Whitehorn 
403b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
404b4dbc599SNathan Whitehorn 
405b4dbc599SNathan Whitehorn 	mtx_destroy(&sc->sc_mutex);
406b4dbc599SNathan Whitehorn 	cv_destroy(&sc->sc_cv);
407b4dbc599SNathan Whitehorn 
408b4dbc599SNathan Whitehorn 	return (0);
409b4dbc599SNathan Whitehorn }
410b4dbc599SNathan Whitehorn 
411b4dbc599SNathan Whitehorn static u_int
412b4dbc599SNathan Whitehorn adb_kbd_receive_packet(device_t dev, u_char status,
413b4dbc599SNathan Whitehorn     u_char command, u_char reg, int len, u_char *data)
414b4dbc599SNathan Whitehorn {
415b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
416b4dbc599SNathan Whitehorn 
417b4dbc599SNathan Whitehorn 	sc = device_get_softc(dev);
418b4dbc599SNathan Whitehorn 
419b4dbc599SNathan Whitehorn 	if (command != ADB_COMMAND_TALK)
420b4dbc599SNathan Whitehorn 		return 0;
421b4dbc599SNathan Whitehorn 
422b4dbc599SNathan Whitehorn 	if (reg != 0 || len != 2)
423b4dbc599SNathan Whitehorn 		return (0);
424b4dbc599SNathan Whitehorn 
425b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
426b6faf3cfSNathan Whitehorn 		/* 0x7f is always the power button */
4270b3a30a6SJustin Hibbits 		if (data[0] == 0x7f) {
428b6faf3cfSNathan Whitehorn 			devctl_notify("PMU", "Button", "pressed", NULL);
429ff1b355cSJustin Hibbits 			mtx_unlock(&sc->sc_mutex);
430b6faf3cfSNathan Whitehorn 			return (0);
431b6faf3cfSNathan Whitehorn 		} else if (data[0] == 0xff) {
432ff1b355cSJustin Hibbits 			mtx_unlock(&sc->sc_mutex);
433b6faf3cfSNathan Whitehorn 			return (0);	/* Ignore power button release. */
434b6faf3cfSNathan Whitehorn 		}
435b4dbc599SNathan Whitehorn 		if ((data[0] & 0x7f) == 57 && sc->buffers < 7) {
436b4dbc599SNathan Whitehorn 			/* Fake the down/up cycle for caps lock */
437b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[0] & 0x7f;
438b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = (data[0] & 0x7f) | (1 << 7);
439b4dbc599SNathan Whitehorn 		} else {
440b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[0];
441b4dbc599SNathan Whitehorn 		}
442b4dbc599SNathan Whitehorn 		if (sc->buffer[sc->buffers-1] < 0xff)
443b4dbc599SNathan Whitehorn 			sc->last_press = sc->buffer[sc->buffers-1];
444b4dbc599SNathan Whitehorn 
445b4dbc599SNathan Whitehorn 		if ((data[1] & 0x7f) == 57 && sc->buffers < 7) {
446b4dbc599SNathan Whitehorn 			/* Fake the down/up cycle for caps lock */
447b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[1] & 0x7f;
448b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = (data[1] & 0x7f) | (1 << 7);
449b4dbc599SNathan Whitehorn 		} else {
450b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = data[1];
451b4dbc599SNathan Whitehorn 		}
452b4dbc599SNathan Whitehorn 
453b4dbc599SNathan Whitehorn 		if (sc->buffer[sc->buffers-1] < 0xff)
454b4dbc599SNathan Whitehorn 			sc->last_press = sc->buffer[sc->buffers-1];
455b4dbc599SNathan Whitehorn 
456b4dbc599SNathan Whitehorn 		/* Stop any existing key repeating */
457b4dbc599SNathan Whitehorn 		callout_stop(&sc->sc_repeater);
458b4dbc599SNathan Whitehorn 
459b4dbc599SNathan Whitehorn 		/* Schedule a repeat callback on keydown */
460b4dbc599SNathan Whitehorn 		if (!(sc->last_press & (1 << 7))) {
461b4dbc599SNathan Whitehorn 			callout_reset(&sc->sc_repeater,
462b4dbc599SNathan Whitehorn 			    ms_to_ticks(sc->sc_kbd.kb_delay1), akbd_repeat, sc);
463b4dbc599SNathan Whitehorn 		}
464b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
465b4dbc599SNathan Whitehorn 
466b4dbc599SNathan Whitehorn 	cv_broadcast(&sc->sc_cv);
467b4dbc599SNathan Whitehorn 
468b4dbc599SNathan Whitehorn 	if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
469b4dbc599SNathan Whitehorn 		sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
470b4dbc599SNathan Whitehorn 			 KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
471b4dbc599SNathan Whitehorn 	}
472b4dbc599SNathan Whitehorn 
473b4dbc599SNathan Whitehorn 	return (0);
474b4dbc599SNathan Whitehorn }
475b4dbc599SNathan Whitehorn 
476b4dbc599SNathan Whitehorn static void
477b4dbc599SNathan Whitehorn akbd_repeat(void *xsc) {
478b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc = xsc;
479b4dbc599SNathan Whitehorn 	int notify_kbd = 0;
480b4dbc599SNathan Whitehorn 
481b4dbc599SNathan Whitehorn 	/* Fake an up/down key repeat so long as we have the
482b4dbc599SNathan Whitehorn 	   free buffers */
483b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
484b4dbc599SNathan Whitehorn 		if (sc->buffers < 7) {
485b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = sc->last_press | (1 << 7);
486b4dbc599SNathan Whitehorn 			sc->buffer[sc->buffers++] = sc->last_press;
487b4dbc599SNathan Whitehorn 
488b4dbc599SNathan Whitehorn 			notify_kbd = 1;
489b4dbc599SNathan Whitehorn 		}
490b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
491b4dbc599SNathan Whitehorn 
492b4dbc599SNathan Whitehorn 	if (notify_kbd && KBD_IS_ACTIVE(&sc->sc_kbd)
493b4dbc599SNathan Whitehorn 	    && KBD_IS_BUSY(&sc->sc_kbd)) {
494b4dbc599SNathan Whitehorn 		sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
495b4dbc599SNathan Whitehorn 		    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
496b4dbc599SNathan Whitehorn 	}
497b4dbc599SNathan Whitehorn 
498b4dbc599SNathan Whitehorn 	/* Reschedule the callout */
499b4dbc599SNathan Whitehorn 	callout_reset(&sc->sc_repeater, ms_to_ticks(sc->sc_kbd.kb_delay2),
500b4dbc599SNathan Whitehorn 	    akbd_repeat, sc);
501b4dbc599SNathan Whitehorn }
502b4dbc599SNathan Whitehorn 
503b4dbc599SNathan Whitehorn static int
504b4dbc599SNathan Whitehorn akbd_configure(int flags)
505b4dbc599SNathan Whitehorn {
506b4dbc599SNathan Whitehorn 	return 0;
507b4dbc599SNathan Whitehorn }
508b4dbc599SNathan Whitehorn 
509b4dbc599SNathan Whitehorn static int
510b4dbc599SNathan Whitehorn akbd_probe(int unit, void *arg, int flags)
511b4dbc599SNathan Whitehorn {
512b4dbc599SNathan Whitehorn 	return 0;
513b4dbc599SNathan Whitehorn }
514b4dbc599SNathan Whitehorn 
515b4dbc599SNathan Whitehorn static int
516b4dbc599SNathan Whitehorn akbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
517b4dbc599SNathan Whitehorn {
518b4dbc599SNathan Whitehorn 	return 0;
519b4dbc599SNathan Whitehorn }
520b4dbc599SNathan Whitehorn 
521b4dbc599SNathan Whitehorn static int
522b4dbc599SNathan Whitehorn akbd_term(keyboard_t *kbd)
523b4dbc599SNathan Whitehorn {
524b4dbc599SNathan Whitehorn 	return 0;
525b4dbc599SNathan Whitehorn }
526b4dbc599SNathan Whitehorn 
527b4dbc599SNathan Whitehorn static int
528b4dbc599SNathan Whitehorn akbd_interrupt(keyboard_t *kbd, void *arg)
529b4dbc599SNathan Whitehorn {
530b4dbc599SNathan Whitehorn 	return 0;
531b4dbc599SNathan Whitehorn }
532b4dbc599SNathan Whitehorn 
533b4dbc599SNathan Whitehorn static int
534b4dbc599SNathan Whitehorn akbd_test_if(keyboard_t *kbd)
535b4dbc599SNathan Whitehorn {
536b4dbc599SNathan Whitehorn 	return 0;
537b4dbc599SNathan Whitehorn }
538b4dbc599SNathan Whitehorn 
539b4dbc599SNathan Whitehorn static int
540b4dbc599SNathan Whitehorn akbd_enable(keyboard_t *kbd)
541b4dbc599SNathan Whitehorn {
542b4dbc599SNathan Whitehorn 	KBD_ACTIVATE(kbd);
543b4dbc599SNathan Whitehorn 	return (0);
544b4dbc599SNathan Whitehorn }
545b4dbc599SNathan Whitehorn 
546b4dbc599SNathan Whitehorn static int
547b4dbc599SNathan Whitehorn akbd_disable(keyboard_t *kbd)
548b4dbc599SNathan Whitehorn {
549b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
550b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
551b4dbc599SNathan Whitehorn 
552b4dbc599SNathan Whitehorn 	callout_stop(&sc->sc_repeater);
553b4dbc599SNathan Whitehorn 	KBD_DEACTIVATE(kbd);
554b4dbc599SNathan Whitehorn 	return (0);
555b4dbc599SNathan Whitehorn }
556b4dbc599SNathan Whitehorn 
557b4dbc599SNathan Whitehorn static int
558b4dbc599SNathan Whitehorn akbd_read(keyboard_t *kbd, int wait)
559b4dbc599SNathan Whitehorn {
560b4dbc599SNathan Whitehorn 	return (0);
561b4dbc599SNathan Whitehorn }
562b4dbc599SNathan Whitehorn 
563b4dbc599SNathan Whitehorn static int
564b4dbc599SNathan Whitehorn akbd_check(keyboard_t *kbd)
565b4dbc599SNathan Whitehorn {
566b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
567b4dbc599SNathan Whitehorn 
568b4dbc599SNathan Whitehorn 	if (!KBD_IS_ACTIVE(kbd))
569b4dbc599SNathan Whitehorn 		return (FALSE);
570b4dbc599SNathan Whitehorn 
571b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
572b4dbc599SNathan Whitehorn 
573b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
5744fb52093SNathan Whitehorn #ifdef AKBD_EMULATE_ATKBD
5754fb52093SNathan Whitehorn 		if (sc->at_buffered_char[0]) {
5764fb52093SNathan Whitehorn 			mtx_unlock(&sc->sc_mutex);
5774fb52093SNathan Whitehorn 			return (TRUE);
5784fb52093SNathan Whitehorn 		}
5794fb52093SNathan Whitehorn #endif
5804fb52093SNathan Whitehorn 
581b4dbc599SNathan Whitehorn 		if (sc->buffers > 0) {
582b4dbc599SNathan Whitehorn 			mtx_unlock(&sc->sc_mutex);
583b4dbc599SNathan Whitehorn 			return (TRUE);
584b4dbc599SNathan Whitehorn 		}
585b4dbc599SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
586b4dbc599SNathan Whitehorn 
587b4dbc599SNathan Whitehorn 	return (FALSE);
588b4dbc599SNathan Whitehorn }
589b4dbc599SNathan Whitehorn 
590b4dbc599SNathan Whitehorn static u_int
591b4dbc599SNathan Whitehorn akbd_read_char(keyboard_t *kbd, int wait)
592b4dbc599SNathan Whitehorn {
593b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
5944fb52093SNathan Whitehorn 	uint16_t key;
5954fb52093SNathan Whitehorn 	uint8_t adb_code;
596b4dbc599SNathan Whitehorn 	int i;
597b4dbc599SNathan Whitehorn 
598b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
599b4dbc599SNathan Whitehorn 
600b4dbc599SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
6014fb52093SNathan Whitehorn 
6024fb52093SNathan Whitehorn #if defined(AKBD_EMULATE_ATKBD)
6034fb52093SNathan Whitehorn 	if (sc->sc_mode == K_RAW && sc->at_buffered_char[0]) {
6044fb52093SNathan Whitehorn 		key = sc->at_buffered_char[0];
6054fb52093SNathan Whitehorn 		if (key & SCAN_PREFIX) {
6064fb52093SNathan Whitehorn 			sc->at_buffered_char[0] = key & ~SCAN_PREFIX;
6074fb52093SNathan Whitehorn 			key = (key & SCAN_PREFIX_E0) ? 0xe0 : 0xe1;
6084fb52093SNathan Whitehorn 		} else {
6094fb52093SNathan Whitehorn 			sc->at_buffered_char[0] = sc->at_buffered_char[1];
6104fb52093SNathan Whitehorn 			sc->at_buffered_char[1] = 0;
6114fb52093SNathan Whitehorn 		}
6124fb52093SNathan Whitehorn 
6134fb52093SNathan Whitehorn 		mtx_unlock(&sc->sc_mutex);
6144fb52093SNathan Whitehorn 
6154fb52093SNathan Whitehorn 		return (key);
6164fb52093SNathan Whitehorn 	}
6174fb52093SNathan Whitehorn #endif
6184fb52093SNathan Whitehorn 
619b4dbc599SNathan Whitehorn 	if (!sc->buffers && wait)
620b4dbc599SNathan Whitehorn 		cv_wait(&sc->sc_cv,&sc->sc_mutex);
621b4dbc599SNathan Whitehorn 
622b4dbc599SNathan Whitehorn 	if (!sc->buffers) {
623b4dbc599SNathan Whitehorn 		mtx_unlock(&sc->sc_mutex);
624f7d6cb20SNathan Whitehorn 		return (NOKEY);
625b4dbc599SNathan Whitehorn 	}
626b4dbc599SNathan Whitehorn 
627b4dbc599SNathan Whitehorn 	adb_code = sc->buffer[0];
628b4dbc599SNathan Whitehorn 
629b4dbc599SNathan Whitehorn 	for (i = 1; i < sc->buffers; i++)
630b4dbc599SNathan Whitehorn 		sc->buffer[i-1] = sc->buffer[i];
631b4dbc599SNathan Whitehorn 
632b4dbc599SNathan Whitehorn 	sc->buffers--;
633b4dbc599SNathan Whitehorn 
634b4dbc599SNathan Whitehorn 	#ifdef AKBD_EMULATE_ATKBD
6354fb52093SNathan Whitehorn 		key = adb_to_at_scancode_map[adb_code & 0x7f];
6364fb52093SNathan Whitehorn 		if (sc->sc_mode == K_CODE) {
6374fb52093SNathan Whitehorn 			/* Add the key-release bit */
6384fb52093SNathan Whitehorn 			key |= adb_code & 0x80;
6394fb52093SNathan Whitehorn 		} else if (sc->sc_mode == K_RAW) {
6404fb52093SNathan Whitehorn 			/*
6414fb52093SNathan Whitehorn 			 * In the raw case, we have to emulate the gross
6424fb52093SNathan Whitehorn 			 * variable-length AT keyboard thing. Since this code
6434fb52093SNathan Whitehorn 			 * is copied from sunkbd, which is the same code
6444fb52093SNathan Whitehorn 			 * as ukbd, it might be nice to have this centralized.
6454fb52093SNathan Whitehorn 			 */
6464fb52093SNathan Whitehorn 
6474fb52093SNathan Whitehorn 			key = keycode2scancode(key,
6484fb52093SNathan Whitehorn 			    0, adb_code & 0x80);
6494fb52093SNathan Whitehorn 
6504fb52093SNathan Whitehorn 			if (key & SCAN_PREFIX) {
6514fb52093SNathan Whitehorn 				if (key & SCAN_PREFIX_CTL) {
6524fb52093SNathan Whitehorn 					sc->at_buffered_char[0] =
6534fb52093SNathan Whitehorn 					    0x1d | (key & SCAN_RELEASE);
6544fb52093SNathan Whitehorn 					sc->at_buffered_char[1] =
6554fb52093SNathan Whitehorn 					    key & ~SCAN_PREFIX;
6564fb52093SNathan Whitehorn 				} else if (key & SCAN_PREFIX_SHIFT) {
6574fb52093SNathan Whitehorn 					sc->at_buffered_char[0] =
6584fb52093SNathan Whitehorn 					    0x2a | (key & SCAN_RELEASE);
6594fb52093SNathan Whitehorn 					sc->at_buffered_char[1] =
6604fb52093SNathan Whitehorn 					    key & ~SCAN_PREFIX_SHIFT;
6614fb52093SNathan Whitehorn 				} else {
6624fb52093SNathan Whitehorn 					sc->at_buffered_char[0] =
6634fb52093SNathan Whitehorn 					    key & ~SCAN_PREFIX;
6644fb52093SNathan Whitehorn 					sc->at_buffered_char[1] = 0;
6654fb52093SNathan Whitehorn 				}
6664fb52093SNathan Whitehorn 
6674fb52093SNathan Whitehorn 				key = (key & SCAN_PREFIX_E0) ? 0xe0 : 0xe1;
6684fb52093SNathan Whitehorn 			}
6694fb52093SNathan Whitehorn 		}
670b4dbc599SNathan Whitehorn 	#else
6714fb52093SNathan Whitehorn 		key = adb_code;
672b4dbc599SNathan Whitehorn 	#endif
673b4dbc599SNathan Whitehorn 
6744fb52093SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
6754fb52093SNathan Whitehorn 
6764fb52093SNathan Whitehorn 	return (key);
677b4dbc599SNathan Whitehorn }
678b4dbc599SNathan Whitehorn 
679b4dbc599SNathan Whitehorn static int
680b4dbc599SNathan Whitehorn akbd_check_char(keyboard_t *kbd)
681b4dbc599SNathan Whitehorn {
682b4dbc599SNathan Whitehorn 	if (!KBD_IS_ACTIVE(kbd))
683b4dbc599SNathan Whitehorn 		return (FALSE);
684b4dbc599SNathan Whitehorn 
685b4dbc599SNathan Whitehorn 	return (akbd_check(kbd));
686b4dbc599SNathan Whitehorn }
687b4dbc599SNathan Whitehorn 
688b4dbc599SNathan Whitehorn static int
689b4dbc599SNathan Whitehorn set_typematic(keyboard_t *kbd, int code)
690b4dbc599SNathan Whitehorn {
691b4dbc599SNathan Whitehorn 	/* These numbers are in microseconds, so convert to ticks */
692b4dbc599SNathan Whitehorn 
693b4dbc599SNathan Whitehorn 	static int delays[] = { 250, 500, 750, 1000 };
694b4dbc599SNathan Whitehorn 	static int rates[] = {  34,  38,  42,  46,  50,  55,  59,  63,
695b4dbc599SNathan Whitehorn 				68,  76,  84,  92, 100, 110, 118, 126,
696b4dbc599SNathan Whitehorn 				136, 152, 168, 184, 200, 220, 236, 252,
697b4dbc599SNathan Whitehorn 				272, 304, 336, 368, 400, 440, 472, 504 };
698b4dbc599SNathan Whitehorn 
699b4dbc599SNathan Whitehorn 	if (code & ~0x7f)
700b4dbc599SNathan Whitehorn 		return EINVAL;
701b4dbc599SNathan Whitehorn 	kbd->kb_delay1 = delays[(code >> 5) & 3];
702b4dbc599SNathan Whitehorn 	kbd->kb_delay2 = rates[code & 0x1f];
703b4dbc599SNathan Whitehorn 	return 0;
704b4dbc599SNathan Whitehorn }
705b4dbc599SNathan Whitehorn 
706b4dbc599SNathan Whitehorn static int akbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
707b4dbc599SNathan Whitehorn {
708b4dbc599SNathan Whitehorn 	struct adb_kbd_softc *sc;
709b4dbc599SNathan Whitehorn 	uint16_t r2;
710b4dbc599SNathan Whitehorn 	int error;
711b4dbc599SNathan Whitehorn 
712b4dbc599SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
713b4dbc599SNathan Whitehorn 	error = 0;
714b4dbc599SNathan Whitehorn 
715b4dbc599SNathan Whitehorn 	switch (cmd) {
716b4dbc599SNathan Whitehorn 	case KDGKBMODE:
717b4dbc599SNathan Whitehorn 		*(int *)data = sc->sc_mode;
718b4dbc599SNathan Whitehorn 		break;
719b4dbc599SNathan Whitehorn 	case KDSKBMODE:
720b4dbc599SNathan Whitehorn 		switch (*(int *)data) {
721b4dbc599SNathan Whitehorn 		case K_XLATE:
722b4dbc599SNathan Whitehorn 			if (sc->sc_mode != K_XLATE) {
723b4dbc599SNathan Whitehorn 				/* make lock key state and LED state match */
724b4dbc599SNathan Whitehorn 				sc->sc_state &= ~LOCK_MASK;
725b4dbc599SNathan Whitehorn 				sc->sc_state |= KBD_LED_VAL(kbd);
726b4dbc599SNathan Whitehorn 			}
727b4dbc599SNathan Whitehorn 			/* FALLTHROUGH */
728b4dbc599SNathan Whitehorn 		case K_RAW:
729b4dbc599SNathan Whitehorn 		case K_CODE:
730b4dbc599SNathan Whitehorn 			if (sc->sc_mode != *(int *)data)
731b4dbc599SNathan Whitehorn 				sc->sc_mode = *(int *)data;
732b4dbc599SNathan Whitehorn 			break;
733b4dbc599SNathan Whitehorn 		default:
734b4dbc599SNathan Whitehorn 			error = EINVAL;
735b4dbc599SNathan Whitehorn 			break;
736b4dbc599SNathan Whitehorn 		}
737b4dbc599SNathan Whitehorn 
738b4dbc599SNathan Whitehorn 		break;
739b4dbc599SNathan Whitehorn 
740b4dbc599SNathan Whitehorn 	case KDGETLED:
741b4dbc599SNathan Whitehorn 		*(int *)data = KBD_LED_VAL(kbd);
742b4dbc599SNathan Whitehorn 		break;
743b4dbc599SNathan Whitehorn 
744b4dbc599SNathan Whitehorn 	case KDSKBSTATE:
745b4dbc599SNathan Whitehorn 		if (*(int *)data & ~LOCK_MASK) {
746b4dbc599SNathan Whitehorn 			error = EINVAL;
747b4dbc599SNathan Whitehorn 			break;
748b4dbc599SNathan Whitehorn 		}
749b4dbc599SNathan Whitehorn 		sc->sc_state &= ~LOCK_MASK;
750b4dbc599SNathan Whitehorn 		sc->sc_state |= *(int *)data;
751b4dbc599SNathan Whitehorn 
752b4dbc599SNathan Whitehorn 		/* FALLTHROUGH */
753b4dbc599SNathan Whitehorn 
754b4dbc599SNathan Whitehorn 	case KDSETLED:
755b4dbc599SNathan Whitehorn 		KBD_LED_VAL(kbd) = *(int *)data;
756b4dbc599SNathan Whitehorn 
757b4dbc599SNathan Whitehorn 		if (!sc->have_led_control)
758b4dbc599SNathan Whitehorn 			break;
759b4dbc599SNathan Whitehorn 
760b4dbc599SNathan Whitehorn 		r2 = (~0 & 0x04) | 3;
761b4dbc599SNathan Whitehorn 
762b4dbc599SNathan Whitehorn 		if (*(int *)data & NLKED)
763b4dbc599SNathan Whitehorn 			r2 &= ~1;
764b4dbc599SNathan Whitehorn 		if (*(int *)data & CLKED)
765b4dbc599SNathan Whitehorn 			r2 &= ~2;
766b4dbc599SNathan Whitehorn 		if (*(int *)data & SLKED)
767b4dbc599SNathan Whitehorn 			r2 &= ~4;
768b4dbc599SNathan Whitehorn 
769b4dbc599SNathan Whitehorn 		adb_send_packet(sc->sc_dev,ADB_COMMAND_LISTEN,2,
770b4dbc599SNathan Whitehorn 			sizeof(uint16_t),(u_char *)&r2);
771b4dbc599SNathan Whitehorn 
772b4dbc599SNathan Whitehorn 		break;
773b4dbc599SNathan Whitehorn 
774b4dbc599SNathan Whitehorn 	case KDGKBSTATE:
775b4dbc599SNathan Whitehorn 		*(int *)data = sc->sc_state & LOCK_MASK;
776b4dbc599SNathan Whitehorn 		break;
777b4dbc599SNathan Whitehorn 
778b4dbc599SNathan Whitehorn 	case KDSETREPEAT:
779b4dbc599SNathan Whitehorn 		if (!KBD_HAS_DEVICE(kbd))
780b4dbc599SNathan Whitehorn 			return 0;
781b4dbc599SNathan Whitehorn 		if (((int *)data)[1] < 0)
782b4dbc599SNathan Whitehorn 			return EINVAL;
783b4dbc599SNathan Whitehorn 		if (((int *)data)[0] < 0)
784b4dbc599SNathan Whitehorn 			return EINVAL;
785b4dbc599SNathan Whitehorn 		else if (((int *)data)[0] == 0)  /* fastest possible value */
786b4dbc599SNathan Whitehorn 			kbd->kb_delay1 = 200;
787b4dbc599SNathan Whitehorn 		else
788b4dbc599SNathan Whitehorn 			kbd->kb_delay1 = ((int *)data)[0];
789b4dbc599SNathan Whitehorn 		kbd->kb_delay2 = ((int *)data)[1];
790b4dbc599SNathan Whitehorn 
791b4dbc599SNathan Whitehorn 		break;
792b4dbc599SNathan Whitehorn 
793b4dbc599SNathan Whitehorn 	case KDSETRAD:
794b4dbc599SNathan Whitehorn 		error = set_typematic(kbd, *(int *)data);
795b4dbc599SNathan Whitehorn 		break;
796b4dbc599SNathan Whitehorn 
797b4dbc599SNathan Whitehorn 	case PIO_KEYMAP:
798b4dbc599SNathan Whitehorn 	case PIO_KEYMAPENT:
799b4dbc599SNathan Whitehorn 	case PIO_DEADKEYMAP:
800*f2005895SStefan Eßer #ifdef COMPAT_FREEBSD13
801*f2005895SStefan Eßer 	case OPIO_KEYMAP:
8024972fb92SStefan Eßer 	case OPIO_DEADKEYMAP:
803*f2005895SStefan Eßer #endif /* COMPAT_FREEBSD13 */
804b4dbc599SNathan Whitehorn 	default:
805b4dbc599SNathan Whitehorn 		return (genkbd_commonioctl(kbd, cmd, data));
806b4dbc599SNathan Whitehorn 	}
807b4dbc599SNathan Whitehorn 
808b4dbc599SNathan Whitehorn 	return (error);
809b4dbc599SNathan Whitehorn }
810b4dbc599SNathan Whitehorn 
811b4dbc599SNathan Whitehorn static int akbd_lock(keyboard_t *kbd, int lock)
812b4dbc599SNathan Whitehorn {
813b4dbc599SNathan Whitehorn 	return (0);
814b4dbc599SNathan Whitehorn }
815b4dbc599SNathan Whitehorn 
816b4dbc599SNathan Whitehorn static void akbd_clear_state(keyboard_t *kbd)
817b4dbc599SNathan Whitehorn {
8184fb52093SNathan Whitehorn 	struct adb_kbd_softc *sc;
8194fb52093SNathan Whitehorn 
8204fb52093SNathan Whitehorn 	sc = (struct adb_kbd_softc *)(kbd);
8214fb52093SNathan Whitehorn 
8224fb52093SNathan Whitehorn 	mtx_lock(&sc->sc_mutex);
8234fb52093SNathan Whitehorn 
8244fb52093SNathan Whitehorn 	sc->buffers = 0;
8254fb52093SNathan Whitehorn 	callout_stop(&sc->sc_repeater);
8264fb52093SNathan Whitehorn 
8274fb52093SNathan Whitehorn #if defined(AKBD_EMULATE_ATKBD)
8284fb52093SNathan Whitehorn 	sc->at_buffered_char[0] = 0;
8294fb52093SNathan Whitehorn 	sc->at_buffered_char[1] = 0;
8304fb52093SNathan Whitehorn #endif
8314fb52093SNathan Whitehorn 	mtx_unlock(&sc->sc_mutex);
832b4dbc599SNathan Whitehorn }
833b4dbc599SNathan Whitehorn 
834b4dbc599SNathan Whitehorn static int akbd_get_state(keyboard_t *kbd, void *buf, size_t len)
835b4dbc599SNathan Whitehorn {
836b4dbc599SNathan Whitehorn 	return (0);
837b4dbc599SNathan Whitehorn }
838b4dbc599SNathan Whitehorn 
839b4dbc599SNathan Whitehorn static int akbd_set_state(keyboard_t *kbd, void *buf, size_t len)
840b4dbc599SNathan Whitehorn {
841b4dbc599SNathan Whitehorn 	return (0);
842b4dbc599SNathan Whitehorn }
843b4dbc599SNathan Whitehorn 
844b4dbc599SNathan Whitehorn static int akbd_poll(keyboard_t *kbd, int on)
845b4dbc599SNathan Whitehorn {
846b4dbc599SNathan Whitehorn 	return (0);
847b4dbc599SNathan Whitehorn }
848b4dbc599SNathan Whitehorn 
849b4dbc599SNathan Whitehorn static int
850b4dbc599SNathan Whitehorn akbd_modevent(module_t mod, int type, void *data)
851b4dbc599SNathan Whitehorn {
852b4dbc599SNathan Whitehorn 	switch (type) {
853b4dbc599SNathan Whitehorn 	case MOD_LOAD:
854b4dbc599SNathan Whitehorn 		kbd_add_driver(&akbd_kbd_driver);
855b4dbc599SNathan Whitehorn 		break;
856b4dbc599SNathan Whitehorn 
857b4dbc599SNathan Whitehorn 	case MOD_UNLOAD:
858b4dbc599SNathan Whitehorn 		kbd_delete_driver(&akbd_kbd_driver);
859b4dbc599SNathan Whitehorn 		break;
860b4dbc599SNathan Whitehorn 
861b4dbc599SNathan Whitehorn 	default:
862b4dbc599SNathan Whitehorn 		return (EOPNOTSUPP);
863b4dbc599SNathan Whitehorn 	}
864b4dbc599SNathan Whitehorn 
865b4dbc599SNathan Whitehorn 	return (0);
866b4dbc599SNathan Whitehorn }
867b4dbc599SNathan Whitehorn 
868b6faf3cfSNathan Whitehorn static int
869b6faf3cfSNathan Whitehorn adb_fn_keys(SYSCTL_HANDLER_ARGS)
870b6faf3cfSNathan Whitehorn {
871b6faf3cfSNathan Whitehorn 	struct adb_kbd_softc *sc = arg1;
872b6faf3cfSNathan Whitehorn 	int error;
873b6faf3cfSNathan Whitehorn 	uint16_t is_fn_enabled;
874b6faf3cfSNathan Whitehorn 	unsigned int is_fn_enabled_sysctl;
875b6faf3cfSNathan Whitehorn 
876b6faf3cfSNathan Whitehorn 	adb_read_register(sc->sc_dev, 1, &is_fn_enabled);
877b6faf3cfSNathan Whitehorn 	is_fn_enabled &= 1;
878b6faf3cfSNathan Whitehorn 	is_fn_enabled_sysctl = is_fn_enabled;
879b6faf3cfSNathan Whitehorn 	error = sysctl_handle_int(oidp, &is_fn_enabled_sysctl, 0, req);
880b6faf3cfSNathan Whitehorn 
881b6faf3cfSNathan Whitehorn 	if (error || !req->newptr)
882b6faf3cfSNathan Whitehorn 		return (error);
883b6faf3cfSNathan Whitehorn 
884b6faf3cfSNathan Whitehorn 	is_fn_enabled = is_fn_enabled_sysctl;
885b6faf3cfSNathan Whitehorn 	if (is_fn_enabled != 1 && is_fn_enabled != 0)
886b6faf3cfSNathan Whitehorn 		return (EINVAL);
887b6faf3cfSNathan Whitehorn 
888b6faf3cfSNathan Whitehorn 	adb_write_register(sc->sc_dev, 1, 2, &is_fn_enabled);
889b6faf3cfSNathan Whitehorn 	return (0);
890b6faf3cfSNathan Whitehorn }
891b6faf3cfSNathan Whitehorn 
892b4dbc599SNathan Whitehorn DEV_MODULE(akbd, akbd_modevent, NULL);
893