1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD$"); 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"); 98242126ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, 99184610Salfred &ukbd_debug, 0, "Debug level"); 100242126ShselaskyTUNABLE_INT("hw.usb.ukbd.debug", &ukbd_debug); 101242126ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RW | CTLFLAG_TUN, 102196489Salfred &ukbd_no_leds, 0, "Disables setting of keyboard leds"); 103199675SthompsaTUNABLE_INT("hw.usb.ukbd.no_leds", &ukbd_no_leds); 104253332ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RW | CTLFLAG_TUN, 105253332Shselasky &ukbd_pollrate, 0, "Force this polling rate, 1-1000Hz"); 106253332ShselaskyTUNABLE_INT("hw.usb.ukbd.pollrate", &ukbd_pollrate); 107184610Salfred#endif 108184610Salfred 109184610Salfred#define UKBD_EMULATE_ATSCANCODE 1 110184610Salfred#define UKBD_DRIVER_NAME "ukbd" 111184610Salfred#define UKBD_NMOD 8 /* units */ 112184610Salfred#define UKBD_NKEYCODE 6 /* units */ 113184610Salfred#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */ 114305645Shselasky#define UKBD_IN_BUF_FULL ((UKBD_IN_BUF_SIZE / 2) - 1) /* bytes */ 115184610Salfred#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */ 116223755Shselasky#define UKBD_BUFFER_SIZE 64 /* bytes */ 117184610Salfred 118184610Salfredstruct ukbd_data { 119223755Shselasky uint16_t modifiers; 120184610Salfred#define MOD_CONTROL_L 0x01 121184610Salfred#define MOD_CONTROL_R 0x10 122184610Salfred#define MOD_SHIFT_L 0x02 123184610Salfred#define MOD_SHIFT_R 0x20 124184610Salfred#define MOD_ALT_L 0x04 125184610Salfred#define MOD_ALT_R 0x40 126184610Salfred#define MOD_WIN_L 0x08 127184610Salfred#define MOD_WIN_R 0x80 128223755Shselasky/* internal */ 129223755Shselasky#define MOD_EJECT 0x0100 130223755Shselasky#define MOD_FN 0x0200 131184610Salfred uint8_t keycode[UKBD_NKEYCODE]; 132192925Sthompsa}; 133184610Salfred 134187259Sthompsaenum { 135305645Shselasky UKBD_INTR_DT_0, 136305645Shselasky UKBD_INTR_DT_1, 137187259Sthompsa UKBD_CTRL_LED, 138192925Sthompsa UKBD_N_TRANSFER, 139187259Sthompsa}; 140187259Sthompsa 141184610Salfredstruct ukbd_softc { 142184610Salfred keyboard_t sc_kbd; 143184610Salfred keymap_t sc_keymap; 144184610Salfred accentmap_t sc_accmap; 145184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 146192925Sthompsa struct hid_location sc_loc_apple_eject; 147192925Sthompsa struct hid_location sc_loc_apple_fn; 148223755Shselasky struct hid_location sc_loc_ctrl_l; 149223755Shselasky struct hid_location sc_loc_ctrl_r; 150223755Shselasky struct hid_location sc_loc_shift_l; 151223755Shselasky struct hid_location sc_loc_shift_r; 152223755Shselasky struct hid_location sc_loc_alt_l; 153223755Shselasky struct hid_location sc_loc_alt_r; 154223755Shselasky struct hid_location sc_loc_win_l; 155223755Shselasky struct hid_location sc_loc_win_r; 156223755Shselasky struct hid_location sc_loc_events; 157223755Shselasky struct hid_location sc_loc_numlock; 158223755Shselasky struct hid_location sc_loc_capslock; 159223755Shselasky struct hid_location sc_loc_scrolllock; 160192984Sthompsa struct usb_callout sc_callout; 161184610Salfred struct ukbd_data sc_ndata; 162184610Salfred struct ukbd_data sc_odata; 163184610Salfred 164203896Sthompsa struct thread *sc_poll_thread; 165192984Sthompsa struct usb_device *sc_udev; 166192984Sthompsa struct usb_interface *sc_iface; 167192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 168184610Salfred 169184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 170184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 171184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 172184610Salfred uint32_t sc_time_ms; 173184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 174184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 175184610Salfred uint32_t sc_buffered_char[2]; 176184610Salfred#endif 177184610Salfred uint32_t sc_flags; /* flags */ 178223755Shselasky#define UKBD_FLAG_COMPOSE 0x00000001 179223755Shselasky#define UKBD_FLAG_POLLING 0x00000002 180223755Shselasky#define UKBD_FLAG_SET_LEDS 0x00000004 181223755Shselasky#define UKBD_FLAG_ATTACHED 0x00000010 182223755Shselasky#define UKBD_FLAG_GONE 0x00000020 183184610Salfred 184223755Shselasky#define UKBD_FLAG_HID_MASK 0x003fffc0 185223755Shselasky#define UKBD_FLAG_APPLE_EJECT 0x00000040 186223755Shselasky#define UKBD_FLAG_APPLE_FN 0x00000080 187223755Shselasky#define UKBD_FLAG_APPLE_SWAP 0x00000100 188223755Shselasky#define UKBD_FLAG_TIMER_RUNNING 0x00000200 189223755Shselasky#define UKBD_FLAG_CTRL_L 0x00000400 190223755Shselasky#define UKBD_FLAG_CTRL_R 0x00000800 191223755Shselasky#define UKBD_FLAG_SHIFT_L 0x00001000 192223755Shselasky#define UKBD_FLAG_SHIFT_R 0x00002000 193223755Shselasky#define UKBD_FLAG_ALT_L 0x00004000 194223755Shselasky#define UKBD_FLAG_ALT_R 0x00008000 195223755Shselasky#define UKBD_FLAG_WIN_L 0x00010000 196223755Shselasky#define UKBD_FLAG_WIN_R 0x00020000 197223755Shselasky#define UKBD_FLAG_EVENTS 0x00040000 198223755Shselasky#define UKBD_FLAG_NUMLOCK 0x00080000 199223755Shselasky#define UKBD_FLAG_CAPSLOCK 0x00100000 200223755Shselasky#define UKBD_FLAG_SCROLLLOCK 0x00200000 201223755Shselasky 202203896Sthompsa int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 203203896Sthompsa int sc_state; /* shift/lock key state */ 204203896Sthompsa int sc_accents; /* accent key index (> 0) */ 205304125Shselasky int sc_polling; /* polling recursion count */ 206223755Shselasky int sc_led_size; 207223755Shselasky int sc_kbd_size; 208184610Salfred 209184610Salfred uint16_t sc_inputs; 210184610Salfred uint16_t sc_inputhead; 211184610Salfred uint16_t sc_inputtail; 212223755Shselasky uint16_t sc_modifiers; 213184610Salfred 214184610Salfred uint8_t sc_leds; /* store for async led requests */ 215184610Salfred uint8_t sc_iface_index; 216184610Salfred uint8_t sc_iface_no; 217223755Shselasky uint8_t sc_id_apple_eject; 218223755Shselasky uint8_t sc_id_apple_fn; 219223755Shselasky uint8_t sc_id_ctrl_l; 220223755Shselasky uint8_t sc_id_ctrl_r; 221223755Shselasky uint8_t sc_id_shift_l; 222223755Shselasky uint8_t sc_id_shift_r; 223223755Shselasky uint8_t sc_id_alt_l; 224223755Shselasky uint8_t sc_id_alt_r; 225223755Shselasky uint8_t sc_id_win_l; 226223755Shselasky uint8_t sc_id_win_r; 227223755Shselasky uint8_t sc_id_event; 228223755Shselasky uint8_t sc_id_numlock; 229223755Shselasky uint8_t sc_id_capslock; 230223755Shselasky uint8_t sc_id_scrolllock; 231223755Shselasky uint8_t sc_id_events; 232192925Sthompsa uint8_t sc_kbd_id; 233223755Shselasky 234223755Shselasky uint8_t sc_buffer[UKBD_BUFFER_SIZE]; 235184610Salfred}; 236184610Salfred 237184610Salfred#define KEY_ERROR 0x01 238184610Salfred 239184610Salfred#define KEY_PRESS 0 240184610Salfred#define KEY_RELEASE 0x400 241184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 242184610Salfred 243184610Salfred#define SCAN_PRESS 0 244184610Salfred#define SCAN_RELEASE 0x80 245184610Salfred#define SCAN_PREFIX_E0 0x100 246184610Salfred#define SCAN_PREFIX_E1 0x200 247184610Salfred#define SCAN_PREFIX_CTL 0x400 248184610Salfred#define SCAN_PREFIX_SHIFT 0x800 249184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 250184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 251184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 252184610Salfred 253228765Savg#define UKBD_LOCK() mtx_lock(&Giant) 254228765Savg#define UKBD_UNLOCK() mtx_unlock(&Giant) 255228765Savg 256228765Savg#ifdef INVARIANTS 257228765Savg 258228765Savg/* 259228765Savg * Assert that the lock is held in all contexts 260228765Savg * where the code can be executed. 261228765Savg */ 262228765Savg#define UKBD_LOCK_ASSERT() mtx_assert(&Giant, MA_OWNED) 263228765Savg 264228765Savg/* 265228765Savg * Assert that the lock is held in the contexts 266228765Savg * where it really has to be so. 267228765Savg */ 268228765Savg#define UKBD_CTX_LOCK_ASSERT() \ 269228765Savg do { \ 270228765Savg if (!kdb_active && panicstr == NULL) \ 271228765Savg mtx_assert(&Giant, MA_OWNED); \ 272228765Savg } while (0) 273228765Savg#else 274228765Savg 275228765Savg#define UKBD_LOCK_ASSERT() (void)0 276228765Savg#define UKBD_CTX_LOCK_ASSERT() (void)0 277228765Savg 278228765Savg#endif 279228765Savg 280184610Salfredstruct ukbd_mods { 281184610Salfred uint32_t mask, key; 282184610Salfred}; 283184610Salfred 284184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 285184610Salfred {MOD_CONTROL_L, 0xe0}, 286184610Salfred {MOD_CONTROL_R, 0xe4}, 287184610Salfred {MOD_SHIFT_L, 0xe1}, 288184610Salfred {MOD_SHIFT_R, 0xe5}, 289184610Salfred {MOD_ALT_L, 0xe2}, 290184610Salfred {MOD_ALT_R, 0xe6}, 291184610Salfred {MOD_WIN_L, 0xe3}, 292184610Salfred {MOD_WIN_R, 0xe7}, 293184610Salfred}; 294184610Salfred 295184610Salfred#define NN 0 /* no translation */ 296184610Salfred/* 297184610Salfred * Translate USB keycodes to AT keyboard scancodes. 298184610Salfred */ 299184610Salfred/* 300184610Salfred * FIXME: Mac USB keyboard generates: 301184610Salfred * 0x53: keypad NumLock/Clear 302184610Salfred * 0x66: Power 303184610Salfred * 0x67: keypad = 304184610Salfred * 0x68: F13 305184610Salfred * 0x69: F14 306184610Salfred * 0x6a: F15 307291254Shselasky * 308291254Shselasky * USB Apple Keyboard JIS generates: 309291254Shselasky * 0x90: Kana 310291254Shselasky * 0x91: Eisu 311184610Salfred */ 312184610Salfredstatic const uint8_t ukbd_trtab[256] = { 313184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 314184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 315184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 316184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 317184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 318184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 319184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 320184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 321184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 322184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 323184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 324184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 325184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 326184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 327184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 328184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 329197999Shrs 121, 120, NN, NN, NN, NN, NN, 123, /* 80 - 87 */ 330197999Shrs 124, 125, 126, 127, 128, NN, NN, NN, /* 88 - 8F */ 331291254Shselasky 129, 130, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 332184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 333184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 334184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 335184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 336184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 337184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 338184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 339184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 340184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 341184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 342184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 343184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 344184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 345184610Salfred}; 346184610Salfred 347223755Shselaskystatic const uint8_t ukbd_boot_desc[] = { 348223755Shselasky 0x05, 0x01, 0x09, 0x06, 0xa1, 349223755Shselasky 0x01, 0x05, 0x07, 0x19, 0xe0, 350223755Shselasky 0x29, 0xe7, 0x15, 0x00, 0x25, 351223755Shselasky 0x01, 0x75, 0x01, 0x95, 0x08, 352223755Shselasky 0x81, 0x02, 0x95, 0x01, 0x75, 353223755Shselasky 0x08, 0x81, 0x01, 0x95, 0x03, 354223755Shselasky 0x75, 0x01, 0x05, 0x08, 0x19, 355223755Shselasky 0x01, 0x29, 0x03, 0x91, 0x02, 356223755Shselasky 0x95, 0x05, 0x75, 0x01, 0x91, 357223755Shselasky 0x01, 0x95, 0x06, 0x75, 0x08, 358223755Shselasky 0x15, 0x00, 0x26, 0xff, 0x00, 359223755Shselasky 0x05, 0x07, 0x19, 0x00, 0x2a, 360223755Shselasky 0xff, 0x00, 0x81, 0x00, 0xc0 361223755Shselasky}; 362223755Shselasky 363184610Salfred/* prototypes */ 364185948Sthompsastatic void ukbd_timeout(void *); 365185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 366185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 367184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 368185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 369184610Salfred#endif 370185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 371185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 372185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 373185948Sthompsastatic int ukbd_enable(keyboard_t *); 374185948Sthompsastatic int ukbd_disable(keyboard_t *); 375185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 376203896Sthompsastatic void ukbd_event_keyinput(struct ukbd_softc *); 377184610Salfred 378184610Salfredstatic device_probe_t ukbd_probe; 379184610Salfredstatic device_attach_t ukbd_attach; 380184610Salfredstatic device_detach_t ukbd_detach; 381184610Salfredstatic device_resume_t ukbd_resume; 382184610Salfred 383196489Salfredstatic uint8_t 384196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc) 385196489Salfred{ 386196489Salfred uint8_t i; 387196489Salfred uint8_t j; 388196489Salfred 389196489Salfred for (j = i = 0; i < UKBD_NKEYCODE; i++) 390196489Salfred j |= sc->sc_odata.keycode[i]; 391196489Salfred 392196489Salfred return (j ? 1 : 0); 393196489Salfred} 394196489Salfred 395184610Salfredstatic void 396196489Salfredukbd_start_timer(struct ukbd_softc *sc) 397196489Salfred{ 398196489Salfred sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; 399196489Salfred usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 400196489Salfred} 401196489Salfred 402196489Salfredstatic void 403184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 404184610Salfred{ 405184610Salfred 406228765Savg UKBD_CTX_LOCK_ASSERT(); 407228765Savg 408184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 409184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 410184610Salfred 411184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 412184610Salfred sc->sc_input[sc->sc_inputtail] = key; 413184610Salfred ++(sc->sc_inputs); 414184610Salfred ++(sc->sc_inputtail); 415184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 416184610Salfred sc->sc_inputtail = 0; 417184610Salfred } 418184610Salfred } else { 419184610Salfred DPRINTF("input buffer is full\n"); 420184610Salfred } 421184610Salfred} 422184610Salfred 423195960Salfredstatic void 424228765Savgukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 425223989Shselasky{ 426223989Shselasky 427228765Savg UKBD_CTX_LOCK_ASSERT(); 428228765Savg KASSERT((sc->sc_flags & UKBD_FLAG_POLLING) != 0, 429228765Savg ("ukbd_do_poll called when not polling\n")); 430195960Salfred DPRINTFN(2, "polling\n"); 431195960Salfred 432228765Savg if (!kdb_active && !SCHEDULER_STOPPED()) { 433228765Savg /* 434228765Savg * In this context the kernel is polling for input, 435228765Savg * but the USB subsystem works in normal interrupt-driven 436228765Savg * mode, so we just wait on the USB threads to do the job. 437228765Savg * Note that we currently hold the Giant, but it's also used 438228765Savg * as the transfer mtx, so we must release it while waiting. 439228765Savg */ 440203896Sthompsa while (sc->sc_inputs == 0) { 441228765Savg /* 442228765Savg * Give USB threads a chance to run. Note that 443228765Savg * kern_yield performs DROP_GIANT + PICKUP_GIANT. 444228765Savg */ 445228765Savg kern_yield(PRI_UNCHANGED); 446203896Sthompsa if (!wait) 447203896Sthompsa break; 448203896Sthompsa } 449228765Savg return; 450203896Sthompsa } 451198152Sthompsa 452195960Salfred while (sc->sc_inputs == 0) { 453195960Salfred 454195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 455195960Salfred 456196489Salfred /* Delay-optimised support for repetition of keys */ 457196489Salfred if (ukbd_any_key_pressed(sc)) { 458196489Salfred /* a key is pressed - need timekeeping */ 459196489Salfred DELAY(1000); 460195960Salfred 461196489Salfred /* 1 millisecond has passed */ 462196489Salfred sc->sc_time_ms += 1; 463196489Salfred } 464195960Salfred 465195960Salfred ukbd_interrupt(sc); 466195960Salfred 467195960Salfred if (!wait) 468195960Salfred break; 469195960Salfred } 470195960Salfred} 471195960Salfred 472184610Salfredstatic int32_t 473184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 474184610Salfred{ 475184610Salfred int32_t c; 476184610Salfred 477228765Savg UKBD_CTX_LOCK_ASSERT(); 478228765Savg KASSERT((!kdb_active && !SCHEDULER_STOPPED()) 479228765Savg || (sc->sc_flags & UKBD_FLAG_POLLING) != 0, 480228765Savg ("not polling in kdb or panic\n")); 481184610Salfred 482261478Shselasky if (sc->sc_inputs == 0 && 483261478Shselasky (sc->sc_flags & UKBD_FLAG_GONE) == 0) { 484184610Salfred /* start transfer, if not already started */ 485305645Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 486305645Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 487184610Salfred } 488203896Sthompsa 489203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 490195960Salfred ukbd_do_poll(sc, wait); 491203896Sthompsa 492184610Salfred if (sc->sc_inputs == 0) { 493184610Salfred c = -1; 494184610Salfred } else { 495184610Salfred c = sc->sc_input[sc->sc_inputhead]; 496184610Salfred --(sc->sc_inputs); 497184610Salfred ++(sc->sc_inputhead); 498184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 499184610Salfred sc->sc_inputhead = 0; 500184610Salfred } 501184610Salfred } 502184610Salfred return (c); 503184610Salfred} 504184610Salfred 505184610Salfredstatic void 506184610Salfredukbd_interrupt(struct ukbd_softc *sc) 507184610Salfred{ 508184610Salfred uint32_t n_mod; 509184610Salfred uint32_t o_mod; 510184610Salfred uint32_t now = sc->sc_time_ms; 511184610Salfred uint32_t dtime; 512184610Salfred uint8_t key; 513184610Salfred uint8_t i; 514184610Salfred uint8_t j; 515184610Salfred 516228765Savg UKBD_CTX_LOCK_ASSERT(); 517228765Savg 518203896Sthompsa if (sc->sc_ndata.keycode[0] == KEY_ERROR) 519203896Sthompsa return; 520203896Sthompsa 521184610Salfred n_mod = sc->sc_ndata.modifiers; 522184610Salfred o_mod = sc->sc_odata.modifiers; 523184610Salfred if (n_mod != o_mod) { 524184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 525184610Salfred if ((n_mod & ukbd_mods[i].mask) != 526184610Salfred (o_mod & ukbd_mods[i].mask)) { 527184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 528184610Salfred ((n_mod & ukbd_mods[i].mask) ? 529184610Salfred KEY_PRESS : KEY_RELEASE)); 530184610Salfred } 531184610Salfred } 532184610Salfred } 533184610Salfred /* Check for released keys. */ 534184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 535184610Salfred key = sc->sc_odata.keycode[i]; 536184610Salfred if (key == 0) { 537184610Salfred continue; 538184610Salfred } 539184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 540184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 541184610Salfred continue; 542184610Salfred } 543184610Salfred if (key == sc->sc_ndata.keycode[j]) { 544184610Salfred goto rfound; 545184610Salfred } 546184610Salfred } 547184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 548184610Salfredrfound: ; 549184610Salfred } 550184610Salfred 551184610Salfred /* Check for pressed keys. */ 552184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 553184610Salfred key = sc->sc_ndata.keycode[i]; 554184610Salfred if (key == 0) { 555184610Salfred continue; 556184610Salfred } 557184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 558184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 559184610Salfred if (sc->sc_odata.keycode[j] == 0) { 560184610Salfred continue; 561184610Salfred } 562184610Salfred if (key == sc->sc_odata.keycode[j]) { 563184610Salfred 564184610Salfred /* key is still pressed */ 565184610Salfred 566184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 567184610Salfred dtime = (sc->sc_otime[j] - now); 568184610Salfred 569184610Salfred if (!(dtime & 0x80000000)) { 570184610Salfred /* time has not elapsed */ 571184610Salfred goto pfound; 572184610Salfred } 573184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 574184610Salfred break; 575184610Salfred } 576184610Salfred } 577184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 578184610Salfred 579184610Salfred /* 580184610Salfred * If any other key is presently down, force its repeat to be 581184610Salfred * well in the future (100s). This makes the last key to be 582184610Salfred * pressed do the autorepeat. 583184610Salfred */ 584184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 585184610Salfred if (j != i) 586184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 587184610Salfred } 588184610Salfredpfound: ; 589184610Salfred } 590184610Salfred 591184610Salfred sc->sc_odata = sc->sc_ndata; 592184610Salfred 593203896Sthompsa memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime)); 594184610Salfred 595203896Sthompsa ukbd_event_keyinput(sc); 596203896Sthompsa} 597203896Sthompsa 598203896Sthompsastatic void 599203896Sthompsaukbd_event_keyinput(struct ukbd_softc *sc) 600203896Sthompsa{ 601203896Sthompsa int c; 602203896Sthompsa 603228765Savg UKBD_CTX_LOCK_ASSERT(); 604228765Savg 605228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) != 0) 606203896Sthompsa return; 607203896Sthompsa 608203896Sthompsa if (sc->sc_inputs == 0) 609203896Sthompsa return; 610203896Sthompsa 611184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 612184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 613184610Salfred /* let the callback function process the input */ 614184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 615184610Salfred sc->sc_kbd.kb_callback.kc_arg); 616184610Salfred } else { 617184610Salfred /* read and discard the input, no one is waiting for it */ 618184610Salfred do { 619184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 620184610Salfred } while (c != NOKEY); 621184610Salfred } 622184610Salfred} 623184610Salfred 624184610Salfredstatic void 625184610Salfredukbd_timeout(void *arg) 626184610Salfred{ 627184610Salfred struct ukbd_softc *sc = arg; 628184610Salfred 629228765Savg UKBD_LOCK_ASSERT(); 630184610Salfred 631203896Sthompsa sc->sc_time_ms += 25; /* milliseconds */ 632203896Sthompsa 633184610Salfred ukbd_interrupt(sc); 634184610Salfred 635203896Sthompsa /* Make sure any leftover key events gets read out */ 636203896Sthompsa ukbd_event_keyinput(sc); 637203896Sthompsa 638203896Sthompsa if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { 639196489Salfred ukbd_start_timer(sc); 640196489Salfred } else { 641196489Salfred sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; 642196489Salfred } 643184610Salfred} 644184610Salfred 645192925Sthompsastatic uint8_t 646192925Sthompsaukbd_apple_fn(uint8_t keycode) { 647192925Sthompsa switch (keycode) { 648192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 649192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 650192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 651192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 652192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 653192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 654192925Sthompsa default: return keycode; 655192925Sthompsa } 656192925Sthompsa} 657184610Salfred 658192925Sthompsastatic uint8_t 659192925Sthompsaukbd_apple_swap(uint8_t keycode) { 660192925Sthompsa switch (keycode) { 661192925Sthompsa case 0x35: return 0x64; 662192925Sthompsa case 0x64: return 0x35; 663192925Sthompsa default: return keycode; 664184610Salfred } 665184610Salfred} 666184610Salfred 667184610Salfredstatic void 668194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 669184610Salfred{ 670194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 671194677Sthompsa struct usb_page_cache *pc; 672184610Salfred uint8_t i; 673192925Sthompsa uint8_t offset; 674192925Sthompsa uint8_t id; 675194677Sthompsa int len; 676184610Salfred 677228765Savg UKBD_LOCK_ASSERT(); 678228765Savg 679194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 680194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 681194677Sthompsa 682184610Salfred switch (USB_GET_STATE(xfer)) { 683184610Salfred case USB_ST_TRANSFERRED: 684184610Salfred DPRINTF("actlen=%d bytes\n", len); 685184610Salfred 686192925Sthompsa if (len == 0) { 687192925Sthompsa DPRINTF("zero length data\n"); 688192925Sthompsa goto tr_setup; 689192925Sthompsa } 690192925Sthompsa 691192925Sthompsa if (sc->sc_kbd_id != 0) { 692192925Sthompsa /* check and remove HID ID byte */ 693194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 694223755Shselasky offset = 1; 695223755Shselasky len--; 696223755Shselasky if (len == 0) { 697223755Shselasky DPRINTF("zero length data\n"); 698192925Sthompsa goto tr_setup; 699192925Sthompsa } 700192925Sthompsa } else { 701192925Sthompsa offset = 0; 702223755Shselasky id = 0; 703192925Sthompsa } 704192925Sthompsa 705223755Shselasky if (len > UKBD_BUFFER_SIZE) 706223755Shselasky len = UKBD_BUFFER_SIZE; 707192925Sthompsa 708223755Shselasky /* get data */ 709223755Shselasky usbd_copy_out(pc, offset, sc->sc_buffer, len); 710192925Sthompsa 711223755Shselasky /* clear temporary storage */ 712223755Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 713192925Sthompsa 714223755Shselasky /* scan through HID data */ 715223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 716223755Shselasky (id == sc->sc_id_apple_eject)) { 717223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject)) 718223755Shselasky sc->sc_modifiers |= MOD_EJECT; 719192925Sthompsa else 720223755Shselasky sc->sc_modifiers &= ~MOD_EJECT; 721223755Shselasky } 722223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 723223755Shselasky (id == sc->sc_id_apple_fn)) { 724223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn)) 725223755Shselasky sc->sc_modifiers |= MOD_FN; 726223755Shselasky else 727223755Shselasky sc->sc_modifiers &= ~MOD_FN; 728223755Shselasky } 729223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_L) && 730223755Shselasky (id == sc->sc_id_ctrl_l)) { 731223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_l)) 732223755Shselasky sc-> sc_modifiers |= MOD_CONTROL_L; 733223755Shselasky else 734223755Shselasky sc-> sc_modifiers &= ~MOD_CONTROL_L; 735223755Shselasky } 736223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_R) && 737223755Shselasky (id == sc->sc_id_ctrl_r)) { 738223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_r)) 739223755Shselasky sc->sc_modifiers |= MOD_CONTROL_R; 740223755Shselasky else 741223755Shselasky sc->sc_modifiers &= ~MOD_CONTROL_R; 742223755Shselasky } 743223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) && 744223755Shselasky (id == sc->sc_id_shift_l)) { 745223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_l)) 746223755Shselasky sc->sc_modifiers |= MOD_SHIFT_L; 747223755Shselasky else 748223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_L; 749223755Shselasky } 750223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) && 751223755Shselasky (id == sc->sc_id_shift_r)) { 752223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_r)) 753223755Shselasky sc->sc_modifiers |= MOD_SHIFT_R; 754223755Shselasky else 755223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_R; 756223755Shselasky } 757223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_L) && 758223755Shselasky (id == sc->sc_id_alt_l)) { 759223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l)) 760223755Shselasky sc->sc_modifiers |= MOD_ALT_L; 761223755Shselasky else 762223755Shselasky sc->sc_modifiers &= ~MOD_ALT_L; 763223755Shselasky } 764223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_R) && 765223755Shselasky (id == sc->sc_id_alt_r)) { 766223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r)) 767223755Shselasky sc->sc_modifiers |= MOD_ALT_R; 768223755Shselasky else 769223755Shselasky sc->sc_modifiers &= ~MOD_ALT_R; 770223755Shselasky } 771223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_L) && 772223755Shselasky (id == sc->sc_id_win_l)) { 773223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l)) 774223755Shselasky sc->sc_modifiers |= MOD_WIN_L; 775223755Shselasky else 776223755Shselasky sc->sc_modifiers &= ~MOD_WIN_L; 777223755Shselasky } 778223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_R) && 779223755Shselasky (id == sc->sc_id_win_r)) { 780223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r)) 781223755Shselasky sc->sc_modifiers |= MOD_WIN_R; 782223755Shselasky else 783223755Shselasky sc->sc_modifiers &= ~MOD_WIN_R; 784223755Shselasky } 785192925Sthompsa 786223755Shselasky sc->sc_ndata.modifiers = sc->sc_modifiers; 787223755Shselasky 788223755Shselasky if ((sc->sc_flags & UKBD_FLAG_EVENTS) && 789223755Shselasky (id == sc->sc_id_events)) { 790223755Shselasky i = sc->sc_loc_events.count; 791223755Shselasky if (i > UKBD_NKEYCODE) 792223755Shselasky i = UKBD_NKEYCODE; 793223755Shselasky if (i > len) 794223755Shselasky i = len; 795223755Shselasky while (i--) { 796223755Shselasky sc->sc_ndata.keycode[i] = 797223755Shselasky hid_get_data(sc->sc_buffer + i, len - i, 798223755Shselasky &sc->sc_loc_events); 799184610Salfred } 800223755Shselasky } 801223755Shselasky 802223755Shselasky#ifdef USB_DEBUG 803223755Shselasky DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers); 804223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 805223755Shselasky if (sc->sc_ndata.keycode[i]) { 806223755Shselasky DPRINTF("[%d] = 0x%02x\n", 807223755Shselasky (int)i, (int)sc->sc_ndata.keycode[i]); 808223755Shselasky } 809223755Shselasky } 810223755Shselasky#endif 811223755Shselasky if (sc->sc_modifiers & MOD_FN) { 812184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 813223755Shselasky sc->sc_ndata.keycode[i] = 814223755Shselasky ukbd_apple_fn(sc->sc_ndata.keycode[i]); 815184610Salfred } 816223755Shselasky } 817192925Sthompsa 818223755Shselasky if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 819223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 820223755Shselasky sc->sc_ndata.keycode[i] = 821223755Shselasky ukbd_apple_swap(sc->sc_ndata.keycode[i]); 822192925Sthompsa } 823223755Shselasky } 824192925Sthompsa 825223755Shselasky ukbd_interrupt(sc); 826192925Sthompsa 827223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { 828223755Shselasky if (ukbd_any_key_pressed(sc)) { 829223755Shselasky ukbd_start_timer(sc); 830196489Salfred } 831184610Salfred } 832223755Shselasky 833184610Salfred case USB_ST_SETUP: 834192925Sthompsatr_setup: 835184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 836194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 837194228Sthompsa usbd_transfer_submit(xfer); 838184610Salfred } else { 839184610Salfred DPRINTF("input queue is full!\n"); 840184610Salfred } 841192925Sthompsa break; 842184610Salfred 843184610Salfred default: /* Error */ 844194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 845184610Salfred 846194677Sthompsa if (error != USB_ERR_CANCELLED) { 847184610Salfred /* try to clear stall first */ 848194677Sthompsa usbd_xfer_set_stall(xfer); 849192925Sthompsa goto tr_setup; 850184610Salfred } 851192925Sthompsa break; 852184610Salfred } 853184610Salfred} 854184610Salfred 855184610Salfredstatic void 856194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 857184610Salfred{ 858223755Shselasky struct ukbd_softc *sc = usbd_xfer_softc(xfer); 859192984Sthompsa struct usb_device_request req; 860194677Sthompsa struct usb_page_cache *pc; 861223755Shselasky uint8_t id; 862223755Shselasky uint8_t any; 863223755Shselasky int len; 864184610Salfred 865228765Savg UKBD_LOCK_ASSERT(); 866228765Savg 867207077Sthompsa#ifdef USB_DEBUG 868196489Salfred if (ukbd_no_leds) 869196489Salfred return; 870196489Salfred#endif 871196489Salfred 872184610Salfred switch (USB_GET_STATE(xfer)) { 873184610Salfred case USB_ST_TRANSFERRED: 874184610Salfred case USB_ST_SETUP: 875223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS)) 876223755Shselasky break; 877223755Shselasky sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 878184610Salfred 879223755Shselasky req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 880223755Shselasky req.bRequest = UR_SET_REPORT; 881223755Shselasky USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 882223755Shselasky req.wIndex[0] = sc->sc_iface_no; 883223755Shselasky req.wIndex[1] = 0; 884223755Shselasky req.wLength[1] = 0; 885184610Salfred 886223755Shselasky memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE); 887223755Shselasky 888223755Shselasky id = 0; 889223755Shselasky any = 0; 890223755Shselasky 891223755Shselasky /* Assumption: All led bits must be in the same ID. */ 892223755Shselasky 893223755Shselasky if (sc->sc_flags & UKBD_FLAG_NUMLOCK) { 894223755Shselasky if (sc->sc_leds & NLKED) { 895223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 896223755Shselasky &sc->sc_loc_numlock, 1); 897192925Sthompsa } 898223755Shselasky id = sc->sc_id_numlock; 899223755Shselasky any = 1; 900223755Shselasky } 901184610Salfred 902223755Shselasky if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) { 903223755Shselasky if (sc->sc_leds & SLKED) { 904223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 905223755Shselasky &sc->sc_loc_scrolllock, 1); 906223755Shselasky } 907223755Shselasky id = sc->sc_id_scrolllock; 908223755Shselasky any = 1; 909223755Shselasky } 910184610Salfred 911223755Shselasky if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) { 912223755Shselasky if (sc->sc_leds & CLKED) { 913223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 914223755Shselasky &sc->sc_loc_capslock, 1); 915223755Shselasky } 916223755Shselasky id = sc->sc_id_capslock; 917223755Shselasky any = 1; 918184610Salfred } 919223755Shselasky 920223755Shselasky /* if no leds, nothing to do */ 921223755Shselasky if (!any) 922223755Shselasky break; 923223755Shselasky 924223755Shselasky /* range check output report length */ 925223755Shselasky len = sc->sc_led_size; 926223755Shselasky if (len > (UKBD_BUFFER_SIZE - 1)) 927223755Shselasky len = (UKBD_BUFFER_SIZE - 1); 928223755Shselasky 929223755Shselasky /* check if we need to prefix an ID byte */ 930223755Shselasky sc->sc_buffer[0] = id; 931223755Shselasky 932223755Shselasky pc = usbd_xfer_get_frame(xfer, 1); 933223755Shselasky if (id != 0) { 934223755Shselasky len++; 935223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer, len); 936223755Shselasky } else { 937223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer + 1, len); 938223755Shselasky } 939223755Shselasky req.wLength[0] = len; 940223755Shselasky usbd_xfer_set_frame_len(xfer, 1, len); 941223755Shselasky 942223755Shselasky DPRINTF("len=%d, id=%d\n", len, id); 943223755Shselasky 944223755Shselasky /* setup control request last */ 945223755Shselasky pc = usbd_xfer_get_frame(xfer, 0); 946223755Shselasky usbd_copy_in(pc, 0, &req, sizeof(req)); 947223755Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 948223755Shselasky 949223755Shselasky /* start data transfer */ 950223755Shselasky usbd_xfer_set_frames(xfer, 2); 951223755Shselasky usbd_transfer_submit(xfer); 952196489Salfred break; 953184610Salfred 954184610Salfred default: /* Error */ 955212128Sthompsa DPRINTFN(1, "error=%s\n", usbd_errstr(error)); 956196489Salfred break; 957184610Salfred } 958184610Salfred} 959184610Salfred 960192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 961184610Salfred 962305645Shselasky [UKBD_INTR_DT_0] = { 963184610Salfred .type = UE_INTERRUPT, 964184610Salfred .endpoint = UE_ADDR_ANY, 965184610Salfred .direction = UE_DIR_IN, 966190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 967190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 968190734Sthompsa .callback = &ukbd_intr_callback, 969184610Salfred }, 970184610Salfred 971305645Shselasky [UKBD_INTR_DT_1] = { 972305645Shselasky .type = UE_INTERRUPT, 973305645Shselasky .endpoint = UE_ADDR_ANY, 974305645Shselasky .direction = UE_DIR_IN, 975305645Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 976305645Shselasky .bufsize = 0, /* use wMaxPacketSize */ 977305645Shselasky .callback = &ukbd_intr_callback, 978305645Shselasky }, 979305645Shselasky 980187259Sthompsa [UKBD_CTRL_LED] = { 981184610Salfred .type = UE_CONTROL, 982184610Salfred .endpoint = 0x00, /* Control pipe */ 983184610Salfred .direction = UE_DIR_ANY, 984223755Shselasky .bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE, 985190734Sthompsa .callback = &ukbd_set_leds_callback, 986190734Sthompsa .timeout = 1000, /* 1 second */ 987184610Salfred }, 988184610Salfred}; 989184610Salfred 990223521Shselasky/* A match on these entries will load ukbd */ 991223521Shselaskystatic const STRUCT_USB_HOST_ID __used ukbd_devs[] = { 992223521Shselasky {USB_IFACE_CLASS(UICLASS_HID), 993223521Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), 994223521Shselasky USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),}, 995223521Shselasky}; 996223521Shselasky 997184610Salfredstatic int 998184610Salfredukbd_probe(device_t dev) 999184610Salfred{ 1000184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 1001192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1002194067Sthompsa void *d_ptr; 1003194067Sthompsa int error; 1004194067Sthompsa uint16_t d_len; 1005184610Salfred 1006228765Savg UKBD_LOCK_ASSERT(); 1007184610Salfred DPRINTFN(11, "\n"); 1008184610Salfred 1009184610Salfred if (sw == NULL) { 1010184610Salfred return (ENXIO); 1011184610Salfred } 1012192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 1013184610Salfred return (ENXIO); 1014184610Salfred } 1015194067Sthompsa 1016194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 1017194067Sthompsa return (ENXIO); 1018194067Sthompsa 1019245248Shselasky if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 1020245248Shselasky return (ENXIO); 1021245248Shselasky 1022194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 1023245248Shselasky (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) 1024245248Shselasky return (BUS_PROBE_DEFAULT); 1025194067Sthompsa 1026194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 1027194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 1028194067Sthompsa 1029194067Sthompsa if (error) 1030194067Sthompsa return (ENXIO); 1031194067Sthompsa 1032245248Shselasky if (hid_is_keyboard(d_ptr, d_len)) { 1033245248Shselasky if (hid_is_mouse(d_ptr, d_len)) { 1034245248Shselasky /* 1035245248Shselasky * NOTE: We currently don't support USB mouse 1036245248Shselasky * and USB keyboard on the same USB endpoint. 1037245248Shselasky * Let "ums" driver win. 1038245248Shselasky */ 1039194067Sthompsa error = ENXIO; 1040245248Shselasky } else { 1041222051Savg error = BUS_PROBE_DEFAULT; 1042245248Shselasky } 1043245248Shselasky } else { 1044194067Sthompsa error = ENXIO; 1045245248Shselasky } 1046194067Sthompsa free(d_ptr, M_TEMP); 1047194067Sthompsa return (error); 1048184610Salfred} 1049184610Salfred 1050223755Shselaskystatic void 1051223755Shselaskyukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len) 1052223755Shselasky{ 1053223755Shselasky uint32_t flags; 1054223755Shselasky 1055223755Shselasky /* reset detected bits */ 1056223755Shselasky sc->sc_flags &= ~UKBD_FLAG_HID_MASK; 1057223755Shselasky 1058223755Shselasky /* check if there is an ID byte */ 1059223755Shselasky sc->sc_kbd_size = hid_report_size(ptr, len, 1060223755Shselasky hid_input, &sc->sc_kbd_id); 1061223755Shselasky 1062223755Shselasky /* investigate if this is an Apple Keyboard */ 1063223755Shselasky if (hid_locate(ptr, len, 1064223755Shselasky HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 1065223755Shselasky hid_input, 0, &sc->sc_loc_apple_eject, &flags, 1066223755Shselasky &sc->sc_id_apple_eject)) { 1067223755Shselasky if (flags & HIO_VARIABLE) 1068223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 1069223755Shselasky UKBD_FLAG_APPLE_SWAP; 1070223755Shselasky DPRINTFN(1, "Found Apple eject-key\n"); 1071223755Shselasky } 1072223755Shselasky if (hid_locate(ptr, len, 1073223755Shselasky HID_USAGE2(0xFFFF, 0x0003), 1074223755Shselasky hid_input, 0, &sc->sc_loc_apple_fn, &flags, 1075223755Shselasky &sc->sc_id_apple_fn)) { 1076223755Shselasky if (flags & HIO_VARIABLE) 1077223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_FN; 1078223755Shselasky DPRINTFN(1, "Found Apple FN-key\n"); 1079223755Shselasky } 1080223755Shselasky /* figure out some keys */ 1081223755Shselasky if (hid_locate(ptr, len, 1082223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE0), 1083223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_l, &flags, 1084223755Shselasky &sc->sc_id_ctrl_l)) { 1085223755Shselasky if (flags & HIO_VARIABLE) 1086223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_L; 1087223755Shselasky DPRINTFN(1, "Found left control\n"); 1088223755Shselasky } 1089223755Shselasky if (hid_locate(ptr, len, 1090223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE4), 1091223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_r, &flags, 1092223755Shselasky &sc->sc_id_ctrl_r)) { 1093223755Shselasky if (flags & HIO_VARIABLE) 1094223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_R; 1095223755Shselasky DPRINTFN(1, "Found right control\n"); 1096223755Shselasky } 1097223755Shselasky if (hid_locate(ptr, len, 1098223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE1), 1099223755Shselasky hid_input, 0, &sc->sc_loc_shift_l, &flags, 1100223755Shselasky &sc->sc_id_shift_l)) { 1101223755Shselasky if (flags & HIO_VARIABLE) 1102223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_L; 1103223755Shselasky DPRINTFN(1, "Found left shift\n"); 1104223755Shselasky } 1105223755Shselasky if (hid_locate(ptr, len, 1106223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE5), 1107223755Shselasky hid_input, 0, &sc->sc_loc_shift_r, &flags, 1108223755Shselasky &sc->sc_id_shift_r)) { 1109223755Shselasky if (flags & HIO_VARIABLE) 1110223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_R; 1111223755Shselasky DPRINTFN(1, "Found right shift\n"); 1112223755Shselasky } 1113223755Shselasky if (hid_locate(ptr, len, 1114223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE2), 1115223755Shselasky hid_input, 0, &sc->sc_loc_alt_l, &flags, 1116223755Shselasky &sc->sc_id_alt_l)) { 1117223755Shselasky if (flags & HIO_VARIABLE) 1118223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_L; 1119223755Shselasky DPRINTFN(1, "Found left alt\n"); 1120223755Shselasky } 1121223755Shselasky if (hid_locate(ptr, len, 1122223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE6), 1123223755Shselasky hid_input, 0, &sc->sc_loc_alt_r, &flags, 1124223755Shselasky &sc->sc_id_alt_r)) { 1125223755Shselasky if (flags & HIO_VARIABLE) 1126223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_R; 1127223755Shselasky DPRINTFN(1, "Found right alt\n"); 1128223755Shselasky } 1129223755Shselasky if (hid_locate(ptr, len, 1130223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE3), 1131223755Shselasky hid_input, 0, &sc->sc_loc_win_l, &flags, 1132223755Shselasky &sc->sc_id_win_l)) { 1133223755Shselasky if (flags & HIO_VARIABLE) 1134223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_L; 1135223755Shselasky DPRINTFN(1, "Found left GUI\n"); 1136223755Shselasky } 1137223755Shselasky if (hid_locate(ptr, len, 1138223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE7), 1139223755Shselasky hid_input, 0, &sc->sc_loc_win_r, &flags, 1140223755Shselasky &sc->sc_id_win_r)) { 1141223755Shselasky if (flags & HIO_VARIABLE) 1142223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_R; 1143223755Shselasky DPRINTFN(1, "Found right GUI\n"); 1144223755Shselasky } 1145223755Shselasky /* figure out event buffer */ 1146223755Shselasky if (hid_locate(ptr, len, 1147223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0x00), 1148223755Shselasky hid_input, 0, &sc->sc_loc_events, &flags, 1149223755Shselasky &sc->sc_id_events)) { 1150254572Shselasky if (flags & HIO_VARIABLE) { 1151254572Shselasky DPRINTFN(1, "Ignoring keyboard event control\n"); 1152254572Shselasky } else { 1153254572Shselasky sc->sc_flags |= UKBD_FLAG_EVENTS; 1154254572Shselasky DPRINTFN(1, "Found keyboard event array\n"); 1155254572Shselasky } 1156223755Shselasky } 1157223755Shselasky 1158223755Shselasky /* figure out leds on keyboard */ 1159223755Shselasky sc->sc_led_size = hid_report_size(ptr, len, 1160223755Shselasky hid_output, NULL); 1161223755Shselasky 1162223755Shselasky if (hid_locate(ptr, len, 1163223755Shselasky HID_USAGE2(HUP_LEDS, 0x01), 1164223755Shselasky hid_output, 0, &sc->sc_loc_numlock, &flags, 1165223755Shselasky &sc->sc_id_numlock)) { 1166223755Shselasky if (flags & HIO_VARIABLE) 1167223755Shselasky sc->sc_flags |= UKBD_FLAG_NUMLOCK; 1168223755Shselasky DPRINTFN(1, "Found keyboard numlock\n"); 1169223755Shselasky } 1170223755Shselasky if (hid_locate(ptr, len, 1171223755Shselasky HID_USAGE2(HUP_LEDS, 0x02), 1172223755Shselasky hid_output, 0, &sc->sc_loc_capslock, &flags, 1173223755Shselasky &sc->sc_id_capslock)) { 1174223755Shselasky if (flags & HIO_VARIABLE) 1175223755Shselasky sc->sc_flags |= UKBD_FLAG_CAPSLOCK; 1176223755Shselasky DPRINTFN(1, "Found keyboard capslock\n"); 1177223755Shselasky } 1178223755Shselasky if (hid_locate(ptr, len, 1179223755Shselasky HID_USAGE2(HUP_LEDS, 0x03), 1180223755Shselasky hid_output, 0, &sc->sc_loc_scrolllock, &flags, 1181223755Shselasky &sc->sc_id_scrolllock)) { 1182223755Shselasky if (flags & HIO_VARIABLE) 1183223755Shselasky sc->sc_flags |= UKBD_FLAG_SCROLLLOCK; 1184223755Shselasky DPRINTFN(1, "Found keyboard scrolllock\n"); 1185223755Shselasky } 1186223755Shselasky} 1187223755Shselasky 1188184610Salfredstatic int 1189184610Salfredukbd_attach(device_t dev) 1190184610Salfred{ 1191184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1192192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1193253332Shselasky int unit = device_get_unit(dev); 1194184610Salfred keyboard_t *kbd = &sc->sc_kbd; 1195192925Sthompsa void *hid_ptr = NULL; 1196193045Sthompsa usb_error_t err; 1197184610Salfred uint16_t n; 1198192925Sthompsa uint16_t hid_len; 1199253332Shselasky#ifdef USB_DEBUG 1200253332Shselasky int rate; 1201253332Shselasky#endif 1202228765Savg UKBD_LOCK_ASSERT(); 1203228765Savg 1204184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 1205184610Salfred 1206184610Salfred kbd->kb_data = (void *)sc; 1207184610Salfred 1208194228Sthompsa device_set_usb_desc(dev); 1209184610Salfred 1210184610Salfred sc->sc_udev = uaa->device; 1211184610Salfred sc->sc_iface = uaa->iface; 1212184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 1213184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 1214184610Salfred sc->sc_mode = K_XLATE; 1215184610Salfred 1216194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 1217184610Salfred 1218305645Shselasky#ifdef UKBD_NO_POLLING 1219194228Sthompsa err = usbd_transfer_setup(uaa->device, 1220184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 1221184610Salfred UKBD_N_TRANSFER, sc, &Giant); 1222305645Shselasky#else 1223305645Shselasky /* 1224305645Shselasky * Setup the UKBD USB transfers one by one, so they are memory 1225305645Shselasky * independent which allows for handling panics triggered by 1226305645Shselasky * the keyboard driver itself, typically via CTRL+ALT+ESC 1227305645Shselasky * sequences. Or if the USB keyboard driver was processing a 1228305645Shselasky * key at the moment of panic. 1229305645Shselasky */ 1230305645Shselasky for (n = 0; n != UKBD_N_TRANSFER; n++) { 1231305645Shselasky err = usbd_transfer_setup(uaa->device, 1232305645Shselasky &uaa->info.bIfaceIndex, sc->sc_xfer + n, ukbd_config + n, 1233305645Shselasky 1, sc, &Giant); 1234305645Shselasky if (err) 1235305645Shselasky break; 1236305645Shselasky } 1237305645Shselasky#endif 1238184610Salfred 1239184610Salfred if (err) { 1240194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 1241184610Salfred goto detach; 1242184610Salfred } 1243184610Salfred /* setup default keyboard maps */ 1244184610Salfred 1245184610Salfred sc->sc_keymap = key_map; 1246184610Salfred sc->sc_accmap = accent_map; 1247184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 1248184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 1249184610Salfred } 1250184610Salfred 1251184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 1252184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 1253184610Salfred 1254184610Salfred KBD_FOUND_DEVICE(kbd); 1255184610Salfred 1256184610Salfred ukbd_clear_state(kbd); 1257184610Salfred 1258184610Salfred /* 1259184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 1260184610Salfred * according to the BIOS data? 1261184610Salfred */ 1262184610Salfred KBD_PROBE_DONE(kbd); 1263184610Salfred 1264223755Shselasky /* get HID descriptor */ 1265194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 1266192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 1267223755Shselasky 1268192925Sthompsa if (err == 0) { 1269223755Shselasky DPRINTF("Parsing HID descriptor of %d bytes\n", 1270223755Shselasky (int)hid_len); 1271192925Sthompsa 1272223755Shselasky ukbd_parse_hid(sc, hid_ptr, hid_len); 1273192925Sthompsa 1274192925Sthompsa free(hid_ptr, M_TEMP); 1275192925Sthompsa } 1276192925Sthompsa 1277223755Shselasky /* check if we should use the boot protocol */ 1278223755Shselasky if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) || 1279223755Shselasky (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) { 1280223755Shselasky 1281223755Shselasky DPRINTF("Forcing boot protocol\n"); 1282223755Shselasky 1283223755Shselasky err = usbd_req_set_protocol(sc->sc_udev, NULL, 1284223755Shselasky sc->sc_iface_index, 0); 1285223755Shselasky 1286223755Shselasky if (err != 0) { 1287223755Shselasky DPRINTF("Set protocol error=%s (ignored)\n", 1288223755Shselasky usbd_errstr(err)); 1289223755Shselasky } 1290223755Shselasky 1291223755Shselasky ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc)); 1292223755Shselasky } 1293223755Shselasky 1294184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 1295223755Shselasky usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); 1296184610Salfred 1297184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 1298184610Salfred 1299184610Salfred KBD_INIT_DONE(kbd); 1300184610Salfred 1301184610Salfred if (kbd_register(kbd) < 0) { 1302184610Salfred goto detach; 1303184610Salfred } 1304184610Salfred KBD_CONFIG_DONE(kbd); 1305184610Salfred 1306184610Salfred ukbd_enable(kbd); 1307184610Salfred 1308184610Salfred#ifdef KBD_INSTALL_CDEV 1309184610Salfred if (kbd_attach(kbd)) { 1310184610Salfred goto detach; 1311184610Salfred } 1312184610Salfred#endif 1313184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 1314184610Salfred 1315184610Salfred if (bootverbose) { 1316184610Salfred genkbd_diag(kbd, bootverbose); 1317184610Salfred } 1318184610Salfred 1319253332Shselasky#ifdef USB_DEBUG 1320253332Shselasky /* check for polling rate override */ 1321253332Shselasky rate = ukbd_pollrate; 1322253332Shselasky if (rate > 0) { 1323253332Shselasky if (rate > 1000) 1324253332Shselasky rate = 1; 1325253332Shselasky else 1326253332Shselasky rate = 1000 / rate; 1327253332Shselasky 1328253332Shselasky /* set new polling interval in ms */ 1329305645Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_0], rate); 1330305645Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_1], rate); 1331253332Shselasky } 1332253332Shselasky#endif 1333184610Salfred /* start the keyboard */ 1334305645Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 1335305645Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 1336184610Salfred 1337184610Salfred return (0); /* success */ 1338184610Salfred 1339184610Salfreddetach: 1340184610Salfred ukbd_detach(dev); 1341184610Salfred return (ENXIO); /* error */ 1342184610Salfred} 1343184610Salfred 1344193315Sthompsastatic int 1345184610Salfredukbd_detach(device_t dev) 1346184610Salfred{ 1347184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1348184610Salfred int error; 1349184610Salfred 1350228765Savg UKBD_LOCK_ASSERT(); 1351228765Savg 1352184610Salfred DPRINTF("\n"); 1353184610Salfred 1354184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 1355184610Salfred 1356194228Sthompsa usb_callout_stop(&sc->sc_callout); 1357184610Salfred 1358261478Shselasky /* kill any stuck keys */ 1359261478Shselasky if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1360261478Shselasky /* stop receiving events from the USB keyboard */ 1361305645Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_0]); 1362305645Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_1]); 1363261478Shselasky 1364261478Shselasky /* release all leftover keys, if any */ 1365261478Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1366261478Shselasky 1367261478Shselasky /* process releasing of all keys */ 1368261478Shselasky ukbd_interrupt(sc); 1369261478Shselasky } 1370261478Shselasky 1371184610Salfred ukbd_disable(&sc->sc_kbd); 1372184610Salfred 1373184610Salfred#ifdef KBD_INSTALL_CDEV 1374184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1375184610Salfred error = kbd_detach(&sc->sc_kbd); 1376184610Salfred if (error) { 1377184610Salfred /* usb attach cannot return an error */ 1378184610Salfred device_printf(dev, "WARNING: kbd_detach() " 1379184610Salfred "returned non-zero! (ignored)\n"); 1380184610Salfred } 1381184610Salfred } 1382184610Salfred#endif 1383184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 1384184610Salfred error = kbd_unregister(&sc->sc_kbd); 1385184610Salfred if (error) { 1386184610Salfred /* usb attach cannot return an error */ 1387184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 1388184610Salfred "returned non-zero! (ignored)\n"); 1389184610Salfred } 1390184610Salfred } 1391184610Salfred sc->sc_kbd.kb_flags = 0; 1392184610Salfred 1393194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 1394184610Salfred 1395194228Sthompsa usb_callout_drain(&sc->sc_callout); 1396184610Salfred 1397184610Salfred DPRINTF("%s: disconnected\n", 1398184610Salfred device_get_nameunit(dev)); 1399184610Salfred 1400184610Salfred return (0); 1401184610Salfred} 1402184610Salfred 1403184610Salfredstatic int 1404184610Salfredukbd_resume(device_t dev) 1405184610Salfred{ 1406184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1407184610Salfred 1408228765Savg UKBD_LOCK_ASSERT(); 1409203896Sthompsa 1410184610Salfred ukbd_clear_state(&sc->sc_kbd); 1411184610Salfred 1412184610Salfred return (0); 1413184610Salfred} 1414184610Salfred 1415184610Salfred/* early keyboard probe, not supported */ 1416184610Salfredstatic int 1417184610Salfredukbd_configure(int flags) 1418184610Salfred{ 1419184610Salfred return (0); 1420184610Salfred} 1421184610Salfred 1422184610Salfred/* detect a keyboard, not used */ 1423184610Salfredstatic int 1424184610Salfredukbd__probe(int unit, void *arg, int flags) 1425184610Salfred{ 1426184610Salfred return (ENXIO); 1427184610Salfred} 1428184610Salfred 1429184610Salfred/* reset and initialize the device, not used */ 1430184610Salfredstatic int 1431184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 1432184610Salfred{ 1433184610Salfred return (ENXIO); 1434184610Salfred} 1435184610Salfred 1436184610Salfred/* test the interface to the device, not used */ 1437184610Salfredstatic int 1438184610Salfredukbd_test_if(keyboard_t *kbd) 1439184610Salfred{ 1440184610Salfred return (0); 1441184610Salfred} 1442184610Salfred 1443184610Salfred/* finish using this keyboard, not used */ 1444184610Salfredstatic int 1445184610Salfredukbd_term(keyboard_t *kbd) 1446184610Salfred{ 1447184610Salfred return (ENXIO); 1448184610Salfred} 1449184610Salfred 1450184610Salfred/* keyboard interrupt routine, not used */ 1451184610Salfredstatic int 1452184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 1453184610Salfred{ 1454184610Salfred return (0); 1455184610Salfred} 1456184610Salfred 1457184610Salfred/* lock the access to the keyboard, not used */ 1458184610Salfredstatic int 1459184610Salfredukbd_lock(keyboard_t *kbd, int lock) 1460184610Salfred{ 1461184610Salfred return (1); 1462184610Salfred} 1463184610Salfred 1464184610Salfred/* 1465184610Salfred * Enable the access to the device; until this function is called, 1466184610Salfred * the client cannot read from the keyboard. 1467184610Salfred */ 1468184610Salfredstatic int 1469184610Salfredukbd_enable(keyboard_t *kbd) 1470184610Salfred{ 1471228765Savg 1472228765Savg UKBD_LOCK(); 1473184610Salfred KBD_ACTIVATE(kbd); 1474228765Savg UKBD_UNLOCK(); 1475228765Savg 1476184610Salfred return (0); 1477184610Salfred} 1478184610Salfred 1479184610Salfred/* disallow the access to the device */ 1480184610Salfredstatic int 1481184610Salfredukbd_disable(keyboard_t *kbd) 1482184610Salfred{ 1483228765Savg 1484228765Savg UKBD_LOCK(); 1485184610Salfred KBD_DEACTIVATE(kbd); 1486228765Savg UKBD_UNLOCK(); 1487228765Savg 1488184610Salfred return (0); 1489184610Salfred} 1490184610Salfred 1491184610Salfred/* check if data is waiting */ 1492228765Savg/* Currently unused. */ 1493184610Salfredstatic int 1494184610Salfredukbd_check(keyboard_t *kbd) 1495184610Salfred{ 1496184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1497184610Salfred 1498228765Savg UKBD_CTX_LOCK_ASSERT(); 1499228765Savg 1500195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1501195960Salfred return (0); 1502195960Salfred 1503203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 1504203896Sthompsa ukbd_do_poll(sc, 0); 1505203896Sthompsa 1506184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1507184610Salfred if (sc->sc_buffered_char[0]) { 1508184610Salfred return (1); 1509184610Salfred } 1510184610Salfred#endif 1511184610Salfred if (sc->sc_inputs > 0) { 1512184610Salfred return (1); 1513184610Salfred } 1514184610Salfred return (0); 1515184610Salfred} 1516184610Salfred 1517184610Salfred/* check if char is waiting */ 1518184610Salfredstatic int 1519228765Savgukbd_check_char_locked(keyboard_t *kbd) 1520184610Salfred{ 1521184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1522184610Salfred 1523228765Savg UKBD_CTX_LOCK_ASSERT(); 1524228765Savg 1525195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1526195960Salfred return (0); 1527195960Salfred 1528184610Salfred if ((sc->sc_composed_char > 0) && 1529184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1530184610Salfred return (1); 1531184610Salfred } 1532184610Salfred return (ukbd_check(kbd)); 1533184610Salfred} 1534184610Salfred 1535228765Savgstatic int 1536228765Savgukbd_check_char(keyboard_t *kbd) 1537228765Savg{ 1538228765Savg int result; 1539184610Salfred 1540228765Savg UKBD_LOCK(); 1541228765Savg result = ukbd_check_char_locked(kbd); 1542228765Savg UKBD_UNLOCK(); 1543228765Savg 1544228765Savg return (result); 1545228765Savg} 1546228765Savg 1547184610Salfred/* read one byte from the keyboard if it's allowed */ 1548228765Savg/* Currently unused. */ 1549184610Salfredstatic int 1550184610Salfredukbd_read(keyboard_t *kbd, int wait) 1551184610Salfred{ 1552184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1553184610Salfred int32_t usbcode; 1554184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1555184610Salfred uint32_t keycode; 1556184610Salfred uint32_t scancode; 1557184610Salfred 1558184610Salfred#endif 1559184610Salfred 1560228765Savg UKBD_CTX_LOCK_ASSERT(); 1561184610Salfred 1562228765Savg if (!KBD_IS_ACTIVE(kbd)) 1563203896Sthompsa return (-1); 1564203896Sthompsa 1565184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1566184610Salfred if (sc->sc_buffered_char[0]) { 1567184610Salfred scancode = sc->sc_buffered_char[0]; 1568184610Salfred if (scancode & SCAN_PREFIX) { 1569184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1570184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1571184610Salfred } 1572184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1573184610Salfred sc->sc_buffered_char[1] = 0; 1574184610Salfred return (scancode); 1575184610Salfred } 1576184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1577184610Salfred 1578184610Salfred /* XXX */ 1579184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1580195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1581195960Salfred return (-1); 1582195960Salfred 1583184610Salfred ++(kbd->kb_count); 1584184610Salfred 1585184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1586184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1587184610Salfred if (keycode == NN) { 1588184610Salfred return -1; 1589184610Salfred } 1590184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1591184610Salfred (usbcode & KEY_RELEASE))); 1592184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1593184610Salfred return (usbcode); 1594184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1595184610Salfred} 1596184610Salfred 1597184610Salfred/* read char from the keyboard */ 1598184610Salfredstatic uint32_t 1599228765Savgukbd_read_char_locked(keyboard_t *kbd, int wait) 1600184610Salfred{ 1601184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1602184610Salfred uint32_t action; 1603184610Salfred uint32_t keycode; 1604184610Salfred int32_t usbcode; 1605184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1606184610Salfred uint32_t scancode; 1607184610Salfred#endif 1608195960Salfred 1609228765Savg UKBD_CTX_LOCK_ASSERT(); 1610228765Savg 1611195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1612195960Salfred return (NOKEY); 1613195960Salfred 1614184610Salfrednext_code: 1615184610Salfred 1616184610Salfred /* do we have a composed char to return ? */ 1617184610Salfred 1618184610Salfred if ((sc->sc_composed_char > 0) && 1619184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1620184610Salfred 1621184610Salfred action = sc->sc_composed_char; 1622184610Salfred sc->sc_composed_char = 0; 1623184610Salfred 1624184610Salfred if (action > 0xFF) { 1625184610Salfred goto errkey; 1626184610Salfred } 1627184610Salfred goto done; 1628184610Salfred } 1629184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1630184610Salfred 1631184610Salfred /* do we have a pending raw scan code? */ 1632184610Salfred 1633184610Salfred if (sc->sc_mode == K_RAW) { 1634184610Salfred scancode = sc->sc_buffered_char[0]; 1635184610Salfred if (scancode) { 1636184610Salfred if (scancode & SCAN_PREFIX) { 1637184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1638184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1639184610Salfred } 1640184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1641184610Salfred sc->sc_buffered_char[1] = 0; 1642184610Salfred return (scancode); 1643184610Salfred } 1644184610Salfred } 1645184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1646184610Salfred 1647184610Salfred /* see if there is something in the keyboard port */ 1648184610Salfred /* XXX */ 1649184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1650184610Salfred if (usbcode == -1) { 1651184610Salfred return (NOKEY); 1652184610Salfred } 1653184610Salfred ++kbd->kb_count; 1654184610Salfred 1655184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1656184610Salfred /* USB key index -> key code -> AT scan code */ 1657184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1658184610Salfred if (keycode == NN) { 1659184610Salfred return (NOKEY); 1660184610Salfred } 1661184610Salfred /* return an AT scan code for the K_RAW mode */ 1662184610Salfred if (sc->sc_mode == K_RAW) { 1663184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1664184610Salfred (usbcode & KEY_RELEASE))); 1665184610Salfred } 1666184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1667184610Salfred 1668184610Salfred /* return the byte as is for the K_RAW mode */ 1669184610Salfred if (sc->sc_mode == K_RAW) { 1670184610Salfred return (usbcode); 1671184610Salfred } 1672184610Salfred /* USB key index -> key code */ 1673184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1674184610Salfred if (keycode == NN) { 1675184610Salfred return (NOKEY); 1676184610Salfred } 1677184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1678184610Salfred 1679184610Salfred switch (keycode) { 1680184610Salfred case 0x38: /* left alt (compose key) */ 1681184610Salfred if (usbcode & KEY_RELEASE) { 1682184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1683184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1684184610Salfred 1685184610Salfred if (sc->sc_composed_char > 0xFF) { 1686184610Salfred sc->sc_composed_char = 0; 1687184610Salfred } 1688184610Salfred } 1689184610Salfred } else { 1690184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1691184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1692184610Salfred sc->sc_composed_char = 0; 1693184610Salfred } 1694184610Salfred } 1695184610Salfred break; 1696184610Salfred /* XXX: I don't like these... */ 1697184610Salfred case 0x5c: /* print screen */ 1698184610Salfred if (sc->sc_flags & ALTS) { 1699184610Salfred keycode = 0x54; /* sysrq */ 1700184610Salfred } 1701184610Salfred break; 1702184610Salfred case 0x68: /* pause/break */ 1703184610Salfred if (sc->sc_flags & CTLS) { 1704184610Salfred keycode = 0x6c; /* break */ 1705184610Salfred } 1706184610Salfred break; 1707184610Salfred } 1708184610Salfred 1709184610Salfred /* return the key code in the K_CODE mode */ 1710184610Salfred if (usbcode & KEY_RELEASE) { 1711184610Salfred keycode |= SCAN_RELEASE; 1712184610Salfred } 1713184610Salfred if (sc->sc_mode == K_CODE) { 1714184610Salfred return (keycode); 1715184610Salfred } 1716184610Salfred /* compose a character code */ 1717184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1718184610Salfred switch (keycode) { 1719184610Salfred /* key pressed, process it */ 1720184610Salfred case 0x47: 1721184610Salfred case 0x48: 1722184610Salfred case 0x49: /* keypad 7,8,9 */ 1723184610Salfred sc->sc_composed_char *= 10; 1724184610Salfred sc->sc_composed_char += keycode - 0x40; 1725184610Salfred goto check_composed; 1726184610Salfred 1727184610Salfred case 0x4B: 1728184610Salfred case 0x4C: 1729184610Salfred case 0x4D: /* keypad 4,5,6 */ 1730184610Salfred sc->sc_composed_char *= 10; 1731184610Salfred sc->sc_composed_char += keycode - 0x47; 1732184610Salfred goto check_composed; 1733184610Salfred 1734184610Salfred case 0x4F: 1735184610Salfred case 0x50: 1736184610Salfred case 0x51: /* keypad 1,2,3 */ 1737184610Salfred sc->sc_composed_char *= 10; 1738184610Salfred sc->sc_composed_char += keycode - 0x4E; 1739184610Salfred goto check_composed; 1740184610Salfred 1741184610Salfred case 0x52: /* keypad 0 */ 1742184610Salfred sc->sc_composed_char *= 10; 1743184610Salfred goto check_composed; 1744184610Salfred 1745184610Salfred /* key released, no interest here */ 1746184610Salfred case SCAN_RELEASE | 0x47: 1747184610Salfred case SCAN_RELEASE | 0x48: 1748184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1749184610Salfred case SCAN_RELEASE | 0x4B: 1750184610Salfred case SCAN_RELEASE | 0x4C: 1751184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1752184610Salfred case SCAN_RELEASE | 0x4F: 1753184610Salfred case SCAN_RELEASE | 0x50: 1754184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1755184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1756184610Salfred goto next_code; 1757184610Salfred 1758184610Salfred case 0x38: /* left alt key */ 1759184610Salfred break; 1760184610Salfred 1761184610Salfred default: 1762184610Salfred if (sc->sc_composed_char > 0) { 1763184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1764184610Salfred sc->sc_composed_char = 0; 1765184610Salfred goto errkey; 1766184610Salfred } 1767184610Salfred break; 1768184610Salfred } 1769184610Salfred } 1770184610Salfred /* keycode to key action */ 1771184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1772184610Salfred (keycode & SCAN_RELEASE), 1773184610Salfred &sc->sc_state, &sc->sc_accents); 1774184610Salfred if (action == NOKEY) { 1775184610Salfred goto next_code; 1776184610Salfred } 1777184610Salfreddone: 1778184610Salfred return (action); 1779184610Salfred 1780184610Salfredcheck_composed: 1781184610Salfred if (sc->sc_composed_char <= 0xFF) { 1782184610Salfred goto next_code; 1783184610Salfred } 1784184610Salfrederrkey: 1785184610Salfred return (ERRKEY); 1786184610Salfred} 1787184610Salfred 1788228765Savg/* Currently wait is always false. */ 1789228765Savgstatic uint32_t 1790228765Savgukbd_read_char(keyboard_t *kbd, int wait) 1791228765Savg{ 1792228765Savg uint32_t keycode; 1793228765Savg 1794228765Savg UKBD_LOCK(); 1795228765Savg keycode = ukbd_read_char_locked(kbd, wait); 1796228765Savg UKBD_UNLOCK(); 1797228765Savg 1798228765Savg return (keycode); 1799228765Savg} 1800228765Savg 1801184610Salfred/* some useful control functions */ 1802184610Salfredstatic int 1803228765Savgukbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg) 1804184610Salfred{ 1805184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1806184610Salfred int i; 1807184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1808184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1809184610Salfred int ival; 1810184610Salfred 1811184610Salfred#endif 1812184610Salfred 1813228765Savg UKBD_LOCK_ASSERT(); 1814228765Savg 1815184610Salfred switch (cmd) { 1816184610Salfred case KDGKBMODE: /* get keyboard mode */ 1817184610Salfred *(int *)arg = sc->sc_mode; 1818184610Salfred break; 1819184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1820184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1821184610Salfred case _IO('K', 7): 1822184610Salfred ival = IOCPARM_IVAL(arg); 1823184610Salfred arg = (caddr_t)&ival; 1824184610Salfred /* FALLTHROUGH */ 1825184610Salfred#endif 1826184610Salfred case KDSKBMODE: /* set keyboard mode */ 1827184610Salfred switch (*(int *)arg) { 1828184610Salfred case K_XLATE: 1829184610Salfred if (sc->sc_mode != K_XLATE) { 1830184610Salfred /* make lock key state and LED state match */ 1831184610Salfred sc->sc_state &= ~LOCK_MASK; 1832184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1833184610Salfred } 1834184610Salfred /* FALLTHROUGH */ 1835184610Salfred case K_RAW: 1836184610Salfred case K_CODE: 1837184610Salfred if (sc->sc_mode != *(int *)arg) { 1838228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) == 0) 1839203896Sthompsa ukbd_clear_state(kbd); 1840184610Salfred sc->sc_mode = *(int *)arg; 1841184610Salfred } 1842184610Salfred break; 1843184610Salfred default: 1844184610Salfred return (EINVAL); 1845184610Salfred } 1846184610Salfred break; 1847184610Salfred 1848184610Salfred case KDGETLED: /* get keyboard LED */ 1849184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1850184610Salfred break; 1851184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1852184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1853184610Salfred case _IO('K', 66): 1854184610Salfred ival = IOCPARM_IVAL(arg); 1855184610Salfred arg = (caddr_t)&ival; 1856184610Salfred /* FALLTHROUGH */ 1857184610Salfred#endif 1858184610Salfred case KDSETLED: /* set keyboard LED */ 1859184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1860223755Shselasky if (*(int *)arg & ~LOCK_MASK) 1861184610Salfred return (EINVAL); 1862223755Shselasky 1863184610Salfred i = *(int *)arg; 1864223755Shselasky 1865184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1866184610Salfred if (sc->sc_mode == K_XLATE && 1867184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1868184610Salfred if (i & ALKED) 1869184610Salfred i |= CLKED; 1870184610Salfred else 1871184610Salfred i &= ~CLKED; 1872184610Salfred } 1873223755Shselasky if (KBD_HAS_DEVICE(kbd)) 1874223755Shselasky ukbd_set_leds(sc, i); 1875223755Shselasky 1876184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1877184610Salfred break; 1878184610Salfred case KDGKBSTATE: /* get lock key state */ 1879184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1880184610Salfred break; 1881184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1882184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1883184610Salfred case _IO('K', 20): 1884184610Salfred ival = IOCPARM_IVAL(arg); 1885184610Salfred arg = (caddr_t)&ival; 1886184610Salfred /* FALLTHROUGH */ 1887184610Salfred#endif 1888184610Salfred case KDSKBSTATE: /* set lock key state */ 1889184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1890184610Salfred return (EINVAL); 1891184610Salfred } 1892184610Salfred sc->sc_state &= ~LOCK_MASK; 1893184610Salfred sc->sc_state |= *(int *)arg; 1894184610Salfred 1895184610Salfred /* set LEDs and quit */ 1896184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1897184610Salfred 1898184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1899184610Salfred * interface) */ 1900184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1901184610Salfred return (0); 1902184610Salfred } 1903184610Salfred if (((int *)arg)[1] < 0) { 1904184610Salfred return (EINVAL); 1905184610Salfred } 1906184610Salfred if (((int *)arg)[0] < 0) { 1907184610Salfred return (EINVAL); 1908184610Salfred } 1909184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1910184610Salfred kbd->kb_delay1 = 200; 1911184610Salfred else 1912184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1913184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1914184610Salfred return (0); 1915184610Salfred 1916184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1917184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1918184610Salfred case _IO('K', 67): 1919184610Salfred ival = IOCPARM_IVAL(arg); 1920184610Salfred arg = (caddr_t)&ival; 1921184610Salfred /* FALLTHROUGH */ 1922184610Salfred#endif 1923184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1924184610Salfred * interface) */ 1925184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1926184610Salfred 1927184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1928224126Sed case OPIO_KEYMAP: /* set keyboard translation table 1929224126Sed * (compat) */ 1930184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1931184610Salfred * entry */ 1932184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1933184610Salfred sc->sc_accents = 0; 1934184610Salfred /* FALLTHROUGH */ 1935184610Salfred default: 1936184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1937184610Salfred } 1938184610Salfred 1939184610Salfred return (0); 1940184610Salfred} 1941184610Salfred 1942228765Savgstatic int 1943228765Savgukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1944228765Savg{ 1945228765Savg int result; 1946228765Savg 1947228765Savg /* 1948263261Shselasky * XXX Check of someone is calling us from a critical section: 1949263261Shselasky */ 1950263261Shselasky if (curthread->td_critnest != 0) 1951263261Shselasky return (EDEADLK); 1952263261Shselasky 1953263261Shselasky /* 1954228765Savg * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any 1955228765Savg * context where printf(9) can be called, which among other things 1956228765Savg * includes interrupt filters and threads with any kinds of locks 1957228765Savg * already held. For this reason it would be dangerous to acquire 1958228765Savg * the Giant here unconditionally. On the other hand we have to 1959228765Savg * have it to handle the ioctl. 1960228765Savg * So we make our best effort to auto-detect whether we can grab 1961228765Savg * the Giant or not. Blame syscons(4) for this. 1962228765Savg */ 1963228765Savg switch (cmd) { 1964228765Savg case KDGKBSTATE: 1965228765Savg case KDSKBSTATE: 1966228765Savg case KDSETLED: 1967228765Savg if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED()) 1968228765Savg return (EDEADLK); /* best I could come up with */ 1969228765Savg /* FALLTHROUGH */ 1970228765Savg default: 1971228765Savg UKBD_LOCK(); 1972228765Savg result = ukbd_ioctl_locked(kbd, cmd, arg); 1973228765Savg UKBD_UNLOCK(); 1974228765Savg return (result); 1975228765Savg } 1976228765Savg} 1977228765Savg 1978228765Savg 1979184610Salfred/* clear the internal state of the keyboard */ 1980184610Salfredstatic void 1981184610Salfredukbd_clear_state(keyboard_t *kbd) 1982184610Salfred{ 1983184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1984184610Salfred 1985228765Savg UKBD_CTX_LOCK_ASSERT(); 1986184610Salfred 1987184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 1988184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 1989184610Salfred sc->sc_accents = 0; 1990184610Salfred sc->sc_composed_char = 0; 1991184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1992184610Salfred sc->sc_buffered_char[0] = 0; 1993184610Salfred sc->sc_buffered_char[1] = 0; 1994184610Salfred#endif 1995203896Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1996203896Sthompsa memset(&sc->sc_odata, 0, sizeof(sc->sc_odata)); 1997203896Sthompsa memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime)); 1998203896Sthompsa memset(&sc->sc_otime, 0, sizeof(sc->sc_otime)); 1999184610Salfred} 2000184610Salfred 2001184610Salfred/* save the internal state, not used */ 2002184610Salfredstatic int 2003184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 2004184610Salfred{ 2005184610Salfred return (len == 0) ? 1 : -1; 2006184610Salfred} 2007184610Salfred 2008184610Salfred/* set the internal state, not used */ 2009184610Salfredstatic int 2010184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 2011184610Salfred{ 2012184610Salfred return (EINVAL); 2013184610Salfred} 2014184610Salfred 2015184610Salfredstatic int 2016184610Salfredukbd_poll(keyboard_t *kbd, int on) 2017184610Salfred{ 2018184610Salfred struct ukbd_softc *sc = kbd->kb_data; 2019184610Salfred 2020228765Savg UKBD_LOCK(); 2021304125Shselasky /* 2022304125Shselasky * Keep a reference count on polling to allow recursive 2023304125Shselasky * cngrab() during a panic for example. 2024304125Shselasky */ 2025304125Shselasky if (on) 2026304125Shselasky sc->sc_polling++; 2027305645Shselasky else if (sc->sc_polling > 0) 2028304125Shselasky sc->sc_polling--; 2029304125Shselasky 2030304125Shselasky if (sc->sc_polling != 0) { 2031184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 2032203896Sthompsa sc->sc_poll_thread = curthread; 2033184610Salfred } else { 2034184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 2035203896Sthompsa ukbd_start_timer(sc); /* start timer */ 2036184610Salfred } 2037228765Savg UKBD_UNLOCK(); 2038228765Savg 2039184610Salfred return (0); 2040184610Salfred} 2041184610Salfred 2042184610Salfred/* local functions */ 2043184610Salfred 2044184610Salfredstatic void 2045184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 2046184610Salfred{ 2047228765Savg 2048228765Savg UKBD_LOCK_ASSERT(); 2049184610Salfred DPRINTF("leds=0x%02x\n", leds); 2050184610Salfred 2051184610Salfred sc->sc_leds = leds; 2052184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 2053184610Salfred 2054184610Salfred /* start transfer, if not already started */ 2055184610Salfred 2056194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 2057184610Salfred} 2058184610Salfred 2059184610Salfredstatic int 2060184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 2061184610Salfred{ 2062184610Salfred static const int delays[] = {250, 500, 750, 1000}; 2063184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 2064184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 2065184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 2066184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 2067184610Salfred 2068184610Salfred if (code & ~0x7f) { 2069184610Salfred return (EINVAL); 2070184610Salfred } 2071184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 2072184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 2073184610Salfred return (0); 2074184610Salfred} 2075184610Salfred 2076184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 2077184610Salfredstatic int 2078184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 2079184610Salfred{ 2080184610Salfred static const int scan[] = { 2081197999Shrs /* 89 */ 2082197999Shrs 0x11c, /* Enter */ 2083197999Shrs /* 90-99 */ 2084197999Shrs 0x11d, /* Ctrl-R */ 2085197999Shrs 0x135, /* Divide */ 2086197999Shrs 0x137 | SCAN_PREFIX_SHIFT, /* PrintScreen */ 2087197999Shrs 0x138, /* Alt-R */ 2088197999Shrs 0x147, /* Home */ 2089197999Shrs 0x148, /* Up */ 2090197999Shrs 0x149, /* PageUp */ 2091197999Shrs 0x14b, /* Left */ 2092197999Shrs 0x14d, /* Right */ 2093197999Shrs 0x14f, /* End */ 2094197999Shrs /* 100-109 */ 2095197999Shrs 0x150, /* Down */ 2096197999Shrs 0x151, /* PageDown */ 2097197999Shrs 0x152, /* Insert */ 2098197999Shrs 0x153, /* Delete */ 2099197999Shrs 0x146, /* XXX Pause/Break */ 2100197999Shrs 0x15b, /* Win_L(Super_L) */ 2101197999Shrs 0x15c, /* Win_R(Super_R) */ 2102197999Shrs 0x15d, /* Application(Menu) */ 2103197999Shrs 2104184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 2105197999Shrs 0x168, /* Sun Type 6 Help */ 2106197999Shrs 0x15e, /* Sun Type 6 Stop */ 2107197999Shrs /* 110 - 119 */ 2108197999Shrs 0x15f, /* Sun Type 6 Again */ 2109197999Shrs 0x160, /* Sun Type 6 Props */ 2110197999Shrs 0x161, /* Sun Type 6 Undo */ 2111197999Shrs 0x162, /* Sun Type 6 Front */ 2112197999Shrs 0x163, /* Sun Type 6 Copy */ 2113197999Shrs 0x164, /* Sun Type 6 Open */ 2114197999Shrs 0x165, /* Sun Type 6 Paste */ 2115197999Shrs 0x166, /* Sun Type 6 Find */ 2116197999Shrs 0x167, /* Sun Type 6 Cut */ 2117197999Shrs 0x125, /* Sun Type 6 Mute */ 2118291254Shselasky /* 120 - 130 */ 2119197999Shrs 0x11f, /* Sun Type 6 VolumeDown */ 2120197999Shrs 0x11e, /* Sun Type 6 VolumeUp */ 2121197999Shrs 0x120, /* Sun Type 6 PowerDown */ 2122197999Shrs 2123197999Shrs /* Japanese 106/109 keyboard */ 2124197999Shrs 0x73, /* Keyboard Intl' 1 (backslash / underscore) */ 2125197999Shrs 0x70, /* Keyboard Intl' 2 (Katakana / Hiragana) */ 2126197999Shrs 0x7d, /* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */ 2127197999Shrs 0x79, /* Keyboard Intl' 4 (Henkan) */ 2128197999Shrs 0x7b, /* Keyboard Intl' 5 (Muhenkan) */ 2129197999Shrs 0x5c, /* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */ 2130291254Shselasky 0x71, /* Apple Keyboard JIS (Kana) */ 2131291254Shselasky 0x72, /* Apple Keyboard JIS (Eisu) */ 2132184610Salfred }; 2133184610Salfred 2134233774Shselasky if ((code >= 89) && (code < (int)(89 + (sizeof(scan) / sizeof(scan[0]))))) { 2135197999Shrs code = scan[code - 89]; 2136184610Salfred } 2137184610Salfred /* Pause/Break */ 2138184610Salfred if ((code == 104) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 2139184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 2140184610Salfred } 2141184610Salfred if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) { 2142184610Salfred code &= ~SCAN_PREFIX_SHIFT; 2143184610Salfred } 2144184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 2145184610Salfred 2146184610Salfred if (code & SCAN_PREFIX) { 2147184610Salfred if (code & SCAN_PREFIX_CTL) { 2148184610Salfred /* Ctrl */ 2149184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 2150184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 2151184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 2152184610Salfred /* Shift */ 2153184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 2154184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 2155184610Salfred } else { 2156184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 2157184610Salfred sc->sc_buffered_char[1] = 0; 2158184610Salfred } 2159184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 2160184610Salfred } 2161184610Salfred return (code); 2162184610Salfred 2163184610Salfred} 2164184610Salfred 2165184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 2166184610Salfred 2167194099Sthompsastatic keyboard_switch_t ukbdsw = { 2168184610Salfred .probe = &ukbd__probe, 2169184610Salfred .init = &ukbd_init, 2170184610Salfred .term = &ukbd_term, 2171184610Salfred .intr = &ukbd_intr, 2172184610Salfred .test_if = &ukbd_test_if, 2173184610Salfred .enable = &ukbd_enable, 2174184610Salfred .disable = &ukbd_disable, 2175184610Salfred .read = &ukbd_read, 2176184610Salfred .check = &ukbd_check, 2177184610Salfred .read_char = &ukbd_read_char, 2178184610Salfred .check_char = &ukbd_check_char, 2179184610Salfred .ioctl = &ukbd_ioctl, 2180184610Salfred .lock = &ukbd_lock, 2181184610Salfred .clear_state = &ukbd_clear_state, 2182184610Salfred .get_state = &ukbd_get_state, 2183184610Salfred .set_state = &ukbd_set_state, 2184184610Salfred .get_fkeystr = &genkbd_get_fkeystr, 2185184610Salfred .poll = &ukbd_poll, 2186184610Salfred .diag = &genkbd_diag, 2187184610Salfred}; 2188184610Salfred 2189184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 2190184610Salfred 2191184610Salfredstatic int 2192184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 2193184610Salfred{ 2194184610Salfred switch (what) { 2195193315Sthompsa case MOD_LOAD: 2196184610Salfred kbd_add_driver(&ukbd_kbd_driver); 2197184610Salfred break; 2198184610Salfred case MOD_UNLOAD: 2199184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 2200184610Salfred break; 2201184610Salfred } 2202184610Salfred return (0); 2203184610Salfred} 2204184610Salfred 2205184610Salfredstatic devclass_t ukbd_devclass; 2206184610Salfred 2207184610Salfredstatic device_method_t ukbd_methods[] = { 2208184610Salfred DEVMETHOD(device_probe, ukbd_probe), 2209184610Salfred DEVMETHOD(device_attach, ukbd_attach), 2210184610Salfred DEVMETHOD(device_detach, ukbd_detach), 2211184610Salfred DEVMETHOD(device_resume, ukbd_resume), 2212246128Ssbz 2213246128Ssbz DEVMETHOD_END 2214184610Salfred}; 2215184610Salfred 2216184610Salfredstatic driver_t ukbd_driver = { 2217184610Salfred .name = "ukbd", 2218184610Salfred .methods = ukbd_methods, 2219184610Salfred .size = sizeof(struct ukbd_softc), 2220184610Salfred}; 2221184610Salfred 2222189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 2223188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 2224212122SthompsaMODULE_VERSION(ukbd, 1); 2225