ukbd.c revision 197999
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/input/ukbd.c 197999 2009-10-12 19:19:08Z hrs $"); 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; 99196489Salfredstatic int ukbd_no_leds = 0; 100184610Salfred 101192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); 102192502SthompsaSYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW, 103184610Salfred &ukbd_debug, 0, "Debug level"); 104196489SalfredSYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RW, 105196489Salfred &ukbd_no_leds, 0, "Disables setting of keyboard leds"); 106196489Salfred 107184610Salfred#endif 108184610Salfred 109184610Salfred#define UPROTO_BOOT_KEYBOARD 1 110184610Salfred 111184610Salfred#define UKBD_EMULATE_ATSCANCODE 1 112184610Salfred#define UKBD_DRIVER_NAME "ukbd" 113184610Salfred#define UKBD_NMOD 8 /* units */ 114184610Salfred#define UKBD_NKEYCODE 6 /* units */ 115184610Salfred#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */ 116184610Salfred#define UKBD_IN_BUF_FULL (UKBD_IN_BUF_SIZE / 2) /* bytes */ 117184610Salfred#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */ 118184610Salfred 119184610Salfredstruct ukbd_data { 120184610Salfred uint8_t modifiers; 121184610Salfred#define MOD_CONTROL_L 0x01 122184610Salfred#define MOD_CONTROL_R 0x10 123184610Salfred#define MOD_SHIFT_L 0x02 124184610Salfred#define MOD_SHIFT_R 0x20 125184610Salfred#define MOD_ALT_L 0x04 126184610Salfred#define MOD_ALT_R 0x40 127184610Salfred#define MOD_WIN_L 0x08 128184610Salfred#define MOD_WIN_R 0x80 129184610Salfred uint8_t reserved; 130184610Salfred uint8_t keycode[UKBD_NKEYCODE]; 131192925Sthompsa uint8_t exten[8]; 132192925Sthompsa}; 133184610Salfred 134187259Sthompsaenum { 135187259Sthompsa UKBD_INTR_DT, 136187259Sthompsa UKBD_CTRL_LED, 137192925Sthompsa UKBD_N_TRANSFER, 138187259Sthompsa}; 139187259Sthompsa 140184610Salfredstruct ukbd_softc { 141184610Salfred keyboard_t sc_kbd; 142184610Salfred keymap_t sc_keymap; 143184610Salfred accentmap_t sc_accmap; 144184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 145192925Sthompsa struct hid_location sc_loc_apple_eject; 146192925Sthompsa struct hid_location sc_loc_apple_fn; 147192984Sthompsa struct usb_callout sc_callout; 148184610Salfred struct ukbd_data sc_ndata; 149184610Salfred struct ukbd_data sc_odata; 150184610Salfred 151192984Sthompsa struct usb_device *sc_udev; 152192984Sthompsa struct usb_interface *sc_iface; 153192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 154184610Salfred 155184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 156184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 157184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 158184610Salfred uint32_t sc_time_ms; 159184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 160184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 161184610Salfred uint32_t sc_buffered_char[2]; 162184610Salfred#endif 163184610Salfred uint32_t sc_flags; /* flags */ 164192925Sthompsa#define UKBD_FLAG_COMPOSE 0x0001 165192925Sthompsa#define UKBD_FLAG_POLLING 0x0002 166192925Sthompsa#define UKBD_FLAG_SET_LEDS 0x0004 167192925Sthompsa#define UKBD_FLAG_ATTACHED 0x0010 168192925Sthompsa#define UKBD_FLAG_GONE 0x0020 169192925Sthompsa#define UKBD_FLAG_APPLE_EJECT 0x0040 170192925Sthompsa#define UKBD_FLAG_APPLE_FN 0x0080 171192925Sthompsa#define UKBD_FLAG_APPLE_SWAP 0x0100 172196489Salfred#define UKBD_FLAG_TIMER_RUNNING 0x0200 173184610Salfred 174184610Salfred int32_t sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 175184610Salfred int32_t sc_state; /* shift/lock key state */ 176184610Salfred int32_t sc_accents; /* accent key index (> 0) */ 177184610Salfred 178184610Salfred uint16_t sc_inputs; 179184610Salfred uint16_t sc_inputhead; 180184610Salfred uint16_t sc_inputtail; 181184610Salfred 182184610Salfred uint8_t sc_leds; /* store for async led requests */ 183184610Salfred uint8_t sc_iface_index; 184184610Salfred uint8_t sc_iface_no; 185192925Sthompsa uint8_t sc_kbd_id; 186192925Sthompsa uint8_t sc_led_id; 187184610Salfred}; 188184610Salfred 189184610Salfred#define KEY_ERROR 0x01 190184610Salfred 191184610Salfred#define KEY_PRESS 0 192184610Salfred#define KEY_RELEASE 0x400 193184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 194184610Salfred 195184610Salfred#define SCAN_PRESS 0 196184610Salfred#define SCAN_RELEASE 0x80 197184610Salfred#define SCAN_PREFIX_E0 0x100 198184610Salfred#define SCAN_PREFIX_E1 0x200 199184610Salfred#define SCAN_PREFIX_CTL 0x400 200184610Salfred#define SCAN_PREFIX_SHIFT 0x800 201184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 202184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 203184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 204184610Salfred 205184610Salfredstruct ukbd_mods { 206184610Salfred uint32_t mask, key; 207184610Salfred}; 208184610Salfred 209184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 210184610Salfred {MOD_CONTROL_L, 0xe0}, 211184610Salfred {MOD_CONTROL_R, 0xe4}, 212184610Salfred {MOD_SHIFT_L, 0xe1}, 213184610Salfred {MOD_SHIFT_R, 0xe5}, 214184610Salfred {MOD_ALT_L, 0xe2}, 215184610Salfred {MOD_ALT_R, 0xe6}, 216184610Salfred {MOD_WIN_L, 0xe3}, 217184610Salfred {MOD_WIN_R, 0xe7}, 218184610Salfred}; 219184610Salfred 220184610Salfred#define NN 0 /* no translation */ 221184610Salfred/* 222184610Salfred * Translate USB keycodes to AT keyboard scancodes. 223184610Salfred */ 224184610Salfred/* 225184610Salfred * FIXME: Mac USB keyboard generates: 226184610Salfred * 0x53: keypad NumLock/Clear 227184610Salfred * 0x66: Power 228184610Salfred * 0x67: keypad = 229184610Salfred * 0x68: F13 230184610Salfred * 0x69: F14 231184610Salfred * 0x6a: F15 232184610Salfred */ 233184610Salfredstatic const uint8_t ukbd_trtab[256] = { 234184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 235184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 236184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 237184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 238184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 239184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 240184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 241184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 242184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 243184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 244184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 245184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 246184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 247184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 248184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 249184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 250197999Shrs 121, 120, NN, NN, NN, NN, NN, 123, /* 80 - 87 */ 251197999Shrs 124, 125, 126, 127, 128, NN, NN, NN, /* 88 - 8F */ 252184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 253184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 254184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 255184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 256184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 257184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 258184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 259184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 260184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 261184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 262184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 263184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 264184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 265184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 266184610Salfred}; 267184610Salfred 268184610Salfred/* prototypes */ 269185948Sthompsastatic void ukbd_timeout(void *); 270185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 271185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 272184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 273185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 274184610Salfred#endif 275185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 276185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 277185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 278185948Sthompsastatic int ukbd_enable(keyboard_t *); 279185948Sthompsastatic int ukbd_disable(keyboard_t *); 280185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 281184610Salfred 282184610Salfredstatic device_probe_t ukbd_probe; 283184610Salfredstatic device_attach_t ukbd_attach; 284184610Salfredstatic device_detach_t ukbd_detach; 285184610Salfredstatic device_resume_t ukbd_resume; 286184610Salfred 287196489Salfredstatic uint8_t 288196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc) 289196489Salfred{ 290196489Salfred uint8_t i; 291196489Salfred uint8_t j; 292196489Salfred 293196489Salfred for (j = i = 0; i < UKBD_NKEYCODE; i++) 294196489Salfred j |= sc->sc_odata.keycode[i]; 295196489Salfred 296196489Salfred return (j ? 1 : 0); 297196489Salfred} 298196489Salfred 299184610Salfredstatic void 300196489Salfredukbd_start_timer(struct ukbd_softc *sc) 301196489Salfred{ 302196489Salfred sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; 303196489Salfred usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 304196489Salfred} 305196489Salfred 306196489Salfredstatic void 307184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 308184610Salfred{ 309184610Salfred mtx_assert(&Giant, MA_OWNED); 310184610Salfred 311184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 312184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 313184610Salfred 314184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 315184610Salfred sc->sc_input[sc->sc_inputtail] = key; 316184610Salfred ++(sc->sc_inputs); 317184610Salfred ++(sc->sc_inputtail); 318184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 319184610Salfred sc->sc_inputtail = 0; 320184610Salfred } 321184610Salfred } else { 322184610Salfred DPRINTF("input buffer is full\n"); 323184610Salfred } 324184610Salfred} 325184610Salfred 326195960Salfredstatic void 327195960Salfredukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 328195960Salfred{ 329195960Salfred DPRINTFN(2, "polling\n"); 330195960Salfred 331195960Salfred while (sc->sc_inputs == 0) { 332195960Salfred 333195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 334195960Salfred 335196489Salfred /* Delay-optimised support for repetition of keys */ 336195960Salfred 337196489Salfred if (ukbd_any_key_pressed(sc)) { 338196489Salfred /* a key is pressed - need timekeeping */ 339196489Salfred DELAY(1000); 340195960Salfred 341196489Salfred /* 1 millisecond has passed */ 342196489Salfred sc->sc_time_ms += 1; 343196489Salfred } 344195960Salfred 345195960Salfred ukbd_interrupt(sc); 346195960Salfred 347195960Salfred if (!wait) 348195960Salfred break; 349195960Salfred } 350195960Salfred} 351195960Salfred 352184610Salfredstatic int32_t 353184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 354184610Salfred{ 355184610Salfred int32_t c; 356184610Salfred 357184610Salfred mtx_assert(&Giant, MA_OWNED); 358184610Salfred 359184610Salfred if (sc->sc_inputs == 0) { 360184610Salfred /* start transfer, if not already started */ 361194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 362184610Salfred } 363184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 364195960Salfred ukbd_do_poll(sc, wait); 365184610Salfred } 366184610Salfred if (sc->sc_inputs == 0) { 367184610Salfred c = -1; 368184610Salfred } else { 369184610Salfred c = sc->sc_input[sc->sc_inputhead]; 370184610Salfred --(sc->sc_inputs); 371184610Salfred ++(sc->sc_inputhead); 372184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 373184610Salfred sc->sc_inputhead = 0; 374184610Salfred } 375184610Salfred } 376184610Salfred return (c); 377184610Salfred} 378184610Salfred 379184610Salfredstatic void 380184610Salfredukbd_interrupt(struct ukbd_softc *sc) 381184610Salfred{ 382184610Salfred uint32_t n_mod; 383184610Salfred uint32_t o_mod; 384184610Salfred uint32_t now = sc->sc_time_ms; 385184610Salfred uint32_t dtime; 386184610Salfred uint32_t c; 387184610Salfred uint8_t key; 388184610Salfred uint8_t i; 389184610Salfred uint8_t j; 390184610Salfred 391184610Salfred if (sc->sc_ndata.keycode[0] == KEY_ERROR) { 392184610Salfred goto done; 393184610Salfred } 394184610Salfred n_mod = sc->sc_ndata.modifiers; 395184610Salfred o_mod = sc->sc_odata.modifiers; 396184610Salfred if (n_mod != o_mod) { 397184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 398184610Salfred if ((n_mod & ukbd_mods[i].mask) != 399184610Salfred (o_mod & ukbd_mods[i].mask)) { 400184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 401184610Salfred ((n_mod & ukbd_mods[i].mask) ? 402184610Salfred KEY_PRESS : KEY_RELEASE)); 403184610Salfred } 404184610Salfred } 405184610Salfred } 406184610Salfred /* Check for released keys. */ 407184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 408184610Salfred key = sc->sc_odata.keycode[i]; 409184610Salfred if (key == 0) { 410184610Salfred continue; 411184610Salfred } 412184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 413184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 414184610Salfred continue; 415184610Salfred } 416184610Salfred if (key == sc->sc_ndata.keycode[j]) { 417184610Salfred goto rfound; 418184610Salfred } 419184610Salfred } 420184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 421184610Salfredrfound: ; 422184610Salfred } 423184610Salfred 424184610Salfred /* Check for pressed keys. */ 425184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 426184610Salfred key = sc->sc_ndata.keycode[i]; 427184610Salfred if (key == 0) { 428184610Salfred continue; 429184610Salfred } 430184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 431184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 432184610Salfred if (sc->sc_odata.keycode[j] == 0) { 433184610Salfred continue; 434184610Salfred } 435184610Salfred if (key == sc->sc_odata.keycode[j]) { 436184610Salfred 437184610Salfred /* key is still pressed */ 438184610Salfred 439184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 440184610Salfred dtime = (sc->sc_otime[j] - now); 441184610Salfred 442184610Salfred if (!(dtime & 0x80000000)) { 443184610Salfred /* time has not elapsed */ 444184610Salfred goto pfound; 445184610Salfred } 446184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 447184610Salfred break; 448184610Salfred } 449184610Salfred } 450184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 451184610Salfred 452184610Salfred /* 453184610Salfred * If any other key is presently down, force its repeat to be 454184610Salfred * well in the future (100s). This makes the last key to be 455184610Salfred * pressed do the autorepeat. 456184610Salfred */ 457184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 458184610Salfred if (j != i) 459184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 460184610Salfred } 461184610Salfredpfound: ; 462184610Salfred } 463184610Salfred 464184610Salfred sc->sc_odata = sc->sc_ndata; 465184610Salfred 466184610Salfred bcopy(sc->sc_ntime, sc->sc_otime, sizeof(sc->sc_otime)); 467184610Salfred 468184610Salfred if (sc->sc_inputs == 0) { 469184610Salfred goto done; 470184610Salfred } 471184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 472184610Salfred goto done; 473184610Salfred } 474184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 475184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 476184610Salfred /* let the callback function process the input */ 477184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 478184610Salfred sc->sc_kbd.kb_callback.kc_arg); 479184610Salfred } else { 480184610Salfred /* read and discard the input, no one is waiting for it */ 481184610Salfred do { 482184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 483184610Salfred } while (c != NOKEY); 484184610Salfred } 485184610Salfreddone: 486184610Salfred return; 487184610Salfred} 488184610Salfred 489184610Salfredstatic void 490184610Salfredukbd_timeout(void *arg) 491184610Salfred{ 492184610Salfred struct ukbd_softc *sc = arg; 493184610Salfred 494184610Salfred mtx_assert(&Giant, MA_OWNED); 495184610Salfred 496184610Salfred if (!(sc->sc_flags & UKBD_FLAG_POLLING)) { 497184610Salfred sc->sc_time_ms += 25; /* milliseconds */ 498184610Salfred } 499184610Salfred ukbd_interrupt(sc); 500184610Salfred 501196489Salfred if (ukbd_any_key_pressed(sc)) { 502196489Salfred ukbd_start_timer(sc); 503196489Salfred } else { 504196489Salfred sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; 505196489Salfred } 506184610Salfred} 507184610Salfred 508192925Sthompsastatic uint8_t 509192925Sthompsaukbd_apple_fn(uint8_t keycode) { 510192925Sthompsa switch (keycode) { 511192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 512192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 513192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 514192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 515192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 516192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 517192925Sthompsa default: return keycode; 518192925Sthompsa } 519192925Sthompsa} 520184610Salfred 521192925Sthompsastatic uint8_t 522192925Sthompsaukbd_apple_swap(uint8_t keycode) { 523192925Sthompsa switch (keycode) { 524192925Sthompsa case 0x35: return 0x64; 525192925Sthompsa case 0x64: return 0x35; 526192925Sthompsa default: return keycode; 527184610Salfred } 528184610Salfred} 529184610Salfred 530184610Salfredstatic void 531194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 532184610Salfred{ 533194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 534194677Sthompsa struct usb_page_cache *pc; 535184610Salfred uint8_t i; 536192925Sthompsa uint8_t offset; 537192925Sthompsa uint8_t id; 538192925Sthompsa uint8_t apple_fn; 539192925Sthompsa uint8_t apple_eject; 540194677Sthompsa int len; 541184610Salfred 542194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 543194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 544194677Sthompsa 545184610Salfred switch (USB_GET_STATE(xfer)) { 546184610Salfred case USB_ST_TRANSFERRED: 547184610Salfred DPRINTF("actlen=%d bytes\n", len); 548184610Salfred 549192925Sthompsa if (len == 0) { 550192925Sthompsa DPRINTF("zero length data\n"); 551192925Sthompsa goto tr_setup; 552192925Sthompsa } 553192925Sthompsa 554192925Sthompsa if (sc->sc_kbd_id != 0) { 555192925Sthompsa /* check and remove HID ID byte */ 556194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 557192925Sthompsa if (id != sc->sc_kbd_id) { 558192925Sthompsa DPRINTF("wrong HID ID\n"); 559192925Sthompsa goto tr_setup; 560192925Sthompsa } 561192925Sthompsa offset = 1; 562192925Sthompsa len--; 563192925Sthompsa } else { 564192925Sthompsa offset = 0; 565192925Sthompsa } 566192925Sthompsa 567184610Salfred if (len > sizeof(sc->sc_ndata)) { 568184610Salfred len = sizeof(sc->sc_ndata); 569184610Salfred } 570192925Sthompsa 571184610Salfred if (len) { 572192925Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 573194677Sthompsa usbd_copy_out(pc, offset, &sc->sc_ndata, len); 574192925Sthompsa 575192925Sthompsa if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 576192925Sthompsa hid_get_data((uint8_t *)&sc->sc_ndata, 577192925Sthompsa len, &sc->sc_loc_apple_eject)) 578192925Sthompsa apple_eject = 1; 579192925Sthompsa else 580192925Sthompsa apple_eject = 0; 581192925Sthompsa 582192925Sthompsa if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 583192925Sthompsa hid_get_data((uint8_t *)&sc->sc_ndata, 584192925Sthompsa len, &sc->sc_loc_apple_fn)) 585192925Sthompsa apple_fn = 1; 586192925Sthompsa else 587192925Sthompsa apple_fn = 0; 588184610Salfred#if USB_DEBUG 589192925Sthompsa DPRINTF("apple_eject=%u apple_fn=%u\n", 590192925Sthompsa apple_eject, apple_fn); 591192925Sthompsa 592184610Salfred if (sc->sc_ndata.modifiers) { 593184610Salfred DPRINTF("mod: 0x%04x\n", sc->sc_ndata.modifiers); 594184610Salfred } 595184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 596184610Salfred if (sc->sc_ndata.keycode[i]) { 597184610Salfred DPRINTF("[%d] = %d\n", i, sc->sc_ndata.keycode[i]); 598184610Salfred } 599184610Salfred } 600184610Salfred#endif /* USB_DEBUG */ 601192925Sthompsa 602192925Sthompsa if (apple_fn) { 603192925Sthompsa for (i = 0; i < UKBD_NKEYCODE; i++) { 604192925Sthompsa sc->sc_ndata.keycode[i] = 605192925Sthompsa ukbd_apple_fn(sc->sc_ndata.keycode[i]); 606192925Sthompsa } 607192925Sthompsa } 608192925Sthompsa 609192925Sthompsa if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 610192925Sthompsa for (i = 0; i < UKBD_NKEYCODE; i++) { 611192925Sthompsa sc->sc_ndata.keycode[i] = 612192925Sthompsa ukbd_apple_swap(sc->sc_ndata.keycode[i]); 613192925Sthompsa } 614192925Sthompsa } 615192925Sthompsa 616184610Salfred ukbd_interrupt(sc); 617196489Salfred 618196489Salfred if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { 619196489Salfred if (ukbd_any_key_pressed(sc)) { 620196489Salfred ukbd_start_timer(sc); 621196489Salfred } 622196489Salfred } 623184610Salfred } 624184610Salfred case USB_ST_SETUP: 625192925Sthompsatr_setup: 626184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 627194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 628194228Sthompsa usbd_transfer_submit(xfer); 629184610Salfred } else { 630184610Salfred DPRINTF("input queue is full!\n"); 631184610Salfred } 632192925Sthompsa break; 633184610Salfred 634184610Salfred default: /* Error */ 635194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 636184610Salfred 637194677Sthompsa if (error != USB_ERR_CANCELLED) { 638184610Salfred /* try to clear stall first */ 639194677Sthompsa usbd_xfer_set_stall(xfer); 640192925Sthompsa goto tr_setup; 641184610Salfred } 642192925Sthompsa break; 643184610Salfred } 644184610Salfred} 645184610Salfred 646184610Salfredstatic void 647194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 648184610Salfred{ 649192984Sthompsa struct usb_device_request req; 650194677Sthompsa struct usb_page_cache *pc; 651192925Sthompsa uint8_t buf[2]; 652194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 653184610Salfred 654196489Salfred#if USB_DEBUG 655196489Salfred if (ukbd_no_leds) 656196489Salfred return; 657196489Salfred#endif 658196489Salfred 659184610Salfred switch (USB_GET_STATE(xfer)) { 660184610Salfred case USB_ST_TRANSFERRED: 661184610Salfred case USB_ST_SETUP: 662184610Salfred if (sc->sc_flags & UKBD_FLAG_SET_LEDS) { 663184610Salfred sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 664184610Salfred 665184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 666184610Salfred req.bRequest = UR_SET_REPORT; 667184610Salfred USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 668184610Salfred req.wIndex[0] = sc->sc_iface_no; 669184610Salfred req.wIndex[1] = 0; 670192925Sthompsa req.wLength[1] = 0; 671184610Salfred 672192925Sthompsa /* check if we need to prefix an ID byte */ 673192925Sthompsa if (sc->sc_led_id != 0) { 674192925Sthompsa req.wLength[0] = 2; 675192925Sthompsa buf[0] = sc->sc_led_id; 676192925Sthompsa buf[1] = sc->sc_leds; 677192925Sthompsa } else { 678192925Sthompsa req.wLength[0] = 1; 679192925Sthompsa buf[0] = sc->sc_leds; 680192925Sthompsa buf[1] = 0; 681192925Sthompsa } 682184610Salfred 683194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 684194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 685194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 686194677Sthompsa usbd_copy_in(pc, 0, buf, sizeof(buf)); 687184610Salfred 688194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 689194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, req.wLength[0]); 690194677Sthompsa usbd_xfer_set_frames(xfer, 2); 691194228Sthompsa usbd_transfer_submit(xfer); 692184610Salfred } 693196489Salfred break; 694184610Salfred 695184610Salfred default: /* Error */ 696194677Sthompsa DPRINTFN(0, "error=%s\n", usbd_errstr(error)); 697196489Salfred break; 698184610Salfred } 699184610Salfred} 700184610Salfred 701192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 702184610Salfred 703187259Sthompsa [UKBD_INTR_DT] = { 704184610Salfred .type = UE_INTERRUPT, 705184610Salfred .endpoint = UE_ADDR_ANY, 706184610Salfred .direction = UE_DIR_IN, 707190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 708190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 709190734Sthompsa .callback = &ukbd_intr_callback, 710184610Salfred }, 711184610Salfred 712187259Sthompsa [UKBD_CTRL_LED] = { 713184610Salfred .type = UE_CONTROL, 714184610Salfred .endpoint = 0x00, /* Control pipe */ 715184610Salfred .direction = UE_DIR_ANY, 716192984Sthompsa .bufsize = sizeof(struct usb_device_request) + 8, 717190734Sthompsa .callback = &ukbd_set_leds_callback, 718190734Sthompsa .timeout = 1000, /* 1 second */ 719184610Salfred }, 720184610Salfred}; 721184610Salfred 722184610Salfredstatic int 723184610Salfredukbd_probe(device_t dev) 724184610Salfred{ 725184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 726192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 727194067Sthompsa void *d_ptr; 728194067Sthompsa int error; 729194067Sthompsa uint16_t d_len; 730184610Salfred 731184610Salfred DPRINTFN(11, "\n"); 732184610Salfred 733184610Salfred if (sw == NULL) { 734184610Salfred return (ENXIO); 735184610Salfred } 736192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 737184610Salfred return (ENXIO); 738184610Salfred } 739194067Sthompsa 740194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 741194067Sthompsa return (ENXIO); 742194067Sthompsa 743194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 744194067Sthompsa (uaa->info.bInterfaceProtocol == UPROTO_BOOT_KEYBOARD)) { 745194228Sthompsa if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 746184610Salfred return (ENXIO); 747184610Salfred else 748184610Salfred return (0); 749184610Salfred } 750194067Sthompsa 751194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 752194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 753194067Sthompsa 754194067Sthompsa if (error) 755194067Sthompsa return (ENXIO); 756194067Sthompsa 757195960Salfred /* 758195960Salfred * NOTE: we currently don't support USB mouse and USB keyboard 759195960Salfred * on the same USB endpoint. 760195960Salfred */ 761194067Sthompsa if (hid_is_collection(d_ptr, d_len, 762195960Salfred HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) { 763195960Salfred /* most likely a mouse */ 764195960Salfred error = ENXIO; 765195960Salfred } else if (hid_is_collection(d_ptr, d_len, 766194067Sthompsa HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) { 767194228Sthompsa if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 768194067Sthompsa error = ENXIO; 769194067Sthompsa else 770194067Sthompsa error = 0; 771194067Sthompsa } else 772194067Sthompsa error = ENXIO; 773194067Sthompsa 774194067Sthompsa free(d_ptr, M_TEMP); 775194067Sthompsa return (error); 776184610Salfred} 777184610Salfred 778184610Salfredstatic int 779184610Salfredukbd_attach(device_t dev) 780184610Salfred{ 781184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 782192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 783184610Salfred int32_t unit = device_get_unit(dev); 784184610Salfred keyboard_t *kbd = &sc->sc_kbd; 785192925Sthompsa void *hid_ptr = NULL; 786193045Sthompsa usb_error_t err; 787192925Sthompsa uint32_t flags; 788184610Salfred uint16_t n; 789192925Sthompsa uint16_t hid_len; 790184610Salfred 791184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 792184610Salfred 793184610Salfred kbd->kb_data = (void *)sc; 794184610Salfred 795194228Sthompsa device_set_usb_desc(dev); 796184610Salfred 797184610Salfred sc->sc_udev = uaa->device; 798184610Salfred sc->sc_iface = uaa->iface; 799184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 800184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 801184610Salfred sc->sc_mode = K_XLATE; 802184610Salfred 803194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 804184610Salfred 805194228Sthompsa err = usbd_transfer_setup(uaa->device, 806184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 807184610Salfred UKBD_N_TRANSFER, sc, &Giant); 808184610Salfred 809184610Salfred if (err) { 810194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 811184610Salfred goto detach; 812184610Salfred } 813184610Salfred /* setup default keyboard maps */ 814184610Salfred 815184610Salfred sc->sc_keymap = key_map; 816184610Salfred sc->sc_accmap = accent_map; 817184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 818184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 819184610Salfred } 820184610Salfred 821184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 822184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 823184610Salfred 824184610Salfred KBD_FOUND_DEVICE(kbd); 825184610Salfred 826184610Salfred ukbd_clear_state(kbd); 827184610Salfred 828184610Salfred /* 829184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 830184610Salfred * according to the BIOS data? 831184610Salfred */ 832184610Salfred KBD_PROBE_DONE(kbd); 833184610Salfred 834192925Sthompsa /* figure out if there is an ID byte in the data */ 835194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 836192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 837192925Sthompsa if (err == 0) { 838192925Sthompsa uint8_t temp_id; 839192925Sthompsa 840192925Sthompsa /* investigate if this is an Apple Keyboard */ 841192925Sthompsa if (hid_locate(hid_ptr, hid_len, 842192925Sthompsa HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 843192925Sthompsa hid_input, 0, &sc->sc_loc_apple_eject, &flags, 844192925Sthompsa &sc->sc_kbd_id)) { 845192925Sthompsa if (flags & HIO_VARIABLE) 846192925Sthompsa sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 847192925Sthompsa UKBD_FLAG_APPLE_SWAP; 848192925Sthompsa if (hid_locate(hid_ptr, hid_len, 849192925Sthompsa HID_USAGE2(0xFFFF, 0x0003), 850192925Sthompsa hid_input, 0, &sc->sc_loc_apple_fn, &flags, 851192925Sthompsa &temp_id)) { 852192925Sthompsa if (flags & HIO_VARIABLE) 853192925Sthompsa sc->sc_flags |= UKBD_FLAG_APPLE_FN | 854192925Sthompsa UKBD_FLAG_APPLE_SWAP; 855192925Sthompsa if (temp_id != sc->sc_kbd_id) { 856192925Sthompsa DPRINTF("HID IDs mismatch\n"); 857192925Sthompsa } 858192925Sthompsa } 859192925Sthompsa } else { 860192925Sthompsa /* 861192925Sthompsa * Assume the first HID ID contains the 862192925Sthompsa * keyboard data 863192925Sthompsa */ 864192925Sthompsa hid_report_size(hid_ptr, hid_len, 865192925Sthompsa hid_input, &sc->sc_kbd_id); 866192925Sthompsa } 867192925Sthompsa 868192925Sthompsa /* investigate if we need an ID-byte for the leds */ 869192925Sthompsa hid_report_size(hid_ptr, hid_len, hid_output, &sc->sc_led_id); 870192925Sthompsa 871192925Sthompsa free(hid_ptr, M_TEMP); 872192925Sthompsa } 873192925Sthompsa 874184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 875196489Salfred err = usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); 876184610Salfred 877184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 878184610Salfred 879184610Salfred KBD_INIT_DONE(kbd); 880184610Salfred 881184610Salfred if (kbd_register(kbd) < 0) { 882184610Salfred goto detach; 883184610Salfred } 884184610Salfred KBD_CONFIG_DONE(kbd); 885184610Salfred 886184610Salfred ukbd_enable(kbd); 887184610Salfred 888184610Salfred#ifdef KBD_INSTALL_CDEV 889184610Salfred if (kbd_attach(kbd)) { 890184610Salfred goto detach; 891184610Salfred } 892184610Salfred#endif 893184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 894184610Salfred 895184610Salfred if (bootverbose) { 896184610Salfred genkbd_diag(kbd, bootverbose); 897184610Salfred } 898196403Sjhb /* lock keyboard mutex */ 899184610Salfred 900196403Sjhb mtx_lock(&Giant); 901196403Sjhb 902184610Salfred /* start the keyboard */ 903184610Salfred 904194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 905184610Salfred 906186454Sthompsa mtx_unlock(&Giant); 907184610Salfred return (0); /* success */ 908184610Salfred 909184610Salfreddetach: 910184610Salfred ukbd_detach(dev); 911184610Salfred return (ENXIO); /* error */ 912184610Salfred} 913184610Salfred 914193315Sthompsastatic int 915184610Salfredukbd_detach(device_t dev) 916184610Salfred{ 917184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 918184610Salfred int error; 919184610Salfred 920184610Salfred DPRINTF("\n"); 921184610Salfred 922184610Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 923184610Salfred panic("cannot detach polled keyboard!\n"); 924184610Salfred } 925184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 926184610Salfred 927194228Sthompsa usb_callout_stop(&sc->sc_callout); 928184610Salfred 929184610Salfred ukbd_disable(&sc->sc_kbd); 930184610Salfred 931184610Salfred#ifdef KBD_INSTALL_CDEV 932184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 933184610Salfred error = kbd_detach(&sc->sc_kbd); 934184610Salfred if (error) { 935184610Salfred /* usb attach cannot return an error */ 936184610Salfred device_printf(dev, "WARNING: kbd_detach() " 937184610Salfred "returned non-zero! (ignored)\n"); 938184610Salfred } 939184610Salfred } 940184610Salfred#endif 941184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 942184610Salfred error = kbd_unregister(&sc->sc_kbd); 943184610Salfred if (error) { 944184610Salfred /* usb attach cannot return an error */ 945184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 946184610Salfred "returned non-zero! (ignored)\n"); 947184610Salfred } 948184610Salfred } 949184610Salfred sc->sc_kbd.kb_flags = 0; 950184610Salfred 951194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 952184610Salfred 953194228Sthompsa usb_callout_drain(&sc->sc_callout); 954184610Salfred 955184610Salfred DPRINTF("%s: disconnected\n", 956184610Salfred device_get_nameunit(dev)); 957184610Salfred 958184610Salfred return (0); 959184610Salfred} 960184610Salfred 961184610Salfredstatic int 962184610Salfredukbd_resume(device_t dev) 963184610Salfred{ 964184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 965184610Salfred 966184610Salfred ukbd_clear_state(&sc->sc_kbd); 967184610Salfred 968184610Salfred return (0); 969184610Salfred} 970184610Salfred 971184610Salfred/* early keyboard probe, not supported */ 972184610Salfredstatic int 973184610Salfredukbd_configure(int flags) 974184610Salfred{ 975184610Salfred return (0); 976184610Salfred} 977184610Salfred 978184610Salfred/* detect a keyboard, not used */ 979184610Salfredstatic int 980184610Salfredukbd__probe(int unit, void *arg, int flags) 981184610Salfred{ 982184610Salfred return (ENXIO); 983184610Salfred} 984184610Salfred 985184610Salfred/* reset and initialize the device, not used */ 986184610Salfredstatic int 987184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 988184610Salfred{ 989184610Salfred return (ENXIO); 990184610Salfred} 991184610Salfred 992184610Salfred/* test the interface to the device, not used */ 993184610Salfredstatic int 994184610Salfredukbd_test_if(keyboard_t *kbd) 995184610Salfred{ 996184610Salfred return (0); 997184610Salfred} 998184610Salfred 999184610Salfred/* finish using this keyboard, not used */ 1000184610Salfredstatic int 1001184610Salfredukbd_term(keyboard_t *kbd) 1002184610Salfred{ 1003184610Salfred return (ENXIO); 1004184610Salfred} 1005184610Salfred 1006184610Salfred/* keyboard interrupt routine, not used */ 1007184610Salfredstatic int 1008184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 1009184610Salfred{ 1010184610Salfred return (0); 1011184610Salfred} 1012184610Salfred 1013184610Salfred/* lock the access to the keyboard, not used */ 1014184610Salfredstatic int 1015184610Salfredukbd_lock(keyboard_t *kbd, int lock) 1016184610Salfred{ 1017184610Salfred return (1); 1018184610Salfred} 1019184610Salfred 1020184610Salfred/* 1021184610Salfred * Enable the access to the device; until this function is called, 1022184610Salfred * the client cannot read from the keyboard. 1023184610Salfred */ 1024184610Salfredstatic int 1025184610Salfredukbd_enable(keyboard_t *kbd) 1026184610Salfred{ 1027195960Salfred if (!mtx_owned(&Giant)) { 1028195960Salfred /* XXX cludge */ 1029195960Salfred int retval; 1030195960Salfred mtx_lock(&Giant); 1031195960Salfred retval = ukbd_enable(kbd); 1032195960Salfred mtx_unlock(&Giant); 1033195960Salfred return (retval); 1034195960Salfred } 1035184610Salfred KBD_ACTIVATE(kbd); 1036184610Salfred return (0); 1037184610Salfred} 1038184610Salfred 1039184610Salfred/* disallow the access to the device */ 1040184610Salfredstatic int 1041184610Salfredukbd_disable(keyboard_t *kbd) 1042184610Salfred{ 1043195960Salfred if (!mtx_owned(&Giant)) { 1044195960Salfred /* XXX cludge */ 1045195960Salfred int retval; 1046195960Salfred mtx_lock(&Giant); 1047195960Salfred retval = ukbd_disable(kbd); 1048195960Salfred mtx_unlock(&Giant); 1049195960Salfred return (retval); 1050195960Salfred } 1051184610Salfred KBD_DEACTIVATE(kbd); 1052184610Salfred return (0); 1053184610Salfred} 1054184610Salfred 1055184610Salfred/* check if data is waiting */ 1056184610Salfredstatic int 1057184610Salfredukbd_check(keyboard_t *kbd) 1058184610Salfred{ 1059184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1060184610Salfred 1061195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1062195960Salfred return (0); 1063195960Salfred 1064195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1065195960Salfred if (!mtx_owned(&Giant)) { 1066195960Salfred /* XXX cludge */ 1067195960Salfred int retval; 1068195960Salfred mtx_lock(&Giant); 1069195960Salfred retval = ukbd_check(kbd); 1070195960Salfred mtx_unlock(&Giant); 1071195960Salfred return (retval); 1072195960Salfred } 1073195960Salfred ukbd_do_poll(sc, 0); 1074195960Salfred } else { 1075195960Salfred /* XXX the keyboard layer requires Giant */ 1076195960Salfred if (!mtx_owned(&Giant)) 1077195960Salfred return (0); 1078184610Salfred } 1079184610Salfred 1080184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1081184610Salfred if (sc->sc_buffered_char[0]) { 1082184610Salfred return (1); 1083184610Salfred } 1084184610Salfred#endif 1085184610Salfred if (sc->sc_inputs > 0) { 1086184610Salfred return (1); 1087184610Salfred } 1088184610Salfred return (0); 1089184610Salfred} 1090184610Salfred 1091184610Salfred/* check if char is waiting */ 1092184610Salfredstatic int 1093184610Salfredukbd_check_char(keyboard_t *kbd) 1094184610Salfred{ 1095184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1096184610Salfred 1097195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1098195960Salfred return (0); 1099195960Salfred 1100195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1101195960Salfred if (!mtx_owned(&Giant)) { 1102195960Salfred /* XXX cludge */ 1103195960Salfred int retval; 1104195960Salfred mtx_lock(&Giant); 1105195960Salfred retval = ukbd_check_char(kbd); 1106195960Salfred mtx_unlock(&Giant); 1107195960Salfred return (retval); 1108195960Salfred } 1109195960Salfred } else { 1110195960Salfred /* XXX the keyboard layer requires Giant */ 1111195960Salfred if (!mtx_owned(&Giant)) 1112195960Salfred return (0); 1113184610Salfred } 1114184610Salfred 1115184610Salfred if ((sc->sc_composed_char > 0) && 1116184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1117184610Salfred return (1); 1118184610Salfred } 1119184610Salfred return (ukbd_check(kbd)); 1120184610Salfred} 1121184610Salfred 1122184610Salfred 1123184610Salfred/* read one byte from the keyboard if it's allowed */ 1124184610Salfredstatic int 1125184610Salfredukbd_read(keyboard_t *kbd, int wait) 1126184610Salfred{ 1127184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1128184610Salfred int32_t usbcode; 1129184610Salfred 1130184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1131184610Salfred uint32_t keycode; 1132184610Salfred uint32_t scancode; 1133184610Salfred 1134184610Salfred#endif 1135195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1136195960Salfred return (-1); 1137184610Salfred 1138195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1139195960Salfred if (!mtx_owned(&Giant)) { 1140195960Salfred /* XXX cludge */ 1141195960Salfred int retval; 1142195960Salfred mtx_lock(&Giant); 1143195960Salfred retval = ukbd_read(kbd, wait); 1144195960Salfred mtx_unlock(&Giant); 1145195960Salfred return (retval); 1146195960Salfred } 1147195960Salfred } else { 1148195960Salfred /* XXX the keyboard layer requires Giant */ 1149195960Salfred if (!mtx_owned(&Giant)) 1150195960Salfred return (-1); 1151184610Salfred } 1152184610Salfred 1153184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1154184610Salfred if (sc->sc_buffered_char[0]) { 1155184610Salfred scancode = sc->sc_buffered_char[0]; 1156184610Salfred if (scancode & SCAN_PREFIX) { 1157184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1158184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1159184610Salfred } 1160184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1161184610Salfred sc->sc_buffered_char[1] = 0; 1162184610Salfred return (scancode); 1163184610Salfred } 1164184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1165184610Salfred 1166184610Salfred /* XXX */ 1167184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1168195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1169195960Salfred return (-1); 1170195960Salfred 1171184610Salfred ++(kbd->kb_count); 1172184610Salfred 1173184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1174184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1175184610Salfred if (keycode == NN) { 1176184610Salfred return -1; 1177184610Salfred } 1178184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1179184610Salfred (usbcode & KEY_RELEASE))); 1180184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1181184610Salfred return (usbcode); 1182184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1183184610Salfred} 1184184610Salfred 1185184610Salfred/* read char from the keyboard */ 1186184610Salfredstatic uint32_t 1187184610Salfredukbd_read_char(keyboard_t *kbd, int wait) 1188184610Salfred{ 1189184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1190184610Salfred uint32_t action; 1191184610Salfred uint32_t keycode; 1192184610Salfred int32_t usbcode; 1193184610Salfred 1194184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1195184610Salfred uint32_t scancode; 1196184610Salfred 1197184610Salfred#endif 1198195960Salfred 1199195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1200195960Salfred return (NOKEY); 1201195960Salfred 1202195960Salfred if (sc->sc_flags & UKBD_FLAG_POLLING) { 1203195960Salfred if (!mtx_owned(&Giant)) { 1204195960Salfred /* XXX cludge */ 1205195960Salfred int retval; 1206195960Salfred mtx_lock(&Giant); 1207195960Salfred retval = ukbd_read_char(kbd, wait); 1208195960Salfred mtx_unlock(&Giant); 1209195960Salfred return (retval); 1210195960Salfred } 1211195960Salfred } else { 1212195960Salfred /* XXX the keyboard layer requires Giant */ 1213195960Salfred if (!mtx_owned(&Giant)) 1214195960Salfred return (NOKEY); 1215184610Salfred } 1216184610Salfred 1217184610Salfrednext_code: 1218184610Salfred 1219184610Salfred /* do we have a composed char to return ? */ 1220184610Salfred 1221184610Salfred if ((sc->sc_composed_char > 0) && 1222184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1223184610Salfred 1224184610Salfred action = sc->sc_composed_char; 1225184610Salfred sc->sc_composed_char = 0; 1226184610Salfred 1227184610Salfred if (action > 0xFF) { 1228184610Salfred goto errkey; 1229184610Salfred } 1230184610Salfred goto done; 1231184610Salfred } 1232184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1233184610Salfred 1234184610Salfred /* do we have a pending raw scan code? */ 1235184610Salfred 1236184610Salfred if (sc->sc_mode == K_RAW) { 1237184610Salfred scancode = sc->sc_buffered_char[0]; 1238184610Salfred if (scancode) { 1239184610Salfred if (scancode & SCAN_PREFIX) { 1240184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1241184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1242184610Salfred } 1243184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1244184610Salfred sc->sc_buffered_char[1] = 0; 1245184610Salfred return (scancode); 1246184610Salfred } 1247184610Salfred } 1248184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1249184610Salfred 1250184610Salfred /* see if there is something in the keyboard port */ 1251184610Salfred /* XXX */ 1252184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1253184610Salfred if (usbcode == -1) { 1254184610Salfred return (NOKEY); 1255184610Salfred } 1256184610Salfred ++kbd->kb_count; 1257184610Salfred 1258184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1259184610Salfred /* USB key index -> key code -> AT scan code */ 1260184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1261184610Salfred if (keycode == NN) { 1262184610Salfred return (NOKEY); 1263184610Salfred } 1264184610Salfred /* return an AT scan code for the K_RAW mode */ 1265184610Salfred if (sc->sc_mode == K_RAW) { 1266184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1267184610Salfred (usbcode & KEY_RELEASE))); 1268184610Salfred } 1269184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1270184610Salfred 1271184610Salfred /* return the byte as is for the K_RAW mode */ 1272184610Salfred if (sc->sc_mode == K_RAW) { 1273184610Salfred return (usbcode); 1274184610Salfred } 1275184610Salfred /* USB key index -> key code */ 1276184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1277184610Salfred if (keycode == NN) { 1278184610Salfred return (NOKEY); 1279184610Salfred } 1280184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1281184610Salfred 1282184610Salfred switch (keycode) { 1283184610Salfred case 0x38: /* left alt (compose key) */ 1284184610Salfred if (usbcode & KEY_RELEASE) { 1285184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1286184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1287184610Salfred 1288184610Salfred if (sc->sc_composed_char > 0xFF) { 1289184610Salfred sc->sc_composed_char = 0; 1290184610Salfred } 1291184610Salfred } 1292184610Salfred } else { 1293184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1294184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1295184610Salfred sc->sc_composed_char = 0; 1296184610Salfred } 1297184610Salfred } 1298184610Salfred break; 1299184610Salfred /* XXX: I don't like these... */ 1300184610Salfred case 0x5c: /* print screen */ 1301184610Salfred if (sc->sc_flags & ALTS) { 1302184610Salfred keycode = 0x54; /* sysrq */ 1303184610Salfred } 1304184610Salfred break; 1305184610Salfred case 0x68: /* pause/break */ 1306184610Salfred if (sc->sc_flags & CTLS) { 1307184610Salfred keycode = 0x6c; /* break */ 1308184610Salfred } 1309184610Salfred break; 1310184610Salfred } 1311184610Salfred 1312184610Salfred /* return the key code in the K_CODE mode */ 1313184610Salfred if (usbcode & KEY_RELEASE) { 1314184610Salfred keycode |= SCAN_RELEASE; 1315184610Salfred } 1316184610Salfred if (sc->sc_mode == K_CODE) { 1317184610Salfred return (keycode); 1318184610Salfred } 1319184610Salfred /* compose a character code */ 1320184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1321184610Salfred switch (keycode) { 1322184610Salfred /* key pressed, process it */ 1323184610Salfred case 0x47: 1324184610Salfred case 0x48: 1325184610Salfred case 0x49: /* keypad 7,8,9 */ 1326184610Salfred sc->sc_composed_char *= 10; 1327184610Salfred sc->sc_composed_char += keycode - 0x40; 1328184610Salfred goto check_composed; 1329184610Salfred 1330184610Salfred case 0x4B: 1331184610Salfred case 0x4C: 1332184610Salfred case 0x4D: /* keypad 4,5,6 */ 1333184610Salfred sc->sc_composed_char *= 10; 1334184610Salfred sc->sc_composed_char += keycode - 0x47; 1335184610Salfred goto check_composed; 1336184610Salfred 1337184610Salfred case 0x4F: 1338184610Salfred case 0x50: 1339184610Salfred case 0x51: /* keypad 1,2,3 */ 1340184610Salfred sc->sc_composed_char *= 10; 1341184610Salfred sc->sc_composed_char += keycode - 0x4E; 1342184610Salfred goto check_composed; 1343184610Salfred 1344184610Salfred case 0x52: /* keypad 0 */ 1345184610Salfred sc->sc_composed_char *= 10; 1346184610Salfred goto check_composed; 1347184610Salfred 1348184610Salfred /* key released, no interest here */ 1349184610Salfred case SCAN_RELEASE | 0x47: 1350184610Salfred case SCAN_RELEASE | 0x48: 1351184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1352184610Salfred case SCAN_RELEASE | 0x4B: 1353184610Salfred case SCAN_RELEASE | 0x4C: 1354184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1355184610Salfred case SCAN_RELEASE | 0x4F: 1356184610Salfred case SCAN_RELEASE | 0x50: 1357184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1358184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1359184610Salfred goto next_code; 1360184610Salfred 1361184610Salfred case 0x38: /* left alt key */ 1362184610Salfred break; 1363184610Salfred 1364184610Salfred default: 1365184610Salfred if (sc->sc_composed_char > 0) { 1366184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1367184610Salfred sc->sc_composed_char = 0; 1368184610Salfred goto errkey; 1369184610Salfred } 1370184610Salfred break; 1371184610Salfred } 1372184610Salfred } 1373184610Salfred /* keycode to key action */ 1374184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1375184610Salfred (keycode & SCAN_RELEASE), 1376184610Salfred &sc->sc_state, &sc->sc_accents); 1377184610Salfred if (action == NOKEY) { 1378184610Salfred goto next_code; 1379184610Salfred } 1380184610Salfreddone: 1381184610Salfred return (action); 1382184610Salfred 1383184610Salfredcheck_composed: 1384184610Salfred if (sc->sc_composed_char <= 0xFF) { 1385184610Salfred goto next_code; 1386184610Salfred } 1387184610Salfrederrkey: 1388184610Salfred return (ERRKEY); 1389184610Salfred} 1390184610Salfred 1391184610Salfred/* some useful control functions */ 1392184610Salfredstatic int 1393184610Salfredukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1394184610Salfred{ 1395184610Salfred /* translate LED_XXX bits into the device specific bits */ 1396184610Salfred static const uint8_t ledmap[8] = { 1397184610Salfred 0, 2, 1, 3, 4, 6, 5, 7, 1398184610Salfred }; 1399184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1400184610Salfred int i; 1401184610Salfred 1402184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1403184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1404184610Salfred int ival; 1405184610Salfred 1406184610Salfred#endif 1407184610Salfred if (!mtx_owned(&Giant)) { 1408184610Salfred /* 1409184610Salfred * XXX big problem: If scroll lock is pressed and "printf()" 1410184610Salfred * is called, the CPU will get here, to un-scroll lock the 1411184610Salfred * keyboard. But if "printf()" acquires the "Giant" lock, 1412184610Salfred * there will be a locking order reversal problem, so the 1413184610Salfred * keyboard system must get out of "Giant" first, before the 1414184610Salfred * CPU can proceed here ... 1415184610Salfred */ 1416184610Salfred return (EINVAL); 1417184610Salfred } 1418184610Salfred 1419184610Salfred switch (cmd) { 1420184610Salfred case KDGKBMODE: /* get keyboard mode */ 1421184610Salfred *(int *)arg = sc->sc_mode; 1422184610Salfred break; 1423184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1424184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1425184610Salfred case _IO('K', 7): 1426184610Salfred ival = IOCPARM_IVAL(arg); 1427184610Salfred arg = (caddr_t)&ival; 1428184610Salfred /* FALLTHROUGH */ 1429184610Salfred#endif 1430184610Salfred case KDSKBMODE: /* set keyboard mode */ 1431184610Salfred switch (*(int *)arg) { 1432184610Salfred case K_XLATE: 1433184610Salfred if (sc->sc_mode != K_XLATE) { 1434184610Salfred /* make lock key state and LED state match */ 1435184610Salfred sc->sc_state &= ~LOCK_MASK; 1436184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1437184610Salfred } 1438184610Salfred /* FALLTHROUGH */ 1439184610Salfred case K_RAW: 1440184610Salfred case K_CODE: 1441184610Salfred if (sc->sc_mode != *(int *)arg) { 1442184610Salfred ukbd_clear_state(kbd); 1443184610Salfred sc->sc_mode = *(int *)arg; 1444184610Salfred } 1445184610Salfred break; 1446184610Salfred default: 1447184610Salfred return (EINVAL); 1448184610Salfred } 1449184610Salfred break; 1450184610Salfred 1451184610Salfred case KDGETLED: /* get keyboard LED */ 1452184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1453184610Salfred break; 1454184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1455184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1456184610Salfred case _IO('K', 66): 1457184610Salfred ival = IOCPARM_IVAL(arg); 1458184610Salfred arg = (caddr_t)&ival; 1459184610Salfred /* FALLTHROUGH */ 1460184610Salfred#endif 1461184610Salfred case KDSETLED: /* set keyboard LED */ 1462184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1463184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1464184610Salfred return (EINVAL); 1465184610Salfred } 1466184610Salfred i = *(int *)arg; 1467184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1468184610Salfred if (sc->sc_mode == K_XLATE && 1469184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1470184610Salfred if (i & ALKED) 1471184610Salfred i |= CLKED; 1472184610Salfred else 1473184610Salfred i &= ~CLKED; 1474184610Salfred } 1475184610Salfred if (KBD_HAS_DEVICE(kbd)) { 1476184610Salfred ukbd_set_leds(sc, ledmap[i & LED_MASK]); 1477184610Salfred } 1478184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1479184610Salfred break; 1480184610Salfred case KDGKBSTATE: /* get lock key state */ 1481184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1482184610Salfred break; 1483184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1484184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1485184610Salfred case _IO('K', 20): 1486184610Salfred ival = IOCPARM_IVAL(arg); 1487184610Salfred arg = (caddr_t)&ival; 1488184610Salfred /* FALLTHROUGH */ 1489184610Salfred#endif 1490184610Salfred case KDSKBSTATE: /* set lock key state */ 1491184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1492184610Salfred return (EINVAL); 1493184610Salfred } 1494184610Salfred sc->sc_state &= ~LOCK_MASK; 1495184610Salfred sc->sc_state |= *(int *)arg; 1496184610Salfred 1497184610Salfred /* set LEDs and quit */ 1498184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1499184610Salfred 1500184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1501184610Salfred * interface) */ 1502184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1503184610Salfred return (0); 1504184610Salfred } 1505184610Salfred if (((int *)arg)[1] < 0) { 1506184610Salfred return (EINVAL); 1507184610Salfred } 1508184610Salfred if (((int *)arg)[0] < 0) { 1509184610Salfred return (EINVAL); 1510184610Salfred } 1511184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1512184610Salfred kbd->kb_delay1 = 200; 1513184610Salfred else 1514184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1515184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1516184610Salfred return (0); 1517184610Salfred 1518184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1519184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1520184610Salfred case _IO('K', 67): 1521184610Salfred ival = IOCPARM_IVAL(arg); 1522184610Salfred arg = (caddr_t)&ival; 1523184610Salfred /* FALLTHROUGH */ 1524184610Salfred#endif 1525184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1526184610Salfred * interface) */ 1527184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1528184610Salfred 1529184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1530184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1531184610Salfred * entry */ 1532184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1533184610Salfred sc->sc_accents = 0; 1534184610Salfred /* FALLTHROUGH */ 1535184610Salfred default: 1536184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1537184610Salfred } 1538184610Salfred 1539184610Salfred return (0); 1540184610Salfred} 1541184610Salfred 1542184610Salfred/* clear the internal state of the keyboard */ 1543184610Salfredstatic void 1544184610Salfredukbd_clear_state(keyboard_t *kbd) 1545184610Salfred{ 1546184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1547184610Salfred 1548184610Salfred if (!mtx_owned(&Giant)) { 1549184610Salfred return; /* XXX */ 1550184610Salfred } 1551184610Salfred 1552184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 1553184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 1554184610Salfred sc->sc_accents = 0; 1555184610Salfred sc->sc_composed_char = 0; 1556184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1557184610Salfred sc->sc_buffered_char[0] = 0; 1558184610Salfred sc->sc_buffered_char[1] = 0; 1559184610Salfred#endif 1560184610Salfred bzero(&sc->sc_ndata, sizeof(sc->sc_ndata)); 1561184610Salfred bzero(&sc->sc_odata, sizeof(sc->sc_odata)); 1562184610Salfred bzero(&sc->sc_ntime, sizeof(sc->sc_ntime)); 1563184610Salfred bzero(&sc->sc_otime, sizeof(sc->sc_otime)); 1564184610Salfred} 1565184610Salfred 1566184610Salfred/* save the internal state, not used */ 1567184610Salfredstatic int 1568184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1569184610Salfred{ 1570184610Salfred return (len == 0) ? 1 : -1; 1571184610Salfred} 1572184610Salfred 1573184610Salfred/* set the internal state, not used */ 1574184610Salfredstatic int 1575184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1576184610Salfred{ 1577184610Salfred return (EINVAL); 1578184610Salfred} 1579184610Salfred 1580184610Salfredstatic int 1581184610Salfredukbd_poll(keyboard_t *kbd, int on) 1582184610Salfred{ 1583184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1584184610Salfred 1585184610Salfred if (!mtx_owned(&Giant)) { 1586195960Salfred /* XXX cludge */ 1587195960Salfred int retval; 1588195960Salfred mtx_lock(&Giant); 1589195960Salfred retval = ukbd_poll(kbd, on); 1590195960Salfred mtx_unlock(&Giant); 1591195960Salfred return (retval); 1592184610Salfred } 1593184610Salfred 1594184610Salfred if (on) { 1595184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 1596184610Salfred } else { 1597184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 1598184610Salfred } 1599184610Salfred return (0); 1600184610Salfred} 1601184610Salfred 1602184610Salfred/* local functions */ 1603184610Salfred 1604184610Salfredstatic void 1605184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 1606184610Salfred{ 1607184610Salfred DPRINTF("leds=0x%02x\n", leds); 1608184610Salfred 1609184610Salfred sc->sc_leds = leds; 1610184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 1611184610Salfred 1612184610Salfred /* start transfer, if not already started */ 1613184610Salfred 1614194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 1615184610Salfred} 1616184610Salfred 1617184610Salfredstatic int 1618184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 1619184610Salfred{ 1620184610Salfred static const int delays[] = {250, 500, 750, 1000}; 1621184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 1622184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 1623184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 1624184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 1625184610Salfred 1626184610Salfred if (code & ~0x7f) { 1627184610Salfred return (EINVAL); 1628184610Salfred } 1629184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 1630184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 1631184610Salfred return (0); 1632184610Salfred} 1633184610Salfred 1634184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1635184610Salfredstatic int 1636184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 1637184610Salfred{ 1638184610Salfred static const int scan[] = { 1639197999Shrs /* 89 */ 1640197999Shrs 0x11c, /* Enter */ 1641197999Shrs /* 90-99 */ 1642197999Shrs 0x11d, /* Ctrl-R */ 1643197999Shrs 0x135, /* Divide */ 1644197999Shrs 0x137 | SCAN_PREFIX_SHIFT, /* PrintScreen */ 1645197999Shrs 0x138, /* Alt-R */ 1646197999Shrs 0x147, /* Home */ 1647197999Shrs 0x148, /* Up */ 1648197999Shrs 0x149, /* PageUp */ 1649197999Shrs 0x14b, /* Left */ 1650197999Shrs 0x14d, /* Right */ 1651197999Shrs 0x14f, /* End */ 1652197999Shrs /* 100-109 */ 1653197999Shrs 0x150, /* Down */ 1654197999Shrs 0x151, /* PageDown */ 1655197999Shrs 0x152, /* Insert */ 1656197999Shrs 0x153, /* Delete */ 1657197999Shrs 0x146, /* XXX Pause/Break */ 1658197999Shrs 0x15b, /* Win_L(Super_L) */ 1659197999Shrs 0x15c, /* Win_R(Super_R) */ 1660197999Shrs 0x15d, /* Application(Menu) */ 1661197999Shrs 1662184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 1663197999Shrs 0x168, /* Sun Type 6 Help */ 1664197999Shrs 0x15e, /* Sun Type 6 Stop */ 1665197999Shrs /* 110 - 119 */ 1666197999Shrs 0x15f, /* Sun Type 6 Again */ 1667197999Shrs 0x160, /* Sun Type 6 Props */ 1668197999Shrs 0x161, /* Sun Type 6 Undo */ 1669197999Shrs 0x162, /* Sun Type 6 Front */ 1670197999Shrs 0x163, /* Sun Type 6 Copy */ 1671197999Shrs 0x164, /* Sun Type 6 Open */ 1672197999Shrs 0x165, /* Sun Type 6 Paste */ 1673197999Shrs 0x166, /* Sun Type 6 Find */ 1674197999Shrs 0x167, /* Sun Type 6 Cut */ 1675197999Shrs 0x125, /* Sun Type 6 Mute */ 1676197999Shrs /* 120 - 128 */ 1677197999Shrs 0x11f, /* Sun Type 6 VolumeDown */ 1678197999Shrs 0x11e, /* Sun Type 6 VolumeUp */ 1679197999Shrs 0x120, /* Sun Type 6 PowerDown */ 1680197999Shrs 1681197999Shrs /* Japanese 106/109 keyboard */ 1682197999Shrs 0x73, /* Keyboard Intl' 1 (backslash / underscore) */ 1683197999Shrs 0x70, /* Keyboard Intl' 2 (Katakana / Hiragana) */ 1684197999Shrs 0x7d, /* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */ 1685197999Shrs 0x79, /* Keyboard Intl' 4 (Henkan) */ 1686197999Shrs 0x7b, /* Keyboard Intl' 5 (Muhenkan) */ 1687197999Shrs 0x5c, /* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */ 1688184610Salfred }; 1689184610Salfred 1690184610Salfred if ((code >= 89) && (code < (89 + (sizeof(scan) / sizeof(scan[0]))))) { 1691197999Shrs code = scan[code - 89]; 1692184610Salfred } 1693184610Salfred /* Pause/Break */ 1694184610Salfred if ((code == 104) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 1695184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 1696184610Salfred } 1697184610Salfred if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) { 1698184610Salfred code &= ~SCAN_PREFIX_SHIFT; 1699184610Salfred } 1700184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 1701184610Salfred 1702184610Salfred if (code & SCAN_PREFIX) { 1703184610Salfred if (code & SCAN_PREFIX_CTL) { 1704184610Salfred /* Ctrl */ 1705184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 1706184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 1707184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 1708184610Salfred /* Shift */ 1709184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 1710184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 1711184610Salfred } else { 1712184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 1713184610Salfred sc->sc_buffered_char[1] = 0; 1714184610Salfred } 1715184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1716184610Salfred } 1717184610Salfred return (code); 1718184610Salfred 1719184610Salfred} 1720184610Salfred 1721184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1722184610Salfred 1723194099Sthompsastatic keyboard_switch_t ukbdsw = { 1724184610Salfred .probe = &ukbd__probe, 1725184610Salfred .init = &ukbd_init, 1726184610Salfred .term = &ukbd_term, 1727184610Salfred .intr = &ukbd_intr, 1728184610Salfred .test_if = &ukbd_test_if, 1729184610Salfred .enable = &ukbd_enable, 1730184610Salfred .disable = &ukbd_disable, 1731184610Salfred .read = &ukbd_read, 1732184610Salfred .check = &ukbd_check, 1733184610Salfred .read_char = &ukbd_read_char, 1734184610Salfred .check_char = &ukbd_check_char, 1735184610Salfred .ioctl = &ukbd_ioctl, 1736184610Salfred .lock = &ukbd_lock, 1737184610Salfred .clear_state = &ukbd_clear_state, 1738184610Salfred .get_state = &ukbd_get_state, 1739184610Salfred .set_state = &ukbd_set_state, 1740184610Salfred .get_fkeystr = &genkbd_get_fkeystr, 1741184610Salfred .poll = &ukbd_poll, 1742184610Salfred .diag = &genkbd_diag, 1743184610Salfred}; 1744184610Salfred 1745184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 1746184610Salfred 1747184610Salfredstatic int 1748184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 1749184610Salfred{ 1750184610Salfred switch (what) { 1751193315Sthompsa case MOD_LOAD: 1752184610Salfred kbd_add_driver(&ukbd_kbd_driver); 1753184610Salfred break; 1754184610Salfred case MOD_UNLOAD: 1755184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 1756184610Salfred break; 1757184610Salfred } 1758184610Salfred return (0); 1759184610Salfred} 1760184610Salfred 1761184610Salfredstatic devclass_t ukbd_devclass; 1762184610Salfred 1763184610Salfredstatic device_method_t ukbd_methods[] = { 1764184610Salfred DEVMETHOD(device_probe, ukbd_probe), 1765184610Salfred DEVMETHOD(device_attach, ukbd_attach), 1766184610Salfred DEVMETHOD(device_detach, ukbd_detach), 1767184610Salfred DEVMETHOD(device_resume, ukbd_resume), 1768184610Salfred {0, 0} 1769184610Salfred}; 1770184610Salfred 1771184610Salfredstatic driver_t ukbd_driver = { 1772184610Salfred .name = "ukbd", 1773184610Salfred .methods = ukbd_methods, 1774184610Salfred .size = sizeof(struct ukbd_softc), 1775184610Salfred}; 1776184610Salfred 1777189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 1778188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 1779