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