ukbd.c revision 304124
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: stable/11/sys/dev/usb/input/ukbd.c 304124 2016-08-15 08:58:55Z 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 */ 111184610Salfred#define UKBD_IN_BUF_FULL (UKBD_IN_BUF_SIZE / 2) /* 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 { 132187259Sthompsa UKBD_INTR_DT, 133187259Sthompsa UKBD_CTRL_LED, 134192925Sthompsa UKBD_N_TRANSFER, 135187259Sthompsa}; 136187259Sthompsa 137184610Salfredstruct ukbd_softc { 138184610Salfred keyboard_t sc_kbd; 139184610Salfred keymap_t sc_keymap; 140184610Salfred accentmap_t sc_accmap; 141184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 142192925Sthompsa struct hid_location sc_loc_apple_eject; 143192925Sthompsa struct hid_location sc_loc_apple_fn; 144223755Shselasky struct hid_location sc_loc_ctrl_l; 145223755Shselasky struct hid_location sc_loc_ctrl_r; 146223755Shselasky struct hid_location sc_loc_shift_l; 147223755Shselasky struct hid_location sc_loc_shift_r; 148223755Shselasky struct hid_location sc_loc_alt_l; 149223755Shselasky struct hid_location sc_loc_alt_r; 150223755Shselasky struct hid_location sc_loc_win_l; 151223755Shselasky struct hid_location sc_loc_win_r; 152223755Shselasky struct hid_location sc_loc_events; 153223755Shselasky struct hid_location sc_loc_numlock; 154223755Shselasky struct hid_location sc_loc_capslock; 155223755Shselasky struct hid_location sc_loc_scrolllock; 156192984Sthompsa struct usb_callout sc_callout; 157184610Salfred struct ukbd_data sc_ndata; 158184610Salfred struct ukbd_data sc_odata; 159184610Salfred 160203896Sthompsa struct thread *sc_poll_thread; 161192984Sthompsa struct usb_device *sc_udev; 162192984Sthompsa struct usb_interface *sc_iface; 163192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 164184610Salfred 165184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 166184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 167184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 168184610Salfred uint32_t sc_time_ms; 169184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 170184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 171184610Salfred uint32_t sc_buffered_char[2]; 172184610Salfred#endif 173184610Salfred uint32_t sc_flags; /* flags */ 174223755Shselasky#define UKBD_FLAG_COMPOSE 0x00000001 175223755Shselasky#define UKBD_FLAG_POLLING 0x00000002 176223755Shselasky#define UKBD_FLAG_SET_LEDS 0x00000004 177223755Shselasky#define UKBD_FLAG_ATTACHED 0x00000010 178223755Shselasky#define UKBD_FLAG_GONE 0x00000020 179184610Salfred 180223755Shselasky#define UKBD_FLAG_HID_MASK 0x003fffc0 181223755Shselasky#define UKBD_FLAG_APPLE_EJECT 0x00000040 182223755Shselasky#define UKBD_FLAG_APPLE_FN 0x00000080 183223755Shselasky#define UKBD_FLAG_APPLE_SWAP 0x00000100 184223755Shselasky#define UKBD_FLAG_TIMER_RUNNING 0x00000200 185223755Shselasky#define UKBD_FLAG_CTRL_L 0x00000400 186223755Shselasky#define UKBD_FLAG_CTRL_R 0x00000800 187223755Shselasky#define UKBD_FLAG_SHIFT_L 0x00001000 188223755Shselasky#define UKBD_FLAG_SHIFT_R 0x00002000 189223755Shselasky#define UKBD_FLAG_ALT_L 0x00004000 190223755Shselasky#define UKBD_FLAG_ALT_R 0x00008000 191223755Shselasky#define UKBD_FLAG_WIN_L 0x00010000 192223755Shselasky#define UKBD_FLAG_WIN_R 0x00020000 193223755Shselasky#define UKBD_FLAG_EVENTS 0x00040000 194223755Shselasky#define UKBD_FLAG_NUMLOCK 0x00080000 195223755Shselasky#define UKBD_FLAG_CAPSLOCK 0x00100000 196223755Shselasky#define UKBD_FLAG_SCROLLLOCK 0x00200000 197223755Shselasky 198203896Sthompsa int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 199203896Sthompsa int sc_state; /* shift/lock key state */ 200203896Sthompsa int sc_accents; /* accent key index (> 0) */ 201304124Shselasky int sc_polling; /* polling recursion count */ 202223755Shselasky int sc_led_size; 203223755Shselasky int sc_kbd_size; 204184610Salfred 205184610Salfred uint16_t sc_inputs; 206184610Salfred uint16_t sc_inputhead; 207184610Salfred uint16_t sc_inputtail; 208223755Shselasky uint16_t sc_modifiers; 209184610Salfred 210184610Salfred uint8_t sc_leds; /* store for async led requests */ 211184610Salfred uint8_t sc_iface_index; 212184610Salfred uint8_t sc_iface_no; 213223755Shselasky uint8_t sc_id_apple_eject; 214223755Shselasky uint8_t sc_id_apple_fn; 215223755Shselasky uint8_t sc_id_ctrl_l; 216223755Shselasky uint8_t sc_id_ctrl_r; 217223755Shselasky uint8_t sc_id_shift_l; 218223755Shselasky uint8_t sc_id_shift_r; 219223755Shselasky uint8_t sc_id_alt_l; 220223755Shselasky uint8_t sc_id_alt_r; 221223755Shselasky uint8_t sc_id_win_l; 222223755Shselasky uint8_t sc_id_win_r; 223223755Shselasky uint8_t sc_id_event; 224223755Shselasky uint8_t sc_id_numlock; 225223755Shselasky uint8_t sc_id_capslock; 226223755Shselasky uint8_t sc_id_scrolllock; 227223755Shselasky uint8_t sc_id_events; 228192925Sthompsa uint8_t sc_kbd_id; 229223755Shselasky 230223755Shselasky uint8_t sc_buffer[UKBD_BUFFER_SIZE]; 231184610Salfred}; 232184610Salfred 233184610Salfred#define KEY_ERROR 0x01 234184610Salfred 235184610Salfred#define KEY_PRESS 0 236184610Salfred#define KEY_RELEASE 0x400 237184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 238184610Salfred 239184610Salfred#define SCAN_PRESS 0 240184610Salfred#define SCAN_RELEASE 0x80 241184610Salfred#define SCAN_PREFIX_E0 0x100 242184610Salfred#define SCAN_PREFIX_E1 0x200 243184610Salfred#define SCAN_PREFIX_CTL 0x400 244184610Salfred#define SCAN_PREFIX_SHIFT 0x800 245184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 246184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 247184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 248184610Salfred 249228765Savg#define UKBD_LOCK() mtx_lock(&Giant) 250228765Savg#define UKBD_UNLOCK() mtx_unlock(&Giant) 251228765Savg 252228765Savg#ifdef INVARIANTS 253228765Savg 254228765Savg/* 255228765Savg * Assert that the lock is held in all contexts 256228765Savg * where the code can be executed. 257228765Savg */ 258228765Savg#define UKBD_LOCK_ASSERT() mtx_assert(&Giant, MA_OWNED) 259228765Savg 260228765Savg/* 261228765Savg * Assert that the lock is held in the contexts 262228765Savg * where it really has to be so. 263228765Savg */ 264228765Savg#define UKBD_CTX_LOCK_ASSERT() \ 265228765Savg do { \ 266228765Savg if (!kdb_active && panicstr == NULL) \ 267228765Savg mtx_assert(&Giant, MA_OWNED); \ 268228765Savg } while (0) 269228765Savg#else 270228765Savg 271228765Savg#define UKBD_LOCK_ASSERT() (void)0 272228765Savg#define UKBD_CTX_LOCK_ASSERT() (void)0 273228765Savg 274228765Savg#endif 275228765Savg 276184610Salfredstruct ukbd_mods { 277184610Salfred uint32_t mask, key; 278184610Salfred}; 279184610Salfred 280184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 281184610Salfred {MOD_CONTROL_L, 0xe0}, 282184610Salfred {MOD_CONTROL_R, 0xe4}, 283184610Salfred {MOD_SHIFT_L, 0xe1}, 284184610Salfred {MOD_SHIFT_R, 0xe5}, 285184610Salfred {MOD_ALT_L, 0xe2}, 286184610Salfred {MOD_ALT_R, 0xe6}, 287184610Salfred {MOD_WIN_L, 0xe3}, 288184610Salfred {MOD_WIN_R, 0xe7}, 289184610Salfred}; 290184610Salfred 291184610Salfred#define NN 0 /* no translation */ 292184610Salfred/* 293184610Salfred * Translate USB keycodes to AT keyboard scancodes. 294184610Salfred */ 295184610Salfred/* 296184610Salfred * FIXME: Mac USB keyboard generates: 297184610Salfred * 0x53: keypad NumLock/Clear 298184610Salfred * 0x66: Power 299184610Salfred * 0x67: keypad = 300184610Salfred * 0x68: F13 301184610Salfred * 0x69: F14 302184610Salfred * 0x6a: F15 303291146Shselasky * 304291146Shselasky * USB Apple Keyboard JIS generates: 305291146Shselasky * 0x90: Kana 306291146Shselasky * 0x91: Eisu 307184610Salfred */ 308184610Salfredstatic const uint8_t ukbd_trtab[256] = { 309184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 310184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 311184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 312184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 313184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 314184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 315184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 316184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 317184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 318184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 319184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 320184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 321184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 322184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 323184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 324184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 325197999Shrs 121, 120, NN, NN, NN, NN, NN, 123, /* 80 - 87 */ 326197999Shrs 124, 125, 126, 127, 128, NN, NN, NN, /* 88 - 8F */ 327291146Shselasky 129, 130, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 328184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 329184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 330184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 331184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 332184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 333184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 334184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 335184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 336184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 337184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 338184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 339184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 340184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 341184610Salfred}; 342184610Salfred 343223755Shselaskystatic const uint8_t ukbd_boot_desc[] = { 344223755Shselasky 0x05, 0x01, 0x09, 0x06, 0xa1, 345223755Shselasky 0x01, 0x05, 0x07, 0x19, 0xe0, 346223755Shselasky 0x29, 0xe7, 0x15, 0x00, 0x25, 347223755Shselasky 0x01, 0x75, 0x01, 0x95, 0x08, 348223755Shselasky 0x81, 0x02, 0x95, 0x01, 0x75, 349223755Shselasky 0x08, 0x81, 0x01, 0x95, 0x03, 350223755Shselasky 0x75, 0x01, 0x05, 0x08, 0x19, 351223755Shselasky 0x01, 0x29, 0x03, 0x91, 0x02, 352223755Shselasky 0x95, 0x05, 0x75, 0x01, 0x91, 353223755Shselasky 0x01, 0x95, 0x06, 0x75, 0x08, 354223755Shselasky 0x15, 0x00, 0x26, 0xff, 0x00, 355223755Shselasky 0x05, 0x07, 0x19, 0x00, 0x2a, 356223755Shselasky 0xff, 0x00, 0x81, 0x00, 0xc0 357223755Shselasky}; 358223755Shselasky 359184610Salfred/* prototypes */ 360185948Sthompsastatic void ukbd_timeout(void *); 361185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 362185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 363184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 364185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 365184610Salfred#endif 366185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 367185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 368185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 369185948Sthompsastatic int ukbd_enable(keyboard_t *); 370185948Sthompsastatic int ukbd_disable(keyboard_t *); 371185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 372203896Sthompsastatic void ukbd_event_keyinput(struct ukbd_softc *); 373184610Salfred 374184610Salfredstatic device_probe_t ukbd_probe; 375184610Salfredstatic device_attach_t ukbd_attach; 376184610Salfredstatic device_detach_t ukbd_detach; 377184610Salfredstatic device_resume_t ukbd_resume; 378184610Salfred 379196489Salfredstatic uint8_t 380196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc) 381196489Salfred{ 382196489Salfred uint8_t i; 383196489Salfred uint8_t j; 384196489Salfred 385196489Salfred for (j = i = 0; i < UKBD_NKEYCODE; i++) 386196489Salfred j |= sc->sc_odata.keycode[i]; 387196489Salfred 388196489Salfred return (j ? 1 : 0); 389196489Salfred} 390196489Salfred 391184610Salfredstatic void 392196489Salfredukbd_start_timer(struct ukbd_softc *sc) 393196489Salfred{ 394196489Salfred sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; 395196489Salfred usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 396196489Salfred} 397196489Salfred 398196489Salfredstatic void 399184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 400184610Salfred{ 401184610Salfred 402228765Savg UKBD_CTX_LOCK_ASSERT(); 403228765Savg 404184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 405184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 406184610Salfred 407184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 408184610Salfred sc->sc_input[sc->sc_inputtail] = key; 409184610Salfred ++(sc->sc_inputs); 410184610Salfred ++(sc->sc_inputtail); 411184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 412184610Salfred sc->sc_inputtail = 0; 413184610Salfred } 414184610Salfred } else { 415184610Salfred DPRINTF("input buffer is full\n"); 416184610Salfred } 417184610Salfred} 418184610Salfred 419195960Salfredstatic void 420228765Savgukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 421223989Shselasky{ 422223989Shselasky 423228765Savg UKBD_CTX_LOCK_ASSERT(); 424228765Savg KASSERT((sc->sc_flags & UKBD_FLAG_POLLING) != 0, 425228765Savg ("ukbd_do_poll called when not polling\n")); 426195960Salfred DPRINTFN(2, "polling\n"); 427195960Salfred 428228765Savg if (!kdb_active && !SCHEDULER_STOPPED()) { 429228765Savg /* 430228765Savg * In this context the kernel is polling for input, 431228765Savg * but the USB subsystem works in normal interrupt-driven 432228765Savg * mode, so we just wait on the USB threads to do the job. 433228765Savg * Note that we currently hold the Giant, but it's also used 434228765Savg * as the transfer mtx, so we must release it while waiting. 435228765Savg */ 436203896Sthompsa while (sc->sc_inputs == 0) { 437228765Savg /* 438228765Savg * Give USB threads a chance to run. Note that 439228765Savg * kern_yield performs DROP_GIANT + PICKUP_GIANT. 440228765Savg */ 441228765Savg kern_yield(PRI_UNCHANGED); 442203896Sthompsa if (!wait) 443203896Sthompsa break; 444203896Sthompsa } 445228765Savg return; 446203896Sthompsa } 447198152Sthompsa 448195960Salfred while (sc->sc_inputs == 0) { 449195960Salfred 450195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 451195960Salfred 452196489Salfred /* Delay-optimised support for repetition of keys */ 453196489Salfred if (ukbd_any_key_pressed(sc)) { 454196489Salfred /* a key is pressed - need timekeeping */ 455196489Salfred DELAY(1000); 456195960Salfred 457196489Salfred /* 1 millisecond has passed */ 458196489Salfred sc->sc_time_ms += 1; 459196489Salfred } 460195960Salfred 461195960Salfred ukbd_interrupt(sc); 462195960Salfred 463195960Salfred if (!wait) 464195960Salfred break; 465195960Salfred } 466195960Salfred} 467195960Salfred 468184610Salfredstatic int32_t 469184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 470184610Salfred{ 471184610Salfred int32_t c; 472184610Salfred 473228765Savg UKBD_CTX_LOCK_ASSERT(); 474228765Savg KASSERT((!kdb_active && !SCHEDULER_STOPPED()) 475228765Savg || (sc->sc_flags & UKBD_FLAG_POLLING) != 0, 476228765Savg ("not polling in kdb or panic\n")); 477184610Salfred 478261228Shselasky if (sc->sc_inputs == 0 && 479261228Shselasky (sc->sc_flags & UKBD_FLAG_GONE) == 0) { 480184610Salfred /* start transfer, if not already started */ 481194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 482184610Salfred } 483203896Sthompsa 484203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 485195960Salfred ukbd_do_poll(sc, wait); 486203896Sthompsa 487184610Salfred if (sc->sc_inputs == 0) { 488184610Salfred c = -1; 489184610Salfred } else { 490184610Salfred c = sc->sc_input[sc->sc_inputhead]; 491184610Salfred --(sc->sc_inputs); 492184610Salfred ++(sc->sc_inputhead); 493184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 494184610Salfred sc->sc_inputhead = 0; 495184610Salfred } 496184610Salfred } 497184610Salfred return (c); 498184610Salfred} 499184610Salfred 500184610Salfredstatic void 501184610Salfredukbd_interrupt(struct ukbd_softc *sc) 502184610Salfred{ 503184610Salfred uint32_t n_mod; 504184610Salfred uint32_t o_mod; 505184610Salfred uint32_t now = sc->sc_time_ms; 506184610Salfred uint32_t dtime; 507184610Salfred uint8_t key; 508184610Salfred uint8_t i; 509184610Salfred uint8_t j; 510184610Salfred 511228765Savg UKBD_CTX_LOCK_ASSERT(); 512228765Savg 513203896Sthompsa if (sc->sc_ndata.keycode[0] == KEY_ERROR) 514203896Sthompsa return; 515203896Sthompsa 516184610Salfred n_mod = sc->sc_ndata.modifiers; 517184610Salfred o_mod = sc->sc_odata.modifiers; 518184610Salfred if (n_mod != o_mod) { 519184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 520184610Salfred if ((n_mod & ukbd_mods[i].mask) != 521184610Salfred (o_mod & ukbd_mods[i].mask)) { 522184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 523184610Salfred ((n_mod & ukbd_mods[i].mask) ? 524184610Salfred KEY_PRESS : KEY_RELEASE)); 525184610Salfred } 526184610Salfred } 527184610Salfred } 528184610Salfred /* Check for released keys. */ 529184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 530184610Salfred key = sc->sc_odata.keycode[i]; 531184610Salfred if (key == 0) { 532184610Salfred continue; 533184610Salfred } 534184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 535184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 536184610Salfred continue; 537184610Salfred } 538184610Salfred if (key == sc->sc_ndata.keycode[j]) { 539184610Salfred goto rfound; 540184610Salfred } 541184610Salfred } 542184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 543184610Salfredrfound: ; 544184610Salfred } 545184610Salfred 546184610Salfred /* Check for pressed keys. */ 547184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 548184610Salfred key = sc->sc_ndata.keycode[i]; 549184610Salfred if (key == 0) { 550184610Salfred continue; 551184610Salfred } 552184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 553184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 554184610Salfred if (sc->sc_odata.keycode[j] == 0) { 555184610Salfred continue; 556184610Salfred } 557184610Salfred if (key == sc->sc_odata.keycode[j]) { 558184610Salfred 559184610Salfred /* key is still pressed */ 560184610Salfred 561184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 562184610Salfred dtime = (sc->sc_otime[j] - now); 563184610Salfred 564184610Salfred if (!(dtime & 0x80000000)) { 565184610Salfred /* time has not elapsed */ 566184610Salfred goto pfound; 567184610Salfred } 568184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 569184610Salfred break; 570184610Salfred } 571184610Salfred } 572184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 573184610Salfred 574184610Salfred /* 575184610Salfred * If any other key is presently down, force its repeat to be 576184610Salfred * well in the future (100s). This makes the last key to be 577184610Salfred * pressed do the autorepeat. 578184610Salfred */ 579184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 580184610Salfred if (j != i) 581184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 582184610Salfred } 583184610Salfredpfound: ; 584184610Salfred } 585184610Salfred 586184610Salfred sc->sc_odata = sc->sc_ndata; 587184610Salfred 588203896Sthompsa memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime)); 589184610Salfred 590203896Sthompsa ukbd_event_keyinput(sc); 591203896Sthompsa} 592203896Sthompsa 593203896Sthompsastatic void 594203896Sthompsaukbd_event_keyinput(struct ukbd_softc *sc) 595203896Sthompsa{ 596203896Sthompsa int c; 597203896Sthompsa 598228765Savg UKBD_CTX_LOCK_ASSERT(); 599228765Savg 600228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) != 0) 601203896Sthompsa return; 602203896Sthompsa 603203896Sthompsa if (sc->sc_inputs == 0) 604203896Sthompsa return; 605203896Sthompsa 606184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 607184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 608184610Salfred /* let the callback function process the input */ 609184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 610184610Salfred sc->sc_kbd.kb_callback.kc_arg); 611184610Salfred } else { 612184610Salfred /* read and discard the input, no one is waiting for it */ 613184610Salfred do { 614184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 615184610Salfred } while (c != NOKEY); 616184610Salfred } 617184610Salfred} 618184610Salfred 619184610Salfredstatic void 620184610Salfredukbd_timeout(void *arg) 621184610Salfred{ 622184610Salfred struct ukbd_softc *sc = arg; 623184610Salfred 624228765Savg UKBD_LOCK_ASSERT(); 625184610Salfred 626203896Sthompsa sc->sc_time_ms += 25; /* milliseconds */ 627203896Sthompsa 628184610Salfred ukbd_interrupt(sc); 629184610Salfred 630203896Sthompsa /* Make sure any leftover key events gets read out */ 631203896Sthompsa ukbd_event_keyinput(sc); 632203896Sthompsa 633203896Sthompsa if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { 634196489Salfred ukbd_start_timer(sc); 635196489Salfred } else { 636196489Salfred sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; 637196489Salfred } 638184610Salfred} 639184610Salfred 640192925Sthompsastatic uint8_t 641192925Sthompsaukbd_apple_fn(uint8_t keycode) { 642192925Sthompsa switch (keycode) { 643192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 644192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 645192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 646192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 647192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 648192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 649192925Sthompsa default: return keycode; 650192925Sthompsa } 651192925Sthompsa} 652184610Salfred 653192925Sthompsastatic uint8_t 654192925Sthompsaukbd_apple_swap(uint8_t keycode) { 655192925Sthompsa switch (keycode) { 656192925Sthompsa case 0x35: return 0x64; 657192925Sthompsa case 0x64: return 0x35; 658192925Sthompsa default: return keycode; 659184610Salfred } 660184610Salfred} 661184610Salfred 662184610Salfredstatic void 663194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 664184610Salfred{ 665194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 666194677Sthompsa struct usb_page_cache *pc; 667184610Salfred uint8_t i; 668192925Sthompsa uint8_t offset; 669192925Sthompsa uint8_t id; 670194677Sthompsa int len; 671184610Salfred 672228765Savg UKBD_LOCK_ASSERT(); 673228765Savg 674194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 675194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 676194677Sthompsa 677184610Salfred switch (USB_GET_STATE(xfer)) { 678184610Salfred case USB_ST_TRANSFERRED: 679184610Salfred DPRINTF("actlen=%d bytes\n", len); 680184610Salfred 681192925Sthompsa if (len == 0) { 682192925Sthompsa DPRINTF("zero length data\n"); 683192925Sthompsa goto tr_setup; 684192925Sthompsa } 685192925Sthompsa 686192925Sthompsa if (sc->sc_kbd_id != 0) { 687192925Sthompsa /* check and remove HID ID byte */ 688194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 689223755Shselasky offset = 1; 690223755Shselasky len--; 691223755Shselasky if (len == 0) { 692223755Shselasky DPRINTF("zero length data\n"); 693192925Sthompsa goto tr_setup; 694192925Sthompsa } 695192925Sthompsa } else { 696192925Sthompsa offset = 0; 697223755Shselasky id = 0; 698192925Sthompsa } 699192925Sthompsa 700223755Shselasky if (len > UKBD_BUFFER_SIZE) 701223755Shselasky len = UKBD_BUFFER_SIZE; 702192925Sthompsa 703223755Shselasky /* get data */ 704223755Shselasky usbd_copy_out(pc, offset, sc->sc_buffer, len); 705192925Sthompsa 706223755Shselasky /* clear temporary storage */ 707223755Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 708192925Sthompsa 709223755Shselasky /* scan through HID data */ 710223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 711223755Shselasky (id == sc->sc_id_apple_eject)) { 712223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject)) 713223755Shselasky sc->sc_modifiers |= MOD_EJECT; 714192925Sthompsa else 715223755Shselasky sc->sc_modifiers &= ~MOD_EJECT; 716223755Shselasky } 717223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 718223755Shselasky (id == sc->sc_id_apple_fn)) { 719223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn)) 720223755Shselasky sc->sc_modifiers |= MOD_FN; 721223755Shselasky else 722223755Shselasky sc->sc_modifiers &= ~MOD_FN; 723223755Shselasky } 724223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_L) && 725223755Shselasky (id == sc->sc_id_ctrl_l)) { 726223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_l)) 727223755Shselasky sc-> sc_modifiers |= MOD_CONTROL_L; 728223755Shselasky else 729223755Shselasky sc-> sc_modifiers &= ~MOD_CONTROL_L; 730223755Shselasky } 731223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_R) && 732223755Shselasky (id == sc->sc_id_ctrl_r)) { 733223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_r)) 734223755Shselasky sc->sc_modifiers |= MOD_CONTROL_R; 735223755Shselasky else 736223755Shselasky sc->sc_modifiers &= ~MOD_CONTROL_R; 737223755Shselasky } 738223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) && 739223755Shselasky (id == sc->sc_id_shift_l)) { 740223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_l)) 741223755Shselasky sc->sc_modifiers |= MOD_SHIFT_L; 742223755Shselasky else 743223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_L; 744223755Shselasky } 745223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) && 746223755Shselasky (id == sc->sc_id_shift_r)) { 747223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_r)) 748223755Shselasky sc->sc_modifiers |= MOD_SHIFT_R; 749223755Shselasky else 750223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_R; 751223755Shselasky } 752223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_L) && 753223755Shselasky (id == sc->sc_id_alt_l)) { 754223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l)) 755223755Shselasky sc->sc_modifiers |= MOD_ALT_L; 756223755Shselasky else 757223755Shselasky sc->sc_modifiers &= ~MOD_ALT_L; 758223755Shselasky } 759223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_R) && 760223755Shselasky (id == sc->sc_id_alt_r)) { 761223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r)) 762223755Shselasky sc->sc_modifiers |= MOD_ALT_R; 763223755Shselasky else 764223755Shselasky sc->sc_modifiers &= ~MOD_ALT_R; 765223755Shselasky } 766223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_L) && 767223755Shselasky (id == sc->sc_id_win_l)) { 768223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l)) 769223755Shselasky sc->sc_modifiers |= MOD_WIN_L; 770223755Shselasky else 771223755Shselasky sc->sc_modifiers &= ~MOD_WIN_L; 772223755Shselasky } 773223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_R) && 774223755Shselasky (id == sc->sc_id_win_r)) { 775223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r)) 776223755Shselasky sc->sc_modifiers |= MOD_WIN_R; 777223755Shselasky else 778223755Shselasky sc->sc_modifiers &= ~MOD_WIN_R; 779223755Shselasky } 780192925Sthompsa 781223755Shselasky sc->sc_ndata.modifiers = sc->sc_modifiers; 782223755Shselasky 783223755Shselasky if ((sc->sc_flags & UKBD_FLAG_EVENTS) && 784223755Shselasky (id == sc->sc_id_events)) { 785223755Shselasky i = sc->sc_loc_events.count; 786223755Shselasky if (i > UKBD_NKEYCODE) 787223755Shselasky i = UKBD_NKEYCODE; 788223755Shselasky if (i > len) 789223755Shselasky i = len; 790223755Shselasky while (i--) { 791223755Shselasky sc->sc_ndata.keycode[i] = 792223755Shselasky hid_get_data(sc->sc_buffer + i, len - i, 793223755Shselasky &sc->sc_loc_events); 794184610Salfred } 795223755Shselasky } 796223755Shselasky 797223755Shselasky#ifdef USB_DEBUG 798223755Shselasky DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers); 799223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 800223755Shselasky if (sc->sc_ndata.keycode[i]) { 801223755Shselasky DPRINTF("[%d] = 0x%02x\n", 802223755Shselasky (int)i, (int)sc->sc_ndata.keycode[i]); 803223755Shselasky } 804223755Shselasky } 805223755Shselasky#endif 806223755Shselasky if (sc->sc_modifiers & MOD_FN) { 807184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 808223755Shselasky sc->sc_ndata.keycode[i] = 809223755Shselasky ukbd_apple_fn(sc->sc_ndata.keycode[i]); 810184610Salfred } 811223755Shselasky } 812192925Sthompsa 813223755Shselasky if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 814223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 815223755Shselasky sc->sc_ndata.keycode[i] = 816223755Shselasky ukbd_apple_swap(sc->sc_ndata.keycode[i]); 817192925Sthompsa } 818223755Shselasky } 819192925Sthompsa 820223755Shselasky ukbd_interrupt(sc); 821192925Sthompsa 822223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { 823223755Shselasky if (ukbd_any_key_pressed(sc)) { 824223755Shselasky ukbd_start_timer(sc); 825196489Salfred } 826184610Salfred } 827223755Shselasky 828184610Salfred case USB_ST_SETUP: 829192925Sthompsatr_setup: 830184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 831194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 832194228Sthompsa usbd_transfer_submit(xfer); 833184610Salfred } else { 834184610Salfred DPRINTF("input queue is full!\n"); 835184610Salfred } 836192925Sthompsa break; 837184610Salfred 838184610Salfred default: /* Error */ 839194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 840184610Salfred 841194677Sthompsa if (error != USB_ERR_CANCELLED) { 842184610Salfred /* try to clear stall first */ 843194677Sthompsa usbd_xfer_set_stall(xfer); 844192925Sthompsa goto tr_setup; 845184610Salfred } 846192925Sthompsa break; 847184610Salfred } 848184610Salfred} 849184610Salfred 850184610Salfredstatic void 851194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 852184610Salfred{ 853223755Shselasky struct ukbd_softc *sc = usbd_xfer_softc(xfer); 854192984Sthompsa struct usb_device_request req; 855194677Sthompsa struct usb_page_cache *pc; 856223755Shselasky uint8_t id; 857223755Shselasky uint8_t any; 858223755Shselasky int len; 859184610Salfred 860228765Savg UKBD_LOCK_ASSERT(); 861228765Savg 862207077Sthompsa#ifdef USB_DEBUG 863196489Salfred if (ukbd_no_leds) 864196489Salfred return; 865196489Salfred#endif 866196489Salfred 867184610Salfred switch (USB_GET_STATE(xfer)) { 868184610Salfred case USB_ST_TRANSFERRED: 869184610Salfred case USB_ST_SETUP: 870223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS)) 871223755Shselasky break; 872223755Shselasky sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 873184610Salfred 874223755Shselasky req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 875223755Shselasky req.bRequest = UR_SET_REPORT; 876223755Shselasky USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 877223755Shselasky req.wIndex[0] = sc->sc_iface_no; 878223755Shselasky req.wIndex[1] = 0; 879223755Shselasky req.wLength[1] = 0; 880184610Salfred 881223755Shselasky memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE); 882223755Shselasky 883223755Shselasky id = 0; 884223755Shselasky any = 0; 885223755Shselasky 886223755Shselasky /* Assumption: All led bits must be in the same ID. */ 887223755Shselasky 888223755Shselasky if (sc->sc_flags & UKBD_FLAG_NUMLOCK) { 889223755Shselasky if (sc->sc_leds & NLKED) { 890223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 891223755Shselasky &sc->sc_loc_numlock, 1); 892192925Sthompsa } 893223755Shselasky id = sc->sc_id_numlock; 894223755Shselasky any = 1; 895223755Shselasky } 896184610Salfred 897223755Shselasky if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) { 898223755Shselasky if (sc->sc_leds & SLKED) { 899223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 900223755Shselasky &sc->sc_loc_scrolllock, 1); 901223755Shselasky } 902223755Shselasky id = sc->sc_id_scrolllock; 903223755Shselasky any = 1; 904223755Shselasky } 905184610Salfred 906223755Shselasky if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) { 907223755Shselasky if (sc->sc_leds & CLKED) { 908223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 909223755Shselasky &sc->sc_loc_capslock, 1); 910223755Shselasky } 911223755Shselasky id = sc->sc_id_capslock; 912223755Shselasky any = 1; 913184610Salfred } 914223755Shselasky 915223755Shselasky /* if no leds, nothing to do */ 916223755Shselasky if (!any) 917223755Shselasky break; 918223755Shselasky 919223755Shselasky /* range check output report length */ 920223755Shselasky len = sc->sc_led_size; 921223755Shselasky if (len > (UKBD_BUFFER_SIZE - 1)) 922223755Shselasky len = (UKBD_BUFFER_SIZE - 1); 923223755Shselasky 924223755Shselasky /* check if we need to prefix an ID byte */ 925223755Shselasky sc->sc_buffer[0] = id; 926223755Shselasky 927223755Shselasky pc = usbd_xfer_get_frame(xfer, 1); 928223755Shselasky if (id != 0) { 929223755Shselasky len++; 930223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer, len); 931223755Shselasky } else { 932223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer + 1, len); 933223755Shselasky } 934223755Shselasky req.wLength[0] = len; 935223755Shselasky usbd_xfer_set_frame_len(xfer, 1, len); 936223755Shselasky 937223755Shselasky DPRINTF("len=%d, id=%d\n", len, id); 938223755Shselasky 939223755Shselasky /* setup control request last */ 940223755Shselasky pc = usbd_xfer_get_frame(xfer, 0); 941223755Shselasky usbd_copy_in(pc, 0, &req, sizeof(req)); 942223755Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 943223755Shselasky 944223755Shselasky /* start data transfer */ 945223755Shselasky usbd_xfer_set_frames(xfer, 2); 946223755Shselasky usbd_transfer_submit(xfer); 947196489Salfred break; 948184610Salfred 949184610Salfred default: /* Error */ 950212128Sthompsa DPRINTFN(1, "error=%s\n", usbd_errstr(error)); 951196489Salfred break; 952184610Salfred } 953184610Salfred} 954184610Salfred 955192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 956184610Salfred 957187259Sthompsa [UKBD_INTR_DT] = { 958184610Salfred .type = UE_INTERRUPT, 959184610Salfred .endpoint = UE_ADDR_ANY, 960184610Salfred .direction = UE_DIR_IN, 961190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 962190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 963190734Sthompsa .callback = &ukbd_intr_callback, 964184610Salfred }, 965184610Salfred 966187259Sthompsa [UKBD_CTRL_LED] = { 967184610Salfred .type = UE_CONTROL, 968184610Salfred .endpoint = 0x00, /* Control pipe */ 969184610Salfred .direction = UE_DIR_ANY, 970223755Shselasky .bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE, 971190734Sthompsa .callback = &ukbd_set_leds_callback, 972190734Sthompsa .timeout = 1000, /* 1 second */ 973184610Salfred }, 974184610Salfred}; 975184610Salfred 976223521Shselasky/* A match on these entries will load ukbd */ 977223521Shselaskystatic const STRUCT_USB_HOST_ID __used ukbd_devs[] = { 978223521Shselasky {USB_IFACE_CLASS(UICLASS_HID), 979223521Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), 980223521Shselasky USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),}, 981223521Shselasky}; 982223521Shselasky 983184610Salfredstatic int 984184610Salfredukbd_probe(device_t dev) 985184610Salfred{ 986184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 987192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 988194067Sthompsa void *d_ptr; 989194067Sthompsa int error; 990194067Sthompsa uint16_t d_len; 991184610Salfred 992228765Savg UKBD_LOCK_ASSERT(); 993184610Salfred DPRINTFN(11, "\n"); 994184610Salfred 995184610Salfred if (sw == NULL) { 996184610Salfred return (ENXIO); 997184610Salfred } 998192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 999184610Salfred return (ENXIO); 1000184610Salfred } 1001194067Sthompsa 1002194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 1003194067Sthompsa return (ENXIO); 1004194067Sthompsa 1005245248Shselasky if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 1006245248Shselasky return (ENXIO); 1007245248Shselasky 1008194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 1009245248Shselasky (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) 1010245248Shselasky return (BUS_PROBE_DEFAULT); 1011194067Sthompsa 1012194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 1013194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 1014194067Sthompsa 1015194067Sthompsa if (error) 1016194067Sthompsa return (ENXIO); 1017194067Sthompsa 1018245248Shselasky if (hid_is_keyboard(d_ptr, d_len)) { 1019245248Shselasky if (hid_is_mouse(d_ptr, d_len)) { 1020245248Shselasky /* 1021245248Shselasky * NOTE: We currently don't support USB mouse 1022245248Shselasky * and USB keyboard on the same USB endpoint. 1023245248Shselasky * Let "ums" driver win. 1024245248Shselasky */ 1025194067Sthompsa error = ENXIO; 1026245248Shselasky } else { 1027222051Savg error = BUS_PROBE_DEFAULT; 1028245248Shselasky } 1029245248Shselasky } else { 1030194067Sthompsa error = ENXIO; 1031245248Shselasky } 1032194067Sthompsa free(d_ptr, M_TEMP); 1033194067Sthompsa return (error); 1034184610Salfred} 1035184610Salfred 1036223755Shselaskystatic void 1037223755Shselaskyukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len) 1038223755Shselasky{ 1039223755Shselasky uint32_t flags; 1040223755Shselasky 1041223755Shselasky /* reset detected bits */ 1042223755Shselasky sc->sc_flags &= ~UKBD_FLAG_HID_MASK; 1043223755Shselasky 1044223755Shselasky /* check if there is an ID byte */ 1045223755Shselasky sc->sc_kbd_size = hid_report_size(ptr, len, 1046223755Shselasky hid_input, &sc->sc_kbd_id); 1047223755Shselasky 1048223755Shselasky /* investigate if this is an Apple Keyboard */ 1049223755Shselasky if (hid_locate(ptr, len, 1050223755Shselasky HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 1051223755Shselasky hid_input, 0, &sc->sc_loc_apple_eject, &flags, 1052223755Shselasky &sc->sc_id_apple_eject)) { 1053223755Shselasky if (flags & HIO_VARIABLE) 1054223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 1055223755Shselasky UKBD_FLAG_APPLE_SWAP; 1056223755Shselasky DPRINTFN(1, "Found Apple eject-key\n"); 1057223755Shselasky } 1058223755Shselasky if (hid_locate(ptr, len, 1059223755Shselasky HID_USAGE2(0xFFFF, 0x0003), 1060223755Shselasky hid_input, 0, &sc->sc_loc_apple_fn, &flags, 1061223755Shselasky &sc->sc_id_apple_fn)) { 1062223755Shselasky if (flags & HIO_VARIABLE) 1063223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_FN; 1064223755Shselasky DPRINTFN(1, "Found Apple FN-key\n"); 1065223755Shselasky } 1066223755Shselasky /* figure out some keys */ 1067223755Shselasky if (hid_locate(ptr, len, 1068223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE0), 1069223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_l, &flags, 1070223755Shselasky &sc->sc_id_ctrl_l)) { 1071223755Shselasky if (flags & HIO_VARIABLE) 1072223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_L; 1073223755Shselasky DPRINTFN(1, "Found left control\n"); 1074223755Shselasky } 1075223755Shselasky if (hid_locate(ptr, len, 1076223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE4), 1077223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_r, &flags, 1078223755Shselasky &sc->sc_id_ctrl_r)) { 1079223755Shselasky if (flags & HIO_VARIABLE) 1080223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_R; 1081223755Shselasky DPRINTFN(1, "Found right control\n"); 1082223755Shselasky } 1083223755Shselasky if (hid_locate(ptr, len, 1084223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE1), 1085223755Shselasky hid_input, 0, &sc->sc_loc_shift_l, &flags, 1086223755Shselasky &sc->sc_id_shift_l)) { 1087223755Shselasky if (flags & HIO_VARIABLE) 1088223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_L; 1089223755Shselasky DPRINTFN(1, "Found left shift\n"); 1090223755Shselasky } 1091223755Shselasky if (hid_locate(ptr, len, 1092223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE5), 1093223755Shselasky hid_input, 0, &sc->sc_loc_shift_r, &flags, 1094223755Shselasky &sc->sc_id_shift_r)) { 1095223755Shselasky if (flags & HIO_VARIABLE) 1096223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_R; 1097223755Shselasky DPRINTFN(1, "Found right shift\n"); 1098223755Shselasky } 1099223755Shselasky if (hid_locate(ptr, len, 1100223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE2), 1101223755Shselasky hid_input, 0, &sc->sc_loc_alt_l, &flags, 1102223755Shselasky &sc->sc_id_alt_l)) { 1103223755Shselasky if (flags & HIO_VARIABLE) 1104223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_L; 1105223755Shselasky DPRINTFN(1, "Found left alt\n"); 1106223755Shselasky } 1107223755Shselasky if (hid_locate(ptr, len, 1108223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE6), 1109223755Shselasky hid_input, 0, &sc->sc_loc_alt_r, &flags, 1110223755Shselasky &sc->sc_id_alt_r)) { 1111223755Shselasky if (flags & HIO_VARIABLE) 1112223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_R; 1113223755Shselasky DPRINTFN(1, "Found right alt\n"); 1114223755Shselasky } 1115223755Shselasky if (hid_locate(ptr, len, 1116223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE3), 1117223755Shselasky hid_input, 0, &sc->sc_loc_win_l, &flags, 1118223755Shselasky &sc->sc_id_win_l)) { 1119223755Shselasky if (flags & HIO_VARIABLE) 1120223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_L; 1121223755Shselasky DPRINTFN(1, "Found left GUI\n"); 1122223755Shselasky } 1123223755Shselasky if (hid_locate(ptr, len, 1124223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE7), 1125223755Shselasky hid_input, 0, &sc->sc_loc_win_r, &flags, 1126223755Shselasky &sc->sc_id_win_r)) { 1127223755Shselasky if (flags & HIO_VARIABLE) 1128223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_R; 1129223755Shselasky DPRINTFN(1, "Found right GUI\n"); 1130223755Shselasky } 1131223755Shselasky /* figure out event buffer */ 1132223755Shselasky if (hid_locate(ptr, len, 1133223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0x00), 1134223755Shselasky hid_input, 0, &sc->sc_loc_events, &flags, 1135223755Shselasky &sc->sc_id_events)) { 1136254572Shselasky if (flags & HIO_VARIABLE) { 1137254572Shselasky DPRINTFN(1, "Ignoring keyboard event control\n"); 1138254572Shselasky } else { 1139254572Shselasky sc->sc_flags |= UKBD_FLAG_EVENTS; 1140254572Shselasky DPRINTFN(1, "Found keyboard event array\n"); 1141254572Shselasky } 1142223755Shselasky } 1143223755Shselasky 1144223755Shselasky /* figure out leds on keyboard */ 1145223755Shselasky sc->sc_led_size = hid_report_size(ptr, len, 1146223755Shselasky hid_output, NULL); 1147223755Shselasky 1148223755Shselasky if (hid_locate(ptr, len, 1149223755Shselasky HID_USAGE2(HUP_LEDS, 0x01), 1150223755Shselasky hid_output, 0, &sc->sc_loc_numlock, &flags, 1151223755Shselasky &sc->sc_id_numlock)) { 1152223755Shselasky if (flags & HIO_VARIABLE) 1153223755Shselasky sc->sc_flags |= UKBD_FLAG_NUMLOCK; 1154223755Shselasky DPRINTFN(1, "Found keyboard numlock\n"); 1155223755Shselasky } 1156223755Shselasky if (hid_locate(ptr, len, 1157223755Shselasky HID_USAGE2(HUP_LEDS, 0x02), 1158223755Shselasky hid_output, 0, &sc->sc_loc_capslock, &flags, 1159223755Shselasky &sc->sc_id_capslock)) { 1160223755Shselasky if (flags & HIO_VARIABLE) 1161223755Shselasky sc->sc_flags |= UKBD_FLAG_CAPSLOCK; 1162223755Shselasky DPRINTFN(1, "Found keyboard capslock\n"); 1163223755Shselasky } 1164223755Shselasky if (hid_locate(ptr, len, 1165223755Shselasky HID_USAGE2(HUP_LEDS, 0x03), 1166223755Shselasky hid_output, 0, &sc->sc_loc_scrolllock, &flags, 1167223755Shselasky &sc->sc_id_scrolllock)) { 1168223755Shselasky if (flags & HIO_VARIABLE) 1169223755Shselasky sc->sc_flags |= UKBD_FLAG_SCROLLLOCK; 1170223755Shselasky DPRINTFN(1, "Found keyboard scrolllock\n"); 1171223755Shselasky } 1172223755Shselasky} 1173223755Shselasky 1174184610Salfredstatic int 1175184610Salfredukbd_attach(device_t dev) 1176184610Salfred{ 1177184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1178192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1179253332Shselasky int unit = device_get_unit(dev); 1180184610Salfred keyboard_t *kbd = &sc->sc_kbd; 1181192925Sthompsa void *hid_ptr = NULL; 1182193045Sthompsa usb_error_t err; 1183184610Salfred uint16_t n; 1184192925Sthompsa uint16_t hid_len; 1185253332Shselasky#ifdef USB_DEBUG 1186253332Shselasky int rate; 1187253332Shselasky#endif 1188228765Savg UKBD_LOCK_ASSERT(); 1189228765Savg 1190184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 1191184610Salfred 1192184610Salfred kbd->kb_data = (void *)sc; 1193184610Salfred 1194194228Sthompsa device_set_usb_desc(dev); 1195184610Salfred 1196184610Salfred sc->sc_udev = uaa->device; 1197184610Salfred sc->sc_iface = uaa->iface; 1198184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 1199184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 1200184610Salfred sc->sc_mode = K_XLATE; 1201184610Salfred 1202194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 1203184610Salfred 1204194228Sthompsa err = usbd_transfer_setup(uaa->device, 1205184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 1206184610Salfred UKBD_N_TRANSFER, sc, &Giant); 1207184610Salfred 1208184610Salfred if (err) { 1209194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 1210184610Salfred goto detach; 1211184610Salfred } 1212184610Salfred /* setup default keyboard maps */ 1213184610Salfred 1214184610Salfred sc->sc_keymap = key_map; 1215184610Salfred sc->sc_accmap = accent_map; 1216184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 1217184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 1218184610Salfred } 1219184610Salfred 1220184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 1221184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 1222184610Salfred 1223184610Salfred KBD_FOUND_DEVICE(kbd); 1224184610Salfred 1225184610Salfred ukbd_clear_state(kbd); 1226184610Salfred 1227184610Salfred /* 1228184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 1229184610Salfred * according to the BIOS data? 1230184610Salfred */ 1231184610Salfred KBD_PROBE_DONE(kbd); 1232184610Salfred 1233223755Shselasky /* get HID descriptor */ 1234194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 1235192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 1236223755Shselasky 1237192925Sthompsa if (err == 0) { 1238223755Shselasky DPRINTF("Parsing HID descriptor of %d bytes\n", 1239223755Shselasky (int)hid_len); 1240192925Sthompsa 1241223755Shselasky ukbd_parse_hid(sc, hid_ptr, hid_len); 1242192925Sthompsa 1243192925Sthompsa free(hid_ptr, M_TEMP); 1244192925Sthompsa } 1245192925Sthompsa 1246223755Shselasky /* check if we should use the boot protocol */ 1247223755Shselasky if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) || 1248223755Shselasky (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) { 1249223755Shselasky 1250223755Shselasky DPRINTF("Forcing boot protocol\n"); 1251223755Shselasky 1252223755Shselasky err = usbd_req_set_protocol(sc->sc_udev, NULL, 1253223755Shselasky sc->sc_iface_index, 0); 1254223755Shselasky 1255223755Shselasky if (err != 0) { 1256223755Shselasky DPRINTF("Set protocol error=%s (ignored)\n", 1257223755Shselasky usbd_errstr(err)); 1258223755Shselasky } 1259223755Shselasky 1260223755Shselasky ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc)); 1261223755Shselasky } 1262223755Shselasky 1263184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 1264223755Shselasky usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); 1265184610Salfred 1266184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 1267184610Salfred 1268184610Salfred KBD_INIT_DONE(kbd); 1269184610Salfred 1270184610Salfred if (kbd_register(kbd) < 0) { 1271184610Salfred goto detach; 1272184610Salfred } 1273184610Salfred KBD_CONFIG_DONE(kbd); 1274184610Salfred 1275184610Salfred ukbd_enable(kbd); 1276184610Salfred 1277184610Salfred#ifdef KBD_INSTALL_CDEV 1278184610Salfred if (kbd_attach(kbd)) { 1279184610Salfred goto detach; 1280184610Salfred } 1281184610Salfred#endif 1282184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 1283184610Salfred 1284184610Salfred if (bootverbose) { 1285184610Salfred genkbd_diag(kbd, bootverbose); 1286184610Salfred } 1287184610Salfred 1288253332Shselasky#ifdef USB_DEBUG 1289253332Shselasky /* check for polling rate override */ 1290253332Shselasky rate = ukbd_pollrate; 1291253332Shselasky if (rate > 0) { 1292253332Shselasky if (rate > 1000) 1293253332Shselasky rate = 1; 1294253332Shselasky else 1295253332Shselasky rate = 1000 / rate; 1296253332Shselasky 1297253332Shselasky /* set new polling interval in ms */ 1298253332Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT], rate); 1299253332Shselasky } 1300253332Shselasky#endif 1301184610Salfred /* start the keyboard */ 1302194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); 1303184610Salfred 1304184610Salfred return (0); /* success */ 1305184610Salfred 1306184610Salfreddetach: 1307184610Salfred ukbd_detach(dev); 1308184610Salfred return (ENXIO); /* error */ 1309184610Salfred} 1310184610Salfred 1311193315Sthompsastatic int 1312184610Salfredukbd_detach(device_t dev) 1313184610Salfred{ 1314184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1315184610Salfred int error; 1316184610Salfred 1317228765Savg UKBD_LOCK_ASSERT(); 1318228765Savg 1319184610Salfred DPRINTF("\n"); 1320184610Salfred 1321184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 1322184610Salfred 1323194228Sthompsa usb_callout_stop(&sc->sc_callout); 1324184610Salfred 1325261228Shselasky /* kill any stuck keys */ 1326261228Shselasky if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1327261228Shselasky /* stop receiving events from the USB keyboard */ 1328261228Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT]); 1329261228Shselasky 1330261228Shselasky /* release all leftover keys, if any */ 1331261228Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1332261228Shselasky 1333261228Shselasky /* process releasing of all keys */ 1334261228Shselasky ukbd_interrupt(sc); 1335261228Shselasky } 1336261228Shselasky 1337184610Salfred ukbd_disable(&sc->sc_kbd); 1338184610Salfred 1339184610Salfred#ifdef KBD_INSTALL_CDEV 1340184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1341184610Salfred error = kbd_detach(&sc->sc_kbd); 1342184610Salfred if (error) { 1343184610Salfred /* usb attach cannot return an error */ 1344184610Salfred device_printf(dev, "WARNING: kbd_detach() " 1345184610Salfred "returned non-zero! (ignored)\n"); 1346184610Salfred } 1347184610Salfred } 1348184610Salfred#endif 1349184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 1350184610Salfred error = kbd_unregister(&sc->sc_kbd); 1351184610Salfred if (error) { 1352184610Salfred /* usb attach cannot return an error */ 1353184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 1354184610Salfred "returned non-zero! (ignored)\n"); 1355184610Salfred } 1356184610Salfred } 1357184610Salfred sc->sc_kbd.kb_flags = 0; 1358184610Salfred 1359194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 1360184610Salfred 1361194228Sthompsa usb_callout_drain(&sc->sc_callout); 1362184610Salfred 1363184610Salfred DPRINTF("%s: disconnected\n", 1364184610Salfred device_get_nameunit(dev)); 1365184610Salfred 1366184610Salfred return (0); 1367184610Salfred} 1368184610Salfred 1369184610Salfredstatic int 1370184610Salfredukbd_resume(device_t dev) 1371184610Salfred{ 1372184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1373184610Salfred 1374228765Savg UKBD_LOCK_ASSERT(); 1375203896Sthompsa 1376184610Salfred ukbd_clear_state(&sc->sc_kbd); 1377184610Salfred 1378184610Salfred return (0); 1379184610Salfred} 1380184610Salfred 1381184610Salfred/* early keyboard probe, not supported */ 1382184610Salfredstatic int 1383184610Salfredukbd_configure(int flags) 1384184610Salfred{ 1385184610Salfred return (0); 1386184610Salfred} 1387184610Salfred 1388184610Salfred/* detect a keyboard, not used */ 1389184610Salfredstatic int 1390184610Salfredukbd__probe(int unit, void *arg, int flags) 1391184610Salfred{ 1392184610Salfred return (ENXIO); 1393184610Salfred} 1394184610Salfred 1395184610Salfred/* reset and initialize the device, not used */ 1396184610Salfredstatic int 1397184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 1398184610Salfred{ 1399184610Salfred return (ENXIO); 1400184610Salfred} 1401184610Salfred 1402184610Salfred/* test the interface to the device, not used */ 1403184610Salfredstatic int 1404184610Salfredukbd_test_if(keyboard_t *kbd) 1405184610Salfred{ 1406184610Salfred return (0); 1407184610Salfred} 1408184610Salfred 1409184610Salfred/* finish using this keyboard, not used */ 1410184610Salfredstatic int 1411184610Salfredukbd_term(keyboard_t *kbd) 1412184610Salfred{ 1413184610Salfred return (ENXIO); 1414184610Salfred} 1415184610Salfred 1416184610Salfred/* keyboard interrupt routine, not used */ 1417184610Salfredstatic int 1418184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 1419184610Salfred{ 1420184610Salfred return (0); 1421184610Salfred} 1422184610Salfred 1423184610Salfred/* lock the access to the keyboard, not used */ 1424184610Salfredstatic int 1425184610Salfredukbd_lock(keyboard_t *kbd, int lock) 1426184610Salfred{ 1427184610Salfred return (1); 1428184610Salfred} 1429184610Salfred 1430184610Salfred/* 1431184610Salfred * Enable the access to the device; until this function is called, 1432184610Salfred * the client cannot read from the keyboard. 1433184610Salfred */ 1434184610Salfredstatic int 1435184610Salfredukbd_enable(keyboard_t *kbd) 1436184610Salfred{ 1437228765Savg 1438228765Savg UKBD_LOCK(); 1439184610Salfred KBD_ACTIVATE(kbd); 1440228765Savg UKBD_UNLOCK(); 1441228765Savg 1442184610Salfred return (0); 1443184610Salfred} 1444184610Salfred 1445184610Salfred/* disallow the access to the device */ 1446184610Salfredstatic int 1447184610Salfredukbd_disable(keyboard_t *kbd) 1448184610Salfred{ 1449228765Savg 1450228765Savg UKBD_LOCK(); 1451184610Salfred KBD_DEACTIVATE(kbd); 1452228765Savg UKBD_UNLOCK(); 1453228765Savg 1454184610Salfred return (0); 1455184610Salfred} 1456184610Salfred 1457184610Salfred/* check if data is waiting */ 1458228765Savg/* Currently unused. */ 1459184610Salfredstatic int 1460184610Salfredukbd_check(keyboard_t *kbd) 1461184610Salfred{ 1462184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1463184610Salfred 1464228765Savg UKBD_CTX_LOCK_ASSERT(); 1465228765Savg 1466195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1467195960Salfred return (0); 1468195960Salfred 1469203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 1470203896Sthompsa ukbd_do_poll(sc, 0); 1471203896Sthompsa 1472184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1473184610Salfred if (sc->sc_buffered_char[0]) { 1474184610Salfred return (1); 1475184610Salfred } 1476184610Salfred#endif 1477184610Salfred if (sc->sc_inputs > 0) { 1478184610Salfred return (1); 1479184610Salfred } 1480184610Salfred return (0); 1481184610Salfred} 1482184610Salfred 1483184610Salfred/* check if char is waiting */ 1484184610Salfredstatic int 1485228765Savgukbd_check_char_locked(keyboard_t *kbd) 1486184610Salfred{ 1487184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1488184610Salfred 1489228765Savg UKBD_CTX_LOCK_ASSERT(); 1490228765Savg 1491195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1492195960Salfred return (0); 1493195960Salfred 1494184610Salfred if ((sc->sc_composed_char > 0) && 1495184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1496184610Salfred return (1); 1497184610Salfred } 1498184610Salfred return (ukbd_check(kbd)); 1499184610Salfred} 1500184610Salfred 1501228765Savgstatic int 1502228765Savgukbd_check_char(keyboard_t *kbd) 1503228765Savg{ 1504228765Savg int result; 1505184610Salfred 1506228765Savg UKBD_LOCK(); 1507228765Savg result = ukbd_check_char_locked(kbd); 1508228765Savg UKBD_UNLOCK(); 1509228765Savg 1510228765Savg return (result); 1511228765Savg} 1512228765Savg 1513184610Salfred/* read one byte from the keyboard if it's allowed */ 1514228765Savg/* Currently unused. */ 1515184610Salfredstatic int 1516184610Salfredukbd_read(keyboard_t *kbd, int wait) 1517184610Salfred{ 1518184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1519184610Salfred int32_t usbcode; 1520184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1521184610Salfred uint32_t keycode; 1522184610Salfred uint32_t scancode; 1523184610Salfred 1524184610Salfred#endif 1525184610Salfred 1526228765Savg UKBD_CTX_LOCK_ASSERT(); 1527184610Salfred 1528228765Savg if (!KBD_IS_ACTIVE(kbd)) 1529203896Sthompsa return (-1); 1530203896Sthompsa 1531184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1532184610Salfred if (sc->sc_buffered_char[0]) { 1533184610Salfred scancode = sc->sc_buffered_char[0]; 1534184610Salfred if (scancode & SCAN_PREFIX) { 1535184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1536184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1537184610Salfred } 1538184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1539184610Salfred sc->sc_buffered_char[1] = 0; 1540184610Salfred return (scancode); 1541184610Salfred } 1542184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1543184610Salfred 1544184610Salfred /* XXX */ 1545184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1546195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1547195960Salfred return (-1); 1548195960Salfred 1549184610Salfred ++(kbd->kb_count); 1550184610Salfred 1551184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1552184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1553184610Salfred if (keycode == NN) { 1554184610Salfred return -1; 1555184610Salfred } 1556184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1557184610Salfred (usbcode & KEY_RELEASE))); 1558184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1559184610Salfred return (usbcode); 1560184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1561184610Salfred} 1562184610Salfred 1563184610Salfred/* read char from the keyboard */ 1564184610Salfredstatic uint32_t 1565228765Savgukbd_read_char_locked(keyboard_t *kbd, int wait) 1566184610Salfred{ 1567184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1568184610Salfred uint32_t action; 1569184610Salfred uint32_t keycode; 1570184610Salfred int32_t usbcode; 1571184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1572184610Salfred uint32_t scancode; 1573184610Salfred#endif 1574195960Salfred 1575228765Savg UKBD_CTX_LOCK_ASSERT(); 1576228765Savg 1577195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1578195960Salfred return (NOKEY); 1579195960Salfred 1580184610Salfrednext_code: 1581184610Salfred 1582184610Salfred /* do we have a composed char to return ? */ 1583184610Salfred 1584184610Salfred if ((sc->sc_composed_char > 0) && 1585184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1586184610Salfred 1587184610Salfred action = sc->sc_composed_char; 1588184610Salfred sc->sc_composed_char = 0; 1589184610Salfred 1590184610Salfred if (action > 0xFF) { 1591184610Salfred goto errkey; 1592184610Salfred } 1593184610Salfred goto done; 1594184610Salfred } 1595184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1596184610Salfred 1597184610Salfred /* do we have a pending raw scan code? */ 1598184610Salfred 1599184610Salfred if (sc->sc_mode == K_RAW) { 1600184610Salfred scancode = sc->sc_buffered_char[0]; 1601184610Salfred if (scancode) { 1602184610Salfred if (scancode & SCAN_PREFIX) { 1603184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1604184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1605184610Salfred } 1606184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1607184610Salfred sc->sc_buffered_char[1] = 0; 1608184610Salfred return (scancode); 1609184610Salfred } 1610184610Salfred } 1611184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1612184610Salfred 1613184610Salfred /* see if there is something in the keyboard port */ 1614184610Salfred /* XXX */ 1615184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1616184610Salfred if (usbcode == -1) { 1617184610Salfred return (NOKEY); 1618184610Salfred } 1619184610Salfred ++kbd->kb_count; 1620184610Salfred 1621184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1622184610Salfred /* USB key index -> key code -> AT scan code */ 1623184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1624184610Salfred if (keycode == NN) { 1625184610Salfred return (NOKEY); 1626184610Salfred } 1627184610Salfred /* return an AT scan code for the K_RAW mode */ 1628184610Salfred if (sc->sc_mode == K_RAW) { 1629184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1630184610Salfred (usbcode & KEY_RELEASE))); 1631184610Salfred } 1632184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1633184610Salfred 1634184610Salfred /* return the byte as is for the K_RAW mode */ 1635184610Salfred if (sc->sc_mode == K_RAW) { 1636184610Salfred return (usbcode); 1637184610Salfred } 1638184610Salfred /* USB key index -> key code */ 1639184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1640184610Salfred if (keycode == NN) { 1641184610Salfred return (NOKEY); 1642184610Salfred } 1643184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1644184610Salfred 1645184610Salfred switch (keycode) { 1646184610Salfred case 0x38: /* left alt (compose key) */ 1647184610Salfred if (usbcode & KEY_RELEASE) { 1648184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1649184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1650184610Salfred 1651184610Salfred if (sc->sc_composed_char > 0xFF) { 1652184610Salfred sc->sc_composed_char = 0; 1653184610Salfred } 1654184610Salfred } 1655184610Salfred } else { 1656184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1657184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1658184610Salfred sc->sc_composed_char = 0; 1659184610Salfred } 1660184610Salfred } 1661184610Salfred break; 1662184610Salfred /* XXX: I don't like these... */ 1663184610Salfred case 0x5c: /* print screen */ 1664184610Salfred if (sc->sc_flags & ALTS) { 1665184610Salfred keycode = 0x54; /* sysrq */ 1666184610Salfred } 1667184610Salfred break; 1668184610Salfred case 0x68: /* pause/break */ 1669184610Salfred if (sc->sc_flags & CTLS) { 1670184610Salfred keycode = 0x6c; /* break */ 1671184610Salfred } 1672184610Salfred break; 1673184610Salfred } 1674184610Salfred 1675184610Salfred /* return the key code in the K_CODE mode */ 1676184610Salfred if (usbcode & KEY_RELEASE) { 1677184610Salfred keycode |= SCAN_RELEASE; 1678184610Salfred } 1679184610Salfred if (sc->sc_mode == K_CODE) { 1680184610Salfred return (keycode); 1681184610Salfred } 1682184610Salfred /* compose a character code */ 1683184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1684184610Salfred switch (keycode) { 1685184610Salfred /* key pressed, process it */ 1686184610Salfred case 0x47: 1687184610Salfred case 0x48: 1688184610Salfred case 0x49: /* keypad 7,8,9 */ 1689184610Salfred sc->sc_composed_char *= 10; 1690184610Salfred sc->sc_composed_char += keycode - 0x40; 1691184610Salfred goto check_composed; 1692184610Salfred 1693184610Salfred case 0x4B: 1694184610Salfred case 0x4C: 1695184610Salfred case 0x4D: /* keypad 4,5,6 */ 1696184610Salfred sc->sc_composed_char *= 10; 1697184610Salfred sc->sc_composed_char += keycode - 0x47; 1698184610Salfred goto check_composed; 1699184610Salfred 1700184610Salfred case 0x4F: 1701184610Salfred case 0x50: 1702184610Salfred case 0x51: /* keypad 1,2,3 */ 1703184610Salfred sc->sc_composed_char *= 10; 1704184610Salfred sc->sc_composed_char += keycode - 0x4E; 1705184610Salfred goto check_composed; 1706184610Salfred 1707184610Salfred case 0x52: /* keypad 0 */ 1708184610Salfred sc->sc_composed_char *= 10; 1709184610Salfred goto check_composed; 1710184610Salfred 1711184610Salfred /* key released, no interest here */ 1712184610Salfred case SCAN_RELEASE | 0x47: 1713184610Salfred case SCAN_RELEASE | 0x48: 1714184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1715184610Salfred case SCAN_RELEASE | 0x4B: 1716184610Salfred case SCAN_RELEASE | 0x4C: 1717184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1718184610Salfred case SCAN_RELEASE | 0x4F: 1719184610Salfred case SCAN_RELEASE | 0x50: 1720184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1721184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1722184610Salfred goto next_code; 1723184610Salfred 1724184610Salfred case 0x38: /* left alt key */ 1725184610Salfred break; 1726184610Salfred 1727184610Salfred default: 1728184610Salfred if (sc->sc_composed_char > 0) { 1729184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1730184610Salfred sc->sc_composed_char = 0; 1731184610Salfred goto errkey; 1732184610Salfred } 1733184610Salfred break; 1734184610Salfred } 1735184610Salfred } 1736184610Salfred /* keycode to key action */ 1737184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1738184610Salfred (keycode & SCAN_RELEASE), 1739184610Salfred &sc->sc_state, &sc->sc_accents); 1740184610Salfred if (action == NOKEY) { 1741184610Salfred goto next_code; 1742184610Salfred } 1743184610Salfreddone: 1744184610Salfred return (action); 1745184610Salfred 1746184610Salfredcheck_composed: 1747184610Salfred if (sc->sc_composed_char <= 0xFF) { 1748184610Salfred goto next_code; 1749184610Salfred } 1750184610Salfrederrkey: 1751184610Salfred return (ERRKEY); 1752184610Salfred} 1753184610Salfred 1754228765Savg/* Currently wait is always false. */ 1755228765Savgstatic uint32_t 1756228765Savgukbd_read_char(keyboard_t *kbd, int wait) 1757228765Savg{ 1758228765Savg uint32_t keycode; 1759228765Savg 1760228765Savg UKBD_LOCK(); 1761228765Savg keycode = ukbd_read_char_locked(kbd, wait); 1762228765Savg UKBD_UNLOCK(); 1763228765Savg 1764228765Savg return (keycode); 1765228765Savg} 1766228765Savg 1767184610Salfred/* some useful control functions */ 1768184610Salfredstatic int 1769228765Savgukbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg) 1770184610Salfred{ 1771184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1772184610Salfred int i; 1773184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1774184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1775184610Salfred int ival; 1776184610Salfred 1777184610Salfred#endif 1778184610Salfred 1779228765Savg UKBD_LOCK_ASSERT(); 1780228765Savg 1781184610Salfred switch (cmd) { 1782184610Salfred case KDGKBMODE: /* get keyboard mode */ 1783184610Salfred *(int *)arg = sc->sc_mode; 1784184610Salfred break; 1785184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1786184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1787184610Salfred case _IO('K', 7): 1788184610Salfred ival = IOCPARM_IVAL(arg); 1789184610Salfred arg = (caddr_t)&ival; 1790184610Salfred /* FALLTHROUGH */ 1791184610Salfred#endif 1792184610Salfred case KDSKBMODE: /* set keyboard mode */ 1793184610Salfred switch (*(int *)arg) { 1794184610Salfred case K_XLATE: 1795184610Salfred if (sc->sc_mode != K_XLATE) { 1796184610Salfred /* make lock key state and LED state match */ 1797184610Salfred sc->sc_state &= ~LOCK_MASK; 1798184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1799184610Salfred } 1800184610Salfred /* FALLTHROUGH */ 1801184610Salfred case K_RAW: 1802184610Salfred case K_CODE: 1803184610Salfred if (sc->sc_mode != *(int *)arg) { 1804228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) == 0) 1805203896Sthompsa ukbd_clear_state(kbd); 1806184610Salfred sc->sc_mode = *(int *)arg; 1807184610Salfred } 1808184610Salfred break; 1809184610Salfred default: 1810184610Salfred return (EINVAL); 1811184610Salfred } 1812184610Salfred break; 1813184610Salfred 1814184610Salfred case KDGETLED: /* get keyboard LED */ 1815184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1816184610Salfred break; 1817184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1818184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1819184610Salfred case _IO('K', 66): 1820184610Salfred ival = IOCPARM_IVAL(arg); 1821184610Salfred arg = (caddr_t)&ival; 1822184610Salfred /* FALLTHROUGH */ 1823184610Salfred#endif 1824184610Salfred case KDSETLED: /* set keyboard LED */ 1825184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1826223755Shselasky if (*(int *)arg & ~LOCK_MASK) 1827184610Salfred return (EINVAL); 1828223755Shselasky 1829184610Salfred i = *(int *)arg; 1830223755Shselasky 1831184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1832184610Salfred if (sc->sc_mode == K_XLATE && 1833184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1834184610Salfred if (i & ALKED) 1835184610Salfred i |= CLKED; 1836184610Salfred else 1837184610Salfred i &= ~CLKED; 1838184610Salfred } 1839223755Shselasky if (KBD_HAS_DEVICE(kbd)) 1840223755Shselasky ukbd_set_leds(sc, i); 1841223755Shselasky 1842184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1843184610Salfred break; 1844184610Salfred case KDGKBSTATE: /* get lock key state */ 1845184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1846184610Salfred break; 1847184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1848184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1849184610Salfred case _IO('K', 20): 1850184610Salfred ival = IOCPARM_IVAL(arg); 1851184610Salfred arg = (caddr_t)&ival; 1852184610Salfred /* FALLTHROUGH */ 1853184610Salfred#endif 1854184610Salfred case KDSKBSTATE: /* set lock key state */ 1855184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1856184610Salfred return (EINVAL); 1857184610Salfred } 1858184610Salfred sc->sc_state &= ~LOCK_MASK; 1859184610Salfred sc->sc_state |= *(int *)arg; 1860184610Salfred 1861184610Salfred /* set LEDs and quit */ 1862184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1863184610Salfred 1864184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1865184610Salfred * interface) */ 1866184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1867184610Salfred return (0); 1868184610Salfred } 1869184610Salfred if (((int *)arg)[1] < 0) { 1870184610Salfred return (EINVAL); 1871184610Salfred } 1872184610Salfred if (((int *)arg)[0] < 0) { 1873184610Salfred return (EINVAL); 1874184610Salfred } 1875184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1876184610Salfred kbd->kb_delay1 = 200; 1877184610Salfred else 1878184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1879184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1880184610Salfred return (0); 1881184610Salfred 1882184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1883184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1884184610Salfred case _IO('K', 67): 1885184610Salfred ival = IOCPARM_IVAL(arg); 1886184610Salfred arg = (caddr_t)&ival; 1887184610Salfred /* FALLTHROUGH */ 1888184610Salfred#endif 1889184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1890184610Salfred * interface) */ 1891184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1892184610Salfred 1893184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1894224126Sed case OPIO_KEYMAP: /* set keyboard translation table 1895224126Sed * (compat) */ 1896184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1897184610Salfred * entry */ 1898184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1899184610Salfred sc->sc_accents = 0; 1900184610Salfred /* FALLTHROUGH */ 1901184610Salfred default: 1902184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1903184610Salfred } 1904184610Salfred 1905184610Salfred return (0); 1906184610Salfred} 1907184610Salfred 1908228765Savgstatic int 1909228765Savgukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1910228765Savg{ 1911228765Savg int result; 1912228765Savg 1913228765Savg /* 1914263262Shselasky * XXX Check if someone is calling us from a critical section: 1915262972Shselasky */ 1916262972Shselasky if (curthread->td_critnest != 0) 1917262972Shselasky return (EDEADLK); 1918262972Shselasky 1919262972Shselasky /* 1920228765Savg * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any 1921228765Savg * context where printf(9) can be called, which among other things 1922228765Savg * includes interrupt filters and threads with any kinds of locks 1923228765Savg * already held. For this reason it would be dangerous to acquire 1924228765Savg * the Giant here unconditionally. On the other hand we have to 1925228765Savg * have it to handle the ioctl. 1926228765Savg * So we make our best effort to auto-detect whether we can grab 1927228765Savg * the Giant or not. Blame syscons(4) for this. 1928228765Savg */ 1929228765Savg switch (cmd) { 1930228765Savg case KDGKBSTATE: 1931228765Savg case KDSKBSTATE: 1932228765Savg case KDSETLED: 1933228765Savg if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED()) 1934228765Savg return (EDEADLK); /* best I could come up with */ 1935228765Savg /* FALLTHROUGH */ 1936228765Savg default: 1937228765Savg UKBD_LOCK(); 1938228765Savg result = ukbd_ioctl_locked(kbd, cmd, arg); 1939228765Savg UKBD_UNLOCK(); 1940228765Savg return (result); 1941228765Savg } 1942228765Savg} 1943228765Savg 1944228765Savg 1945184610Salfred/* clear the internal state of the keyboard */ 1946184610Salfredstatic void 1947184610Salfredukbd_clear_state(keyboard_t *kbd) 1948184610Salfred{ 1949184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1950184610Salfred 1951228765Savg UKBD_CTX_LOCK_ASSERT(); 1952184610Salfred 1953184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 1954184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 1955184610Salfred sc->sc_accents = 0; 1956184610Salfred sc->sc_composed_char = 0; 1957184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1958184610Salfred sc->sc_buffered_char[0] = 0; 1959184610Salfred sc->sc_buffered_char[1] = 0; 1960184610Salfred#endif 1961203896Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1962203896Sthompsa memset(&sc->sc_odata, 0, sizeof(sc->sc_odata)); 1963203896Sthompsa memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime)); 1964203896Sthompsa memset(&sc->sc_otime, 0, sizeof(sc->sc_otime)); 1965184610Salfred} 1966184610Salfred 1967184610Salfred/* save the internal state, not used */ 1968184610Salfredstatic int 1969184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1970184610Salfred{ 1971184610Salfred return (len == 0) ? 1 : -1; 1972184610Salfred} 1973184610Salfred 1974184610Salfred/* set the internal state, not used */ 1975184610Salfredstatic int 1976184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1977184610Salfred{ 1978184610Salfred return (EINVAL); 1979184610Salfred} 1980184610Salfred 1981184610Salfredstatic int 1982184610Salfredukbd_poll(keyboard_t *kbd, int on) 1983184610Salfred{ 1984184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1985184610Salfred 1986228765Savg UKBD_LOCK(); 1987304124Shselasky /* 1988304124Shselasky * Keep a reference count on polling to allow recursive 1989304124Shselasky * cngrab() during a panic for example. 1990304124Shselasky */ 1991304124Shselasky if (on) 1992304124Shselasky sc->sc_polling++; 1993304124Shselasky else 1994304124Shselasky sc->sc_polling--; 1995304124Shselasky 1996304124Shselasky if (sc->sc_polling != 0) { 1997184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 1998203896Sthompsa sc->sc_poll_thread = curthread; 1999184610Salfred } else { 2000184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 2001203896Sthompsa ukbd_start_timer(sc); /* start timer */ 2002184610Salfred } 2003228765Savg UKBD_UNLOCK(); 2004228765Savg 2005184610Salfred return (0); 2006184610Salfred} 2007184610Salfred 2008184610Salfred/* local functions */ 2009184610Salfred 2010184610Salfredstatic void 2011184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 2012184610Salfred{ 2013228765Savg 2014228765Savg UKBD_LOCK_ASSERT(); 2015184610Salfred DPRINTF("leds=0x%02x\n", leds); 2016184610Salfred 2017184610Salfred sc->sc_leds = leds; 2018184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 2019184610Salfred 2020184610Salfred /* start transfer, if not already started */ 2021184610Salfred 2022194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 2023184610Salfred} 2024184610Salfred 2025184610Salfredstatic int 2026184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 2027184610Salfred{ 2028184610Salfred static const int delays[] = {250, 500, 750, 1000}; 2029184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 2030184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 2031184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 2032184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 2033184610Salfred 2034184610Salfred if (code & ~0x7f) { 2035184610Salfred return (EINVAL); 2036184610Salfred } 2037184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 2038184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 2039184610Salfred return (0); 2040184610Salfred} 2041184610Salfred 2042184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 2043184610Salfredstatic int 2044184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 2045184610Salfred{ 2046184610Salfred static const int scan[] = { 2047197999Shrs /* 89 */ 2048197999Shrs 0x11c, /* Enter */ 2049197999Shrs /* 90-99 */ 2050197999Shrs 0x11d, /* Ctrl-R */ 2051197999Shrs 0x135, /* Divide */ 2052197999Shrs 0x137 | SCAN_PREFIX_SHIFT, /* PrintScreen */ 2053197999Shrs 0x138, /* Alt-R */ 2054197999Shrs 0x147, /* Home */ 2055197999Shrs 0x148, /* Up */ 2056197999Shrs 0x149, /* PageUp */ 2057197999Shrs 0x14b, /* Left */ 2058197999Shrs 0x14d, /* Right */ 2059197999Shrs 0x14f, /* End */ 2060197999Shrs /* 100-109 */ 2061197999Shrs 0x150, /* Down */ 2062197999Shrs 0x151, /* PageDown */ 2063197999Shrs 0x152, /* Insert */ 2064197999Shrs 0x153, /* Delete */ 2065197999Shrs 0x146, /* XXX Pause/Break */ 2066197999Shrs 0x15b, /* Win_L(Super_L) */ 2067197999Shrs 0x15c, /* Win_R(Super_R) */ 2068197999Shrs 0x15d, /* Application(Menu) */ 2069197999Shrs 2070184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 2071197999Shrs 0x168, /* Sun Type 6 Help */ 2072197999Shrs 0x15e, /* Sun Type 6 Stop */ 2073197999Shrs /* 110 - 119 */ 2074197999Shrs 0x15f, /* Sun Type 6 Again */ 2075197999Shrs 0x160, /* Sun Type 6 Props */ 2076197999Shrs 0x161, /* Sun Type 6 Undo */ 2077197999Shrs 0x162, /* Sun Type 6 Front */ 2078197999Shrs 0x163, /* Sun Type 6 Copy */ 2079197999Shrs 0x164, /* Sun Type 6 Open */ 2080197999Shrs 0x165, /* Sun Type 6 Paste */ 2081197999Shrs 0x166, /* Sun Type 6 Find */ 2082197999Shrs 0x167, /* Sun Type 6 Cut */ 2083197999Shrs 0x125, /* Sun Type 6 Mute */ 2084291146Shselasky /* 120 - 130 */ 2085197999Shrs 0x11f, /* Sun Type 6 VolumeDown */ 2086197999Shrs 0x11e, /* Sun Type 6 VolumeUp */ 2087197999Shrs 0x120, /* Sun Type 6 PowerDown */ 2088197999Shrs 2089197999Shrs /* Japanese 106/109 keyboard */ 2090197999Shrs 0x73, /* Keyboard Intl' 1 (backslash / underscore) */ 2091197999Shrs 0x70, /* Keyboard Intl' 2 (Katakana / Hiragana) */ 2092197999Shrs 0x7d, /* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */ 2093197999Shrs 0x79, /* Keyboard Intl' 4 (Henkan) */ 2094197999Shrs 0x7b, /* Keyboard Intl' 5 (Muhenkan) */ 2095197999Shrs 0x5c, /* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */ 2096291146Shselasky 0x71, /* Apple Keyboard JIS (Kana) */ 2097291146Shselasky 0x72, /* Apple Keyboard JIS (Eisu) */ 2098184610Salfred }; 2099184610Salfred 2100298300Spfg if ((code >= 89) && (code < (int)(89 + nitems(scan)))) { 2101197999Shrs code = scan[code - 89]; 2102184610Salfred } 2103184610Salfred /* Pause/Break */ 2104184610Salfred if ((code == 104) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 2105184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 2106184610Salfred } 2107184610Salfred if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) { 2108184610Salfred code &= ~SCAN_PREFIX_SHIFT; 2109184610Salfred } 2110184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 2111184610Salfred 2112184610Salfred if (code & SCAN_PREFIX) { 2113184610Salfred if (code & SCAN_PREFIX_CTL) { 2114184610Salfred /* Ctrl */ 2115184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 2116184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 2117184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 2118184610Salfred /* Shift */ 2119184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 2120184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 2121184610Salfred } else { 2122184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 2123184610Salfred sc->sc_buffered_char[1] = 0; 2124184610Salfred } 2125184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 2126184610Salfred } 2127184610Salfred return (code); 2128184610Salfred 2129184610Salfred} 2130184610Salfred 2131184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 2132184610Salfred 2133194099Sthompsastatic keyboard_switch_t ukbdsw = { 2134184610Salfred .probe = &ukbd__probe, 2135184610Salfred .init = &ukbd_init, 2136184610Salfred .term = &ukbd_term, 2137184610Salfred .intr = &ukbd_intr, 2138184610Salfred .test_if = &ukbd_test_if, 2139184610Salfred .enable = &ukbd_enable, 2140184610Salfred .disable = &ukbd_disable, 2141184610Salfred .read = &ukbd_read, 2142184610Salfred .check = &ukbd_check, 2143184610Salfred .read_char = &ukbd_read_char, 2144184610Salfred .check_char = &ukbd_check_char, 2145184610Salfred .ioctl = &ukbd_ioctl, 2146184610Salfred .lock = &ukbd_lock, 2147184610Salfred .clear_state = &ukbd_clear_state, 2148184610Salfred .get_state = &ukbd_get_state, 2149184610Salfred .set_state = &ukbd_set_state, 2150184610Salfred .get_fkeystr = &genkbd_get_fkeystr, 2151184610Salfred .poll = &ukbd_poll, 2152184610Salfred .diag = &genkbd_diag, 2153184610Salfred}; 2154184610Salfred 2155184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 2156184610Salfred 2157184610Salfredstatic int 2158184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 2159184610Salfred{ 2160184610Salfred switch (what) { 2161193315Sthompsa case MOD_LOAD: 2162184610Salfred kbd_add_driver(&ukbd_kbd_driver); 2163184610Salfred break; 2164184610Salfred case MOD_UNLOAD: 2165184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 2166184610Salfred break; 2167184610Salfred } 2168184610Salfred return (0); 2169184610Salfred} 2170184610Salfred 2171184610Salfredstatic devclass_t ukbd_devclass; 2172184610Salfred 2173184610Salfredstatic device_method_t ukbd_methods[] = { 2174184610Salfred DEVMETHOD(device_probe, ukbd_probe), 2175184610Salfred DEVMETHOD(device_attach, ukbd_attach), 2176184610Salfred DEVMETHOD(device_detach, ukbd_detach), 2177184610Salfred DEVMETHOD(device_resume, ukbd_resume), 2178246128Ssbz 2179246128Ssbz DEVMETHOD_END 2180184610Salfred}; 2181184610Salfred 2182184610Salfredstatic driver_t ukbd_driver = { 2183184610Salfred .name = "ukbd", 2184184610Salfred .methods = ukbd_methods, 2185184610Salfred .size = sizeof(struct ukbd_softc), 2186184610Salfred}; 2187184610Salfred 2188189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 2189188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 2190212122SthompsaMODULE_VERSION(ukbd, 1); 2191292080SimpUSB_PNP_HOST_INFO(ukbd_devs); 2192