xref: /onnv-gate/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c (revision 10617:ae54b3d31f50)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51762Slt200341  * Common Development and Distribution License (the "License").
61762Slt200341  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229237SStrony.Zhang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * USB keyboard input streams module - processes USB keypacket
290Sstevel@tonic-gate  * received from HID driver below to either ASCII or event
300Sstevel@tonic-gate  * format for windowing system.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #define	KEYMAP_SIZE_VARIABLE
350Sstevel@tonic-gate #include <sys/usb/usba.h>
360Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
370Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
380Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
390Sstevel@tonic-gate #include <sys/stropts.h>
400Sstevel@tonic-gate #include <sys/stream.h>
410Sstevel@tonic-gate #include <sys/strsun.h>
420Sstevel@tonic-gate #include <sys/kbio.h>
430Sstevel@tonic-gate #include <sys/vuid_event.h>
440Sstevel@tonic-gate #include <sys/kbd.h>
450Sstevel@tonic-gate #include <sys/consdev.h>
460Sstevel@tonic-gate #include <sys/kbtrans.h>
470Sstevel@tonic-gate #include <sys/usb/clients/usbkbm/usbkbm.h>
480Sstevel@tonic-gate #include <sys/beep.h>
495129Smarx #include <sys/inttypes.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /* debugging information */
52880Sfrits uint_t	usbkbm_errmask = (uint_t)PRINT_MASK_ALL;
53880Sfrits uint_t	usbkbm_errlevel = USB_LOG_L2;
540Sstevel@tonic-gate static usb_log_handle_t usbkbm_log_handle;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate typedef void (*process_key_callback_t)(usbkbm_state_t *, int, enum keystate);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * Internal Function Prototypes
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate static void usbkbm_streams_setled(struct kbtrans_hardware *, int);
620Sstevel@tonic-gate static void usbkbm_polled_setled(struct kbtrans_hardware *, int);
630Sstevel@tonic-gate static boolean_t usbkbm_polled_keycheck(struct kbtrans_hardware *,
640Sstevel@tonic-gate 			int *, enum keystate *);
650Sstevel@tonic-gate static void usbkbm_poll_callback(usbkbm_state_t *, int, enum keystate);
660Sstevel@tonic-gate static void usbkbm_streams_callback(usbkbm_state_t *, int, enum keystate);
670Sstevel@tonic-gate static void usbkbm_unpack_usb_packet(usbkbm_state_t *, process_key_callback_t,
689607SPengcheng.Chen@Sun.COM 			uchar_t *);
690Sstevel@tonic-gate static boolean_t usbkbm_is_modkey(uchar_t);
700Sstevel@tonic-gate static void usbkbm_reioctl(void	*);
711762Slt200341 static int usbkbm_polled_getchar(cons_polledio_arg_t);
721762Slt200341 static boolean_t usbkbm_polled_ischar(cons_polledio_arg_t);
731762Slt200341 static void usbkbm_polled_enter(cons_polledio_arg_t);
741762Slt200341 static void usbkbm_polled_exit(cons_polledio_arg_t);
750Sstevel@tonic-gate static void usbkbm_mctl_receive(queue_t *, mblk_t *);
760Sstevel@tonic-gate static enum kbtrans_message_response usbkbm_ioctl(queue_t *, mblk_t *);
770Sstevel@tonic-gate static int usbkbm_kioccmd(usbkbm_state_t *, mblk_t *, char, size_t *);
780Sstevel@tonic-gate static void	usbkbm_usb2pc_xlate(usbkbm_state_t *, int, enum keystate);
790Sstevel@tonic-gate static void	usbkbm_wrap_kbtrans(usbkbm_state_t *, int, enum keystate);
809607SPengcheng.Chen@Sun.COM static int	usbkbm_get_input_format(usbkbm_state_t *);
819237SStrony.Zhang@Sun.COM static int	usbkbm_get_vid_pid(usbkbm_state_t *);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /* stream qinit functions defined here */
840Sstevel@tonic-gate static int	usbkbm_open(queue_t *, dev_t *, int, int, cred_t *);
850Sstevel@tonic-gate static int	usbkbm_close(queue_t *, int, cred_t *);
860Sstevel@tonic-gate static void	usbkbm_wput(queue_t *, mblk_t *);
870Sstevel@tonic-gate static void	usbkbm_rput(queue_t *, mblk_t *);
880Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *);
890Sstevel@tonic-gate static void	usbkbm_get_scancode(usbkbm_state_t *, int *, enum keystate *);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static struct keyboard *usbkbm_keyindex;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /* External Functions */
940Sstevel@tonic-gate extern void space_free(char *);
950Sstevel@tonic-gate extern uintptr_t space_fetch(char *);
960Sstevel@tonic-gate extern int space_store(char *, uintptr_t);
970Sstevel@tonic-gate extern struct keyboard *kbtrans_usbkb_maptab_init(void);
980Sstevel@tonic-gate extern void kbtrans_usbkb_maptab_fini(struct keyboard **);
990Sstevel@tonic-gate extern keymap_entry_t kbtrans_keycode_usb2pc(int);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Structure to setup callbacks
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate struct kbtrans_callbacks kbd_usb_callbacks = {
1050Sstevel@tonic-gate 	usbkbm_streams_setled,
1060Sstevel@tonic-gate 	usbkbm_polled_setled,
1070Sstevel@tonic-gate 	usbkbm_polled_keycheck,
1080Sstevel@tonic-gate };
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * Global Variables
1120Sstevel@tonic-gate  */
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /* This variable saves the LED state across hotplugging. */
1159237SStrony.Zhang@Sun.COM static uchar_t	usbkbm_led_state = 0;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /* This variable saves the layout state */
118918Sqz150045 static uint16_t usbkbm_layout = 0;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * Function pointer array for mapping of scancodes.
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate void (*usbkbm_xlate[2])(usbkbm_state_t *, int, enum keystate) = {
1240Sstevel@tonic-gate 	usbkbm_wrap_kbtrans,
1250Sstevel@tonic-gate 	usbkbm_usb2pc_xlate
1260Sstevel@tonic-gate };
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static struct streamtab usbkbm_info;
1290Sstevel@tonic-gate static struct fmodsw fsw = {
1300Sstevel@tonic-gate 	"usbkbm",
1310Sstevel@tonic-gate 	&usbkbm_info,
1320Sstevel@tonic-gate 	D_MP | D_MTPERMOD
1330Sstevel@tonic-gate };
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * Module linkage information for the kernel.
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
1400Sstevel@tonic-gate 	&mod_strmodops,
1417127Ssethg 	"USB keyboard streams 1.44",
1420Sstevel@tonic-gate 	&fsw
1430Sstevel@tonic-gate };
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static struct modlinkage modlinkage = {
1460Sstevel@tonic-gate 	MODREV_1,
1470Sstevel@tonic-gate 	(void *)&modlstrmod,
1480Sstevel@tonic-gate 	NULL
1490Sstevel@tonic-gate };
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate int
_init(void)1530Sstevel@tonic-gate _init(void)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	int	rval = mod_install(&modlinkage);
1560Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	if (rval != 0) {
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 		return (rval);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	usbkbm_keyindex = kbtrans_usbkb_maptab_init();
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	usbkbm_log_handle = usb_alloc_log_hdl(NULL, "usbkbm",
1665129Smarx 	    &usbkbm_errlevel, &usbkbm_errmask, NULL, 0);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	sp = (usbkbm_save_state_t *)space_fetch("SUNW,usbkbm_state");
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if (sp == NULL) {
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		return (0);
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/* Restore LED information */
1760Sstevel@tonic-gate 	usbkbm_led_state = sp->usbkbm_save_led;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* Restore the Layout */
1790Sstevel@tonic-gate 	usbkbm_layout = sp->usbkbm_layout;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/* Restore abort information */
1820Sstevel@tonic-gate 	usbkbm_keyindex->k_abort1 =
1835129Smarx 	    sp->usbkbm_save_keyindex.k_abort1;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	usbkbm_keyindex->k_abort2 =
1865129Smarx 	    sp->usbkbm_save_keyindex.k_abort2;
1873505Sqz150045 
1883505Sqz150045 	usbkbm_keyindex->k_newabort1 =
1895129Smarx 	    sp->usbkbm_save_keyindex.k_newabort1;
1903505Sqz150045 
1913505Sqz150045 	usbkbm_keyindex->k_newabort2 =
1925129Smarx 	    sp->usbkbm_save_keyindex.k_newabort2;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/* Restore keytables */
1950Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_normal,
1960Sstevel@tonic-gate 	    usbkbm_keyindex->k_normal, USB_KEYTABLE_SIZE);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_shifted,
1990Sstevel@tonic-gate 	    usbkbm_keyindex->k_shifted, USB_KEYTABLE_SIZE);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_caps,
2020Sstevel@tonic-gate 	    usbkbm_keyindex->k_caps, USB_KEYTABLE_SIZE);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_altgraph,
2050Sstevel@tonic-gate 	    usbkbm_keyindex->k_altgraph, USB_KEYTABLE_SIZE);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_numlock,
2080Sstevel@tonic-gate 	    usbkbm_keyindex->k_numlock, USB_KEYTABLE_SIZE);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_control,
2110Sstevel@tonic-gate 	    usbkbm_keyindex->k_control, USB_KEYTABLE_SIZE);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_up,
2140Sstevel@tonic-gate 	    usbkbm_keyindex->k_up, USB_KEYTABLE_SIZE);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_normal,
2175129Smarx 	    USB_KEYTABLE_SIZE);
2180Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_shifted,
2195129Smarx 	    USB_KEYTABLE_SIZE);
2200Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_caps,
2215129Smarx 	    USB_KEYTABLE_SIZE);
2220Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_altgraph,
2235129Smarx 	    USB_KEYTABLE_SIZE);
2240Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_numlock,
2255129Smarx 	    USB_KEYTABLE_SIZE);
2260Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_control,
2275129Smarx 	    USB_KEYTABLE_SIZE);
2280Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_up,
2295129Smarx 	    USB_KEYTABLE_SIZE);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	kmem_free(sp, sizeof (usbkbm_save_state_t));
2320Sstevel@tonic-gate 	space_free("SUNW,usbkbm_state");
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	return (0);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate int
_fini(void)2380Sstevel@tonic-gate _fini(void)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
2410Sstevel@tonic-gate 	int sval;
2420Sstevel@tonic-gate 	int rval;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (usbkbm_save_state_t), KM_SLEEP);
2450Sstevel@tonic-gate 	sval = space_store("SUNW,usbkbm_state", (uintptr_t)sp);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * If it's not possible to store the state, return
2490Sstevel@tonic-gate 	 * EBUSY.
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	if (sval != 0) {
2520Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		return (EBUSY);
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	rval = mod_remove(&modlinkage);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	if (rval != 0) {
2600Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2610Sstevel@tonic-gate 		space_free("SUNW,usbkbm_state");
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		return (rval);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	usb_free_log_hdl(usbkbm_log_handle);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/* Save the LED state */
2690Sstevel@tonic-gate 	sp->usbkbm_save_led = usbkbm_led_state;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/* Save the layout */
2727492SZhigang.Lu@Sun.COM 	sp->usbkbm_layout = (uchar_t)usbkbm_layout;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * Save entries of the keyboard structure that
2760Sstevel@tonic-gate 	 * have changed.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort1 = usbkbm_keyindex->k_abort1;
2790Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort2 = usbkbm_keyindex->k_abort2;
2800Sstevel@tonic-gate 
2813505Sqz150045 	sp->usbkbm_save_keyindex.k_newabort1 = usbkbm_keyindex->k_newabort1;
2823505Sqz150045 	sp->usbkbm_save_keyindex.k_newabort2 = usbkbm_keyindex->k_newabort2;
2833505Sqz150045 
2840Sstevel@tonic-gate 	/* Allocate space for keytables to be stored */
2850Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_normal =
2865129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2870Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_shifted =
2885129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2890Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_caps =
2905129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2910Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_altgraph =
2925129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2930Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_numlock =
2945129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2950Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_control =
2965129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2970Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_up =
2985129Smarx 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	/* Copy over the keytables */
3010Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_normal,
3020Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_normal, USB_KEYTABLE_SIZE);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_shifted,
3050Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_shifted, USB_KEYTABLE_SIZE);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_caps,
3080Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_caps, USB_KEYTABLE_SIZE);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_altgraph,
3110Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_altgraph, USB_KEYTABLE_SIZE);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_numlock,
3140Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_numlock, USB_KEYTABLE_SIZE);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_control,
3170Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_control, USB_KEYTABLE_SIZE);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_up,
3200Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_up, USB_KEYTABLE_SIZE);
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	kbtrans_usbkb_maptab_fini(&usbkbm_keyindex);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	return (0);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate int
_info(struct modinfo * modinfop)3280Sstevel@tonic-gate _info(struct modinfo *modinfop)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * Module qinit functions
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate static struct module_info usbkbm_minfo = {
3380Sstevel@tonic-gate 	0,		/* module id number */
3390Sstevel@tonic-gate 	"usbkbm",	/* module name */
3400Sstevel@tonic-gate 	0,		/* min packet size accepted */
3410Sstevel@tonic-gate 	INFPSZ,		/* max packet size accepted */
3420Sstevel@tonic-gate 	2048,		/* hi-water mark */
3430Sstevel@tonic-gate 	128		/* lo-water mark */
3440Sstevel@tonic-gate 	};
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate /* read side for key data and ioctl replies */
3470Sstevel@tonic-gate static struct qinit usbkbm_rinit = {
3480Sstevel@tonic-gate 	(int (*)())usbkbm_rput,
3490Sstevel@tonic-gate 	(int (*)())NULL,		/* service not used */
3500Sstevel@tonic-gate 	usbkbm_open,
3510Sstevel@tonic-gate 	usbkbm_close,
3520Sstevel@tonic-gate 	(int (*)())NULL,
3530Sstevel@tonic-gate 	&usbkbm_minfo
3540Sstevel@tonic-gate 	};
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate /* write side for ioctls */
3570Sstevel@tonic-gate static struct qinit usbkbm_winit = {
3580Sstevel@tonic-gate 	(int (*)())usbkbm_wput,
3590Sstevel@tonic-gate 	(int (*)())NULL,
3600Sstevel@tonic-gate 	usbkbm_open,
3610Sstevel@tonic-gate 	usbkbm_close,
3620Sstevel@tonic-gate 	(int (*)())NULL,
3630Sstevel@tonic-gate 	&usbkbm_minfo
3640Sstevel@tonic-gate 	};
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate static struct streamtab usbkbm_info = {
3670Sstevel@tonic-gate 	&usbkbm_rinit,
3680Sstevel@tonic-gate 	&usbkbm_winit,
3690Sstevel@tonic-gate 	NULL,		/* for muxes */
3700Sstevel@tonic-gate 	NULL,		/* for muxes */
3710Sstevel@tonic-gate };
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate  * usbkbm_open :
3750Sstevel@tonic-gate  *	Open a keyboard
3760Sstevel@tonic-gate  */
3770Sstevel@tonic-gate /* ARGSUSED */
3780Sstevel@tonic-gate static int
usbkbm_open(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)3790Sstevel@tonic-gate usbkbm_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
3820Sstevel@tonic-gate 	struct iocblk	mctlmsg;
3830Sstevel@tonic-gate 	mblk_t		*mctl_ptr;
3849432SPengcheng.Chen@Sun.COM 	uintptr_t	abortable = (uintptr_t)B_TRUE;
3850Sstevel@tonic-gate 	int		error, ret;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (q->q_ptr) {
3885129Smarx 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
3895129Smarx 		    "usbkbm_open already opened");
3900Sstevel@tonic-gate 
3915129Smarx 		return (0); /* already opened */
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	switch (sflag) {
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	case MODOPEN:
3970Sstevel@tonic-gate 		break;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	case CLONEOPEN:
4000Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4015129Smarx 		    "usbkbm_open: Clone open not supported");
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		/* FALLTHRU */
4040Sstevel@tonic-gate 	default:
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		return (EINVAL);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/* allocate usb keyboard state structure */
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	usbkbmd = kmem_zalloc(sizeof (usbkbm_state_t), KM_SLEEP);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4145129Smarx 	    "usbkbm_state= %p", (void *)usbkbmd);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * Set up private data.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	usbkbmd->usbkbm_readq = q;
4200Sstevel@tonic-gate 	usbkbmd->usbkbm_writeq = WR(q);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	usbkbmd->usbkbm_vkbd_type = KB_USB;
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
4250Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
4260Sstevel@tonic-gate 	 */
4270Sstevel@tonic-gate 	q->q_ptr = (caddr_t)usbkbmd;
4280Sstevel@tonic-gate 	WR(q)->q_ptr = (caddr_t)usbkbmd;
4290Sstevel@tonic-gate 
430*10617SPengcheng.Chen@Sun.COM 	error = kbtrans_streams_init(q, sflag,
4315129Smarx 	    (struct kbtrans_hardware *)usbkbmd, &kbd_usb_callbacks,
4325129Smarx 	    &usbkbmd->usbkbm_kbtrans, usbkbm_led_state, 0);
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (error != 0) {
4350Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4365129Smarx 		    "kbdopen:  kbtrans_streams_init failed\n");
4370Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 		return (error);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/*
4430Sstevel@tonic-gate 	 * Set the polled information in the state structure.
4440Sstevel@tonic-gate 	 * This information is set once, and doesn't change
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_version =
4475129Smarx 	    CONSPOLLEDIO_V1;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_argument =
4505129Smarx 	    (cons_polledio_arg_t)usbkbmd;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_putchar = NULL;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_getchar =
4555129Smarx 	    usbkbm_polled_getchar;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_ischar =
4585129Smarx 	    usbkbm_polled_ischar;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_enter =
4615129Smarx 	    usbkbm_polled_enter;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_exit =
4645129Smarx 	    usbkbm_polled_exit;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_setled =
4675129Smarx 	    (void (*)(cons_polledio_arg_t, int))usbkbm_polled_setled;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_keycheck =
4705129Smarx 	    (boolean_t (*)(cons_polledio_arg_t, int *,
4715129Smarx 	    enum keystate *))usbkbm_polled_keycheck;
4720Sstevel@tonic-gate 	/*
4730Sstevel@tonic-gate 	 * The head and the tail pointing at the same byte means empty or
4740Sstevel@tonic-gate 	 * full. usbkbm_polled_buffer_num_characters is used to
4750Sstevel@tonic-gate 	 * tell the difference.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head =
4785129Smarx 	    usbkbmd->usbkbm_polled_scancode_buffer;
4790Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail =
4805129Smarx 	    usbkbmd->usbkbm_polled_scancode_buffer;
4810Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters = 0;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	qprocson(q);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/* request hid report descriptor from HID */
4860Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
4870Sstevel@tonic-gate 	mctlmsg.ioc_count = 0;
4880Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
4890Sstevel@tonic-gate 	if (mctl_ptr == NULL) {
4900Sstevel@tonic-gate 		/* failure to allocate M_CTL message */
4910Sstevel@tonic-gate 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
4920Sstevel@tonic-gate 		qprocsoff(q);
4930Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		return (ENOMEM);
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/* send message to hid */
4990Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/*
5020Sstevel@tonic-gate 	 * Now that M_CTL has been sent, wait for report descriptor.  Cleanup
5030Sstevel@tonic-gate 	 * if user signals in the mean time (as when this gets opened in an
5040Sstevel@tonic-gate 	 * inappropriate context and the user types a ^C).
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
5070Sstevel@tonic-gate 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		if (qwait_sig(q) == 0) {
5100Sstevel@tonic-gate 			usbkbmd->usbkbm_flags = 0;
5110Sstevel@tonic-gate 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
5120Sstevel@tonic-gate 			qprocsoff(q);
5130Sstevel@tonic-gate 			kmem_free(usbkbmd, sizeof (*usbkbmd));
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 			return (EINTR);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 
5209607SPengcheng.Chen@Sun.COM 	/* get the input format from the hid descriptor */
5219607SPengcheng.Chen@Sun.COM 	if (usbkbm_get_input_format(usbkbmd) != USB_SUCCESS) {
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5241274Sqz150045 		    "usbkbm: Invalid HID Descriptor Tree."
5259607SPengcheng.Chen@Sun.COM 		    "setting default report format");
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
528918Sqz150045 	/*
529918Sqz150045 	 * Although Sun Japanese type6 and type7 keyboards have the same
530918Sqz150045 	 * layout number(15), they should be recognized for loading the
531918Sqz150045 	 * different keytables on upper apps (e.g. X). The new layout
532918Sqz150045 	 * number (271) is defined for the Sun Japanese type6 keyboards.
533918Sqz150045 	 * The layout number (15) specified in HID spec is used for other
534918Sqz150045 	 * Japanese keyboards. It is a workaround for the old Sun Japanese
535918Sqz150045 	 * type6 keyboards defect.
536918Sqz150045 	 */
537918Sqz150045 	if (usbkbmd->usbkbm_layout == SUN_JAPANESE_TYPE7) {
538918Sqz150045 
539918Sqz150045 		if ((ret = usbkbm_get_vid_pid(usbkbmd)) != 0) {
540918Sqz150045 
541918Sqz150045 			return (ret);
542918Sqz150045 		}
543918Sqz150045 
544918Sqz150045 		if ((usbkbmd->usbkbm_vid_pid.VendorId ==
5455129Smarx 		    HID_SUN_JAPANESE_TYPE6_KBD_VID) &&
5465129Smarx 		    (usbkbmd->usbkbm_vid_pid.ProductId ==
5475129Smarx 		    HID_SUN_JAPANESE_TYPE6_KBD_PID)) {
548918Sqz150045 			usbkbmd->usbkbm_layout = SUN_JAPANESE_TYPE6;
549918Sqz150045 		}
550918Sqz150045 	}
551918Sqz150045 
5520Sstevel@tonic-gate 	kbtrans_streams_set_keyboard(usbkbmd->usbkbm_kbtrans, KB_USB,
5535129Smarx 	    usbkbm_keyindex);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = USBKBM_OPEN;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	kbtrans_streams_enable(usbkbmd->usbkbm_kbtrans);
5580Sstevel@tonic-gate 
5599432SPengcheng.Chen@Sun.COM 	/*
5609432SPengcheng.Chen@Sun.COM 	 * Enable abort sequence on inital. For an internal open, conskbd
5619432SPengcheng.Chen@Sun.COM 	 * will disable driver abort handling (later through M_IOCTL) and
5629432SPengcheng.Chen@Sun.COM 	 * handle it by itself.
5639432SPengcheng.Chen@Sun.COM 	 * For an external (aka. physical) open, this is necessary since
5649432SPengcheng.Chen@Sun.COM 	 * no STREAMS module linked on top of usbkbm handles abort sequence.
5659432SPengcheng.Chen@Sun.COM 	 */
5669432SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_cmd = CONSSETABORTENABLE;
5679432SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_count = TRANSPARENT;
5689432SPengcheng.Chen@Sun.COM 	mctl_ptr = usba_mk_mctl(mctlmsg, &abortable, sizeof (abortable));
5699432SPengcheng.Chen@Sun.COM 	if (mctl_ptr != NULL) {
5709432SPengcheng.Chen@Sun.COM 		DB_TYPE(mctl_ptr) = M_IOCTL;
5719432SPengcheng.Chen@Sun.COM 		if (kbtrans_streams_message(usbkbmd->usbkbm_kbtrans, mctl_ptr)
5729432SPengcheng.Chen@Sun.COM 		    != KBTRANS_MESSAGE_HANDLED) {
5739432SPengcheng.Chen@Sun.COM 			freemsg(mctl_ptr);
5749432SPengcheng.Chen@Sun.COM 		}
5759432SPengcheng.Chen@Sun.COM 	} else {
5769432SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5779432SPengcheng.Chen@Sun.COM 		    "usbkbm: enable abort sequence failed");
5789432SPengcheng.Chen@Sun.COM 	}
5799432SPengcheng.Chen@Sun.COM 
5800Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5815129Smarx 	    "usbkbm_open exiting");
5820Sstevel@tonic-gate 	return (0);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate  * usbkbm_close :
5880Sstevel@tonic-gate  *	Close a keyboard.
5890Sstevel@tonic-gate  */
5900Sstevel@tonic-gate /* ARGSUSED1 */
5910Sstevel@tonic-gate static int
usbkbm_close(register queue_t * q,int flag,cred_t * crp)5920Sstevel@tonic-gate usbkbm_close(register queue_t *q, int flag, cred_t *crp)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate 	usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/* If a beep is in progress, stop that */
5975129Smarx 	(void) beeper_off();
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	qprocsoff(q);
6020Sstevel@tonic-gate 	/*
6030Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
6040Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
6050Sstevel@tonic-gate 	 * and try to use that data.
6060Sstevel@tonic-gate 	 */
6070Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = 0;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	kmem_free(usbkbmd, sizeof (usbkbm_state_t));
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbkbm_log_handle,
6125129Smarx 	    "usbkbm_close exiting");
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	return (0);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /*
6190Sstevel@tonic-gate  * usbkbm_wput :
6200Sstevel@tonic-gate  *	usb keyboard module output queue put procedure: handles M_IOCTL
6210Sstevel@tonic-gate  *	messages.
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate static void
usbkbm_wput(register queue_t * q,register mblk_t * mp)6240Sstevel@tonic-gate usbkbm_wput(register queue_t *q, register mblk_t *mp)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
6270Sstevel@tonic-gate 	enum kbtrans_message_response	ret;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6305129Smarx 	    "usbkbm_wput entering");
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/* First, see if kbtrans will handle the message */
6350Sstevel@tonic-gate 	ret = kbtrans_streams_message(usbkbmd->usbkbm_kbtrans, mp);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	if (ret == KBTRANS_MESSAGE_HANDLED) {
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6405129Smarx 		    "usbkbm_wput exiting:2");
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		return;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	/* kbtrans didn't handle the message.  Try to handle it here */
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	case M_FLUSH:
6500Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
6510Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
6520Sstevel@tonic-gate 		}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
6550Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
6560Sstevel@tonic-gate 		}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		break;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	case M_IOCTL:
6610Sstevel@tonic-gate 		ret = usbkbm_ioctl(q, mp);
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		if (ret == KBTRANS_MESSAGE_HANDLED) {
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6665129Smarx 			    "usbkbm_wput exiting:1");
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 			return;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 	default:
6710Sstevel@tonic-gate 		break;
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 * The message has not been handled
6760Sstevel@tonic-gate 	 * by kbtrans or this module.  Pass it down the stream
6770Sstevel@tonic-gate 	 */
6780Sstevel@tonic-gate 	putnext(q, mp);
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6815129Smarx 	    "usbkbm_wput exiting:3");
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * usbkbm_ioctl :
6860Sstevel@tonic-gate  *	Handles the ioctls sent from upper module. Returns
6870Sstevel@tonic-gate  *	ACK/NACK back.
6880Sstevel@tonic-gate  */
6890Sstevel@tonic-gate static enum kbtrans_message_response
usbkbm_ioctl(register queue_t * q,register mblk_t * mp)6900Sstevel@tonic-gate usbkbm_ioctl(register queue_t *q, register mblk_t *mp)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
6930Sstevel@tonic-gate 	struct iocblk		mctlmsg;
6940Sstevel@tonic-gate 	struct iocblk		*iocp;
6950Sstevel@tonic-gate 	mblk_t			*datap, *mctl_ptr;
6960Sstevel@tonic-gate 	size_t			ioctlrespsize;
6970Sstevel@tonic-gate 	int			err;
6980Sstevel@tonic-gate 	int			tmp;
6995129Smarx 	int			cycles;
7005129Smarx 	int			frequency;
7015129Smarx 	int			msecs;
7020Sstevel@tonic-gate 	char			command;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	err = 0;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
7070Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
7100Sstevel@tonic-gate 	case CONSSETKBDTYPE:
7110Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7120Sstevel@tonic-gate 		if (err != 0) {
7130Sstevel@tonic-gate 			break;
7140Sstevel@tonic-gate 		}
7150Sstevel@tonic-gate 		tmp = *(int *)mp->b_cont->b_rptr;
7160Sstevel@tonic-gate 		if (tmp != KB_PC && tmp != KB_USB) {
7170Sstevel@tonic-gate 			err = EINVAL;
7180Sstevel@tonic-gate 			break;
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 		usbkbmd->usbkbm_vkbd_type = tmp;
7210Sstevel@tonic-gate 		break;
7220Sstevel@tonic-gate 	case KIOCLAYOUT:
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		datap = allocb(sizeof (int), BPRI_HI);
7250Sstevel@tonic-gate 		if (datap == NULL) {
7260Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 			goto allocfailure;
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 		*(int *)datap->b_wptr = usbkbmd->usbkbm_layout;
7320Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		freemsg(mp->b_cont);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		mp->b_cont = datap;
7370Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7380Sstevel@tonic-gate 		break;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	case KIOCSLAYOUT:
7410Sstevel@tonic-gate 		/*
7420Sstevel@tonic-gate 		 * Supply a layout if not specified by the hardware, or
7430Sstevel@tonic-gate 		 * override any that was specified.
7440Sstevel@tonic-gate 		 */
7450Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
7460Sstevel@tonic-gate 			err = EINVAL;
7470Sstevel@tonic-gate 			break;
7480Sstevel@tonic-gate 		}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		usbkbmd->usbkbm_layout = *(intptr_t *)mp->b_cont->b_rptr;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		/*
7530Sstevel@tonic-gate 		 * Save the layout in usbkbm_layout so as to handle the
7540Sstevel@tonic-gate 		 * the case when the user has re-plugged in the non-self
7550Sstevel@tonic-gate 		 * identifying non US keyboard. In this the layout is saved
7560Sstevel@tonic-gate 		 * in global variable, so the user does not have to run
7570Sstevel@tonic-gate 		 * kdmconfig again after the X server reset
7580Sstevel@tonic-gate 		 */
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 		usbkbm_layout = usbkbmd->usbkbm_layout;
7610Sstevel@tonic-gate 		break;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	case KIOCCMD:
7640Sstevel@tonic-gate 		/*
7650Sstevel@tonic-gate 		 * Check if we have at least the subcommand field; any
7660Sstevel@tonic-gate 		 * other argument validation has to occur inside
7670Sstevel@tonic-gate 		 * usbkbm_kioccmd().
7680Sstevel@tonic-gate 		 */
7690Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7700Sstevel@tonic-gate 		if (err != 0)
7710Sstevel@tonic-gate 			break;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 		/* Subcommand */
7740Sstevel@tonic-gate 		command = (char)(*(int *)mp->b_cont->b_rptr);
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 		/*
7770Sstevel@tonic-gate 		 * Check if this ioctl is followed by a previous
7780Sstevel@tonic-gate 		 * KBD_CMD_SETLED command, in which case we take
7790Sstevel@tonic-gate 		 * the command byte as the data for setting the LED
7800Sstevel@tonic-gate 		 */
7810Sstevel@tonic-gate 		if (usbkbmd->usbkbm_setled_second_byte) {
7820Sstevel@tonic-gate 			usbkbm_streams_setled((struct kbtrans_hardware *)
7835129Smarx 			    usbkbmd, command);
7840Sstevel@tonic-gate 			usbkbmd->usbkbm_setled_second_byte = 0;
7850Sstevel@tonic-gate 			break;
7860Sstevel@tonic-gate 		}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 		/*
7890Sstevel@tonic-gate 		 * In  case of allocb failure, this will
7900Sstevel@tonic-gate 		 * return the size of the allocation which
7910Sstevel@tonic-gate 		 * failed so that it can be allocated later
7920Sstevel@tonic-gate 		 * through bufcall.
7930Sstevel@tonic-gate 		 */
7940Sstevel@tonic-gate 		ioctlrespsize = 0;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		err = usbkbm_kioccmd(usbkbmd, mp, command, &ioctlrespsize);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 		if (ioctlrespsize != 0) {
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 			goto allocfailure;
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		break;
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	case CONSOPENPOLLEDIO:
8060Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8075129Smarx 		    "usbkbm_ioctl CONSOPENPOLLEDIO");
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct cons_polledio *));
8100Sstevel@tonic-gate 		if (err != 0) {
8110Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, usbkbm_log_handle,
8120Sstevel@tonic-gate 			    "usbkbm_ioctl: malformed request");
8130Sstevel@tonic-gate 			break;
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		/*
8190Sstevel@tonic-gate 		 * Get the polled input structure from hid
8200Sstevel@tonic-gate 		 */
8210Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_OPEN_POLLED_INPUT;
8220Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8230Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8240Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8250Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 			goto allocfailure;
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 		/*
8330Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8340Sstevel@tonic-gate 		 * result of HID_OPEN_POLLED_INPUT
8350Sstevel@tonic-gate 		 */
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	case CONSCLOSEPOLLEDIO:
8400Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8415129Smarx 		    "usbkbm_ioctl CONSCLOSEPOLLEDIO mp = 0x%p", (void *)mp);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 		/*
8460Sstevel@tonic-gate 		 * Get the polled input structure from hid
8470Sstevel@tonic-gate 		 */
8480Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_CLOSE_POLLED_INPUT;
8490Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8500Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8510Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8520Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 			goto allocfailure;
8550Sstevel@tonic-gate 		}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		/*
8600Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8610Sstevel@tonic-gate 		 * result of HID_CLOSE_POLLED_INPUT
8620Sstevel@tonic-gate 		 */
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	case CONSSETABORTENABLE:
8670Sstevel@tonic-gate 		/*
8680Sstevel@tonic-gate 		 * Nothing special to do for USB.
8690Sstevel@tonic-gate 		 */
8700Sstevel@tonic-gate 		break;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 
8735129Smarx 	case KIOCMKTONE:
8745129Smarx 		if (iocp->ioc_count != TRANSPARENT) {
8755129Smarx 			err = EINVAL;
8765129Smarx 			break;
8775129Smarx 		}
8785129Smarx 
8795129Smarx 		tmp = (int)(*(intptr_t *)mp->b_cont->b_rptr);
8805129Smarx 		cycles = tmp & 0xffff;
8815129Smarx 		msecs = (tmp >> 16) & 0xffff;
8825129Smarx 
8835129Smarx 		if (cycles == 0)
8845129Smarx 			frequency = UINT16_MAX;
8855129Smarx 		else if (cycles == UINT16_MAX)
8865129Smarx 			frequency = 0;
8875129Smarx 		else {
8885129Smarx 			frequency = (PIT_HZ + cycles / 2) / cycles;
8895129Smarx 			if (frequency > UINT16_MAX)
8905129Smarx 				frequency = UINT16_MAX;
8915129Smarx 		}
8925129Smarx 
8935129Smarx 		err = beep_mktone(frequency, msecs);
8945129Smarx 		break;
8955129Smarx 
8960Sstevel@tonic-gate 	default:
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_NOT_HANDLED);
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * Send ACK/NACK to upper module for
9030Sstevel@tonic-gate 	 * the messages that have been handled.
9040Sstevel@tonic-gate 	 */
9050Sstevel@tonic-gate 	if (err != 0) {
9060Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9070Sstevel@tonic-gate 		iocp->ioc_error = err;
9080Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
9090Sstevel@tonic-gate 	} else {
9100Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9110Sstevel@tonic-gate 		iocp->ioc_error = 0;	/* brain rot */
9120Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	/* Send the response back up the stream */
9160Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_readq, mp);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	return (KBTRANS_MESSAGE_HANDLED);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate allocfailure:
9210Sstevel@tonic-gate 	/*
9220Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
9230Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
9240Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
9250Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
9260Sstevel@tonic-gate 	 * must have timed out.
9270Sstevel@tonic-gate 	 */
9280Sstevel@tonic-gate 	freemsg(usbkbmd->usbkbm_streams_iocpending);
9290Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_iocpending = mp;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	if (usbkbmd->usbkbm_streams_bufcallid) {
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		qunbufcall(usbkbmd->usbkbm_readq,
9345129Smarx 		    usbkbmd->usbkbm_streams_bufcallid);
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_bufcallid =
9375129Smarx 	    qbufcall(usbkbmd->usbkbm_readq, ioctlrespsize, BPRI_HI,
9385129Smarx 	    usbkbm_reioctl, usbkbmd);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	return (KBTRANS_MESSAGE_HANDLED);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate /*
9440Sstevel@tonic-gate  * usbkbm_kioccmd :
9450Sstevel@tonic-gate  *	Handles KIOCCMD ioctl.
9460Sstevel@tonic-gate  */
9470Sstevel@tonic-gate static int
usbkbm_kioccmd(usbkbm_state_t * usbkbmd,register mblk_t * mp,char command,size_t * ioctlrepsize)9480Sstevel@tonic-gate usbkbm_kioccmd(usbkbm_state_t *usbkbmd, register mblk_t *mp,
9490Sstevel@tonic-gate 		char command, size_t *ioctlrepsize)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate 	register mblk_t			*datap;
9520Sstevel@tonic-gate 	register struct iocblk		*iocp;
9530Sstevel@tonic-gate 	int				err = 0;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	switch (command) {
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 		/* Keyboard layout command */
9600Sstevel@tonic-gate 		case KBD_CMD_GETLAYOUT:
9610Sstevel@tonic-gate 			/* layout learned at attached time. */
9620Sstevel@tonic-gate 			datap = allocb(sizeof (int), BPRI_HI);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 			/* Return error  on allocation failure */
9650Sstevel@tonic-gate 			if (datap == NULL) {
9660Sstevel@tonic-gate 				*ioctlrepsize = sizeof (int);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 				return (EIO);
9690Sstevel@tonic-gate 			}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 			*(int *)datap->b_wptr = usbkbmd->usbkbm_layout;
9720Sstevel@tonic-gate 			datap->b_wptr += sizeof (int);
9730Sstevel@tonic-gate 			freemsg(mp->b_cont);
9740Sstevel@tonic-gate 			mp->b_cont = datap;
9750Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
9760Sstevel@tonic-gate 			break;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 		case KBD_CMD_SETLED:
9790Sstevel@tonic-gate 			/*
9800Sstevel@tonic-gate 			 * Emulate type 4 keyboard :
9810Sstevel@tonic-gate 			 * Ignore this ioctl; the following
9820Sstevel@tonic-gate 			 * ioctl will specify the data byte for
9830Sstevel@tonic-gate 			 * setting the LEDs; setting usbkbm_setled_second_byte
9840Sstevel@tonic-gate 			 * will help recognizing that ioctl
9850Sstevel@tonic-gate 			 */
9860Sstevel@tonic-gate 			usbkbmd->usbkbm_setled_second_byte = 1;
9870Sstevel@tonic-gate 			break;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 		case KBD_CMD_RESET:
9900Sstevel@tonic-gate 			break;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 		case KBD_CMD_BELL:
9930Sstevel@tonic-gate 			/*
9940Sstevel@tonic-gate 			 * USB keyboards do not have a beeper
9950Sstevel@tonic-gate 			 * in it, the generic beeper interface
9960Sstevel@tonic-gate 			 * is used. Turn the beeper on.
9970Sstevel@tonic-gate 			 */
9985129Smarx 			(void) beeper_on(BEEP_TYPE4);
9990Sstevel@tonic-gate 			break;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		case KBD_CMD_NOBELL:
10020Sstevel@tonic-gate 			/*
10030Sstevel@tonic-gate 			 * USB keyboards do not have a beeper
10040Sstevel@tonic-gate 			 * in it, the generic beeper interface
10050Sstevel@tonic-gate 			 * is used. Turn the beeper off.
10060Sstevel@tonic-gate 			 */
10075129Smarx 			(void) beeper_off();
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 		case KBD_CMD_CLICK:
10110Sstevel@tonic-gate 			/* FALLTHRU */
10120Sstevel@tonic-gate 		case KBD_CMD_NOCLICK:
10130Sstevel@tonic-gate 			break;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 		default:
10160Sstevel@tonic-gate 			err = EIO;
10170Sstevel@tonic-gate 			break;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	return (err);
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate /*
10260Sstevel@tonic-gate  * usbkbm_rput :
10270Sstevel@tonic-gate  *	Put procedure for input from driver end of stream (read queue).
10280Sstevel@tonic-gate  */
10290Sstevel@tonic-gate static void
usbkbm_rput(register queue_t * q,register mblk_t * mp)10300Sstevel@tonic-gate usbkbm_rput(register queue_t *q, register mblk_t *mp)
10310Sstevel@tonic-gate {
10320Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
10375129Smarx 	    "usbkbm_rput");
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if (usbkbmd == 0) {
10400Sstevel@tonic-gate 		freemsg(mp);	/* nobody's listening */
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 		return;
10430Sstevel@tonic-gate 	}
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	case M_FLUSH:
10480Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
10490Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
10500Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
10510Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		freemsg(mp);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		return;
10560Sstevel@tonic-gate 	case M_BREAK:
10570Sstevel@tonic-gate 		/*
10580Sstevel@tonic-gate 		 * Will get M_BREAK only if this is not the system
10590Sstevel@tonic-gate 		 * keyboard, otherwise serial port will eat break
10600Sstevel@tonic-gate 		 * and call kmdb/OBP, without passing anything up.
10610Sstevel@tonic-gate 		 */
10620Sstevel@tonic-gate 		freemsg(mp);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		return;
10650Sstevel@tonic-gate 	case M_DATA:
10660Sstevel@tonic-gate 		if (!(usbkbmd->usbkbm_flags & USBKBM_OPEN)) {
10670Sstevel@tonic-gate 			freemsg(mp);	/* not ready to listen */
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 			return;
10700Sstevel@tonic-gate 		}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 		break;
10730Sstevel@tonic-gate 	case M_CTL:
10740Sstevel@tonic-gate 		usbkbm_mctl_receive(q, mp);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 		return;
10770Sstevel@tonic-gate 	case M_ERROR:
10780Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
10799432SPengcheng.Chen@Sun.COM 		if (*mp->b_rptr == ENODEV) {
10809432SPengcheng.Chen@Sun.COM 			putnext(q, mp);
10819432SPengcheng.Chen@Sun.COM 		} else {
10829432SPengcheng.Chen@Sun.COM 			freemsg(mp);
10839432SPengcheng.Chen@Sun.COM 		}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 		return;
10860Sstevel@tonic-gate 	case M_IOCACK:
10870Sstevel@tonic-gate 	case M_IOCNAK:
10880Sstevel@tonic-gate 		putnext(q, mp);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		return;
10910Sstevel@tonic-gate 	default:
10920Sstevel@tonic-gate 		putnext(q, mp);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 		return;
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/*
10980Sstevel@tonic-gate 	 * A data message, consisting of bytes from the keyboard.
10990Sstevel@tonic-gate 	 * Ram them through the translator, only if there are
11000Sstevel@tonic-gate 	 * correct no. of bytes.
11010Sstevel@tonic-gate 	 */
11029607SPengcheng.Chen@Sun.COM 	if (MBLKL(mp) == usbkbmd->usbkbm_report_format.tlen) {
11039607SPengcheng.Chen@Sun.COM 		if (usbkbmd->usbkbm_report_format.keyid !=
11049607SPengcheng.Chen@Sun.COM 		    HID_REPORT_ID_UNDEFINED) {
11059607SPengcheng.Chen@Sun.COM 			if (*(mp->b_rptr) !=
11069607SPengcheng.Chen@Sun.COM 			    usbkbmd->usbkbm_report_format.keyid) {
11079607SPengcheng.Chen@Sun.COM 				freemsg(mp);
11089607SPengcheng.Chen@Sun.COM 
11099607SPengcheng.Chen@Sun.COM 				return;
11109607SPengcheng.Chen@Sun.COM 			} else {
11119607SPengcheng.Chen@Sun.COM 				/* We skip the report id prefix */
11129607SPengcheng.Chen@Sun.COM 				mp->b_rptr++;
11139607SPengcheng.Chen@Sun.COM 			}
11149607SPengcheng.Chen@Sun.COM 		}
11150Sstevel@tonic-gate 		usbkbm_unpack_usb_packet(usbkbmd, usbkbm_streams_callback,
11169607SPengcheng.Chen@Sun.COM 		    mp->b_rptr);
11170Sstevel@tonic-gate 	}
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	freemsg(mp);
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate /*
11230Sstevel@tonic-gate  * usbkbm_mctl_receive :
11240Sstevel@tonic-gate  *	Handle M_CTL messages from hid. If we don't understand
11250Sstevel@tonic-gate  *	the command, send it up.
11260Sstevel@tonic-gate  */
11270Sstevel@tonic-gate static void
usbkbm_mctl_receive(register queue_t * q,register mblk_t * mp)11280Sstevel@tonic-gate usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate 	register usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
11319237SStrony.Zhang@Sun.COM 	register struct iocblk *iocp;
11320Sstevel@tonic-gate 	caddr_t  data = NULL;
11339237SStrony.Zhang@Sun.COM 	mblk_t	*reply_mp;
11340Sstevel@tonic-gate 	uchar_t	new_buffer[USBKBM_MAXPKTSIZE];
11359237SStrony.Zhang@Sun.COM 	size_t	 size;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
11380Sstevel@tonic-gate 	if (mp->b_cont != NULL)
11390Sstevel@tonic-gate 		data = (caddr_t)mp->b_cont->b_rptr;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	case HID_SET_REPORT:
11440Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
11455129Smarx 		    "usbkbm_mctl_receive HID_SET mctl");
11460Sstevel@tonic-gate 		freemsg(mp);
11470Sstevel@tonic-gate 		/* Setting of the LED is not waiting for this message */
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		break;
11500Sstevel@tonic-gate 	case HID_GET_PARSER_HANDLE:
11510Sstevel@tonic-gate 		if ((data != NULL) &&
11520Sstevel@tonic-gate 		    (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
11537492SZhigang.Lu@Sun.COM 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
11540Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr =
11550Sstevel@tonic-gate 			    *(hidparser_handle_t *)data;
11560Sstevel@tonic-gate 		} else {
11570Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr = NULL;
11580Sstevel@tonic-gate 		}
11590Sstevel@tonic-gate 		freemsg(mp);
11600Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 		break;
1163918Sqz150045 	case HID_GET_VID_PID:
1164918Sqz150045 		if ((data != NULL) &&
1165918Sqz150045 		    (iocp->ioc_count == sizeof (hid_vid_pid_t)) &&
11667492SZhigang.Lu@Sun.COM 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1167918Sqz150045 			bcopy(data, &usbkbmd->usbkbm_vid_pid, iocp->ioc_count);
1168918Sqz150045 		}
1169918Sqz150045 		freemsg(mp);
1170918Sqz150045 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
1171918Sqz150045 
1172918Sqz150045 		break;
11730Sstevel@tonic-gate 	case HID_OPEN_POLLED_INPUT:
11740Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
11755129Smarx 		    "usbkbm_mctl_receive HID_OPEN_POLLED_INPUT");
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 		size = sizeof (hid_polled_input_callback_t);
11780Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
11790Sstevel@tonic-gate 		if ((data != NULL) &&
11800Sstevel@tonic-gate 		    (iocp->ioc_count == size) &&
11817492SZhigang.Lu@Sun.COM 		    (MBLKL(mp->b_cont) == size)) {
11820Sstevel@tonic-gate 			/*
11830Sstevel@tonic-gate 			 *  Copy the information from hid into the
11840Sstevel@tonic-gate 			 * state structure
11850Sstevel@tonic-gate 			 */
11860Sstevel@tonic-gate 			bcopy(data, &usbkbmd->usbkbm_hid_callback, size);
11870Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCACK;
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 			/*
11900Sstevel@tonic-gate 			 * We are given an appropriate-sized data block,
11910Sstevel@tonic-gate 			 * and return a pointer to our structure in it.
11920Sstevel@tonic-gate 			 * The structure is saved in the states structure
11930Sstevel@tonic-gate 			 */
11940Sstevel@tonic-gate 			*(cons_polledio_t **)reply_mp->b_cont->b_rptr =
11955129Smarx 			    &usbkbmd->usbkbm_polled_info;
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 		} else {
11980Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCNAK;
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 		freemsg(mp);
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		putnext(q, reply_mp);
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 		break;
12070Sstevel@tonic-gate 	case HID_CLOSE_POLLED_INPUT:
12080Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12095129Smarx 		    "usbkbm_mctl_receive HID_CLOSE_POLLED_INPUT");
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		bzero(&usbkbmd->usbkbm_hid_callback,
12135129Smarx 		    sizeof (hid_polled_input_callback_t));
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 		freemsg(mp);
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 		iocp = (struct iocblk *)reply_mp->b_rptr;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12225129Smarx 		    "usbkbm_mctl_receive reply reply_mp 0x%p cmd 0x%x",
12235129Smarx 		    (void *)reply_mp, iocp->ioc_cmd);
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 		reply_mp->b_datap->db_type = M_IOCACK;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		putnext(q, reply_mp);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 		break;
12330Sstevel@tonic-gate 	case HID_DISCONNECT_EVENT :
12340Sstevel@tonic-gate 	case HID_POWER_OFF:
12350Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12360Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_DISCONNECT_EVENT/HID_POWER_OFF");
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 		/* Indicate all keys have been released */
12390Sstevel@tonic-gate 		bzero(new_buffer, USBKBM_MAXPKTSIZE);
12400Sstevel@tonic-gate 		usbkbm_unpack_usb_packet(usbkbmd, usbkbm_streams_callback,
12419607SPengcheng.Chen@Sun.COM 		    new_buffer);
12420Sstevel@tonic-gate 		freemsg(mp);
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 		break;
12450Sstevel@tonic-gate 	case HID_CONNECT_EVENT:
12460Sstevel@tonic-gate 	case HID_FULL_POWER :
12470Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12485129Smarx 		    "usbkbm_mctl_receive restore LEDs");
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 		/* send setled command down to restore LED states */
12510Sstevel@tonic-gate 		usbkbm_streams_setled((struct kbtrans_hardware *)usbkbmd,
12525129Smarx 		    usbkbm_led_state);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		freemsg(mp);
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 		break;
12570Sstevel@tonic-gate 	default:
12580Sstevel@tonic-gate 		putnext(q, mp);
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 		break;
12610Sstevel@tonic-gate 	}
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate /*
12660Sstevel@tonic-gate  * usbkbm_streams_setled :
12670Sstevel@tonic-gate  *	Update the keyboard LEDs to match the current keyboard state.
12680Sstevel@tonic-gate  *	Send LED state downstreams to hid driver.
12690Sstevel@tonic-gate  */
12700Sstevel@tonic-gate static void
usbkbm_streams_setled(struct kbtrans_hardware * kbtrans_hw,int state)12710Sstevel@tonic-gate usbkbm_streams_setled(struct kbtrans_hardware *kbtrans_hw, int state)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	struct iocblk	mctlmsg;
12742278Sgc161489 	mblk_t		*mctl_ptr;
12750Sstevel@tonic-gate 	hid_req_t	*LED_report;
12760Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
12779607SPengcheng.Chen@Sun.COM 	uchar_t		led_id, led_state;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	usbkbm_led_state = (uchar_t)state;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)kbtrans_hw;
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	LED_report = kmem_zalloc(sizeof (hid_req_t), KM_NOSLEEP);
12840Sstevel@tonic-gate 	if (LED_report == NULL) {
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 		return;
12870Sstevel@tonic-gate 	}
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	/*
12900Sstevel@tonic-gate 	 * Send the request to the hid driver to set LED.
12910Sstevel@tonic-gate 	 */
12929607SPengcheng.Chen@Sun.COM 	led_id = usbkbmd->usbkbm_report_format.keyid;
12930Sstevel@tonic-gate 	led_state = 0;
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	/*
12960Sstevel@tonic-gate 	 * Set the led state based on the state that is passed in.
12970Sstevel@tonic-gate 	 */
12980Sstevel@tonic-gate 	if (state & LED_NUM_LOCK) {
12990Sstevel@tonic-gate 		led_state |= USB_LED_NUM_LOCK;
13000Sstevel@tonic-gate 	}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	if (state & LED_COMPOSE) {
13030Sstevel@tonic-gate 		led_state |= USB_LED_COMPOSE;
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	if (state & LED_SCROLL_LOCK) {
13070Sstevel@tonic-gate 		led_state |= USB_LED_SCROLL_LOCK;
13080Sstevel@tonic-gate 	}
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	if (state & LED_CAPS_LOCK) {
13110Sstevel@tonic-gate 		led_state |= USB_LED_CAPS_LOCK;
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if (state & LED_KANA) {
13150Sstevel@tonic-gate 		led_state |= USB_LED_KANA;
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	LED_report->hid_req_version_no = HID_VERSION_V_0;
13199607SPengcheng.Chen@Sun.COM 	LED_report->hid_req_wValue = REPORT_TYPE_OUTPUT | led_id;
13200Sstevel@tonic-gate 	LED_report->hid_req_wLength = sizeof (uchar_t);
13212278Sgc161489 	LED_report->hid_req_data[0] = led_state;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_SET_REPORT;
13240Sstevel@tonic-gate 	mctlmsg.ioc_count = sizeof (LED_report);
13250Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, LED_report, sizeof (hid_req_t));
13260Sstevel@tonic-gate 	if (mctl_ptr != NULL) {
13270Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * We are not waiting for response of HID_SET_REPORT
13320Sstevel@tonic-gate 	 * mctl for setting the LED.
13330Sstevel@tonic-gate 	 */
13340Sstevel@tonic-gate 	kmem_free(LED_report, sizeof (hid_req_t));
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate /*
13390Sstevel@tonic-gate  * usbkbm_polled_keycheck :
13400Sstevel@tonic-gate  *	This routine is called to determine if there is a scancode that
13410Sstevel@tonic-gate  *	is available for input.  This routine is called at poll time and
13420Sstevel@tonic-gate  *	returns a key/state pair to the caller.  If there are characters
13430Sstevel@tonic-gate  *	buffered up, the routine returns right away with the key/state pair.
13440Sstevel@tonic-gate  *	Otherwise, the routine calls down to check for characters and returns
13450Sstevel@tonic-gate  *	the first key/state pair if there are any characters pending.
13460Sstevel@tonic-gate  */
13470Sstevel@tonic-gate static boolean_t
usbkbm_polled_keycheck(struct kbtrans_hardware * hw,int * key,enum keystate * state)13480Sstevel@tonic-gate usbkbm_polled_keycheck(struct kbtrans_hardware *hw,
13490Sstevel@tonic-gate 	int *key, enum keystate *state)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
13520Sstevel@tonic-gate 	uchar_t				*buffer;
13539607SPengcheng.Chen@Sun.COM 	unsigned			size;
13540Sstevel@tonic-gate 	hid_polled_handle_t		hid_polled_handle;
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)hw;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	/*
13590Sstevel@tonic-gate 	 * If there are already characters buffered up, then we are done.
13600Sstevel@tonic-gate 	 */
13610Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 		return (B_TRUE);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	hid_polled_handle =
13695129Smarx 	    usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
13700Sstevel@tonic-gate 
13719607SPengcheng.Chen@Sun.COM 	size = (usbkbmd->usbkbm_hid_callback.hid_polled_read)
13725129Smarx 	    (hid_polled_handle, &buffer);
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	/*
13759607SPengcheng.Chen@Sun.COM 	 * If we don't get a valid input report then indicate that,
13769607SPengcheng.Chen@Sun.COM 	 * and we are done.
13770Sstevel@tonic-gate 	 */
13789607SPengcheng.Chen@Sun.COM 	if (size != usbkbmd->usbkbm_report_format.tlen) {
13790Sstevel@tonic-gate 		return (B_FALSE);
13800Sstevel@tonic-gate 	}
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	/*
13830Sstevel@tonic-gate 	 * We have a usb packet, so pass this packet to
13840Sstevel@tonic-gate 	 * usbkbm_unpack_usb_packet so that it can be broken up into
13850Sstevel@tonic-gate 	 * individual key/state values.
13860Sstevel@tonic-gate 	 */
13879607SPengcheng.Chen@Sun.COM 	if (usbkbmd->usbkbm_report_format.keyid != HID_REPORT_ID_UNDEFINED) {
13889607SPengcheng.Chen@Sun.COM 		if (*buffer != usbkbmd->usbkbm_report_format.keyid) {
13899607SPengcheng.Chen@Sun.COM 			return (B_FALSE);
13909607SPengcheng.Chen@Sun.COM 		} else {
13919607SPengcheng.Chen@Sun.COM 			/* We skip the report id prefix */
13929607SPengcheng.Chen@Sun.COM 			buffer++;
13939607SPengcheng.Chen@Sun.COM 		}
13949607SPengcheng.Chen@Sun.COM 	}
13959607SPengcheng.Chen@Sun.COM 	usbkbm_unpack_usb_packet(usbkbmd, usbkbm_poll_callback, buffer);
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/*
13980Sstevel@tonic-gate 	 * If a scancode was returned as a result of this packet,
13990Sstevel@tonic-gate 	 * then translate the scancode.
14000Sstevel@tonic-gate 	 */
14010Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		return (B_TRUE);
14060Sstevel@tonic-gate 	}
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	return (B_FALSE);
14090Sstevel@tonic-gate }
14100Sstevel@tonic-gate 
usbkbm_get_state(usbkbm_state_t * usbkbmd)14110Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *usbkbmd)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate 	ushort_t	ret;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	ASSERT(usbkbmd->usbkbm_vkbd_type == KB_PC ||
14160Sstevel@tonic-gate 	    usbkbmd->usbkbm_vkbd_type == KB_USB);
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	if (usbkbmd->usbkbm_vkbd_type == KB_PC)
14190Sstevel@tonic-gate 		ret = INDEXTO_PC;
14200Sstevel@tonic-gate 	else
14210Sstevel@tonic-gate 		ret = INDEXTO_USB;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	return (ret);
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate /*
14260Sstevel@tonic-gate  * usbkbm_streams_callback :
14270Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14280Sstevel@tonic-gate  *	usb packets for normal streams-based input.  We pass a pointer
14290Sstevel@tonic-gate  *	to this routine to usbkbm_unpack_usb_packet.  This routine will
14300Sstevel@tonic-gate  *	get called with an unpacked key (scancode) and state (press/release).
14310Sstevel@tonic-gate  *	We pass it to the generic keyboard module.
14320Sstevel@tonic-gate  *
14339237SStrony.Zhang@Sun.COM  *	'index' and the function pointers:
14340Sstevel@tonic-gate  *	Map USB scancodes to PC scancodes by lookup table.
14350Sstevel@tonic-gate  *	This fix is mainly meant for x86 platforms. For SPARC systems
14360Sstevel@tonic-gate  *	this fix doesn't change the way in which the scancodes are processed.
14370Sstevel@tonic-gate  */
14380Sstevel@tonic-gate static void
usbkbm_streams_callback(usbkbm_state_t * usbkbmd,int key,enum keystate state)14390Sstevel@tonic-gate usbkbm_streams_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14400Sstevel@tonic-gate {
14410Sstevel@tonic-gate 	ushort_t index = usbkbm_get_state(usbkbmd);
14420Sstevel@tonic-gate 	(*usbkbm_xlate[index])(usbkbmd, key, state);
14430Sstevel@tonic-gate }
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate  * Don't do any translations. Send to 'kbtrans' for processing.
14470Sstevel@tonic-gate  */
14480Sstevel@tonic-gate static void
usbkbm_wrap_kbtrans(usbkbm_state_t * usbkbmd,int key,enum keystate state)14490Sstevel@tonic-gate usbkbm_wrap_kbtrans(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14500Sstevel@tonic-gate {
14510Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate /*
14550Sstevel@tonic-gate  * Translate USB scancodes to PC scancodes before sending it to 'kbtrans'
14560Sstevel@tonic-gate  */
14570Sstevel@tonic-gate void
usbkbm_usb2pc_xlate(usbkbm_state_t * usbkbmd,int key,enum keystate state)14580Sstevel@tonic-gate usbkbm_usb2pc_xlate(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate 	key = kbtrans_keycode_usb2pc(key);
14610Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate  * usbkbm_poll_callback :
14660Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14670Sstevel@tonic-gate  *	usb packets for polled input.  We pass a pointer to this routine
14680Sstevel@tonic-gate  *	to usbkbm_unpack_usb_packet.  This routine will get called with
14690Sstevel@tonic-gate  *	an unpacked key (scancode) and state (press/release).  We will
14700Sstevel@tonic-gate  *	store the key/state pair into a circular buffer so that it can
14710Sstevel@tonic-gate  *	be translated into an ascii key later.
14720Sstevel@tonic-gate  */
14730Sstevel@tonic-gate static void
usbkbm_poll_callback(usbkbm_state_t * usbkbmd,int key,enum keystate state)14740Sstevel@tonic-gate usbkbm_poll_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14750Sstevel@tonic-gate {
14760Sstevel@tonic-gate 	/*
14770Sstevel@tonic-gate 	 * Check to make sure that the buffer isn't already full
14780Sstevel@tonic-gate 	 */
14790Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters ==
14805129Smarx 	    USB_POLLED_BUFFER_SIZE) {
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 		/*
14830Sstevel@tonic-gate 		 * The buffer is full, we will drop this character.
14840Sstevel@tonic-gate 		 */
14850Sstevel@tonic-gate 		return;
14860Sstevel@tonic-gate 	}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	/*
14890Sstevel@tonic-gate 	 * Save the scancode in the buffer
14900Sstevel@tonic-gate 	 */
14910Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_key = key;
14920Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_state = state;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	/*
14950Sstevel@tonic-gate 	 * We have one more character in the buffer
14960Sstevel@tonic-gate 	 */
14970Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters++;
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	/*
15000Sstevel@tonic-gate 	 * Increment to the next available slot.
15010Sstevel@tonic-gate 	 */
15020Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head++;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	/*
15050Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15060Sstevel@tonic-gate 	 */
15070Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_head -
15085129Smarx 	    usbkbmd->usbkbm_polled_scancode_buffer ==
15095129Smarx 	    USB_POLLED_BUFFER_SIZE) {
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_head =
15125129Smarx 		    usbkbmd->usbkbm_polled_scancode_buffer;
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate /*
15170Sstevel@tonic-gate  * usbkbm_get_scancode :
15180Sstevel@tonic-gate  *	This routine retreives a key/state pair from the circular buffer.
15190Sstevel@tonic-gate  *	The pair was put in the buffer by usbkbm_poll_callback when a
15200Sstevel@tonic-gate  *	USB packet was translated into a key/state by usbkbm_unpack_usb_packet.
15210Sstevel@tonic-gate  */
15220Sstevel@tonic-gate static void
usbkbm_get_scancode(usbkbm_state_t * usbkbmd,int * key,enum keystate * state)15230Sstevel@tonic-gate usbkbm_get_scancode(usbkbm_state_t *usbkbmd, int *key, enum keystate *state)
15240Sstevel@tonic-gate {
15250Sstevel@tonic-gate 	/*
15260Sstevel@tonic-gate 	 * Copy the character.
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 	*key = usbkbmd->usbkbm_polled_buffer_tail->poll_key;
15290Sstevel@tonic-gate 	*state = usbkbmd->usbkbm_polled_buffer_tail->poll_state;
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 	/*
15320Sstevel@tonic-gate 	 * Increment to the next character to be copied from
15330Sstevel@tonic-gate 	 * and to.
15340Sstevel@tonic-gate 	 */
15350Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail++;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	/*
15380Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15390Sstevel@tonic-gate 	 */
15400Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_tail -
15415129Smarx 	    usbkbmd->usbkbm_polled_scancode_buffer ==
15425129Smarx 	    USB_POLLED_BUFFER_SIZE) {
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_tail =
15455129Smarx 		    usbkbmd->usbkbm_polled_scancode_buffer;
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	/*
15490Sstevel@tonic-gate 	 * We have one less character in the buffer.
15500Sstevel@tonic-gate 	 */
15510Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters--;
15520Sstevel@tonic-gate }
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate /*
15550Sstevel@tonic-gate  * usbkbm_polled_setled :
15560Sstevel@tonic-gate  *	This routine is a place holder.  Someday, we may want to allow led
15570Sstevel@tonic-gate  *	state to be updated from within polled mode.
15580Sstevel@tonic-gate  */
15590Sstevel@tonic-gate /* ARGSUSED */
15600Sstevel@tonic-gate static void
usbkbm_polled_setled(struct kbtrans_hardware * hw,int led_state)15610Sstevel@tonic-gate usbkbm_polled_setled(struct kbtrans_hardware *hw, int led_state)
15620Sstevel@tonic-gate {
15630Sstevel@tonic-gate 	/* nothing to do for now */
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate /*
15670Sstevel@tonic-gate  * This is a pass-thru routine to get a character at poll time.
15680Sstevel@tonic-gate  */
15690Sstevel@tonic-gate static int
usbkbm_polled_getchar(cons_polledio_arg_t arg)15701762Slt200341 usbkbm_polled_getchar(cons_polledio_arg_t arg)
15710Sstevel@tonic-gate {
15720Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	return (kbtrans_getchar(usbkbmd->usbkbm_kbtrans));
15770Sstevel@tonic-gate }
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate /*
15800Sstevel@tonic-gate  * This is a pass-thru routine to test if character is available for reading
15810Sstevel@tonic-gate  * at poll time.
15820Sstevel@tonic-gate  */
15830Sstevel@tonic-gate static boolean_t
usbkbm_polled_ischar(cons_polledio_arg_t arg)15841762Slt200341 usbkbm_polled_ischar(cons_polledio_arg_t arg)
15850Sstevel@tonic-gate {
15860Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	return (kbtrans_ischar(usbkbmd->usbkbm_kbtrans));
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate /*
15940Sstevel@tonic-gate  * usbkbm_polled_input_enter :
15950Sstevel@tonic-gate  *	This is a pass-thru initialization routine for the lower layer drivers.
15960Sstevel@tonic-gate  *	This routine is called at poll time to set the state for polled input.
15970Sstevel@tonic-gate  */
15980Sstevel@tonic-gate static void
usbkbm_polled_enter(cons_polledio_arg_t arg)15991762Slt200341 usbkbm_polled_enter(cons_polledio_arg_t arg)
16000Sstevel@tonic-gate {
16019607SPengcheng.Chen@Sun.COM 	usbkbm_state_t		*usbkbmd = (usbkbm_state_t *)arg;
16029607SPengcheng.Chen@Sun.COM 	hid_polled_handle_t	hid_polled_handle;
16039607SPengcheng.Chen@Sun.COM 	int			kbstart, kbend, uindex;
16040Sstevel@tonic-gate 
16059607SPengcheng.Chen@Sun.COM 	kbstart = usbkbmd->usbkbm_report_format.kpos;
16069607SPengcheng.Chen@Sun.COM 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/*
16090Sstevel@tonic-gate 	 * Before switching to POLLED mode, copy the contents of
16100Sstevel@tonic-gate 	 * usbkbm_pendingusbpacket to usbkbm_lastusbpacket since
16110Sstevel@tonic-gate 	 * usbkbm_pendingusbpacket field has currently processed
16120Sstevel@tonic-gate 	 * key events of the current OS mode usb keyboard packet.
16130Sstevel@tonic-gate 	 */
16149607SPengcheng.Chen@Sun.COM 	for (uindex = kbstart + 2; uindex < kbend; uindex++) {
16150Sstevel@tonic-gate 		usbkbmd->usbkbm_lastusbpacket[uindex] =
16165129Smarx 		    usbkbmd->usbkbm_pendingusbpacket[uindex];
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	hid_polled_handle =
16225129Smarx 	    usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	(void) (usbkbmd->usbkbm_hid_callback.hid_polled_input_enter)
16255129Smarx 	    (hid_polled_handle);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate /*
16290Sstevel@tonic-gate  * usbkbm_polled_input_exit :
16300Sstevel@tonic-gate  *	This is a pass-thru restoration routine for the lower layer drivers.
16310Sstevel@tonic-gate  *	This routine is called at poll time to reset the state back to streams
16320Sstevel@tonic-gate  *	input.
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate static void
usbkbm_polled_exit(cons_polledio_arg_t arg)16351762Slt200341 usbkbm_polled_exit(cons_polledio_arg_t arg)
16360Sstevel@tonic-gate {
16379607SPengcheng.Chen@Sun.COM 	usbkbm_state_t		*usbkbmd = (usbkbm_state_t *)arg;
16389607SPengcheng.Chen@Sun.COM 	hid_polled_handle_t	hid_polled_handle;
16399607SPengcheng.Chen@Sun.COM 	int			kbstart, kbend, uindex;
16400Sstevel@tonic-gate 
16419607SPengcheng.Chen@Sun.COM 	kbstart = usbkbmd->usbkbm_report_format.kpos;
16429607SPengcheng.Chen@Sun.COM 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	/*
16450Sstevel@tonic-gate 	 * Before returning to OS mode, copy the contents of
16460Sstevel@tonic-gate 	 * usbkbm_lastusbpacket to usbkbm_pendingusbpacket since
16470Sstevel@tonic-gate 	 * usbkbm_lastusbpacket field has processed key events
16480Sstevel@tonic-gate 	 * of the last POLLED mode usb keyboard packet.
16490Sstevel@tonic-gate 	 */
16509607SPengcheng.Chen@Sun.COM 	for (uindex = kbstart + 2; uindex < kbend; uindex ++) {
16510Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] =
16525129Smarx 		    usbkbmd->usbkbm_lastusbpacket[uindex];
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 		usbkbmd->usbkbm_lastusbpacket[uindex] = 0;
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	hid_polled_handle =
16585129Smarx 	    usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 	(void) (usbkbmd->usbkbm_hid_callback.hid_polled_input_exit)
16615129Smarx 	    (hid_polled_handle);
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate /*
16650Sstevel@tonic-gate  * usbkbm_unpack_usb_packet :
16667127Ssethg  *	USB key packets contain 8 bytes while in boot-protocol mode.
16670Sstevel@tonic-gate  *	The first byte contains bit packed modifier key information.
16680Sstevel@tonic-gate  *	Second byte is reserved. The last 6 bytes contain bytes of
16690Sstevel@tonic-gate  *	currently pressed keys. If a key was not recorded on the
16700Sstevel@tonic-gate  *	previous packet, but present in the current packet, then set
16710Sstevel@tonic-gate  *	state to KEY_PRESSED. If a key was recorded in the previous packet,
16720Sstevel@tonic-gate  *	but not present in the current packet, then state to KEY_RELEASED
16730Sstevel@tonic-gate  *	Follow a similar algorithm for bit packed modifier keys.
16740Sstevel@tonic-gate  */
16750Sstevel@tonic-gate static void
usbkbm_unpack_usb_packet(usbkbm_state_t * usbkbmd,process_key_callback_t func,uchar_t * usbpacket)16760Sstevel@tonic-gate usbkbm_unpack_usb_packet(usbkbm_state_t *usbkbmd, process_key_callback_t func,
16779607SPengcheng.Chen@Sun.COM 	uchar_t *usbpacket)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate 	uchar_t		mkb;
16800Sstevel@tonic-gate 	uchar_t		lastmkb;
16810Sstevel@tonic-gate 	uchar_t		*lastusbpacket = usbkbmd->usbkbm_lastusbpacket;
16829607SPengcheng.Chen@Sun.COM 	int		packet_size, kbstart, kbend;
16830Sstevel@tonic-gate 	int		uindex, lindex, rollover;
16840Sstevel@tonic-gate 
16859607SPengcheng.Chen@Sun.COM 	packet_size = usbkbmd->usbkbm_report_format.tlen;
16869607SPengcheng.Chen@Sun.COM 	kbstart = usbkbmd->usbkbm_report_format.kpos;
16879607SPengcheng.Chen@Sun.COM 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
16889607SPengcheng.Chen@Sun.COM 	mkb = usbpacket[kbstart];
16899607SPengcheng.Chen@Sun.COM 	lastmkb = lastusbpacket[kbstart];
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	for (uindex = 0; uindex < packet_size; uindex++) {
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
16945129Smarx 		    " %x ", usbpacket[uindex]);
16950Sstevel@tonic-gate 	}
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
16985129Smarx 	    " is the usbkeypacket");
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	/* check to see if modifier keys are different */
17010Sstevel@tonic-gate 	if (mkb != lastmkb) {
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 		if ((mkb & USB_LSHIFTBIT) != (lastmkb & USB_LSHIFTBIT)) {
17040Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LSHIFTKEY, (mkb&USB_LSHIFTBIT) ?
17055129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17060Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17075129Smarx 			    "unpack: sending USB_LSHIFTKEY");
17080Sstevel@tonic-gate 		}
17090Sstevel@tonic-gate 
17100Sstevel@tonic-gate 		if ((mkb & USB_LCTLBIT) != (lastmkb & USB_LCTLBIT)) {
17110Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LCTLCKEY, mkb&USB_LCTLBIT ?
17125129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17130Sstevel@tonic-gate 		}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 		if ((mkb & USB_LALTBIT) != (lastmkb & USB_LALTBIT)) {
17160Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LALTKEY, mkb&USB_LALTBIT ?
17175129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17180Sstevel@tonic-gate 		}
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 		if ((mkb & USB_LMETABIT) != (lastmkb & USB_LMETABIT)) {
17210Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LMETAKEY, mkb&USB_LMETABIT ?
17225129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17230Sstevel@tonic-gate 		}
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 		if ((mkb & USB_RMETABIT) != (lastmkb & USB_RMETABIT)) {
17260Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RMETAKEY, mkb&USB_RMETABIT ?
17275129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17280Sstevel@tonic-gate 		}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 		if ((mkb & USB_RALTBIT) != (lastmkb & USB_RALTBIT)) {
17310Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RALTKEY, mkb&USB_RALTBIT ?
17325129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17330Sstevel@tonic-gate 		}
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 		if ((mkb & USB_RCTLBIT) != (lastmkb & USB_RCTLBIT)) {
17360Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RCTLCKEY, mkb&USB_RCTLBIT ?
17375129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17380Sstevel@tonic-gate 		}
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 		if ((mkb & USB_RSHIFTBIT) != (lastmkb & USB_RSHIFTBIT)) {
17410Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RSHIFTKEY, mkb&USB_RSHIFTBIT ?
17425129Smarx 			    KEY_PRESSED : KEY_RELEASED);
17430Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17445129Smarx 			    "unpack: sending USB_RSHIFTKEY");
17450Sstevel@tonic-gate 		}
17460Sstevel@tonic-gate 	}
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	/* save modifier bits */
17499607SPengcheng.Chen@Sun.COM 	lastusbpacket[kbstart] = usbpacket[kbstart];
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	/* Check Keyboard rollover error. */
17529607SPengcheng.Chen@Sun.COM 	if (usbpacket[kbstart + 2] == USB_ERRORROLLOVER) {
17530Sstevel@tonic-gate 		rollover = 1;
17549607SPengcheng.Chen@Sun.COM 		for (uindex = kbstart + 3; uindex < kbend;
17555129Smarx 		    uindex++) {
17560Sstevel@tonic-gate 			if (usbpacket[uindex] != USB_ERRORROLLOVER) {
17570Sstevel@tonic-gate 				rollover = 0;
17580Sstevel@tonic-gate 				break;
17590Sstevel@tonic-gate 			}
17600Sstevel@tonic-gate 		}
17610Sstevel@tonic-gate 		if (rollover) {
17620Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17635129Smarx 			    "unpack: errorrollover");
17640Sstevel@tonic-gate 			return;
17650Sstevel@tonic-gate 		}
17660Sstevel@tonic-gate 	}
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	/* check for released keys */
17699607SPengcheng.Chen@Sun.COM 	for (lindex = kbstart + 2; lindex < kbend; lindex++) {
17700Sstevel@tonic-gate 		int released = 1;
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 		if (lastusbpacket[lindex] == 0) {
17730Sstevel@tonic-gate 			continue;
17740Sstevel@tonic-gate 		}
17759607SPengcheng.Chen@Sun.COM 		for (uindex = kbstart + 2; uindex < kbend; uindex++)
17760Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
17770Sstevel@tonic-gate 				released = 0;
17780Sstevel@tonic-gate 				break;
17790Sstevel@tonic-gate 			}
17800Sstevel@tonic-gate 		if (released) {
17810Sstevel@tonic-gate 			(*func)(usbkbmd, lastusbpacket[lindex], KEY_RELEASED);
17820Sstevel@tonic-gate 		}
17830Sstevel@tonic-gate 	}
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	/* check for new presses */
17869607SPengcheng.Chen@Sun.COM 	for (uindex = kbstart + 2; uindex < kbend; uindex++) {
17870Sstevel@tonic-gate 		int newkey = 1;
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = usbpacket[uindex];
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 		if (usbpacket[uindex] == 0) {
17920Sstevel@tonic-gate 			continue;
17930Sstevel@tonic-gate 		}
17940Sstevel@tonic-gate 
17959607SPengcheng.Chen@Sun.COM 		for (lindex = kbstart + 2; lindex < kbend; lindex++) {
17960Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
17970Sstevel@tonic-gate 				newkey = 0;
17980Sstevel@tonic-gate 				break;
17990Sstevel@tonic-gate 			}
18000Sstevel@tonic-gate 		}
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		if (newkey) {
18030Sstevel@tonic-gate 			/*
18040Sstevel@tonic-gate 			 * Modifier keys can be present as part of both the
18050Sstevel@tonic-gate 			 * first byte and as separate key bytes. In the sec-
18060Sstevel@tonic-gate 			 * ond case ignore it.
18070Sstevel@tonic-gate 			 */
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 			if (!usbkbm_is_modkey(usbpacket[uindex])) {
18100Sstevel@tonic-gate 				(*func)(usbkbmd, usbpacket[uindex],
18115129Smarx 				    KEY_PRESSED);
18120Sstevel@tonic-gate 			} else {
18130Sstevel@tonic-gate 				usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 				continue;
18160Sstevel@tonic-gate 			}
18170Sstevel@tonic-gate 		}
18180Sstevel@tonic-gate 	}
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	/*
18210Sstevel@tonic-gate 	 * Copy the processed key events of the current usb keyboard
18220Sstevel@tonic-gate 	 * packet, which is saved in the usbkbm_pendingusbpacket field
18230Sstevel@tonic-gate 	 * to the usbkbm_lastusbpacket field.
18240Sstevel@tonic-gate 	 */
18259607SPengcheng.Chen@Sun.COM 	for (uindex = kbstart + 2; uindex < kbend; uindex++) {
18260Sstevel@tonic-gate 		lastusbpacket[uindex] =
18275129Smarx 		    usbkbmd->usbkbm_pendingusbpacket[uindex];
18280Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18290Sstevel@tonic-gate 	}
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate static boolean_t
usbkbm_is_modkey(uchar_t key)18330Sstevel@tonic-gate usbkbm_is_modkey(uchar_t key)
18340Sstevel@tonic-gate {
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	switch (key) {
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	case USB_LSHIFTKEY:
18390Sstevel@tonic-gate 	case USB_LCTLCKEY:
18400Sstevel@tonic-gate 	case USB_LALTKEY:
18410Sstevel@tonic-gate 	case USB_LMETAKEY:
18420Sstevel@tonic-gate 	case USB_RCTLCKEY:
18430Sstevel@tonic-gate 	case USB_RSHIFTKEY:
18440Sstevel@tonic-gate 	case USB_RMETAKEY:
18450Sstevel@tonic-gate 	case USB_RALTKEY:
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 		return (B_TRUE);
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	default:
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 		break;
18520Sstevel@tonic-gate 	}
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	return (B_FALSE);
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate /*
18580Sstevel@tonic-gate  * usbkbm_reioctl :
18590Sstevel@tonic-gate  *	This function is set up as call-back function should an ioctl fail.
18600Sstevel@tonic-gate  *	It retries the ioctl
18610Sstevel@tonic-gate  */
18620Sstevel@tonic-gate static void
usbkbm_reioctl(void * arg)18630Sstevel@tonic-gate usbkbm_reioctl(void	*arg)
18640Sstevel@tonic-gate {
18650Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
18660Sstevel@tonic-gate 	mblk_t *mp;
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_bufcallid = 0;
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	if ((mp = usbkbmd->usbkbm_streams_iocpending) != NULL) {
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 		/* not pending any more */
18750Sstevel@tonic-gate 		usbkbmd->usbkbm_streams_iocpending = NULL;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 		(void) usbkbm_ioctl(usbkbmd->usbkbm_writeq, mp);
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate }
18800Sstevel@tonic-gate 
1881918Sqz150045 /*
1882918Sqz150045  * usbkbm_get_vid_pid
1883918Sqz150045  *	Issue a M_CTL to hid to get the device info
1884918Sqz150045  */
1885918Sqz150045 static int
usbkbm_get_vid_pid(usbkbm_state_t * usbkbmd)1886918Sqz150045 usbkbm_get_vid_pid(usbkbm_state_t *usbkbmd)
1887918Sqz150045 {
1888918Sqz150045 	struct iocblk mctlmsg;
1889918Sqz150045 	mblk_t *mctl_ptr;
1890918Sqz150045 	queue_t *q = usbkbmd->usbkbm_readq;
1891918Sqz150045 
1892918Sqz150045 	mctlmsg.ioc_cmd = HID_GET_VID_PID;
1893918Sqz150045 	mctlmsg.ioc_count = 0;
1894918Sqz150045 
1895918Sqz150045 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
1896918Sqz150045 	if (mctl_ptr == NULL) {
1897918Sqz150045 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
1898918Sqz150045 		qprocsoff(q);
1899918Sqz150045 		kmem_free(usbkbmd, sizeof (usbkbm_state_t));
1900918Sqz150045 
1901918Sqz150045 		return (ENOMEM);
1902918Sqz150045 	}
1903918Sqz150045 
1904918Sqz150045 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
1905918Sqz150045 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
1906918Sqz150045 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
1907918Sqz150045 		if (qwait_sig(q) == 0) {
1908918Sqz150045 			usbkbmd->usbkbm_flags = 0;
1909918Sqz150045 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
1910918Sqz150045 			qprocsoff(q);
1911918Sqz150045 			kmem_free(usbkbmd, sizeof (usbkbm_state_t));
1912918Sqz150045 
1913918Sqz150045 			return (EINTR);
1914918Sqz150045 		}
1915918Sqz150045 	}
1916918Sqz150045 
1917918Sqz150045 	return (0);
1918918Sqz150045 }
19199237SStrony.Zhang@Sun.COM 
19209237SStrony.Zhang@Sun.COM /*
19219607SPengcheng.Chen@Sun.COM  * usbkbm_get_input_format() :
19229607SPengcheng.Chen@Sun.COM  *     Get the input report format of keyboard
19239237SStrony.Zhang@Sun.COM  */
19249237SStrony.Zhang@Sun.COM static int
usbkbm_get_input_format(usbkbm_state_t * usbkbmd)19259607SPengcheng.Chen@Sun.COM usbkbm_get_input_format(usbkbm_state_t *usbkbmd)
19269237SStrony.Zhang@Sun.COM {
19279607SPengcheng.Chen@Sun.COM 
19289607SPengcheng.Chen@Sun.COM 	hidparser_rpt_t *kb_rpt;
19299607SPengcheng.Chen@Sun.COM 	uint_t i, kbd_page = 0, kpos = 0, klen = 0, limit = 0;
19309607SPengcheng.Chen@Sun.COM 	uint32_t rptcnt, rptsz;
19319607SPengcheng.Chen@Sun.COM 	usbkbm_report_format_t *kbd_fmt = &usbkbmd->usbkbm_report_format;
19329607SPengcheng.Chen@Sun.COM 	int rptid, rval;
19339237SStrony.Zhang@Sun.COM 
19349607SPengcheng.Chen@Sun.COM 	/* Setup default input report format */
19359607SPengcheng.Chen@Sun.COM 	kbd_fmt->keyid = HID_REPORT_ID_UNDEFINED;
19369607SPengcheng.Chen@Sun.COM 	kbd_fmt->tlen = USB_KBD_BOOT_PROTOCOL_PACKET_SIZE;
19379607SPengcheng.Chen@Sun.COM 	kbd_fmt->klen = kbd_fmt->tlen;
19389607SPengcheng.Chen@Sun.COM 	kbd_fmt->kpos = 0;
19399607SPengcheng.Chen@Sun.COM 
19409607SPengcheng.Chen@Sun.COM 	if (usbkbmd->usbkbm_report_descr == NULL) {
19419607SPengcheng.Chen@Sun.COM 		return (USB_FAILURE);
19429607SPengcheng.Chen@Sun.COM 	}
19439237SStrony.Zhang@Sun.COM 
19449607SPengcheng.Chen@Sun.COM 	/* Get keyboard layout */
19459607SPengcheng.Chen@Sun.COM 	if (hidparser_get_country_code(usbkbmd->usbkbm_report_descr,
19469607SPengcheng.Chen@Sun.COM 	    (uint16_t *)&usbkbmd->usbkbm_layout) == HIDPARSER_FAILURE) {
19479237SStrony.Zhang@Sun.COM 
19489607SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L3(PRINT_MASK_OPEN,
19499607SPengcheng.Chen@Sun.COM 		    usbkbm_log_handle, "get_country_code failed"
19509607SPengcheng.Chen@Sun.COM 		    "setting default layout(0)");
19519607SPengcheng.Chen@Sun.COM 
19529607SPengcheng.Chen@Sun.COM 		usbkbmd->usbkbm_layout = usbkbm_layout;
19539237SStrony.Zhang@Sun.COM 	}
19549237SStrony.Zhang@Sun.COM 
19559607SPengcheng.Chen@Sun.COM 	/* Get the id of the report which contains keyboard data */
19569607SPengcheng.Chen@Sun.COM 	if (hidparser_get_usage_attribute(
19579607SPengcheng.Chen@Sun.COM 	    usbkbmd->usbkbm_report_descr,
19589607SPengcheng.Chen@Sun.COM 	    0, /* Doesn't matter */
19599607SPengcheng.Chen@Sun.COM 	    HIDPARSER_ITEM_INPUT,
19609607SPengcheng.Chen@Sun.COM 	    HID_KEYBOARD_KEYPAD_KEYS,
19619607SPengcheng.Chen@Sun.COM 	    0,
19629607SPengcheng.Chen@Sun.COM 	    HIDPARSER_ITEM_REPORT_ID,
19639607SPengcheng.Chen@Sun.COM 	    &rptid) == HIDPARSER_NOT_FOUND) {
19649607SPengcheng.Chen@Sun.COM 
19659607SPengcheng.Chen@Sun.COM 		return (USB_SUCCESS);
19669607SPengcheng.Chen@Sun.COM 	}
19679607SPengcheng.Chen@Sun.COM 
19689607SPengcheng.Chen@Sun.COM 	/* Allocate hidparser report structure */
19699607SPengcheng.Chen@Sun.COM 	kb_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
19709237SStrony.Zhang@Sun.COM 
19719607SPengcheng.Chen@Sun.COM 	/*
19729607SPengcheng.Chen@Sun.COM 	 * Check what is the total length of the keyboard packet
19739607SPengcheng.Chen@Sun.COM 	 * and get the usages and their lengths in order
19749607SPengcheng.Chen@Sun.COM 	 */
19759607SPengcheng.Chen@Sun.COM 	rval = hidparser_get_usage_list_in_order(
19769607SPengcheng.Chen@Sun.COM 	    usbkbmd->usbkbm_report_descr,
19779607SPengcheng.Chen@Sun.COM 	    rptid,
19789607SPengcheng.Chen@Sun.COM 	    HIDPARSER_ITEM_INPUT,
19799607SPengcheng.Chen@Sun.COM 	    kb_rpt);
19809607SPengcheng.Chen@Sun.COM 	if (rval != HIDPARSER_SUCCESS) {
19819607SPengcheng.Chen@Sun.COM 
19829607SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
19839607SPengcheng.Chen@Sun.COM 		    "get_usage_list_in_order failed");
19849607SPengcheng.Chen@Sun.COM 		kmem_free(kb_rpt, sizeof (hidparser_rpt_t));
19859607SPengcheng.Chen@Sun.COM 		return (USB_FAILURE);
19869607SPengcheng.Chen@Sun.COM 	}
19879607SPengcheng.Chen@Sun.COM 
19889607SPengcheng.Chen@Sun.COM 	for (i = 0; i < kb_rpt->no_of_usages; i++) {
19899607SPengcheng.Chen@Sun.COM 		rptcnt = kb_rpt->usage_descr[i].rptcnt;
19909607SPengcheng.Chen@Sun.COM 		rptsz = kb_rpt->usage_descr[i].rptsz;
19919607SPengcheng.Chen@Sun.COM 
19929607SPengcheng.Chen@Sun.COM 		switch (kb_rpt->usage_descr[i].usage_page) {
19939607SPengcheng.Chen@Sun.COM 		case HID_KEYBOARD_KEYPAD_KEYS:
19949607SPengcheng.Chen@Sun.COM 			if (!kbd_page) {
19959607SPengcheng.Chen@Sun.COM 				kpos = limit;
19969607SPengcheng.Chen@Sun.COM 				kbd_page = 1;
19979607SPengcheng.Chen@Sun.COM 			}
19989607SPengcheng.Chen@Sun.COM 			klen += rptcnt * rptsz;
19999607SPengcheng.Chen@Sun.COM 			/*FALLTHRU*/
20009607SPengcheng.Chen@Sun.COM 		default:
20019607SPengcheng.Chen@Sun.COM 			limit += rptcnt * rptsz;
20029607SPengcheng.Chen@Sun.COM 			break;
20039237SStrony.Zhang@Sun.COM 		}
20049237SStrony.Zhang@Sun.COM 	}
20059237SStrony.Zhang@Sun.COM 
20069607SPengcheng.Chen@Sun.COM 	kmem_free(kb_rpt, sizeof (hidparser_rpt_t));
20079607SPengcheng.Chen@Sun.COM 
20089607SPengcheng.Chen@Sun.COM 	/* Invalid input report format */
20099607SPengcheng.Chen@Sun.COM 	if (!kbd_page || limit > USBKBM_MAXPKTSIZE * 8 ||
20109607SPengcheng.Chen@Sun.COM 	    kpos + klen > limit || (kpos % 8 != 0)) {
20119607SPengcheng.Chen@Sun.COM 
20129607SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
20139607SPengcheng.Chen@Sun.COM 		    "Invalid input report format: kbd_page (%d), limit (%d), "
20149607SPengcheng.Chen@Sun.COM 		    "kpos (%d), klen (%d)", kbd_page, limit, kpos, klen);
20159607SPengcheng.Chen@Sun.COM 		return (USB_FAILURE);
20169607SPengcheng.Chen@Sun.COM 	}
20179607SPengcheng.Chen@Sun.COM 
20189607SPengcheng.Chen@Sun.COM 	/* Set report format */
20199607SPengcheng.Chen@Sun.COM 	kbd_fmt->keyid = (uint8_t)rptid;
20209607SPengcheng.Chen@Sun.COM 	kbd_fmt->tlen = limit / 8 + 1;
20219607SPengcheng.Chen@Sun.COM 	kbd_fmt->klen = klen / 8;
20229607SPengcheng.Chen@Sun.COM 	kbd_fmt->kpos = kpos / 8;
20239607SPengcheng.Chen@Sun.COM 
20249607SPengcheng.Chen@Sun.COM 	return (USB_SUCCESS);
20259237SStrony.Zhang@Sun.COM }
2026