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