ukbd.c revision 305644
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: stable/11/sys/dev/usb/input/ukbd.c 305644 2016-09-09 06:36:43Z hselasky $"); 3184610Salfred 4184610Salfred 5184610Salfred/*- 6184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. 7184610Salfred * All rights reserved. 8184610Salfred * 9184610Salfred * This code is derived from software contributed to The NetBSD Foundation 10184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at 11184610Salfred * Carlstedt Research & Technology. 12184610Salfred * 13184610Salfred * Redistribution and use in source and binary forms, with or without 14184610Salfred * modification, are permitted provided that the following conditions 15184610Salfred * are met: 16184610Salfred * 1. Redistributions of source code must retain the above copyright 17184610Salfred * notice, this list of conditions and the following disclaimer. 18184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 19184610Salfred * notice, this list of conditions and the following disclaimer in the 20184610Salfred * documentation and/or other materials provided with the distribution. 21184610Salfred * 22184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32184610Salfred * POSSIBILITY OF SUCH DAMAGE. 33184610Salfred * 34184610Salfred */ 35184610Salfred 36184610Salfred/* 37184610Salfred * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 38184610Salfred */ 39184610Salfred 40184610Salfred#include "opt_compat.h" 41184610Salfred#include "opt_kbd.h" 42184610Salfred#include "opt_ukbd.h" 43184610Salfred 44194677Sthompsa#include <sys/stdint.h> 45194677Sthompsa#include <sys/stddef.h> 46194677Sthompsa#include <sys/param.h> 47194677Sthompsa#include <sys/queue.h> 48194677Sthompsa#include <sys/types.h> 49194677Sthompsa#include <sys/systm.h> 50194677Sthompsa#include <sys/kernel.h> 51194677Sthompsa#include <sys/bus.h> 52194677Sthompsa#include <sys/module.h> 53194677Sthompsa#include <sys/lock.h> 54194677Sthompsa#include <sys/mutex.h> 55194677Sthompsa#include <sys/condvar.h> 56194677Sthompsa#include <sys/sysctl.h> 57194677Sthompsa#include <sys/sx.h> 58194677Sthompsa#include <sys/unistd.h> 59194677Sthompsa#include <sys/callout.h> 60194677Sthompsa#include <sys/malloc.h> 61194677Sthompsa#include <sys/priv.h> 62223989Shselasky#include <sys/proc.h> 63223989Shselasky#include <sys/sched.h> 64198152Sthompsa#include <sys/kdb.h> 65194677Sthompsa 66188942Sthompsa#include <dev/usb/usb.h> 67194677Sthompsa#include <dev/usb/usbdi.h> 68194677Sthompsa#include <dev/usb/usbdi_util.h> 69188942Sthompsa#include <dev/usb/usbhid.h> 70184610Salfred 71184610Salfred#define USB_DEBUG_VAR ukbd_debug 72188942Sthompsa#include <dev/usb/usb_debug.h> 73184610Salfred 74188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 75184610Salfred 76184610Salfred#include <sys/ioccom.h> 77184610Salfred#include <sys/filio.h> 78184610Salfred#include <sys/tty.h> 79184610Salfred#include <sys/kbio.h> 80184610Salfred 81184610Salfred#include <dev/kbd/kbdreg.h> 82184610Salfred 83184610Salfred/* the initial key map, accent map and fkey strings */ 84184610Salfred#if defined(UKBD_DFLT_KEYMAP) && !defined(KLD_MODULE) 85184610Salfred#define KBD_DFLT_KEYMAP 86184610Salfred#include "ukbdmap.h" 87184610Salfred#endif 88184610Salfred 89184610Salfred/* the following file must be included after "ukbdmap.h" */ 90184610Salfred#include <dev/kbd/kbdtables.h> 91184610Salfred 92207077Sthompsa#ifdef USB_DEBUG 93184610Salfredstatic int ukbd_debug = 0; 94196489Salfredstatic int ukbd_no_leds = 0; 95253332Shselaskystatic int ukbd_pollrate = 0; 96184610Salfred 97253332Shselaskystatic SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB keyboard"); 98267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RWTUN, 99184610Salfred &ukbd_debug, 0, "Debug level"); 100267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RWTUN, 101196489Salfred &ukbd_no_leds, 0, "Disables setting of keyboard leds"); 102267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RWTUN, 103253332Shselasky &ukbd_pollrate, 0, "Force this polling rate, 1-1000Hz"); 104184610Salfred#endif 105184610Salfred 106184610Salfred#define UKBD_EMULATE_ATSCANCODE 1 107184610Salfred#define UKBD_DRIVER_NAME "ukbd" 108184610Salfred#define UKBD_NMOD 8 /* units */ 109184610Salfred#define UKBD_NKEYCODE 6 /* units */ 110184610Salfred#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */ 111305644Shselasky#define UKBD_IN_BUF_FULL ((UKBD_IN_BUF_SIZE / 2) - 1) /* bytes */ 112184610Salfred#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */ 113223755Shselasky#define UKBD_BUFFER_SIZE 64 /* bytes */ 114184610Salfred 115184610Salfredstruct ukbd_data { 116223755Shselasky uint16_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 125223755Shselasky/* internal */ 126223755Shselasky#define MOD_EJECT 0x0100 127223755Shselasky#define MOD_FN 0x0200 128184610Salfred uint8_t keycode[UKBD_NKEYCODE]; 129192925Sthompsa}; 130184610Salfred 131187259Sthompsaenum { 132305644Shselasky UKBD_INTR_DT_0, 133305644Shselasky UKBD_INTR_DT_1, 134187259Sthompsa UKBD_CTRL_LED, 135192925Sthompsa UKBD_N_TRANSFER, 136187259Sthompsa}; 137187259Sthompsa 138184610Salfredstruct ukbd_softc { 139184610Salfred keyboard_t sc_kbd; 140184610Salfred keymap_t sc_keymap; 141184610Salfred accentmap_t sc_accmap; 142184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 143192925Sthompsa struct hid_location sc_loc_apple_eject; 144192925Sthompsa struct hid_location sc_loc_apple_fn; 145223755Shselasky struct hid_location sc_loc_ctrl_l; 146223755Shselasky struct hid_location sc_loc_ctrl_r; 147223755Shselasky struct hid_location sc_loc_shift_l; 148223755Shselasky struct hid_location sc_loc_shift_r; 149223755Shselasky struct hid_location sc_loc_alt_l; 150223755Shselasky struct hid_location sc_loc_alt_r; 151223755Shselasky struct hid_location sc_loc_win_l; 152223755Shselasky struct hid_location sc_loc_win_r; 153223755Shselasky struct hid_location sc_loc_events; 154223755Shselasky struct hid_location sc_loc_numlock; 155223755Shselasky struct hid_location sc_loc_capslock; 156223755Shselasky struct hid_location sc_loc_scrolllock; 157192984Sthompsa struct usb_callout sc_callout; 158184610Salfred struct ukbd_data sc_ndata; 159184610Salfred struct ukbd_data sc_odata; 160184610Salfred 161203896Sthompsa struct thread *sc_poll_thread; 162192984Sthompsa struct usb_device *sc_udev; 163192984Sthompsa struct usb_interface *sc_iface; 164192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 165184610Salfred 166184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 167184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 168184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 169184610Salfred uint32_t sc_time_ms; 170184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 171184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 172184610Salfred uint32_t sc_buffered_char[2]; 173184610Salfred#endif 174184610Salfred uint32_t sc_flags; /* flags */ 175223755Shselasky#define UKBD_FLAG_COMPOSE 0x00000001 176223755Shselasky#define UKBD_FLAG_POLLING 0x00000002 177223755Shselasky#define UKBD_FLAG_SET_LEDS 0x00000004 178223755Shselasky#define UKBD_FLAG_ATTACHED 0x00000010 179223755Shselasky#define UKBD_FLAG_GONE 0x00000020 180184610Salfred 181223755Shselasky#define UKBD_FLAG_HID_MASK 0x003fffc0 182223755Shselasky#define UKBD_FLAG_APPLE_EJECT 0x00000040 183223755Shselasky#define UKBD_FLAG_APPLE_FN 0x00000080 184223755Shselasky#define UKBD_FLAG_APPLE_SWAP 0x00000100 185223755Shselasky#define UKBD_FLAG_TIMER_RUNNING 0x00000200 186223755Shselasky#define UKBD_FLAG_CTRL_L 0x00000400 187223755Shselasky#define UKBD_FLAG_CTRL_R 0x00000800 188223755Shselasky#define UKBD_FLAG_SHIFT_L 0x00001000 189223755Shselasky#define UKBD_FLAG_SHIFT_R 0x00002000 190223755Shselasky#define UKBD_FLAG_ALT_L 0x00004000 191223755Shselasky#define UKBD_FLAG_ALT_R 0x00008000 192223755Shselasky#define UKBD_FLAG_WIN_L 0x00010000 193223755Shselasky#define UKBD_FLAG_WIN_R 0x00020000 194223755Shselasky#define UKBD_FLAG_EVENTS 0x00040000 195223755Shselasky#define UKBD_FLAG_NUMLOCK 0x00080000 196223755Shselasky#define UKBD_FLAG_CAPSLOCK 0x00100000 197223755Shselasky#define UKBD_FLAG_SCROLLLOCK 0x00200000 198223755Shselasky 199203896Sthompsa int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 200203896Sthompsa int sc_state; /* shift/lock key state */ 201203896Sthompsa int sc_accents; /* accent key index (> 0) */ 202304124Shselasky int sc_polling; /* polling recursion count */ 203223755Shselasky int sc_led_size; 204223755Shselasky int sc_kbd_size; 205184610Salfred 206184610Salfred uint16_t sc_inputs; 207184610Salfred uint16_t sc_inputhead; 208184610Salfred uint16_t sc_inputtail; 209223755Shselasky uint16_t sc_modifiers; 210184610Salfred 211184610Salfred uint8_t sc_leds; /* store for async led requests */ 212184610Salfred uint8_t sc_iface_index; 213184610Salfred uint8_t sc_iface_no; 214223755Shselasky uint8_t sc_id_apple_eject; 215223755Shselasky uint8_t sc_id_apple_fn; 216223755Shselasky uint8_t sc_id_ctrl_l; 217223755Shselasky uint8_t sc_id_ctrl_r; 218223755Shselasky uint8_t sc_id_shift_l; 219223755Shselasky uint8_t sc_id_shift_r; 220223755Shselasky uint8_t sc_id_alt_l; 221223755Shselasky uint8_t sc_id_alt_r; 222223755Shselasky uint8_t sc_id_win_l; 223223755Shselasky uint8_t sc_id_win_r; 224223755Shselasky uint8_t sc_id_event; 225223755Shselasky uint8_t sc_id_numlock; 226223755Shselasky uint8_t sc_id_capslock; 227223755Shselasky uint8_t sc_id_scrolllock; 228223755Shselasky uint8_t sc_id_events; 229192925Sthompsa uint8_t sc_kbd_id; 230223755Shselasky 231223755Shselasky uint8_t sc_buffer[UKBD_BUFFER_SIZE]; 232184610Salfred}; 233184610Salfred 234184610Salfred#define KEY_ERROR 0x01 235184610Salfred 236184610Salfred#define KEY_PRESS 0 237184610Salfred#define KEY_RELEASE 0x400 238184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 239184610Salfred 240184610Salfred#define SCAN_PRESS 0 241184610Salfred#define SCAN_RELEASE 0x80 242184610Salfred#define SCAN_PREFIX_E0 0x100 243184610Salfred#define SCAN_PREFIX_E1 0x200 244184610Salfred#define SCAN_PREFIX_CTL 0x400 245184610Salfred#define SCAN_PREFIX_SHIFT 0x800 246184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 247184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 248184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 249184610Salfred 250228765Savg#define UKBD_LOCK() mtx_lock(&Giant) 251228765Savg#define UKBD_UNLOCK() mtx_unlock(&Giant) 252228765Savg 253228765Savg#ifdef INVARIANTS 254228765Savg 255228765Savg/* 256228765Savg * Assert that the lock is held in all contexts 257228765Savg * where the code can be executed. 258228765Savg */ 259228765Savg#define UKBD_LOCK_ASSERT() mtx_assert(&Giant, MA_OWNED) 260228765Savg 261228765Savg/* 262228765Savg * Assert that the lock is held in the contexts 263228765Savg * where it really has to be so. 264228765Savg */ 265228765Savg#define UKBD_CTX_LOCK_ASSERT() \ 266228765Savg do { \ 267228765Savg if (!kdb_active && panicstr == NULL) \ 268228765Savg mtx_assert(&Giant, MA_OWNED); \ 269228765Savg } while (0) 270228765Savg#else 271228765Savg 272228765Savg#define UKBD_LOCK_ASSERT() (void)0 273228765Savg#define UKBD_CTX_LOCK_ASSERT() (void)0 274228765Savg 275228765Savg#endif 276228765Savg 277184610Salfredstruct ukbd_mods { 278184610Salfred uint32_t mask, key; 279184610Salfred}; 280184610Salfred 281184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 282184610Salfred {MOD_CONTROL_L, 0xe0}, 283184610Salfred {MOD_CONTROL_R, 0xe4}, 284184610Salfred {MOD_SHIFT_L, 0xe1}, 285184610Salfred {MOD_SHIFT_R, 0xe5}, 286184610Salfred {MOD_ALT_L, 0xe2}, 287184610Salfred {MOD_ALT_R, 0xe6}, 288184610Salfred {MOD_WIN_L, 0xe3}, 289184610Salfred {MOD_WIN_R, 0xe7}, 290184610Salfred}; 291184610Salfred 292184610Salfred#define NN 0 /* no translation */ 293184610Salfred/* 294184610Salfred * Translate USB keycodes to AT keyboard scancodes. 295184610Salfred */ 296184610Salfred/* 297184610Salfred * FIXME: Mac USB keyboard generates: 298184610Salfred * 0x53: keypad NumLock/Clear 299184610Salfred * 0x66: Power 300184610Salfred * 0x67: keypad = 301184610Salfred * 0x68: F13 302184610Salfred * 0x69: F14 303184610Salfred * 0x6a: F15 304291146Shselasky * 305291146Shselasky * USB Apple Keyboard JIS generates: 306291146Shselasky * 0x90: Kana 307291146Shselasky * 0x91: Eisu 308184610Salfred */ 309184610Salfredstatic const uint8_t ukbd_trtab[256] = { 310184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 311184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 312184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 313184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 314184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 315184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 316184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 317184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 318184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 319184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 320184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 321184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 322184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 323184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 324184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 325184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 326197999Shrs 121, 120, NN, NN, NN, NN, NN, 123, /* 80 - 87 */ 327197999Shrs 124, 125, 126, 127, 128, NN, NN, NN, /* 88 - 8F */ 328291146Shselasky 129, 130, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 329184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 330184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 331184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 332184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 333184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 334184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 335184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 336184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 337184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 338184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 339184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 340184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 341184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 342184610Salfred}; 343184610Salfred 344223755Shselaskystatic const uint8_t ukbd_boot_desc[] = { 345223755Shselasky 0x05, 0x01, 0x09, 0x06, 0xa1, 346223755Shselasky 0x01, 0x05, 0x07, 0x19, 0xe0, 347223755Shselasky 0x29, 0xe7, 0x15, 0x00, 0x25, 348223755Shselasky 0x01, 0x75, 0x01, 0x95, 0x08, 349223755Shselasky 0x81, 0x02, 0x95, 0x01, 0x75, 350223755Shselasky 0x08, 0x81, 0x01, 0x95, 0x03, 351223755Shselasky 0x75, 0x01, 0x05, 0x08, 0x19, 352223755Shselasky 0x01, 0x29, 0x03, 0x91, 0x02, 353223755Shselasky 0x95, 0x05, 0x75, 0x01, 0x91, 354223755Shselasky 0x01, 0x95, 0x06, 0x75, 0x08, 355223755Shselasky 0x15, 0x00, 0x26, 0xff, 0x00, 356223755Shselasky 0x05, 0x07, 0x19, 0x00, 0x2a, 357223755Shselasky 0xff, 0x00, 0x81, 0x00, 0xc0 358223755Shselasky}; 359223755Shselasky 360184610Salfred/* prototypes */ 361185948Sthompsastatic void ukbd_timeout(void *); 362185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 363185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 364184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 365185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 366184610Salfred#endif 367185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 368185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 369185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 370185948Sthompsastatic int ukbd_enable(keyboard_t *); 371185948Sthompsastatic int ukbd_disable(keyboard_t *); 372185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 373203896Sthompsastatic void ukbd_event_keyinput(struct ukbd_softc *); 374184610Salfred 375184610Salfredstatic device_probe_t ukbd_probe; 376184610Salfredstatic device_attach_t ukbd_attach; 377184610Salfredstatic device_detach_t ukbd_detach; 378184610Salfredstatic device_resume_t ukbd_resume; 379184610Salfred 380196489Salfredstatic uint8_t 381196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc) 382196489Salfred{ 383196489Salfred uint8_t i; 384196489Salfred uint8_t j; 385196489Salfred 386196489Salfred for (j = i = 0; i < UKBD_NKEYCODE; i++) 387196489Salfred j |= sc->sc_odata.keycode[i]; 388196489Salfred 389196489Salfred return (j ? 1 : 0); 390196489Salfred} 391196489Salfred 392184610Salfredstatic void 393196489Salfredukbd_start_timer(struct ukbd_softc *sc) 394196489Salfred{ 395196489Salfred sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; 396196489Salfred usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 397196489Salfred} 398196489Salfred 399196489Salfredstatic void 400184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 401184610Salfred{ 402184610Salfred 403228765Savg UKBD_CTX_LOCK_ASSERT(); 404228765Savg 405184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 406184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 407184610Salfred 408184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 409184610Salfred sc->sc_input[sc->sc_inputtail] = key; 410184610Salfred ++(sc->sc_inputs); 411184610Salfred ++(sc->sc_inputtail); 412184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 413184610Salfred sc->sc_inputtail = 0; 414184610Salfred } 415184610Salfred } else { 416184610Salfred DPRINTF("input buffer is full\n"); 417184610Salfred } 418184610Salfred} 419184610Salfred 420195960Salfredstatic void 421228765Savgukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 422223989Shselasky{ 423223989Shselasky 424228765Savg UKBD_CTX_LOCK_ASSERT(); 425228765Savg KASSERT((sc->sc_flags & UKBD_FLAG_POLLING) != 0, 426228765Savg ("ukbd_do_poll called when not polling\n")); 427195960Salfred DPRINTFN(2, "polling\n"); 428195960Salfred 429228765Savg if (!kdb_active && !SCHEDULER_STOPPED()) { 430228765Savg /* 431228765Savg * In this context the kernel is polling for input, 432228765Savg * but the USB subsystem works in normal interrupt-driven 433228765Savg * mode, so we just wait on the USB threads to do the job. 434228765Savg * Note that we currently hold the Giant, but it's also used 435228765Savg * as the transfer mtx, so we must release it while waiting. 436228765Savg */ 437203896Sthompsa while (sc->sc_inputs == 0) { 438228765Savg /* 439228765Savg * Give USB threads a chance to run. Note that 440228765Savg * kern_yield performs DROP_GIANT + PICKUP_GIANT. 441228765Savg */ 442228765Savg kern_yield(PRI_UNCHANGED); 443203896Sthompsa if (!wait) 444203896Sthompsa break; 445203896Sthompsa } 446228765Savg return; 447203896Sthompsa } 448198152Sthompsa 449195960Salfred while (sc->sc_inputs == 0) { 450195960Salfred 451195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 452195960Salfred 453196489Salfred /* Delay-optimised support for repetition of keys */ 454196489Salfred if (ukbd_any_key_pressed(sc)) { 455196489Salfred /* a key is pressed - need timekeeping */ 456196489Salfred DELAY(1000); 457195960Salfred 458196489Salfred /* 1 millisecond has passed */ 459196489Salfred sc->sc_time_ms += 1; 460196489Salfred } 461195960Salfred 462195960Salfred ukbd_interrupt(sc); 463195960Salfred 464195960Salfred if (!wait) 465195960Salfred break; 466195960Salfred } 467195960Salfred} 468195960Salfred 469184610Salfredstatic int32_t 470184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 471184610Salfred{ 472184610Salfred int32_t c; 473184610Salfred 474228765Savg UKBD_CTX_LOCK_ASSERT(); 475228765Savg KASSERT((!kdb_active && !SCHEDULER_STOPPED()) 476228765Savg || (sc->sc_flags & UKBD_FLAG_POLLING) != 0, 477228765Savg ("not polling in kdb or panic\n")); 478184610Salfred 479261228Shselasky if (sc->sc_inputs == 0 && 480261228Shselasky (sc->sc_flags & UKBD_FLAG_GONE) == 0) { 481184610Salfred /* start transfer, if not already started */ 482305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 483305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 484184610Salfred } 485203896Sthompsa 486203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 487195960Salfred ukbd_do_poll(sc, wait); 488203896Sthompsa 489184610Salfred if (sc->sc_inputs == 0) { 490184610Salfred c = -1; 491184610Salfred } else { 492184610Salfred c = sc->sc_input[sc->sc_inputhead]; 493184610Salfred --(sc->sc_inputs); 494184610Salfred ++(sc->sc_inputhead); 495184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 496184610Salfred sc->sc_inputhead = 0; 497184610Salfred } 498184610Salfred } 499184610Salfred return (c); 500184610Salfred} 501184610Salfred 502184610Salfredstatic void 503184610Salfredukbd_interrupt(struct ukbd_softc *sc) 504184610Salfred{ 505184610Salfred uint32_t n_mod; 506184610Salfred uint32_t o_mod; 507184610Salfred uint32_t now = sc->sc_time_ms; 508184610Salfred uint32_t dtime; 509184610Salfred uint8_t key; 510184610Salfred uint8_t i; 511184610Salfred uint8_t j; 512184610Salfred 513228765Savg UKBD_CTX_LOCK_ASSERT(); 514228765Savg 515203896Sthompsa if (sc->sc_ndata.keycode[0] == KEY_ERROR) 516203896Sthompsa return; 517203896Sthompsa 518184610Salfred n_mod = sc->sc_ndata.modifiers; 519184610Salfred o_mod = sc->sc_odata.modifiers; 520184610Salfred if (n_mod != o_mod) { 521184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 522184610Salfred if ((n_mod & ukbd_mods[i].mask) != 523184610Salfred (o_mod & ukbd_mods[i].mask)) { 524184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 525184610Salfred ((n_mod & ukbd_mods[i].mask) ? 526184610Salfred KEY_PRESS : KEY_RELEASE)); 527184610Salfred } 528184610Salfred } 529184610Salfred } 530184610Salfred /* Check for released keys. */ 531184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 532184610Salfred key = sc->sc_odata.keycode[i]; 533184610Salfred if (key == 0) { 534184610Salfred continue; 535184610Salfred } 536184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 537184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 538184610Salfred continue; 539184610Salfred } 540184610Salfred if (key == sc->sc_ndata.keycode[j]) { 541184610Salfred goto rfound; 542184610Salfred } 543184610Salfred } 544184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 545184610Salfredrfound: ; 546184610Salfred } 547184610Salfred 548184610Salfred /* Check for pressed keys. */ 549184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 550184610Salfred key = sc->sc_ndata.keycode[i]; 551184610Salfred if (key == 0) { 552184610Salfred continue; 553184610Salfred } 554184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 555184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 556184610Salfred if (sc->sc_odata.keycode[j] == 0) { 557184610Salfred continue; 558184610Salfred } 559184610Salfred if (key == sc->sc_odata.keycode[j]) { 560184610Salfred 561184610Salfred /* key is still pressed */ 562184610Salfred 563184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 564184610Salfred dtime = (sc->sc_otime[j] - now); 565184610Salfred 566184610Salfred if (!(dtime & 0x80000000)) { 567184610Salfred /* time has not elapsed */ 568184610Salfred goto pfound; 569184610Salfred } 570184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 571184610Salfred break; 572184610Salfred } 573184610Salfred } 574184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 575184610Salfred 576184610Salfred /* 577184610Salfred * If any other key is presently down, force its repeat to be 578184610Salfred * well in the future (100s). This makes the last key to be 579184610Salfred * pressed do the autorepeat. 580184610Salfred */ 581184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 582184610Salfred if (j != i) 583184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 584184610Salfred } 585184610Salfredpfound: ; 586184610Salfred } 587184610Salfred 588184610Salfred sc->sc_odata = sc->sc_ndata; 589184610Salfred 590203896Sthompsa memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime)); 591184610Salfred 592203896Sthompsa ukbd_event_keyinput(sc); 593203896Sthompsa} 594203896Sthompsa 595203896Sthompsastatic void 596203896Sthompsaukbd_event_keyinput(struct ukbd_softc *sc) 597203896Sthompsa{ 598203896Sthompsa int c; 599203896Sthompsa 600228765Savg UKBD_CTX_LOCK_ASSERT(); 601228765Savg 602228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) != 0) 603203896Sthompsa return; 604203896Sthompsa 605203896Sthompsa if (sc->sc_inputs == 0) 606203896Sthompsa return; 607203896Sthompsa 608184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 609184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 610184610Salfred /* let the callback function process the input */ 611184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 612184610Salfred sc->sc_kbd.kb_callback.kc_arg); 613184610Salfred } else { 614184610Salfred /* read and discard the input, no one is waiting for it */ 615184610Salfred do { 616184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 617184610Salfred } while (c != NOKEY); 618184610Salfred } 619184610Salfred} 620184610Salfred 621184610Salfredstatic void 622184610Salfredukbd_timeout(void *arg) 623184610Salfred{ 624184610Salfred struct ukbd_softc *sc = arg; 625184610Salfred 626228765Savg UKBD_LOCK_ASSERT(); 627184610Salfred 628203896Sthompsa sc->sc_time_ms += 25; /* milliseconds */ 629203896Sthompsa 630184610Salfred ukbd_interrupt(sc); 631184610Salfred 632203896Sthompsa /* Make sure any leftover key events gets read out */ 633203896Sthompsa ukbd_event_keyinput(sc); 634203896Sthompsa 635203896Sthompsa if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { 636196489Salfred ukbd_start_timer(sc); 637196489Salfred } else { 638196489Salfred sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; 639196489Salfred } 640184610Salfred} 641184610Salfred 642192925Sthompsastatic uint8_t 643192925Sthompsaukbd_apple_fn(uint8_t keycode) { 644192925Sthompsa switch (keycode) { 645192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 646192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 647192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 648192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 649192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 650192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 651192925Sthompsa default: return keycode; 652192925Sthompsa } 653192925Sthompsa} 654184610Salfred 655192925Sthompsastatic uint8_t 656192925Sthompsaukbd_apple_swap(uint8_t keycode) { 657192925Sthompsa switch (keycode) { 658192925Sthompsa case 0x35: return 0x64; 659192925Sthompsa case 0x64: return 0x35; 660192925Sthompsa default: return keycode; 661184610Salfred } 662184610Salfred} 663184610Salfred 664184610Salfredstatic void 665194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 666184610Salfred{ 667194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 668194677Sthompsa struct usb_page_cache *pc; 669184610Salfred uint8_t i; 670192925Sthompsa uint8_t offset; 671192925Sthompsa uint8_t id; 672194677Sthompsa int len; 673184610Salfred 674228765Savg UKBD_LOCK_ASSERT(); 675228765Savg 676194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 677194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 678194677Sthompsa 679184610Salfred switch (USB_GET_STATE(xfer)) { 680184610Salfred case USB_ST_TRANSFERRED: 681184610Salfred DPRINTF("actlen=%d bytes\n", len); 682184610Salfred 683192925Sthompsa if (len == 0) { 684192925Sthompsa DPRINTF("zero length data\n"); 685192925Sthompsa goto tr_setup; 686192925Sthompsa } 687192925Sthompsa 688192925Sthompsa if (sc->sc_kbd_id != 0) { 689192925Sthompsa /* check and remove HID ID byte */ 690194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 691223755Shselasky offset = 1; 692223755Shselasky len--; 693223755Shselasky if (len == 0) { 694223755Shselasky DPRINTF("zero length data\n"); 695192925Sthompsa goto tr_setup; 696192925Sthompsa } 697192925Sthompsa } else { 698192925Sthompsa offset = 0; 699223755Shselasky id = 0; 700192925Sthompsa } 701192925Sthompsa 702223755Shselasky if (len > UKBD_BUFFER_SIZE) 703223755Shselasky len = UKBD_BUFFER_SIZE; 704192925Sthompsa 705223755Shselasky /* get data */ 706223755Shselasky usbd_copy_out(pc, offset, sc->sc_buffer, len); 707192925Sthompsa 708223755Shselasky /* clear temporary storage */ 709223755Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 710192925Sthompsa 711223755Shselasky /* scan through HID data */ 712223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 713223755Shselasky (id == sc->sc_id_apple_eject)) { 714223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject)) 715223755Shselasky sc->sc_modifiers |= MOD_EJECT; 716192925Sthompsa else 717223755Shselasky sc->sc_modifiers &= ~MOD_EJECT; 718223755Shselasky } 719223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 720223755Shselasky (id == sc->sc_id_apple_fn)) { 721223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn)) 722223755Shselasky sc->sc_modifiers |= MOD_FN; 723223755Shselasky else 724223755Shselasky sc->sc_modifiers &= ~MOD_FN; 725223755Shselasky } 726223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_L) && 727223755Shselasky (id == sc->sc_id_ctrl_l)) { 728223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_l)) 729223755Shselasky sc-> sc_modifiers |= MOD_CONTROL_L; 730223755Shselasky else 731223755Shselasky sc-> sc_modifiers &= ~MOD_CONTROL_L; 732223755Shselasky } 733223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_R) && 734223755Shselasky (id == sc->sc_id_ctrl_r)) { 735223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_r)) 736223755Shselasky sc->sc_modifiers |= MOD_CONTROL_R; 737223755Shselasky else 738223755Shselasky sc->sc_modifiers &= ~MOD_CONTROL_R; 739223755Shselasky } 740223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) && 741223755Shselasky (id == sc->sc_id_shift_l)) { 742223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_l)) 743223755Shselasky sc->sc_modifiers |= MOD_SHIFT_L; 744223755Shselasky else 745223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_L; 746223755Shselasky } 747223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) && 748223755Shselasky (id == sc->sc_id_shift_r)) { 749223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_r)) 750223755Shselasky sc->sc_modifiers |= MOD_SHIFT_R; 751223755Shselasky else 752223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_R; 753223755Shselasky } 754223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_L) && 755223755Shselasky (id == sc->sc_id_alt_l)) { 756223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l)) 757223755Shselasky sc->sc_modifiers |= MOD_ALT_L; 758223755Shselasky else 759223755Shselasky sc->sc_modifiers &= ~MOD_ALT_L; 760223755Shselasky } 761223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_R) && 762223755Shselasky (id == sc->sc_id_alt_r)) { 763223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r)) 764223755Shselasky sc->sc_modifiers |= MOD_ALT_R; 765223755Shselasky else 766223755Shselasky sc->sc_modifiers &= ~MOD_ALT_R; 767223755Shselasky } 768223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_L) && 769223755Shselasky (id == sc->sc_id_win_l)) { 770223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l)) 771223755Shselasky sc->sc_modifiers |= MOD_WIN_L; 772223755Shselasky else 773223755Shselasky sc->sc_modifiers &= ~MOD_WIN_L; 774223755Shselasky } 775223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_R) && 776223755Shselasky (id == sc->sc_id_win_r)) { 777223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r)) 778223755Shselasky sc->sc_modifiers |= MOD_WIN_R; 779223755Shselasky else 780223755Shselasky sc->sc_modifiers &= ~MOD_WIN_R; 781223755Shselasky } 782192925Sthompsa 783223755Shselasky sc->sc_ndata.modifiers = sc->sc_modifiers; 784223755Shselasky 785223755Shselasky if ((sc->sc_flags & UKBD_FLAG_EVENTS) && 786223755Shselasky (id == sc->sc_id_events)) { 787223755Shselasky i = sc->sc_loc_events.count; 788223755Shselasky if (i > UKBD_NKEYCODE) 789223755Shselasky i = UKBD_NKEYCODE; 790223755Shselasky if (i > len) 791223755Shselasky i = len; 792223755Shselasky while (i--) { 793223755Shselasky sc->sc_ndata.keycode[i] = 794223755Shselasky hid_get_data(sc->sc_buffer + i, len - i, 795223755Shselasky &sc->sc_loc_events); 796184610Salfred } 797223755Shselasky } 798223755Shselasky 799223755Shselasky#ifdef USB_DEBUG 800223755Shselasky DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers); 801223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 802223755Shselasky if (sc->sc_ndata.keycode[i]) { 803223755Shselasky DPRINTF("[%d] = 0x%02x\n", 804223755Shselasky (int)i, (int)sc->sc_ndata.keycode[i]); 805223755Shselasky } 806223755Shselasky } 807223755Shselasky#endif 808223755Shselasky if (sc->sc_modifiers & MOD_FN) { 809184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 810223755Shselasky sc->sc_ndata.keycode[i] = 811223755Shselasky ukbd_apple_fn(sc->sc_ndata.keycode[i]); 812184610Salfred } 813223755Shselasky } 814192925Sthompsa 815223755Shselasky if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 816223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 817223755Shselasky sc->sc_ndata.keycode[i] = 818223755Shselasky ukbd_apple_swap(sc->sc_ndata.keycode[i]); 819192925Sthompsa } 820223755Shselasky } 821192925Sthompsa 822223755Shselasky ukbd_interrupt(sc); 823192925Sthompsa 824223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { 825223755Shselasky if (ukbd_any_key_pressed(sc)) { 826223755Shselasky ukbd_start_timer(sc); 827196489Salfred } 828184610Salfred } 829223755Shselasky 830184610Salfred case USB_ST_SETUP: 831192925Sthompsatr_setup: 832184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 833194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 834194228Sthompsa usbd_transfer_submit(xfer); 835184610Salfred } else { 836184610Salfred DPRINTF("input queue is full!\n"); 837184610Salfred } 838192925Sthompsa break; 839184610Salfred 840184610Salfred default: /* Error */ 841194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 842184610Salfred 843194677Sthompsa if (error != USB_ERR_CANCELLED) { 844184610Salfred /* try to clear stall first */ 845194677Sthompsa usbd_xfer_set_stall(xfer); 846192925Sthompsa goto tr_setup; 847184610Salfred } 848192925Sthompsa break; 849184610Salfred } 850184610Salfred} 851184610Salfred 852184610Salfredstatic void 853194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 854184610Salfred{ 855223755Shselasky struct ukbd_softc *sc = usbd_xfer_softc(xfer); 856192984Sthompsa struct usb_device_request req; 857194677Sthompsa struct usb_page_cache *pc; 858223755Shselasky uint8_t id; 859223755Shselasky uint8_t any; 860223755Shselasky int len; 861184610Salfred 862228765Savg UKBD_LOCK_ASSERT(); 863228765Savg 864207077Sthompsa#ifdef USB_DEBUG 865196489Salfred if (ukbd_no_leds) 866196489Salfred return; 867196489Salfred#endif 868196489Salfred 869184610Salfred switch (USB_GET_STATE(xfer)) { 870184610Salfred case USB_ST_TRANSFERRED: 871184610Salfred case USB_ST_SETUP: 872223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS)) 873223755Shselasky break; 874223755Shselasky sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 875184610Salfred 876223755Shselasky req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 877223755Shselasky req.bRequest = UR_SET_REPORT; 878223755Shselasky USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 879223755Shselasky req.wIndex[0] = sc->sc_iface_no; 880223755Shselasky req.wIndex[1] = 0; 881223755Shselasky req.wLength[1] = 0; 882184610Salfred 883223755Shselasky memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE); 884223755Shselasky 885223755Shselasky id = 0; 886223755Shselasky any = 0; 887223755Shselasky 888223755Shselasky /* Assumption: All led bits must be in the same ID. */ 889223755Shselasky 890223755Shselasky if (sc->sc_flags & UKBD_FLAG_NUMLOCK) { 891223755Shselasky if (sc->sc_leds & NLKED) { 892223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 893223755Shselasky &sc->sc_loc_numlock, 1); 894192925Sthompsa } 895223755Shselasky id = sc->sc_id_numlock; 896223755Shselasky any = 1; 897223755Shselasky } 898184610Salfred 899223755Shselasky if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) { 900223755Shselasky if (sc->sc_leds & SLKED) { 901223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 902223755Shselasky &sc->sc_loc_scrolllock, 1); 903223755Shselasky } 904223755Shselasky id = sc->sc_id_scrolllock; 905223755Shselasky any = 1; 906223755Shselasky } 907184610Salfred 908223755Shselasky if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) { 909223755Shselasky if (sc->sc_leds & CLKED) { 910223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 911223755Shselasky &sc->sc_loc_capslock, 1); 912223755Shselasky } 913223755Shselasky id = sc->sc_id_capslock; 914223755Shselasky any = 1; 915184610Salfred } 916223755Shselasky 917223755Shselasky /* if no leds, nothing to do */ 918223755Shselasky if (!any) 919223755Shselasky break; 920223755Shselasky 921223755Shselasky /* range check output report length */ 922223755Shselasky len = sc->sc_led_size; 923223755Shselasky if (len > (UKBD_BUFFER_SIZE - 1)) 924223755Shselasky len = (UKBD_BUFFER_SIZE - 1); 925223755Shselasky 926223755Shselasky /* check if we need to prefix an ID byte */ 927223755Shselasky sc->sc_buffer[0] = id; 928223755Shselasky 929223755Shselasky pc = usbd_xfer_get_frame(xfer, 1); 930223755Shselasky if (id != 0) { 931223755Shselasky len++; 932223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer, len); 933223755Shselasky } else { 934223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer + 1, len); 935223755Shselasky } 936223755Shselasky req.wLength[0] = len; 937223755Shselasky usbd_xfer_set_frame_len(xfer, 1, len); 938223755Shselasky 939223755Shselasky DPRINTF("len=%d, id=%d\n", len, id); 940223755Shselasky 941223755Shselasky /* setup control request last */ 942223755Shselasky pc = usbd_xfer_get_frame(xfer, 0); 943223755Shselasky usbd_copy_in(pc, 0, &req, sizeof(req)); 944223755Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 945223755Shselasky 946223755Shselasky /* start data transfer */ 947223755Shselasky usbd_xfer_set_frames(xfer, 2); 948223755Shselasky usbd_transfer_submit(xfer); 949196489Salfred break; 950184610Salfred 951184610Salfred default: /* Error */ 952212128Sthompsa DPRINTFN(1, "error=%s\n", usbd_errstr(error)); 953196489Salfred break; 954184610Salfred } 955184610Salfred} 956184610Salfred 957192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 958184610Salfred 959305644Shselasky [UKBD_INTR_DT_0] = { 960184610Salfred .type = UE_INTERRUPT, 961184610Salfred .endpoint = UE_ADDR_ANY, 962184610Salfred .direction = UE_DIR_IN, 963190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 964190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 965190734Sthompsa .callback = &ukbd_intr_callback, 966184610Salfred }, 967184610Salfred 968305644Shselasky [UKBD_INTR_DT_1] = { 969305644Shselasky .type = UE_INTERRUPT, 970305644Shselasky .endpoint = UE_ADDR_ANY, 971305644Shselasky .direction = UE_DIR_IN, 972305644Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 973305644Shselasky .bufsize = 0, /* use wMaxPacketSize */ 974305644Shselasky .callback = &ukbd_intr_callback, 975305644Shselasky }, 976305644Shselasky 977187259Sthompsa [UKBD_CTRL_LED] = { 978184610Salfred .type = UE_CONTROL, 979184610Salfred .endpoint = 0x00, /* Control pipe */ 980184610Salfred .direction = UE_DIR_ANY, 981223755Shselasky .bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE, 982190734Sthompsa .callback = &ukbd_set_leds_callback, 983190734Sthompsa .timeout = 1000, /* 1 second */ 984184610Salfred }, 985184610Salfred}; 986184610Salfred 987223521Shselasky/* A match on these entries will load ukbd */ 988223521Shselaskystatic const STRUCT_USB_HOST_ID __used ukbd_devs[] = { 989223521Shselasky {USB_IFACE_CLASS(UICLASS_HID), 990223521Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), 991223521Shselasky USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),}, 992223521Shselasky}; 993223521Shselasky 994184610Salfredstatic int 995184610Salfredukbd_probe(device_t dev) 996184610Salfred{ 997184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 998192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 999194067Sthompsa void *d_ptr; 1000194067Sthompsa int error; 1001194067Sthompsa uint16_t d_len; 1002184610Salfred 1003228765Savg UKBD_LOCK_ASSERT(); 1004184610Salfred DPRINTFN(11, "\n"); 1005184610Salfred 1006184610Salfred if (sw == NULL) { 1007184610Salfred return (ENXIO); 1008184610Salfred } 1009192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 1010184610Salfred return (ENXIO); 1011184610Salfred } 1012194067Sthompsa 1013194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 1014194067Sthompsa return (ENXIO); 1015194067Sthompsa 1016245248Shselasky if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 1017245248Shselasky return (ENXIO); 1018245248Shselasky 1019194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 1020245248Shselasky (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) 1021245248Shselasky return (BUS_PROBE_DEFAULT); 1022194067Sthompsa 1023194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 1024194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 1025194067Sthompsa 1026194067Sthompsa if (error) 1027194067Sthompsa return (ENXIO); 1028194067Sthompsa 1029245248Shselasky if (hid_is_keyboard(d_ptr, d_len)) { 1030245248Shselasky if (hid_is_mouse(d_ptr, d_len)) { 1031245248Shselasky /* 1032245248Shselasky * NOTE: We currently don't support USB mouse 1033245248Shselasky * and USB keyboard on the same USB endpoint. 1034245248Shselasky * Let "ums" driver win. 1035245248Shselasky */ 1036194067Sthompsa error = ENXIO; 1037245248Shselasky } else { 1038222051Savg error = BUS_PROBE_DEFAULT; 1039245248Shselasky } 1040245248Shselasky } else { 1041194067Sthompsa error = ENXIO; 1042245248Shselasky } 1043194067Sthompsa free(d_ptr, M_TEMP); 1044194067Sthompsa return (error); 1045184610Salfred} 1046184610Salfred 1047223755Shselaskystatic void 1048223755Shselaskyukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len) 1049223755Shselasky{ 1050223755Shselasky uint32_t flags; 1051223755Shselasky 1052223755Shselasky /* reset detected bits */ 1053223755Shselasky sc->sc_flags &= ~UKBD_FLAG_HID_MASK; 1054223755Shselasky 1055223755Shselasky /* check if there is an ID byte */ 1056223755Shselasky sc->sc_kbd_size = hid_report_size(ptr, len, 1057223755Shselasky hid_input, &sc->sc_kbd_id); 1058223755Shselasky 1059223755Shselasky /* investigate if this is an Apple Keyboard */ 1060223755Shselasky if (hid_locate(ptr, len, 1061223755Shselasky HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 1062223755Shselasky hid_input, 0, &sc->sc_loc_apple_eject, &flags, 1063223755Shselasky &sc->sc_id_apple_eject)) { 1064223755Shselasky if (flags & HIO_VARIABLE) 1065223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 1066223755Shselasky UKBD_FLAG_APPLE_SWAP; 1067223755Shselasky DPRINTFN(1, "Found Apple eject-key\n"); 1068223755Shselasky } 1069223755Shselasky if (hid_locate(ptr, len, 1070223755Shselasky HID_USAGE2(0xFFFF, 0x0003), 1071223755Shselasky hid_input, 0, &sc->sc_loc_apple_fn, &flags, 1072223755Shselasky &sc->sc_id_apple_fn)) { 1073223755Shselasky if (flags & HIO_VARIABLE) 1074223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_FN; 1075223755Shselasky DPRINTFN(1, "Found Apple FN-key\n"); 1076223755Shselasky } 1077223755Shselasky /* figure out some keys */ 1078223755Shselasky if (hid_locate(ptr, len, 1079223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE0), 1080223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_l, &flags, 1081223755Shselasky &sc->sc_id_ctrl_l)) { 1082223755Shselasky if (flags & HIO_VARIABLE) 1083223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_L; 1084223755Shselasky DPRINTFN(1, "Found left control\n"); 1085223755Shselasky } 1086223755Shselasky if (hid_locate(ptr, len, 1087223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE4), 1088223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_r, &flags, 1089223755Shselasky &sc->sc_id_ctrl_r)) { 1090223755Shselasky if (flags & HIO_VARIABLE) 1091223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_R; 1092223755Shselasky DPRINTFN(1, "Found right control\n"); 1093223755Shselasky } 1094223755Shselasky if (hid_locate(ptr, len, 1095223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE1), 1096223755Shselasky hid_input, 0, &sc->sc_loc_shift_l, &flags, 1097223755Shselasky &sc->sc_id_shift_l)) { 1098223755Shselasky if (flags & HIO_VARIABLE) 1099223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_L; 1100223755Shselasky DPRINTFN(1, "Found left shift\n"); 1101223755Shselasky } 1102223755Shselasky if (hid_locate(ptr, len, 1103223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE5), 1104223755Shselasky hid_input, 0, &sc->sc_loc_shift_r, &flags, 1105223755Shselasky &sc->sc_id_shift_r)) { 1106223755Shselasky if (flags & HIO_VARIABLE) 1107223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_R; 1108223755Shselasky DPRINTFN(1, "Found right shift\n"); 1109223755Shselasky } 1110223755Shselasky if (hid_locate(ptr, len, 1111223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE2), 1112223755Shselasky hid_input, 0, &sc->sc_loc_alt_l, &flags, 1113223755Shselasky &sc->sc_id_alt_l)) { 1114223755Shselasky if (flags & HIO_VARIABLE) 1115223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_L; 1116223755Shselasky DPRINTFN(1, "Found left alt\n"); 1117223755Shselasky } 1118223755Shselasky if (hid_locate(ptr, len, 1119223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE6), 1120223755Shselasky hid_input, 0, &sc->sc_loc_alt_r, &flags, 1121223755Shselasky &sc->sc_id_alt_r)) { 1122223755Shselasky if (flags & HIO_VARIABLE) 1123223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_R; 1124223755Shselasky DPRINTFN(1, "Found right alt\n"); 1125223755Shselasky } 1126223755Shselasky if (hid_locate(ptr, len, 1127223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE3), 1128223755Shselasky hid_input, 0, &sc->sc_loc_win_l, &flags, 1129223755Shselasky &sc->sc_id_win_l)) { 1130223755Shselasky if (flags & HIO_VARIABLE) 1131223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_L; 1132223755Shselasky DPRINTFN(1, "Found left GUI\n"); 1133223755Shselasky } 1134223755Shselasky if (hid_locate(ptr, len, 1135223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE7), 1136223755Shselasky hid_input, 0, &sc->sc_loc_win_r, &flags, 1137223755Shselasky &sc->sc_id_win_r)) { 1138223755Shselasky if (flags & HIO_VARIABLE) 1139223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_R; 1140223755Shselasky DPRINTFN(1, "Found right GUI\n"); 1141223755Shselasky } 1142223755Shselasky /* figure out event buffer */ 1143223755Shselasky if (hid_locate(ptr, len, 1144223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0x00), 1145223755Shselasky hid_input, 0, &sc->sc_loc_events, &flags, 1146223755Shselasky &sc->sc_id_events)) { 1147254572Shselasky if (flags & HIO_VARIABLE) { 1148254572Shselasky DPRINTFN(1, "Ignoring keyboard event control\n"); 1149254572Shselasky } else { 1150254572Shselasky sc->sc_flags |= UKBD_FLAG_EVENTS; 1151254572Shselasky DPRINTFN(1, "Found keyboard event array\n"); 1152254572Shselasky } 1153223755Shselasky } 1154223755Shselasky 1155223755Shselasky /* figure out leds on keyboard */ 1156223755Shselasky sc->sc_led_size = hid_report_size(ptr, len, 1157223755Shselasky hid_output, NULL); 1158223755Shselasky 1159223755Shselasky if (hid_locate(ptr, len, 1160223755Shselasky HID_USAGE2(HUP_LEDS, 0x01), 1161223755Shselasky hid_output, 0, &sc->sc_loc_numlock, &flags, 1162223755Shselasky &sc->sc_id_numlock)) { 1163223755Shselasky if (flags & HIO_VARIABLE) 1164223755Shselasky sc->sc_flags |= UKBD_FLAG_NUMLOCK; 1165223755Shselasky DPRINTFN(1, "Found keyboard numlock\n"); 1166223755Shselasky } 1167223755Shselasky if (hid_locate(ptr, len, 1168223755Shselasky HID_USAGE2(HUP_LEDS, 0x02), 1169223755Shselasky hid_output, 0, &sc->sc_loc_capslock, &flags, 1170223755Shselasky &sc->sc_id_capslock)) { 1171223755Shselasky if (flags & HIO_VARIABLE) 1172223755Shselasky sc->sc_flags |= UKBD_FLAG_CAPSLOCK; 1173223755Shselasky DPRINTFN(1, "Found keyboard capslock\n"); 1174223755Shselasky } 1175223755Shselasky if (hid_locate(ptr, len, 1176223755Shselasky HID_USAGE2(HUP_LEDS, 0x03), 1177223755Shselasky hid_output, 0, &sc->sc_loc_scrolllock, &flags, 1178223755Shselasky &sc->sc_id_scrolllock)) { 1179223755Shselasky if (flags & HIO_VARIABLE) 1180223755Shselasky sc->sc_flags |= UKBD_FLAG_SCROLLLOCK; 1181223755Shselasky DPRINTFN(1, "Found keyboard scrolllock\n"); 1182223755Shselasky } 1183223755Shselasky} 1184223755Shselasky 1185184610Salfredstatic int 1186184610Salfredukbd_attach(device_t dev) 1187184610Salfred{ 1188184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1189192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1190253332Shselasky int unit = device_get_unit(dev); 1191184610Salfred keyboard_t *kbd = &sc->sc_kbd; 1192192925Sthompsa void *hid_ptr = NULL; 1193193045Sthompsa usb_error_t err; 1194184610Salfred uint16_t n; 1195192925Sthompsa uint16_t hid_len; 1196253332Shselasky#ifdef USB_DEBUG 1197253332Shselasky int rate; 1198253332Shselasky#endif 1199228765Savg UKBD_LOCK_ASSERT(); 1200228765Savg 1201184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 1202184610Salfred 1203184610Salfred kbd->kb_data = (void *)sc; 1204184610Salfred 1205194228Sthompsa device_set_usb_desc(dev); 1206184610Salfred 1207184610Salfred sc->sc_udev = uaa->device; 1208184610Salfred sc->sc_iface = uaa->iface; 1209184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 1210184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 1211184610Salfred sc->sc_mode = K_XLATE; 1212184610Salfred 1213194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 1214184610Salfred 1215305644Shselasky#ifdef UKBD_NO_POLLING 1216194228Sthompsa err = usbd_transfer_setup(uaa->device, 1217184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 1218184610Salfred UKBD_N_TRANSFER, sc, &Giant); 1219305644Shselasky#else 1220305644Shselasky /* 1221305644Shselasky * Setup the UKBD USB transfers one by one, so they are memory 1222305644Shselasky * independent which allows for handling panics triggered by 1223305644Shselasky * the keyboard driver itself, typically via CTRL+ALT+ESC 1224305644Shselasky * sequences. Or if the USB keyboard driver was processing a 1225305644Shselasky * key at the moment of panic. 1226305644Shselasky */ 1227305644Shselasky for (n = 0; n != UKBD_N_TRANSFER; n++) { 1228305644Shselasky err = usbd_transfer_setup(uaa->device, 1229305644Shselasky &uaa->info.bIfaceIndex, sc->sc_xfer + n, ukbd_config + n, 1230305644Shselasky 1, sc, &Giant); 1231305644Shselasky if (err) 1232305644Shselasky break; 1233305644Shselasky } 1234305644Shselasky#endif 1235184610Salfred 1236184610Salfred if (err) { 1237194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 1238184610Salfred goto detach; 1239184610Salfred } 1240184610Salfred /* setup default keyboard maps */ 1241184610Salfred 1242184610Salfred sc->sc_keymap = key_map; 1243184610Salfred sc->sc_accmap = accent_map; 1244184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 1245184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 1246184610Salfred } 1247184610Salfred 1248184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 1249184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 1250184610Salfred 1251184610Salfred KBD_FOUND_DEVICE(kbd); 1252184610Salfred 1253184610Salfred ukbd_clear_state(kbd); 1254184610Salfred 1255184610Salfred /* 1256184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 1257184610Salfred * according to the BIOS data? 1258184610Salfred */ 1259184610Salfred KBD_PROBE_DONE(kbd); 1260184610Salfred 1261223755Shselasky /* get HID descriptor */ 1262194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 1263192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 1264223755Shselasky 1265192925Sthompsa if (err == 0) { 1266223755Shselasky DPRINTF("Parsing HID descriptor of %d bytes\n", 1267223755Shselasky (int)hid_len); 1268192925Sthompsa 1269223755Shselasky ukbd_parse_hid(sc, hid_ptr, hid_len); 1270192925Sthompsa 1271192925Sthompsa free(hid_ptr, M_TEMP); 1272192925Sthompsa } 1273192925Sthompsa 1274223755Shselasky /* check if we should use the boot protocol */ 1275223755Shselasky if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) || 1276223755Shselasky (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) { 1277223755Shselasky 1278223755Shselasky DPRINTF("Forcing boot protocol\n"); 1279223755Shselasky 1280223755Shselasky err = usbd_req_set_protocol(sc->sc_udev, NULL, 1281223755Shselasky sc->sc_iface_index, 0); 1282223755Shselasky 1283223755Shselasky if (err != 0) { 1284223755Shselasky DPRINTF("Set protocol error=%s (ignored)\n", 1285223755Shselasky usbd_errstr(err)); 1286223755Shselasky } 1287223755Shselasky 1288223755Shselasky ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc)); 1289223755Shselasky } 1290223755Shselasky 1291184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 1292223755Shselasky usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); 1293184610Salfred 1294184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 1295184610Salfred 1296184610Salfred KBD_INIT_DONE(kbd); 1297184610Salfred 1298184610Salfred if (kbd_register(kbd) < 0) { 1299184610Salfred goto detach; 1300184610Salfred } 1301184610Salfred KBD_CONFIG_DONE(kbd); 1302184610Salfred 1303184610Salfred ukbd_enable(kbd); 1304184610Salfred 1305184610Salfred#ifdef KBD_INSTALL_CDEV 1306184610Salfred if (kbd_attach(kbd)) { 1307184610Salfred goto detach; 1308184610Salfred } 1309184610Salfred#endif 1310184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 1311184610Salfred 1312184610Salfred if (bootverbose) { 1313184610Salfred genkbd_diag(kbd, bootverbose); 1314184610Salfred } 1315184610Salfred 1316253332Shselasky#ifdef USB_DEBUG 1317253332Shselasky /* check for polling rate override */ 1318253332Shselasky rate = ukbd_pollrate; 1319253332Shselasky if (rate > 0) { 1320253332Shselasky if (rate > 1000) 1321253332Shselasky rate = 1; 1322253332Shselasky else 1323253332Shselasky rate = 1000 / rate; 1324253332Shselasky 1325253332Shselasky /* set new polling interval in ms */ 1326305644Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_0], rate); 1327305644Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_1], rate); 1328253332Shselasky } 1329253332Shselasky#endif 1330184610Salfred /* start the keyboard */ 1331305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 1332305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 1333184610Salfred 1334184610Salfred return (0); /* success */ 1335184610Salfred 1336184610Salfreddetach: 1337184610Salfred ukbd_detach(dev); 1338184610Salfred return (ENXIO); /* error */ 1339184610Salfred} 1340184610Salfred 1341193315Sthompsastatic int 1342184610Salfredukbd_detach(device_t dev) 1343184610Salfred{ 1344184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1345184610Salfred int error; 1346184610Salfred 1347228765Savg UKBD_LOCK_ASSERT(); 1348228765Savg 1349184610Salfred DPRINTF("\n"); 1350184610Salfred 1351184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 1352184610Salfred 1353194228Sthompsa usb_callout_stop(&sc->sc_callout); 1354184610Salfred 1355261228Shselasky /* kill any stuck keys */ 1356261228Shselasky if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1357261228Shselasky /* stop receiving events from the USB keyboard */ 1358305644Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_0]); 1359305644Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_1]); 1360261228Shselasky 1361261228Shselasky /* release all leftover keys, if any */ 1362261228Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1363261228Shselasky 1364261228Shselasky /* process releasing of all keys */ 1365261228Shselasky ukbd_interrupt(sc); 1366261228Shselasky } 1367261228Shselasky 1368184610Salfred ukbd_disable(&sc->sc_kbd); 1369184610Salfred 1370184610Salfred#ifdef KBD_INSTALL_CDEV 1371184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1372184610Salfred error = kbd_detach(&sc->sc_kbd); 1373184610Salfred if (error) { 1374184610Salfred /* usb attach cannot return an error */ 1375184610Salfred device_printf(dev, "WARNING: kbd_detach() " 1376184610Salfred "returned non-zero! (ignored)\n"); 1377184610Salfred } 1378184610Salfred } 1379184610Salfred#endif 1380184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 1381184610Salfred error = kbd_unregister(&sc->sc_kbd); 1382184610Salfred if (error) { 1383184610Salfred /* usb attach cannot return an error */ 1384184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 1385184610Salfred "returned non-zero! (ignored)\n"); 1386184610Salfred } 1387184610Salfred } 1388184610Salfred sc->sc_kbd.kb_flags = 0; 1389184610Salfred 1390194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 1391184610Salfred 1392194228Sthompsa usb_callout_drain(&sc->sc_callout); 1393184610Salfred 1394184610Salfred DPRINTF("%s: disconnected\n", 1395184610Salfred device_get_nameunit(dev)); 1396184610Salfred 1397184610Salfred return (0); 1398184610Salfred} 1399184610Salfred 1400184610Salfredstatic int 1401184610Salfredukbd_resume(device_t dev) 1402184610Salfred{ 1403184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1404184610Salfred 1405228765Savg UKBD_LOCK_ASSERT(); 1406203896Sthompsa 1407184610Salfred ukbd_clear_state(&sc->sc_kbd); 1408184610Salfred 1409184610Salfred return (0); 1410184610Salfred} 1411184610Salfred 1412184610Salfred/* early keyboard probe, not supported */ 1413184610Salfredstatic int 1414184610Salfredukbd_configure(int flags) 1415184610Salfred{ 1416184610Salfred return (0); 1417184610Salfred} 1418184610Salfred 1419184610Salfred/* detect a keyboard, not used */ 1420184610Salfredstatic int 1421184610Salfredukbd__probe(int unit, void *arg, int flags) 1422184610Salfred{ 1423184610Salfred return (ENXIO); 1424184610Salfred} 1425184610Salfred 1426184610Salfred/* reset and initialize the device, not used */ 1427184610Salfredstatic int 1428184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 1429184610Salfred{ 1430184610Salfred return (ENXIO); 1431184610Salfred} 1432184610Salfred 1433184610Salfred/* test the interface to the device, not used */ 1434184610Salfredstatic int 1435184610Salfredukbd_test_if(keyboard_t *kbd) 1436184610Salfred{ 1437184610Salfred return (0); 1438184610Salfred} 1439184610Salfred 1440184610Salfred/* finish using this keyboard, not used */ 1441184610Salfredstatic int 1442184610Salfredukbd_term(keyboard_t *kbd) 1443184610Salfred{ 1444184610Salfred return (ENXIO); 1445184610Salfred} 1446184610Salfred 1447184610Salfred/* keyboard interrupt routine, not used */ 1448184610Salfredstatic int 1449184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 1450184610Salfred{ 1451184610Salfred return (0); 1452184610Salfred} 1453184610Salfred 1454184610Salfred/* lock the access to the keyboard, not used */ 1455184610Salfredstatic int 1456184610Salfredukbd_lock(keyboard_t *kbd, int lock) 1457184610Salfred{ 1458184610Salfred return (1); 1459184610Salfred} 1460184610Salfred 1461184610Salfred/* 1462184610Salfred * Enable the access to the device; until this function is called, 1463184610Salfred * the client cannot read from the keyboard. 1464184610Salfred */ 1465184610Salfredstatic int 1466184610Salfredukbd_enable(keyboard_t *kbd) 1467184610Salfred{ 1468228765Savg 1469228765Savg UKBD_LOCK(); 1470184610Salfred KBD_ACTIVATE(kbd); 1471228765Savg UKBD_UNLOCK(); 1472228765Savg 1473184610Salfred return (0); 1474184610Salfred} 1475184610Salfred 1476184610Salfred/* disallow the access to the device */ 1477184610Salfredstatic int 1478184610Salfredukbd_disable(keyboard_t *kbd) 1479184610Salfred{ 1480228765Savg 1481228765Savg UKBD_LOCK(); 1482184610Salfred KBD_DEACTIVATE(kbd); 1483228765Savg UKBD_UNLOCK(); 1484228765Savg 1485184610Salfred return (0); 1486184610Salfred} 1487184610Salfred 1488184610Salfred/* check if data is waiting */ 1489228765Savg/* Currently unused. */ 1490184610Salfredstatic int 1491184610Salfredukbd_check(keyboard_t *kbd) 1492184610Salfred{ 1493184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1494184610Salfred 1495228765Savg UKBD_CTX_LOCK_ASSERT(); 1496228765Savg 1497195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1498195960Salfred return (0); 1499195960Salfred 1500203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 1501203896Sthompsa ukbd_do_poll(sc, 0); 1502203896Sthompsa 1503184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1504184610Salfred if (sc->sc_buffered_char[0]) { 1505184610Salfred return (1); 1506184610Salfred } 1507184610Salfred#endif 1508184610Salfred if (sc->sc_inputs > 0) { 1509184610Salfred return (1); 1510184610Salfred } 1511184610Salfred return (0); 1512184610Salfred} 1513184610Salfred 1514184610Salfred/* check if char is waiting */ 1515184610Salfredstatic int 1516228765Savgukbd_check_char_locked(keyboard_t *kbd) 1517184610Salfred{ 1518184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1519184610Salfred 1520228765Savg UKBD_CTX_LOCK_ASSERT(); 1521228765Savg 1522195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1523195960Salfred return (0); 1524195960Salfred 1525184610Salfred if ((sc->sc_composed_char > 0) && 1526184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1527184610Salfred return (1); 1528184610Salfred } 1529184610Salfred return (ukbd_check(kbd)); 1530184610Salfred} 1531184610Salfred 1532228765Savgstatic int 1533228765Savgukbd_check_char(keyboard_t *kbd) 1534228765Savg{ 1535228765Savg int result; 1536184610Salfred 1537228765Savg UKBD_LOCK(); 1538228765Savg result = ukbd_check_char_locked(kbd); 1539228765Savg UKBD_UNLOCK(); 1540228765Savg 1541228765Savg return (result); 1542228765Savg} 1543228765Savg 1544184610Salfred/* read one byte from the keyboard if it's allowed */ 1545228765Savg/* Currently unused. */ 1546184610Salfredstatic int 1547184610Salfredukbd_read(keyboard_t *kbd, int wait) 1548184610Salfred{ 1549184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1550184610Salfred int32_t usbcode; 1551184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1552184610Salfred uint32_t keycode; 1553184610Salfred uint32_t scancode; 1554184610Salfred 1555184610Salfred#endif 1556184610Salfred 1557228765Savg UKBD_CTX_LOCK_ASSERT(); 1558184610Salfred 1559228765Savg if (!KBD_IS_ACTIVE(kbd)) 1560203896Sthompsa return (-1); 1561203896Sthompsa 1562184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1563184610Salfred if (sc->sc_buffered_char[0]) { 1564184610Salfred scancode = sc->sc_buffered_char[0]; 1565184610Salfred if (scancode & SCAN_PREFIX) { 1566184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1567184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1568184610Salfred } 1569184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1570184610Salfred sc->sc_buffered_char[1] = 0; 1571184610Salfred return (scancode); 1572184610Salfred } 1573184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1574184610Salfred 1575184610Salfred /* XXX */ 1576184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1577195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1578195960Salfred return (-1); 1579195960Salfred 1580184610Salfred ++(kbd->kb_count); 1581184610Salfred 1582184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1583184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1584184610Salfred if (keycode == NN) { 1585184610Salfred return -1; 1586184610Salfred } 1587184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1588184610Salfred (usbcode & KEY_RELEASE))); 1589184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1590184610Salfred return (usbcode); 1591184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1592184610Salfred} 1593184610Salfred 1594184610Salfred/* read char from the keyboard */ 1595184610Salfredstatic uint32_t 1596228765Savgukbd_read_char_locked(keyboard_t *kbd, int wait) 1597184610Salfred{ 1598184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1599184610Salfred uint32_t action; 1600184610Salfred uint32_t keycode; 1601184610Salfred int32_t usbcode; 1602184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1603184610Salfred uint32_t scancode; 1604184610Salfred#endif 1605195960Salfred 1606228765Savg UKBD_CTX_LOCK_ASSERT(); 1607228765Savg 1608195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1609195960Salfred return (NOKEY); 1610195960Salfred 1611184610Salfrednext_code: 1612184610Salfred 1613184610Salfred /* do we have a composed char to return ? */ 1614184610Salfred 1615184610Salfred if ((sc->sc_composed_char > 0) && 1616184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1617184610Salfred 1618184610Salfred action = sc->sc_composed_char; 1619184610Salfred sc->sc_composed_char = 0; 1620184610Salfred 1621184610Salfred if (action > 0xFF) { 1622184610Salfred goto errkey; 1623184610Salfred } 1624184610Salfred goto done; 1625184610Salfred } 1626184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1627184610Salfred 1628184610Salfred /* do we have a pending raw scan code? */ 1629184610Salfred 1630184610Salfred if (sc->sc_mode == K_RAW) { 1631184610Salfred scancode = sc->sc_buffered_char[0]; 1632184610Salfred if (scancode) { 1633184610Salfred if (scancode & SCAN_PREFIX) { 1634184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1635184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1636184610Salfred } 1637184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1638184610Salfred sc->sc_buffered_char[1] = 0; 1639184610Salfred return (scancode); 1640184610Salfred } 1641184610Salfred } 1642184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1643184610Salfred 1644184610Salfred /* see if there is something in the keyboard port */ 1645184610Salfred /* XXX */ 1646184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1647184610Salfred if (usbcode == -1) { 1648184610Salfred return (NOKEY); 1649184610Salfred } 1650184610Salfred ++kbd->kb_count; 1651184610Salfred 1652184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1653184610Salfred /* USB key index -> key code -> AT scan code */ 1654184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1655184610Salfred if (keycode == NN) { 1656184610Salfred return (NOKEY); 1657184610Salfred } 1658184610Salfred /* return an AT scan code for the K_RAW mode */ 1659184610Salfred if (sc->sc_mode == K_RAW) { 1660184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1661184610Salfred (usbcode & KEY_RELEASE))); 1662184610Salfred } 1663184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1664184610Salfred 1665184610Salfred /* return the byte as is for the K_RAW mode */ 1666184610Salfred if (sc->sc_mode == K_RAW) { 1667184610Salfred return (usbcode); 1668184610Salfred } 1669184610Salfred /* USB key index -> key code */ 1670184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1671184610Salfred if (keycode == NN) { 1672184610Salfred return (NOKEY); 1673184610Salfred } 1674184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1675184610Salfred 1676184610Salfred switch (keycode) { 1677184610Salfred case 0x38: /* left alt (compose key) */ 1678184610Salfred if (usbcode & KEY_RELEASE) { 1679184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1680184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1681184610Salfred 1682184610Salfred if (sc->sc_composed_char > 0xFF) { 1683184610Salfred sc->sc_composed_char = 0; 1684184610Salfred } 1685184610Salfred } 1686184610Salfred } else { 1687184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1688184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1689184610Salfred sc->sc_composed_char = 0; 1690184610Salfred } 1691184610Salfred } 1692184610Salfred break; 1693184610Salfred /* XXX: I don't like these... */ 1694184610Salfred case 0x5c: /* print screen */ 1695184610Salfred if (sc->sc_flags & ALTS) { 1696184610Salfred keycode = 0x54; /* sysrq */ 1697184610Salfred } 1698184610Salfred break; 1699184610Salfred case 0x68: /* pause/break */ 1700184610Salfred if (sc->sc_flags & CTLS) { 1701184610Salfred keycode = 0x6c; /* break */ 1702184610Salfred } 1703184610Salfred break; 1704184610Salfred } 1705184610Salfred 1706184610Salfred /* return the key code in the K_CODE mode */ 1707184610Salfred if (usbcode & KEY_RELEASE) { 1708184610Salfred keycode |= SCAN_RELEASE; 1709184610Salfred } 1710184610Salfred if (sc->sc_mode == K_CODE) { 1711184610Salfred return (keycode); 1712184610Salfred } 1713184610Salfred /* compose a character code */ 1714184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1715184610Salfred switch (keycode) { 1716184610Salfred /* key pressed, process it */ 1717184610Salfred case 0x47: 1718184610Salfred case 0x48: 1719184610Salfred case 0x49: /* keypad 7,8,9 */ 1720184610Salfred sc->sc_composed_char *= 10; 1721184610Salfred sc->sc_composed_char += keycode - 0x40; 1722184610Salfred goto check_composed; 1723184610Salfred 1724184610Salfred case 0x4B: 1725184610Salfred case 0x4C: 1726184610Salfred case 0x4D: /* keypad 4,5,6 */ 1727184610Salfred sc->sc_composed_char *= 10; 1728184610Salfred sc->sc_composed_char += keycode - 0x47; 1729184610Salfred goto check_composed; 1730184610Salfred 1731184610Salfred case 0x4F: 1732184610Salfred case 0x50: 1733184610Salfred case 0x51: /* keypad 1,2,3 */ 1734184610Salfred sc->sc_composed_char *= 10; 1735184610Salfred sc->sc_composed_char += keycode - 0x4E; 1736184610Salfred goto check_composed; 1737184610Salfred 1738184610Salfred case 0x52: /* keypad 0 */ 1739184610Salfred sc->sc_composed_char *= 10; 1740184610Salfred goto check_composed; 1741184610Salfred 1742184610Salfred /* key released, no interest here */ 1743184610Salfred case SCAN_RELEASE | 0x47: 1744184610Salfred case SCAN_RELEASE | 0x48: 1745184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1746184610Salfred case SCAN_RELEASE | 0x4B: 1747184610Salfred case SCAN_RELEASE | 0x4C: 1748184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1749184610Salfred case SCAN_RELEASE | 0x4F: 1750184610Salfred case SCAN_RELEASE | 0x50: 1751184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1752184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1753184610Salfred goto next_code; 1754184610Salfred 1755184610Salfred case 0x38: /* left alt key */ 1756184610Salfred break; 1757184610Salfred 1758184610Salfred default: 1759184610Salfred if (sc->sc_composed_char > 0) { 1760184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1761184610Salfred sc->sc_composed_char = 0; 1762184610Salfred goto errkey; 1763184610Salfred } 1764184610Salfred break; 1765184610Salfred } 1766184610Salfred } 1767184610Salfred /* keycode to key action */ 1768184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1769184610Salfred (keycode & SCAN_RELEASE), 1770184610Salfred &sc->sc_state, &sc->sc_accents); 1771184610Salfred if (action == NOKEY) { 1772184610Salfred goto next_code; 1773184610Salfred } 1774184610Salfreddone: 1775184610Salfred return (action); 1776184610Salfred 1777184610Salfredcheck_composed: 1778184610Salfred if (sc->sc_composed_char <= 0xFF) { 1779184610Salfred goto next_code; 1780184610Salfred } 1781184610Salfrederrkey: 1782184610Salfred return (ERRKEY); 1783184610Salfred} 1784184610Salfred 1785228765Savg/* Currently wait is always false. */ 1786228765Savgstatic uint32_t 1787228765Savgukbd_read_char(keyboard_t *kbd, int wait) 1788228765Savg{ 1789228765Savg uint32_t keycode; 1790228765Savg 1791228765Savg UKBD_LOCK(); 1792228765Savg keycode = ukbd_read_char_locked(kbd, wait); 1793228765Savg UKBD_UNLOCK(); 1794228765Savg 1795228765Savg return (keycode); 1796228765Savg} 1797228765Savg 1798184610Salfred/* some useful control functions */ 1799184610Salfredstatic int 1800228765Savgukbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg) 1801184610Salfred{ 1802184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1803184610Salfred int i; 1804184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1805184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1806184610Salfred int ival; 1807184610Salfred 1808184610Salfred#endif 1809184610Salfred 1810228765Savg UKBD_LOCK_ASSERT(); 1811228765Savg 1812184610Salfred switch (cmd) { 1813184610Salfred case KDGKBMODE: /* get keyboard mode */ 1814184610Salfred *(int *)arg = sc->sc_mode; 1815184610Salfred break; 1816184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1817184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1818184610Salfred case _IO('K', 7): 1819184610Salfred ival = IOCPARM_IVAL(arg); 1820184610Salfred arg = (caddr_t)&ival; 1821184610Salfred /* FALLTHROUGH */ 1822184610Salfred#endif 1823184610Salfred case KDSKBMODE: /* set keyboard mode */ 1824184610Salfred switch (*(int *)arg) { 1825184610Salfred case K_XLATE: 1826184610Salfred if (sc->sc_mode != K_XLATE) { 1827184610Salfred /* make lock key state and LED state match */ 1828184610Salfred sc->sc_state &= ~LOCK_MASK; 1829184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1830184610Salfred } 1831184610Salfred /* FALLTHROUGH */ 1832184610Salfred case K_RAW: 1833184610Salfred case K_CODE: 1834184610Salfred if (sc->sc_mode != *(int *)arg) { 1835228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) == 0) 1836203896Sthompsa ukbd_clear_state(kbd); 1837184610Salfred sc->sc_mode = *(int *)arg; 1838184610Salfred } 1839184610Salfred break; 1840184610Salfred default: 1841184610Salfred return (EINVAL); 1842184610Salfred } 1843184610Salfred break; 1844184610Salfred 1845184610Salfred case KDGETLED: /* get keyboard LED */ 1846184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1847184610Salfred break; 1848184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1849184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1850184610Salfred case _IO('K', 66): 1851184610Salfred ival = IOCPARM_IVAL(arg); 1852184610Salfred arg = (caddr_t)&ival; 1853184610Salfred /* FALLTHROUGH */ 1854184610Salfred#endif 1855184610Salfred case KDSETLED: /* set keyboard LED */ 1856184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1857223755Shselasky if (*(int *)arg & ~LOCK_MASK) 1858184610Salfred return (EINVAL); 1859223755Shselasky 1860184610Salfred i = *(int *)arg; 1861223755Shselasky 1862184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1863184610Salfred if (sc->sc_mode == K_XLATE && 1864184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1865184610Salfred if (i & ALKED) 1866184610Salfred i |= CLKED; 1867184610Salfred else 1868184610Salfred i &= ~CLKED; 1869184610Salfred } 1870223755Shselasky if (KBD_HAS_DEVICE(kbd)) 1871223755Shselasky ukbd_set_leds(sc, i); 1872223755Shselasky 1873184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1874184610Salfred break; 1875184610Salfred case KDGKBSTATE: /* get lock key state */ 1876184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1877184610Salfred break; 1878184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1879184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1880184610Salfred case _IO('K', 20): 1881184610Salfred ival = IOCPARM_IVAL(arg); 1882184610Salfred arg = (caddr_t)&ival; 1883184610Salfred /* FALLTHROUGH */ 1884184610Salfred#endif 1885184610Salfred case KDSKBSTATE: /* set lock key state */ 1886184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1887184610Salfred return (EINVAL); 1888184610Salfred } 1889184610Salfred sc->sc_state &= ~LOCK_MASK; 1890184610Salfred sc->sc_state |= *(int *)arg; 1891184610Salfred 1892184610Salfred /* set LEDs and quit */ 1893184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1894184610Salfred 1895184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1896184610Salfred * interface) */ 1897184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1898184610Salfred return (0); 1899184610Salfred } 1900184610Salfred if (((int *)arg)[1] < 0) { 1901184610Salfred return (EINVAL); 1902184610Salfred } 1903184610Salfred if (((int *)arg)[0] < 0) { 1904184610Salfred return (EINVAL); 1905184610Salfred } 1906184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1907184610Salfred kbd->kb_delay1 = 200; 1908184610Salfred else 1909184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1910184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1911184610Salfred return (0); 1912184610Salfred 1913184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1914184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1915184610Salfred case _IO('K', 67): 1916184610Salfred ival = IOCPARM_IVAL(arg); 1917184610Salfred arg = (caddr_t)&ival; 1918184610Salfred /* FALLTHROUGH */ 1919184610Salfred#endif 1920184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1921184610Salfred * interface) */ 1922184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1923184610Salfred 1924184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1925224126Sed case OPIO_KEYMAP: /* set keyboard translation table 1926224126Sed * (compat) */ 1927184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1928184610Salfred * entry */ 1929184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1930184610Salfred sc->sc_accents = 0; 1931184610Salfred /* FALLTHROUGH */ 1932184610Salfred default: 1933184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1934184610Salfred } 1935184610Salfred 1936184610Salfred return (0); 1937184610Salfred} 1938184610Salfred 1939228765Savgstatic int 1940228765Savgukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1941228765Savg{ 1942228765Savg int result; 1943228765Savg 1944228765Savg /* 1945263262Shselasky * XXX Check if someone is calling us from a critical section: 1946262972Shselasky */ 1947262972Shselasky if (curthread->td_critnest != 0) 1948262972Shselasky return (EDEADLK); 1949262972Shselasky 1950262972Shselasky /* 1951228765Savg * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any 1952228765Savg * context where printf(9) can be called, which among other things 1953228765Savg * includes interrupt filters and threads with any kinds of locks 1954228765Savg * already held. For this reason it would be dangerous to acquire 1955228765Savg * the Giant here unconditionally. On the other hand we have to 1956228765Savg * have it to handle the ioctl. 1957228765Savg * So we make our best effort to auto-detect whether we can grab 1958228765Savg * the Giant or not. Blame syscons(4) for this. 1959228765Savg */ 1960228765Savg switch (cmd) { 1961228765Savg case KDGKBSTATE: 1962228765Savg case KDSKBSTATE: 1963228765Savg case KDSETLED: 1964228765Savg if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED()) 1965228765Savg return (EDEADLK); /* best I could come up with */ 1966228765Savg /* FALLTHROUGH */ 1967228765Savg default: 1968228765Savg UKBD_LOCK(); 1969228765Savg result = ukbd_ioctl_locked(kbd, cmd, arg); 1970228765Savg UKBD_UNLOCK(); 1971228765Savg return (result); 1972228765Savg } 1973228765Savg} 1974228765Savg 1975228765Savg 1976184610Salfred/* clear the internal state of the keyboard */ 1977184610Salfredstatic void 1978184610Salfredukbd_clear_state(keyboard_t *kbd) 1979184610Salfred{ 1980184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1981184610Salfred 1982228765Savg UKBD_CTX_LOCK_ASSERT(); 1983184610Salfred 1984184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 1985184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 1986184610Salfred sc->sc_accents = 0; 1987184610Salfred sc->sc_composed_char = 0; 1988184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1989184610Salfred sc->sc_buffered_char[0] = 0; 1990184610Salfred sc->sc_buffered_char[1] = 0; 1991184610Salfred#endif 1992203896Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1993203896Sthompsa memset(&sc->sc_odata, 0, sizeof(sc->sc_odata)); 1994203896Sthompsa memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime)); 1995203896Sthompsa memset(&sc->sc_otime, 0, sizeof(sc->sc_otime)); 1996184610Salfred} 1997184610Salfred 1998184610Salfred/* save the internal state, not used */ 1999184610Salfredstatic int 2000184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 2001184610Salfred{ 2002184610Salfred return (len == 0) ? 1 : -1; 2003184610Salfred} 2004184610Salfred 2005184610Salfred/* set the internal state, not used */ 2006184610Salfredstatic int 2007184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 2008184610Salfred{ 2009184610Salfred return (EINVAL); 2010184610Salfred} 2011184610Salfred 2012184610Salfredstatic int 2013184610Salfredukbd_poll(keyboard_t *kbd, int on) 2014184610Salfred{ 2015184610Salfred struct ukbd_softc *sc = kbd->kb_data; 2016184610Salfred 2017228765Savg UKBD_LOCK(); 2018304124Shselasky /* 2019304124Shselasky * Keep a reference count on polling to allow recursive 2020304124Shselasky * cngrab() during a panic for example. 2021304124Shselasky */ 2022304124Shselasky if (on) 2023304124Shselasky sc->sc_polling++; 2024305644Shselasky else if (sc->sc_polling > 0) 2025304124Shselasky sc->sc_polling--; 2026304124Shselasky 2027304124Shselasky if (sc->sc_polling != 0) { 2028184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 2029203896Sthompsa sc->sc_poll_thread = curthread; 2030184610Salfred } else { 2031184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 2032203896Sthompsa ukbd_start_timer(sc); /* start timer */ 2033184610Salfred } 2034228765Savg UKBD_UNLOCK(); 2035228765Savg 2036184610Salfred return (0); 2037184610Salfred} 2038184610Salfred 2039184610Salfred/* local functions */ 2040184610Salfred 2041184610Salfredstatic void 2042184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 2043184610Salfred{ 2044228765Savg 2045228765Savg UKBD_LOCK_ASSERT(); 2046184610Salfred DPRINTF("leds=0x%02x\n", leds); 2047184610Salfred 2048184610Salfred sc->sc_leds = leds; 2049184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 2050184610Salfred 2051184610Salfred /* start transfer, if not already started */ 2052184610Salfred 2053194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 2054184610Salfred} 2055184610Salfred 2056184610Salfredstatic int 2057184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 2058184610Salfred{ 2059184610Salfred static const int delays[] = {250, 500, 750, 1000}; 2060184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 2061184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 2062184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 2063184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 2064184610Salfred 2065184610Salfred if (code & ~0x7f) { 2066184610Salfred return (EINVAL); 2067184610Salfred } 2068184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 2069184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 2070184610Salfred return (0); 2071184610Salfred} 2072184610Salfred 2073184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 2074184610Salfredstatic int 2075184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 2076184610Salfred{ 2077184610Salfred static const int scan[] = { 2078197999Shrs /* 89 */ 2079197999Shrs 0x11c, /* Enter */ 2080197999Shrs /* 90-99 */ 2081197999Shrs 0x11d, /* Ctrl-R */ 2082197999Shrs 0x135, /* Divide */ 2083197999Shrs 0x137 | SCAN_PREFIX_SHIFT, /* PrintScreen */ 2084197999Shrs 0x138, /* Alt-R */ 2085197999Shrs 0x147, /* Home */ 2086197999Shrs 0x148, /* Up */ 2087197999Shrs 0x149, /* PageUp */ 2088197999Shrs 0x14b, /* Left */ 2089197999Shrs 0x14d, /* Right */ 2090197999Shrs 0x14f, /* End */ 2091197999Shrs /* 100-109 */ 2092197999Shrs 0x150, /* Down */ 2093197999Shrs 0x151, /* PageDown */ 2094197999Shrs 0x152, /* Insert */ 2095197999Shrs 0x153, /* Delete */ 2096197999Shrs 0x146, /* XXX Pause/Break */ 2097197999Shrs 0x15b, /* Win_L(Super_L) */ 2098197999Shrs 0x15c, /* Win_R(Super_R) */ 2099197999Shrs 0x15d, /* Application(Menu) */ 2100197999Shrs 2101184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 2102197999Shrs 0x168, /* Sun Type 6 Help */ 2103197999Shrs 0x15e, /* Sun Type 6 Stop */ 2104197999Shrs /* 110 - 119 */ 2105197999Shrs 0x15f, /* Sun Type 6 Again */ 2106197999Shrs 0x160, /* Sun Type 6 Props */ 2107197999Shrs 0x161, /* Sun Type 6 Undo */ 2108197999Shrs 0x162, /* Sun Type 6 Front */ 2109197999Shrs 0x163, /* Sun Type 6 Copy */ 2110197999Shrs 0x164, /* Sun Type 6 Open */ 2111197999Shrs 0x165, /* Sun Type 6 Paste */ 2112197999Shrs 0x166, /* Sun Type 6 Find */ 2113197999Shrs 0x167, /* Sun Type 6 Cut */ 2114197999Shrs 0x125, /* Sun Type 6 Mute */ 2115291146Shselasky /* 120 - 130 */ 2116197999Shrs 0x11f, /* Sun Type 6 VolumeDown */ 2117197999Shrs 0x11e, /* Sun Type 6 VolumeUp */ 2118197999Shrs 0x120, /* Sun Type 6 PowerDown */ 2119197999Shrs 2120197999Shrs /* Japanese 106/109 keyboard */ 2121197999Shrs 0x73, /* Keyboard Intl' 1 (backslash / underscore) */ 2122197999Shrs 0x70, /* Keyboard Intl' 2 (Katakana / Hiragana) */ 2123197999Shrs 0x7d, /* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */ 2124197999Shrs 0x79, /* Keyboard Intl' 4 (Henkan) */ 2125197999Shrs 0x7b, /* Keyboard Intl' 5 (Muhenkan) */ 2126197999Shrs 0x5c, /* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */ 2127291146Shselasky 0x71, /* Apple Keyboard JIS (Kana) */ 2128291146Shselasky 0x72, /* Apple Keyboard JIS (Eisu) */ 2129184610Salfred }; 2130184610Salfred 2131298300Spfg if ((code >= 89) && (code < (int)(89 + nitems(scan)))) { 2132197999Shrs code = scan[code - 89]; 2133184610Salfred } 2134184610Salfred /* Pause/Break */ 2135184610Salfred if ((code == 104) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 2136184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 2137184610Salfred } 2138184610Salfred if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) { 2139184610Salfred code &= ~SCAN_PREFIX_SHIFT; 2140184610Salfred } 2141184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 2142184610Salfred 2143184610Salfred if (code & SCAN_PREFIX) { 2144184610Salfred if (code & SCAN_PREFIX_CTL) { 2145184610Salfred /* Ctrl */ 2146184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 2147184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 2148184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 2149184610Salfred /* Shift */ 2150184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 2151184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 2152184610Salfred } else { 2153184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 2154184610Salfred sc->sc_buffered_char[1] = 0; 2155184610Salfred } 2156184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 2157184610Salfred } 2158184610Salfred return (code); 2159184610Salfred 2160184610Salfred} 2161184610Salfred 2162184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 2163184610Salfred 2164194099Sthompsastatic keyboard_switch_t ukbdsw = { 2165184610Salfred .probe = &ukbd__probe, 2166184610Salfred .init = &ukbd_init, 2167184610Salfred .term = &ukbd_term, 2168184610Salfred .intr = &ukbd_intr, 2169184610Salfred .test_if = &ukbd_test_if, 2170184610Salfred .enable = &ukbd_enable, 2171184610Salfred .disable = &ukbd_disable, 2172184610Salfred .read = &ukbd_read, 2173184610Salfred .check = &ukbd_check, 2174184610Salfred .read_char = &ukbd_read_char, 2175184610Salfred .check_char = &ukbd_check_char, 2176184610Salfred .ioctl = &ukbd_ioctl, 2177184610Salfred .lock = &ukbd_lock, 2178184610Salfred .clear_state = &ukbd_clear_state, 2179184610Salfred .get_state = &ukbd_get_state, 2180184610Salfred .set_state = &ukbd_set_state, 2181184610Salfred .get_fkeystr = &genkbd_get_fkeystr, 2182184610Salfred .poll = &ukbd_poll, 2183184610Salfred .diag = &genkbd_diag, 2184184610Salfred}; 2185184610Salfred 2186184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 2187184610Salfred 2188184610Salfredstatic int 2189184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 2190184610Salfred{ 2191184610Salfred switch (what) { 2192193315Sthompsa case MOD_LOAD: 2193184610Salfred kbd_add_driver(&ukbd_kbd_driver); 2194184610Salfred break; 2195184610Salfred case MOD_UNLOAD: 2196184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 2197184610Salfred break; 2198184610Salfred } 2199184610Salfred return (0); 2200184610Salfred} 2201184610Salfred 2202184610Salfredstatic devclass_t ukbd_devclass; 2203184610Salfred 2204184610Salfredstatic device_method_t ukbd_methods[] = { 2205184610Salfred DEVMETHOD(device_probe, ukbd_probe), 2206184610Salfred DEVMETHOD(device_attach, ukbd_attach), 2207184610Salfred DEVMETHOD(device_detach, ukbd_detach), 2208184610Salfred DEVMETHOD(device_resume, ukbd_resume), 2209246128Ssbz 2210246128Ssbz DEVMETHOD_END 2211184610Salfred}; 2212184610Salfred 2213184610Salfredstatic driver_t ukbd_driver = { 2214184610Salfred .name = "ukbd", 2215184610Salfred .methods = ukbd_methods, 2216184610Salfred .size = sizeof(struct ukbd_softc), 2217184610Salfred}; 2218184610Salfred 2219189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 2220188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 2221212122SthompsaMODULE_VERSION(ukbd, 1); 2222292080SimpUSB_PNP_HOST_INFO(ukbd_devs); 2223