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