Home | History | Annotate | Line # | Download | only in usb
ukbd.c revision 1.145
      1  1.145  christos /*      $NetBSD: ukbd.c,v 1.145 2020/03/14 02:35:33 christos Exp $        */
      2    1.1  augustss 
      3    1.1  augustss /*
      4    1.1  augustss  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5    1.1  augustss  * All rights reserved.
      6    1.1  augustss  *
      7   1.11  augustss  * This code is derived from software contributed to The NetBSD Foundation
      8   1.59  augustss  * by Lennart Augustsson (lennart (at) augustsson.net) at
      9   1.11  augustss  * Carlstedt Research & Technology.
     10    1.1  augustss  *
     11    1.1  augustss  * Redistribution and use in source and binary forms, with or without
     12    1.1  augustss  * modification, are permitted provided that the following conditions
     13    1.1  augustss  * are met:
     14    1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     15    1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     16    1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     17    1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     18    1.1  augustss  *    documentation and/or other materials provided with the distribution.
     19    1.1  augustss  *
     20    1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21    1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22    1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23    1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24    1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25    1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26    1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27    1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28    1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29    1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30    1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     31    1.1  augustss  */
     32    1.1  augustss 
     33   1.17  augustss /*
     34   1.85  augustss  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
     35   1.17  augustss  */
     36   1.72     lukem 
     37   1.72     lukem #include <sys/cdefs.h>
     38  1.145  christos __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.145 2020/03/14 02:35:33 christos Exp $");
     39  1.125  christos 
     40  1.125  christos #ifdef _KERNEL_OPT
     41  1.134     skrll #include "opt_ddb.h"
     42  1.125  christos #include "opt_ukbd.h"
     43  1.125  christos #include "opt_ukbd_layout.h"
     44  1.132  jakllsch #include "opt_usb.h"
     45  1.125  christos #include "opt_wsdisplay_compat.h"
     46  1.125  christos #endif /* _KERNEL_OPT */
     47   1.17  augustss 
     48    1.1  augustss #include <sys/param.h>
     49    1.1  augustss #include <sys/systm.h>
     50   1.57   thorpej #include <sys/callout.h>
     51    1.1  augustss #include <sys/kernel.h>
     52    1.1  augustss #include <sys/device.h>
     53    1.1  augustss #include <sys/ioctl.h>
     54    1.1  augustss #include <sys/file.h>
     55    1.1  augustss #include <sys/select.h>
     56    1.1  augustss #include <sys/proc.h>
     57    1.1  augustss #include <sys/vnode.h>
     58    1.1  augustss #include <sys/poll.h>
     59    1.1  augustss 
     60    1.1  augustss #include <dev/usb/usb.h>
     61    1.2  augustss #include <dev/usb/usbhid.h>
     62   1.37  augustss 
     63    1.1  augustss #include <dev/usb/usbdi.h>
     64    1.1  augustss #include <dev/usb/usbdi_util.h>
     65  1.117       mrg #include <dev/usb/usbdivar.h>
     66    1.1  augustss #include <dev/usb/usbdevs.h>
     67    1.1  augustss #include <dev/usb/usb_quirks.h>
     68   1.75  augustss #include <dev/usb/uhidev.h>
     69   1.31   thorpej #include <dev/usb/ukbdvar.h>
     70  1.139    bouyer #include <dev/hid/hid.h>
     71    1.1  augustss 
     72    1.2  augustss #include <dev/wscons/wsconsio.h>
     73    1.2  augustss #include <dev/wscons/wskbdvar.h>
     74    1.2  augustss #include <dev/wscons/wsksymdef.h>
     75    1.2  augustss #include <dev/wscons/wsksymvar.h>
     76    1.2  augustss 
     77   1.62  augustss #ifdef UKBD_DEBUG
     78  1.108    dyoung #define DPRINTF(x)	if (ukbddebug) printf x
     79  1.108    dyoung #define DPRINTFN(n,x)	if (ukbddebug>(n)) printf x
     80    1.1  augustss int	ukbddebug = 0;
     81    1.1  augustss #else
     82    1.1  augustss #define DPRINTF(x)
     83    1.1  augustss #define DPRINTFN(n,x)
     84    1.1  augustss #endif
     85    1.1  augustss 
     86  1.138  jakllsch #define MAXKEYCODE 32
     87  1.138  jakllsch #define MAXKEYS 256
     88    1.2  augustss 
     89    1.1  augustss struct ukbd_data {
     90  1.138  jakllsch 	uint8_t		keys[MAXKEYS/NBBY];
     91    1.1  augustss };
     92    1.1  augustss 
     93   1.23  augustss #define PRESS    0x000
     94   1.23  augustss #define RELEASE  0x100
     95   1.23  augustss #define CODEMASK 0x0ff
     96    1.1  augustss 
     97  1.109       phx struct ukbd_keycodetrans {
     98  1.131     skrll 	uint16_t	from;
     99  1.131     skrll 	uint16_t	to;
    100  1.109       phx };
    101  1.109       phx 
    102  1.112  macallan #define IS_PMF	0x8000
    103  1.112  macallan 
    104  1.109       phx Static const struct ukbd_keycodetrans trtab_apple_fn[] = {
    105  1.109       phx 	{ 0x0c, 0x5d },	/* i -> KP 5 */
    106  1.109       phx 	{ 0x0d, 0x59 },	/* j -> KP 1 */
    107  1.109       phx 	{ 0x0e, 0x5a },	/* k -> KP 2 */
    108  1.109       phx 	{ 0x0f, 0x5b },	/* l -> KP 3 */
    109  1.109       phx 	{ 0x10, 0x62 },	/* m -> KP 0 */
    110  1.109       phx 	{ 0x12, 0x5e },	/* o -> KP 6 */
    111  1.109       phx 	{ 0x13, 0x55 },	/* o -> KP * */
    112  1.109       phx 	{ 0x18, 0x5c },	/* u -> KP 4 */
    113  1.109       phx 	{ 0x0c, 0x5d },	/* i -> KP 5 */
    114  1.109       phx 	{ 0x2a, 0x4c },	/* Backspace -> Delete */
    115  1.109       phx 	{ 0x28, 0x49 },	/* Return -> Insert */
    116  1.109       phx 	{ 0x24, 0x5f }, /* 7 -> KP 7 */
    117  1.109       phx 	{ 0x25, 0x60 }, /* 8 -> KP 8 */
    118  1.109       phx 	{ 0x26, 0x61 }, /* 9 -> KP 9 */
    119  1.109       phx 	{ 0x27, 0x54 }, /* 0 -> KP / */
    120  1.109       phx 	{ 0x2d, 0x67 }, /* - -> KP = */
    121  1.109       phx 	{ 0x33, 0x56 },	/* ; -> KP - */
    122  1.109       phx 	{ 0x37, 0x63 },	/* . -> KP . */
    123  1.109       phx 	{ 0x38, 0x57 },	/* / -> KP + */
    124  1.143  macallan 	{ 0x3a, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN },
    125  1.143  macallan 	{ 0x3b, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP },
    126  1.143  macallan 	{ 0x3c, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE },
    127  1.143  macallan 	{ 0x3d, IS_PMF | PMFE_AUDIO_VOLUME_DOWN },
    128  1.143  macallan 	{ 0x3e, IS_PMF | PMFE_AUDIO_VOLUME_UP },
    129  1.143  macallan 	{ 0x3f, 0xd6 },	/* num lock */
    130  1.109       phx 	{ 0x40, 0xd7 },
    131  1.109       phx 	{ 0x41, 0xd8 },
    132  1.143  macallan 	{ 0x42, 0xd9 },	/* kbd light down */
    133  1.143  macallan 	{ 0x43, 0xda },	/* kbd light up */
    134  1.109       phx 	{ 0x44, 0xdb },
    135  1.109       phx 	{ 0x45, 0xdc },
    136  1.109       phx 	{ 0x4f, 0x4d },	/* Right -> End */
    137  1.109       phx 	{ 0x50, 0x4a },	/* Left -> Home */
    138  1.109       phx 	{ 0x51, 0x4e },	/* Down -> PageDown */
    139  1.109       phx 	{ 0x52, 0x4b },	/* Up -> PageUp */
    140  1.109       phx 	{ 0x00, 0x00 }
    141  1.109       phx };
    142  1.109       phx 
    143  1.109       phx Static const struct ukbd_keycodetrans trtab_apple_iso[] = {
    144  1.109       phx 	{ 0x35, 0x64 },	/* swap the key above tab with key right of shift */
    145  1.109       phx 	{ 0x64, 0x35 },
    146  1.109       phx 	{ 0x31, 0x32 },	/* key left of return is Europe1, not "\|" */
    147  1.109       phx 	{ 0x00, 0x00 }
    148  1.109       phx };
    149  1.109       phx 
    150  1.113  macallan #ifdef GDIUM_KEYBOARD_HACK
    151  1.125  christos Static const struct ukbd_keycodetrans trtab_gdium_fn[] = {
    152  1.111  macallan #ifdef notyet
    153  1.119   khorben 	{ 58, 0 },	/* F1 -> toggle camera */
    154  1.119   khorben 	{ 59, 0 },	/* F2 -> toggle wireless */
    155  1.111  macallan #endif
    156  1.119   khorben 	{ 60, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE },
    157  1.119   khorben 	{ 61, IS_PMF | PMFE_AUDIO_VOLUME_UP },
    158  1.119   khorben 	{ 62, IS_PMF | PMFE_AUDIO_VOLUME_DOWN },
    159  1.111  macallan #ifdef notyet
    160  1.119   khorben 	{ 63, 0 },	/* F6 -> toggle ext. video */
    161  1.119   khorben 	{ 64, 0 },	/* F7 -> toggle mouse */
    162  1.112  macallan #endif
    163  1.119   khorben 	{ 65, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP },
    164  1.119   khorben 	{ 66, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN },
    165  1.112  macallan #ifdef notyet
    166  1.119   khorben 	{ 67, 0 },	/* F10 -> suspend */
    167  1.119   khorben 	{ 68, 0 },	/* F11 -> user1 */
    168  1.119   khorben 	{ 69, 0 },	/* F12 -> user2 */
    169  1.119   khorben 	{ 70, 0 },	/* print screen -> sysrq */
    170  1.119   khorben #endif
    171  1.119   khorben 	{ 76, 71 },	/* delete -> scroll lock */
    172  1.119   khorben 	{ 81, 78 },	/* down -> page down */
    173  1.119   khorben 	{ 82, 75 },	/* up -> page up */
    174  1.119   khorben 	{  0, 0 }
    175  1.111  macallan };
    176  1.113  macallan #endif
    177  1.111  macallan 
    178  1.120   khorben Static const struct ukbd_keycodetrans trtab_generic[] = {
    179  1.120   khorben 	{ 0x7f, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE },
    180  1.120   khorben 	{ 0x80, IS_PMF | PMFE_AUDIO_VOLUME_UP },
    181  1.120   khorben 	{ 0x81, IS_PMF | PMFE_AUDIO_VOLUME_DOWN },
    182  1.120   khorben 	{ 0x00, 0x00 }
    183  1.120   khorben };
    184  1.120   khorben 
    185  1.116       mrg #if defined(WSDISPLAY_COMPAT_RAWKBD)
    186    1.5  augustss #define NN 0			/* no translation */
    187   1.82  augustss /*
    188   1.23  augustss  * Translate USB keycodes to US keyboard XT scancodes.
    189   1.76  augustss  * Scancodes >= 0x80 represent EXTENDED keycodes.
    190   1.76  augustss  *
    191  1.104  jakllsch  * See http://www.microsoft.com/whdc/archive/scancode.mspx
    192  1.104  jakllsch  *
    193  1.107  sborrill  * Note: a real pckbd(4) has more complexity in its
    194  1.104  jakllsch  * protocol for some keys than this translation implements.
    195  1.107  sborrill  * For example, some keys generate Fake ShiftL events (e0 2a)
    196  1.107  sborrill  * before the actual key sequence.
    197   1.19  augustss  */
    198  1.131     skrll Static const uint8_t ukbd_trtab[256] = {
    199  1.123   khorben       NN,   NN,   NN,   NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
    200  1.123   khorben     0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
    201  1.123   khorben     0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
    202  1.123   khorben     0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
    203  1.123   khorben     0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
    204  1.123   khorben     0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
    205  1.123   khorben     0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
    206  1.123   khorben     0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
    207  1.123   khorben     0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */
    208  1.123   khorben     0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
    209  1.123   khorben     0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
    210  1.123   khorben     0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
    211  1.123   khorben     0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, 0xdf, 0x59, /* 60 - 67 */
    212  1.123   khorben     0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,   NN, /* 68 - 6f */
    213  1.123   khorben       NN,   NN,   NN,   NN, 0x84, 0x85, 0x87, 0x88, /* 70 - 77 */
    214  1.123   khorben     0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,   NN, /* 78 - 7f */
    215  1.123   khorben       NN,   NN,   NN,   NN,   NN, 0x7e,   NN, 0x73, /* 80 - 87 */
    216  1.123   khorben     0x70, 0x7d, 0x79, 0x7b, 0x5c,   NN,   NN,   NN, /* 88 - 8f */
    217  1.123   khorben       NN,   NN, 0x78, 0x77, 0x76,   NN,   NN,   NN, /* 90 - 97 */
    218  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* 98 - 9f */
    219  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* a0 - a7 */
    220  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* a8 - af */
    221  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* b0 - b7 */
    222  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* b8 - bf */
    223  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* c0 - c7 */
    224  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* c8 - cf */
    225  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* d0 - d7 */
    226  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* d8 - df */
    227  1.123   khorben     0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
    228  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* e8 - ef */
    229  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* f0 - f7 */
    230  1.123   khorben       NN,   NN,   NN,   NN,   NN,   NN,   NN,   NN, /* f8 - ff */
    231    1.1  augustss };
    232  1.116       mrg #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
    233    1.1  augustss 
    234    1.1  augustss #define KEY_ERROR 0x01
    235    1.1  augustss 
    236    1.1  augustss struct ukbd_softc {
    237   1.75  augustss 	struct uhidev sc_hdev;
    238    1.1  augustss 
    239    1.1  augustss 	struct ukbd_data sc_ndata;
    240    1.1  augustss 	struct ukbd_data sc_odata;
    241  1.138  jakllsch 	struct hid_location sc_keyloc[MAXKEYS];
    242  1.138  jakllsch 	uint8_t sc_keyuse[MAXKEYS];
    243  1.138  jakllsch 	u_int sc_nkeyloc;
    244   1.75  augustss 
    245   1.75  augustss 	struct hid_location sc_keycodeloc;
    246   1.75  augustss 	u_int sc_nkeycode;
    247    1.1  augustss 
    248  1.109       phx 	u_int sc_flags;			/* flags */
    249  1.109       phx #define FLAG_ENABLED		0x0001
    250  1.109       phx #define FLAG_POLLING		0x0002
    251  1.109       phx #define FLAG_DEBOUNCE		0x0004	/* for quirk handling */
    252  1.109       phx #define FLAG_APPLE_FIX_ISO	0x0008
    253  1.109       phx #define FLAG_APPLE_FN		0x0010
    254  1.111  macallan #define FLAG_GDIUM_FN		0x0020
    255  1.109       phx #define FLAG_FN_PRESSED		0x0100	/* FN key is held down */
    256  1.109       phx #define FLAG_FN_ALT		0x0200	/* Last Alt key was FN-Alt = AltGr */
    257    1.1  augustss 
    258   1.29   thorpej 	int sc_console_keyboard;	/* we are the console keyboard */
    259   1.29   thorpej 
    260  1.109       phx 	struct callout sc_delay;	/* for quirk handling */
    261   1.62  augustss 	struct ukbd_data sc_data;	/* for quirk handling */
    262   1.62  augustss 
    263  1.109       phx 	struct hid_location sc_apple_fn;
    264   1.75  augustss 	struct hid_location sc_numloc;
    265   1.75  augustss 	struct hid_location sc_capsloc;
    266   1.75  augustss 	struct hid_location sc_scroloc;
    267  1.121   khorben 	struct hid_location sc_compose;
    268    1.2  augustss 	int sc_leds;
    269  1.129     skrll 	struct usb_task sc_ledtask;
    270   1.97    dyoung 	device_t sc_wskbddev;
    271   1.57   thorpej 
    272   1.23  augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
    273   1.87  augustss 	int sc_rawkbd;
    274   1.87  augustss #if defined(UKBD_REPEAT)
    275  1.108    dyoung 	struct callout sc_rawrepeat_ch;
    276   1.20  augustss #define REP_DELAY1 400
    277   1.20  augustss #define REP_DELAYN 100
    278   1.20  augustss 	int sc_nrep;
    279   1.20  augustss 	char sc_rep[MAXKEYS];
    280   1.87  augustss #endif /* defined(UKBD_REPEAT) */
    281   1.23  augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
    282    1.3  augustss 
    283   1.84  augustss 	int sc_spl;
    284   1.23  augustss 	int sc_npollchar;
    285  1.131     skrll 	uint16_t sc_pollchars[MAXKEYS];
    286   1.40  augustss 
    287   1.40  augustss 	u_char sc_dying;
    288    1.1  augustss };
    289    1.1  augustss 
    290   1.62  augustss #ifdef UKBD_DEBUG
    291   1.62  augustss #define UKBDTRACESIZE 64
    292   1.62  augustss struct ukbdtraceinfo {
    293   1.62  augustss 	int unit;
    294   1.62  augustss 	struct timeval tv;
    295   1.62  augustss 	struct ukbd_data ud;
    296   1.62  augustss };
    297   1.62  augustss struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE];
    298   1.62  augustss int ukbdtraceindex = 0;
    299   1.62  augustss int ukbdtrace = 0;
    300   1.62  augustss void ukbdtracedump(void);
    301   1.62  augustss void
    302   1.62  augustss ukbdtracedump(void)
    303   1.62  augustss {
    304  1.138  jakllsch 	size_t i, j;
    305   1.62  augustss 	for (i = 0; i < UKBDTRACESIZE; i++) {
    306   1.82  augustss 		struct ukbdtraceinfo *p =
    307   1.62  augustss 		    &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE];
    308  1.138  jakllsch 		printf("%"PRIu64".%06"PRIu64":", p->tv.tv_sec,
    309  1.138  jakllsch 		    (uint64_t)p->tv.tv_usec);
    310  1.138  jakllsch 		for (j = 0; j < MAXKEYS; j++) {
    311  1.138  jakllsch 			if (isset(p->ud.keys, j))
    312  1.138  jakllsch 				printf(" %zu", j);
    313  1.138  jakllsch 		}
    314  1.138  jakllsch 		printf(".\n");
    315   1.62  augustss 	}
    316   1.62  augustss }
    317   1.62  augustss #endif
    318   1.62  augustss 
    319    1.1  augustss #define	UKBDUNIT(dev)	(minor(dev))
    320    1.1  augustss #define	UKBD_CHUNK	128	/* chunk size for read */
    321    1.1  augustss #define	UKBD_BSIZE	1020	/* buffer size */
    322    1.1  augustss 
    323   1.58  augustss Static int	ukbd_is_console;
    324   1.31   thorpej 
    325   1.60  augustss Static void	ukbd_cngetc(void *, u_int *, int *);
    326   1.60  augustss Static void	ukbd_cnpollc(void *, int);
    327    1.3  augustss 
    328    1.8  drochner const struct wskbd_consops ukbd_consops = {
    329  1.124       mrg 	.getc =  ukbd_cngetc,
    330  1.124       mrg 	.pollc = ukbd_cnpollc,
    331  1.124       mrg 	.bell =  NULL,
    332    1.8  drochner };
    333    1.8  drochner 
    334  1.131     skrll Static const char *ukbd_parse_desc(struct ukbd_softc *);
    335   1.75  augustss 
    336  1.131     skrll Static void	ukbd_intr(struct uhidev *, void *, u_int);
    337  1.131     skrll Static void	ukbd_decode(struct ukbd_softc *, struct ukbd_data *);
    338  1.131     skrll Static void	ukbd_delayed_decode(void *);
    339    1.2  augustss 
    340   1.60  augustss Static int	ukbd_enable(void *, int);
    341   1.60  augustss Static void	ukbd_set_leds(void *, int);
    342  1.129     skrll Static void	ukbd_set_leds_task(void *);
    343   1.23  augustss 
    344   1.95  christos Static int	ukbd_ioctl(void *, u_long, void *, int, struct lwp *);
    345   1.88  jonathan #if  defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
    346   1.60  augustss Static void	ukbd_rawrepeat(void *v);
    347   1.48    mjacob #endif
    348    1.1  augustss 
    349    1.8  drochner const struct wskbd_accessops ukbd_accessops = {
    350    1.8  drochner 	ukbd_enable,
    351    1.8  drochner 	ukbd_set_leds,
    352    1.8  drochner 	ukbd_ioctl,
    353    1.8  drochner };
    354    1.8  drochner 
    355  1.139    bouyer extern const struct wscons_keydesc hidkbd_keydesctab[];
    356   1.23  augustss 
    357    1.8  drochner const struct wskbd_mapdata ukbd_keymapdata = {
    358  1.139    bouyer 	hidkbd_keydesctab,
    359   1.86  augustss #if defined(UKBD_LAYOUT)
    360   1.66  augustss 	UKBD_LAYOUT,
    361   1.86  augustss #elif defined(PCKBD_LAYOUT)
    362   1.86  augustss 	PCKBD_LAYOUT,
    363   1.66  augustss #else
    364    1.8  drochner 	KB_US,
    365   1.66  augustss #endif
    366    1.8  drochner };
    367    1.8  drochner 
    368  1.100      cube static int ukbd_match(device_t, cfdata_t, void *);
    369   1.97    dyoung static void ukbd_attach(device_t, device_t, void *);
    370   1.97    dyoung static int ukbd_detach(device_t, int);
    371   1.97    dyoung static int ukbd_activate(device_t, enum devact);
    372   1.97    dyoung static void ukbd_childdet(device_t, device_t);
    373   1.97    dyoung 
    374  1.142       mrg 
    375   1.97    dyoung 
    376  1.100      cube CFATTACH_DECL2_NEW(ukbd, sizeof(struct ukbd_softc), ukbd_match, ukbd_attach,
    377   1.97    dyoung     ukbd_detach, ukbd_activate, NULL, ukbd_childdet);
    378    1.1  augustss 
    379   1.75  augustss int
    380  1.100      cube ukbd_match(device_t parent, cfdata_t match, void *aux)
    381    1.1  augustss {
    382   1.75  augustss 	struct uhidev_attach_arg *uha = aux;
    383   1.75  augustss 	int size;
    384   1.75  augustss 	void *desc;
    385   1.82  augustss 
    386   1.75  augustss 	uhidev_get_report_desc(uha->parent, &desc, &size);
    387   1.75  augustss 	if (!hid_is_collection(desc, size, uha->reportid,
    388   1.75  augustss 			       HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
    389  1.131     skrll 		return UMATCH_NONE;
    390   1.75  augustss 
    391  1.131     skrll 	return UMATCH_IFACECLASS;
    392    1.1  augustss }
    393    1.1  augustss 
    394   1.75  augustss void
    395   1.97    dyoung ukbd_attach(device_t parent, device_t self, void *aux)
    396    1.1  augustss {
    397   1.97    dyoung 	struct ukbd_softc *sc = device_private(self);
    398   1.75  augustss 	struct uhidev_attach_arg *uha = aux;
    399  1.131     skrll 	uint32_t qflags;
    400   1.75  augustss 	const char *parseerr;
    401    1.2  augustss 	struct wskbddev_attach_args a;
    402   1.82  augustss 
    403  1.100      cube 	sc->sc_hdev.sc_dev = self;
    404   1.75  augustss 	sc->sc_hdev.sc_intr = ukbd_intr;
    405   1.75  augustss 	sc->sc_hdev.sc_parent = uha->parent;
    406   1.75  augustss 	sc->sc_hdev.sc_report_id = uha->reportid;
    407  1.109       phx 	sc->sc_flags = 0;
    408   1.75  augustss 
    409  1.127     soren 	aprint_naive("\n");
    410  1.127     soren 
    411  1.101  jmcneill 	if (!pmf_device_register(self, NULL, NULL)) {
    412  1.101  jmcneill 		aprint_normal("\n");
    413  1.101  jmcneill 		aprint_error_dev(self, "couldn't establish power handler\n");
    414  1.101  jmcneill 	}
    415  1.101  jmcneill 
    416   1.75  augustss 	parseerr = ukbd_parse_desc(sc);
    417   1.75  augustss 	if (parseerr != NULL) {
    418   1.98    cegger 		aprint_normal("\n");
    419  1.100      cube 		aprint_error_dev(self, "attach failed, %s\n", parseerr);
    420  1.108    dyoung 		return;
    421    1.1  augustss 	}
    422   1.82  augustss 
    423  1.109       phx 	/* Quirks */
    424  1.109       phx 	qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
    425  1.109       phx 	if (qflags & UQ_SPUR_BUT_UP)
    426  1.109       phx 		sc->sc_flags |= FLAG_DEBOUNCE;
    427  1.109       phx 	if (qflags & UQ_APPLE_ISO)
    428  1.109       phx 		sc->sc_flags |= FLAG_APPLE_FIX_ISO;
    429  1.109       phx 
    430  1.113  macallan #ifdef GDIUM_KEYBOARD_HACK
    431  1.133     skrll 	if (uha->uiaa->uiaa_vendor == USB_VENDOR_CYPRESS &&
    432  1.133     skrll 	    uha->uiaa->uiaa_product == USB_PRODUCT_CYPRESS_LPRDK)
    433  1.111  macallan 		sc->sc_flags = FLAG_GDIUM_FN;
    434  1.113  macallan #endif
    435  1.111  macallan 
    436   1.75  augustss #ifdef DIAGNOSTIC
    437  1.138  jakllsch 	aprint_normal(": %d Variable keys, %d Array codes", sc->sc_nkeyloc,
    438   1.75  augustss 	       sc->sc_nkeycode);
    439  1.109       phx 	if (sc->sc_flags & FLAG_APPLE_FN)
    440  1.109       phx 		aprint_normal(", apple fn key");
    441  1.109       phx 	if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
    442  1.109       phx 		aprint_normal(", fix apple iso");
    443  1.111  macallan 	if (sc->sc_flags & FLAG_GDIUM_FN)
    444  1.111  macallan 		aprint_normal(", Gdium fn key");
    445   1.75  augustss #endif
    446  1.100      cube 	aprint_normal("\n");
    447    1.1  augustss 
    448   1.29   thorpej 	/*
    449   1.29   thorpej 	 * Remember if we're the console keyboard.
    450   1.29   thorpej 	 *
    451   1.31   thorpej 	 * XXX This always picks the first keyboard on the
    452   1.31   thorpej 	 * first USB bus, but what else can we really do?
    453   1.29   thorpej 	 */
    454   1.31   thorpej 	if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
    455   1.29   thorpej 		/* Don't let any other keyboard have it. */
    456   1.31   thorpej 		ukbd_is_console = 0;
    457   1.29   thorpej 	}
    458   1.29   thorpej 
    459   1.31   thorpej 	if (sc->sc_console_keyboard) {
    460  1.141  christos 		DPRINTF(("%s: console keyboard sc=%p\n", __func__, sc));
    461   1.31   thorpej 		wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
    462   1.34  wrstuden 		ukbd_enable(sc, 1);
    463   1.31   thorpej 	}
    464   1.29   thorpej 
    465   1.29   thorpej 	a.console = sc->sc_console_keyboard;
    466    1.8  drochner 
    467    1.8  drochner 	a.keymap = &ukbd_keymapdata;
    468    1.8  drochner 
    469    1.8  drochner 	a.accessops = &ukbd_accessops;
    470    1.2  augustss 	a.accesscookie = sc;
    471    1.8  drochner 
    472   1.87  augustss #ifdef UKBD_REPEAT
    473  1.108    dyoung 	callout_init(&sc->sc_rawrepeat_ch, 0);
    474   1.87  augustss #endif
    475   1.57   thorpej 
    476  1.108    dyoung 	callout_init(&sc->sc_delay, 0);
    477   1.62  augustss 
    478  1.130       mrg 	usb_init_task(&sc->sc_ledtask, ukbd_set_leds_task, sc, 0);
    479  1.129     skrll 
    480   1.19  augustss 	/* Flash the leds; no real purpose, just shows we're alive. */
    481  1.121   khorben 	ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS
    482  1.121   khorben 			| WSKBD_LED_COMPOSE);
    483   1.75  augustss 	usbd_delay_ms(uha->parent->sc_udev, 400);
    484   1.19  augustss 	ukbd_set_leds(sc, 0);
    485   1.19  augustss 
    486   1.64  augustss 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
    487   1.55  augustss 
    488  1.108    dyoung 	return;
    489    1.1  augustss }
    490    1.1  augustss 
    491    1.8  drochner int
    492   1.60  augustss ukbd_enable(void *v, int on)
    493    1.8  drochner {
    494    1.9  augustss 	struct ukbd_softc *sc = v;
    495    1.9  augustss 
    496   1.40  augustss 	if (on && sc->sc_dying)
    497  1.131     skrll 		return EIO;
    498   1.40  augustss 
    499   1.38  augustss 	/* Should only be called to change state */
    500  1.109       phx 	if ((sc->sc_flags & FLAG_ENABLED) != 0 && on != 0) {
    501   1.38  augustss #ifdef DIAGNOSTIC
    502  1.141  christos 		aprint_error_dev(sc->sc_hdev.sc_dev, "bad call on=%d\n", on);
    503   1.38  augustss #endif
    504  1.131     skrll 		return EBUSY;
    505   1.38  augustss 	}
    506   1.38  augustss 
    507  1.141  christos 	DPRINTF(("%s: sc=%p on=%d\n", __func__, sc, on));
    508    1.9  augustss 	if (on) {
    509  1.109       phx 		sc->sc_flags |= FLAG_ENABLED;
    510  1.131     skrll 		return uhidev_open(&sc->sc_hdev);
    511    1.9  augustss 	} else {
    512  1.109       phx 		sc->sc_flags &= ~FLAG_ENABLED;
    513   1.75  augustss 		uhidev_close(&sc->sc_hdev);
    514  1.131     skrll 		return 0;
    515    1.9  augustss 	}
    516   1.37  augustss }
    517   1.37  augustss 
    518   1.97    dyoung 
    519   1.97    dyoung static void
    520   1.97    dyoung ukbd_childdet(device_t self, device_t child)
    521   1.97    dyoung {
    522   1.97    dyoung 	struct ukbd_softc *sc = device_private(self);
    523   1.97    dyoung 
    524   1.97    dyoung 	KASSERT(sc->sc_wskbddev == child);
    525   1.97    dyoung 	sc->sc_wskbddev = NULL;
    526   1.97    dyoung }
    527   1.97    dyoung 
    528   1.37  augustss int
    529   1.97    dyoung ukbd_activate(device_t self, enum devact act)
    530   1.37  augustss {
    531   1.97    dyoung 	struct ukbd_softc *sc = device_private(self);
    532   1.40  augustss 
    533   1.40  augustss 	switch (act) {
    534   1.40  augustss 	case DVACT_DEACTIVATE:
    535   1.40  augustss 		sc->sc_dying = 1;
    536  1.105    dyoung 		return 0;
    537  1.105    dyoung 	default:
    538  1.105    dyoung 		return EOPNOTSUPP;
    539   1.40  augustss 	}
    540   1.37  augustss }
    541   1.37  augustss 
    542   1.75  augustss int
    543   1.97    dyoung ukbd_detach(device_t self, int flags)
    544   1.37  augustss {
    545   1.97    dyoung 	struct ukbd_softc *sc = device_private(self);
    546   1.37  augustss 	int rv = 0;
    547   1.37  augustss 
    548  1.141  christos 	DPRINTF(("%s: sc=%p flags=%d\n", __func__, sc, flags));
    549   1.46  augustss 
    550  1.101  jmcneill 	pmf_device_deregister(self);
    551  1.101  jmcneill 
    552   1.37  augustss 	if (sc->sc_console_keyboard) {
    553   1.50  augustss #if 0
    554   1.37  augustss 		/*
    555   1.37  augustss 		 * XXX Should probably disconnect our consops,
    556   1.37  augustss 		 * XXX and either notify some other keyboard that
    557   1.37  augustss 		 * XXX it can now be the console, or if there aren't
    558   1.37  augustss 		 * XXX any more USB keyboards, set ukbd_is_console
    559   1.37  augustss 		 * XXX back to 1 so that the next USB keyboard attached
    560   1.37  augustss 		 * XXX to the system will get it.
    561   1.37  augustss 		 */
    562   1.37  augustss 		panic("ukbd_detach: console keyboard");
    563   1.50  augustss #else
    564   1.51  augustss 		/*
    565   1.51  augustss 		 * Disconnect our consops and set ukbd_is_console
    566   1.51  augustss 		 * back to 1 so that the next USB keyboard attached
    567   1.51  augustss 		 * to the system will get it.
    568   1.51  augustss 		 * XXX Should notify some other keyboard that it can be
    569   1.51  augustss 		 * XXX console, if there are any other keyboards.
    570   1.51  augustss 		 */
    571   1.75  augustss 		printf("%s: was console keyboard\n",
    572  1.108    dyoung 		       device_xname(sc->sc_hdev.sc_dev));
    573   1.50  augustss 		wskbd_cndetach();
    574   1.50  augustss 		ukbd_is_console = 1;
    575   1.50  augustss #endif
    576   1.37  augustss 	}
    577   1.45  augustss 	/* No need to do reference counting of ukbd, wskbd has all the goo. */
    578   1.47  augustss 	if (sc->sc_wskbddev != NULL)
    579   1.37  augustss 		rv = config_detach(sc->sc_wskbddev, flags);
    580   1.68  augustss 
    581   1.68  augustss 	/* The console keyboard does not get a disable call, so check pipe. */
    582   1.75  augustss 	if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
    583   1.75  augustss 		uhidev_close(&sc->sc_hdev);
    584   1.55  augustss 
    585  1.131     skrll 	return rv;
    586    1.1  augustss }
    587    1.1  augustss 
    588  1.109       phx static void
    589  1.109       phx ukbd_translate_keycodes(struct ukbd_softc *sc, struct ukbd_data *ud,
    590  1.109       phx     const struct ukbd_keycodetrans *tab)
    591  1.109       phx {
    592  1.109       phx 	const struct ukbd_keycodetrans *tp;
    593  1.138  jakllsch 	struct ukbd_data oud;
    594  1.109       phx 	int i;
    595  1.109       phx 
    596  1.138  jakllsch 	oud = *ud;
    597  1.138  jakllsch 
    598  1.138  jakllsch 	for (i = 4; i < MAXKEYS; i++) {
    599  1.138  jakllsch 		if (isset(oud.keys, i))
    600  1.109       phx 			for (tp = tab; tp->from; tp++)
    601  1.138  jakllsch 				if (tp->from == i) {
    602  1.112  macallan 					if (tp->to & IS_PMF) {
    603  1.112  macallan 						pmf_event_inject(
    604  1.112  macallan 						    sc->sc_hdev.sc_dev,
    605  1.112  macallan 						    tp->to & 0xff);
    606  1.112  macallan 					} else
    607  1.138  jakllsch 						setbit(ud->keys, tp->to);
    608  1.138  jakllsch 					clrbit(ud->keys, i);
    609  1.109       phx 					break;
    610  1.109       phx 				}
    611  1.109       phx 	}
    612  1.109       phx }
    613  1.109       phx 
    614  1.131     skrll static uint16_t
    615  1.131     skrll ukbd_translate_modifier(struct ukbd_softc *sc, uint16_t key)
    616  1.109       phx {
    617  1.109       phx 	if ((sc->sc_flags & FLAG_APPLE_FN) && (key & CODEMASK) == 0x00e2) {
    618  1.109       phx 		if ((key & ~CODEMASK) == PRESS) {
    619  1.109       phx 			if (sc->sc_flags & FLAG_FN_PRESSED) {
    620  1.109       phx 				/* pressed FN-Alt, translate to AltGr */
    621  1.109       phx 				key = 0x00e6 | PRESS;
    622  1.109       phx 				sc->sc_flags |= FLAG_FN_ALT;
    623  1.109       phx 			}
    624  1.109       phx 		} else {
    625  1.109       phx 			if (sc->sc_flags & FLAG_FN_ALT) {
    626  1.109       phx 				/* released Alt, which was treated as FN-Alt */
    627  1.109       phx 				key = 0x00e6 | RELEASE;
    628  1.109       phx 				sc->sc_flags &= ~FLAG_FN_ALT;
    629  1.109       phx 			}
    630  1.109       phx 		}
    631  1.109       phx 	}
    632  1.109       phx 	return key;
    633  1.109       phx }
    634  1.109       phx 
    635    1.1  augustss void
    636   1.94  christos ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
    637    1.1  augustss {
    638   1.75  augustss 	struct ukbd_softc *sc = (struct ukbd_softc *)addr;
    639    1.1  augustss 	struct ukbd_data *ud = &sc->sc_ndata;
    640   1.75  augustss 	int i;
    641   1.76  augustss 
    642   1.76  augustss #ifdef UKBD_DEBUG
    643   1.76  augustss 	if (ukbddebug > 5) {
    644   1.76  augustss 		printf("ukbd_intr: data");
    645   1.76  augustss 		for (i = 0; i < len; i++)
    646  1.145  christos 			printf(" 0x%02x", ((u_char *)ibuf)[i]);
    647   1.76  augustss 		printf("\n");
    648   1.76  augustss 	}
    649   1.76  augustss #endif
    650   1.76  augustss 
    651  1.138  jakllsch 	memset(ud->keys, 0, sizeof(ud->keys));
    652  1.138  jakllsch 
    653  1.138  jakllsch 	for (i = 0; i < sc->sc_nkeyloc; i++)
    654  1.138  jakllsch 		if (hid_get_data(ibuf, &sc->sc_keyloc[i]))
    655  1.138  jakllsch 			setbit(ud->keys, sc->sc_keyuse[i]);
    656  1.138  jakllsch 
    657  1.138  jakllsch 	const uint8_t * const scancode = (char *)ibuf + sc->sc_keycodeloc.pos / 8;
    658  1.138  jakllsch 	const uint16_t Keyboard_NoEvent = 0x0000;
    659  1.138  jakllsch 	for (i = 0; i < sc->sc_nkeycode; i++) {
    660  1.138  jakllsch 		if (scancode[i] != Keyboard_NoEvent)
    661  1.138  jakllsch 			setbit(ud->keys, scancode[i]);
    662  1.138  jakllsch 	}
    663    1.1  augustss 
    664  1.109       phx 	if (sc->sc_flags & FLAG_APPLE_FN) {
    665  1.109       phx 		if (hid_get_data(ibuf, &sc->sc_apple_fn)) {
    666  1.109       phx 			sc->sc_flags |= FLAG_FN_PRESSED;
    667  1.109       phx 			ukbd_translate_keycodes(sc, ud, trtab_apple_fn);
    668  1.109       phx 		}
    669  1.109       phx 		else
    670  1.109       phx 			sc->sc_flags &= ~FLAG_FN_PRESSED;
    671  1.109       phx 	}
    672  1.113  macallan 
    673  1.113  macallan #ifdef GDIUM_KEYBOARD_HACK
    674  1.111  macallan 	if (sc->sc_flags & FLAG_GDIUM_FN) {
    675  1.111  macallan 		if (sc->sc_flags & FLAG_FN_PRESSED) {
    676  1.111  macallan 			ukbd_translate_keycodes(sc, ud, trtab_gdium_fn);
    677  1.111  macallan 		}
    678  1.111  macallan 	}
    679  1.113  macallan #endif
    680  1.109       phx 
    681  1.120   khorben 	ukbd_translate_keycodes(sc, ud, trtab_generic);
    682  1.120   khorben 
    683  1.109       phx 	if ((sc->sc_flags & FLAG_DEBOUNCE) && !(sc->sc_flags & FLAG_POLLING)) {
    684   1.62  augustss 		/*
    685   1.62  augustss 		 * Some keyboards have a peculiar quirk.  They sometimes
    686   1.62  augustss 		 * generate a key up followed by a key down for the same
    687   1.62  augustss 		 * key after about 10 ms.
    688   1.62  augustss 		 * We avoid this bug by holding off decoding for 20 ms.
    689   1.62  augustss 		 */
    690   1.62  augustss 		sc->sc_data = *ud;
    691  1.108    dyoung 		callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
    692   1.74     lukem #ifdef DDB
    693  1.109       phx 	} else if (sc->sc_console_keyboard && !(sc->sc_flags & FLAG_POLLING)) {
    694   1.69  augustss 		/*
    695   1.69  augustss 		 * For the console keyboard we can't deliver CTL-ALT-ESC
    696   1.69  augustss 		 * from the interrupt routine.  Doing so would start
    697   1.69  augustss 		 * polling from inside the interrupt routine and that
    698   1.69  augustss 		 * loses bigtime.
    699   1.69  augustss 		 */
    700   1.69  augustss 		sc->sc_data = *ud;
    701  1.108    dyoung 		callout_reset(&sc->sc_delay, 1, ukbd_delayed_decode, sc);
    702   1.69  augustss #endif
    703   1.62  augustss 	} else {
    704   1.62  augustss 		ukbd_decode(sc, ud);
    705   1.62  augustss 	}
    706   1.62  augustss }
    707   1.62  augustss 
    708   1.62  augustss void
    709   1.62  augustss ukbd_delayed_decode(void *addr)
    710   1.62  augustss {
    711   1.62  augustss 	struct ukbd_softc *sc = addr;
    712   1.62  augustss 
    713   1.62  augustss 	ukbd_decode(sc, &sc->sc_data);
    714   1.62  augustss }
    715   1.62  augustss 
    716   1.62  augustss void
    717   1.62  augustss ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
    718   1.62  augustss {
    719  1.131     skrll 	uint16_t ibuf[MAXKEYS];	/* chars events */
    720   1.62  augustss 	int s;
    721  1.138  jakllsch 	int nkeys, i;
    722  1.138  jakllsch #ifdef WSDISPLAY_COMPAT_RAWKBD
    723  1.138  jakllsch 	int j;
    724  1.138  jakllsch #endif
    725   1.62  augustss 	int key;
    726  1.135      maya #define ADDKEY(c) do { \
    727  1.135      maya     KASSERT(nkeys < MAXKEYS); \
    728  1.135      maya     ibuf[nkeys++] = (c); \
    729  1.135      maya } while (0)
    730   1.62  augustss 
    731   1.62  augustss #ifdef UKBD_DEBUG
    732   1.82  augustss 	/*
    733   1.62  augustss 	 * Keep a trace of the last events.  Using printf changes the
    734   1.62  augustss 	 * timing, so this can be useful sometimes.
    735   1.62  augustss 	 */
    736   1.62  augustss 	if (ukbdtrace) {
    737   1.62  augustss 		struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
    738  1.100      cube 		p->unit = device_unit(sc->sc_hdev.sc_dev);
    739   1.62  augustss 		microtime(&p->tv);
    740   1.62  augustss 		p->ud = *ud;
    741   1.62  augustss 		if (++ukbdtraceindex >= UKBDTRACESIZE)
    742   1.62  augustss 			ukbdtraceindex = 0;
    743   1.62  augustss 	}
    744   1.62  augustss 	if (ukbddebug > 5) {
    745   1.62  augustss 		struct timeval tv;
    746   1.62  augustss 		microtime(&tv);
    747  1.138  jakllsch 		DPRINTF((" at %"PRIu64".%06"PRIu64":", tv.tv_sec,
    748  1.138  jakllsch 		    (uint64_t)tv.tv_usec));
    749  1.138  jakllsch 		for (size_t k = 0; k < MAXKEYS; k++) {
    750  1.138  jakllsch 			if (isset(ud->keys, k))
    751  1.138  jakllsch 				DPRINTF((" %zu", k));
    752  1.138  jakllsch 		}
    753  1.138  jakllsch 		DPRINTF((".\n"));
    754   1.62  augustss 	}
    755   1.62  augustss #endif
    756    1.1  augustss 
    757  1.138  jakllsch 	if (isset(ud->keys, KEY_ERROR)) {
    758  1.141  christos 		DPRINTF(("%s: KEY_ERROR\n", __func__));
    759    1.1  augustss 		return;		/* ignore  */
    760   1.53  augustss 	}
    761  1.109       phx 
    762  1.109       phx 	if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
    763  1.109       phx 		ukbd_translate_keycodes(sc, ud, trtab_apple_iso);
    764  1.109       phx 
    765    1.1  augustss 	nkeys = 0;
    766  1.138  jakllsch 	for (i = 0; i < MAXKEYS; i++) {
    767  1.113  macallan #ifdef GDIUM_KEYBOARD_HACK
    768  1.138  jakllsch 			if (sc->sc_flags & FLAG_GDIUM_FN && i == 0x82) {
    769  1.138  jakllsch 				if (isset(ud->keys, i))
    770  1.138  jakllsch 					sc->sc_flags |= FLAG_FN_PRESSED;
    771  1.138  jakllsch 				else
    772  1.111  macallan 					sc->sc_flags &= ~FLAG_FN_PRESSED;
    773  1.111  macallan 			}
    774  1.113  macallan #endif
    775  1.138  jakllsch 			if (isset(ud->keys, i) != isset(sc->sc_odata.keys, i)) {
    776  1.138  jakllsch 				key = i | ((isset(ud->keys, i) ? PRESS : RELEASE));
    777  1.138  jakllsch 				ADDKEY(ukbd_translate_modifier(sc, key));
    778  1.111  macallan 			}
    779    1.1  augustss 	}
    780    1.1  augustss 	sc->sc_odata = *ud;
    781    1.1  augustss 
    782   1.20  augustss 	if (nkeys == 0)
    783   1.20  augustss 		return;
    784   1.20  augustss 
    785  1.109       phx 	if (sc->sc_flags & FLAG_POLLING) {
    786  1.145  christos 		DPRINTFN(1,("%s: pollchar = 0x%03x\n", __func__, ibuf[0]));
    787  1.131     skrll 		memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(uint16_t));
    788   1.23  augustss 		sc->sc_npollchar = nkeys;
    789    1.3  augustss 		return;
    790    1.3  augustss 	}
    791   1.20  augustss #ifdef WSDISPLAY_COMPAT_RAWKBD
    792   1.19  augustss 	if (sc->sc_rawkbd) {
    793   1.79  augustss 		u_char cbuf[MAXKEYS * 2];
    794   1.24  augustss 		int c;
    795  1.128    martin #if defined(UKBD_REPEAT)
    796  1.128    martin 		int npress = 0;
    797  1.128    martin #endif
    798   1.20  augustss 
    799  1.128    martin 		for (i = j = 0; i < nkeys; i++) {
    800   1.23  augustss 			key = ibuf[i];
    801   1.23  augustss 			c = ukbd_trtab[key & CODEMASK];
    802   1.23  augustss 			if (c == NN)
    803   1.23  augustss 				continue;
    804  1.104  jakllsch 			if (c == 0x7f) {
    805  1.104  jakllsch 				/* pause key */
    806  1.104  jakllsch 				cbuf[j++] = 0xe1;
    807  1.104  jakllsch 				cbuf[j++] = 0x1d;
    808  1.104  jakllsch 				cbuf[j-1] |= (key & RELEASE) ? 0x80 : 0;
    809  1.104  jakllsch 				cbuf[j] = 0x45;
    810  1.104  jakllsch 			} else {
    811  1.104  jakllsch 				if (c & 0x80)
    812  1.104  jakllsch 					cbuf[j++] = 0xe0;
    813  1.104  jakllsch 				cbuf[j] = c & 0x7f;
    814  1.104  jakllsch 			}
    815   1.23  augustss 			if (key & RELEASE)
    816   1.19  augustss 				cbuf[j] |= 0x80;
    817   1.87  augustss #if defined(UKBD_REPEAT)
    818   1.20  augustss 			else {
    819   1.23  augustss 				/* remember pressed keys for autorepeat */
    820   1.20  augustss 				if (c & 0x80)
    821   1.20  augustss 					sc->sc_rep[npress++] = 0xe0;
    822   1.20  augustss 				sc->sc_rep[npress++] = c & 0x7f;
    823   1.20  augustss 			}
    824   1.87  augustss #endif
    825  1.145  christos 			DPRINTFN(1,("%s: raw = %s0x%02x\n", __func__,
    826   1.27  augustss 				    c & 0x80 ? "0xe0 " : "",
    827   1.27  augustss 				    cbuf[j]));
    828   1.23  augustss 			j++;
    829   1.19  augustss 		}
    830   1.30  augustss 		s = spltty();
    831   1.19  augustss 		wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
    832   1.30  augustss 		splx(s);
    833   1.87  augustss #ifdef UKBD_REPEAT
    834  1.108    dyoung 		callout_stop(&sc->sc_rawrepeat_ch);
    835   1.20  augustss 		if (npress != 0) {
    836   1.20  augustss 			sc->sc_nrep = npress;
    837  1.108    dyoung 			callout_reset(&sc->sc_rawrepeat_ch,
    838   1.57   thorpej 			    hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc);
    839   1.20  augustss 		}
    840   1.87  augustss #endif
    841   1.19  augustss 		return;
    842   1.19  augustss 	}
    843   1.19  augustss #endif
    844   1.19  augustss 
    845   1.30  augustss 	s = spltty();
    846    1.2  augustss 	for (i = 0; i < nkeys; i++) {
    847   1.23  augustss 		key = ibuf[i];
    848   1.82  augustss 		wskbd_input(sc->sc_wskbddev,
    849   1.23  augustss 		    key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
    850   1.23  augustss 		    key&CODEMASK);
    851   1.20  augustss 	}
    852   1.30  augustss 	splx(s);
    853    1.1  augustss }
    854    1.1  augustss 
    855    1.2  augustss void
    856   1.60  augustss ukbd_set_leds(void *v, int leds)
    857    1.1  augustss {
    858    1.2  augustss 	struct ukbd_softc *sc = v;
    859  1.131     skrll 	struct usbd_device *udev = sc->sc_hdev.sc_parent->sc_udev;
    860    1.1  augustss 
    861  1.141  christos 	DPRINTF(("%s: sc=%p leds=%d, sc_leds=%d\n", __func__,
    862   1.71  augustss 		 sc, leds, sc->sc_leds));
    863   1.40  augustss 
    864   1.40  augustss 	if (sc->sc_dying)
    865   1.40  augustss 		return;
    866    1.1  augustss 
    867   1.71  augustss 	if (sc->sc_leds == leds)
    868   1.71  augustss 		return;
    869  1.129     skrll 
    870    1.2  augustss 	sc->sc_leds = leds;
    871  1.129     skrll 	usb_add_task(udev, &sc->sc_ledtask, USB_TASKQ_DRIVER);
    872  1.129     skrll }
    873  1.129     skrll 
    874  1.129     skrll void
    875  1.129     skrll ukbd_set_leds_task(void *v)
    876  1.129     skrll {
    877  1.129     skrll 	struct ukbd_softc *sc = v;
    878  1.129     skrll 	int leds = sc->sc_leds;
    879  1.129     skrll 	uint8_t res = 0;
    880  1.129     skrll 
    881   1.75  augustss 	/* XXX not really right */
    882  1.121   khorben 	if ((leds & WSKBD_LED_COMPOSE) && sc->sc_compose.size == 1)
    883  1.121   khorben 		res |= 1 << sc->sc_compose.pos;
    884   1.75  augustss 	if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
    885   1.75  augustss 		res |= 1 << sc->sc_scroloc.pos;
    886   1.75  augustss 	if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
    887   1.75  augustss 		res |= 1 << sc->sc_numloc.pos;
    888   1.75  augustss 	if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
    889   1.75  augustss 		res |= 1 << sc->sc_capsloc.pos;
    890  1.129     skrll 
    891  1.129     skrll 	uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1);
    892    1.1  augustss }
    893    1.1  augustss 
    894   1.87  augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
    895   1.20  augustss void
    896   1.60  augustss ukbd_rawrepeat(void *v)
    897   1.20  augustss {
    898   1.20  augustss 	struct ukbd_softc *sc = v;
    899   1.30  augustss 	int s;
    900   1.20  augustss 
    901   1.30  augustss 	s = spltty();
    902   1.20  augustss 	wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
    903   1.30  augustss 	splx(s);
    904  1.108    dyoung 	callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
    905   1.57   thorpej 	    ukbd_rawrepeat, sc);
    906   1.20  augustss }
    907   1.87  augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */
    908   1.20  augustss 
    909    1.1  augustss int
    910   1.95  christos ukbd_ioctl(void *v, u_long cmd, void *data, int flag,
    911   1.94  christos     struct lwp *l)
    912    1.1  augustss {
    913    1.2  augustss 	struct ukbd_softc *sc = v;
    914    1.1  augustss 
    915    1.2  augustss 	switch (cmd) {
    916    1.2  augustss 	case WSKBDIO_GTYPE:
    917   1.20  augustss 		*(int *)data = WSKBD_TYPE_USB;
    918  1.131     skrll 		return 0;
    919    1.2  augustss 	case WSKBDIO_SETLEDS:
    920    1.2  augustss 		ukbd_set_leds(v, *(int *)data);
    921  1.131     skrll 		return 0;
    922    1.2  augustss 	case WSKBDIO_GETLEDS:
    923    1.2  augustss 		*(int *)data = sc->sc_leds;
    924  1.131     skrll 		return 0;
    925   1.87  augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
    926    1.2  augustss 	case WSKBDIO_SETMODE:
    927  1.141  christos 		DPRINTF(("%s: set raw = %d\n", __func__, *(int *)data));
    928    1.2  augustss 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
    929   1.87  augustss #if defined(UKBD_REPEAT)
    930  1.108    dyoung 		callout_stop(&sc->sc_rawrepeat_ch);
    931   1.87  augustss #endif
    932  1.131     skrll 		return 0;
    933    1.2  augustss #endif
    934    1.2  augustss 	}
    935  1.131     skrll 	return EPASSTHROUGH;
    936    1.1  augustss }
    937    1.7  augustss 
    938   1.71  augustss /*
    939   1.71  augustss  * This is a hack to work around some broken ports that don't call
    940   1.71  augustss  * cnpollc() before cngetc().
    941   1.71  augustss  */
    942   1.71  augustss static int pollenter, warned;
    943   1.71  augustss 
    944    1.7  augustss /* Console interface. */
    945    1.3  augustss void
    946   1.60  augustss ukbd_cngetc(void *v, u_int *type, int *data)
    947    1.3  augustss {
    948    1.3  augustss 	struct ukbd_softc *sc = v;
    949    1.4  augustss 	int c;
    950   1.71  augustss 	int broken;
    951   1.71  augustss 
    952   1.71  augustss 	if (pollenter == 0) {
    953   1.71  augustss 		if (!warned) {
    954   1.71  augustss 			printf("\n"
    955   1.71  augustss "This port is broken, it does not call cnpollc() before calling cngetc().\n"
    956   1.71  augustss "This should be fixed, but it will work anyway (for now).\n");
    957   1.71  augustss 			warned = 1;
    958   1.71  augustss 		}
    959   1.71  augustss 		broken = 1;
    960   1.71  augustss 		ukbd_cnpollc(v, 1);
    961   1.71  augustss 	} else
    962   1.71  augustss 		broken = 0;
    963    1.3  augustss 
    964  1.141  christos 	DPRINTFN(0,("%s: enter\n", __func__));
    965  1.109       phx 	sc->sc_flags |= FLAG_POLLING;
    966  1.140  jmcneill 	if (sc->sc_npollchar <= 0)
    967   1.75  augustss 		usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
    968  1.109       phx 	sc->sc_flags &= ~FLAG_POLLING;
    969  1.140  jmcneill 	if (sc->sc_npollchar > 0) {
    970  1.140  jmcneill 		c = sc->sc_pollchars[0];
    971  1.140  jmcneill 		sc->sc_npollchar--;
    972  1.140  jmcneill 		memmove(sc->sc_pollchars, sc->sc_pollchars+1,
    973  1.140  jmcneill 		       sc->sc_npollchar * sizeof(uint16_t));
    974  1.140  jmcneill 		*type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
    975  1.140  jmcneill 		*data = c & CODEMASK;
    976  1.145  christos 		DPRINTFN(0,("%s: return 0x%02x\n", __func__, c));
    977  1.140  jmcneill 	} else {
    978  1.140  jmcneill 		*type = 0;
    979  1.140  jmcneill 		*data = 0;
    980  1.140  jmcneill 	}
    981   1.71  augustss 	if (broken)
    982   1.71  augustss 		ukbd_cnpollc(v, 0);
    983    1.3  augustss }
    984    1.3  augustss 
    985    1.3  augustss void
    986   1.60  augustss ukbd_cnpollc(void *v, int on)
    987    1.3  augustss {
    988    1.6  augustss 	struct ukbd_softc *sc = v;
    989  1.131     skrll 	struct usbd_device *dev;
    990    1.6  augustss 
    991  1.141  christos 	DPRINTFN(2,("%s: sc=%p on=%d\n", __func__, v, on));
    992    1.6  augustss 
    993   1.75  augustss 	usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
    994   1.84  augustss 	if (on) {
    995   1.84  augustss 		sc->sc_spl = splusb();
    996   1.84  augustss 		pollenter++;
    997   1.84  augustss 	} else {
    998   1.84  augustss 		splx(sc->sc_spl);
    999   1.84  augustss 		pollenter--;
   1000   1.84  augustss 	}
   1001   1.52  augustss 	usbd_set_polling(dev, on);
   1002    1.3  augustss }
   1003   1.18  augustss 
   1004   1.18  augustss int
   1005   1.60  augustss ukbd_cnattach(void)
   1006   1.18  augustss {
   1007   1.18  augustss 
   1008   1.31   thorpej 	/*
   1009   1.31   thorpej 	 * XXX USB requires too many parts of the kernel to be running
   1010   1.31   thorpej 	 * XXX in order to work, so we can't do much for the console
   1011   1.31   thorpej 	 * XXX keyboard until autconfiguration has run its course.
   1012   1.31   thorpej 	 */
   1013   1.31   thorpej 	ukbd_is_console = 1;
   1014  1.131     skrll 	return 0;
   1015   1.75  augustss }
   1016   1.75  augustss 
   1017   1.75  augustss const char *
   1018   1.75  augustss ukbd_parse_desc(struct ukbd_softc *sc)
   1019   1.75  augustss {
   1020   1.75  augustss 	struct hid_data *d;
   1021   1.75  augustss 	struct hid_item h;
   1022   1.75  augustss 	int size;
   1023   1.75  augustss 	void *desc;
   1024  1.138  jakllsch 	int ikey;
   1025   1.75  augustss 
   1026   1.75  augustss 	uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
   1027  1.138  jakllsch 	ikey = 0;
   1028   1.75  augustss 	sc->sc_nkeycode = 0;
   1029   1.75  augustss 	d = hid_start_parse(desc, size, hid_input);
   1030   1.75  augustss 	while (hid_get_item(d, &h)) {
   1031  1.144  christos 		/*printf("ukbd: id=%d kind=%d usage=%#x flags=%#x pos=%d size=%d cnt=%d\n",
   1032   1.75  augustss 		  h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
   1033  1.109       phx 
   1034  1.109       phx 		/* Check for special Apple notebook FN key */
   1035  1.109       phx 		if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff &&
   1036  1.109       phx 		    HID_GET_USAGE(h.usage) == 0x0003 &&
   1037  1.109       phx 		    h.kind == hid_input && (h.flags & HIO_VARIABLE)) {
   1038  1.109       phx 			sc->sc_flags |= FLAG_APPLE_FN;
   1039  1.109       phx 			sc->sc_apple_fn = h.loc;
   1040  1.109       phx 		}
   1041  1.109       phx 
   1042   1.75  augustss 		if (h.kind != hid_input || (h.flags & HIO_CONST) ||
   1043   1.75  augustss 		    HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
   1044   1.75  augustss 		    h.report_ID != sc->sc_hdev.sc_report_id)
   1045   1.75  augustss 			continue;
   1046  1.144  christos 		DPRINTF(("%s: ikey=%d usage=%#x flags=%#x pos=%d size=%d "
   1047  1.141  christos 		    "cnt=%d\n", __func__, ikey, h.usage, h.flags, h.loc.pos,
   1048  1.141  christos 		    h.loc.size, h.loc.count));
   1049   1.75  augustss 		if (h.flags & HIO_VARIABLE) {
   1050  1.137  jakllsch 			if (h.loc.size != 1) {
   1051  1.137  jakllsch 				hid_end_parse(d);
   1052  1.131     skrll 				return "bad modifier size";
   1053  1.137  jakllsch 			}
   1054   1.75  augustss 			/* Single item */
   1055  1.138  jakllsch 			if (ikey < MAXKEYS) {
   1056  1.138  jakllsch 				sc->sc_keyloc[ikey] = h.loc;
   1057  1.138  jakllsch 				sc->sc_keyuse[ikey] = HID_GET_USAGE(h.usage);
   1058  1.138  jakllsch 				ikey++;
   1059  1.137  jakllsch 			} else {
   1060  1.137  jakllsch 				hid_end_parse(d);
   1061  1.138  jakllsch 				return "too many Variable keys";
   1062  1.137  jakllsch 			}
   1063   1.75  augustss 		} else {
   1064   1.75  augustss 			/* Array */
   1065  1.137  jakllsch 			if (h.loc.size != 8) {
   1066  1.137  jakllsch 				hid_end_parse(d);
   1067  1.131     skrll 				return "key code size != 8";
   1068  1.137  jakllsch 			}
   1069   1.75  augustss 			if (h.loc.count > MAXKEYCODE)
   1070  1.110   mbalmer 				h.loc.count = MAXKEYCODE;
   1071  1.137  jakllsch 			if (h.loc.pos % 8 != 0) {
   1072  1.137  jakllsch 				hid_end_parse(d);
   1073  1.131     skrll 				return "key codes not on byte boundary";
   1074  1.137  jakllsch 			}
   1075  1.137  jakllsch 			if (sc->sc_nkeycode != 0) {
   1076  1.137  jakllsch 				hid_end_parse(d);
   1077  1.131     skrll 				return "multiple key code arrays";
   1078  1.137  jakllsch 			}
   1079   1.75  augustss 			sc->sc_keycodeloc = h.loc;
   1080   1.75  augustss 			sc->sc_nkeycode = h.loc.count;
   1081   1.75  augustss 		}
   1082   1.75  augustss 	}
   1083  1.138  jakllsch 	sc->sc_nkeyloc = ikey;
   1084   1.75  augustss 	hid_end_parse(d);
   1085   1.75  augustss 
   1086   1.75  augustss 	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
   1087   1.75  augustss 		   sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL);
   1088   1.75  augustss 	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
   1089   1.75  augustss 		   sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL);
   1090   1.75  augustss 	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
   1091   1.75  augustss 		   sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL);
   1092  1.121   khorben 	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_COMPOSE),
   1093  1.121   khorben 		   sc->sc_hdev.sc_report_id, hid_output, &sc->sc_compose, NULL);
   1094   1.75  augustss 
   1095  1.131     skrll 	return NULL;
   1096   1.18  augustss }
   1097