ukbd.c revision 196403
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/input/ukbd.c 196403 2009-08-20 19:17:53Z jhb $"); 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 * 3. All advertising materials mentioning features or use of this software 22184610Salfred * must display the following acknowledgement: 23184610Salfred * This product includes software developed by the NetBSD 24184610Salfred * Foundation, Inc. and its contributors. 25184610Salfred * 4. Neither the name of The NetBSD Foundation nor the names of its 26184610Salfred * contributors may be used to endorse or promote products derived 27184610Salfred * from this software without specific prior written permission. 28184610Salfred * 29184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 30184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 33184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39184610Salfred * POSSIBILITY OF SUCH DAMAGE. 40184610Salfred * 41184610Salfred */ 42184610Salfred 43184610Salfred/* 44184610Salfred * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 45184610Salfred */ 46184610Salfred 47184610Salfred#include "opt_compat.h" 48184610Salfred#include "opt_kbd.h" 49184610Salfred#include "opt_ukbd.h" 50184610Salfred 51194677Sthompsa#include <sys/stdint.h> 52194677Sthompsa#include <sys/stddef.h> 53194677Sthompsa#include <sys/param.h> 54194677Sthompsa#include <sys/queue.h> 55194677Sthompsa#include <sys/types.h> 56194677Sthompsa#include <sys/systm.h> 57194677Sthompsa#include <sys/kernel.h> 58194677Sthompsa#include <sys/bus.h> 59194677Sthompsa#include <sys/linker_set.h> 60194677Sthompsa#include <sys/module.h> 61194677Sthompsa#include <sys/lock.h> 62194677Sthompsa#include <sys/mutex.h> 63194677Sthompsa#include <sys/condvar.h> 64194677Sthompsa#include <sys/sysctl.h> 65194677Sthompsa#include <sys/sx.h> 66194677Sthompsa#include <sys/unistd.h> 67194677Sthompsa#include <sys/callout.h> 68194677Sthompsa#include <sys/malloc.h> 69194677Sthompsa#include <sys/priv.h> 70194677Sthompsa 71188942Sthompsa#include <dev/usb/usb.h> 72194677Sthompsa#include <dev/usb/usbdi.h> 73194677Sthompsa#include <dev/usb/usbdi_util.h> 74188942Sthompsa#include <dev/usb/usbhid.h> 75184610Salfred 76184610Salfred#define USB_DEBUG_VAR ukbd_debug 77188942Sthompsa#include <dev/usb/usb_debug.h> 78184610Salfred 79188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 80184610Salfred 81184610Salfred#include <sys/ioccom.h> 82184610Salfred#include <sys/filio.h> 83184610Salfred#include <sys/tty.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 97184610Salfred#if USB_DEBUG 98184610Salfredstatic int ukbd_debug = 0; 99184610Salfred 100192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); 101192502SthompsaSYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW, 102184610Salfred &ukbd_debug, 0, "Debug level"); 103184610Salfred#endif 104184610Salfred 105184610Salfred#define UPROTO_BOOT_KEYBOARD 1 106184610Salfred 107184610Salfred#define UKBD_EMULATE_ATSCANCODE 1 108184610Salfred#define UKBD_DRIVER_NAME "ukbd" 109184610Salfred#define UKBD_NMOD 8 /* units */ 110184610Salfred#define UKBD_NKEYCODE 6 /* units */ 111184610Salfred#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */ 112184610Salfred#define UKBD_IN_BUF_FULL (UKBD_IN_BUF_SIZE / 2) /* bytes */ 113184610Salfred#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */ 114184610Salfred 115184610Salfredstruct ukbd_data { 116184610Salfred uint8_t modifiers; 117184610Salfred#define MOD_CONTROL_L 0x01 118184610Salfred#define MOD_CONTROL_R 0x10 119184610Salfred#define MOD_SHIFT_L 0x02 120184610Salfred#define MOD_SHIFT_R 0x20 121184610Salfred#define MOD_ALT_L 0x04 122184610Salfred#define MOD_ALT_R 0x40 123184610Salfred#define MOD_WIN_L 0x08 124184610Salfred#define MOD_WIN_R 0x80 125184610Salfred uint8_t reserved; 126184610Salfred uint8_t keycode[UKBD_NKEYCODE]; 127192925Sthompsa uint8_t exten[8]; 128192925Sthompsa}; 129184610Salfred 130187259Sthompsaenum { 131187259Sthompsa UKBD_INTR_DT, 132187259Sthompsa UKBD_CTRL_LED, 133192925Sthompsa UKBD_N_TRANSFER, 134187259Sthompsa}; 135187259Sthompsa 136184610Salfredstruct ukbd_softc { 137184610Salfred keyboard_t sc_kbd; 138184610Salfred keymap_t sc_keymap; 139184610Salfred accentmap_t sc_accmap; 140184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 141192925Sthompsa struct hid_location sc_loc_apple_eject; 142192925Sthompsa struct hid_location sc_loc_apple_fn; 143192984Sthompsa struct usb_callout sc_callout; 144184610Salfred struct ukbd_data sc_ndata; 145184610Salfred struct ukbd_data sc_odata; 146184610Salfred 147192984Sthompsa struct usb_device *sc_udev; 148192984Sthompsa struct usb_interface *sc_iface; 149192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 150184610Salfred 151184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 152184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 153184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 154184610Salfred uint32_t sc_time_ms; 155184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 156184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 157184610Salfred uint32_t sc_buffered_char[2]; 158184610Salfred#endif 159184610Salfred uint32_t sc_flags; /* flags */ 160192925Sthompsa#define UKBD_FLAG_COMPOSE 0x0001 161192925Sthompsa#define UKBD_FLAG_POLLING 0x0002 162192925Sthompsa#define UKBD_FLAG_SET_LEDS 0x0004 163192925Sthompsa#define UKBD_FLAG_ATTACHED 0x0010 164192925Sthompsa#define UKBD_FLAG_GONE 0x0020 165192925Sthompsa#define UKBD_FLAG_APPLE_EJECT 0x0040 166192925Sthompsa#define UKBD_FLAG_APPLE_FN 0x0080 167192925Sthompsa#define UKBD_FLAG_APPLE_SWAP 0x0100 168184610Salfred 169184610Salfred int32_t sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 170184610Salfred int32_t sc_state; /* shift/lock key state */ 171184610Salfred int32_t sc_accents; /* accent key index (> 0) */ 172184610Salfred 173184610Salfred uint16_t sc_inputs; 174184610Salfred uint16_t sc_inputhead; 175184610Salfred uint16_t sc_inputtail; 176184610Salfred 177184610Salfred uint8_t sc_leds; /* store for async led requests */ 178184610Salfred uint8_t sc_iface_index; 179184610Salfred uint8_t sc_iface_no; 180192925Sthompsa uint8_t sc_kbd_id; 181192925Sthompsa uint8_t sc_led_id; 182184610Salfred}; 183184610Salfred 184184610Salfred#define KEY_ERROR 0x01 185184610Salfred 186184610Salfred#define KEY_PRESS 0 187184610Salfred#define KEY_RELEASE 0x400 188184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 189184610Salfred 190184610Salfred#define SCAN_PRESS 0 191184610Salfred#define SCAN_RELEASE 0x80 192184610Salfred#define SCAN_PREFIX_E0 0x100 193184610Salfred#define SCAN_PREFIX_E1 0x200 194184610Salfred#define SCAN_PREFIX_CTL 0x400 195184610Salfred#define SCAN_PREFIX_SHIFT 0x800 196184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 197184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 198184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 199184610Salfred 200184610Salfredstruct ukbd_mods { 201184610Salfred uint32_t mask, key; 202184610Salfred}; 203184610Salfred 204184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 205184610Salfred {MOD_CONTROL_L, 0xe0}, 206184610Salfred {MOD_CONTROL_R, 0xe4}, 207184610Salfred {MOD_SHIFT_L, 0xe1}, 208184610Salfred {MOD_SHIFT_R, 0xe5}, 209184610Salfred {MOD_ALT_L, 0xe2}, 210184610Salfred {MOD_ALT_R, 0xe6}, 211184610Salfred {MOD_WIN_L, 0xe3}, 212184610Salfred {MOD_WIN_R, 0xe7}, 213184610Salfred}; 214184610Salfred 215184610Salfred#define NN 0 /* no translation */ 216184610Salfred/* 217184610Salfred * Translate USB keycodes to AT keyboard scancodes. 218184610Salfred */ 219184610Salfred/* 220184610Salfred * FIXME: Mac USB keyboard generates: 221184610Salfred * 0x53: keypad NumLock/Clear 222184610Salfred * 0x66: Power 223184610Salfred * 0x67: keypad = 224184610Salfred * 0x68: F13 225184610Salfred * 0x69: F14 226184610Salfred * 0x6a: F15 227184610Salfred */ 228184610Salfredstatic const uint8_t ukbd_trtab[256] = { 229184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 230184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 231184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 232184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 233184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 234184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 235184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 236184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 237184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 238184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 239184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 240184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 241184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 242184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 243184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 244184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 245184610Salfred 121, 120, NN, NN, NN, NN, NN, 115, /* 80 - 87 */ 246184610Salfred 112, 125, 121, 123, NN, NN, NN, NN, /* 88 - 8F */ 247184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 248184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 249184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 250184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 251184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 252184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 253184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 254184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 255184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 256184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 257184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 258184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 259184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 260184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 261184610Salfred}; 262184610Salfred 263184610Salfred/* prototypes */ 264185948Sthompsastatic void ukbd_timeout(void *); 265185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 266185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 267184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 268185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 269184610Salfred#endif 270185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 271185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 272185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 273185948Sthompsastatic int ukbd_enable(keyboard_t *); 274185948Sthompsastatic int ukbd_disable(keyboard_t *); 275185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 276184610Salfred 277184610Salfredstatic device_probe_t ukbd_probe; 278184610Salfredstatic device_attach_t ukbd_attach; 279184610Salfredstatic device_detach_t ukbd_detach; 280184610Salfredstatic device_resume_t ukbd_resume; 281184610Salfred 282184610Salfredstatic void 283184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 284184610Salfred{ 285184610Salfred mtx_assert(&Giant, MA_OWNED); 286184610Salfred 287184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 288184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 289184610Salfred 290184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 291184610Salfred sc->sc_input[sc->sc_inputtail] = key; 292184610Salfred ++(sc->sc_inputs); 293184610Salfred ++(sc->sc_inputtail); 294184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 295184610Salfred sc->sc_inputtail = 0; 296184610Salfred } 297184610Salfred } else { 298184610Salfred DPRINTF("input buffer is full\n"); 299184610Salfred } 300184610Salfred} 301184610Salfred 302195960Salfredstatic void 303195960Salfredukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 304195960Salfred{ 305195960Salfred DPRINTFN(2, "polling\n"); 306195960Salfred 307195960Salfred while (sc->sc_inputs == 0) { 308195960Salfred 309195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 310195960Salfred 311195960Salfred DELAY(1000); /* delay 1 ms */ 312195960Salfred 313195960Salfred sc->sc_time_ms++; 314195960Salfred 315195960Salfred /* support repetition of keys: */ 316195960Salfred 317195960Salfred ukbd_interrupt(sc); 318195960Salfred 319195960Salfred if (!wait) 320195960Salfred break; 321195960Salfred } 322195960Salfred} 323195960Salfred 324184610Salfredstatic int32_t 325184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 326184610Salfred{ 327184610Salfred int32_t c; 328184610Salfred 329184610Salfred mtx_assert(&Giant, MA_OWNED); 330184610Salfred 331184610Salfred if (sc->sc_inputs == 0) { 332184610Salfred /* start transfer, if not already started */ 333194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 334184610Salfred } 335184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 336195960Salfred ukbd_do_poll(sc, wait); 337184610Salfred } 338184610Salfred if (sc->sc_inputs == 0) { 339184610Salfred c = -1; 340184610Salfred } else { 341184610Salfred c = sc->sc_input[sc->sc_inputhead]; 342184610Salfred --(sc->sc_inputs); 343184610Salfred ++(sc->sc_inputhead); 344184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 345184610Salfred sc->sc_inputhead = 0; 346184610Salfred } 347184610Salfred } 348184610Salfred return (c); 349184610Salfred} 350184610Salfred 351184610Salfredstatic void 352184610Salfredukbd_interrupt(struct ukbd_softc *sc) 353184610Salfred{ 354184610Salfred uint32_t n_mod; 355184610Salfred uint32_t o_mod; 356184610Salfred uint32_t now = sc->sc_time_ms; 357184610Salfred uint32_t dtime; 358184610Salfred uint32_t c; 359184610Salfred uint8_t key; 360184610Salfred uint8_t i; 361184610Salfred uint8_t j; 362184610Salfred 363184610Salfred if (sc->sc_ndata.keycode[0] == KEY_ERROR) { 364184610Salfred goto done; 365184610Salfred } 366184610Salfred n_mod = sc->sc_ndata.modifiers; 367184610Salfred o_mod = sc->sc_odata.modifiers; 368184610Salfred if (n_mod != o_mod) { 369184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 370184610Salfred if ((n_mod & ukbd_mods[i].mask) != 371184610Salfred (o_mod & ukbd_mods[i].mask)) { 372184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 373184610Salfred ((n_mod & ukbd_mods[i].mask) ? 374184610Salfred KEY_PRESS : KEY_RELEASE)); 375184610Salfred } 376184610Salfred } 377184610Salfred } 378184610Salfred /* Check for released keys. */ 379184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 380184610Salfred key = sc->sc_odata.keycode[i]; 381184610Salfred if (key == 0) { 382184610Salfred continue; 383184610Salfred } 384184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 385184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 386184610Salfred continue; 387184610Salfred } 388184610Salfred if (key == sc->sc_ndata.keycode[j]) { 389184610Salfred goto rfound; 390184610Salfred } 391184610Salfred } 392184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 393184610Salfredrfound: ; 394184610Salfred } 395184610Salfred 396184610Salfred /* Check for pressed keys. */ 397184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 398184610Salfred key = sc->sc_ndata.keycode[i]; 399184610Salfred if (key == 0) { 400184610Salfred continue; 401184610Salfred } 402184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 403184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 404184610Salfred if (sc->sc_odata.keycode[j] == 0) { 405184610Salfred continue; 406184610Salfred } 407184610Salfred if (key == sc->sc_odata.keycode[j]) { 408184610Salfred 409184610Salfred /* key is still pressed */ 410184610Salfred 411184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 412184610Salfred dtime = (sc->sc_otime[j] - now); 413184610Salfred 414184610Salfred if (!(dtime & 0x80000000)) { 415184610Salfred /* time has not elapsed */ 416184610Salfred goto pfound; 417184610Salfred } 418184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 419184610Salfred break; 420184610Salfred } 421184610Salfred } 422184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 423184610Salfred 424184610Salfred /* 425184610Salfred * If any other key is presently down, force its repeat to be 426184610Salfred * well in the future (100s). This makes the last key to be 427184610Salfred * pressed do the autorepeat. 428184610Salfred */ 429184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 430184610Salfred if (j != i) 431184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 432184610Salfred } 433184610Salfredpfound: ; 434184610Salfred } 435184610Salfred 436184610Salfred sc->sc_odata = sc->sc_ndata; 437184610Salfred 438184610Salfred bcopy(sc->sc_ntime, sc->sc_otime, sizeof(sc->sc_otime)); 439184610Salfred 440184610Salfred if (sc->sc_inputs == 0) { 441184610Salfred goto done; 442184610Salfred } 443184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 444184610Salfred goto done; 445184610Salfred } 446184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 447184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 448184610Salfred /* let the callback function process the input */ 449184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 450184610Salfred sc->sc_kbd.kb_callback.kc_arg); 451184610Salfred } else { 452184610Salfred /* read and discard the input, no one is waiting for it */ 453184610Salfred do { 454184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 455184610Salfred } while (c != NOKEY); 456184610Salfred } 457184610Salfreddone: 458184610Salfred return; 459184610Salfred} 460184610Salfred 461184610Salfredstatic void 462184610Salfredukbd_timeout(void *arg) 463184610Salfred{ 464184610Salfred struct ukbd_softc *sc = arg; 465184610Salfred 466184610Salfred mtx_assert(&Giant, MA_OWNED); 467184610Salfred 468184610Salfred if (!(sc->sc_flags & UKBD_FLAG_POLLING)) { 469184610Salfred sc->sc_time_ms += 25; /* milliseconds */ 470184610Salfred } 471184610Salfred ukbd_interrupt(sc); 472184610Salfred 473194228Sthompsa usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 474184610Salfred} 475184610Salfred 476192925Sthompsastatic uint8_t 477192925Sthompsaukbd_apple_fn(uint8_t keycode) { 478192925Sthompsa switch (keycode) { 479192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 480192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 481192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 482192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 483192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 484192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 485192925Sthompsa default: return keycode; 486192925Sthompsa } 487192925Sthompsa} 488184610Salfred 489192925Sthompsastatic uint8_t 490192925Sthompsaukbd_apple_swap(uint8_t keycode) { 491192925Sthompsa switch (keycode) { 492192925Sthompsa case 0x35: return 0x64; 493192925Sthompsa case 0x64: return 0x35; 494192925Sthompsa default: return keycode; 495184610Salfred } 496184610Salfred} 497184610Salfred 498184610Salfredstatic void 499194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 500184610Salfred{ 501194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 502194677Sthompsa struct usb_page_cache *pc; 503184610Salfred uint8_t i; 504192925Sthompsa uint8_t offset; 505192925Sthompsa uint8_t id; 506192925Sthompsa uint8_t apple_fn; 507192925Sthompsa uint8_t apple_eject; 508194677Sthompsa int len; 509184610Salfred 510194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 511194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 512194677Sthompsa 513184610Salfred switch (USB_GET_STATE(xfer)) { 514184610Salfred case USB_ST_TRANSFERRED: 515184610Salfred DPRINTF("actlen=%d bytes\n", len); 516184610Salfred 517192925Sthompsa if (len == 0) { 518192925Sthompsa DPRINTF("zero length data\n"); 519192925Sthompsa goto tr_setup; 520192925Sthompsa } 521192925Sthompsa 522192925Sthompsa if (sc->sc_kbd_id != 0) { 523192925Sthompsa /* check and remove HID ID byte */ 524194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 525192925Sthompsa if (id != sc->sc_kbd_id) { 526192925Sthompsa DPRINTF("wrong HID ID\n"); 527192925Sthompsa goto tr_setup; 528192925Sthompsa } 529192925Sthompsa offset = 1; 530192925Sthompsa len--; 531192925Sthompsa } else { 532192925Sthompsa offset = 0; 533192925Sthompsa } 534192925Sthompsa 535184610Salfred if (len > sizeof(sc->sc_ndata)) { 536184610Salfred len = sizeof(sc->sc_ndata); 537184610Salfred } 538192925Sthompsa 539184610Salfred if (len) { 540192925Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 541194677Sthompsa usbd_copy_out(pc, offset, &sc->sc_ndata, len); 542192925Sthompsa 543192925Sthompsa if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 544192925Sthompsa hid_get_data((uint8_t *)&sc->sc_ndata, 545192925Sthompsa len, &sc->sc_loc_apple_eject)) 546192925Sthompsa apple_eject = 1; 547192925Sthompsa else 548192925Sthompsa apple_eject = 0; 549192925Sthompsa 550192925Sthompsa if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 551192925Sthompsa hid_get_data((uint8_t *)&sc->sc_ndata, 552192925Sthompsa len, &sc->sc_loc_apple_fn)) 553192925Sthompsa apple_fn = 1; 554192925Sthompsa else 555192925Sthompsa apple_fn = 0; 556184610Salfred#if USB_DEBUG 557192925Sthompsa DPRINTF("apple_eject=%u apple_fn=%u\n", 558192925Sthompsa apple_eject, apple_fn); 559192925Sthompsa 560184610Salfred if (sc->sc_ndata.modifiers) { 561184610Salfred DPRINTF("mod: 0x%04x\n", sc->sc_ndata.modifiers); 562184610Salfred } 563184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 564184610Salfred if (sc->sc_ndata.keycode[i]) { 565184610Salfred DPRINTF("[%d] = %d\n", i, sc->sc_ndata.keycode[i]); 566184610Salfred } 567184610Salfred } 568184610Salfred#endif /* USB_DEBUG */ 569192925Sthompsa 570192925Sthompsa if (apple_fn) { 571192925Sthompsa for (i = 0; i < UKBD_NKEYCODE; i++) { 572192925Sthompsa sc->sc_ndata.keycode[i] = 573192925Sthompsa ukbd_apple_fn(sc->sc_ndata.keycode[i]); 574192925Sthompsa } 575192925Sthompsa } 576192925Sthompsa 577192925Sthompsa if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 578192925Sthompsa for (i = 0; i < UKBD_NKEYCODE; i++) { 579192925Sthompsa sc->sc_ndata.keycode[i] = 580192925Sthompsa ukbd_apple_swap(sc->sc_ndata.keycode[i]); 581192925Sthompsa } 582192925Sthompsa } 583192925Sthompsa 584184610Salfred ukbd_interrupt(sc); 585184610Salfred } 586184610Salfred case USB_ST_SETUP: 587192925Sthompsatr_setup: 588184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 589194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 590194228Sthompsa usbd_transfer_submit(xfer); 591184610Salfred } else { 592184610Salfred DPRINTF("input queue is full!\n"); 593184610Salfred } 594192925Sthompsa break; 595184610Salfred 596184610Salfred default: /* Error */ 597194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 598184610Salfred 599194677Sthompsa if (error != USB_ERR_CANCELLED) { 600184610Salfred /* try to clear stall first */ 601194677Sthompsa usbd_xfer_set_stall(xfer); 602192925Sthompsa goto tr_setup; 603184610Salfred } 604192925Sthompsa break; 605184610Salfred } 606184610Salfred} 607184610Salfred 608184610Salfredstatic void 609194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 610184610Salfred{ 611192984Sthompsa struct usb_device_request req; 612194677Sthompsa struct usb_page_cache *pc; 613192925Sthompsa uint8_t buf[2]; 614194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 615184610Salfred 616184610Salfred switch (USB_GET_STATE(xfer)) { 617184610Salfred case USB_ST_TRANSFERRED: 618184610Salfred case USB_ST_SETUP: 619184610Salfred if (sc->sc_flags & UKBD_FLAG_SET_LEDS) { 620184610Salfred sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 621184610Salfred 622184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 623184610Salfred req.bRequest = UR_SET_REPORT; 624184610Salfred USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 625184610Salfred req.wIndex[0] = sc->sc_iface_no; 626184610Salfred req.wIndex[1] = 0; 627192925Sthompsa req.wLength[1] = 0; 628184610Salfred 629192925Sthompsa /* check if we need to prefix an ID byte */ 630192925Sthompsa if (sc->sc_led_id != 0) { 631192925Sthompsa req.wLength[0] = 2; 632192925Sthompsa buf[0] = sc->sc_led_id; 633192925Sthompsa buf[1] = sc->sc_leds; 634192925Sthompsa } else { 635192925Sthompsa req.wLength[0] = 1; 636192925Sthompsa buf[0] = sc->sc_leds; 637192925Sthompsa buf[1] = 0; 638192925Sthompsa } 639184610Salfred 640194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 641194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 642194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 643194677Sthompsa usbd_copy_in(pc, 0, buf, sizeof(buf)); 644184610Salfred 645194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 646194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, req.wLength[0]); 647194677Sthompsa usbd_xfer_set_frames(xfer, 2); 648194228Sthompsa usbd_transfer_submit(xfer); 649184610Salfred } 650184610Salfred return; 651184610Salfred 652184610Salfred default: /* Error */ 653194677Sthompsa DPRINTFN(0, "error=%s\n", usbd_errstr(error)); 654184610Salfred return; 655184610Salfred } 656184610Salfred} 657184610Salfred 658192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 659184610Salfred 660187259Sthompsa [UKBD_INTR_DT] = { 661184610Salfred .type = UE_INTERRUPT, 662184610Salfred .endpoint = UE_ADDR_ANY, 663184610Salfred .direction = UE_DIR_IN, 664190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 665190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 666190734Sthompsa .callback = &ukbd_intr_callback, 667184610Salfred }, 668184610Salfred 669187259Sthompsa [UKBD_CTRL_LED] = { 670184610Salfred .type = UE_CONTROL, 671184610Salfred .endpoint = 0x00, /* Control pipe */ 672184610Salfred .direction = UE_DIR_ANY, 673192984Sthompsa .bufsize = sizeof(struct usb_device_request) + 8, 674190734Sthompsa .callback = &ukbd_set_leds_callback, 675190734Sthompsa .timeout = 1000, /* 1 second */ 676184610Salfred }, 677184610Salfred}; 678184610Salfred 679184610Salfredstatic int 680184610Salfredukbd_probe(device_t dev) 681184610Salfred{ 682184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 683192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 684194067Sthompsa void *d_ptr; 685194067Sthompsa int error; 686194067Sthompsa uint16_t d_len; 687184610Salfred 688184610Salfred DPRINTFN(11, "\n"); 689184610Salfred 690184610Salfred if (sw == NULL) { 691184610Salfred return (ENXIO); 692184610Salfred } 693192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 694184610Salfred return (ENXIO); 695184610Salfred } 696194067Sthompsa 697194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 698194067Sthompsa return (ENXIO); 699194067Sthompsa 700194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 701194067Sthompsa (uaa->info.bInterfaceProtocol == UPROTO_BOOT_KEYBOARD)) { 702194228Sthompsa if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 703184610Salfred return (ENXIO); 704184610Salfred else 705184610Salfred return (0); 706184610Salfred } 707194067Sthompsa 708194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 709194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 710194067Sthompsa 711194067Sthompsa if (error) 712194067Sthompsa return (ENXIO); 713194067Sthompsa 714195960Salfred /* 715195960Salfred * NOTE: we currently don't support USB mouse and USB keyboard 716195960Salfred * on the same USB endpoint. 717195960Salfred */ 718194067Sthompsa if (hid_is_collection(d_ptr, d_len, 719195960Salfred HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) { 720195960Salfred /* most likely a mouse */ 721195960Salfred error = ENXIO; 722195960Salfred } else if (hid_is_collection(d_ptr, d_len, 723194067Sthompsa HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) { 724194228Sthompsa if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 725194067Sthompsa error = ENXIO; 726194067Sthompsa else 727194067Sthompsa error = 0; 728194067Sthompsa } else 729194067Sthompsa error = ENXIO; 730194067Sthompsa 731194067Sthompsa free(d_ptr, M_TEMP); 732194067Sthompsa return (error); 733184610Salfred} 734184610Salfred 735184610Salfredstatic int 736184610Salfredukbd_attach(device_t dev) 737184610Salfred{ 738184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 739192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 740184610Salfred int32_t unit = device_get_unit(dev); 741184610Salfred keyboard_t *kbd = &sc->sc_kbd; 742192925Sthompsa void *hid_ptr = NULL; 743193045Sthompsa usb_error_t err; 744192925Sthompsa uint32_t flags; 745184610Salfred uint16_t n; 746192925Sthompsa uint16_t hid_len; 747184610Salfred 748196403Sjhb mtx_assert(&Giant, MA_OWNED); 749184610Salfred 750184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 751184610Salfred 752184610Salfred kbd->kb_data = (void *)sc; 753184610Salfred 754194228Sthompsa device_set_usb_desc(dev); 755184610Salfred 756184610Salfred sc->sc_udev = uaa->device; 757184610Salfred sc->sc_iface = uaa->iface; 758184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 759184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 760184610Salfred sc->sc_mode = K_XLATE; 761184610Salfred 762194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 763184610Salfred 764194228Sthompsa err = usbd_transfer_setup(uaa->device, 765184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 766184610Salfred UKBD_N_TRANSFER, sc, &Giant); 767184610Salfred 768184610Salfred if (err) { 769194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 770184610Salfred goto detach; 771184610Salfred } 772184610Salfred /* setup default keyboard maps */ 773184610Salfred 774184610Salfred sc->sc_keymap = key_map; 775184610Salfred sc->sc_accmap = accent_map; 776184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 777184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 778184610Salfred } 779184610Salfred 780184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 781184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 782184610Salfred 783184610Salfred KBD_FOUND_DEVICE(kbd); 784184610Salfred 785184610Salfred ukbd_clear_state(kbd); 786184610Salfred 787184610Salfred /* 788184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 789184610Salfred * according to the BIOS data? 790184610Salfred */ 791184610Salfred KBD_PROBE_DONE(kbd); 792184610Salfred 793192925Sthompsa /* figure out if there is an ID byte in the data */ 794194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 795192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 796192925Sthompsa if (err == 0) { 797192925Sthompsa uint8_t temp_id; 798192925Sthompsa 799192925Sthompsa /* investigate if this is an Apple Keyboard */ 800192925Sthompsa if (hid_locate(hid_ptr, hid_len, 801192925Sthompsa HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 802192925Sthompsa hid_input, 0, &sc->sc_loc_apple_eject, &flags, 803192925Sthompsa &sc->sc_kbd_id)) { 804192925Sthompsa if (flags & HIO_VARIABLE) 805192925Sthompsa sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 806192925Sthompsa UKBD_FLAG_APPLE_SWAP; 807192925Sthompsa if (hid_locate(hid_ptr, hid_len, 808192925Sthompsa HID_USAGE2(0xFFFF, 0x0003), 809192925Sthompsa hid_input, 0, &sc->sc_loc_apple_fn, &flags, 810192925Sthompsa &temp_id)) { 811192925Sthompsa if (flags & HIO_VARIABLE) 812192925Sthompsa sc->sc_flags |= UKBD_FLAG_APPLE_FN | 813192925Sthompsa UKBD_FLAG_APPLE_SWAP; 814192925Sthompsa if (temp_id != sc->sc_kbd_id) { 815192925Sthompsa DPRINTF("HID IDs mismatch\n"); 816192925Sthompsa } 817192925Sthompsa } 818192925Sthompsa } else { 819192925Sthompsa /* 820192925Sthompsa * Assume the first HID ID contains the 821192925Sthompsa * keyboard data 822192925Sthompsa */ 823192925Sthompsa hid_report_size(hid_ptr, hid_len, 824192925Sthompsa hid_input, &sc->sc_kbd_id); 825192925Sthompsa } 826192925Sthompsa 827192925Sthompsa /* investigate if we need an ID-byte for the leds */ 828192925Sthompsa hid_report_size(hid_ptr, hid_len, hid_output, &sc->sc_led_id); 829192925Sthompsa 830192925Sthompsa free(hid_ptr, M_TEMP); 831192925Sthompsa } 832192925Sthompsa 833184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 834194228Sthompsa err = usbd_req_set_idle(sc->sc_udev, &Giant, sc->sc_iface_index, 0, 0); 835184610Salfred 836184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 837184610Salfred 838184610Salfred KBD_INIT_DONE(kbd); 839184610Salfred 840184610Salfred if (kbd_register(kbd) < 0) { 841184610Salfred goto detach; 842184610Salfred } 843184610Salfred KBD_CONFIG_DONE(kbd); 844184610Salfred 845184610Salfred ukbd_enable(kbd); 846184610Salfred 847184610Salfred#ifdef KBD_INSTALL_CDEV 848184610Salfred if (kbd_attach(kbd)) { 849184610Salfred goto detach; 850184610Salfred } 851184610Salfred#endif 852184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 853184610Salfred 854184610Salfred if (bootverbose) { 855184610Salfred genkbd_diag(kbd, bootverbose); 856184610Salfred } 857196403Sjhb /* lock keyboard mutex */ 858184610Salfred 859196403Sjhb mtx_lock(&Giant); 860196403Sjhb 861184610Salfred /* start the keyboard */ 862184610Salfred 863194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 864184610Salfred 865184610Salfred /* start the timer */ 866184610Salfred 867186454Sthompsa ukbd_timeout(sc); 868186454Sthompsa mtx_unlock(&Giant); 869184610Salfred return (0); /* success */ 870184610Salfred 871184610Salfreddetach: 872184610Salfred ukbd_detach(dev); 873184610Salfred return (ENXIO); /* error */ 874184610Salfred} 875184610Salfred 876193315Sthompsastatic int 877184610Salfredukbd_detach(device_t dev) 878184610Salfred{ 879184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 880184610Salfred int error; 881184610Salfred 882196403Sjhb mtx_assert(&Giant, MA_OWNED); 883184610Salfred 884184610Salfred DPRINTF("\n"); 885184610Salfred 886184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 887184610Salfred panic("cannot detach polled keyboard!\n"); 888184610Salfred } 889184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 890184610Salfred 891194228Sthompsa usb_callout_stop(&sc->sc_callout); 892184610Salfred 893184610Salfred ukbd_disable(&sc->sc_kbd); 894184610Salfred 895184610Salfred#ifdef KBD_INSTALL_CDEV 896184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 897184610Salfred error = kbd_detach(&sc->sc_kbd); 898184610Salfred if (error) { 899184610Salfred /* usb attach cannot return an error */ 900184610Salfred device_printf(dev, "WARNING: kbd_detach() " 901184610Salfred "returned non-zero! (ignored)\n"); 902184610Salfred } 903184610Salfred } 904184610Salfred#endif 905184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 906184610Salfred error = kbd_unregister(&sc->sc_kbd); 907184610Salfred if (error) { 908184610Salfred /* usb attach cannot return an error */ 909184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 910184610Salfred "returned non-zero! (ignored)\n"); 911184610Salfred } 912184610Salfred } 913184610Salfred sc->sc_kbd.kb_flags = 0; 914184610Salfred 915194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 916184610Salfred 917194228Sthompsa usb_callout_drain(&sc->sc_callout); 918184610Salfred 919184610Salfred DPRINTF("%s: disconnected\n", 920184610Salfred device_get_nameunit(dev)); 921184610Salfred 922184610Salfred return (0); 923184610Salfred} 924184610Salfred 925184610Salfredstatic int 926184610Salfredukbd_resume(device_t dev) 927184610Salfred{ 928184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 929184610Salfred 930196403Sjhb mtx_assert(&Giant, MA_OWNED); 931196403Sjhb 932184610Salfred ukbd_clear_state(&sc->sc_kbd); 933184610Salfred 934184610Salfred return (0); 935184610Salfred} 936184610Salfred 937184610Salfred/* early keyboard probe, not supported */ 938184610Salfredstatic int 939184610Salfredukbd_configure(int flags) 940184610Salfred{ 941184610Salfred return (0); 942184610Salfred} 943184610Salfred 944184610Salfred/* detect a keyboard, not used */ 945184610Salfredstatic int 946184610Salfredukbd__probe(int unit, void *arg, int flags) 947184610Salfred{ 948184610Salfred mtx_assert(&Giant, MA_OWNED); 949184610Salfred return (ENXIO); 950184610Salfred} 951184610Salfred 952184610Salfred/* reset and initialize the device, not used */ 953184610Salfredstatic int 954184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 955184610Salfred{ 956184610Salfred mtx_assert(&Giant, MA_OWNED); 957184610Salfred return (ENXIO); 958184610Salfred} 959184610Salfred 960184610Salfred/* test the interface to the device, not used */ 961184610Salfredstatic int 962184610Salfredukbd_test_if(keyboard_t *kbd) 963184610Salfred{ 964184610Salfred mtx_assert(&Giant, MA_OWNED); 965184610Salfred return (0); 966184610Salfred} 967184610Salfred 968184610Salfred/* finish using this keyboard, not used */ 969184610Salfredstatic int 970184610Salfredukbd_term(keyboard_t *kbd) 971184610Salfred{ 972184610Salfred mtx_assert(&Giant, MA_OWNED); 973184610Salfred return (ENXIO); 974184610Salfred} 975184610Salfred 976184610Salfred/* keyboard interrupt routine, not used */ 977184610Salfredstatic int 978184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 979184610Salfred{ 980184610Salfred mtx_assert(&Giant, MA_OWNED); 981184610Salfred return (0); 982184610Salfred} 983184610Salfred 984184610Salfred/* lock the access to the keyboard, not used */ 985184610Salfredstatic int 986184610Salfredukbd_lock(keyboard_t *kbd, int lock) 987184610Salfred{ 988184610Salfred mtx_assert(&Giant, MA_OWNED); 989184610Salfred return (1); 990184610Salfred} 991184610Salfred 992184610Salfred/* 993184610Salfred * Enable the access to the device; until this function is called, 994184610Salfred * the client cannot read from the keyboard. 995184610Salfred */ 996184610Salfredstatic int 997184610Salfredukbd_enable(keyboard_t *kbd) 998184610Salfred{ 999195960Salfred if (!mtx_owned(&Giant)) { 1000195960Salfred /* XXX cludge */ 1001195960Salfred int retval; 1002195960Salfred mtx_lock(&Giant); 1003195960Salfred retval = ukbd_enable(kbd); 1004195960Salfred mtx_unlock(&Giant); 1005195960Salfred return (retval); 1006195960Salfred } 1007184610Salfred mtx_assert(&Giant, MA_OWNED); 1008184610Salfred KBD_ACTIVATE(kbd); 1009184610Salfred return (0); 1010184610Salfred} 1011184610Salfred 1012184610Salfred/* disallow the access to the device */ 1013184610Salfredstatic int 1014184610Salfredukbd_disable(keyboard_t *kbd) 1015184610Salfred{ 1016195960Salfred if (!mtx_owned(&Giant)) { 1017195960Salfred /* XXX cludge */ 1018195960Salfred int retval; 1019195960Salfred mtx_lock(&Giant); 1020195960Salfred retval = ukbd_disable(kbd); 1021195960Salfred mtx_unlock(&Giant); 1022195960Salfred return (retval); 1023195960Salfred } 1024184610Salfred mtx_assert(&Giant, MA_OWNED); 1025184610Salfred KBD_DEACTIVATE(kbd); 1026184610Salfred return (0); 1027184610Salfred} 1028184610Salfred 1029184610Salfred/* check if data is waiting */ 1030184610Salfredstatic int 1031184610Salfredukbd_check(keyboard_t *kbd) 1032184610Salfred{ 1033184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1034184610Salfred 1035195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1036195960Salfred return (0); 1037195960Salfred 1038195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1039195960Salfred if (!mtx_owned(&Giant)) { 1040195960Salfred /* XXX cludge */ 1041195960Salfred int retval; 1042195960Salfred mtx_lock(&Giant); 1043195960Salfred retval = ukbd_check(kbd); 1044195960Salfred mtx_unlock(&Giant); 1045195960Salfred return (retval); 1046195960Salfred } 1047195960Salfred ukbd_do_poll(sc, 0); 1048195960Salfred } else { 1049195960Salfred /* XXX the keyboard layer requires Giant */ 1050195960Salfred if (!mtx_owned(&Giant)) 1051195960Salfred return (0); 1052184610Salfred } 1053184610Salfred mtx_assert(&Giant, MA_OWNED); 1054184610Salfred 1055184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1056184610Salfred if (sc->sc_buffered_char[0]) { 1057184610Salfred return (1); 1058184610Salfred } 1059184610Salfred#endif 1060184610Salfred if (sc->sc_inputs > 0) { 1061184610Salfred return (1); 1062184610Salfred } 1063184610Salfred return (0); 1064184610Salfred} 1065184610Salfred 1066184610Salfred/* check if char is waiting */ 1067184610Salfredstatic int 1068184610Salfredukbd_check_char(keyboard_t *kbd) 1069184610Salfred{ 1070184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1071184610Salfred 1072195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1073195960Salfred return (0); 1074195960Salfred 1075195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1076195960Salfred if (!mtx_owned(&Giant)) { 1077195960Salfred /* XXX cludge */ 1078195960Salfred int retval; 1079195960Salfred mtx_lock(&Giant); 1080195960Salfred retval = ukbd_check_char(kbd); 1081195960Salfred mtx_unlock(&Giant); 1082195960Salfred return (retval); 1083195960Salfred } 1084195960Salfred } else { 1085195960Salfred /* XXX the keyboard layer requires Giant */ 1086195960Salfred if (!mtx_owned(&Giant)) 1087195960Salfred return (0); 1088184610Salfred } 1089184610Salfred mtx_assert(&Giant, MA_OWNED); 1090184610Salfred 1091184610Salfred if ((sc->sc_composed_char > 0) && 1092184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1093184610Salfred return (1); 1094184610Salfred } 1095184610Salfred return (ukbd_check(kbd)); 1096184610Salfred} 1097184610Salfred 1098184610Salfred 1099184610Salfred/* read one byte from the keyboard if it's allowed */ 1100184610Salfredstatic int 1101184610Salfredukbd_read(keyboard_t *kbd, int wait) 1102184610Salfred{ 1103184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1104184610Salfred int32_t usbcode; 1105184610Salfred 1106184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1107184610Salfred uint32_t keycode; 1108184610Salfred uint32_t scancode; 1109184610Salfred 1110184610Salfred#endif 1111195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1112195960Salfred return (-1); 1113184610Salfred 1114195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1115195960Salfred if (!mtx_owned(&Giant)) { 1116195960Salfred /* XXX cludge */ 1117195960Salfred int retval; 1118195960Salfred mtx_lock(&Giant); 1119195960Salfred retval = ukbd_read(kbd, wait); 1120195960Salfred mtx_unlock(&Giant); 1121195960Salfred return (retval); 1122195960Salfred } 1123195960Salfred } else { 1124195960Salfred /* XXX the keyboard layer requires Giant */ 1125195960Salfred if (!mtx_owned(&Giant)) 1126195960Salfred return (-1); 1127184610Salfred } 1128184610Salfred mtx_assert(&Giant, MA_OWNED); 1129184610Salfred 1130184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1131184610Salfred if (sc->sc_buffered_char[0]) { 1132184610Salfred scancode = sc->sc_buffered_char[0]; 1133184610Salfred if (scancode & SCAN_PREFIX) { 1134184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1135184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1136184610Salfred } 1137184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1138184610Salfred sc->sc_buffered_char[1] = 0; 1139184610Salfred return (scancode); 1140184610Salfred } 1141184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1142184610Salfred 1143184610Salfred /* XXX */ 1144184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1145195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1146195960Salfred return (-1); 1147195960Salfred 1148184610Salfred ++(kbd->kb_count); 1149184610Salfred 1150184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1151184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1152184610Salfred if (keycode == NN) { 1153184610Salfred return -1; 1154184610Salfred } 1155184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1156184610Salfred (usbcode & KEY_RELEASE))); 1157184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1158184610Salfred return (usbcode); 1159184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1160184610Salfred} 1161184610Salfred 1162184610Salfred/* read char from the keyboard */ 1163184610Salfredstatic uint32_t 1164184610Salfredukbd_read_char(keyboard_t *kbd, int wait) 1165184610Salfred{ 1166184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1167184610Salfred uint32_t action; 1168184610Salfred uint32_t keycode; 1169184610Salfred int32_t usbcode; 1170184610Salfred 1171184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1172184610Salfred uint32_t scancode; 1173184610Salfred 1174184610Salfred#endif 1175195960Salfred 1176195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1177195960Salfred return (NOKEY); 1178195960Salfred 1179195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1180195960Salfred if (!mtx_owned(&Giant)) { 1181195960Salfred /* XXX cludge */ 1182195960Salfred int retval; 1183195960Salfred mtx_lock(&Giant); 1184195960Salfred retval = ukbd_read_char(kbd, wait); 1185195960Salfred mtx_unlock(&Giant); 1186195960Salfred return (retval); 1187195960Salfred } 1188195960Salfred } else { 1189195960Salfred /* XXX the keyboard layer requires Giant */ 1190195960Salfred if (!mtx_owned(&Giant)) 1191195960Salfred return (NOKEY); 1192184610Salfred } 1193184610Salfred mtx_assert(&Giant, MA_OWNED); 1194184610Salfred 1195184610Salfrednext_code: 1196184610Salfred 1197184610Salfred /* do we have a composed char to return ? */ 1198184610Salfred 1199184610Salfred if ((sc->sc_composed_char > 0) && 1200184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1201184610Salfred 1202184610Salfred action = sc->sc_composed_char; 1203184610Salfred sc->sc_composed_char = 0; 1204184610Salfred 1205184610Salfred if (action > 0xFF) { 1206184610Salfred goto errkey; 1207184610Salfred } 1208184610Salfred goto done; 1209184610Salfred } 1210184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1211184610Salfred 1212184610Salfred /* do we have a pending raw scan code? */ 1213184610Salfred 1214184610Salfred if (sc->sc_mode == K_RAW) { 1215184610Salfred scancode = sc->sc_buffered_char[0]; 1216184610Salfred if (scancode) { 1217184610Salfred if (scancode & SCAN_PREFIX) { 1218184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1219184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1220184610Salfred } 1221184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1222184610Salfred sc->sc_buffered_char[1] = 0; 1223184610Salfred return (scancode); 1224184610Salfred } 1225184610Salfred } 1226184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1227184610Salfred 1228184610Salfred /* see if there is something in the keyboard port */ 1229184610Salfred /* XXX */ 1230184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1231184610Salfred if (usbcode == -1) { 1232184610Salfred return (NOKEY); 1233184610Salfred } 1234184610Salfred ++kbd->kb_count; 1235184610Salfred 1236184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1237184610Salfred /* USB key index -> key code -> AT scan code */ 1238184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1239184610Salfred if (keycode == NN) { 1240184610Salfred return (NOKEY); 1241184610Salfred } 1242184610Salfred /* return an AT scan code for the K_RAW mode */ 1243184610Salfred if (sc->sc_mode == K_RAW) { 1244184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1245184610Salfred (usbcode & KEY_RELEASE))); 1246184610Salfred } 1247184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1248184610Salfred 1249184610Salfred /* return the byte as is for the K_RAW mode */ 1250184610Salfred if (sc->sc_mode == K_RAW) { 1251184610Salfred return (usbcode); 1252184610Salfred } 1253184610Salfred /* USB key index -> key code */ 1254184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1255184610Salfred if (keycode == NN) { 1256184610Salfred return (NOKEY); 1257184610Salfred } 1258184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1259184610Salfred 1260184610Salfred switch (keycode) { 1261184610Salfred case 0x38: /* left alt (compose key) */ 1262184610Salfred if (usbcode & KEY_RELEASE) { 1263184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1264184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1265184610Salfred 1266184610Salfred if (sc->sc_composed_char > 0xFF) { 1267184610Salfred sc->sc_composed_char = 0; 1268184610Salfred } 1269184610Salfred } 1270184610Salfred } else { 1271184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1272184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1273184610Salfred sc->sc_composed_char = 0; 1274184610Salfred } 1275184610Salfred } 1276184610Salfred break; 1277184610Salfred /* XXX: I don't like these... */ 1278184610Salfred case 0x5c: /* print screen */ 1279184610Salfred if (sc->sc_flags & ALTS) { 1280184610Salfred keycode = 0x54; /* sysrq */ 1281184610Salfred } 1282184610Salfred break; 1283184610Salfred case 0x68: /* pause/break */ 1284184610Salfred if (sc->sc_flags & CTLS) { 1285184610Salfred keycode = 0x6c; /* break */ 1286184610Salfred } 1287184610Salfred break; 1288184610Salfred } 1289184610Salfred 1290184610Salfred /* return the key code in the K_CODE mode */ 1291184610Salfred if (usbcode & KEY_RELEASE) { 1292184610Salfred keycode |= SCAN_RELEASE; 1293184610Salfred } 1294184610Salfred if (sc->sc_mode == K_CODE) { 1295184610Salfred return (keycode); 1296184610Salfred } 1297184610Salfred /* compose a character code */ 1298184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1299184610Salfred switch (keycode) { 1300184610Salfred /* key pressed, process it */ 1301184610Salfred case 0x47: 1302184610Salfred case 0x48: 1303184610Salfred case 0x49: /* keypad 7,8,9 */ 1304184610Salfred sc->sc_composed_char *= 10; 1305184610Salfred sc->sc_composed_char += keycode - 0x40; 1306184610Salfred goto check_composed; 1307184610Salfred 1308184610Salfred case 0x4B: 1309184610Salfred case 0x4C: 1310184610Salfred case 0x4D: /* keypad 4,5,6 */ 1311184610Salfred sc->sc_composed_char *= 10; 1312184610Salfred sc->sc_composed_char += keycode - 0x47; 1313184610Salfred goto check_composed; 1314184610Salfred 1315184610Salfred case 0x4F: 1316184610Salfred case 0x50: 1317184610Salfred case 0x51: /* keypad 1,2,3 */ 1318184610Salfred sc->sc_composed_char *= 10; 1319184610Salfred sc->sc_composed_char += keycode - 0x4E; 1320184610Salfred goto check_composed; 1321184610Salfred 1322184610Salfred case 0x52: /* keypad 0 */ 1323184610Salfred sc->sc_composed_char *= 10; 1324184610Salfred goto check_composed; 1325184610Salfred 1326184610Salfred /* key released, no interest here */ 1327184610Salfred case SCAN_RELEASE | 0x47: 1328184610Salfred case SCAN_RELEASE | 0x48: 1329184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1330184610Salfred case SCAN_RELEASE | 0x4B: 1331184610Salfred case SCAN_RELEASE | 0x4C: 1332184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1333184610Salfred case SCAN_RELEASE | 0x4F: 1334184610Salfred case SCAN_RELEASE | 0x50: 1335184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1336184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1337184610Salfred goto next_code; 1338184610Salfred 1339184610Salfred case 0x38: /* left alt key */ 1340184610Salfred break; 1341184610Salfred 1342184610Salfred default: 1343184610Salfred if (sc->sc_composed_char > 0) { 1344184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1345184610Salfred sc->sc_composed_char = 0; 1346184610Salfred goto errkey; 1347184610Salfred } 1348184610Salfred break; 1349184610Salfred } 1350184610Salfred } 1351184610Salfred /* keycode to key action */ 1352184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1353184610Salfred (keycode & SCAN_RELEASE), 1354184610Salfred &sc->sc_state, &sc->sc_accents); 1355184610Salfred if (action == NOKEY) { 1356184610Salfred goto next_code; 1357184610Salfred } 1358184610Salfreddone: 1359184610Salfred return (action); 1360184610Salfred 1361184610Salfredcheck_composed: 1362184610Salfred if (sc->sc_composed_char <= 0xFF) { 1363184610Salfred goto next_code; 1364184610Salfred } 1365184610Salfrederrkey: 1366184610Salfred return (ERRKEY); 1367184610Salfred} 1368184610Salfred 1369184610Salfred/* some useful control functions */ 1370184610Salfredstatic int 1371184610Salfredukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1372184610Salfred{ 1373184610Salfred /* translate LED_XXX bits into the device specific bits */ 1374184610Salfred static const uint8_t ledmap[8] = { 1375184610Salfred 0, 2, 1, 3, 4, 6, 5, 7, 1376184610Salfred }; 1377184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1378184610Salfred int i; 1379184610Salfred 1380184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1381184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1382184610Salfred int ival; 1383184610Salfred 1384184610Salfred#endif 1385184610Salfred if (!mtx_owned(&Giant)) { 1386184610Salfred /* 1387184610Salfred * XXX big problem: If scroll lock is pressed and "printf()" 1388184610Salfred * is called, the CPU will get here, to un-scroll lock the 1389184610Salfred * keyboard. But if "printf()" acquires the "Giant" lock, 1390184610Salfred * there will be a locking order reversal problem, so the 1391184610Salfred * keyboard system must get out of "Giant" first, before the 1392184610Salfred * CPU can proceed here ... 1393184610Salfred */ 1394184610Salfred return (EINVAL); 1395184610Salfred } 1396184610Salfred mtx_assert(&Giant, MA_OWNED); 1397184610Salfred 1398184610Salfred switch (cmd) { 1399184610Salfred case KDGKBMODE: /* get keyboard mode */ 1400184610Salfred *(int *)arg = sc->sc_mode; 1401184610Salfred break; 1402184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1403184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1404184610Salfred case _IO('K', 7): 1405184610Salfred ival = IOCPARM_IVAL(arg); 1406184610Salfred arg = (caddr_t)&ival; 1407184610Salfred /* FALLTHROUGH */ 1408184610Salfred#endif 1409184610Salfred case KDSKBMODE: /* set keyboard mode */ 1410184610Salfred switch (*(int *)arg) { 1411184610Salfred case K_XLATE: 1412184610Salfred if (sc->sc_mode != K_XLATE) { 1413184610Salfred /* make lock key state and LED state match */ 1414184610Salfred sc->sc_state &= ~LOCK_MASK; 1415184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1416184610Salfred } 1417184610Salfred /* FALLTHROUGH */ 1418184610Salfred case K_RAW: 1419184610Salfred case K_CODE: 1420184610Salfred if (sc->sc_mode != *(int *)arg) { 1421184610Salfred ukbd_clear_state(kbd); 1422184610Salfred sc->sc_mode = *(int *)arg; 1423184610Salfred } 1424184610Salfred break; 1425184610Salfred default: 1426184610Salfred return (EINVAL); 1427184610Salfred } 1428184610Salfred break; 1429184610Salfred 1430184610Salfred case KDGETLED: /* get keyboard LED */ 1431184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1432184610Salfred break; 1433184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1434184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1435184610Salfred case _IO('K', 66): 1436184610Salfred ival = IOCPARM_IVAL(arg); 1437184610Salfred arg = (caddr_t)&ival; 1438184610Salfred /* FALLTHROUGH */ 1439184610Salfred#endif 1440184610Salfred case KDSETLED: /* set keyboard LED */ 1441184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1442184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1443184610Salfred return (EINVAL); 1444184610Salfred } 1445184610Salfred i = *(int *)arg; 1446184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1447184610Salfred if (sc->sc_mode == K_XLATE && 1448184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1449184610Salfred if (i & ALKED) 1450184610Salfred i |= CLKED; 1451184610Salfred else 1452184610Salfred i &= ~CLKED; 1453184610Salfred } 1454184610Salfred if (KBD_HAS_DEVICE(kbd)) { 1455184610Salfred ukbd_set_leds(sc, ledmap[i & LED_MASK]); 1456184610Salfred } 1457184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1458184610Salfred break; 1459184610Salfred case KDGKBSTATE: /* get lock key state */ 1460184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1461184610Salfred break; 1462184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1463184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1464184610Salfred case _IO('K', 20): 1465184610Salfred ival = IOCPARM_IVAL(arg); 1466184610Salfred arg = (caddr_t)&ival; 1467184610Salfred /* FALLTHROUGH */ 1468184610Salfred#endif 1469184610Salfred case KDSKBSTATE: /* set lock key state */ 1470184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1471184610Salfred return (EINVAL); 1472184610Salfred } 1473184610Salfred sc->sc_state &= ~LOCK_MASK; 1474184610Salfred sc->sc_state |= *(int *)arg; 1475184610Salfred 1476184610Salfred /* set LEDs and quit */ 1477184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1478184610Salfred 1479184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1480184610Salfred * interface) */ 1481184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1482184610Salfred return (0); 1483184610Salfred } 1484184610Salfred if (((int *)arg)[1] < 0) { 1485184610Salfred return (EINVAL); 1486184610Salfred } 1487184610Salfred if (((int *)arg)[0] < 0) { 1488184610Salfred return (EINVAL); 1489184610Salfred } 1490184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1491184610Salfred kbd->kb_delay1 = 200; 1492184610Salfred else 1493184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1494184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1495184610Salfred return (0); 1496184610Salfred 1497184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1498184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1499184610Salfred case _IO('K', 67): 1500184610Salfred ival = IOCPARM_IVAL(arg); 1501184610Salfred arg = (caddr_t)&ival; 1502184610Salfred /* FALLTHROUGH */ 1503184610Salfred#endif 1504184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1505184610Salfred * interface) */ 1506184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1507184610Salfred 1508184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1509184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1510184610Salfred * entry */ 1511184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1512184610Salfred sc->sc_accents = 0; 1513184610Salfred /* FALLTHROUGH */ 1514184610Salfred default: 1515184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1516184610Salfred } 1517184610Salfred 1518184610Salfred return (0); 1519184610Salfred} 1520184610Salfred 1521184610Salfred/* clear the internal state of the keyboard */ 1522184610Salfredstatic void 1523184610Salfredukbd_clear_state(keyboard_t *kbd) 1524184610Salfred{ 1525184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1526184610Salfred 1527184610Salfred if (!mtx_owned(&Giant)) { 1528184610Salfred return; /* XXX */ 1529184610Salfred } 1530184610Salfred mtx_assert(&Giant, MA_OWNED); 1531184610Salfred 1532184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 1533184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 1534184610Salfred sc->sc_accents = 0; 1535184610Salfred sc->sc_composed_char = 0; 1536184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1537184610Salfred sc->sc_buffered_char[0] = 0; 1538184610Salfred sc->sc_buffered_char[1] = 0; 1539184610Salfred#endif 1540184610Salfred bzero(&sc->sc_ndata, sizeof(sc->sc_ndata)); 1541184610Salfred bzero(&sc->sc_odata, sizeof(sc->sc_odata)); 1542184610Salfred bzero(&sc->sc_ntime, sizeof(sc->sc_ntime)); 1543184610Salfred bzero(&sc->sc_otime, sizeof(sc->sc_otime)); 1544184610Salfred} 1545184610Salfred 1546184610Salfred/* save the internal state, not used */ 1547184610Salfredstatic int 1548184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1549184610Salfred{ 1550184610Salfred mtx_assert(&Giant, MA_OWNED); 1551184610Salfred return (len == 0) ? 1 : -1; 1552184610Salfred} 1553184610Salfred 1554184610Salfred/* set the internal state, not used */ 1555184610Salfredstatic int 1556184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1557184610Salfred{ 1558184610Salfred mtx_assert(&Giant, MA_OWNED); 1559184610Salfred return (EINVAL); 1560184610Salfred} 1561184610Salfred 1562184610Salfredstatic int 1563184610Salfredukbd_poll(keyboard_t *kbd, int on) 1564184610Salfred{ 1565184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1566184610Salfred 1567184610Salfred if (!mtx_owned(&Giant)) { 1568195960Salfred /* XXX cludge */ 1569195960Salfred int retval; 1570195960Salfred mtx_lock(&Giant); 1571195960Salfred retval = ukbd_poll(kbd, on); 1572195960Salfred mtx_unlock(&Giant); 1573195960Salfred return (retval); 1574184610Salfred } 1575184610Salfred mtx_assert(&Giant, MA_OWNED); 1576184610Salfred 1577184610Salfred if (on) { 1578184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 1579184610Salfred } else { 1580184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 1581184610Salfred } 1582184610Salfred return (0); 1583184610Salfred} 1584184610Salfred 1585184610Salfred/* local functions */ 1586184610Salfred 1587184610Salfredstatic void 1588184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 1589184610Salfred{ 1590184610Salfred DPRINTF("leds=0x%02x\n", leds); 1591184610Salfred 1592184610Salfred sc->sc_leds = leds; 1593184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 1594184610Salfred 1595184610Salfred /* start transfer, if not already started */ 1596184610Salfred 1597194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 1598184610Salfred} 1599184610Salfred 1600184610Salfredstatic int 1601184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 1602184610Salfred{ 1603184610Salfred static const int delays[] = {250, 500, 750, 1000}; 1604184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 1605184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 1606184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 1607184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 1608184610Salfred 1609184610Salfred if (code & ~0x7f) { 1610184610Salfred return (EINVAL); 1611184610Salfred } 1612184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 1613184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 1614184610Salfred return (0); 1615184610Salfred} 1616184610Salfred 1617184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1618184610Salfredstatic int 1619184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 1620184610Salfred{ 1621184610Salfred static const int scan[] = { 1622184610Salfred 0x1c, 0x1d, 0x35, 1623184610Salfred 0x37 | SCAN_PREFIX_SHIFT, /* PrintScreen */ 1624184610Salfred 0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f, 1625184610Salfred 0x50, 0x51, 0x52, 0x53, 1626184610Salfred 0x46, /* XXX Pause/Break */ 1627184610Salfred 0x5b, 0x5c, 0x5d, 1628184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 1629184610Salfred 0x68, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 1630184610Salfred 0x64, 0x65, 0x66, 0x67, 0x25, 0x1f, 0x1e, 1631184610Salfred 0x20, 1632184610Salfred }; 1633184610Salfred 1634184610Salfred if ((code >= 89) && (code < (89 + (sizeof(scan) / sizeof(scan[0]))))) { 1635184610Salfred code = scan[code - 89] | SCAN_PREFIX_E0; 1636184610Salfred } 1637184610Salfred /* Pause/Break */ 1638184610Salfred if ((code == 104) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 1639184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 1640184610Salfred } 1641184610Salfred if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) { 1642184610Salfred code &= ~SCAN_PREFIX_SHIFT; 1643184610Salfred } 1644184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 1645184610Salfred 1646184610Salfred if (code & SCAN_PREFIX) { 1647184610Salfred if (code & SCAN_PREFIX_CTL) { 1648184610Salfred /* Ctrl */ 1649184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 1650184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 1651184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 1652184610Salfred /* Shift */ 1653184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 1654184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 1655184610Salfred } else { 1656184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 1657184610Salfred sc->sc_buffered_char[1] = 0; 1658184610Salfred } 1659184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1660184610Salfred } 1661184610Salfred return (code); 1662184610Salfred 1663184610Salfred} 1664184610Salfred 1665184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1666184610Salfred 1667194099Sthompsastatic keyboard_switch_t ukbdsw = { 1668184610Salfred .probe = &ukbd__probe, 1669184610Salfred .init = &ukbd_init, 1670184610Salfred .term = &ukbd_term, 1671184610Salfred .intr = &ukbd_intr, 1672184610Salfred .test_if = &ukbd_test_if, 1673184610Salfred .enable = &ukbd_enable, 1674184610Salfred .disable = &ukbd_disable, 1675184610Salfred .read = &ukbd_read, 1676184610Salfred .check = &ukbd_check, 1677184610Salfred .read_char = &ukbd_read_char, 1678184610Salfred .check_char = &ukbd_check_char, 1679184610Salfred .ioctl = &ukbd_ioctl, 1680184610Salfred .lock = &ukbd_lock, 1681184610Salfred .clear_state = &ukbd_clear_state, 1682184610Salfred .get_state = &ukbd_get_state, 1683184610Salfred .set_state = &ukbd_set_state, 1684184610Salfred .get_fkeystr = &genkbd_get_fkeystr, 1685184610Salfred .poll = &ukbd_poll, 1686184610Salfred .diag = &genkbd_diag, 1687184610Salfred}; 1688184610Salfred 1689184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 1690184610Salfred 1691184610Salfredstatic int 1692184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 1693184610Salfred{ 1694184610Salfred switch (what) { 1695193315Sthompsa case MOD_LOAD: 1696184610Salfred kbd_add_driver(&ukbd_kbd_driver); 1697184610Salfred break; 1698184610Salfred case MOD_UNLOAD: 1699184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 1700184610Salfred break; 1701184610Salfred } 1702184610Salfred return (0); 1703184610Salfred} 1704184610Salfred 1705184610Salfredstatic devclass_t ukbd_devclass; 1706184610Salfred 1707184610Salfredstatic device_method_t ukbd_methods[] = { 1708184610Salfred DEVMETHOD(device_probe, ukbd_probe), 1709184610Salfred DEVMETHOD(device_attach, ukbd_attach), 1710184610Salfred DEVMETHOD(device_detach, ukbd_detach), 1711184610Salfred DEVMETHOD(device_resume, ukbd_resume), 1712184610Salfred {0, 0} 1713184610Salfred}; 1714184610Salfred 1715184610Salfredstatic driver_t ukbd_driver = { 1716184610Salfred .name = "ukbd", 1717184610Salfred .methods = ukbd_methods, 1718184610Salfred .size = sizeof(struct ukbd_softc), 1719184610Salfred}; 1720184610Salfred 1721189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 1722188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 1723