ukbd.c revision 358213
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: stable/11/sys/dev/usb/input/ukbd.c 358213 2020-02-21 08:41:44Z 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" 43307764Sgonzo#include "opt_evdev.h" 44184610Salfred 45194677Sthompsa#include <sys/stdint.h> 46194677Sthompsa#include <sys/stddef.h> 47194677Sthompsa#include <sys/param.h> 48194677Sthompsa#include <sys/queue.h> 49194677Sthompsa#include <sys/types.h> 50194677Sthompsa#include <sys/systm.h> 51194677Sthompsa#include <sys/kernel.h> 52194677Sthompsa#include <sys/bus.h> 53194677Sthompsa#include <sys/module.h> 54194677Sthompsa#include <sys/lock.h> 55194677Sthompsa#include <sys/mutex.h> 56194677Sthompsa#include <sys/condvar.h> 57194677Sthompsa#include <sys/sysctl.h> 58194677Sthompsa#include <sys/sx.h> 59194677Sthompsa#include <sys/unistd.h> 60194677Sthompsa#include <sys/callout.h> 61194677Sthompsa#include <sys/malloc.h> 62194677Sthompsa#include <sys/priv.h> 63223989Shselasky#include <sys/proc.h> 64223989Shselasky#include <sys/sched.h> 65198152Sthompsa#include <sys/kdb.h> 66194677Sthompsa 67188942Sthompsa#include <dev/usb/usb.h> 68194677Sthompsa#include <dev/usb/usbdi.h> 69194677Sthompsa#include <dev/usb/usbdi_util.h> 70188942Sthompsa#include <dev/usb/usbhid.h> 71184610Salfred 72184610Salfred#define USB_DEBUG_VAR ukbd_debug 73188942Sthompsa#include <dev/usb/usb_debug.h> 74184610Salfred 75188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 76184610Salfred 77307775Sgonzo#ifdef EVDEV_SUPPORT 78307764Sgonzo#include <dev/evdev/input.h> 79307764Sgonzo#include <dev/evdev/evdev.h> 80307764Sgonzo#endif 81307764Sgonzo 82184610Salfred#include <sys/ioccom.h> 83184610Salfred#include <sys/filio.h> 84184610Salfred#include <sys/kbio.h> 85184610Salfred 86184610Salfred#include <dev/kbd/kbdreg.h> 87184610Salfred 88184610Salfred/* the initial key map, accent map and fkey strings */ 89184610Salfred#if defined(UKBD_DFLT_KEYMAP) && !defined(KLD_MODULE) 90184610Salfred#define KBD_DFLT_KEYMAP 91184610Salfred#include "ukbdmap.h" 92184610Salfred#endif 93184610Salfred 94184610Salfred/* the following file must be included after "ukbdmap.h" */ 95184610Salfred#include <dev/kbd/kbdtables.h> 96184610Salfred 97207077Sthompsa#ifdef USB_DEBUG 98184610Salfredstatic int ukbd_debug = 0; 99196489Salfredstatic int ukbd_no_leds = 0; 100253332Shselaskystatic int ukbd_pollrate = 0; 101184610Salfred 102253332Shselaskystatic SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB keyboard"); 103267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RWTUN, 104184610Salfred &ukbd_debug, 0, "Debug level"); 105267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RWTUN, 106196489Salfred &ukbd_no_leds, 0, "Disables setting of keyboard leds"); 107267992ShselaskySYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RWTUN, 108253332Shselasky &ukbd_pollrate, 0, "Force this polling rate, 1-1000Hz"); 109184610Salfred#endif 110184610Salfred 111184610Salfred#define UKBD_EMULATE_ATSCANCODE 1 112184610Salfred#define UKBD_DRIVER_NAME "ukbd" 113184610Salfred#define UKBD_NMOD 8 /* units */ 114184610Salfred#define UKBD_NKEYCODE 6 /* units */ 115184610Salfred#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */ 116305644Shselasky#define UKBD_IN_BUF_FULL ((UKBD_IN_BUF_SIZE / 2) - 1) /* bytes */ 117184610Salfred#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */ 118223755Shselasky#define UKBD_BUFFER_SIZE 64 /* bytes */ 119184610Salfred 120184610Salfredstruct ukbd_data { 121223755Shselasky uint16_t modifiers; 122184610Salfred#define MOD_CONTROL_L 0x01 123184610Salfred#define MOD_CONTROL_R 0x10 124184610Salfred#define MOD_SHIFT_L 0x02 125184610Salfred#define MOD_SHIFT_R 0x20 126184610Salfred#define MOD_ALT_L 0x04 127184610Salfred#define MOD_ALT_R 0x40 128184610Salfred#define MOD_WIN_L 0x08 129184610Salfred#define MOD_WIN_R 0x80 130223755Shselasky/* internal */ 131223755Shselasky#define MOD_EJECT 0x0100 132223755Shselasky#define MOD_FN 0x0200 133184610Salfred uint8_t keycode[UKBD_NKEYCODE]; 134192925Sthompsa}; 135184610Salfred 136187259Sthompsaenum { 137305644Shselasky UKBD_INTR_DT_0, 138305644Shselasky UKBD_INTR_DT_1, 139187259Sthompsa UKBD_CTRL_LED, 140192925Sthompsa UKBD_N_TRANSFER, 141187259Sthompsa}; 142187259Sthompsa 143184610Salfredstruct ukbd_softc { 144184610Salfred keyboard_t sc_kbd; 145184610Salfred keymap_t sc_keymap; 146184610Salfred accentmap_t sc_accmap; 147184610Salfred fkeytab_t sc_fkeymap[UKBD_NFKEY]; 148192925Sthompsa struct hid_location sc_loc_apple_eject; 149192925Sthompsa struct hid_location sc_loc_apple_fn; 150223755Shselasky struct hid_location sc_loc_ctrl_l; 151223755Shselasky struct hid_location sc_loc_ctrl_r; 152223755Shselasky struct hid_location sc_loc_shift_l; 153223755Shselasky struct hid_location sc_loc_shift_r; 154223755Shselasky struct hid_location sc_loc_alt_l; 155223755Shselasky struct hid_location sc_loc_alt_r; 156223755Shselasky struct hid_location sc_loc_win_l; 157223755Shselasky struct hid_location sc_loc_win_r; 158223755Shselasky struct hid_location sc_loc_events; 159223755Shselasky struct hid_location sc_loc_numlock; 160223755Shselasky struct hid_location sc_loc_capslock; 161223755Shselasky struct hid_location sc_loc_scrolllock; 162192984Sthompsa struct usb_callout sc_callout; 163184610Salfred struct ukbd_data sc_ndata; 164184610Salfred struct ukbd_data sc_odata; 165184610Salfred 166203896Sthompsa struct thread *sc_poll_thread; 167192984Sthompsa struct usb_device *sc_udev; 168192984Sthompsa struct usb_interface *sc_iface; 169192984Sthompsa struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; 170307775Sgonzo#ifdef EVDEV_SUPPORT 171307764Sgonzo struct evdev_dev *sc_evdev; 172307764Sgonzo#endif 173184610Salfred 174184610Salfred uint32_t sc_ntime[UKBD_NKEYCODE]; 175184610Salfred uint32_t sc_otime[UKBD_NKEYCODE]; 176184610Salfred uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ 177184610Salfred uint32_t sc_time_ms; 178184610Salfred uint32_t sc_composed_char; /* composed char code, if non-zero */ 179184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 180184610Salfred uint32_t sc_buffered_char[2]; 181184610Salfred#endif 182184610Salfred uint32_t sc_flags; /* flags */ 183223755Shselasky#define UKBD_FLAG_COMPOSE 0x00000001 184223755Shselasky#define UKBD_FLAG_POLLING 0x00000002 185223755Shselasky#define UKBD_FLAG_SET_LEDS 0x00000004 186223755Shselasky#define UKBD_FLAG_ATTACHED 0x00000010 187223755Shselasky#define UKBD_FLAG_GONE 0x00000020 188184610Salfred 189223755Shselasky#define UKBD_FLAG_HID_MASK 0x003fffc0 190223755Shselasky#define UKBD_FLAG_APPLE_EJECT 0x00000040 191223755Shselasky#define UKBD_FLAG_APPLE_FN 0x00000080 192223755Shselasky#define UKBD_FLAG_APPLE_SWAP 0x00000100 193223755Shselasky#define UKBD_FLAG_TIMER_RUNNING 0x00000200 194223755Shselasky#define UKBD_FLAG_CTRL_L 0x00000400 195223755Shselasky#define UKBD_FLAG_CTRL_R 0x00000800 196223755Shselasky#define UKBD_FLAG_SHIFT_L 0x00001000 197223755Shselasky#define UKBD_FLAG_SHIFT_R 0x00002000 198223755Shselasky#define UKBD_FLAG_ALT_L 0x00004000 199223755Shselasky#define UKBD_FLAG_ALT_R 0x00008000 200223755Shselasky#define UKBD_FLAG_WIN_L 0x00010000 201223755Shselasky#define UKBD_FLAG_WIN_R 0x00020000 202223755Shselasky#define UKBD_FLAG_EVENTS 0x00040000 203223755Shselasky#define UKBD_FLAG_NUMLOCK 0x00080000 204223755Shselasky#define UKBD_FLAG_CAPSLOCK 0x00100000 205223755Shselasky#define UKBD_FLAG_SCROLLLOCK 0x00200000 206223755Shselasky 207203896Sthompsa int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 208203896Sthompsa int sc_state; /* shift/lock key state */ 209203896Sthompsa int sc_accents; /* accent key index (> 0) */ 210304124Shselasky int sc_polling; /* polling recursion count */ 211223755Shselasky int sc_led_size; 212223755Shselasky int sc_kbd_size; 213184610Salfred 214184610Salfred uint16_t sc_inputs; 215184610Salfred uint16_t sc_inputhead; 216184610Salfred uint16_t sc_inputtail; 217223755Shselasky uint16_t sc_modifiers; 218184610Salfred 219184610Salfred uint8_t sc_leds; /* store for async led requests */ 220184610Salfred uint8_t sc_iface_index; 221184610Salfred uint8_t sc_iface_no; 222223755Shselasky uint8_t sc_id_apple_eject; 223223755Shselasky uint8_t sc_id_apple_fn; 224223755Shselasky uint8_t sc_id_ctrl_l; 225223755Shselasky uint8_t sc_id_ctrl_r; 226223755Shselasky uint8_t sc_id_shift_l; 227223755Shselasky uint8_t sc_id_shift_r; 228223755Shselasky uint8_t sc_id_alt_l; 229223755Shselasky uint8_t sc_id_alt_r; 230223755Shselasky uint8_t sc_id_win_l; 231223755Shselasky uint8_t sc_id_win_r; 232223755Shselasky uint8_t sc_id_event; 233223755Shselasky uint8_t sc_id_numlock; 234223755Shselasky uint8_t sc_id_capslock; 235223755Shselasky uint8_t sc_id_scrolllock; 236223755Shselasky uint8_t sc_id_events; 237192925Sthompsa uint8_t sc_kbd_id; 238223755Shselasky 239223755Shselasky uint8_t sc_buffer[UKBD_BUFFER_SIZE]; 240184610Salfred}; 241184610Salfred 242184610Salfred#define KEY_ERROR 0x01 243184610Salfred 244184610Salfred#define KEY_PRESS 0 245184610Salfred#define KEY_RELEASE 0x400 246184610Salfred#define KEY_INDEX(c) ((c) & 0xFF) 247184610Salfred 248184610Salfred#define SCAN_PRESS 0 249184610Salfred#define SCAN_RELEASE 0x80 250184610Salfred#define SCAN_PREFIX_E0 0x100 251184610Salfred#define SCAN_PREFIX_E1 0x200 252184610Salfred#define SCAN_PREFIX_CTL 0x400 253184610Salfred#define SCAN_PREFIX_SHIFT 0x800 254184610Salfred#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | \ 255184610Salfred SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT) 256184610Salfred#define SCAN_CHAR(c) ((c) & 0x7f) 257184610Salfred 258228765Savg#define UKBD_LOCK() mtx_lock(&Giant) 259228765Savg#define UKBD_UNLOCK() mtx_unlock(&Giant) 260228765Savg 261228765Savg#ifdef INVARIANTS 262228765Savg 263228765Savg/* 264228765Savg * Assert that the lock is held in all contexts 265228765Savg * where the code can be executed. 266228765Savg */ 267228765Savg#define UKBD_LOCK_ASSERT() mtx_assert(&Giant, MA_OWNED) 268228765Savg 269228765Savg/* 270228765Savg * Assert that the lock is held in the contexts 271228765Savg * where it really has to be so. 272228765Savg */ 273228765Savg#define UKBD_CTX_LOCK_ASSERT() \ 274228765Savg do { \ 275228765Savg if (!kdb_active && panicstr == NULL) \ 276228765Savg mtx_assert(&Giant, MA_OWNED); \ 277228765Savg } while (0) 278228765Savg#else 279228765Savg 280228765Savg#define UKBD_LOCK_ASSERT() (void)0 281228765Savg#define UKBD_CTX_LOCK_ASSERT() (void)0 282228765Savg 283228765Savg#endif 284228765Savg 285184610Salfredstruct ukbd_mods { 286184610Salfred uint32_t mask, key; 287184610Salfred}; 288184610Salfred 289184610Salfredstatic const struct ukbd_mods ukbd_mods[UKBD_NMOD] = { 290184610Salfred {MOD_CONTROL_L, 0xe0}, 291184610Salfred {MOD_CONTROL_R, 0xe4}, 292184610Salfred {MOD_SHIFT_L, 0xe1}, 293184610Salfred {MOD_SHIFT_R, 0xe5}, 294184610Salfred {MOD_ALT_L, 0xe2}, 295184610Salfred {MOD_ALT_R, 0xe6}, 296184610Salfred {MOD_WIN_L, 0xe3}, 297184610Salfred {MOD_WIN_R, 0xe7}, 298184610Salfred}; 299184610Salfred 300184610Salfred#define NN 0 /* no translation */ 301184610Salfred/* 302184610Salfred * Translate USB keycodes to AT keyboard scancodes. 303184610Salfred */ 304184610Salfred/* 305184610Salfred * FIXME: Mac USB keyboard generates: 306184610Salfred * 0x53: keypad NumLock/Clear 307184610Salfred * 0x66: Power 308184610Salfred * 0x67: keypad = 309184610Salfred * 0x68: F13 310184610Salfred * 0x69: F14 311184610Salfred * 0x6a: F15 312291146Shselasky * 313291146Shselasky * USB Apple Keyboard JIS generates: 314291146Shselasky * 0x90: Kana 315291146Shselasky * 0x91: Eisu 316184610Salfred */ 317184610Salfredstatic const uint8_t ukbd_trtab[256] = { 318184610Salfred 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ 319184610Salfred 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 320184610Salfred 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 321184610Salfred 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 322184610Salfred 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 323184610Salfred 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 324184610Salfred 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 325184610Salfred 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 326184610Salfred 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ 327184610Salfred 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ 328184610Salfred 97, 100, 95, 69, 91, 55, 74, 78,/* 50 - 57 */ 329184610Salfred 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 330184610Salfred 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ 331184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 332184610Salfred NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ 333184610Salfred 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ 334197999Shrs 121, 120, NN, NN, NN, NN, NN, 123, /* 80 - 87 */ 335358213Shselasky 124, 125, 126, 127, 128, NN, NN, NN, /* 88 - 8F */ 336291146Shselasky 129, 130, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 337184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 338184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 339184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 340184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 341184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 342184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 343184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 344184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 345184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 346184610Salfred 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ 347184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 348184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 349184610Salfred NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 350184610Salfred}; 351184610Salfred 352223755Shselaskystatic const uint8_t ukbd_boot_desc[] = { 353223755Shselasky 0x05, 0x01, 0x09, 0x06, 0xa1, 354223755Shselasky 0x01, 0x05, 0x07, 0x19, 0xe0, 355223755Shselasky 0x29, 0xe7, 0x15, 0x00, 0x25, 356223755Shselasky 0x01, 0x75, 0x01, 0x95, 0x08, 357223755Shselasky 0x81, 0x02, 0x95, 0x01, 0x75, 358223755Shselasky 0x08, 0x81, 0x01, 0x95, 0x03, 359223755Shselasky 0x75, 0x01, 0x05, 0x08, 0x19, 360223755Shselasky 0x01, 0x29, 0x03, 0x91, 0x02, 361223755Shselasky 0x95, 0x05, 0x75, 0x01, 0x91, 362223755Shselasky 0x01, 0x95, 0x06, 0x75, 0x08, 363223755Shselasky 0x15, 0x00, 0x26, 0xff, 0x00, 364223755Shselasky 0x05, 0x07, 0x19, 0x00, 0x2a, 365223755Shselasky 0xff, 0x00, 0x81, 0x00, 0xc0 366223755Shselasky}; 367223755Shselasky 368184610Salfred/* prototypes */ 369185948Sthompsastatic void ukbd_timeout(void *); 370185948Sthompsastatic void ukbd_set_leds(struct ukbd_softc *, uint8_t); 371185948Sthompsastatic int ukbd_set_typematic(keyboard_t *, int); 372184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 373358213Shselaskystatic uint32_t ukbd_atkeycode(int, int); 374185948Sthompsastatic int ukbd_key2scan(struct ukbd_softc *, int, int, int); 375184610Salfred#endif 376185948Sthompsastatic uint32_t ukbd_read_char(keyboard_t *, int); 377185948Sthompsastatic void ukbd_clear_state(keyboard_t *); 378185948Sthompsastatic int ukbd_ioctl(keyboard_t *, u_long, caddr_t); 379185948Sthompsastatic int ukbd_enable(keyboard_t *); 380185948Sthompsastatic int ukbd_disable(keyboard_t *); 381185948Sthompsastatic void ukbd_interrupt(struct ukbd_softc *); 382203896Sthompsastatic void ukbd_event_keyinput(struct ukbd_softc *); 383184610Salfred 384184610Salfredstatic device_probe_t ukbd_probe; 385184610Salfredstatic device_attach_t ukbd_attach; 386184610Salfredstatic device_detach_t ukbd_detach; 387184610Salfredstatic device_resume_t ukbd_resume; 388184610Salfred 389307775Sgonzo#ifdef EVDEV_SUPPORT 390307777Sgonzostatic const struct evdev_methods ukbd_evdev_methods = { 391307764Sgonzo .ev_event = evdev_ev_kbd_event, 392307764Sgonzo}; 393307764Sgonzo#endif 394307764Sgonzo 395196489Salfredstatic uint8_t 396196489Salfredukbd_any_key_pressed(struct ukbd_softc *sc) 397196489Salfred{ 398196489Salfred uint8_t i; 399196489Salfred uint8_t j; 400196489Salfred 401196489Salfred for (j = i = 0; i < UKBD_NKEYCODE; i++) 402196489Salfred j |= sc->sc_odata.keycode[i]; 403196489Salfred 404196489Salfred return (j ? 1 : 0); 405196489Salfred} 406196489Salfred 407184610Salfredstatic void 408196489Salfredukbd_start_timer(struct ukbd_softc *sc) 409196489Salfred{ 410196489Salfred sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; 411196489Salfred usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); 412196489Salfred} 413196489Salfred 414196489Salfredstatic void 415184610Salfredukbd_put_key(struct ukbd_softc *sc, uint32_t key) 416184610Salfred{ 417184610Salfred 418228765Savg UKBD_CTX_LOCK_ASSERT(); 419228765Savg 420184610Salfred DPRINTF("0x%02x (%d) %s\n", key, key, 421184610Salfred (key & KEY_RELEASE) ? "released" : "pressed"); 422184610Salfred 423307775Sgonzo#ifdef EVDEV_SUPPORT 424307764Sgonzo if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD && sc->sc_evdev != NULL) { 425307764Sgonzo evdev_push_event(sc->sc_evdev, EV_KEY, 426307764Sgonzo evdev_hid2key(KEY_INDEX(key)), !(key & KEY_RELEASE)); 427307764Sgonzo evdev_sync(sc->sc_evdev); 428307764Sgonzo } 429307764Sgonzo#endif 430307764Sgonzo 431184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_SIZE) { 432184610Salfred sc->sc_input[sc->sc_inputtail] = key; 433184610Salfred ++(sc->sc_inputs); 434184610Salfred ++(sc->sc_inputtail); 435184610Salfred if (sc->sc_inputtail >= UKBD_IN_BUF_SIZE) { 436184610Salfred sc->sc_inputtail = 0; 437184610Salfred } 438184610Salfred } else { 439184610Salfred DPRINTF("input buffer is full\n"); 440184610Salfred } 441184610Salfred} 442184610Salfred 443195960Salfredstatic void 444228765Savgukbd_do_poll(struct ukbd_softc *sc, uint8_t wait) 445223989Shselasky{ 446223989Shselasky 447228765Savg UKBD_CTX_LOCK_ASSERT(); 448228765Savg KASSERT((sc->sc_flags & UKBD_FLAG_POLLING) != 0, 449228765Savg ("ukbd_do_poll called when not polling\n")); 450195960Salfred DPRINTFN(2, "polling\n"); 451195960Salfred 452228765Savg if (!kdb_active && !SCHEDULER_STOPPED()) { 453228765Savg /* 454228765Savg * In this context the kernel is polling for input, 455228765Savg * but the USB subsystem works in normal interrupt-driven 456228765Savg * mode, so we just wait on the USB threads to do the job. 457228765Savg * Note that we currently hold the Giant, but it's also used 458228765Savg * as the transfer mtx, so we must release it while waiting. 459228765Savg */ 460203896Sthompsa while (sc->sc_inputs == 0) { 461228765Savg /* 462228765Savg * Give USB threads a chance to run. Note that 463228765Savg * kern_yield performs DROP_GIANT + PICKUP_GIANT. 464228765Savg */ 465228765Savg kern_yield(PRI_UNCHANGED); 466203896Sthompsa if (!wait) 467203896Sthompsa break; 468203896Sthompsa } 469228765Savg return; 470203896Sthompsa } 471198152Sthompsa 472195960Salfred while (sc->sc_inputs == 0) { 473195960Salfred 474195960Salfred usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER); 475195960Salfred 476196489Salfred /* Delay-optimised support for repetition of keys */ 477196489Salfred if (ukbd_any_key_pressed(sc)) { 478196489Salfred /* a key is pressed - need timekeeping */ 479196489Salfred DELAY(1000); 480195960Salfred 481196489Salfred /* 1 millisecond has passed */ 482196489Salfred sc->sc_time_ms += 1; 483196489Salfred } 484195960Salfred 485195960Salfred ukbd_interrupt(sc); 486195960Salfred 487195960Salfred if (!wait) 488195960Salfred break; 489195960Salfred } 490195960Salfred} 491195960Salfred 492184610Salfredstatic int32_t 493184610Salfredukbd_get_key(struct ukbd_softc *sc, uint8_t wait) 494184610Salfred{ 495184610Salfred int32_t c; 496184610Salfred 497228765Savg UKBD_CTX_LOCK_ASSERT(); 498228765Savg KASSERT((!kdb_active && !SCHEDULER_STOPPED()) 499228765Savg || (sc->sc_flags & UKBD_FLAG_POLLING) != 0, 500228765Savg ("not polling in kdb or panic\n")); 501184610Salfred 502261228Shselasky if (sc->sc_inputs == 0 && 503261228Shselasky (sc->sc_flags & UKBD_FLAG_GONE) == 0) { 504184610Salfred /* start transfer, if not already started */ 505305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 506305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 507184610Salfred } 508203896Sthompsa 509203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 510195960Salfred ukbd_do_poll(sc, wait); 511203896Sthompsa 512184610Salfred if (sc->sc_inputs == 0) { 513184610Salfred c = -1; 514184610Salfred } else { 515184610Salfred c = sc->sc_input[sc->sc_inputhead]; 516184610Salfred --(sc->sc_inputs); 517184610Salfred ++(sc->sc_inputhead); 518184610Salfred if (sc->sc_inputhead >= UKBD_IN_BUF_SIZE) { 519184610Salfred sc->sc_inputhead = 0; 520184610Salfred } 521184610Salfred } 522184610Salfred return (c); 523184610Salfred} 524184610Salfred 525184610Salfredstatic void 526184610Salfredukbd_interrupt(struct ukbd_softc *sc) 527184610Salfred{ 528184610Salfred uint32_t n_mod; 529184610Salfred uint32_t o_mod; 530184610Salfred uint32_t now = sc->sc_time_ms; 531184610Salfred uint32_t dtime; 532184610Salfred uint8_t key; 533184610Salfred uint8_t i; 534184610Salfred uint8_t j; 535184610Salfred 536228765Savg UKBD_CTX_LOCK_ASSERT(); 537228765Savg 538203896Sthompsa if (sc->sc_ndata.keycode[0] == KEY_ERROR) 539203896Sthompsa return; 540203896Sthompsa 541184610Salfred n_mod = sc->sc_ndata.modifiers; 542184610Salfred o_mod = sc->sc_odata.modifiers; 543184610Salfred if (n_mod != o_mod) { 544184610Salfred for (i = 0; i < UKBD_NMOD; i++) { 545184610Salfred if ((n_mod & ukbd_mods[i].mask) != 546184610Salfred (o_mod & ukbd_mods[i].mask)) { 547184610Salfred ukbd_put_key(sc, ukbd_mods[i].key | 548184610Salfred ((n_mod & ukbd_mods[i].mask) ? 549184610Salfred KEY_PRESS : KEY_RELEASE)); 550184610Salfred } 551184610Salfred } 552184610Salfred } 553184610Salfred /* Check for released keys. */ 554184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 555184610Salfred key = sc->sc_odata.keycode[i]; 556184610Salfred if (key == 0) { 557184610Salfred continue; 558184610Salfred } 559184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 560184610Salfred if (sc->sc_ndata.keycode[j] == 0) { 561184610Salfred continue; 562184610Salfred } 563184610Salfred if (key == sc->sc_ndata.keycode[j]) { 564184610Salfred goto rfound; 565184610Salfred } 566184610Salfred } 567184610Salfred ukbd_put_key(sc, key | KEY_RELEASE); 568184610Salfredrfound: ; 569184610Salfred } 570184610Salfred 571184610Salfred /* Check for pressed keys. */ 572184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 573184610Salfred key = sc->sc_ndata.keycode[i]; 574184610Salfred if (key == 0) { 575184610Salfred continue; 576184610Salfred } 577184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1; 578184610Salfred for (j = 0; j < UKBD_NKEYCODE; j++) { 579184610Salfred if (sc->sc_odata.keycode[j] == 0) { 580184610Salfred continue; 581184610Salfred } 582184610Salfred if (key == sc->sc_odata.keycode[j]) { 583184610Salfred 584184610Salfred /* key is still pressed */ 585184610Salfred 586184610Salfred sc->sc_ntime[i] = sc->sc_otime[j]; 587184610Salfred dtime = (sc->sc_otime[j] - now); 588184610Salfred 589184610Salfred if (!(dtime & 0x80000000)) { 590184610Salfred /* time has not elapsed */ 591184610Salfred goto pfound; 592184610Salfred } 593184610Salfred sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2; 594184610Salfred break; 595184610Salfred } 596184610Salfred } 597184610Salfred ukbd_put_key(sc, key | KEY_PRESS); 598184610Salfred 599184610Salfred /* 600184610Salfred * If any other key is presently down, force its repeat to be 601184610Salfred * well in the future (100s). This makes the last key to be 602184610Salfred * pressed do the autorepeat. 603184610Salfred */ 604184610Salfred for (j = 0; j != UKBD_NKEYCODE; j++) { 605184610Salfred if (j != i) 606184610Salfred sc->sc_ntime[j] = now + (100 * 1000); 607184610Salfred } 608184610Salfredpfound: ; 609184610Salfred } 610184610Salfred 611184610Salfred sc->sc_odata = sc->sc_ndata; 612184610Salfred 613203896Sthompsa memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime)); 614184610Salfred 615203896Sthompsa ukbd_event_keyinput(sc); 616203896Sthompsa} 617203896Sthompsa 618203896Sthompsastatic void 619203896Sthompsaukbd_event_keyinput(struct ukbd_softc *sc) 620203896Sthompsa{ 621203896Sthompsa int c; 622203896Sthompsa 623228765Savg UKBD_CTX_LOCK_ASSERT(); 624228765Savg 625228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) != 0) 626203896Sthompsa return; 627203896Sthompsa 628203896Sthompsa if (sc->sc_inputs == 0) 629203896Sthompsa return; 630203896Sthompsa 631184610Salfred if (KBD_IS_ACTIVE(&sc->sc_kbd) && 632184610Salfred KBD_IS_BUSY(&sc->sc_kbd)) { 633184610Salfred /* let the callback function process the input */ 634184610Salfred (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, 635184610Salfred sc->sc_kbd.kb_callback.kc_arg); 636184610Salfred } else { 637184610Salfred /* read and discard the input, no one is waiting for it */ 638184610Salfred do { 639184610Salfred c = ukbd_read_char(&sc->sc_kbd, 0); 640184610Salfred } while (c != NOKEY); 641184610Salfred } 642184610Salfred} 643184610Salfred 644184610Salfredstatic void 645184610Salfredukbd_timeout(void *arg) 646184610Salfred{ 647184610Salfred struct ukbd_softc *sc = arg; 648184610Salfred 649228765Savg UKBD_LOCK_ASSERT(); 650184610Salfred 651203896Sthompsa sc->sc_time_ms += 25; /* milliseconds */ 652203896Sthompsa 653184610Salfred ukbd_interrupt(sc); 654184610Salfred 655203896Sthompsa /* Make sure any leftover key events gets read out */ 656203896Sthompsa ukbd_event_keyinput(sc); 657203896Sthompsa 658203896Sthompsa if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { 659196489Salfred ukbd_start_timer(sc); 660196489Salfred } else { 661196489Salfred sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; 662196489Salfred } 663184610Salfred} 664184610Salfred 665192925Sthompsastatic uint8_t 666192925Sthompsaukbd_apple_fn(uint8_t keycode) { 667192925Sthompsa switch (keycode) { 668192925Sthompsa case 0x28: return 0x49; /* RETURN -> INSERT */ 669192925Sthompsa case 0x2a: return 0x4c; /* BACKSPACE -> DEL */ 670192925Sthompsa case 0x50: return 0x4a; /* LEFT ARROW -> HOME */ 671192925Sthompsa case 0x4f: return 0x4d; /* RIGHT ARROW -> END */ 672192925Sthompsa case 0x52: return 0x4b; /* UP ARROW -> PGUP */ 673192925Sthompsa case 0x51: return 0x4e; /* DOWN ARROW -> PGDN */ 674192925Sthompsa default: return keycode; 675192925Sthompsa } 676192925Sthompsa} 677184610Salfred 678192925Sthompsastatic uint8_t 679192925Sthompsaukbd_apple_swap(uint8_t keycode) { 680192925Sthompsa switch (keycode) { 681192925Sthompsa case 0x35: return 0x64; 682192925Sthompsa case 0x64: return 0x35; 683192925Sthompsa default: return keycode; 684184610Salfred } 685184610Salfred} 686184610Salfred 687184610Salfredstatic void 688194677Sthompsaukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) 689184610Salfred{ 690194677Sthompsa struct ukbd_softc *sc = usbd_xfer_softc(xfer); 691194677Sthompsa struct usb_page_cache *pc; 692184610Salfred uint8_t i; 693192925Sthompsa uint8_t offset; 694192925Sthompsa uint8_t id; 695194677Sthompsa int len; 696184610Salfred 697228765Savg UKBD_LOCK_ASSERT(); 698228765Savg 699194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 700194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 701194677Sthompsa 702184610Salfred switch (USB_GET_STATE(xfer)) { 703184610Salfred case USB_ST_TRANSFERRED: 704184610Salfred DPRINTF("actlen=%d bytes\n", len); 705184610Salfred 706192925Sthompsa if (len == 0) { 707192925Sthompsa DPRINTF("zero length data\n"); 708192925Sthompsa goto tr_setup; 709192925Sthompsa } 710192925Sthompsa 711192925Sthompsa if (sc->sc_kbd_id != 0) { 712192925Sthompsa /* check and remove HID ID byte */ 713194677Sthompsa usbd_copy_out(pc, 0, &id, 1); 714223755Shselasky offset = 1; 715223755Shselasky len--; 716223755Shselasky if (len == 0) { 717223755Shselasky DPRINTF("zero length data\n"); 718192925Sthompsa goto tr_setup; 719192925Sthompsa } 720192925Sthompsa } else { 721192925Sthompsa offset = 0; 722223755Shselasky id = 0; 723192925Sthompsa } 724192925Sthompsa 725223755Shselasky if (len > UKBD_BUFFER_SIZE) 726223755Shselasky len = UKBD_BUFFER_SIZE; 727192925Sthompsa 728223755Shselasky /* get data */ 729223755Shselasky usbd_copy_out(pc, offset, sc->sc_buffer, len); 730192925Sthompsa 731223755Shselasky /* clear temporary storage */ 732223755Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 733192925Sthompsa 734223755Shselasky /* scan through HID data */ 735223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) && 736223755Shselasky (id == sc->sc_id_apple_eject)) { 737223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject)) 738223755Shselasky sc->sc_modifiers |= MOD_EJECT; 739192925Sthompsa else 740223755Shselasky sc->sc_modifiers &= ~MOD_EJECT; 741223755Shselasky } 742223755Shselasky if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) && 743223755Shselasky (id == sc->sc_id_apple_fn)) { 744223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn)) 745223755Shselasky sc->sc_modifiers |= MOD_FN; 746223755Shselasky else 747223755Shselasky sc->sc_modifiers &= ~MOD_FN; 748223755Shselasky } 749223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_L) && 750223755Shselasky (id == sc->sc_id_ctrl_l)) { 751223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_l)) 752223755Shselasky sc-> sc_modifiers |= MOD_CONTROL_L; 753223755Shselasky else 754223755Shselasky sc-> sc_modifiers &= ~MOD_CONTROL_L; 755223755Shselasky } 756223755Shselasky if ((sc->sc_flags & UKBD_FLAG_CTRL_R) && 757223755Shselasky (id == sc->sc_id_ctrl_r)) { 758223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_r)) 759223755Shselasky sc->sc_modifiers |= MOD_CONTROL_R; 760223755Shselasky else 761223755Shselasky sc->sc_modifiers &= ~MOD_CONTROL_R; 762223755Shselasky } 763223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) && 764223755Shselasky (id == sc->sc_id_shift_l)) { 765223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_l)) 766223755Shselasky sc->sc_modifiers |= MOD_SHIFT_L; 767223755Shselasky else 768223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_L; 769223755Shselasky } 770223755Shselasky if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) && 771223755Shselasky (id == sc->sc_id_shift_r)) { 772223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_r)) 773223755Shselasky sc->sc_modifiers |= MOD_SHIFT_R; 774223755Shselasky else 775223755Shselasky sc->sc_modifiers &= ~MOD_SHIFT_R; 776223755Shselasky } 777223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_L) && 778223755Shselasky (id == sc->sc_id_alt_l)) { 779223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l)) 780223755Shselasky sc->sc_modifiers |= MOD_ALT_L; 781223755Shselasky else 782223755Shselasky sc->sc_modifiers &= ~MOD_ALT_L; 783223755Shselasky } 784223755Shselasky if ((sc->sc_flags & UKBD_FLAG_ALT_R) && 785223755Shselasky (id == sc->sc_id_alt_r)) { 786223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r)) 787223755Shselasky sc->sc_modifiers |= MOD_ALT_R; 788223755Shselasky else 789223755Shselasky sc->sc_modifiers &= ~MOD_ALT_R; 790223755Shselasky } 791223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_L) && 792223755Shselasky (id == sc->sc_id_win_l)) { 793223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l)) 794223755Shselasky sc->sc_modifiers |= MOD_WIN_L; 795223755Shselasky else 796223755Shselasky sc->sc_modifiers &= ~MOD_WIN_L; 797223755Shselasky } 798223755Shselasky if ((sc->sc_flags & UKBD_FLAG_WIN_R) && 799223755Shselasky (id == sc->sc_id_win_r)) { 800223755Shselasky if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r)) 801223755Shselasky sc->sc_modifiers |= MOD_WIN_R; 802223755Shselasky else 803223755Shselasky sc->sc_modifiers &= ~MOD_WIN_R; 804223755Shselasky } 805192925Sthompsa 806223755Shselasky sc->sc_ndata.modifiers = sc->sc_modifiers; 807223755Shselasky 808223755Shselasky if ((sc->sc_flags & UKBD_FLAG_EVENTS) && 809223755Shselasky (id == sc->sc_id_events)) { 810223755Shselasky i = sc->sc_loc_events.count; 811223755Shselasky if (i > UKBD_NKEYCODE) 812223755Shselasky i = UKBD_NKEYCODE; 813223755Shselasky if (i > len) 814223755Shselasky i = len; 815223755Shselasky while (i--) { 816223755Shselasky sc->sc_ndata.keycode[i] = 817223755Shselasky hid_get_data(sc->sc_buffer + i, len - i, 818223755Shselasky &sc->sc_loc_events); 819184610Salfred } 820223755Shselasky } 821223755Shselasky 822223755Shselasky#ifdef USB_DEBUG 823223755Shselasky DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers); 824223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 825223755Shselasky if (sc->sc_ndata.keycode[i]) { 826223755Shselasky DPRINTF("[%d] = 0x%02x\n", 827223755Shselasky (int)i, (int)sc->sc_ndata.keycode[i]); 828223755Shselasky } 829223755Shselasky } 830223755Shselasky#endif 831223755Shselasky if (sc->sc_modifiers & MOD_FN) { 832184610Salfred for (i = 0; i < UKBD_NKEYCODE; i++) { 833223755Shselasky sc->sc_ndata.keycode[i] = 834223755Shselasky ukbd_apple_fn(sc->sc_ndata.keycode[i]); 835184610Salfred } 836223755Shselasky } 837192925Sthompsa 838223755Shselasky if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) { 839223755Shselasky for (i = 0; i < UKBD_NKEYCODE; i++) { 840223755Shselasky sc->sc_ndata.keycode[i] = 841223755Shselasky ukbd_apple_swap(sc->sc_ndata.keycode[i]); 842192925Sthompsa } 843223755Shselasky } 844192925Sthompsa 845223755Shselasky ukbd_interrupt(sc); 846192925Sthompsa 847223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { 848223755Shselasky if (ukbd_any_key_pressed(sc)) { 849223755Shselasky ukbd_start_timer(sc); 850196489Salfred } 851184610Salfred } 852223755Shselasky 853184610Salfred case USB_ST_SETUP: 854192925Sthompsatr_setup: 855184610Salfred if (sc->sc_inputs < UKBD_IN_BUF_FULL) { 856194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 857194228Sthompsa usbd_transfer_submit(xfer); 858184610Salfred } else { 859184610Salfred DPRINTF("input queue is full!\n"); 860184610Salfred } 861192925Sthompsa break; 862184610Salfred 863184610Salfred default: /* Error */ 864194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 865184610Salfred 866194677Sthompsa if (error != USB_ERR_CANCELLED) { 867184610Salfred /* try to clear stall first */ 868194677Sthompsa usbd_xfer_set_stall(xfer); 869192925Sthompsa goto tr_setup; 870184610Salfred } 871192925Sthompsa break; 872184610Salfred } 873184610Salfred} 874184610Salfred 875184610Salfredstatic void 876194677Sthompsaukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) 877184610Salfred{ 878223755Shselasky struct ukbd_softc *sc = usbd_xfer_softc(xfer); 879192984Sthompsa struct usb_device_request req; 880194677Sthompsa struct usb_page_cache *pc; 881223755Shselasky uint8_t id; 882223755Shselasky uint8_t any; 883223755Shselasky int len; 884184610Salfred 885228765Savg UKBD_LOCK_ASSERT(); 886228765Savg 887207077Sthompsa#ifdef USB_DEBUG 888196489Salfred if (ukbd_no_leds) 889196489Salfred return; 890196489Salfred#endif 891196489Salfred 892184610Salfred switch (USB_GET_STATE(xfer)) { 893184610Salfred case USB_ST_TRANSFERRED: 894184610Salfred case USB_ST_SETUP: 895223755Shselasky if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS)) 896223755Shselasky break; 897223755Shselasky sc->sc_flags &= ~UKBD_FLAG_SET_LEDS; 898184610Salfred 899223755Shselasky req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 900223755Shselasky req.bRequest = UR_SET_REPORT; 901223755Shselasky USETW2(req.wValue, UHID_OUTPUT_REPORT, 0); 902223755Shselasky req.wIndex[0] = sc->sc_iface_no; 903223755Shselasky req.wIndex[1] = 0; 904223755Shselasky req.wLength[1] = 0; 905184610Salfred 906223755Shselasky memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE); 907223755Shselasky 908223755Shselasky id = 0; 909223755Shselasky any = 0; 910223755Shselasky 911223755Shselasky /* Assumption: All led bits must be in the same ID. */ 912223755Shselasky 913223755Shselasky if (sc->sc_flags & UKBD_FLAG_NUMLOCK) { 914223755Shselasky if (sc->sc_leds & NLKED) { 915223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 916223755Shselasky &sc->sc_loc_numlock, 1); 917192925Sthompsa } 918223755Shselasky id = sc->sc_id_numlock; 919223755Shselasky any = 1; 920223755Shselasky } 921184610Salfred 922223755Shselasky if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) { 923223755Shselasky if (sc->sc_leds & SLKED) { 924223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 925223755Shselasky &sc->sc_loc_scrolllock, 1); 926223755Shselasky } 927223755Shselasky id = sc->sc_id_scrolllock; 928223755Shselasky any = 1; 929223755Shselasky } 930184610Salfred 931223755Shselasky if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) { 932223755Shselasky if (sc->sc_leds & CLKED) { 933223755Shselasky hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, 934223755Shselasky &sc->sc_loc_capslock, 1); 935223755Shselasky } 936223755Shselasky id = sc->sc_id_capslock; 937223755Shselasky any = 1; 938184610Salfred } 939223755Shselasky 940223755Shselasky /* if no leds, nothing to do */ 941223755Shselasky if (!any) 942223755Shselasky break; 943223755Shselasky 944307775Sgonzo#ifdef EVDEV_SUPPORT 945307764Sgonzo if (sc->sc_evdev != NULL) 946307764Sgonzo evdev_push_leds(sc->sc_evdev, sc->sc_leds); 947307764Sgonzo#endif 948307764Sgonzo 949223755Shselasky /* range check output report length */ 950223755Shselasky len = sc->sc_led_size; 951223755Shselasky if (len > (UKBD_BUFFER_SIZE - 1)) 952223755Shselasky len = (UKBD_BUFFER_SIZE - 1); 953223755Shselasky 954223755Shselasky /* check if we need to prefix an ID byte */ 955223755Shselasky sc->sc_buffer[0] = id; 956223755Shselasky 957223755Shselasky pc = usbd_xfer_get_frame(xfer, 1); 958223755Shselasky if (id != 0) { 959223755Shselasky len++; 960223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer, len); 961223755Shselasky } else { 962223755Shselasky usbd_copy_in(pc, 0, sc->sc_buffer + 1, len); 963223755Shselasky } 964223755Shselasky req.wLength[0] = len; 965223755Shselasky usbd_xfer_set_frame_len(xfer, 1, len); 966223755Shselasky 967223755Shselasky DPRINTF("len=%d, id=%d\n", len, id); 968223755Shselasky 969223755Shselasky /* setup control request last */ 970223755Shselasky pc = usbd_xfer_get_frame(xfer, 0); 971223755Shselasky usbd_copy_in(pc, 0, &req, sizeof(req)); 972223755Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 973223755Shselasky 974223755Shselasky /* start data transfer */ 975223755Shselasky usbd_xfer_set_frames(xfer, 2); 976223755Shselasky usbd_transfer_submit(xfer); 977196489Salfred break; 978184610Salfred 979184610Salfred default: /* Error */ 980212128Sthompsa DPRINTFN(1, "error=%s\n", usbd_errstr(error)); 981196489Salfred break; 982184610Salfred } 983184610Salfred} 984184610Salfred 985192984Sthompsastatic const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { 986184610Salfred 987305644Shselasky [UKBD_INTR_DT_0] = { 988184610Salfred .type = UE_INTERRUPT, 989184610Salfred .endpoint = UE_ADDR_ANY, 990184610Salfred .direction = UE_DIR_IN, 991190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 992190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 993190734Sthompsa .callback = &ukbd_intr_callback, 994184610Salfred }, 995184610Salfred 996305644Shselasky [UKBD_INTR_DT_1] = { 997305644Shselasky .type = UE_INTERRUPT, 998305644Shselasky .endpoint = UE_ADDR_ANY, 999305644Shselasky .direction = UE_DIR_IN, 1000305644Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 1001305644Shselasky .bufsize = 0, /* use wMaxPacketSize */ 1002305644Shselasky .callback = &ukbd_intr_callback, 1003305644Shselasky }, 1004305644Shselasky 1005187259Sthompsa [UKBD_CTRL_LED] = { 1006184610Salfred .type = UE_CONTROL, 1007184610Salfred .endpoint = 0x00, /* Control pipe */ 1008184610Salfred .direction = UE_DIR_ANY, 1009223755Shselasky .bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE, 1010190734Sthompsa .callback = &ukbd_set_leds_callback, 1011190734Sthompsa .timeout = 1000, /* 1 second */ 1012184610Salfred }, 1013184610Salfred}; 1014184610Salfred 1015223521Shselasky/* A match on these entries will load ukbd */ 1016223521Shselaskystatic const STRUCT_USB_HOST_ID __used ukbd_devs[] = { 1017223521Shselasky {USB_IFACE_CLASS(UICLASS_HID), 1018223521Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), 1019223521Shselasky USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),}, 1020223521Shselasky}; 1021223521Shselasky 1022184610Salfredstatic int 1023184610Salfredukbd_probe(device_t dev) 1024184610Salfred{ 1025184610Salfred keyboard_switch_t *sw = kbd_get_switch(UKBD_DRIVER_NAME); 1026192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1027194067Sthompsa void *d_ptr; 1028194067Sthompsa int error; 1029194067Sthompsa uint16_t d_len; 1030184610Salfred 1031228765Savg UKBD_LOCK_ASSERT(); 1032184610Salfred DPRINTFN(11, "\n"); 1033184610Salfred 1034184610Salfred if (sw == NULL) { 1035184610Salfred return (ENXIO); 1036184610Salfred } 1037192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 1038184610Salfred return (ENXIO); 1039184610Salfred } 1040194067Sthompsa 1041194067Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 1042194067Sthompsa return (ENXIO); 1043194067Sthompsa 1044245248Shselasky if (usb_test_quirk(uaa, UQ_KBD_IGNORE)) 1045245248Shselasky return (ENXIO); 1046245248Shselasky 1047194067Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 1048245248Shselasky (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) 1049245248Shselasky return (BUS_PROBE_DEFAULT); 1050194067Sthompsa 1051194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 1052194067Sthompsa &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 1053194067Sthompsa 1054194067Sthompsa if (error) 1055194067Sthompsa return (ENXIO); 1056194067Sthompsa 1057245248Shselasky if (hid_is_keyboard(d_ptr, d_len)) { 1058245248Shselasky if (hid_is_mouse(d_ptr, d_len)) { 1059245248Shselasky /* 1060245248Shselasky * NOTE: We currently don't support USB mouse 1061245248Shselasky * and USB keyboard on the same USB endpoint. 1062245248Shselasky * Let "ums" driver win. 1063245248Shselasky */ 1064194067Sthompsa error = ENXIO; 1065245248Shselasky } else { 1066222051Savg error = BUS_PROBE_DEFAULT; 1067245248Shselasky } 1068245248Shselasky } else { 1069194067Sthompsa error = ENXIO; 1070245248Shselasky } 1071194067Sthompsa free(d_ptr, M_TEMP); 1072194067Sthompsa return (error); 1073184610Salfred} 1074184610Salfred 1075223755Shselaskystatic void 1076223755Shselaskyukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len) 1077223755Shselasky{ 1078223755Shselasky uint32_t flags; 1079223755Shselasky 1080223755Shselasky /* reset detected bits */ 1081223755Shselasky sc->sc_flags &= ~UKBD_FLAG_HID_MASK; 1082223755Shselasky 1083223755Shselasky /* check if there is an ID byte */ 1084223755Shselasky sc->sc_kbd_size = hid_report_size(ptr, len, 1085223755Shselasky hid_input, &sc->sc_kbd_id); 1086223755Shselasky 1087223755Shselasky /* investigate if this is an Apple Keyboard */ 1088223755Shselasky if (hid_locate(ptr, len, 1089223755Shselasky HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT), 1090223755Shselasky hid_input, 0, &sc->sc_loc_apple_eject, &flags, 1091223755Shselasky &sc->sc_id_apple_eject)) { 1092223755Shselasky if (flags & HIO_VARIABLE) 1093223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_EJECT | 1094223755Shselasky UKBD_FLAG_APPLE_SWAP; 1095223755Shselasky DPRINTFN(1, "Found Apple eject-key\n"); 1096223755Shselasky } 1097223755Shselasky if (hid_locate(ptr, len, 1098223755Shselasky HID_USAGE2(0xFFFF, 0x0003), 1099223755Shselasky hid_input, 0, &sc->sc_loc_apple_fn, &flags, 1100223755Shselasky &sc->sc_id_apple_fn)) { 1101223755Shselasky if (flags & HIO_VARIABLE) 1102223755Shselasky sc->sc_flags |= UKBD_FLAG_APPLE_FN; 1103223755Shselasky DPRINTFN(1, "Found Apple FN-key\n"); 1104223755Shselasky } 1105223755Shselasky /* figure out some keys */ 1106223755Shselasky if (hid_locate(ptr, len, 1107223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE0), 1108223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_l, &flags, 1109223755Shselasky &sc->sc_id_ctrl_l)) { 1110223755Shselasky if (flags & HIO_VARIABLE) 1111223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_L; 1112223755Shselasky DPRINTFN(1, "Found left control\n"); 1113223755Shselasky } 1114223755Shselasky if (hid_locate(ptr, len, 1115223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE4), 1116223755Shselasky hid_input, 0, &sc->sc_loc_ctrl_r, &flags, 1117223755Shselasky &sc->sc_id_ctrl_r)) { 1118223755Shselasky if (flags & HIO_VARIABLE) 1119223755Shselasky sc->sc_flags |= UKBD_FLAG_CTRL_R; 1120223755Shselasky DPRINTFN(1, "Found right control\n"); 1121223755Shselasky } 1122223755Shselasky if (hid_locate(ptr, len, 1123223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE1), 1124223755Shselasky hid_input, 0, &sc->sc_loc_shift_l, &flags, 1125223755Shselasky &sc->sc_id_shift_l)) { 1126223755Shselasky if (flags & HIO_VARIABLE) 1127223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_L; 1128223755Shselasky DPRINTFN(1, "Found left shift\n"); 1129223755Shselasky } 1130223755Shselasky if (hid_locate(ptr, len, 1131223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE5), 1132223755Shselasky hid_input, 0, &sc->sc_loc_shift_r, &flags, 1133223755Shselasky &sc->sc_id_shift_r)) { 1134223755Shselasky if (flags & HIO_VARIABLE) 1135223755Shselasky sc->sc_flags |= UKBD_FLAG_SHIFT_R; 1136223755Shselasky DPRINTFN(1, "Found right shift\n"); 1137223755Shselasky } 1138223755Shselasky if (hid_locate(ptr, len, 1139223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE2), 1140223755Shselasky hid_input, 0, &sc->sc_loc_alt_l, &flags, 1141223755Shselasky &sc->sc_id_alt_l)) { 1142223755Shselasky if (flags & HIO_VARIABLE) 1143223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_L; 1144223755Shselasky DPRINTFN(1, "Found left alt\n"); 1145223755Shselasky } 1146223755Shselasky if (hid_locate(ptr, len, 1147223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE6), 1148223755Shselasky hid_input, 0, &sc->sc_loc_alt_r, &flags, 1149223755Shselasky &sc->sc_id_alt_r)) { 1150223755Shselasky if (flags & HIO_VARIABLE) 1151223755Shselasky sc->sc_flags |= UKBD_FLAG_ALT_R; 1152223755Shselasky DPRINTFN(1, "Found right alt\n"); 1153223755Shselasky } 1154223755Shselasky if (hid_locate(ptr, len, 1155223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE3), 1156223755Shselasky hid_input, 0, &sc->sc_loc_win_l, &flags, 1157223755Shselasky &sc->sc_id_win_l)) { 1158223755Shselasky if (flags & HIO_VARIABLE) 1159223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_L; 1160223755Shselasky DPRINTFN(1, "Found left GUI\n"); 1161223755Shselasky } 1162223755Shselasky if (hid_locate(ptr, len, 1163223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0xE7), 1164223755Shselasky hid_input, 0, &sc->sc_loc_win_r, &flags, 1165223755Shselasky &sc->sc_id_win_r)) { 1166223755Shselasky if (flags & HIO_VARIABLE) 1167223755Shselasky sc->sc_flags |= UKBD_FLAG_WIN_R; 1168223755Shselasky DPRINTFN(1, "Found right GUI\n"); 1169223755Shselasky } 1170223755Shselasky /* figure out event buffer */ 1171223755Shselasky if (hid_locate(ptr, len, 1172223755Shselasky HID_USAGE2(HUP_KEYBOARD, 0x00), 1173223755Shselasky hid_input, 0, &sc->sc_loc_events, &flags, 1174223755Shselasky &sc->sc_id_events)) { 1175254572Shselasky if (flags & HIO_VARIABLE) { 1176254572Shselasky DPRINTFN(1, "Ignoring keyboard event control\n"); 1177254572Shselasky } else { 1178254572Shselasky sc->sc_flags |= UKBD_FLAG_EVENTS; 1179254572Shselasky DPRINTFN(1, "Found keyboard event array\n"); 1180254572Shselasky } 1181223755Shselasky } 1182223755Shselasky 1183223755Shselasky /* figure out leds on keyboard */ 1184223755Shselasky sc->sc_led_size = hid_report_size(ptr, len, 1185223755Shselasky hid_output, NULL); 1186223755Shselasky 1187223755Shselasky if (hid_locate(ptr, len, 1188223755Shselasky HID_USAGE2(HUP_LEDS, 0x01), 1189223755Shselasky hid_output, 0, &sc->sc_loc_numlock, &flags, 1190223755Shselasky &sc->sc_id_numlock)) { 1191223755Shselasky if (flags & HIO_VARIABLE) 1192223755Shselasky sc->sc_flags |= UKBD_FLAG_NUMLOCK; 1193223755Shselasky DPRINTFN(1, "Found keyboard numlock\n"); 1194223755Shselasky } 1195223755Shselasky if (hid_locate(ptr, len, 1196223755Shselasky HID_USAGE2(HUP_LEDS, 0x02), 1197223755Shselasky hid_output, 0, &sc->sc_loc_capslock, &flags, 1198223755Shselasky &sc->sc_id_capslock)) { 1199223755Shselasky if (flags & HIO_VARIABLE) 1200223755Shselasky sc->sc_flags |= UKBD_FLAG_CAPSLOCK; 1201223755Shselasky DPRINTFN(1, "Found keyboard capslock\n"); 1202223755Shselasky } 1203223755Shselasky if (hid_locate(ptr, len, 1204223755Shselasky HID_USAGE2(HUP_LEDS, 0x03), 1205223755Shselasky hid_output, 0, &sc->sc_loc_scrolllock, &flags, 1206223755Shselasky &sc->sc_id_scrolllock)) { 1207223755Shselasky if (flags & HIO_VARIABLE) 1208223755Shselasky sc->sc_flags |= UKBD_FLAG_SCROLLLOCK; 1209223755Shselasky DPRINTFN(1, "Found keyboard scrolllock\n"); 1210223755Shselasky } 1211223755Shselasky} 1212223755Shselasky 1213184610Salfredstatic int 1214184610Salfredukbd_attach(device_t dev) 1215184610Salfred{ 1216184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1217192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1218253332Shselasky int unit = device_get_unit(dev); 1219184610Salfred keyboard_t *kbd = &sc->sc_kbd; 1220192925Sthompsa void *hid_ptr = NULL; 1221193045Sthompsa usb_error_t err; 1222184610Salfred uint16_t n; 1223192925Sthompsa uint16_t hid_len; 1224307775Sgonzo#ifdef EVDEV_SUPPORT 1225307764Sgonzo struct evdev_dev *evdev; 1226307764Sgonzo int i; 1227307764Sgonzo#endif 1228253332Shselasky#ifdef USB_DEBUG 1229253332Shselasky int rate; 1230253332Shselasky#endif 1231228765Savg UKBD_LOCK_ASSERT(); 1232228765Savg 1233184610Salfred kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); 1234184610Salfred 1235184610Salfred kbd->kb_data = (void *)sc; 1236184610Salfred 1237194228Sthompsa device_set_usb_desc(dev); 1238184610Salfred 1239184610Salfred sc->sc_udev = uaa->device; 1240184610Salfred sc->sc_iface = uaa->iface; 1241184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 1242184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 1243184610Salfred sc->sc_mode = K_XLATE; 1244184610Salfred 1245194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &Giant, 0); 1246184610Salfred 1247305644Shselasky#ifdef UKBD_NO_POLLING 1248194228Sthompsa err = usbd_transfer_setup(uaa->device, 1249184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config, 1250184610Salfred UKBD_N_TRANSFER, sc, &Giant); 1251305644Shselasky#else 1252305644Shselasky /* 1253305644Shselasky * Setup the UKBD USB transfers one by one, so they are memory 1254305644Shselasky * independent which allows for handling panics triggered by 1255305644Shselasky * the keyboard driver itself, typically via CTRL+ALT+ESC 1256305644Shselasky * sequences. Or if the USB keyboard driver was processing a 1257305644Shselasky * key at the moment of panic. 1258305644Shselasky */ 1259305644Shselasky for (n = 0; n != UKBD_N_TRANSFER; n++) { 1260305644Shselasky err = usbd_transfer_setup(uaa->device, 1261305644Shselasky &uaa->info.bIfaceIndex, sc->sc_xfer + n, ukbd_config + n, 1262305644Shselasky 1, sc, &Giant); 1263305644Shselasky if (err) 1264305644Shselasky break; 1265305644Shselasky } 1266305644Shselasky#endif 1267184610Salfred 1268184610Salfred if (err) { 1269194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 1270184610Salfred goto detach; 1271184610Salfred } 1272184610Salfred /* setup default keyboard maps */ 1273184610Salfred 1274184610Salfred sc->sc_keymap = key_map; 1275184610Salfred sc->sc_accmap = accent_map; 1276184610Salfred for (n = 0; n < UKBD_NFKEY; n++) { 1277184610Salfred sc->sc_fkeymap[n] = fkey_tab[n]; 1278184610Salfred } 1279184610Salfred 1280184610Salfred kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap, 1281184610Salfred sc->sc_fkeymap, UKBD_NFKEY); 1282184610Salfred 1283184610Salfred KBD_FOUND_DEVICE(kbd); 1284184610Salfred 1285184610Salfred ukbd_clear_state(kbd); 1286184610Salfred 1287184610Salfred /* 1288184610Salfred * FIXME: set the initial value for lock keys in "sc_state" 1289184610Salfred * according to the BIOS data? 1290184610Salfred */ 1291184610Salfred KBD_PROBE_DONE(kbd); 1292184610Salfred 1293223755Shselasky /* get HID descriptor */ 1294194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, 1295192925Sthompsa &hid_len, M_TEMP, uaa->info.bIfaceIndex); 1296223755Shselasky 1297192925Sthompsa if (err == 0) { 1298223755Shselasky DPRINTF("Parsing HID descriptor of %d bytes\n", 1299223755Shselasky (int)hid_len); 1300192925Sthompsa 1301223755Shselasky ukbd_parse_hid(sc, hid_ptr, hid_len); 1302192925Sthompsa 1303192925Sthompsa free(hid_ptr, M_TEMP); 1304192925Sthompsa } 1305192925Sthompsa 1306223755Shselasky /* check if we should use the boot protocol */ 1307223755Shselasky if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) || 1308223755Shselasky (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) { 1309223755Shselasky 1310223755Shselasky DPRINTF("Forcing boot protocol\n"); 1311223755Shselasky 1312223755Shselasky err = usbd_req_set_protocol(sc->sc_udev, NULL, 1313223755Shselasky sc->sc_iface_index, 0); 1314223755Shselasky 1315223755Shselasky if (err != 0) { 1316223755Shselasky DPRINTF("Set protocol error=%s (ignored)\n", 1317223755Shselasky usbd_errstr(err)); 1318223755Shselasky } 1319223755Shselasky 1320223755Shselasky ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc)); 1321223755Shselasky } 1322223755Shselasky 1323184610Salfred /* ignore if SETIDLE fails, hence it is not crucial */ 1324223755Shselasky usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); 1325184610Salfred 1326184610Salfred ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); 1327184610Salfred 1328184610Salfred KBD_INIT_DONE(kbd); 1329184610Salfred 1330184610Salfred if (kbd_register(kbd) < 0) { 1331184610Salfred goto detach; 1332184610Salfred } 1333184610Salfred KBD_CONFIG_DONE(kbd); 1334184610Salfred 1335184610Salfred ukbd_enable(kbd); 1336184610Salfred 1337184610Salfred#ifdef KBD_INSTALL_CDEV 1338184610Salfred if (kbd_attach(kbd)) { 1339184610Salfred goto detach; 1340184610Salfred } 1341184610Salfred#endif 1342307764Sgonzo 1343307775Sgonzo#ifdef EVDEV_SUPPORT 1344307764Sgonzo evdev = evdev_alloc(); 1345307764Sgonzo evdev_set_name(evdev, device_get_desc(dev)); 1346307764Sgonzo evdev_set_phys(evdev, device_get_nameunit(dev)); 1347307764Sgonzo evdev_set_id(evdev, BUS_USB, uaa->info.idVendor, 1348307764Sgonzo uaa->info.idProduct, 0); 1349307764Sgonzo evdev_set_serial(evdev, usb_get_serial(uaa->device)); 1350307764Sgonzo evdev_set_methods(evdev, kbd, &ukbd_evdev_methods); 1351307764Sgonzo evdev_support_event(evdev, EV_SYN); 1352307764Sgonzo evdev_support_event(evdev, EV_KEY); 1353307764Sgonzo if (sc->sc_flags & (UKBD_FLAG_NUMLOCK | UKBD_FLAG_CAPSLOCK | 1354307764Sgonzo UKBD_FLAG_SCROLLLOCK)) 1355307764Sgonzo evdev_support_event(evdev, EV_LED); 1356307764Sgonzo evdev_support_event(evdev, EV_REP); 1357307764Sgonzo 1358307764Sgonzo for (i = 0x00; i <= 0xFF; i++) 1359307764Sgonzo evdev_support_key(evdev, evdev_hid2key(i)); 1360307764Sgonzo if (sc->sc_flags & UKBD_FLAG_NUMLOCK) 1361307764Sgonzo evdev_support_led(evdev, LED_NUML); 1362307764Sgonzo if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) 1363307764Sgonzo evdev_support_led(evdev, LED_CAPSL); 1364307764Sgonzo if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) 1365307764Sgonzo evdev_support_led(evdev, LED_SCROLLL); 1366307764Sgonzo 1367307764Sgonzo if (evdev_register(evdev)) 1368307764Sgonzo evdev_free(evdev); 1369307764Sgonzo else 1370307764Sgonzo sc->sc_evdev = evdev; 1371307764Sgonzo#endif 1372307764Sgonzo 1373184610Salfred sc->sc_flags |= UKBD_FLAG_ATTACHED; 1374184610Salfred 1375184610Salfred if (bootverbose) { 1376356012Skevans kbdd_diag(kbd, bootverbose); 1377184610Salfred } 1378184610Salfred 1379253332Shselasky#ifdef USB_DEBUG 1380253332Shselasky /* check for polling rate override */ 1381253332Shselasky rate = ukbd_pollrate; 1382253332Shselasky if (rate > 0) { 1383253332Shselasky if (rate > 1000) 1384253332Shselasky rate = 1; 1385253332Shselasky else 1386253332Shselasky rate = 1000 / rate; 1387253332Shselasky 1388253332Shselasky /* set new polling interval in ms */ 1389305644Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_0], rate); 1390305644Shselasky usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_1], rate); 1391253332Shselasky } 1392253332Shselasky#endif 1393184610Salfred /* start the keyboard */ 1394305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]); 1395305644Shselasky usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]); 1396184610Salfred 1397184610Salfred return (0); /* success */ 1398184610Salfred 1399184610Salfreddetach: 1400184610Salfred ukbd_detach(dev); 1401184610Salfred return (ENXIO); /* error */ 1402184610Salfred} 1403184610Salfred 1404193315Sthompsastatic int 1405184610Salfredukbd_detach(device_t dev) 1406184610Salfred{ 1407184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1408184610Salfred int error; 1409184610Salfred 1410228765Savg UKBD_LOCK_ASSERT(); 1411228765Savg 1412184610Salfred DPRINTF("\n"); 1413184610Salfred 1414184610Salfred sc->sc_flags |= UKBD_FLAG_GONE; 1415184610Salfred 1416194228Sthompsa usb_callout_stop(&sc->sc_callout); 1417184610Salfred 1418261228Shselasky /* kill any stuck keys */ 1419261228Shselasky if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1420261228Shselasky /* stop receiving events from the USB keyboard */ 1421305644Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_0]); 1422305644Shselasky usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_1]); 1423261228Shselasky 1424261228Shselasky /* release all leftover keys, if any */ 1425261228Shselasky memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 1426261228Shselasky 1427261228Shselasky /* process releasing of all keys */ 1428261228Shselasky ukbd_interrupt(sc); 1429261228Shselasky } 1430261228Shselasky 1431184610Salfred ukbd_disable(&sc->sc_kbd); 1432184610Salfred 1433184610Salfred#ifdef KBD_INSTALL_CDEV 1434184610Salfred if (sc->sc_flags & UKBD_FLAG_ATTACHED) { 1435184610Salfred error = kbd_detach(&sc->sc_kbd); 1436184610Salfred if (error) { 1437184610Salfred /* usb attach cannot return an error */ 1438184610Salfred device_printf(dev, "WARNING: kbd_detach() " 1439184610Salfred "returned non-zero! (ignored)\n"); 1440184610Salfred } 1441184610Salfred } 1442184610Salfred#endif 1443307764Sgonzo 1444307775Sgonzo#ifdef EVDEV_SUPPORT 1445307764Sgonzo evdev_free(sc->sc_evdev); 1446307764Sgonzo#endif 1447307764Sgonzo 1448184610Salfred if (KBD_IS_CONFIGURED(&sc->sc_kbd)) { 1449184610Salfred error = kbd_unregister(&sc->sc_kbd); 1450184610Salfred if (error) { 1451184610Salfred /* usb attach cannot return an error */ 1452184610Salfred device_printf(dev, "WARNING: kbd_unregister() " 1453184610Salfred "returned non-zero! (ignored)\n"); 1454184610Salfred } 1455184610Salfred } 1456184610Salfred sc->sc_kbd.kb_flags = 0; 1457184610Salfred 1458194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); 1459184610Salfred 1460194228Sthompsa usb_callout_drain(&sc->sc_callout); 1461184610Salfred 1462184610Salfred DPRINTF("%s: disconnected\n", 1463184610Salfred device_get_nameunit(dev)); 1464184610Salfred 1465184610Salfred return (0); 1466184610Salfred} 1467184610Salfred 1468184610Salfredstatic int 1469184610Salfredukbd_resume(device_t dev) 1470184610Salfred{ 1471184610Salfred struct ukbd_softc *sc = device_get_softc(dev); 1472184610Salfred 1473228765Savg UKBD_LOCK_ASSERT(); 1474203896Sthompsa 1475184610Salfred ukbd_clear_state(&sc->sc_kbd); 1476184610Salfred 1477184610Salfred return (0); 1478184610Salfred} 1479184610Salfred 1480184610Salfred/* early keyboard probe, not supported */ 1481184610Salfredstatic int 1482184610Salfredukbd_configure(int flags) 1483184610Salfred{ 1484184610Salfred return (0); 1485184610Salfred} 1486184610Salfred 1487184610Salfred/* detect a keyboard, not used */ 1488184610Salfredstatic int 1489184610Salfredukbd__probe(int unit, void *arg, int flags) 1490184610Salfred{ 1491184610Salfred return (ENXIO); 1492184610Salfred} 1493184610Salfred 1494184610Salfred/* reset and initialize the device, not used */ 1495184610Salfredstatic int 1496184610Salfredukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 1497184610Salfred{ 1498184610Salfred return (ENXIO); 1499184610Salfred} 1500184610Salfred 1501184610Salfred/* test the interface to the device, not used */ 1502184610Salfredstatic int 1503184610Salfredukbd_test_if(keyboard_t *kbd) 1504184610Salfred{ 1505184610Salfred return (0); 1506184610Salfred} 1507184610Salfred 1508184610Salfred/* finish using this keyboard, not used */ 1509184610Salfredstatic int 1510184610Salfredukbd_term(keyboard_t *kbd) 1511184610Salfred{ 1512184610Salfred return (ENXIO); 1513184610Salfred} 1514184610Salfred 1515184610Salfred/* keyboard interrupt routine, not used */ 1516184610Salfredstatic int 1517184610Salfredukbd_intr(keyboard_t *kbd, void *arg) 1518184610Salfred{ 1519184610Salfred return (0); 1520184610Salfred} 1521184610Salfred 1522184610Salfred/* lock the access to the keyboard, not used */ 1523184610Salfredstatic int 1524184610Salfredukbd_lock(keyboard_t *kbd, int lock) 1525184610Salfred{ 1526184610Salfred return (1); 1527184610Salfred} 1528184610Salfred 1529184610Salfred/* 1530184610Salfred * Enable the access to the device; until this function is called, 1531184610Salfred * the client cannot read from the keyboard. 1532184610Salfred */ 1533184610Salfredstatic int 1534184610Salfredukbd_enable(keyboard_t *kbd) 1535184610Salfred{ 1536228765Savg 1537228765Savg UKBD_LOCK(); 1538184610Salfred KBD_ACTIVATE(kbd); 1539228765Savg UKBD_UNLOCK(); 1540228765Savg 1541184610Salfred return (0); 1542184610Salfred} 1543184610Salfred 1544184610Salfred/* disallow the access to the device */ 1545184610Salfredstatic int 1546184610Salfredukbd_disable(keyboard_t *kbd) 1547184610Salfred{ 1548228765Savg 1549228765Savg UKBD_LOCK(); 1550184610Salfred KBD_DEACTIVATE(kbd); 1551228765Savg UKBD_UNLOCK(); 1552228765Savg 1553184610Salfred return (0); 1554184610Salfred} 1555184610Salfred 1556184610Salfred/* check if data is waiting */ 1557228765Savg/* Currently unused. */ 1558184610Salfredstatic int 1559184610Salfredukbd_check(keyboard_t *kbd) 1560184610Salfred{ 1561184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1562184610Salfred 1563228765Savg UKBD_CTX_LOCK_ASSERT(); 1564228765Savg 1565195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1566195960Salfred return (0); 1567195960Salfred 1568203896Sthompsa if (sc->sc_flags & UKBD_FLAG_POLLING) 1569203896Sthompsa ukbd_do_poll(sc, 0); 1570203896Sthompsa 1571184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1572184610Salfred if (sc->sc_buffered_char[0]) { 1573184610Salfred return (1); 1574184610Salfred } 1575184610Salfred#endif 1576184610Salfred if (sc->sc_inputs > 0) { 1577184610Salfred return (1); 1578184610Salfred } 1579184610Salfred return (0); 1580184610Salfred} 1581184610Salfred 1582184610Salfred/* check if char is waiting */ 1583184610Salfredstatic int 1584228765Savgukbd_check_char_locked(keyboard_t *kbd) 1585184610Salfred{ 1586184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1587184610Salfred 1588228765Savg UKBD_CTX_LOCK_ASSERT(); 1589228765Savg 1590195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1591195960Salfred return (0); 1592195960Salfred 1593184610Salfred if ((sc->sc_composed_char > 0) && 1594184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1595184610Salfred return (1); 1596184610Salfred } 1597184610Salfred return (ukbd_check(kbd)); 1598184610Salfred} 1599184610Salfred 1600228765Savgstatic int 1601228765Savgukbd_check_char(keyboard_t *kbd) 1602228765Savg{ 1603228765Savg int result; 1604184610Salfred 1605228765Savg UKBD_LOCK(); 1606228765Savg result = ukbd_check_char_locked(kbd); 1607228765Savg UKBD_UNLOCK(); 1608228765Savg 1609228765Savg return (result); 1610228765Savg} 1611228765Savg 1612184610Salfred/* read one byte from the keyboard if it's allowed */ 1613228765Savg/* Currently unused. */ 1614184610Salfredstatic int 1615184610Salfredukbd_read(keyboard_t *kbd, int wait) 1616184610Salfred{ 1617184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1618184610Salfred int32_t usbcode; 1619184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1620184610Salfred uint32_t keycode; 1621184610Salfred uint32_t scancode; 1622184610Salfred 1623184610Salfred#endif 1624184610Salfred 1625228765Savg UKBD_CTX_LOCK_ASSERT(); 1626184610Salfred 1627228765Savg if (!KBD_IS_ACTIVE(kbd)) 1628203896Sthompsa return (-1); 1629203896Sthompsa 1630184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1631184610Salfred if (sc->sc_buffered_char[0]) { 1632184610Salfred scancode = sc->sc_buffered_char[0]; 1633184610Salfred if (scancode & SCAN_PREFIX) { 1634184610Salfred sc->sc_buffered_char[0] &= ~SCAN_PREFIX; 1635184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1636184610Salfred } 1637184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1638184610Salfred sc->sc_buffered_char[1] = 0; 1639184610Salfred return (scancode); 1640184610Salfred } 1641184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1642184610Salfred 1643184610Salfred /* XXX */ 1644184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1645195960Salfred if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) 1646195960Salfred return (-1); 1647195960Salfred 1648184610Salfred ++(kbd->kb_count); 1649184610Salfred 1650184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1651358213Shselasky keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.modifiers); 1652184610Salfred if (keycode == NN) { 1653184610Salfred return -1; 1654184610Salfred } 1655184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1656184610Salfred (usbcode & KEY_RELEASE))); 1657184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1658184610Salfred return (usbcode); 1659184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1660184610Salfred} 1661184610Salfred 1662184610Salfred/* read char from the keyboard */ 1663184610Salfredstatic uint32_t 1664228765Savgukbd_read_char_locked(keyboard_t *kbd, int wait) 1665184610Salfred{ 1666184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1667184610Salfred uint32_t action; 1668184610Salfred uint32_t keycode; 1669184610Salfred int32_t usbcode; 1670184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1671184610Salfred uint32_t scancode; 1672184610Salfred#endif 1673195960Salfred 1674228765Savg UKBD_CTX_LOCK_ASSERT(); 1675228765Savg 1676195960Salfred if (!KBD_IS_ACTIVE(kbd)) 1677195960Salfred return (NOKEY); 1678195960Salfred 1679184610Salfrednext_code: 1680184610Salfred 1681184610Salfred /* do we have a composed char to return ? */ 1682184610Salfred 1683184610Salfred if ((sc->sc_composed_char > 0) && 1684184610Salfred (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { 1685184610Salfred 1686184610Salfred action = sc->sc_composed_char; 1687184610Salfred sc->sc_composed_char = 0; 1688184610Salfred 1689184610Salfred if (action > 0xFF) { 1690184610Salfred goto errkey; 1691184610Salfred } 1692184610Salfred goto done; 1693184610Salfred } 1694184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1695184610Salfred 1696184610Salfred /* do we have a pending raw scan code? */ 1697184610Salfred 1698184610Salfred if (sc->sc_mode == K_RAW) { 1699184610Salfred scancode = sc->sc_buffered_char[0]; 1700184610Salfred if (scancode) { 1701184610Salfred if (scancode & SCAN_PREFIX) { 1702184610Salfred sc->sc_buffered_char[0] = (scancode & ~SCAN_PREFIX); 1703184610Salfred return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 1704184610Salfred } 1705184610Salfred sc->sc_buffered_char[0] = sc->sc_buffered_char[1]; 1706184610Salfred sc->sc_buffered_char[1] = 0; 1707184610Salfred return (scancode); 1708184610Salfred } 1709184610Salfred } 1710184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1711184610Salfred 1712184610Salfred /* see if there is something in the keyboard port */ 1713184610Salfred /* XXX */ 1714184610Salfred usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1); 1715184610Salfred if (usbcode == -1) { 1716184610Salfred return (NOKEY); 1717184610Salfred } 1718184610Salfred ++kbd->kb_count; 1719184610Salfred 1720184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 1721184610Salfred /* USB key index -> key code -> AT scan code */ 1722358213Shselasky keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.modifiers); 1723184610Salfred if (keycode == NN) { 1724184610Salfred return (NOKEY); 1725184610Salfred } 1726184610Salfred /* return an AT scan code for the K_RAW mode */ 1727184610Salfred if (sc->sc_mode == K_RAW) { 1728184610Salfred return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers, 1729184610Salfred (usbcode & KEY_RELEASE))); 1730184610Salfred } 1731184610Salfred#else /* !UKBD_EMULATE_ATSCANCODE */ 1732184610Salfred 1733184610Salfred /* return the byte as is for the K_RAW mode */ 1734184610Salfred if (sc->sc_mode == K_RAW) { 1735184610Salfred return (usbcode); 1736184610Salfred } 1737184610Salfred /* USB key index -> key code */ 1738184610Salfred keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 1739184610Salfred if (keycode == NN) { 1740184610Salfred return (NOKEY); 1741184610Salfred } 1742184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 1743184610Salfred 1744184610Salfred switch (keycode) { 1745184610Salfred case 0x38: /* left alt (compose key) */ 1746184610Salfred if (usbcode & KEY_RELEASE) { 1747184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1748184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1749184610Salfred 1750184610Salfred if (sc->sc_composed_char > 0xFF) { 1751184610Salfred sc->sc_composed_char = 0; 1752184610Salfred } 1753184610Salfred } 1754184610Salfred } else { 1755184610Salfred if (!(sc->sc_flags & UKBD_FLAG_COMPOSE)) { 1756184610Salfred sc->sc_flags |= UKBD_FLAG_COMPOSE; 1757184610Salfred sc->sc_composed_char = 0; 1758184610Salfred } 1759184610Salfred } 1760184610Salfred break; 1761184610Salfred } 1762184610Salfred 1763184610Salfred /* return the key code in the K_CODE mode */ 1764184610Salfred if (usbcode & KEY_RELEASE) { 1765184610Salfred keycode |= SCAN_RELEASE; 1766184610Salfred } 1767184610Salfred if (sc->sc_mode == K_CODE) { 1768184610Salfred return (keycode); 1769184610Salfred } 1770184610Salfred /* compose a character code */ 1771184610Salfred if (sc->sc_flags & UKBD_FLAG_COMPOSE) { 1772184610Salfred switch (keycode) { 1773184610Salfred /* key pressed, process it */ 1774184610Salfred case 0x47: 1775184610Salfred case 0x48: 1776184610Salfred case 0x49: /* keypad 7,8,9 */ 1777184610Salfred sc->sc_composed_char *= 10; 1778184610Salfred sc->sc_composed_char += keycode - 0x40; 1779184610Salfred goto check_composed; 1780184610Salfred 1781184610Salfred case 0x4B: 1782184610Salfred case 0x4C: 1783184610Salfred case 0x4D: /* keypad 4,5,6 */ 1784184610Salfred sc->sc_composed_char *= 10; 1785184610Salfred sc->sc_composed_char += keycode - 0x47; 1786184610Salfred goto check_composed; 1787184610Salfred 1788184610Salfred case 0x4F: 1789184610Salfred case 0x50: 1790184610Salfred case 0x51: /* keypad 1,2,3 */ 1791184610Salfred sc->sc_composed_char *= 10; 1792184610Salfred sc->sc_composed_char += keycode - 0x4E; 1793184610Salfred goto check_composed; 1794184610Salfred 1795184610Salfred case 0x52: /* keypad 0 */ 1796184610Salfred sc->sc_composed_char *= 10; 1797184610Salfred goto check_composed; 1798184610Salfred 1799184610Salfred /* key released, no interest here */ 1800184610Salfred case SCAN_RELEASE | 0x47: 1801184610Salfred case SCAN_RELEASE | 0x48: 1802184610Salfred case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ 1803184610Salfred case SCAN_RELEASE | 0x4B: 1804184610Salfred case SCAN_RELEASE | 0x4C: 1805184610Salfred case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ 1806184610Salfred case SCAN_RELEASE | 0x4F: 1807184610Salfred case SCAN_RELEASE | 0x50: 1808184610Salfred case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ 1809184610Salfred case SCAN_RELEASE | 0x52: /* keypad 0 */ 1810184610Salfred goto next_code; 1811184610Salfred 1812184610Salfred case 0x38: /* left alt key */ 1813184610Salfred break; 1814184610Salfred 1815184610Salfred default: 1816184610Salfred if (sc->sc_composed_char > 0) { 1817184610Salfred sc->sc_flags &= ~UKBD_FLAG_COMPOSE; 1818184610Salfred sc->sc_composed_char = 0; 1819184610Salfred goto errkey; 1820184610Salfred } 1821184610Salfred break; 1822184610Salfred } 1823184610Salfred } 1824184610Salfred /* keycode to key action */ 1825184610Salfred action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), 1826184610Salfred (keycode & SCAN_RELEASE), 1827184610Salfred &sc->sc_state, &sc->sc_accents); 1828184610Salfred if (action == NOKEY) { 1829184610Salfred goto next_code; 1830184610Salfred } 1831184610Salfreddone: 1832184610Salfred return (action); 1833184610Salfred 1834184610Salfredcheck_composed: 1835184610Salfred if (sc->sc_composed_char <= 0xFF) { 1836184610Salfred goto next_code; 1837184610Salfred } 1838184610Salfrederrkey: 1839184610Salfred return (ERRKEY); 1840184610Salfred} 1841184610Salfred 1842228765Savg/* Currently wait is always false. */ 1843228765Savgstatic uint32_t 1844228765Savgukbd_read_char(keyboard_t *kbd, int wait) 1845228765Savg{ 1846228765Savg uint32_t keycode; 1847228765Savg 1848228765Savg UKBD_LOCK(); 1849228765Savg keycode = ukbd_read_char_locked(kbd, wait); 1850228765Savg UKBD_UNLOCK(); 1851228765Savg 1852228765Savg return (keycode); 1853228765Savg} 1854228765Savg 1855184610Salfred/* some useful control functions */ 1856184610Salfredstatic int 1857228765Savgukbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg) 1858184610Salfred{ 1859184610Salfred struct ukbd_softc *sc = kbd->kb_data; 1860184610Salfred int i; 1861184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1862184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1863184610Salfred int ival; 1864184610Salfred 1865184610Salfred#endif 1866184610Salfred 1867228765Savg UKBD_LOCK_ASSERT(); 1868228765Savg 1869184610Salfred switch (cmd) { 1870184610Salfred case KDGKBMODE: /* get keyboard mode */ 1871184610Salfred *(int *)arg = sc->sc_mode; 1872184610Salfred break; 1873184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1874184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1875184610Salfred case _IO('K', 7): 1876184610Salfred ival = IOCPARM_IVAL(arg); 1877184610Salfred arg = (caddr_t)&ival; 1878184610Salfred /* FALLTHROUGH */ 1879184610Salfred#endif 1880184610Salfred case KDSKBMODE: /* set keyboard mode */ 1881184610Salfred switch (*(int *)arg) { 1882184610Salfred case K_XLATE: 1883184610Salfred if (sc->sc_mode != K_XLATE) { 1884184610Salfred /* make lock key state and LED state match */ 1885184610Salfred sc->sc_state &= ~LOCK_MASK; 1886184610Salfred sc->sc_state |= KBD_LED_VAL(kbd); 1887184610Salfred } 1888184610Salfred /* FALLTHROUGH */ 1889184610Salfred case K_RAW: 1890184610Salfred case K_CODE: 1891184610Salfred if (sc->sc_mode != *(int *)arg) { 1892228765Savg if ((sc->sc_flags & UKBD_FLAG_POLLING) == 0) 1893203896Sthompsa ukbd_clear_state(kbd); 1894184610Salfred sc->sc_mode = *(int *)arg; 1895184610Salfred } 1896184610Salfred break; 1897184610Salfred default: 1898184610Salfred return (EINVAL); 1899184610Salfred } 1900184610Salfred break; 1901184610Salfred 1902184610Salfred case KDGETLED: /* get keyboard LED */ 1903184610Salfred *(int *)arg = KBD_LED_VAL(kbd); 1904184610Salfred break; 1905184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1906184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1907184610Salfred case _IO('K', 66): 1908184610Salfred ival = IOCPARM_IVAL(arg); 1909184610Salfred arg = (caddr_t)&ival; 1910184610Salfred /* FALLTHROUGH */ 1911184610Salfred#endif 1912184610Salfred case KDSETLED: /* set keyboard LED */ 1913184610Salfred /* NOTE: lock key state in "sc_state" won't be changed */ 1914223755Shselasky if (*(int *)arg & ~LOCK_MASK) 1915184610Salfred return (EINVAL); 1916223755Shselasky 1917184610Salfred i = *(int *)arg; 1918223755Shselasky 1919184610Salfred /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1920184610Salfred if (sc->sc_mode == K_XLATE && 1921184610Salfred kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1922184610Salfred if (i & ALKED) 1923184610Salfred i |= CLKED; 1924184610Salfred else 1925184610Salfred i &= ~CLKED; 1926184610Salfred } 1927223755Shselasky if (KBD_HAS_DEVICE(kbd)) 1928223755Shselasky ukbd_set_leds(sc, i); 1929223755Shselasky 1930184610Salfred KBD_LED_VAL(kbd) = *(int *)arg; 1931184610Salfred break; 1932184610Salfred case KDGKBSTATE: /* get lock key state */ 1933184610Salfred *(int *)arg = sc->sc_state & LOCK_MASK; 1934184610Salfred break; 1935184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1936184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1937184610Salfred case _IO('K', 20): 1938184610Salfred ival = IOCPARM_IVAL(arg); 1939184610Salfred arg = (caddr_t)&ival; 1940184610Salfred /* FALLTHROUGH */ 1941184610Salfred#endif 1942184610Salfred case KDSKBSTATE: /* set lock key state */ 1943184610Salfred if (*(int *)arg & ~LOCK_MASK) { 1944184610Salfred return (EINVAL); 1945184610Salfred } 1946184610Salfred sc->sc_state &= ~LOCK_MASK; 1947184610Salfred sc->sc_state |= *(int *)arg; 1948184610Salfred 1949184610Salfred /* set LEDs and quit */ 1950184610Salfred return (ukbd_ioctl(kbd, KDSETLED, arg)); 1951184610Salfred 1952184610Salfred case KDSETREPEAT: /* set keyboard repeat rate (new 1953184610Salfred * interface) */ 1954184610Salfred if (!KBD_HAS_DEVICE(kbd)) { 1955184610Salfred return (0); 1956184610Salfred } 1957184610Salfred if (((int *)arg)[1] < 0) { 1958184610Salfred return (EINVAL); 1959184610Salfred } 1960184610Salfred if (((int *)arg)[0] < 0) { 1961184610Salfred return (EINVAL); 1962184610Salfred } 1963184610Salfred if (((int *)arg)[0] < 200) /* fastest possible value */ 1964184610Salfred kbd->kb_delay1 = 200; 1965184610Salfred else 1966184610Salfred kbd->kb_delay1 = ((int *)arg)[0]; 1967184610Salfred kbd->kb_delay2 = ((int *)arg)[1]; 1968307775Sgonzo#ifdef EVDEV_SUPPORT 1969307764Sgonzo if (sc->sc_evdev != NULL) 1970307764Sgonzo evdev_push_repeats(sc->sc_evdev, kbd); 1971307764Sgonzo#endif 1972184610Salfred return (0); 1973184610Salfred 1974184610Salfred#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1975184610Salfred defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1976184610Salfred case _IO('K', 67): 1977184610Salfred ival = IOCPARM_IVAL(arg); 1978184610Salfred arg = (caddr_t)&ival; 1979184610Salfred /* FALLTHROUGH */ 1980184610Salfred#endif 1981184610Salfred case KDSETRAD: /* set keyboard repeat rate (old 1982184610Salfred * interface) */ 1983184610Salfred return (ukbd_set_typematic(kbd, *(int *)arg)); 1984184610Salfred 1985184610Salfred case PIO_KEYMAP: /* set keyboard translation table */ 1986224126Sed case OPIO_KEYMAP: /* set keyboard translation table 1987224126Sed * (compat) */ 1988184610Salfred case PIO_KEYMAPENT: /* set keyboard translation table 1989184610Salfred * entry */ 1990184610Salfred case PIO_DEADKEYMAP: /* set accent key translation table */ 1991184610Salfred sc->sc_accents = 0; 1992184610Salfred /* FALLTHROUGH */ 1993184610Salfred default: 1994184610Salfred return (genkbd_commonioctl(kbd, cmd, arg)); 1995184610Salfred } 1996184610Salfred 1997184610Salfred return (0); 1998184610Salfred} 1999184610Salfred 2000228765Savgstatic int 2001228765Savgukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 2002228765Savg{ 2003228765Savg int result; 2004228765Savg 2005228765Savg /* 2006263262Shselasky * XXX Check if someone is calling us from a critical section: 2007262972Shselasky */ 2008262972Shselasky if (curthread->td_critnest != 0) 2009262972Shselasky return (EDEADLK); 2010262972Shselasky 2011262972Shselasky /* 2012228765Savg * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any 2013228765Savg * context where printf(9) can be called, which among other things 2014228765Savg * includes interrupt filters and threads with any kinds of locks 2015228765Savg * already held. For this reason it would be dangerous to acquire 2016228765Savg * the Giant here unconditionally. On the other hand we have to 2017228765Savg * have it to handle the ioctl. 2018228765Savg * So we make our best effort to auto-detect whether we can grab 2019228765Savg * the Giant or not. Blame syscons(4) for this. 2020228765Savg */ 2021228765Savg switch (cmd) { 2022228765Savg case KDGKBSTATE: 2023228765Savg case KDSKBSTATE: 2024228765Savg case KDSETLED: 2025228765Savg if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED()) 2026228765Savg return (EDEADLK); /* best I could come up with */ 2027228765Savg /* FALLTHROUGH */ 2028228765Savg default: 2029228765Savg UKBD_LOCK(); 2030228765Savg result = ukbd_ioctl_locked(kbd, cmd, arg); 2031228765Savg UKBD_UNLOCK(); 2032228765Savg return (result); 2033228765Savg } 2034228765Savg} 2035228765Savg 2036228765Savg 2037184610Salfred/* clear the internal state of the keyboard */ 2038184610Salfredstatic void 2039184610Salfredukbd_clear_state(keyboard_t *kbd) 2040184610Salfred{ 2041184610Salfred struct ukbd_softc *sc = kbd->kb_data; 2042184610Salfred 2043228765Savg UKBD_CTX_LOCK_ASSERT(); 2044184610Salfred 2045184610Salfred sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); 2046184610Salfred sc->sc_state &= LOCK_MASK; /* preserve locking key state */ 2047184610Salfred sc->sc_accents = 0; 2048184610Salfred sc->sc_composed_char = 0; 2049184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 2050184610Salfred sc->sc_buffered_char[0] = 0; 2051184610Salfred sc->sc_buffered_char[1] = 0; 2052184610Salfred#endif 2053203896Sthompsa memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); 2054203896Sthompsa memset(&sc->sc_odata, 0, sizeof(sc->sc_odata)); 2055203896Sthompsa memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime)); 2056203896Sthompsa memset(&sc->sc_otime, 0, sizeof(sc->sc_otime)); 2057184610Salfred} 2058184610Salfred 2059184610Salfred/* save the internal state, not used */ 2060184610Salfredstatic int 2061184610Salfredukbd_get_state(keyboard_t *kbd, void *buf, size_t len) 2062184610Salfred{ 2063184610Salfred return (len == 0) ? 1 : -1; 2064184610Salfred} 2065184610Salfred 2066184610Salfred/* set the internal state, not used */ 2067184610Salfredstatic int 2068184610Salfredukbd_set_state(keyboard_t *kbd, void *buf, size_t len) 2069184610Salfred{ 2070184610Salfred return (EINVAL); 2071184610Salfred} 2072184610Salfred 2073184610Salfredstatic int 2074184610Salfredukbd_poll(keyboard_t *kbd, int on) 2075184610Salfred{ 2076184610Salfred struct ukbd_softc *sc = kbd->kb_data; 2077184610Salfred 2078228765Savg UKBD_LOCK(); 2079304124Shselasky /* 2080304124Shselasky * Keep a reference count on polling to allow recursive 2081304124Shselasky * cngrab() during a panic for example. 2082304124Shselasky */ 2083304124Shselasky if (on) 2084304124Shselasky sc->sc_polling++; 2085305644Shselasky else if (sc->sc_polling > 0) 2086304124Shselasky sc->sc_polling--; 2087304124Shselasky 2088304124Shselasky if (sc->sc_polling != 0) { 2089184610Salfred sc->sc_flags |= UKBD_FLAG_POLLING; 2090203896Sthompsa sc->sc_poll_thread = curthread; 2091184610Salfred } else { 2092184610Salfred sc->sc_flags &= ~UKBD_FLAG_POLLING; 2093203896Sthompsa ukbd_start_timer(sc); /* start timer */ 2094184610Salfred } 2095228765Savg UKBD_UNLOCK(); 2096228765Savg 2097184610Salfred return (0); 2098184610Salfred} 2099184610Salfred 2100184610Salfred/* local functions */ 2101184610Salfred 2102184610Salfredstatic void 2103184610Salfredukbd_set_leds(struct ukbd_softc *sc, uint8_t leds) 2104184610Salfred{ 2105228765Savg 2106228765Savg UKBD_LOCK_ASSERT(); 2107184610Salfred DPRINTF("leds=0x%02x\n", leds); 2108184610Salfred 2109184610Salfred sc->sc_leds = leds; 2110184610Salfred sc->sc_flags |= UKBD_FLAG_SET_LEDS; 2111184610Salfred 2112184610Salfred /* start transfer, if not already started */ 2113184610Salfred 2114194228Sthompsa usbd_transfer_start(sc->sc_xfer[UKBD_CTRL_LED]); 2115184610Salfred} 2116184610Salfred 2117184610Salfredstatic int 2118184610Salfredukbd_set_typematic(keyboard_t *kbd, int code) 2119184610Salfred{ 2120307775Sgonzo#ifdef EVDEV_SUPPORT 2121307764Sgonzo struct ukbd_softc *sc = kbd->kb_data; 2122307764Sgonzo#endif 2123184610Salfred static const int delays[] = {250, 500, 750, 1000}; 2124184610Salfred static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63, 2125184610Salfred 68, 76, 84, 92, 100, 110, 118, 126, 2126184610Salfred 136, 152, 168, 184, 200, 220, 236, 252, 2127184610Salfred 272, 304, 336, 368, 400, 440, 472, 504}; 2128184610Salfred 2129184610Salfred if (code & ~0x7f) { 2130184610Salfred return (EINVAL); 2131184610Salfred } 2132184610Salfred kbd->kb_delay1 = delays[(code >> 5) & 3]; 2133184610Salfred kbd->kb_delay2 = rates[code & 0x1f]; 2134307775Sgonzo#ifdef EVDEV_SUPPORT 2135307764Sgonzo if (sc->sc_evdev != NULL) 2136307764Sgonzo evdev_push_repeats(sc->sc_evdev, kbd); 2137307764Sgonzo#endif 2138184610Salfred return (0); 2139184610Salfred} 2140184610Salfred 2141184610Salfred#ifdef UKBD_EMULATE_ATSCANCODE 2142358213Shselaskystatic uint32_t 2143358213Shselaskyukbd_atkeycode(int usbcode, int shift) 2144358213Shselasky{ 2145358213Shselasky uint32_t keycode; 2146358213Shselasky 2147358213Shselasky keycode = ukbd_trtab[KEY_INDEX(usbcode)]; 2148358213Shselasky /* 2149358213Shselasky * Translate Alt-PrintScreen to SysRq. 2150358213Shselasky * 2151358213Shselasky * Some or all AT keyboards connected through USB have already 2152358213Shselasky * mapped Alted PrintScreens to an unusual usbcode (0x8a). 2153358213Shselasky * ukbd_trtab translates this to 0x7e, and key2scan() would 2154358213Shselasky * translate that to 0x79 (Intl' 4). Assume that if we have 2155358213Shselasky * an Alted 0x7e here then it actually is an Alted PrintScreen. 2156358213Shselasky * 2157358213Shselasky * The usual usbcode for all PrintScreens is 0x46. ukbd_trtab 2158358213Shselasky * translates this to 0x5c, so the Alt check to classify 0x5c 2159358213Shselasky * is routine. 2160358213Shselasky */ 2161358213Shselasky if ((keycode == 0x5c || keycode == 0x7e) && 2162358213Shselasky shift & (MOD_ALT_L | MOD_ALT_R)) 2163358213Shselasky return (0x54); 2164358213Shselasky return (keycode); 2165358213Shselasky} 2166358213Shselasky 2167184610Salfredstatic int 2168184610Salfredukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up) 2169184610Salfred{ 2170184610Salfred static const int scan[] = { 2171197999Shrs /* 89 */ 2172197999Shrs 0x11c, /* Enter */ 2173197999Shrs /* 90-99 */ 2174197999Shrs 0x11d, /* Ctrl-R */ 2175197999Shrs 0x135, /* Divide */ 2176358212Shselasky 0x137, /* PrintScreen */ 2177197999Shrs 0x138, /* Alt-R */ 2178197999Shrs 0x147, /* Home */ 2179197999Shrs 0x148, /* Up */ 2180197999Shrs 0x149, /* PageUp */ 2181197999Shrs 0x14b, /* Left */ 2182197999Shrs 0x14d, /* Right */ 2183197999Shrs 0x14f, /* End */ 2184197999Shrs /* 100-109 */ 2185197999Shrs 0x150, /* Down */ 2186197999Shrs 0x151, /* PageDown */ 2187197999Shrs 0x152, /* Insert */ 2188197999Shrs 0x153, /* Delete */ 2189358213Shselasky 0x146, /* Pause/Break */ 2190197999Shrs 0x15b, /* Win_L(Super_L) */ 2191197999Shrs 0x15c, /* Win_R(Super_R) */ 2192197999Shrs 0x15d, /* Application(Menu) */ 2193197999Shrs 2194184610Salfred /* SUN TYPE 6 USB KEYBOARD */ 2195197999Shrs 0x168, /* Sun Type 6 Help */ 2196197999Shrs 0x15e, /* Sun Type 6 Stop */ 2197197999Shrs /* 110 - 119 */ 2198197999Shrs 0x15f, /* Sun Type 6 Again */ 2199197999Shrs 0x160, /* Sun Type 6 Props */ 2200197999Shrs 0x161, /* Sun Type 6 Undo */ 2201197999Shrs 0x162, /* Sun Type 6 Front */ 2202197999Shrs 0x163, /* Sun Type 6 Copy */ 2203197999Shrs 0x164, /* Sun Type 6 Open */ 2204197999Shrs 0x165, /* Sun Type 6 Paste */ 2205197999Shrs 0x166, /* Sun Type 6 Find */ 2206197999Shrs 0x167, /* Sun Type 6 Cut */ 2207197999Shrs 0x125, /* Sun Type 6 Mute */ 2208291146Shselasky /* 120 - 130 */ 2209197999Shrs 0x11f, /* Sun Type 6 VolumeDown */ 2210197999Shrs 0x11e, /* Sun Type 6 VolumeUp */ 2211197999Shrs 0x120, /* Sun Type 6 PowerDown */ 2212197999Shrs 2213197999Shrs /* Japanese 106/109 keyboard */ 2214197999Shrs 0x73, /* Keyboard Intl' 1 (backslash / underscore) */ 2215197999Shrs 0x70, /* Keyboard Intl' 2 (Katakana / Hiragana) */ 2216197999Shrs 0x7d, /* Keyboard Intl' 3 (Yen sign) (Not using in jp106/109) */ 2217197999Shrs 0x79, /* Keyboard Intl' 4 (Henkan) */ 2218197999Shrs 0x7b, /* Keyboard Intl' 5 (Muhenkan) */ 2219197999Shrs 0x5c, /* Keyboard Intl' 6 (Keypad ,) (For PC-9821 layout) */ 2220291146Shselasky 0x71, /* Apple Keyboard JIS (Kana) */ 2221291146Shselasky 0x72, /* Apple Keyboard JIS (Eisu) */ 2222184610Salfred }; 2223184610Salfred 2224298300Spfg if ((code >= 89) && (code < (int)(89 + nitems(scan)))) { 2225197999Shrs code = scan[code - 89]; 2226184610Salfred } 2227358212Shselasky /* PrintScreen */ 2228358212Shselasky if (code == 0x137 && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R | 2229358213Shselasky MOD_SHIFT_L | MOD_SHIFT_R)))) { 2230358212Shselasky code |= SCAN_PREFIX_SHIFT; 2231358212Shselasky } 2232184610Salfred /* Pause/Break */ 2233358212Shselasky if ((code == 0x146) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) { 2234184610Salfred code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL); 2235184610Salfred } 2236184610Salfred code |= (up ? SCAN_RELEASE : SCAN_PRESS); 2237184610Salfred 2238184610Salfred if (code & SCAN_PREFIX) { 2239184610Salfred if (code & SCAN_PREFIX_CTL) { 2240184610Salfred /* Ctrl */ 2241184610Salfred sc->sc_buffered_char[0] = (0x1d | (code & SCAN_RELEASE)); 2242184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX); 2243184610Salfred } else if (code & SCAN_PREFIX_SHIFT) { 2244184610Salfred /* Shift */ 2245184610Salfred sc->sc_buffered_char[0] = (0x2a | (code & SCAN_RELEASE)); 2246184610Salfred sc->sc_buffered_char[1] = (code & ~SCAN_PREFIX_SHIFT); 2247184610Salfred } else { 2248184610Salfred sc->sc_buffered_char[0] = (code & ~SCAN_PREFIX); 2249184610Salfred sc->sc_buffered_char[1] = 0; 2250184610Salfred } 2251184610Salfred return ((code & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); 2252184610Salfred } 2253184610Salfred return (code); 2254184610Salfred 2255184610Salfred} 2256184610Salfred 2257184610Salfred#endif /* UKBD_EMULATE_ATSCANCODE */ 2258184610Salfred 2259194099Sthompsastatic keyboard_switch_t ukbdsw = { 2260184610Salfred .probe = &ukbd__probe, 2261184610Salfred .init = &ukbd_init, 2262184610Salfred .term = &ukbd_term, 2263184610Salfred .intr = &ukbd_intr, 2264184610Salfred .test_if = &ukbd_test_if, 2265184610Salfred .enable = &ukbd_enable, 2266184610Salfred .disable = &ukbd_disable, 2267184610Salfred .read = &ukbd_read, 2268184610Salfred .check = &ukbd_check, 2269184610Salfred .read_char = &ukbd_read_char, 2270184610Salfred .check_char = &ukbd_check_char, 2271184610Salfred .ioctl = &ukbd_ioctl, 2272184610Salfred .lock = &ukbd_lock, 2273184610Salfred .clear_state = &ukbd_clear_state, 2274184610Salfred .get_state = &ukbd_get_state, 2275184610Salfred .set_state = &ukbd_set_state, 2276184610Salfred .poll = &ukbd_poll, 2277184610Salfred}; 2278184610Salfred 2279184610SalfredKEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); 2280184610Salfred 2281184610Salfredstatic int 2282184610Salfredukbd_driver_load(module_t mod, int what, void *arg) 2283184610Salfred{ 2284184610Salfred switch (what) { 2285193315Sthompsa case MOD_LOAD: 2286184610Salfred kbd_add_driver(&ukbd_kbd_driver); 2287184610Salfred break; 2288184610Salfred case MOD_UNLOAD: 2289184610Salfred kbd_delete_driver(&ukbd_kbd_driver); 2290184610Salfred break; 2291184610Salfred } 2292184610Salfred return (0); 2293184610Salfred} 2294184610Salfred 2295184610Salfredstatic devclass_t ukbd_devclass; 2296184610Salfred 2297184610Salfredstatic device_method_t ukbd_methods[] = { 2298184610Salfred DEVMETHOD(device_probe, ukbd_probe), 2299184610Salfred DEVMETHOD(device_attach, ukbd_attach), 2300184610Salfred DEVMETHOD(device_detach, ukbd_detach), 2301184610Salfred DEVMETHOD(device_resume, ukbd_resume), 2302246128Ssbz 2303246128Ssbz DEVMETHOD_END 2304184610Salfred}; 2305184610Salfred 2306184610Salfredstatic driver_t ukbd_driver = { 2307184610Salfred .name = "ukbd", 2308184610Salfred .methods = ukbd_methods, 2309184610Salfred .size = sizeof(struct ukbd_softc), 2310184610Salfred}; 2311184610Salfred 2312189275SthompsaDRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); 2313188942SthompsaMODULE_DEPEND(ukbd, usb, 1, 1, 1); 2314307775Sgonzo#ifdef EVDEV_SUPPORT 2315307775SgonzoMODULE_DEPEND(ukbd, evdev, 1, 1, 1); 2316307775Sgonzo#endif 2317212122SthompsaMODULE_VERSION(ukbd, 1); 2318292080SimpUSB_PNP_HOST_INFO(ukbd_devs); 2319