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