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