1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: stable/11/sys/dev/usb/input/ukbd.c 359559 2020-04-02 07:42:29Z hselasky $");
3184610Salfred
4184610Salfred
5184610Salfred/*-
6184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc.
7184610Salfred * All rights reserved.
8184610Salfred *
9184610Salfred * This code is derived from software contributed to The NetBSD Foundation
10184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at
11184610Salfred * Carlstedt Research & Technology.
12184610Salfred *
13184610Salfred * Redistribution and use in source and binary forms, with or without
14184610Salfred * modification, are permitted provided that the following conditions
15184610Salfred * are met:
16184610Salfred * 1. Redistributions of source code must retain the above copyright
17184610Salfred *    notice, this list of conditions and the following disclaimer.
18184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
19184610Salfred *    notice, this list of conditions and the following disclaimer in the
20184610Salfred *    documentation and/or other materials provided with the distribution.
21184610Salfred *
22184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25184610Salfred * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32184610Salfred * POSSIBILITY OF SUCH DAMAGE.
33184610Salfred *
34184610Salfred */
35184610Salfred
36184610Salfred/*
37184610Salfred * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
38184610Salfred */
39184610Salfred
40184610Salfred#include "opt_compat.h"
41184610Salfred#include "opt_kbd.h"
42184610Salfred#include "opt_ukbd.h"
43307764Sgonzo#include "opt_evdev.h"
44184610Salfred
45194677Sthompsa#include <sys/stdint.h>
46194677Sthompsa#include <sys/stddef.h>
47194677Sthompsa#include <sys/param.h>
48194677Sthompsa#include <sys/queue.h>
49194677Sthompsa#include <sys/types.h>
50194677Sthompsa#include <sys/systm.h>
51194677Sthompsa#include <sys/kernel.h>
52194677Sthompsa#include <sys/bus.h>
53194677Sthompsa#include <sys/module.h>
54194677Sthompsa#include <sys/lock.h>
55194677Sthompsa#include <sys/mutex.h>
56194677Sthompsa#include <sys/condvar.h>
57194677Sthompsa#include <sys/sysctl.h>
58194677Sthompsa#include <sys/sx.h>
59194677Sthompsa#include <sys/unistd.h>
60194677Sthompsa#include <sys/callout.h>
61194677Sthompsa#include <sys/malloc.h>
62194677Sthompsa#include <sys/priv.h>
63223989Shselasky#include <sys/proc.h>
64223989Shselasky#include <sys/sched.h>
65198152Sthompsa#include <sys/kdb.h>
66194677Sthompsa
67188942Sthompsa#include <dev/usb/usb.h>
68194677Sthompsa#include <dev/usb/usbdi.h>
69194677Sthompsa#include <dev/usb/usbdi_util.h>
70188942Sthompsa#include <dev/usb/usbhid.h>
71184610Salfred
72184610Salfred#define	USB_DEBUG_VAR ukbd_debug
73188942Sthompsa#include <dev/usb/usb_debug.h>
74184610Salfred
75188942Sthompsa#include <dev/usb/quirk/usb_quirk.h>
76184610Salfred
77307775Sgonzo#ifdef EVDEV_SUPPORT
78307764Sgonzo#include <dev/evdev/input.h>
79307764Sgonzo#include <dev/evdev/evdev.h>
80307764Sgonzo#endif
81307764Sgonzo
82184610Salfred#include <sys/ioccom.h>
83184610Salfred#include <sys/filio.h>
84184610Salfred#include <sys/kbio.h>
85184610Salfred
86184610Salfred#include <dev/kbd/kbdreg.h>
87184610Salfred
88184610Salfred/* the initial key map, accent map and fkey strings */
89184610Salfred#if defined(UKBD_DFLT_KEYMAP) && !defined(KLD_MODULE)
90184610Salfred#define	KBD_DFLT_KEYMAP
91184610Salfred#include "ukbdmap.h"
92184610Salfred#endif
93184610Salfred
94184610Salfred/* the following file must be included after "ukbdmap.h" */
95184610Salfred#include <dev/kbd/kbdtables.h>
96184610Salfred
97207077Sthompsa#ifdef USB_DEBUG
98184610Salfredstatic int ukbd_debug = 0;
99196489Salfredstatic int ukbd_no_leds = 0;
100253332Shselaskystatic int ukbd_pollrate = 0;
101184610Salfred
102253332Shselaskystatic SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB keyboard");
103267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RWTUN,
104184610Salfred    &ukbd_debug, 0, "Debug level");
105267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RWTUN,
106196489Salfred    &ukbd_no_leds, 0, "Disables setting of keyboard leds");
107267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RWTUN,
108253332Shselasky    &ukbd_pollrate, 0, "Force this polling rate, 1-1000Hz");
109184610Salfred#endif
110184610Salfred
111184610Salfred#define	UKBD_EMULATE_ATSCANCODE	       1
112184610Salfred#define	UKBD_DRIVER_NAME          "ukbd"
113358216Shselasky#define	UKBD_NKEYCODE                 256 /* units */
114358216Shselasky#define	UKBD_IN_BUF_SIZE  (4 * UKBD_NKEYCODE) /* scancodes */
115358216Shselasky#define	UKBD_IN_BUF_FULL  ((UKBD_IN_BUF_SIZE / 2) - 1)	/* scancodes */
116184610Salfred#define	UKBD_NFKEY        (sizeof(fkey_tab)/sizeof(fkey_tab[0]))	/* units */
117223755Shselasky#define	UKBD_BUFFER_SIZE	      64	/* bytes */
118358216Shselasky#define	UKBD_KEY_PRESSED(map, key) ({ \
119358216Shselasky	CTASSERT((key) >= 0 && (key) < UKBD_NKEYCODE); \
120358216Shselasky	((map)[(key) / 64] & (1ULL << ((key) % 64))); \
121358216Shselasky})
122184610Salfred
123358216Shselasky#define	MOD_EJECT	0x01
124358216Shselasky#define	MOD_FN		0x02
125358216Shselasky
126184610Salfredstruct ukbd_data {
127358216Shselasky	uint64_t bitmap[howmany(UKBD_NKEYCODE, 64)];
128192925Sthompsa};
129184610Salfred
130187259Sthompsaenum {
131305644Shselasky	UKBD_INTR_DT_0,
132305644Shselasky	UKBD_INTR_DT_1,
133187259Sthompsa	UKBD_CTRL_LED,
134192925Sthompsa	UKBD_N_TRANSFER,
135187259Sthompsa};
136187259Sthompsa
137184610Salfredstruct ukbd_softc {
138184610Salfred	keyboard_t sc_kbd;
139184610Salfred	keymap_t sc_keymap;
140184610Salfred	accentmap_t sc_accmap;
141184610Salfred	fkeytab_t sc_fkeymap[UKBD_NFKEY];
142358216Shselasky	uint64_t sc_loc_key_valid[howmany(UKBD_NKEYCODE, 64)];
143192925Sthompsa	struct hid_location sc_loc_apple_eject;
144192925Sthompsa	struct hid_location sc_loc_apple_fn;
145358216Shselasky	struct hid_location sc_loc_key[UKBD_NKEYCODE];
146223755Shselasky	struct hid_location sc_loc_numlock;
147223755Shselasky	struct hid_location sc_loc_capslock;
148223755Shselasky	struct hid_location sc_loc_scrolllock;
149192984Sthompsa	struct usb_callout sc_callout;
150184610Salfred	struct ukbd_data sc_ndata;
151184610Salfred	struct ukbd_data sc_odata;
152184610Salfred
153203896Sthompsa	struct thread *sc_poll_thread;
154192984Sthompsa	struct usb_device *sc_udev;
155192984Sthompsa	struct usb_interface *sc_iface;
156192984Sthompsa	struct usb_xfer *sc_xfer[UKBD_N_TRANSFER];
157307775Sgonzo#ifdef EVDEV_SUPPORT
158307764Sgonzo	struct evdev_dev *sc_evdev;
159307764Sgonzo#endif
160184610Salfred
161358215Shselasky	sbintime_t sc_co_basetime;
162358215Shselasky	int	sc_delay;
163358216Shselasky	uint32_t sc_repeat_time;
164184610Salfred	uint32_t sc_input[UKBD_IN_BUF_SIZE];	/* input buffer */
165184610Salfred	uint32_t sc_time_ms;
166184610Salfred	uint32_t sc_composed_char;	/* composed char code, if non-zero */
167184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
168184610Salfred	uint32_t sc_buffered_char[2];
169184610Salfred#endif
170184610Salfred	uint32_t sc_flags;		/* flags */
171223755Shselasky#define	UKBD_FLAG_COMPOSE	0x00000001
172223755Shselasky#define	UKBD_FLAG_POLLING	0x00000002
173223755Shselasky#define	UKBD_FLAG_SET_LEDS	0x00000004
174223755Shselasky#define	UKBD_FLAG_ATTACHED	0x00000010
175223755Shselasky#define	UKBD_FLAG_GONE		0x00000020
176184610Salfred
177223755Shselasky#define	UKBD_FLAG_HID_MASK	0x003fffc0
178223755Shselasky#define	UKBD_FLAG_APPLE_EJECT	0x00000040
179223755Shselasky#define	UKBD_FLAG_APPLE_FN	0x00000080
180223755Shselasky#define	UKBD_FLAG_APPLE_SWAP	0x00000100
181223755Shselasky#define	UKBD_FLAG_NUMLOCK	0x00080000
182223755Shselasky#define	UKBD_FLAG_CAPSLOCK	0x00100000
183223755Shselasky#define	UKBD_FLAG_SCROLLLOCK 	0x00200000
184223755Shselasky
185203896Sthompsa	int	sc_mode;		/* input mode (K_XLATE,K_RAW,K_CODE) */
186203896Sthompsa	int	sc_state;		/* shift/lock key state */
187203896Sthompsa	int	sc_accents;		/* accent key index (> 0) */
188304124Shselasky	int	sc_polling;		/* polling recursion count */
189223755Shselasky	int	sc_led_size;
190223755Shselasky	int	sc_kbd_size;
191184610Salfred
192184610Salfred	uint16_t sc_inputs;
193184610Salfred	uint16_t sc_inputhead;
194184610Salfred	uint16_t sc_inputtail;
195184610Salfred
196184610Salfred	uint8_t	sc_leds;		/* store for async led requests */
197184610Salfred	uint8_t	sc_iface_index;
198184610Salfred	uint8_t	sc_iface_no;
199223755Shselasky	uint8_t sc_id_apple_eject;
200223755Shselasky	uint8_t sc_id_apple_fn;
201358216Shselasky	uint8_t sc_id_loc_key[UKBD_NKEYCODE];
202223755Shselasky	uint8_t sc_id_numlock;
203223755Shselasky	uint8_t sc_id_capslock;
204223755Shselasky	uint8_t sc_id_scrolllock;
205192925Sthompsa	uint8_t sc_kbd_id;
206358216Shselasky	uint8_t sc_repeat_key;
207223755Shselasky
208223755Shselasky	uint8_t sc_buffer[UKBD_BUFFER_SIZE];
209184610Salfred};
210184610Salfred
211358216Shselasky#define	KEY_NONE	  0x00
212184610Salfred#define	KEY_ERROR	  0x01
213184610Salfred
214184610Salfred#define	KEY_PRESS	  0
215184610Salfred#define	KEY_RELEASE	  0x400
216184610Salfred#define	KEY_INDEX(c)	  ((c) & 0xFF)
217184610Salfred
218184610Salfred#define	SCAN_PRESS	  0
219184610Salfred#define	SCAN_RELEASE	  0x80
220184610Salfred#define	SCAN_PREFIX_E0	  0x100
221184610Salfred#define	SCAN_PREFIX_E1	  0x200
222184610Salfred#define	SCAN_PREFIX_CTL	  0x400
223184610Salfred#define	SCAN_PREFIX_SHIFT 0x800
224184610Salfred#define	SCAN_PREFIX	(SCAN_PREFIX_E0  | SCAN_PREFIX_E1 | \
225184610Salfred			 SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT)
226184610Salfred#define	SCAN_CHAR(c)	((c) & 0x7f)
227184610Salfred
228228765Savg#define	UKBD_LOCK()	mtx_lock(&Giant)
229228765Savg#define	UKBD_UNLOCK()	mtx_unlock(&Giant)
230228765Savg
231228765Savg#ifdef	INVARIANTS
232228765Savg
233228765Savg/*
234228765Savg * Assert that the lock is held in all contexts
235228765Savg * where the code can be executed.
236228765Savg */
237228765Savg#define	UKBD_LOCK_ASSERT()	mtx_assert(&Giant, MA_OWNED)
238228765Savg
239228765Savg/*
240228765Savg * Assert that the lock is held in the contexts
241228765Savg * where it really has to be so.
242228765Savg */
243228765Savg#define	UKBD_CTX_LOCK_ASSERT()			 	\
244228765Savg	do {						\
245228765Savg		if (!kdb_active && panicstr == NULL)	\
246228765Savg			mtx_assert(&Giant, MA_OWNED);	\
247228765Savg	} while (0)
248228765Savg#else
249228765Savg
250228765Savg#define UKBD_LOCK_ASSERT()	(void)0
251228765Savg#define UKBD_CTX_LOCK_ASSERT()	(void)0
252228765Savg
253228765Savg#endif
254228765Savg
255184610Salfred#define	NN 0				/* no translation */
256184610Salfred/*
257184610Salfred * Translate USB keycodes to AT keyboard scancodes.
258184610Salfred */
259184610Salfred/*
260184610Salfred * FIXME: Mac USB keyboard generates:
261184610Salfred * 0x53: keypad NumLock/Clear
262184610Salfred * 0x66: Power
263184610Salfred * 0x67: keypad =
264184610Salfred * 0x68: F13
265184610Salfred * 0x69: F14
266184610Salfred * 0x6a: F15
267291146Shselasky *
268291146Shselasky * USB Apple Keyboard JIS generates:
269291146Shselasky * 0x90: Kana
270291146Shselasky * 0x91: Eisu
271184610Salfred */
272184610Salfredstatic const uint8_t ukbd_trtab[256] = {
273184610Salfred	0, 0, 0, 0, 30, 48, 46, 32,	/* 00 - 07 */
274184610Salfred	18, 33, 34, 35, 23, 36, 37, 38,	/* 08 - 0F */
275184610Salfred	50, 49, 24, 25, 16, 19, 31, 20,	/* 10 - 17 */
276184610Salfred	22, 47, 17, 45, 21, 44, 2, 3,	/* 18 - 1F */
277184610Salfred	4, 5, 6, 7, 8, 9, 10, 11,	/* 20 - 27 */
278184610Salfred	28, 1, 14, 15, 57, 12, 13, 26,	/* 28 - 2F */
279184610Salfred	27, 43, 43, 39, 40, 41, 51, 52,	/* 30 - 37 */
280184610Salfred	53, 58, 59, 60, 61, 62, 63, 64,	/* 38 - 3F */
281184610Salfred	65, 66, 67, 68, 87, 88, 92, 70,	/* 40 - 47 */
282184610Salfred	104, 102, 94, 96, 103, 99, 101, 98,	/* 48 - 4F */
283184610Salfred	97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */
284184610Salfred	89, 79, 80, 81, 75, 76, 77, 71,	/* 58 - 5F */
285184610Salfred	72, 73, 82, 83, 86, 107, 122, NN,	/* 60 - 67 */
286184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* 68 - 6F */
287184610Salfred	NN, NN, NN, NN, 115, 108, 111, 113,	/* 70 - 77 */
288184610Salfred	109, 110, 112, 118, 114, 116, 117, 119,	/* 78 - 7F */
289197999Shrs	121, 120, NN, NN, NN, NN, NN, 123,	/* 80 - 87 */
290358213Shselasky	124, 125, 126, 127, 128, NN, NN, NN,	/* 88 - 8F */
291291146Shselasky	129, 130, NN, NN, NN, NN, NN, NN,	/* 90 - 97 */
292184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* 98 - 9F */
293184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* A0 - A7 */
294184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* A8 - AF */
295184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* B0 - B7 */
296184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* B8 - BF */
297184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* C0 - C7 */
298184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* C8 - CF */
299184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* D0 - D7 */
300184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* D8 - DF */
301184610Salfred	29, 42, 56, 105, 90, 54, 93, 106,	/* E0 - E7 */
302184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* E8 - EF */
303184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* F0 - F7 */
304184610Salfred	NN, NN, NN, NN, NN, NN, NN, NN,	/* F8 - FF */
305184610Salfred};
306184610Salfred
307223755Shselaskystatic const uint8_t ukbd_boot_desc[] = {
308223755Shselasky	0x05, 0x01, 0x09, 0x06, 0xa1,
309223755Shselasky	0x01, 0x05, 0x07, 0x19, 0xe0,
310223755Shselasky	0x29, 0xe7, 0x15, 0x00, 0x25,
311223755Shselasky	0x01, 0x75, 0x01, 0x95, 0x08,
312223755Shselasky	0x81, 0x02, 0x95, 0x01, 0x75,
313223755Shselasky	0x08, 0x81, 0x01, 0x95, 0x03,
314223755Shselasky	0x75, 0x01, 0x05, 0x08, 0x19,
315223755Shselasky	0x01, 0x29, 0x03, 0x91, 0x02,
316223755Shselasky	0x95, 0x05, 0x75, 0x01, 0x91,
317223755Shselasky	0x01, 0x95, 0x06, 0x75, 0x08,
318223755Shselasky	0x15, 0x00, 0x26, 0xff, 0x00,
319223755Shselasky	0x05, 0x07, 0x19, 0x00, 0x2a,
320223755Shselasky	0xff, 0x00, 0x81, 0x00, 0xc0
321223755Shselasky};
322223755Shselasky
323184610Salfred/* prototypes */
324185948Sthompsastatic void	ukbd_timeout(void *);
325185948Sthompsastatic void	ukbd_set_leds(struct ukbd_softc *, uint8_t);
326185948Sthompsastatic int	ukbd_set_typematic(keyboard_t *, int);
327184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
328358216Shselaskystatic uint32_t	ukbd_atkeycode(int, const uint64_t *);
329358216Shselaskystatic int	ukbd_key2scan(struct ukbd_softc *, int, const uint64_t *, int);
330184610Salfred#endif
331185948Sthompsastatic uint32_t	ukbd_read_char(keyboard_t *, int);
332185948Sthompsastatic void	ukbd_clear_state(keyboard_t *);
333185948Sthompsastatic int	ukbd_ioctl(keyboard_t *, u_long, caddr_t);
334185948Sthompsastatic int	ukbd_enable(keyboard_t *);
335185948Sthompsastatic int	ukbd_disable(keyboard_t *);
336185948Sthompsastatic void	ukbd_interrupt(struct ukbd_softc *);
337203896Sthompsastatic void	ukbd_event_keyinput(struct ukbd_softc *);
338184610Salfred
339184610Salfredstatic device_probe_t ukbd_probe;
340184610Salfredstatic device_attach_t ukbd_attach;
341184610Salfredstatic device_detach_t ukbd_detach;
342184610Salfredstatic device_resume_t ukbd_resume;
343184610Salfred
344307775Sgonzo#ifdef EVDEV_SUPPORT
345307777Sgonzostatic const struct evdev_methods ukbd_evdev_methods = {
346307764Sgonzo	.ev_event = evdev_ev_kbd_event,
347307764Sgonzo};
348307764Sgonzo#endif
349307764Sgonzo
350358216Shselaskystatic bool
351196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc)
352196489Salfred{
353358216Shselasky	bool ret = false;
354358216Shselasky	unsigned i;
355196489Salfred
356358216Shselasky	for (i = 0; i != howmany(UKBD_NKEYCODE, 64); i++)
357358216Shselasky		ret |= (sc->sc_odata.bitmap[i] != 0);
358358216Shselasky	return (ret);
359358216Shselasky}
360196489Salfred
361358216Shselaskystatic bool
362358216Shselaskyukbd_any_key_valid(struct ukbd_softc *sc)
363358216Shselasky{
364358216Shselasky	bool ret = false;
365358216Shselasky	unsigned i;
366358216Shselasky
367358216Shselasky	for (i = 0; i != howmany(UKBD_NKEYCODE, 64); i++)
368358216Shselasky		ret |= (sc->sc_loc_key_valid[i] != 0);
369358216Shselasky	return (ret);
370196489Salfred}
371196489Salfred
372358216Shselaskystatic bool
373358216Shselaskyukbd_is_modifier_key(uint32_t key)
374358216Shselasky{
375358216Shselasky
376358216Shselasky	return (key >= 0xe0 && key <= 0xe7);
377358216Shselasky}
378358216Shselasky
379184610Salfredstatic void
380196489Salfredukbd_start_timer(struct ukbd_softc *sc)
381196489Salfred{
382358215Shselasky	sbintime_t delay, now, prec;
383358215Shselasky
384358215Shselasky	now = sbinuptime();
385358215Shselasky
386358215Shselasky	/* check if initial delay passed and fallback to key repeat delay */
387358215Shselasky	if (sc->sc_delay == 0)
388358215Shselasky		sc->sc_delay = sc->sc_kbd.kb_delay2;
389358215Shselasky
390358215Shselasky	/* compute timeout */
391358215Shselasky	delay = SBT_1MS * sc->sc_delay;
392358215Shselasky	sc->sc_co_basetime += delay;
393358215Shselasky
394358215Shselasky	/* check if we are running behind */
395358215Shselasky	if (sc->sc_co_basetime < now)
396358215Shselasky		sc->sc_co_basetime = now;
397358215Shselasky
398358215Shselasky	/* This is rarely called, so prefer precision to efficiency. */
399358215Shselasky	prec = qmin(delay >> 7, SBT_1MS * 10);
400358215Shselasky	callout_reset_sbt(&sc->sc_callout.co, sc->sc_co_basetime, prec,
401358215Shselasky	    ukbd_timeout, sc, C_ABSOLUTE);
402196489Salfred}
403196489Salfred
404196489Salfredstatic void
405184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key)
406184610Salfred{
407184610Salfred
408228765Savg	UKBD_CTX_LOCK_ASSERT();
409228765Savg
410184610Salfred	DPRINTF("0x%02x (%d) %s\n", key, key,
411184610Salfred	    (key & KEY_RELEASE) ? "released" : "pressed");
412184610Salfred
413307775Sgonzo#ifdef EVDEV_SUPPORT
414307764Sgonzo	if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD && sc->sc_evdev != NULL) {
415307764Sgonzo		evdev_push_event(sc->sc_evdev, EV_KEY,
416307764Sgonzo		    evdev_hid2key(KEY_INDEX(key)), !(key & KEY_RELEASE));
417307764Sgonzo		evdev_sync(sc->sc_evdev);
418307764Sgonzo	}
419307764Sgonzo#endif
420307764Sgonzo
421184610Salfred	if (sc->sc_inputs < UKBD_IN_BUF_SIZE) {
422184610Salfred		sc->sc_input[sc->sc_inputtail] = key;
423184610Salfred		++(sc->sc_inputs);
424184610Salfred		++(sc->sc_inputtail);
425184610Salfred		if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) {
426184610Salfred			sc->sc_inputtail = 0;
427184610Salfred		}
428184610Salfred	} else {
429184610Salfred		DPRINTF("input buffer is full\n");
430184610Salfred	}
431184610Salfred}
432184610Salfred
433195960Salfredstatic void
434228765Savgukbd_do_poll(struct ukbd_softc *sc, uint8_t wait)
435223989Shselasky{
436223989Shselasky
437228765Savg	UKBD_CTX_LOCK_ASSERT();
438228765Savg	KASSERT((sc->sc_flags & UKBD_FLAG_POLLING) != 0,
439228765Savg	    ("ukbd_do_poll called when not polling\n"));
440195960Salfred	DPRINTFN(2, "polling\n");
441195960Salfred
442228765Savg	if (!kdb_active && !SCHEDULER_STOPPED()) {
443228765Savg		/*
444228765Savg		 * In this context the kernel is polling for input,
445228765Savg		 * but the USB subsystem works in normal interrupt-driven
446228765Savg		 * mode, so we just wait on the USB threads to do the job.
447228765Savg		 * Note that we currently hold the Giant, but it's also used
448228765Savg		 * as the transfer mtx, so we must release it while waiting.
449228765Savg		 */
450203896Sthompsa		while (sc->sc_inputs == 0) {
451228765Savg			/*
452228765Savg			 * Give USB threads a chance to run.  Note that
453228765Savg			 * kern_yield performs DROP_GIANT + PICKUP_GIANT.
454228765Savg			 */
455228765Savg			kern_yield(PRI_UNCHANGED);
456203896Sthompsa			if (!wait)
457203896Sthompsa				break;
458203896Sthompsa		}
459228765Savg		return;
460203896Sthompsa	}
461198152Sthompsa
462195960Salfred	while (sc->sc_inputs == 0) {
463195960Salfred
464195960Salfred		usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
465195960Salfred
466196489Salfred		/* Delay-optimised support for repetition of keys */
467196489Salfred		if (ukbd_any_key_pressed(sc)) {
468196489Salfred			/* a key is pressed - need timekeeping */
469196489Salfred			DELAY(1000);
470195960Salfred
471196489Salfred			/* 1 millisecond has passed */
472196489Salfred			sc->sc_time_ms += 1;
473196489Salfred		}
474195960Salfred
475195960Salfred		ukbd_interrupt(sc);
476195960Salfred
477195960Salfred		if (!wait)
478195960Salfred			break;
479195960Salfred	}
480195960Salfred}
481195960Salfred
482184610Salfredstatic int32_t
483184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
484184610Salfred{
485184610Salfred	int32_t c;
486184610Salfred
487228765Savg	UKBD_CTX_LOCK_ASSERT();
488228765Savg	KASSERT((!kdb_active && !SCHEDULER_STOPPED())
489228765Savg	    || (sc->sc_flags & UKBD_FLAG_POLLING) != 0,
490228765Savg	    ("not polling in kdb or panic\n"));
491184610Salfred
492261228Shselasky	if (sc->sc_inputs == 0 &&
493261228Shselasky	    (sc->sc_flags & UKBD_FLAG_GONE) == 0) {
494184610Salfred		/* start transfer, if not already started */
495305644Shselasky		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]);
496305644Shselasky		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]);
497184610Salfred	}
498203896Sthompsa
499203896Sthompsa	if (sc->sc_flags & UKBD_FLAG_POLLING)
500195960Salfred		ukbd_do_poll(sc, wait);
501203896Sthompsa
502184610Salfred	if (sc->sc_inputs == 0) {
503184610Salfred		c = -1;
504184610Salfred	} else {
505184610Salfred		c = sc->sc_input[sc->sc_inputhead];
506184610Salfred		--(sc->sc_inputs);
507184610Salfred		++(sc->sc_inputhead);
508184610Salfred		if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) {
509184610Salfred			sc->sc_inputhead = 0;
510184610Salfred		}
511184610Salfred	}
512184610Salfred	return (c);
513184610Salfred}
514184610Salfred
515184610Salfredstatic void
516184610Salfredukbd_interrupt(struct ukbd_softc *sc)
517184610Salfred{
518358216Shselasky	const uint32_t now = sc->sc_time_ms;
519358216Shselasky	unsigned key;
520184610Salfred
521228765Savg	UKBD_CTX_LOCK_ASSERT();
522228765Savg
523359559Shselasky	/* Check for modifier key changes first */
524359559Shselasky	for (key = 0xe0; key != 0xe8; key++) {
525359559Shselasky		const uint64_t mask = 1ULL << (key % 64);
526359559Shselasky		const uint64_t delta =
527359559Shselasky		    sc->sc_odata.bitmap[key / 64] ^
528359559Shselasky		    sc->sc_ndata.bitmap[key / 64];
529359559Shselasky
530359559Shselasky		if (delta & mask) {
531359559Shselasky			if (sc->sc_odata.bitmap[key / 64] & mask)
532359559Shselasky				ukbd_put_key(sc, key | KEY_RELEASE);
533359559Shselasky			else
534359559Shselasky				ukbd_put_key(sc, key | KEY_PRESS);
535359559Shselasky		}
536359559Shselasky	}
537359559Shselasky
538358216Shselasky	/* Check for key changes */
539358216Shselasky	for (key = 0; key != UKBD_NKEYCODE; key++) {
540358216Shselasky		const uint64_t mask = 1ULL << (key % 64);
541358216Shselasky		const uint64_t delta =
542358216Shselasky		    sc->sc_odata.bitmap[key / 64] ^
543358216Shselasky		    sc->sc_ndata.bitmap[key / 64];
544203896Sthompsa
545358216Shselasky		if (mask == 1 && delta == 0) {
546358216Shselasky			key += 63;
547358216Shselasky			continue;	/* skip empty areas */
548359559Shselasky		} else if (ukbd_is_modifier_key(key)) {
549359559Shselasky			continue;
550358216Shselasky		} else if (delta & mask) {
551358216Shselasky			if (sc->sc_odata.bitmap[key / 64] & mask) {
552358216Shselasky				ukbd_put_key(sc, key | KEY_RELEASE);
553184610Salfred
554358216Shselasky				/* clear repeating key, if any */
555358216Shselasky				if (sc->sc_repeat_key == key)
556358216Shselasky					sc->sc_repeat_key = 0;
557358216Shselasky			} else {
558358216Shselasky				ukbd_put_key(sc, key | KEY_PRESS);
559184610Salfred
560358697Shselasky				sc->sc_co_basetime = sbinuptime();
561358697Shselasky				sc->sc_delay = sc->sc_kbd.kb_delay1;
562358697Shselasky				ukbd_start_timer(sc);
563184610Salfred
564358216Shselasky				/* set repeat time for last key */
565358216Shselasky				sc->sc_repeat_time = now + sc->sc_kbd.kb_delay1;
566358216Shselasky				sc->sc_repeat_key = key;
567184610Salfred			}
568184610Salfred		}
569184610Salfred	}
570184610Salfred
571358216Shselasky	/* synchronize old data with new data */
572184610Salfred	sc->sc_odata = sc->sc_ndata;
573358216Shselasky
574358216Shselasky	/* check if last key is still pressed */
575358216Shselasky	if (sc->sc_repeat_key != 0) {
576358216Shselasky		const int32_t dtime = (sc->sc_repeat_time - now);
577184610Salfred
578358216Shselasky		/* check if time has elapsed */
579358216Shselasky		if (dtime <= 0) {
580358216Shselasky			ukbd_put_key(sc, sc->sc_repeat_key | KEY_PRESS);
581358216Shselasky			sc->sc_repeat_time = now + sc->sc_kbd.kb_delay2;
582358216Shselasky		}
583358216Shselasky	}
584184610Salfred
585358216Shselasky	/* wakeup keyboard system */
586203896Sthompsa	ukbd_event_keyinput(sc);
587203896Sthompsa}
588203896Sthompsa
589203896Sthompsastatic void
590203896Sthompsaukbd_event_keyinput(struct ukbd_softc *sc)
591203896Sthompsa{
592203896Sthompsa	int c;
593203896Sthompsa
594228765Savg	UKBD_CTX_LOCK_ASSERT();
595228765Savg
596228765Savg	if ((sc->sc_flags & UKBD_FLAG_POLLING) != 0)
597203896Sthompsa		return;
598203896Sthompsa
599203896Sthompsa	if (sc->sc_inputs == 0)
600203896Sthompsa		return;
601203896Sthompsa
602184610Salfred	if (KBD_IS_ACTIVE(&sc->sc_kbd) &&
603184610Salfred	    KBD_IS_BUSY(&sc->sc_kbd)) {
604184610Salfred		/* let the callback function process the input */
605184610Salfred		(sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT,
606184610Salfred		    sc->sc_kbd.kb_callback.kc_arg);
607184610Salfred	} else {
608184610Salfred		/* read and discard the input, no one is waiting for it */
609184610Salfred		do {
610184610Salfred			c = ukbd_read_char(&sc->sc_kbd, 0);
611184610Salfred		} while (c != NOKEY);
612184610Salfred	}
613184610Salfred}
614184610Salfred
615184610Salfredstatic void
616184610Salfredukbd_timeout(void *arg)
617184610Salfred{
618184610Salfred	struct ukbd_softc *sc = arg;
619184610Salfred
620228765Savg	UKBD_LOCK_ASSERT();
621184610Salfred
622358215Shselasky	sc->sc_time_ms += sc->sc_delay;
623358215Shselasky	sc->sc_delay = 0;
624203896Sthompsa
625184610Salfred	ukbd_interrupt(sc);
626184610Salfred
627203896Sthompsa	/* Make sure any leftover key events gets read out */
628203896Sthompsa	ukbd_event_keyinput(sc);
629203896Sthompsa
630203896Sthompsa	if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) {
631196489Salfred		ukbd_start_timer(sc);
632196489Salfred	}
633184610Salfred}
634184610Salfred
635358216Shselaskystatic uint32_t
636358216Shselaskyukbd_apple_fn(uint32_t keycode)
637358216Shselasky{
638192925Sthompsa	switch (keycode) {
639192925Sthompsa	case 0x28: return 0x49; /* RETURN -> INSERT */
640192925Sthompsa	case 0x2a: return 0x4c; /* BACKSPACE -> DEL */
641192925Sthompsa	case 0x50: return 0x4a; /* LEFT ARROW -> HOME */
642192925Sthompsa	case 0x4f: return 0x4d; /* RIGHT ARROW -> END */
643192925Sthompsa	case 0x52: return 0x4b; /* UP ARROW -> PGUP */
644192925Sthompsa	case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */
645192925Sthompsa	default: return keycode;
646192925Sthompsa	}
647192925Sthompsa}
648184610Salfred
649358216Shselaskystatic uint32_t
650358216Shselaskyukbd_apple_swap(uint32_t keycode)
651358216Shselasky{
652192925Sthompsa	switch (keycode) {
653192925Sthompsa	case 0x35: return 0x64;
654192925Sthompsa	case 0x64: return 0x35;
655192925Sthompsa	default: return keycode;
656184610Salfred	}
657184610Salfred}
658184610Salfred
659184610Salfredstatic void
660194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error)
661184610Salfred{
662194677Sthompsa	struct ukbd_softc *sc = usbd_xfer_softc(xfer);
663194677Sthompsa	struct usb_page_cache *pc;
664358216Shselasky	uint32_t i;
665192925Sthompsa	uint8_t id;
666358216Shselasky	uint8_t modifiers;
667358216Shselasky	int offset;
668194677Sthompsa	int len;
669184610Salfred
670228765Savg	UKBD_LOCK_ASSERT();
671228765Savg
672194677Sthompsa	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
673194677Sthompsa	pc = usbd_xfer_get_frame(xfer, 0);
674194677Sthompsa
675184610Salfred	switch (USB_GET_STATE(xfer)) {
676184610Salfred	case USB_ST_TRANSFERRED:
677184610Salfred		DPRINTF("actlen=%d bytes\n", len);
678184610Salfred
679192925Sthompsa		if (len == 0) {
680192925Sthompsa			DPRINTF("zero length data\n");
681192925Sthompsa			goto tr_setup;
682192925Sthompsa		}
683192925Sthompsa
684192925Sthompsa		if (sc->sc_kbd_id != 0) {
685192925Sthompsa			/* check and remove HID ID byte */
686194677Sthompsa			usbd_copy_out(pc, 0, &id, 1);
687223755Shselasky			offset = 1;
688223755Shselasky			len--;
689223755Shselasky			if (len == 0) {
690223755Shselasky				DPRINTF("zero length data\n");
691192925Sthompsa				goto tr_setup;
692192925Sthompsa			}
693192925Sthompsa		} else {
694192925Sthompsa			offset = 0;
695223755Shselasky			id = 0;
696192925Sthompsa		}
697192925Sthompsa
698223755Shselasky		if (len > UKBD_BUFFER_SIZE)
699223755Shselasky			len = UKBD_BUFFER_SIZE;
700192925Sthompsa
701223755Shselasky		/* get data */
702223755Shselasky		usbd_copy_out(pc, offset, sc->sc_buffer, len);
703192925Sthompsa
704223755Shselasky		/* clear temporary storage */
705223755Shselasky		memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
706192925Sthompsa
707358216Shselasky		/* clear modifiers */
708358216Shselasky		modifiers = 0;
709358216Shselasky
710223755Shselasky		/* scan through HID data */
711223755Shselasky		if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) &&
712223755Shselasky		    (id == sc->sc_id_apple_eject)) {
713223755Shselasky			if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject))
714358216Shselasky				modifiers |= MOD_EJECT;
715223755Shselasky		}
716223755Shselasky		if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) &&
717223755Shselasky		    (id == sc->sc_id_apple_fn)) {
718223755Shselasky			if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn))
719358216Shselasky				modifiers |= MOD_FN;
720223755Shselasky		}
721192925Sthompsa
722358216Shselasky		for (i = 0; i != UKBD_NKEYCODE; i++) {
723358216Shselasky			const uint64_t valid = sc->sc_loc_key_valid[i / 64];
724358216Shselasky			const uint64_t mask = 1ULL << (i % 64);
725223755Shselasky
726358216Shselasky			if (mask == 1 && valid == 0) {
727358216Shselasky				i += 63;
728358216Shselasky				continue;	/* skip empty areas */
729358216Shselasky			} else if (~valid & mask) {
730358216Shselasky				continue;	/* location is not valid */
731358216Shselasky			} else if (id != sc->sc_id_loc_key[i]) {
732358216Shselasky				continue;	/* invalid HID ID */
733358216Shselasky			} else if (i == 0) {
734358453Shselasky				struct hid_location tmp_loc = sc->sc_loc_key[0];
735358453Shselasky				/* range check array size */
736358453Shselasky				if (tmp_loc.count > UKBD_NKEYCODE)
737358453Shselasky					tmp_loc.count = UKBD_NKEYCODE;
738358453Shselasky				while (tmp_loc.count--) {
739358216Shselasky					uint32_t key =
740358453Shselasky					    hid_get_data_unsigned(sc->sc_buffer, len, &tmp_loc);
741358453Shselasky					/* advance to next location */
742358453Shselasky					tmp_loc.pos += tmp_loc.size;
743358216Shselasky					if (modifiers & MOD_FN)
744358216Shselasky						key = ukbd_apple_fn(key);
745358216Shselasky					if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP)
746358216Shselasky						key = ukbd_apple_swap(key);
747358216Shselasky					if (key == KEY_NONE || key == KEY_ERROR || key >= UKBD_NKEYCODE)
748358216Shselasky						continue;
749358216Shselasky					/* set key in bitmap */
750358216Shselasky					sc->sc_ndata.bitmap[key / 64] |= 1ULL << (key % 64);
751358216Shselasky				}
752358216Shselasky			} else if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_key[i])) {
753358216Shselasky				uint32_t key = i;
754358216Shselasky
755358216Shselasky				if (modifiers & MOD_FN)
756358216Shselasky					key = ukbd_apple_fn(key);
757358216Shselasky				if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP)
758358216Shselasky					key = ukbd_apple_swap(key);
759358216Shselasky				if (key == KEY_NONE || key == KEY_ERROR || key >= UKBD_NKEYCODE)
760358216Shselasky					continue;
761358216Shselasky				/* set key in bitmap */
762358216Shselasky				sc->sc_ndata.bitmap[key / 64] |= 1ULL << (key % 64);
763184610Salfred			}
764223755Shselasky		}
765358216Shselasky#ifdef USB_DEBUG
766358216Shselasky		DPRINTF("modifiers = 0x%04x\n", modifiers);
767358216Shselasky		for (i = 0; i != UKBD_NKEYCODE; i++) {
768358216Shselasky			const uint64_t valid = sc->sc_ndata.bitmap[i / 64];
769358216Shselasky			const uint64_t mask = 1ULL << (i % 64);
770223755Shselasky
771358216Shselasky			if (valid & mask)
772358216Shselasky				DPRINTF("Key 0x%02x pressed\n", i);
773223755Shselasky		}
774223755Shselasky#endif
775223755Shselasky		ukbd_interrupt(sc);
776192925Sthompsa
777184610Salfred	case USB_ST_SETUP:
778192925Sthompsatr_setup:
779184610Salfred		if (sc->sc_inputs < UKBD_IN_BUF_FULL) {
780194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
781194228Sthompsa			usbd_transfer_submit(xfer);
782184610Salfred		} else {
783184610Salfred			DPRINTF("input queue is full!\n");
784184610Salfred		}
785192925Sthompsa		break;
786184610Salfred
787184610Salfred	default:			/* Error */
788194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
789184610Salfred
790194677Sthompsa		if (error != USB_ERR_CANCELLED) {
791184610Salfred			/* try to clear stall first */
792194677Sthompsa			usbd_xfer_set_stall(xfer);
793192925Sthompsa			goto tr_setup;
794184610Salfred		}
795192925Sthompsa		break;
796184610Salfred	}
797184610Salfred}
798184610Salfred
799184610Salfredstatic void
800194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error)
801184610Salfred{
802223755Shselasky	struct ukbd_softc *sc = usbd_xfer_softc(xfer);
803192984Sthompsa	struct usb_device_request req;
804194677Sthompsa	struct usb_page_cache *pc;
805223755Shselasky	uint8_t id;
806223755Shselasky	uint8_t any;
807223755Shselasky	int len;
808184610Salfred
809228765Savg	UKBD_LOCK_ASSERT();
810228765Savg
811207077Sthompsa#ifdef USB_DEBUG
812196489Salfred	if (ukbd_no_leds)
813196489Salfred		return;
814196489Salfred#endif
815196489Salfred
816184610Salfred	switch (USB_GET_STATE(xfer)) {
817184610Salfred	case USB_ST_TRANSFERRED:
818184610Salfred	case USB_ST_SETUP:
819223755Shselasky		if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS))
820223755Shselasky			break;
821223755Shselasky		sc->sc_flags &= ~UKBD_FLAG_SET_LEDS;
822184610Salfred
823223755Shselasky		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
824223755Shselasky		req.bRequest = UR_SET_REPORT;
825223755Shselasky		USETW2(req.wValue, UHID_OUTPUT_REPORT, 0);
826223755Shselasky		req.wIndex[0] = sc->sc_iface_no;
827223755Shselasky		req.wIndex[1] = 0;
828223755Shselasky		req.wLength[1] = 0;
829184610Salfred
830223755Shselasky		memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE);
831223755Shselasky
832223755Shselasky		id = 0;
833223755Shselasky		any = 0;
834223755Shselasky
835223755Shselasky		/* Assumption: All led bits must be in the same ID. */
836223755Shselasky
837223755Shselasky		if (sc->sc_flags & UKBD_FLAG_NUMLOCK) {
838223755Shselasky			if (sc->sc_leds & NLKED) {
839223755Shselasky				hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
840223755Shselasky				    &sc->sc_loc_numlock, 1);
841192925Sthompsa			}
842223755Shselasky			id = sc->sc_id_numlock;
843223755Shselasky			any = 1;
844223755Shselasky		}
845184610Salfred
846223755Shselasky		if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) {
847223755Shselasky			if (sc->sc_leds & SLKED) {
848223755Shselasky				hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
849223755Shselasky				    &sc->sc_loc_scrolllock, 1);
850223755Shselasky			}
851223755Shselasky			id = sc->sc_id_scrolllock;
852223755Shselasky			any = 1;
853223755Shselasky		}
854184610Salfred
855223755Shselasky		if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) {
856223755Shselasky			if (sc->sc_leds & CLKED) {
857223755Shselasky				hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
858223755Shselasky				    &sc->sc_loc_capslock, 1);
859223755Shselasky			}
860223755Shselasky			id = sc->sc_id_capslock;
861223755Shselasky			any = 1;
862184610Salfred		}
863223755Shselasky
864223755Shselasky		/* if no leds, nothing to do */
865223755Shselasky		if (!any)
866223755Shselasky			break;
867223755Shselasky
868307775Sgonzo#ifdef EVDEV_SUPPORT
869307764Sgonzo		if (sc->sc_evdev != NULL)
870307764Sgonzo			evdev_push_leds(sc->sc_evdev, sc->sc_leds);
871307764Sgonzo#endif
872307764Sgonzo
873223755Shselasky		/* range check output report length */
874223755Shselasky		len = sc->sc_led_size;
875223755Shselasky		if (len > (UKBD_BUFFER_SIZE - 1))
876223755Shselasky			len = (UKBD_BUFFER_SIZE - 1);
877223755Shselasky
878223755Shselasky		/* check if we need to prefix an ID byte */
879223755Shselasky		sc->sc_buffer[0] = id;
880223755Shselasky
881223755Shselasky		pc = usbd_xfer_get_frame(xfer, 1);
882223755Shselasky		if (id != 0) {
883223755Shselasky			len++;
884223755Shselasky			usbd_copy_in(pc, 0, sc->sc_buffer, len);
885223755Shselasky		} else {
886223755Shselasky			usbd_copy_in(pc, 0, sc->sc_buffer + 1, len);
887223755Shselasky		}
888223755Shselasky		req.wLength[0] = len;
889223755Shselasky		usbd_xfer_set_frame_len(xfer, 1, len);
890223755Shselasky
891223755Shselasky		DPRINTF("len=%d, id=%d\n", len, id);
892223755Shselasky
893223755Shselasky		/* setup control request last */
894223755Shselasky		pc = usbd_xfer_get_frame(xfer, 0);
895223755Shselasky		usbd_copy_in(pc, 0, &req, sizeof(req));
896223755Shselasky		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
897223755Shselasky
898223755Shselasky		/* start data transfer */
899223755Shselasky		usbd_xfer_set_frames(xfer, 2);
900223755Shselasky		usbd_transfer_submit(xfer);
901196489Salfred		break;
902184610Salfred
903184610Salfred	default:			/* Error */
904212128Sthompsa		DPRINTFN(1, "error=%s\n", usbd_errstr(error));
905196489Salfred		break;
906184610Salfred	}
907184610Salfred}
908184610Salfred
909192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = {
910184610Salfred
911305644Shselasky	[UKBD_INTR_DT_0] = {
912184610Salfred		.type = UE_INTERRUPT,
913184610Salfred		.endpoint = UE_ADDR_ANY,
914184610Salfred		.direction = UE_DIR_IN,
915190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
916190734Sthompsa		.bufsize = 0,	/* use wMaxPacketSize */
917190734Sthompsa		.callback = &ukbd_intr_callback,
918184610Salfred	},
919184610Salfred
920305644Shselasky	[UKBD_INTR_DT_1] = {
921305644Shselasky		.type = UE_INTERRUPT,
922305644Shselasky		.endpoint = UE_ADDR_ANY,
923305644Shselasky		.direction = UE_DIR_IN,
924305644Shselasky		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
925305644Shselasky		.bufsize = 0,	/* use wMaxPacketSize */
926305644Shselasky		.callback = &ukbd_intr_callback,
927305644Shselasky	},
928305644Shselasky
929187259Sthompsa	[UKBD_CTRL_LED] = {
930184610Salfred		.type = UE_CONTROL,
931184610Salfred		.endpoint = 0x00,	/* Control pipe */
932184610Salfred		.direction = UE_DIR_ANY,
933223755Shselasky		.bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE,
934190734Sthompsa		.callback = &ukbd_set_leds_callback,
935190734Sthompsa		.timeout = 1000,	/* 1 second */
936184610Salfred	},
937184610Salfred};
938184610Salfred
939223521Shselasky/* A match on these entries will load ukbd */
940223521Shselaskystatic const STRUCT_USB_HOST_ID __used ukbd_devs[] = {
941223521Shselasky	{USB_IFACE_CLASS(UICLASS_HID),
942223521Shselasky	 USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
943223521Shselasky	 USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),},
944223521Shselasky};
945223521Shselasky
946184610Salfredstatic int
947184610Salfredukbd_probe(device_t dev)
948184610Salfred{
949184610Salfred	keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME);
950192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
951194067Sthompsa	void *d_ptr;
952194067Sthompsa	int error;
953194067Sthompsa	uint16_t d_len;
954184610Salfred
955228765Savg	UKBD_LOCK_ASSERT();
956184610Salfred	DPRINTFN(11, "\n");
957184610Salfred
958184610Salfred	if (sw == NULL) {
959184610Salfred		return (ENXIO);
960184610Salfred	}
961192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST) {
962184610Salfred		return (ENXIO);
963184610Salfred	}
964194067Sthompsa
965194067Sthompsa	if (uaa->info.bInterfaceClass != UICLASS_HID)
966194067Sthompsa		return (ENXIO);
967194067Sthompsa
968245248Shselasky	if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
969245248Shselasky		return (ENXIO);
970245248Shselasky
971194067Sthompsa	if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
972245248Shselasky	    (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD))
973245248Shselasky		return (BUS_PROBE_DEFAULT);
974194067Sthompsa
975194228Sthompsa	error = usbd_req_get_hid_desc(uaa->device, NULL,
976194067Sthompsa	    &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
977194067Sthompsa
978194067Sthompsa	if (error)
979194067Sthompsa		return (ENXIO);
980194067Sthompsa
981245248Shselasky	if (hid_is_keyboard(d_ptr, d_len)) {
982245248Shselasky		if (hid_is_mouse(d_ptr, d_len)) {
983245248Shselasky			/*
984245248Shselasky			 * NOTE: We currently don't support USB mouse
985245248Shselasky			 * and USB keyboard on the same USB endpoint.
986245248Shselasky			 * Let "ums" driver win.
987245248Shselasky			 */
988194067Sthompsa			error = ENXIO;
989245248Shselasky		} else {
990222051Savg			error = BUS_PROBE_DEFAULT;
991245248Shselasky		}
992245248Shselasky	} else {
993194067Sthompsa		error = ENXIO;
994245248Shselasky	}
995194067Sthompsa	free(d_ptr, M_TEMP);
996194067Sthompsa	return (error);
997184610Salfred}
998184610Salfred
999223755Shselaskystatic void
1000223755Shselaskyukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len)
1001223755Shselasky{
1002223755Shselasky	uint32_t flags;
1003358216Shselasky	uint32_t key;
1004223755Shselasky
1005223755Shselasky	/* reset detected bits */
1006223755Shselasky	sc->sc_flags &= ~UKBD_FLAG_HID_MASK;
1007223755Shselasky
1008358216Shselasky	/* reset detected keys */
1009358216Shselasky	memset(sc->sc_loc_key_valid, 0, sizeof(sc->sc_loc_key_valid));
1010358216Shselasky
1011223755Shselasky	/* check if there is an ID byte */
1012223755Shselasky	sc->sc_kbd_size = hid_report_size(ptr, len,
1013223755Shselasky	    hid_input, &sc->sc_kbd_id);
1014223755Shselasky
1015223755Shselasky	/* investigate if this is an Apple Keyboard */
1016223755Shselasky	if (hid_locate(ptr, len,
1017223755Shselasky	    HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT),
1018223755Shselasky	    hid_input, 0, &sc->sc_loc_apple_eject, &flags,
1019223755Shselasky	    &sc->sc_id_apple_eject)) {
1020223755Shselasky		if (flags & HIO_VARIABLE)
1021223755Shselasky			sc->sc_flags |= UKBD_FLAG_APPLE_EJECT |
1022223755Shselasky			    UKBD_FLAG_APPLE_SWAP;
1023223755Shselasky		DPRINTFN(1, "Found Apple eject-key\n");
1024223755Shselasky	}
1025223755Shselasky	if (hid_locate(ptr, len,
1026223755Shselasky	    HID_USAGE2(0xFFFF, 0x0003),
1027223755Shselasky	    hid_input, 0, &sc->sc_loc_apple_fn, &flags,
1028223755Shselasky	    &sc->sc_id_apple_fn)) {
1029223755Shselasky		if (flags & HIO_VARIABLE)
1030223755Shselasky			sc->sc_flags |= UKBD_FLAG_APPLE_FN;
1031223755Shselasky		DPRINTFN(1, "Found Apple FN-key\n");
1032223755Shselasky	}
1033358216Shselasky
1034223755Shselasky	/* figure out event buffer */
1035223755Shselasky	if (hid_locate(ptr, len,
1036223755Shselasky	    HID_USAGE2(HUP_KEYBOARD, 0x00),
1037358216Shselasky	    hid_input, 0, &sc->sc_loc_key[0], &flags,
1038358216Shselasky	    &sc->sc_id_loc_key[0])) {
1039254572Shselasky		if (flags & HIO_VARIABLE) {
1040254572Shselasky			DPRINTFN(1, "Ignoring keyboard event control\n");
1041254572Shselasky		} else {
1042358216Shselasky			sc->sc_loc_key_valid[0] |= 1;
1043254572Shselasky			DPRINTFN(1, "Found keyboard event array\n");
1044254572Shselasky		}
1045223755Shselasky	}
1046223755Shselasky
1047358216Shselasky	/* figure out the keys */
1048358216Shselasky	for (key = 1; key != UKBD_NKEYCODE; key++) {
1049358216Shselasky		if (hid_locate(ptr, len,
1050358216Shselasky		    HID_USAGE2(HUP_KEYBOARD, key),
1051358216Shselasky		    hid_input, 0, &sc->sc_loc_key[key], &flags,
1052358216Shselasky		    &sc->sc_id_loc_key[key])) {
1053358216Shselasky			if (flags & HIO_VARIABLE) {
1054358216Shselasky				sc->sc_loc_key_valid[key / 64] |=
1055358216Shselasky				    1ULL << (key % 64);
1056358216Shselasky				DPRINTFN(1, "Found key 0x%02x\n", key);
1057358216Shselasky			}
1058358216Shselasky		}
1059358216Shselasky	}
1060358216Shselasky
1061223755Shselasky	/* figure out leds on keyboard */
1062223755Shselasky	sc->sc_led_size = hid_report_size(ptr, len,
1063223755Shselasky	    hid_output, NULL);
1064223755Shselasky
1065223755Shselasky	if (hid_locate(ptr, len,
1066223755Shselasky	    HID_USAGE2(HUP_LEDS, 0x01),
1067223755Shselasky	    hid_output, 0, &sc->sc_loc_numlock, &flags,
1068223755Shselasky	    &sc->sc_id_numlock)) {
1069223755Shselasky		if (flags & HIO_VARIABLE)
1070223755Shselasky			sc->sc_flags |= UKBD_FLAG_NUMLOCK;
1071223755Shselasky		DPRINTFN(1, "Found keyboard numlock\n");
1072223755Shselasky	}
1073223755Shselasky	if (hid_locate(ptr, len,
1074223755Shselasky	    HID_USAGE2(HUP_LEDS, 0x02),
1075223755Shselasky	    hid_output, 0, &sc->sc_loc_capslock, &flags,
1076223755Shselasky	    &sc->sc_id_capslock)) {
1077223755Shselasky		if (flags & HIO_VARIABLE)
1078223755Shselasky			sc->sc_flags |= UKBD_FLAG_CAPSLOCK;
1079223755Shselasky		DPRINTFN(1, "Found keyboard capslock\n");
1080223755Shselasky	}
1081223755Shselasky	if (hid_locate(ptr, len,
1082223755Shselasky	    HID_USAGE2(HUP_LEDS, 0x03),
1083223755Shselasky	    hid_output, 0, &sc->sc_loc_scrolllock, &flags,
1084223755Shselasky	    &sc->sc_id_scrolllock)) {
1085223755Shselasky		if (flags & HIO_VARIABLE)
1086223755Shselasky			sc->sc_flags |= UKBD_FLAG_SCROLLLOCK;
1087223755Shselasky		DPRINTFN(1, "Found keyboard scrolllock\n");
1088223755Shselasky	}
1089223755Shselasky}
1090223755Shselasky
1091184610Salfredstatic int
1092184610Salfredukbd_attach(device_t dev)
1093184610Salfred{
1094184610Salfred	struct ukbd_softc *sc = device_get_softc(dev);
1095192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
1096253332Shselasky	int unit = device_get_unit(dev);
1097184610Salfred	keyboard_t *kbd = &sc->sc_kbd;
1098192925Sthompsa	void *hid_ptr = NULL;
1099193045Sthompsa	usb_error_t err;
1100184610Salfred	uint16_t n;
1101192925Sthompsa	uint16_t hid_len;
1102307775Sgonzo#ifdef EVDEV_SUPPORT
1103307764Sgonzo	struct evdev_dev *evdev;
1104307764Sgonzo	int i;
1105307764Sgonzo#endif
1106253332Shselasky#ifdef USB_DEBUG
1107253332Shselasky	int rate;
1108253332Shselasky#endif
1109228765Savg	UKBD_LOCK_ASSERT();
1110228765Savg
1111184610Salfred	kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0);
1112184610Salfred
1113184610Salfred	kbd->kb_data = (void *)sc;
1114184610Salfred
1115194228Sthompsa	device_set_usb_desc(dev);
1116184610Salfred
1117184610Salfred	sc->sc_udev = uaa->device;
1118184610Salfred	sc->sc_iface = uaa->iface;
1119184610Salfred	sc->sc_iface_index = uaa->info.bIfaceIndex;
1120184610Salfred	sc->sc_iface_no = uaa->info.bIfaceNum;
1121184610Salfred	sc->sc_mode = K_XLATE;
1122184610Salfred
1123194228Sthompsa	usb_callout_init_mtx(&sc->sc_callout, &Giant, 0);
1124184610Salfred
1125305644Shselasky#ifdef UKBD_NO_POLLING
1126194228Sthompsa	err = usbd_transfer_setup(uaa->device,
1127184610Salfred	    &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config,
1128184610Salfred	    UKBD_N_TRANSFER, sc, &Giant);
1129305644Shselasky#else
1130305644Shselasky	/*
1131305644Shselasky	 * Setup the UKBD USB transfers one by one, so they are memory
1132305644Shselasky	 * independent which allows for handling panics triggered by
1133305644Shselasky	 * the keyboard driver itself, typically via CTRL+ALT+ESC
1134305644Shselasky	 * sequences. Or if the USB keyboard driver was processing a
1135305644Shselasky	 * key at the moment of panic.
1136305644Shselasky	 */
1137305644Shselasky	for (n = 0; n != UKBD_N_TRANSFER; n++) {
1138305644Shselasky		err = usbd_transfer_setup(uaa->device,
1139305644Shselasky		    &uaa->info.bIfaceIndex, sc->sc_xfer + n, ukbd_config + n,
1140305644Shselasky		    1, sc, &Giant);
1141305644Shselasky		if (err)
1142305644Shselasky			break;
1143305644Shselasky	}
1144305644Shselasky#endif
1145184610Salfred
1146184610Salfred	if (err) {
1147194228Sthompsa		DPRINTF("error=%s\n", usbd_errstr(err));
1148184610Salfred		goto detach;
1149184610Salfred	}
1150184610Salfred	/* setup default keyboard maps */
1151184610Salfred
1152184610Salfred	sc->sc_keymap = key_map;
1153184610Salfred	sc->sc_accmap = accent_map;
1154184610Salfred	for (n = 0; n < UKBD_NFKEY; n++) {
1155184610Salfred		sc->sc_fkeymap[n] = fkey_tab[n];
1156184610Salfred	}
1157184610Salfred
1158184610Salfred	kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap,
1159184610Salfred	    sc->sc_fkeymap, UKBD_NFKEY);
1160184610Salfred
1161184610Salfred	KBD_FOUND_DEVICE(kbd);
1162184610Salfred
1163184610Salfred	ukbd_clear_state(kbd);
1164184610Salfred
1165184610Salfred	/*
1166184610Salfred	 * FIXME: set the initial value for lock keys in "sc_state"
1167184610Salfred	 * according to the BIOS data?
1168184610Salfred	 */
1169184610Salfred	KBD_PROBE_DONE(kbd);
1170184610Salfred
1171223755Shselasky	/* get HID descriptor */
1172194228Sthompsa	err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr,
1173192925Sthompsa	    &hid_len, M_TEMP, uaa->info.bIfaceIndex);
1174223755Shselasky
1175192925Sthompsa	if (err == 0) {
1176223755Shselasky		DPRINTF("Parsing HID descriptor of %d bytes\n",
1177223755Shselasky		    (int)hid_len);
1178192925Sthompsa
1179223755Shselasky		ukbd_parse_hid(sc, hid_ptr, hid_len);
1180192925Sthompsa
1181192925Sthompsa		free(hid_ptr, M_TEMP);
1182192925Sthompsa	}
1183192925Sthompsa
1184223755Shselasky	/* check if we should use the boot protocol */
1185223755Shselasky	if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) ||
1186358216Shselasky	    (err != 0) || ukbd_any_key_valid(sc) == false) {
1187223755Shselasky
1188223755Shselasky		DPRINTF("Forcing boot protocol\n");
1189223755Shselasky
1190223755Shselasky		err = usbd_req_set_protocol(sc->sc_udev, NULL,
1191223755Shselasky			sc->sc_iface_index, 0);
1192223755Shselasky
1193223755Shselasky		if (err != 0) {
1194223755Shselasky			DPRINTF("Set protocol error=%s (ignored)\n",
1195223755Shselasky			    usbd_errstr(err));
1196223755Shselasky		}
1197223755Shselasky
1198223755Shselasky		ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc));
1199223755Shselasky	}
1200223755Shselasky
1201184610Salfred	/* ignore if SETIDLE fails, hence it is not crucial */
1202223755Shselasky	usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0);
1203184610Salfred
1204184610Salfred	ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state);
1205184610Salfred
1206184610Salfred	KBD_INIT_DONE(kbd);
1207184610Salfred
1208184610Salfred	if (kbd_register(kbd) < 0) {
1209184610Salfred		goto detach;
1210184610Salfred	}
1211184610Salfred	KBD_CONFIG_DONE(kbd);
1212184610Salfred
1213184610Salfred	ukbd_enable(kbd);
1214184610Salfred
1215184610Salfred#ifdef KBD_INSTALL_CDEV
1216184610Salfred	if (kbd_attach(kbd)) {
1217184610Salfred		goto detach;
1218184610Salfred	}
1219184610Salfred#endif
1220307764Sgonzo
1221307775Sgonzo#ifdef EVDEV_SUPPORT
1222307764Sgonzo	evdev = evdev_alloc();
1223307764Sgonzo	evdev_set_name(evdev, device_get_desc(dev));
1224307764Sgonzo	evdev_set_phys(evdev, device_get_nameunit(dev));
1225307764Sgonzo	evdev_set_id(evdev, BUS_USB, uaa->info.idVendor,
1226307764Sgonzo	   uaa->info.idProduct, 0);
1227307764Sgonzo	evdev_set_serial(evdev, usb_get_serial(uaa->device));
1228307764Sgonzo	evdev_set_methods(evdev, kbd, &ukbd_evdev_methods);
1229307764Sgonzo	evdev_support_event(evdev, EV_SYN);
1230307764Sgonzo	evdev_support_event(evdev, EV_KEY);
1231307764Sgonzo	if (sc->sc_flags & (UKBD_FLAG_NUMLOCK | UKBD_FLAG_CAPSLOCK |
1232307764Sgonzo			    UKBD_FLAG_SCROLLLOCK))
1233307764Sgonzo		evdev_support_event(evdev, EV_LED);
1234307764Sgonzo	evdev_support_event(evdev, EV_REP);
1235307764Sgonzo
1236307764Sgonzo	for (i = 0x00; i <= 0xFF; i++)
1237307764Sgonzo		evdev_support_key(evdev, evdev_hid2key(i));
1238307764Sgonzo	if (sc->sc_flags & UKBD_FLAG_NUMLOCK)
1239307764Sgonzo		evdev_support_led(evdev, LED_NUML);
1240307764Sgonzo	if (sc->sc_flags & UKBD_FLAG_CAPSLOCK)
1241307764Sgonzo		evdev_support_led(evdev, LED_CAPSL);
1242307764Sgonzo	if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK)
1243307764Sgonzo		evdev_support_led(evdev, LED_SCROLLL);
1244307764Sgonzo
1245307764Sgonzo	if (evdev_register(evdev))
1246307764Sgonzo		evdev_free(evdev);
1247307764Sgonzo	else
1248307764Sgonzo		sc->sc_evdev = evdev;
1249307764Sgonzo#endif
1250307764Sgonzo
1251184610Salfred	sc->sc_flags |= UKBD_FLAG_ATTACHED;
1252184610Salfred
1253184610Salfred	if (bootverbose) {
1254356012Skevans		kbdd_diag(kbd, bootverbose);
1255184610Salfred	}
1256184610Salfred
1257253332Shselasky#ifdef USB_DEBUG
1258253332Shselasky	/* check for polling rate override */
1259253332Shselasky	rate = ukbd_pollrate;
1260253332Shselasky	if (rate > 0) {
1261253332Shselasky		if (rate > 1000)
1262253332Shselasky			rate = 1;
1263253332Shselasky		else
1264253332Shselasky			rate = 1000 / rate;
1265253332Shselasky
1266253332Shselasky		/* set new polling interval in ms */
1267305644Shselasky		usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_0], rate);
1268305644Shselasky		usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_1], rate);
1269253332Shselasky	}
1270253332Shselasky#endif
1271184610Salfred	/* start the keyboard */
1272305644Shselasky	usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]);
1273305644Shselasky	usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]);
1274184610Salfred
1275184610Salfred	return (0);			/* success */
1276184610Salfred
1277184610Salfreddetach:
1278184610Salfred	ukbd_detach(dev);
1279184610Salfred	return (ENXIO);			/* error */
1280184610Salfred}
1281184610Salfred
1282193315Sthompsastatic int
1283184610Salfredukbd_detach(device_t dev)
1284184610Salfred{
1285184610Salfred	struct ukbd_softc *sc = device_get_softc(dev);
1286184610Salfred	int error;
1287184610Salfred
1288228765Savg	UKBD_LOCK_ASSERT();
1289228765Savg
1290184610Salfred	DPRINTF("\n");
1291184610Salfred
1292184610Salfred	sc->sc_flags |= UKBD_FLAG_GONE;
1293184610Salfred
1294194228Sthompsa	usb_callout_stop(&sc->sc_callout);
1295184610Salfred
1296261228Shselasky	/* kill any stuck keys */
1297261228Shselasky	if (sc->sc_flags & UKBD_FLAG_ATTACHED) {
1298261228Shselasky		/* stop receiving events from the USB keyboard */
1299305644Shselasky		usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_0]);
1300305644Shselasky		usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_1]);
1301261228Shselasky
1302261228Shselasky		/* release all leftover keys, if any */
1303261228Shselasky		memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
1304261228Shselasky
1305261228Shselasky		/* process releasing of all keys */
1306261228Shselasky		ukbd_interrupt(sc);
1307261228Shselasky	}
1308261228Shselasky
1309184610Salfred	ukbd_disable(&sc->sc_kbd);
1310184610Salfred
1311184610Salfred#ifdef KBD_INSTALL_CDEV
1312184610Salfred	if (sc->sc_flags & UKBD_FLAG_ATTACHED) {
1313184610Salfred		error = kbd_detach(&sc->sc_kbd);
1314184610Salfred		if (error) {
1315184610Salfred			/* usb attach cannot return an error */
1316184610Salfred			device_printf(dev, "WARNING: kbd_detach() "
1317184610Salfred			    "returned non-zero! (ignored)\n");
1318184610Salfred		}
1319184610Salfred	}
1320184610Salfred#endif
1321307764Sgonzo
1322307775Sgonzo#ifdef EVDEV_SUPPORT
1323307764Sgonzo	evdev_free(sc->sc_evdev);
1324307764Sgonzo#endif
1325307764Sgonzo
1326184610Salfred	if (KBD_IS_CONFIGURED(&sc->sc_kbd)) {
1327184610Salfred		error = kbd_unregister(&sc->sc_kbd);
1328184610Salfred		if (error) {
1329184610Salfred			/* usb attach cannot return an error */
1330184610Salfred			device_printf(dev, "WARNING: kbd_unregister() "
1331184610Salfred			    "returned non-zero! (ignored)\n");
1332184610Salfred		}
1333184610Salfred	}
1334184610Salfred	sc->sc_kbd.kb_flags = 0;
1335184610Salfred
1336194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER);
1337184610Salfred
1338194228Sthompsa	usb_callout_drain(&sc->sc_callout);
1339184610Salfred
1340184610Salfred	DPRINTF("%s: disconnected\n",
1341184610Salfred	    device_get_nameunit(dev));
1342184610Salfred
1343184610Salfred	return (0);
1344184610Salfred}
1345184610Salfred
1346184610Salfredstatic int
1347184610Salfredukbd_resume(device_t dev)
1348184610Salfred{
1349184610Salfred	struct ukbd_softc *sc = device_get_softc(dev);
1350184610Salfred
1351228765Savg	UKBD_LOCK_ASSERT();
1352203896Sthompsa
1353184610Salfred	ukbd_clear_state(&sc->sc_kbd);
1354184610Salfred
1355184610Salfred	return (0);
1356184610Salfred}
1357184610Salfred
1358184610Salfred/* early keyboard probe, not supported */
1359184610Salfredstatic int
1360184610Salfredukbd_configure(int flags)
1361184610Salfred{
1362184610Salfred	return (0);
1363184610Salfred}
1364184610Salfred
1365184610Salfred/* detect a keyboard, not used */
1366184610Salfredstatic int
1367184610Salfredukbd__probe(int unit, void *arg, int flags)
1368184610Salfred{
1369184610Salfred	return (ENXIO);
1370184610Salfred}
1371184610Salfred
1372184610Salfred/* reset and initialize the device, not used */
1373184610Salfredstatic int
1374184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
1375184610Salfred{
1376184610Salfred	return (ENXIO);
1377184610Salfred}
1378184610Salfred
1379184610Salfred/* test the interface to the device, not used */
1380184610Salfredstatic int
1381184610Salfredukbd_test_if(keyboard_t *kbd)
1382184610Salfred{
1383184610Salfred	return (0);
1384184610Salfred}
1385184610Salfred
1386184610Salfred/* finish using this keyboard, not used */
1387184610Salfredstatic int
1388184610Salfredukbd_term(keyboard_t *kbd)
1389184610Salfred{
1390184610Salfred	return (ENXIO);
1391184610Salfred}
1392184610Salfred
1393184610Salfred/* keyboard interrupt routine, not used */
1394184610Salfredstatic int
1395184610Salfredukbd_intr(keyboard_t *kbd, void *arg)
1396184610Salfred{
1397184610Salfred	return (0);
1398184610Salfred}
1399184610Salfred
1400184610Salfred/* lock the access to the keyboard, not used */
1401184610Salfredstatic int
1402184610Salfredukbd_lock(keyboard_t *kbd, int lock)
1403184610Salfred{
1404184610Salfred	return (1);
1405184610Salfred}
1406184610Salfred
1407184610Salfred/*
1408184610Salfred * Enable the access to the device; until this function is called,
1409184610Salfred * the client cannot read from the keyboard.
1410184610Salfred */
1411184610Salfredstatic int
1412184610Salfredukbd_enable(keyboard_t *kbd)
1413184610Salfred{
1414228765Savg
1415228765Savg	UKBD_LOCK();
1416184610Salfred	KBD_ACTIVATE(kbd);
1417228765Savg	UKBD_UNLOCK();
1418228765Savg
1419184610Salfred	return (0);
1420184610Salfred}
1421184610Salfred
1422184610Salfred/* disallow the access to the device */
1423184610Salfredstatic int
1424184610Salfredukbd_disable(keyboard_t *kbd)
1425184610Salfred{
1426228765Savg
1427228765Savg	UKBD_LOCK();
1428184610Salfred	KBD_DEACTIVATE(kbd);
1429228765Savg	UKBD_UNLOCK();
1430228765Savg
1431184610Salfred	return (0);
1432184610Salfred}
1433184610Salfred
1434184610Salfred/* check if data is waiting */
1435228765Savg/* Currently unused. */
1436184610Salfredstatic int
1437184610Salfredukbd_check(keyboard_t *kbd)
1438184610Salfred{
1439184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1440184610Salfred
1441228765Savg	UKBD_CTX_LOCK_ASSERT();
1442228765Savg
1443195960Salfred	if (!KBD_IS_ACTIVE(kbd))
1444195960Salfred		return (0);
1445195960Salfred
1446203896Sthompsa	if (sc->sc_flags & UKBD_FLAG_POLLING)
1447203896Sthompsa		ukbd_do_poll(sc, 0);
1448203896Sthompsa
1449184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1450184610Salfred	if (sc->sc_buffered_char[0]) {
1451184610Salfred		return (1);
1452184610Salfred	}
1453184610Salfred#endif
1454184610Salfred	if (sc->sc_inputs > 0) {
1455184610Salfred		return (1);
1456184610Salfred	}
1457184610Salfred	return (0);
1458184610Salfred}
1459184610Salfred
1460184610Salfred/* check if char is waiting */
1461184610Salfredstatic int
1462228765Savgukbd_check_char_locked(keyboard_t *kbd)
1463184610Salfred{
1464184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1465184610Salfred
1466228765Savg	UKBD_CTX_LOCK_ASSERT();
1467228765Savg
1468195960Salfred	if (!KBD_IS_ACTIVE(kbd))
1469195960Salfred		return (0);
1470195960Salfred
1471184610Salfred	if ((sc->sc_composed_char > 0) &&
1472184610Salfred	    (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) {
1473184610Salfred		return (1);
1474184610Salfred	}
1475184610Salfred	return (ukbd_check(kbd));
1476184610Salfred}
1477184610Salfred
1478228765Savgstatic int
1479228765Savgukbd_check_char(keyboard_t *kbd)
1480228765Savg{
1481228765Savg	int result;
1482184610Salfred
1483228765Savg	UKBD_LOCK();
1484228765Savg	result = ukbd_check_char_locked(kbd);
1485228765Savg	UKBD_UNLOCK();
1486228765Savg
1487228765Savg	return (result);
1488228765Savg}
1489228765Savg
1490184610Salfred/* read one byte from the keyboard if it's allowed */
1491228765Savg/* Currently unused. */
1492184610Salfredstatic int
1493184610Salfredukbd_read(keyboard_t *kbd, int wait)
1494184610Salfred{
1495184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1496184610Salfred	int32_t usbcode;
1497184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1498184610Salfred	uint32_t keycode;
1499184610Salfred	uint32_t scancode;
1500184610Salfred
1501184610Salfred#endif
1502184610Salfred
1503228765Savg	UKBD_CTX_LOCK_ASSERT();
1504184610Salfred
1505228765Savg	if (!KBD_IS_ACTIVE(kbd))
1506203896Sthompsa		return (-1);
1507203896Sthompsa
1508184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1509184610Salfred	if (sc->sc_buffered_char[0]) {
1510184610Salfred		scancode = sc->sc_buffered_char[0];
1511184610Salfred		if (scancode & SCAN_PREFIX) {
1512184610Salfred			sc->sc_buffered_char[0] &= ~SCAN_PREFIX;
1513184610Salfred			return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
1514184610Salfred		}
1515184610Salfred		sc->sc_buffered_char[0] = sc->sc_buffered_char[1];
1516184610Salfred		sc->sc_buffered_char[1] = 0;
1517184610Salfred		return (scancode);
1518184610Salfred	}
1519184610Salfred#endif					/* UKBD_EMULATE_ATSCANCODE */
1520184610Salfred
1521184610Salfred	/* XXX */
1522184610Salfred	usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1);
1523195960Salfred	if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1))
1524195960Salfred		return (-1);
1525195960Salfred
1526184610Salfred	++(kbd->kb_count);
1527184610Salfred
1528184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1529358216Shselasky	keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.bitmap);
1530184610Salfred	if (keycode == NN) {
1531184610Salfred		return -1;
1532184610Salfred	}
1533358216Shselasky	return (ukbd_key2scan(sc, keycode, sc->sc_ndata.bitmap,
1534184610Salfred	    (usbcode & KEY_RELEASE)));
1535184610Salfred#else					/* !UKBD_EMULATE_ATSCANCODE */
1536184610Salfred	return (usbcode);
1537184610Salfred#endif					/* UKBD_EMULATE_ATSCANCODE */
1538184610Salfred}
1539184610Salfred
1540184610Salfred/* read char from the keyboard */
1541184610Salfredstatic uint32_t
1542228765Savgukbd_read_char_locked(keyboard_t *kbd, int wait)
1543184610Salfred{
1544184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1545184610Salfred	uint32_t action;
1546184610Salfred	uint32_t keycode;
1547184610Salfred	int32_t usbcode;
1548184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1549184610Salfred	uint32_t scancode;
1550184610Salfred#endif
1551195960Salfred
1552228765Savg	UKBD_CTX_LOCK_ASSERT();
1553228765Savg
1554195960Salfred	if (!KBD_IS_ACTIVE(kbd))
1555195960Salfred		return (NOKEY);
1556195960Salfred
1557184610Salfrednext_code:
1558184610Salfred
1559184610Salfred	/* do we have a composed char to return ? */
1560184610Salfred
1561184610Salfred	if ((sc->sc_composed_char > 0) &&
1562184610Salfred	    (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) {
1563184610Salfred
1564184610Salfred		action = sc->sc_composed_char;
1565184610Salfred		sc->sc_composed_char = 0;
1566184610Salfred
1567184610Salfred		if (action > 0xFF) {
1568184610Salfred			goto errkey;
1569184610Salfred		}
1570184610Salfred		goto done;
1571184610Salfred	}
1572184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1573184610Salfred
1574184610Salfred	/* do we have a pending raw scan code? */
1575184610Salfred
1576184610Salfred	if (sc->sc_mode == K_RAW) {
1577184610Salfred		scancode = sc->sc_buffered_char[0];
1578184610Salfred		if (scancode) {
1579184610Salfred			if (scancode & SCAN_PREFIX) {
1580184610Salfred				sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX);
1581184610Salfred				return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
1582184610Salfred			}
1583184610Salfred			sc->sc_buffered_char[0] = sc->sc_buffered_char[1];
1584184610Salfred			sc->sc_buffered_char[1] = 0;
1585184610Salfred			return (scancode);
1586184610Salfred		}
1587184610Salfred	}
1588184610Salfred#endif					/* UKBD_EMULATE_ATSCANCODE */
1589184610Salfred
1590184610Salfred	/* see if there is something in the keyboard port */
1591184610Salfred	/* XXX */
1592184610Salfred	usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1);
1593184610Salfred	if (usbcode == -1) {
1594184610Salfred		return (NOKEY);
1595184610Salfred	}
1596184610Salfred	++kbd->kb_count;
1597184610Salfred
1598184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1599184610Salfred	/* USB key index -> key code -> AT scan code */
1600358216Shselasky	keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.bitmap);
1601184610Salfred	if (keycode == NN) {
1602184610Salfred		return (NOKEY);
1603184610Salfred	}
1604184610Salfred	/* return an AT scan code for the K_RAW mode */
1605184610Salfred	if (sc->sc_mode == K_RAW) {
1606358216Shselasky		return (ukbd_key2scan(sc, keycode, sc->sc_ndata.bitmap,
1607184610Salfred		    (usbcode & KEY_RELEASE)));
1608184610Salfred	}
1609184610Salfred#else					/* !UKBD_EMULATE_ATSCANCODE */
1610184610Salfred
1611184610Salfred	/* return the byte as is for the K_RAW mode */
1612184610Salfred	if (sc->sc_mode == K_RAW) {
1613184610Salfred		return (usbcode);
1614184610Salfred	}
1615184610Salfred	/* USB key index -> key code */
1616184610Salfred	keycode = ukbd_trtab[KEY_INDEX(usbcode)];
1617184610Salfred	if (keycode == NN) {
1618184610Salfred		return (NOKEY);
1619184610Salfred	}
1620184610Salfred#endif					/* UKBD_EMULATE_ATSCANCODE */
1621184610Salfred
1622184610Salfred	switch (keycode) {
1623184610Salfred	case 0x38:			/* left alt (compose key) */
1624184610Salfred		if (usbcode & KEY_RELEASE) {
1625184610Salfred			if (sc->sc_flags & UKBD_FLAG_COMPOSE) {
1626184610Salfred				sc->sc_flags &= ~UKBD_FLAG_COMPOSE;
1627184610Salfred
1628184610Salfred				if (sc->sc_composed_char > 0xFF) {
1629184610Salfred					sc->sc_composed_char = 0;
1630184610Salfred				}
1631184610Salfred			}
1632184610Salfred		} else {
1633184610Salfred			if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) {
1634184610Salfred				sc->sc_flags |= UKBD_FLAG_COMPOSE;
1635184610Salfred				sc->sc_composed_char = 0;
1636184610Salfred			}
1637184610Salfred		}
1638184610Salfred		break;
1639184610Salfred	}
1640184610Salfred
1641184610Salfred	/* return the key code in the K_CODE mode */
1642184610Salfred	if (usbcode & KEY_RELEASE) {
1643184610Salfred		keycode |= SCAN_RELEASE;
1644184610Salfred	}
1645184610Salfred	if (sc->sc_mode == K_CODE) {
1646184610Salfred		return (keycode);
1647184610Salfred	}
1648184610Salfred	/* compose a character code */
1649184610Salfred	if (sc->sc_flags & UKBD_FLAG_COMPOSE) {
1650184610Salfred		switch (keycode) {
1651184610Salfred			/* key pressed, process it */
1652184610Salfred		case 0x47:
1653184610Salfred		case 0x48:
1654184610Salfred		case 0x49:		/* keypad 7,8,9 */
1655184610Salfred			sc->sc_composed_char *= 10;
1656184610Salfred			sc->sc_composed_char += keycode - 0x40;
1657184610Salfred			goto check_composed;
1658184610Salfred
1659184610Salfred		case 0x4B:
1660184610Salfred		case 0x4C:
1661184610Salfred		case 0x4D:		/* keypad 4,5,6 */
1662184610Salfred			sc->sc_composed_char *= 10;
1663184610Salfred			sc->sc_composed_char += keycode - 0x47;
1664184610Salfred			goto check_composed;
1665184610Salfred
1666184610Salfred		case 0x4F:
1667184610Salfred		case 0x50:
1668184610Salfred		case 0x51:		/* keypad 1,2,3 */
1669184610Salfred			sc->sc_composed_char *= 10;
1670184610Salfred			sc->sc_composed_char += keycode - 0x4E;
1671184610Salfred			goto check_composed;
1672184610Salfred
1673184610Salfred		case 0x52:		/* keypad 0 */
1674184610Salfred			sc->sc_composed_char *= 10;
1675184610Salfred			goto check_composed;
1676184610Salfred
1677184610Salfred			/* key released, no interest here */
1678184610Salfred		case SCAN_RELEASE | 0x47:
1679184610Salfred		case SCAN_RELEASE | 0x48:
1680184610Salfred		case SCAN_RELEASE | 0x49:	/* keypad 7,8,9 */
1681184610Salfred		case SCAN_RELEASE | 0x4B:
1682184610Salfred		case SCAN_RELEASE | 0x4C:
1683184610Salfred		case SCAN_RELEASE | 0x4D:	/* keypad 4,5,6 */
1684184610Salfred		case SCAN_RELEASE | 0x4F:
1685184610Salfred		case SCAN_RELEASE | 0x50:
1686184610Salfred		case SCAN_RELEASE | 0x51:	/* keypad 1,2,3 */
1687184610Salfred		case SCAN_RELEASE | 0x52:	/* keypad 0 */
1688184610Salfred			goto next_code;
1689184610Salfred
1690184610Salfred		case 0x38:		/* left alt key */
1691184610Salfred			break;
1692184610Salfred
1693184610Salfred		default:
1694184610Salfred			if (sc->sc_composed_char > 0) {
1695184610Salfred				sc->sc_flags &= ~UKBD_FLAG_COMPOSE;
1696184610Salfred				sc->sc_composed_char = 0;
1697184610Salfred				goto errkey;
1698184610Salfred			}
1699184610Salfred			break;
1700184610Salfred		}
1701184610Salfred	}
1702184610Salfred	/* keycode to key action */
1703184610Salfred	action = genkbd_keyaction(kbd, SCAN_CHAR(keycode),
1704184610Salfred	    (keycode & SCAN_RELEASE),
1705184610Salfred	    &sc->sc_state, &sc->sc_accents);
1706184610Salfred	if (action == NOKEY) {
1707184610Salfred		goto next_code;
1708184610Salfred	}
1709184610Salfreddone:
1710184610Salfred	return (action);
1711184610Salfred
1712184610Salfredcheck_composed:
1713184610Salfred	if (sc->sc_composed_char <= 0xFF) {
1714184610Salfred		goto next_code;
1715184610Salfred	}
1716184610Salfrederrkey:
1717184610Salfred	return (ERRKEY);
1718184610Salfred}
1719184610Salfred
1720228765Savg/* Currently wait is always false. */
1721228765Savgstatic uint32_t
1722228765Savgukbd_read_char(keyboard_t *kbd, int wait)
1723228765Savg{
1724228765Savg	uint32_t keycode;
1725228765Savg
1726228765Savg	UKBD_LOCK();
1727228765Savg	keycode = ukbd_read_char_locked(kbd, wait);
1728228765Savg	UKBD_UNLOCK();
1729228765Savg
1730228765Savg	return (keycode);
1731228765Savg}
1732228765Savg
1733184610Salfred/* some useful control functions */
1734184610Salfredstatic int
1735228765Savgukbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg)
1736184610Salfred{
1737184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1738184610Salfred	int i;
1739184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1740184610Salfred    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1741184610Salfred	int ival;
1742184610Salfred
1743184610Salfred#endif
1744184610Salfred
1745228765Savg	UKBD_LOCK_ASSERT();
1746228765Savg
1747184610Salfred	switch (cmd) {
1748184610Salfred	case KDGKBMODE:		/* get keyboard mode */
1749184610Salfred		*(int *)arg = sc->sc_mode;
1750184610Salfred		break;
1751184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1752184610Salfred    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1753184610Salfred	case _IO('K', 7):
1754184610Salfred		ival = IOCPARM_IVAL(arg);
1755184610Salfred		arg = (caddr_t)&ival;
1756184610Salfred		/* FALLTHROUGH */
1757184610Salfred#endif
1758184610Salfred	case KDSKBMODE:		/* set keyboard mode */
1759184610Salfred		switch (*(int *)arg) {
1760184610Salfred		case K_XLATE:
1761184610Salfred			if (sc->sc_mode != K_XLATE) {
1762184610Salfred				/* make lock key state and LED state match */
1763184610Salfred				sc->sc_state &= ~LOCK_MASK;
1764184610Salfred				sc->sc_state |= KBD_LED_VAL(kbd);
1765184610Salfred			}
1766184610Salfred			/* FALLTHROUGH */
1767184610Salfred		case K_RAW:
1768184610Salfred		case K_CODE:
1769184610Salfred			if (sc->sc_mode != *(int *)arg) {
1770228765Savg				if ((sc->sc_flags & UKBD_FLAG_POLLING) == 0)
1771203896Sthompsa					ukbd_clear_state(kbd);
1772184610Salfred				sc->sc_mode = *(int *)arg;
1773184610Salfred			}
1774184610Salfred			break;
1775184610Salfred		default:
1776184610Salfred			return (EINVAL);
1777184610Salfred		}
1778184610Salfred		break;
1779184610Salfred
1780184610Salfred	case KDGETLED:			/* get keyboard LED */
1781184610Salfred		*(int *)arg = KBD_LED_VAL(kbd);
1782184610Salfred		break;
1783184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1784184610Salfred    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1785184610Salfred	case _IO('K', 66):
1786184610Salfred		ival = IOCPARM_IVAL(arg);
1787184610Salfred		arg = (caddr_t)&ival;
1788184610Salfred		/* FALLTHROUGH */
1789184610Salfred#endif
1790184610Salfred	case KDSETLED:			/* set keyboard LED */
1791184610Salfred		/* NOTE: lock key state in "sc_state" won't be changed */
1792223755Shselasky		if (*(int *)arg & ~LOCK_MASK)
1793184610Salfred			return (EINVAL);
1794223755Shselasky
1795184610Salfred		i = *(int *)arg;
1796223755Shselasky
1797184610Salfred		/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
1798184610Salfred		if (sc->sc_mode == K_XLATE &&
1799184610Salfred		    kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
1800184610Salfred			if (i & ALKED)
1801184610Salfred				i |= CLKED;
1802184610Salfred			else
1803184610Salfred				i &= ~CLKED;
1804184610Salfred		}
1805223755Shselasky		if (KBD_HAS_DEVICE(kbd))
1806223755Shselasky			ukbd_set_leds(sc, i);
1807223755Shselasky
1808184610Salfred		KBD_LED_VAL(kbd) = *(int *)arg;
1809184610Salfred		break;
1810184610Salfred	case KDGKBSTATE:		/* get lock key state */
1811184610Salfred		*(int *)arg = sc->sc_state & LOCK_MASK;
1812184610Salfred		break;
1813184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1814184610Salfred    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1815184610Salfred	case _IO('K', 20):
1816184610Salfred		ival = IOCPARM_IVAL(arg);
1817184610Salfred		arg = (caddr_t)&ival;
1818184610Salfred		/* FALLTHROUGH */
1819184610Salfred#endif
1820184610Salfred	case KDSKBSTATE:		/* set lock key state */
1821184610Salfred		if (*(int *)arg & ~LOCK_MASK) {
1822184610Salfred			return (EINVAL);
1823184610Salfred		}
1824184610Salfred		sc->sc_state &= ~LOCK_MASK;
1825184610Salfred		sc->sc_state |= *(int *)arg;
1826184610Salfred
1827184610Salfred		/* set LEDs and quit */
1828184610Salfred		return (ukbd_ioctl(kbd, KDSETLED, arg));
1829184610Salfred
1830184610Salfred	case KDSETREPEAT:		/* set keyboard repeat rate (new
1831184610Salfred					 * interface) */
1832184610Salfred		if (!KBD_HAS_DEVICE(kbd)) {
1833184610Salfred			return (0);
1834184610Salfred		}
1835358214Shselasky		/*
1836358214Shselasky		 * Convert negative, zero and tiny args to the same limits
1837358214Shselasky		 * as atkbd.  We could support delays of 1 msec, but
1838358214Shselasky		 * anything much shorter than the shortest atkbd value
1839358214Shselasky		 * of 250.34 is almost unusable as well as incompatible.
1840358214Shselasky		 */
1841358214Shselasky		kbd->kb_delay1 = imax(((int *)arg)[0], 250);
1842358214Shselasky		kbd->kb_delay2 = imax(((int *)arg)[1], 34);
1843307775Sgonzo#ifdef EVDEV_SUPPORT
1844307764Sgonzo		if (sc->sc_evdev != NULL)
1845307764Sgonzo			evdev_push_repeats(sc->sc_evdev, kbd);
1846307764Sgonzo#endif
1847184610Salfred		return (0);
1848184610Salfred
1849184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1850184610Salfred    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1851184610Salfred	case _IO('K', 67):
1852184610Salfred		ival = IOCPARM_IVAL(arg);
1853184610Salfred		arg = (caddr_t)&ival;
1854184610Salfred		/* FALLTHROUGH */
1855184610Salfred#endif
1856184610Salfred	case KDSETRAD:			/* set keyboard repeat rate (old
1857184610Salfred					 * interface) */
1858184610Salfred		return (ukbd_set_typematic(kbd, *(int *)arg));
1859184610Salfred
1860184610Salfred	case PIO_KEYMAP:		/* set keyboard translation table */
1861224126Sed	case OPIO_KEYMAP:		/* set keyboard translation table
1862224126Sed					 * (compat) */
1863184610Salfred	case PIO_KEYMAPENT:		/* set keyboard translation table
1864184610Salfred					 * entry */
1865184610Salfred	case PIO_DEADKEYMAP:		/* set accent key translation table */
1866184610Salfred		sc->sc_accents = 0;
1867184610Salfred		/* FALLTHROUGH */
1868184610Salfred	default:
1869184610Salfred		return (genkbd_commonioctl(kbd, cmd, arg));
1870184610Salfred	}
1871184610Salfred
1872184610Salfred	return (0);
1873184610Salfred}
1874184610Salfred
1875228765Savgstatic int
1876228765Savgukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
1877228765Savg{
1878228765Savg	int result;
1879228765Savg
1880228765Savg	/*
1881263262Shselasky	 * XXX Check if someone is calling us from a critical section:
1882262972Shselasky	 */
1883262972Shselasky	if (curthread->td_critnest != 0)
1884262972Shselasky		return (EDEADLK);
1885262972Shselasky
1886262972Shselasky	/*
1887228765Savg	 * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any
1888228765Savg	 * context where printf(9) can be called, which among other things
1889228765Savg	 * includes interrupt filters and threads with any kinds of locks
1890228765Savg	 * already held.  For this reason it would be dangerous to acquire
1891228765Savg	 * the Giant here unconditionally.  On the other hand we have to
1892228765Savg	 * have it to handle the ioctl.
1893228765Savg	 * So we make our best effort to auto-detect whether we can grab
1894228765Savg	 * the Giant or not.  Blame syscons(4) for this.
1895228765Savg	 */
1896228765Savg	switch (cmd) {
1897228765Savg	case KDGKBSTATE:
1898228765Savg	case KDSKBSTATE:
1899228765Savg	case KDSETLED:
1900228765Savg		if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED())
1901228765Savg			return (EDEADLK);	/* best I could come up with */
1902228765Savg		/* FALLTHROUGH */
1903228765Savg	default:
1904228765Savg		UKBD_LOCK();
1905228765Savg		result = ukbd_ioctl_locked(kbd, cmd, arg);
1906228765Savg		UKBD_UNLOCK();
1907228765Savg		return (result);
1908228765Savg	}
1909228765Savg}
1910228765Savg
1911228765Savg
1912184610Salfred/* clear the internal state of the keyboard */
1913184610Salfredstatic void
1914184610Salfredukbd_clear_state(keyboard_t *kbd)
1915184610Salfred{
1916184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1917184610Salfred
1918228765Savg	UKBD_CTX_LOCK_ASSERT();
1919184610Salfred
1920184610Salfred	sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING);
1921184610Salfred	sc->sc_state &= LOCK_MASK;	/* preserve locking key state */
1922184610Salfred	sc->sc_accents = 0;
1923184610Salfred	sc->sc_composed_char = 0;
1924184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
1925184610Salfred	sc->sc_buffered_char[0] = 0;
1926184610Salfred	sc->sc_buffered_char[1] = 0;
1927184610Salfred#endif
1928203896Sthompsa	memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
1929203896Sthompsa	memset(&sc->sc_odata, 0, sizeof(sc->sc_odata));
1930358216Shselasky	sc->sc_repeat_time = 0;
1931358216Shselasky	sc->sc_repeat_key = 0;
1932184610Salfred}
1933184610Salfred
1934184610Salfred/* save the internal state, not used */
1935184610Salfredstatic int
1936184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len)
1937184610Salfred{
1938184610Salfred	return (len == 0) ? 1 : -1;
1939184610Salfred}
1940184610Salfred
1941184610Salfred/* set the internal state, not used */
1942184610Salfredstatic int
1943184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len)
1944184610Salfred{
1945184610Salfred	return (EINVAL);
1946184610Salfred}
1947184610Salfred
1948184610Salfredstatic int
1949184610Salfredukbd_poll(keyboard_t *kbd, int on)
1950184610Salfred{
1951184610Salfred	struct ukbd_softc *sc = kbd->kb_data;
1952184610Salfred
1953228765Savg	UKBD_LOCK();
1954304124Shselasky	/*
1955304124Shselasky	 * Keep a reference count on polling to allow recursive
1956304124Shselasky	 * cngrab() during a panic for example.
1957304124Shselasky	 */
1958304124Shselasky	if (on)
1959304124Shselasky		sc->sc_polling++;
1960305644Shselasky	else if (sc->sc_polling > 0)
1961304124Shselasky		sc->sc_polling--;
1962304124Shselasky
1963304124Shselasky	if (sc->sc_polling != 0) {
1964184610Salfred		sc->sc_flags |= UKBD_FLAG_POLLING;
1965203896Sthompsa		sc->sc_poll_thread = curthread;
1966184610Salfred	} else {
1967184610Salfred		sc->sc_flags &= ~UKBD_FLAG_POLLING;
1968358215Shselasky		sc->sc_delay = 0;
1969184610Salfred	}
1970228765Savg	UKBD_UNLOCK();
1971228765Savg
1972184610Salfred	return (0);
1973184610Salfred}
1974184610Salfred
1975184610Salfred/* local functions */
1976184610Salfred
1977184610Salfredstatic void
1978184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds)
1979184610Salfred{
1980228765Savg
1981228765Savg	UKBD_LOCK_ASSERT();
1982184610Salfred	DPRINTF("leds=0x%02x\n", leds);
1983184610Salfred
1984184610Salfred	sc->sc_leds = leds;
1985184610Salfred	sc->sc_flags |= UKBD_FLAG_SET_LEDS;
1986184610Salfred
1987184610Salfred	/* start transfer, if not already started */
1988184610Salfred
1989194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]);
1990184610Salfred}
1991184610Salfred
1992184610Salfredstatic int
1993184610Salfredukbd_set_typematic(keyboard_t *kbd, int code)
1994184610Salfred{
1995307775Sgonzo#ifdef EVDEV_SUPPORT
1996307764Sgonzo	struct ukbd_softc *sc = kbd->kb_data;
1997307764Sgonzo#endif
1998184610Salfred	static const int delays[] = {250, 500, 750, 1000};
1999184610Salfred	static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63,
2000184610Salfred		68, 76, 84, 92, 100, 110, 118, 126,
2001184610Salfred		136, 152, 168, 184, 200, 220, 236, 252,
2002184610Salfred	272, 304, 336, 368, 400, 440, 472, 504};
2003184610Salfred
2004184610Salfred	if (code & ~0x7f) {
2005184610Salfred		return (EINVAL);
2006184610Salfred	}
2007184610Salfred	kbd->kb_delay1 = delays[(code >> 5) & 3];
2008184610Salfred	kbd->kb_delay2 = rates[code & 0x1f];
2009307775Sgonzo#ifdef EVDEV_SUPPORT
2010307764Sgonzo	if (sc->sc_evdev != NULL)
2011307764Sgonzo		evdev_push_repeats(sc->sc_evdev, kbd);
2012307764Sgonzo#endif
2013184610Salfred	return (0);
2014184610Salfred}
2015184610Salfred
2016184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE
2017358213Shselaskystatic uint32_t
2018358216Shselaskyukbd_atkeycode(int usbcode, const uint64_t *bitmap)
2019358213Shselasky{
2020358213Shselasky	uint32_t keycode;
2021358213Shselasky
2022358213Shselasky	keycode = ukbd_trtab[KEY_INDEX(usbcode)];
2023358216Shselasky
2024358213Shselasky	/*
2025358213Shselasky	 * Translate Alt-PrintScreen to SysRq.
2026358213Shselasky	 *
2027358213Shselasky	 * Some or all AT keyboards connected through USB have already
2028358213Shselasky	 * mapped Alted PrintScreens to an unusual usbcode (0x8a).
2029358213Shselasky	 * ukbd_trtab translates this to 0x7e, and key2scan() would
2030358213Shselasky	 * translate that to 0x79 (Intl' 4).  Assume that if we have
2031358213Shselasky	 * an Alted 0x7e here then it actually is an Alted PrintScreen.
2032358213Shselasky	 *
2033358213Shselasky	 * The usual usbcode for all PrintScreens is 0x46.  ukbd_trtab
2034358213Shselasky	 * translates this to 0x5c, so the Alt check to classify 0x5c
2035358213Shselasky	 * is routine.
2036358213Shselasky	 */
2037358213Shselasky	if ((keycode == 0x5c || keycode == 0x7e) &&
2038358216Shselasky	    (UKBD_KEY_PRESSED(bitmap, 0xe2 /* ALT-L */) ||
2039358216Shselasky	     UKBD_KEY_PRESSED(bitmap, 0xe6 /* ALT-R */)))
2040358213Shselasky		return (0x54);
2041358213Shselasky	return (keycode);
2042358213Shselasky}
2043358213Shselasky
2044184610Salfredstatic int
2045358216Shselaskyukbd_key2scan(struct ukbd_softc *sc, int code, const uint64_t *bitmap, int up)
2046184610Salfred{
2047184610Salfred	static const int scan[] = {
2048197999Shrs		/* 89 */
2049197999Shrs		0x11c,	/* Enter */
2050197999Shrs		/* 90-99 */
2051197999Shrs		0x11d,	/* Ctrl-R */
2052197999Shrs		0x135,	/* Divide */
2053358212Shselasky		0x137,	/* PrintScreen */
2054197999Shrs		0x138,	/* Alt-R */
2055197999Shrs		0x147,	/* Home */
2056197999Shrs		0x148,	/* Up */
2057197999Shrs		0x149,	/* PageUp */
2058197999Shrs		0x14b,	/* Left */
2059197999Shrs		0x14d,	/* Right */
2060197999Shrs		0x14f,	/* End */
2061197999Shrs		/* 100-109 */
2062197999Shrs		0x150,	/* Down */
2063197999Shrs		0x151,	/* PageDown */
2064197999Shrs		0x152,	/* Insert */
2065197999Shrs		0x153,	/* Delete */
2066358213Shselasky		0x146,	/* Pause/Break */
2067197999Shrs		0x15b,	/* Win_L(Super_L) */
2068197999Shrs		0x15c,	/* Win_R(Super_R) */
2069197999Shrs		0x15d,	/* Application(Menu) */
2070197999Shrs
2071184610Salfred		/* SUN TYPE 6 USB KEYBOARD */
2072197999Shrs		0x168,	/* Sun Type 6 Help */
2073197999Shrs		0x15e,	/* Sun Type 6 Stop */
2074197999Shrs		/* 110 - 119 */
2075197999Shrs		0x15f,	/* Sun Type 6 Again */
2076197999Shrs		0x160,	/* Sun Type 6 Props */
2077197999Shrs		0x161,	/* Sun Type 6 Undo */
2078197999Shrs		0x162,	/* Sun Type 6 Front */
2079197999Shrs		0x163,	/* Sun Type 6 Copy */
2080197999Shrs		0x164,	/* Sun Type 6 Open */
2081197999Shrs		0x165,	/* Sun Type 6 Paste */
2082197999Shrs		0x166,	/* Sun Type 6 Find */
2083197999Shrs		0x167,	/* Sun Type 6 Cut */
2084197999Shrs		0x125,	/* Sun Type 6 Mute */
2085291146Shselasky		/* 120 - 130 */
2086197999Shrs		0x11f,	/* Sun Type 6 VolumeDown */
2087197999Shrs		0x11e,	/* Sun Type 6 VolumeUp */
2088197999Shrs		0x120,	/* Sun Type 6 PowerDown */
2089197999Shrs
2090197999Shrs		/* Japanese 106/109 keyboard */
2091197999Shrs		0x73,	/* Keyboard Intl' 1 (backslash / underscore) */
2092197999Shrs		0x70,	/* Keyboard Intl' 2 (Katakana / Hiragana) */
2093197999Shrs		0x7d,	/* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */
2094197999Shrs		0x79,	/* Keyboard Intl' 4 (Henkan) */
2095197999Shrs		0x7b,	/* Keyboard Intl' 5 (Muhenkan) */
2096197999Shrs		0x5c,	/* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */
2097291146Shselasky		0x71,   /* Apple Keyboard JIS (Kana) */
2098291146Shselasky		0x72,   /* Apple Keyboard JIS (Eisu) */
2099184610Salfred	};
2100184610Salfred
2101298300Spfg	if ((code >= 89) && (code < (int)(89 + nitems(scan)))) {
2102197999Shrs		code = scan[code - 89];
2103184610Salfred	}
2104358212Shselasky	/* PrintScreen */
2105358216Shselasky	if (code == 0x137 && (!(
2106358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe0 /* CTRL-L */) ||
2107358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe4 /* CTRL-R */) ||
2108358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe1 /* SHIFT-L */) ||
2109358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe5 /* SHIFT-R */)))) {
2110358212Shselasky		code |= SCAN_PREFIX_SHIFT;
2111358212Shselasky	}
2112184610Salfred	/* Pause/Break */
2113358216Shselasky	if ((code == 0x146) && (!(
2114358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe0 /* CTRL-L */) ||
2115358216Shselasky	    UKBD_KEY_PRESSED(bitmap, 0xe4 /* CTRL-R */)))) {
2116184610Salfred		code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL);
2117184610Salfred	}
2118184610Salfred	code |= (up ? SCAN_RELEASE : SCAN_PRESS);
2119184610Salfred
2120184610Salfred	if (code & SCAN_PREFIX) {
2121184610Salfred		if (code & SCAN_PREFIX_CTL) {
2122184610Salfred			/* Ctrl */
2123184610Salfred			sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE));
2124184610Salfred			sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX);
2125184610Salfred		} else if (code & SCAN_PREFIX_SHIFT) {
2126184610Salfred			/* Shift */
2127184610Salfred			sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE));
2128184610Salfred			sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT);
2129184610Salfred		} else {
2130184610Salfred			sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX);
2131184610Salfred			sc->sc_buffered_char[1] = 0;
2132184610Salfred		}
2133184610Salfred		return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
2134184610Salfred	}
2135184610Salfred	return (code);
2136184610Salfred
2137184610Salfred}
2138184610Salfred
2139184610Salfred#endif					/* UKBD_EMULATE_ATSCANCODE */
2140184610Salfred
2141194099Sthompsastatic keyboard_switch_t ukbdsw = {
2142184610Salfred	.probe = &ukbd__probe,
2143184610Salfred	.init = &ukbd_init,
2144184610Salfred	.term = &ukbd_term,
2145184610Salfred	.intr = &ukbd_intr,
2146184610Salfred	.test_if = &ukbd_test_if,
2147184610Salfred	.enable = &ukbd_enable,
2148184610Salfred	.disable = &ukbd_disable,
2149184610Salfred	.read = &ukbd_read,
2150184610Salfred	.check = &ukbd_check,
2151184610Salfred	.read_char = &ukbd_read_char,
2152184610Salfred	.check_char = &ukbd_check_char,
2153184610Salfred	.ioctl = &ukbd_ioctl,
2154184610Salfred	.lock = &ukbd_lock,
2155184610Salfred	.clear_state = &ukbd_clear_state,
2156184610Salfred	.get_state = &ukbd_get_state,
2157184610Salfred	.set_state = &ukbd_set_state,
2158184610Salfred	.poll = &ukbd_poll,
2159184610Salfred};
2160184610Salfred
2161184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure);
2162184610Salfred
2163184610Salfredstatic int
2164184610Salfredukbd_driver_load(module_t mod, int what, void *arg)
2165184610Salfred{
2166184610Salfred	switch (what) {
2167193315Sthompsa	case MOD_LOAD:
2168184610Salfred		kbd_add_driver(&ukbd_kbd_driver);
2169184610Salfred		break;
2170184610Salfred	case MOD_UNLOAD:
2171184610Salfred		kbd_delete_driver(&ukbd_kbd_driver);
2172184610Salfred		break;
2173184610Salfred	}
2174184610Salfred	return (0);
2175184610Salfred}
2176184610Salfred
2177184610Salfredstatic devclass_t ukbd_devclass;
2178184610Salfred
2179184610Salfredstatic device_method_t ukbd_methods[] = {
2180184610Salfred	DEVMETHOD(device_probe, ukbd_probe),
2181184610Salfred	DEVMETHOD(device_attach, ukbd_attach),
2182184610Salfred	DEVMETHOD(device_detach, ukbd_detach),
2183184610Salfred	DEVMETHOD(device_resume, ukbd_resume),
2184246128Ssbz
2185246128Ssbz	DEVMETHOD_END
2186184610Salfred};
2187184610Salfred
2188184610Salfredstatic driver_t ukbd_driver = {
2189184610Salfred	.name = "ukbd",
2190184610Salfred	.methods = ukbd_methods,
2191184610Salfred	.size = sizeof(struct ukbd_softc),
2192184610Salfred};
2193184610Salfred
2194189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0);
2195188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1);
2196307775Sgonzo#ifdef EVDEV_SUPPORT
2197307775SgonzoMODULE_DEPEND(ukbd, evdev, 1, 1, 1);
2198307775Sgonzo#endif
2199212122SthompsaMODULE_VERSION(ukbd, 1);
2200292080SimpUSB_PNP_HOST_INFO(ukbd_devs);
2201