17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * USB keyboard input streams module - processes USB keypacket
317c478bd9Sstevel@tonic-gate  * received from HID driver below to either ASCII or event
327c478bd9Sstevel@tonic-gate  * format for windowing system.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #define	KEYMAP_SIZE_VARIABLE
377c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
387c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
397c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
407c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
417c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
427c478bd9Sstevel@tonic-gate #include <sys/stream.h>
437c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
447c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
457c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
467c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
477c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
487c478bd9Sstevel@tonic-gate #include <sys/kbtrans.h>
497c478bd9Sstevel@tonic-gate #include <sys/usb/clients/usbkbm/usbkbm.h>
507c478bd9Sstevel@tonic-gate #include <sys/beep.h>
517c478bd9Sstevel@tonic-gate #include <sys/policy.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* debugging information */
544610e4a0Sfrits uint_t	usbkbm_errmask = (uint_t)PRINT_MASK_ALL;
554610e4a0Sfrits uint_t	usbkbm_errlevel = USB_LOG_L2;
567c478bd9Sstevel@tonic-gate static usb_log_handle_t usbkbm_log_handle;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate typedef void (*process_key_callback_t)(usbkbm_state_t *, int, enum keystate);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * Internal Function Prototypes
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate static void usbkbm_streams_setled(struct kbtrans_hardware *, int);
647c478bd9Sstevel@tonic-gate static void usbkbm_polled_setled(struct kbtrans_hardware *, int);
657c478bd9Sstevel@tonic-gate static boolean_t usbkbm_polled_keycheck(struct kbtrans_hardware *,
667c478bd9Sstevel@tonic-gate 			int *, enum keystate *);
677c478bd9Sstevel@tonic-gate static void usbkbm_poll_callback(usbkbm_state_t *, int, enum keystate);
687c478bd9Sstevel@tonic-gate static void usbkbm_streams_callback(usbkbm_state_t *, int, enum keystate);
697c478bd9Sstevel@tonic-gate static void usbkbm_unpack_usb_packet(usbkbm_state_t *, process_key_callback_t,
707c478bd9Sstevel@tonic-gate 			uchar_t *, int);
717c478bd9Sstevel@tonic-gate static boolean_t usbkbm_is_modkey(uchar_t);
727c478bd9Sstevel@tonic-gate static void usbkbm_reioctl(void	*);
737c478bd9Sstevel@tonic-gate static int usbkbm_polled_getchar(struct cons_polledio_arg *);
747c478bd9Sstevel@tonic-gate static boolean_t usbkbm_polled_ischar(struct cons_polledio_arg *);
757c478bd9Sstevel@tonic-gate static void usbkbm_polled_enter(struct cons_polledio_arg *);
767c478bd9Sstevel@tonic-gate static void usbkbm_polled_exit(struct cons_polledio_arg *);
777c478bd9Sstevel@tonic-gate static void usbkbm_mctl_receive(queue_t *, mblk_t *);
787c478bd9Sstevel@tonic-gate static enum kbtrans_message_response usbkbm_ioctl(queue_t *, mblk_t *);
797c478bd9Sstevel@tonic-gate static int usbkbm_kioccmd(usbkbm_state_t *, mblk_t *, char, size_t *);
807c478bd9Sstevel@tonic-gate static void	usbkbm_usb2pc_xlate(usbkbm_state_t *, int, enum keystate);
817c478bd9Sstevel@tonic-gate static void	usbkbm_wrap_kbtrans(usbkbm_state_t *, int, enum keystate);
827c478bd9Sstevel@tonic-gate static int 	usbkbm_set_protocol(usbkbm_state_t *, uint16_t);
83*6d9a41ffSqz150045 static int 	usbkbm_get_vid_pid(usbkbm_state_t *);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /* stream qinit functions defined here */
867c478bd9Sstevel@tonic-gate static int	usbkbm_open(queue_t *, dev_t *, int, int, cred_t *);
877c478bd9Sstevel@tonic-gate static int	usbkbm_close(queue_t *, int, cred_t *);
887c478bd9Sstevel@tonic-gate static void	usbkbm_wput(queue_t *, mblk_t *);
897c478bd9Sstevel@tonic-gate static void	usbkbm_rput(queue_t *, mblk_t *);
907c478bd9Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *);
917c478bd9Sstevel@tonic-gate static void	usbkbm_get_scancode(usbkbm_state_t *, int *, enum keystate *);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static struct keyboard *usbkbm_keyindex;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /* External Functions */
967c478bd9Sstevel@tonic-gate extern void space_free(char *);
977c478bd9Sstevel@tonic-gate extern uintptr_t space_fetch(char *);
987c478bd9Sstevel@tonic-gate extern int space_store(char *, uintptr_t);
997c478bd9Sstevel@tonic-gate extern struct keyboard *kbtrans_usbkb_maptab_init(void);
1007c478bd9Sstevel@tonic-gate extern void kbtrans_usbkb_maptab_fini(struct keyboard **);
1017c478bd9Sstevel@tonic-gate extern keymap_entry_t kbtrans_keycode_usb2pc(int);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Structure to setup callbacks
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate struct kbtrans_callbacks kbd_usb_callbacks = {
1077c478bd9Sstevel@tonic-gate 	usbkbm_streams_setled,
1087c478bd9Sstevel@tonic-gate 	usbkbm_polled_setled,
1097c478bd9Sstevel@tonic-gate 	usbkbm_polled_keycheck,
1107c478bd9Sstevel@tonic-gate };
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * Global Variables
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* This variable saves the LED state across hotplugging. */
1177c478bd9Sstevel@tonic-gate static uchar_t  usbkbm_led_state = 0;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* This variable saves the layout state */
120*6d9a41ffSqz150045 static uint16_t usbkbm_layout = 0;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Function pointer array for mapping of scancodes.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate void (*usbkbm_xlate[2])(usbkbm_state_t *, int, enum keystate) = {
1267c478bd9Sstevel@tonic-gate 	usbkbm_wrap_kbtrans,
1277c478bd9Sstevel@tonic-gate 	usbkbm_usb2pc_xlate
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static struct streamtab usbkbm_info;
1317c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
1327c478bd9Sstevel@tonic-gate 	"usbkbm",
1337c478bd9Sstevel@tonic-gate 	&usbkbm_info,
1347c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD
1357c478bd9Sstevel@tonic-gate };
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
1427c478bd9Sstevel@tonic-gate 	&mod_strmodops,
1437c478bd9Sstevel@tonic-gate 	"USB keyboard streams %I%",
1447c478bd9Sstevel@tonic-gate 	&fsw
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1487c478bd9Sstevel@tonic-gate 	MODREV_1,
1497c478bd9Sstevel@tonic-gate 	(void *)&modlstrmod,
1507c478bd9Sstevel@tonic-gate 	NULL
1517c478bd9Sstevel@tonic-gate };
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate int
1557c478bd9Sstevel@tonic-gate _init(void)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	int	rval = mod_install(&modlinkage);
1587c478bd9Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (rval != 0) {
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		return (rval);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	usbkbm_keyindex = kbtrans_usbkb_maptab_init();
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	usbkbm_log_handle = usb_alloc_log_hdl(NULL, "usbkbm",
1687c478bd9Sstevel@tonic-gate 		&usbkbm_errlevel, &usbkbm_errmask, NULL, 0);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	sp = (usbkbm_save_state_t *)space_fetch("SUNW,usbkbm_state");
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		return (0);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	/* Restore LED information */
1787c478bd9Sstevel@tonic-gate 	usbkbm_led_state = sp->usbkbm_save_led;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* Restore the Layout */
1817c478bd9Sstevel@tonic-gate 	usbkbm_layout = sp->usbkbm_layout;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/* Restore abort information */
1847c478bd9Sstevel@tonic-gate 	usbkbm_keyindex->k_abort1 =
1857c478bd9Sstevel@tonic-gate 		    sp->usbkbm_save_keyindex.k_abort1;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	usbkbm_keyindex->k_abort2 =
1887c478bd9Sstevel@tonic-gate 		sp->usbkbm_save_keyindex.k_abort2;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/* Restore keytables */
1917c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_normal,
1927c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_normal, USB_KEYTABLE_SIZE);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_shifted,
1957c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_shifted, USB_KEYTABLE_SIZE);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_caps,
1987c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_caps, USB_KEYTABLE_SIZE);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_altgraph,
2017c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_altgraph, USB_KEYTABLE_SIZE);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_numlock,
2047c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_numlock, USB_KEYTABLE_SIZE);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_control,
2077c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_control, USB_KEYTABLE_SIZE);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_up,
2107c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_up, USB_KEYTABLE_SIZE);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_normal,
2137c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2147c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_shifted,
2157c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2167c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_caps,
2177c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2187c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_altgraph,
2197c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2207c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_numlock,
2217c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2227c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_control,
2237c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2247c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_up,
2257c478bd9Sstevel@tonic-gate 		USB_KEYTABLE_SIZE);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (usbkbm_save_state_t));
2287c478bd9Sstevel@tonic-gate 	space_free("SUNW,usbkbm_state");
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	return (0);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate int
2347c478bd9Sstevel@tonic-gate _fini(void)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
2377c478bd9Sstevel@tonic-gate 	int sval;
2387c478bd9Sstevel@tonic-gate 	int rval;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (usbkbm_save_state_t), KM_SLEEP);
2417c478bd9Sstevel@tonic-gate 	sval = space_store("SUNW,usbkbm_state", (uintptr_t)sp);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * If it's not possible to store the state, return
2457c478bd9Sstevel@tonic-gate 	 * EBUSY.
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (sval != 0) {
2487c478bd9Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		return (EBUSY);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	rval = mod_remove(&modlinkage);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (rval != 0) {
2567c478bd9Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2577c478bd9Sstevel@tonic-gate 		space_free("SUNW,usbkbm_state");
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		return (rval);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usbkbm_log_handle);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/* Save the LED state */
2657c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_led = usbkbm_led_state;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* Save the layout */
2687c478bd9Sstevel@tonic-gate 	sp->usbkbm_layout = usbkbm_layout;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	/*
2717c478bd9Sstevel@tonic-gate 	 * Save entries of the keyboard structure that
2727c478bd9Sstevel@tonic-gate 	 * have changed.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort1 = usbkbm_keyindex->k_abort1;
2757c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort2 = usbkbm_keyindex->k_abort2;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	/* Allocate space for keytables to be stored */
2787c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_normal =
2797c478bd9Sstevel@tonic-gate 		kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2807c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_shifted =
2817c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2827c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_caps =
2837c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2847c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_altgraph =
2857c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2867c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_numlock =
2877c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2887c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_control =
2897c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2907c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_up =
2917c478bd9Sstevel@tonic-gate 		    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	/* Copy over the keytables */
2947c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_normal,
2957c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_normal, USB_KEYTABLE_SIZE);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_shifted,
2987c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_shifted, USB_KEYTABLE_SIZE);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_caps,
3017c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_caps, USB_KEYTABLE_SIZE);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_altgraph,
3047c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_altgraph, USB_KEYTABLE_SIZE);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_numlock,
3077c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_numlock, USB_KEYTABLE_SIZE);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_control,
3107c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_control, USB_KEYTABLE_SIZE);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_up,
3137c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_up, USB_KEYTABLE_SIZE);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	kbtrans_usbkb_maptab_fini(&usbkbm_keyindex);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	return (0);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate int
3217c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  * Module qinit functions
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate static struct module_info usbkbm_minfo = {
3317c478bd9Sstevel@tonic-gate 	0,		/* module id number */
3327c478bd9Sstevel@tonic-gate 	"usbkbm",	/* module name */
3337c478bd9Sstevel@tonic-gate 	0,		/* min packet size accepted */
3347c478bd9Sstevel@tonic-gate 	INFPSZ,		/* max packet size accepted */
3357c478bd9Sstevel@tonic-gate 	2048,		/* hi-water mark */
3367c478bd9Sstevel@tonic-gate 	128		/* lo-water mark */
3377c478bd9Sstevel@tonic-gate 	};
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /* read side for key data and ioctl replies */
3407c478bd9Sstevel@tonic-gate static struct qinit usbkbm_rinit = {
3417c478bd9Sstevel@tonic-gate 	(int (*)())usbkbm_rput,
3427c478bd9Sstevel@tonic-gate 	(int (*)())NULL,		/* service not used */
3437c478bd9Sstevel@tonic-gate 	usbkbm_open,
3447c478bd9Sstevel@tonic-gate 	usbkbm_close,
3457c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
3467c478bd9Sstevel@tonic-gate 	&usbkbm_minfo
3477c478bd9Sstevel@tonic-gate 	};
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /* write side for ioctls */
3507c478bd9Sstevel@tonic-gate static struct qinit usbkbm_winit = {
3517c478bd9Sstevel@tonic-gate 	(int (*)())usbkbm_wput,
3527c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
3537c478bd9Sstevel@tonic-gate 	usbkbm_open,
3547c478bd9Sstevel@tonic-gate 	usbkbm_close,
3557c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
3567c478bd9Sstevel@tonic-gate 	&usbkbm_minfo
3577c478bd9Sstevel@tonic-gate 	};
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate static struct streamtab usbkbm_info = {
3607c478bd9Sstevel@tonic-gate 	&usbkbm_rinit,
3617c478bd9Sstevel@tonic-gate 	&usbkbm_winit,
3627c478bd9Sstevel@tonic-gate 	NULL,		/* for muxes */
3637c478bd9Sstevel@tonic-gate 	NULL,		/* for muxes */
3647c478bd9Sstevel@tonic-gate };
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * usbkbm_open :
3687c478bd9Sstevel@tonic-gate  *	Open a keyboard
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate /* ARGSUSED */
3717c478bd9Sstevel@tonic-gate static int
3727c478bd9Sstevel@tonic-gate usbkbm_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
3757c478bd9Sstevel@tonic-gate 	struct iocblk	mctlmsg;
3767c478bd9Sstevel@tonic-gate 	uint32_t	packet_size;
3777c478bd9Sstevel@tonic-gate 	mblk_t		*mctl_ptr;
3787c478bd9Sstevel@tonic-gate 	int		error, ret;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	packet_size = 0;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (q->q_ptr) {
3837c478bd9Sstevel@tonic-gate 	    USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
3847c478bd9Sstevel@tonic-gate 		"usbkbm_open already opened");
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	    return (0); /* already opened */
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * Only allow open requests to succeed for privileged users.  This
3917c478bd9Sstevel@tonic-gate 	 * necessary to prevent users from pushing the "usbkbm" module again
3927c478bd9Sstevel@tonic-gate 	 * on the stream associated with /dev/kbd.
3937c478bd9Sstevel@tonic-gate 	 */
3947c478bd9Sstevel@tonic-gate 	if (secpolicy_console(crp) != 0)
3957c478bd9Sstevel@tonic-gate 		return (EPERM);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	switch (sflag) {
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	case MODOPEN:
4007c478bd9Sstevel@tonic-gate 		break;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	case CLONEOPEN:
4037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4047c478bd9Sstevel@tonic-gate 			"usbkbm_open: Clone open not supported");
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4077c478bd9Sstevel@tonic-gate 	default:
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		return (EINVAL);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/* allocate usb keyboard state structure */
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	usbkbmd = kmem_zalloc(sizeof (usbkbm_state_t), KM_SLEEP);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4177c478bd9Sstevel@tonic-gate 		"usbkbm_state= %p", (void *)usbkbmd);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	/*
4207c478bd9Sstevel@tonic-gate 	 * Set up private data.
4217c478bd9Sstevel@tonic-gate 	 */
4227c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_readq = q;
4237c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_writeq = WR(q);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_vkbd_type = KB_USB;
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
4287c478bd9Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
4297c478bd9Sstevel@tonic-gate 	 */
4307c478bd9Sstevel@tonic-gate 	q->q_ptr = (caddr_t)usbkbmd;
4317c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (caddr_t)usbkbmd;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	error = kbtrans_streams_init(q, sflag, crp,
4347c478bd9Sstevel@tonic-gate 		(struct kbtrans_hardware *)usbkbmd, &kbd_usb_callbacks,
4357c478bd9Sstevel@tonic-gate 		&usbkbmd->usbkbm_kbtrans, usbkbm_led_state, 0);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (error != 0) {
4387c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4397c478bd9Sstevel@tonic-gate 			"kbdopen:  kbtrans_streams_init failed\n");
4407c478bd9Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		return (error);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 * Set the polled information in the state structure.
4477c478bd9Sstevel@tonic-gate 	 * This information is set once, and doesn't change
4487c478bd9Sstevel@tonic-gate 	 */
4497c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_version =
4507c478bd9Sstevel@tonic-gate 				    CONSPOLLEDIO_V1;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_argument =
4537c478bd9Sstevel@tonic-gate 				(struct cons_polledio_arg *)usbkbmd;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_putchar = NULL;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_getchar =
4587c478bd9Sstevel@tonic-gate 				usbkbm_polled_getchar;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_ischar =
4617c478bd9Sstevel@tonic-gate 				usbkbm_polled_ischar;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_enter =
4647c478bd9Sstevel@tonic-gate 				    usbkbm_polled_enter;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_exit =
4677c478bd9Sstevel@tonic-gate 				usbkbm_polled_exit;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_setled =
4707c478bd9Sstevel@tonic-gate 		(void (*)(struct cons_polledio_arg *, int))usbkbm_polled_setled;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_keycheck =
4737c478bd9Sstevel@tonic-gate 		(boolean_t (*)(struct cons_polledio_arg *, int *,
4747c478bd9Sstevel@tonic-gate 		enum keystate *))usbkbm_polled_keycheck;
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * The head and the tail pointing at the same byte means empty or
4777c478bd9Sstevel@tonic-gate 	 * full. usbkbm_polled_buffer_num_characters is used to
4787c478bd9Sstevel@tonic-gate 	 * tell the difference.
4797c478bd9Sstevel@tonic-gate 	 */
4807c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head =
4817c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_polled_scancode_buffer;
4827c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail =
4837c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_polled_scancode_buffer;
4847c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters = 0;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	qprocson(q);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (ret = usbkbm_set_protocol(usbkbmd, SET_BOOT_PROTOCOL)) {
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		return (ret);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/* request hid report descriptor from HID */
4947c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
4957c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_count = 0;
4967c478bd9Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
4977c478bd9Sstevel@tonic-gate 	if (mctl_ptr == NULL) {
4987c478bd9Sstevel@tonic-gate 		/* failure to allocate M_CTL message */
4997c478bd9Sstevel@tonic-gate 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
5007c478bd9Sstevel@tonic-gate 		qprocsoff(q);
5017c478bd9Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		return (ENOMEM);
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	/* send message to hid */
5077c478bd9Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * Now that M_CTL has been sent, wait for report descriptor.  Cleanup
5117c478bd9Sstevel@tonic-gate 	 * if user signals in the mean time (as when this gets opened in an
5127c478bd9Sstevel@tonic-gate 	 * inappropriate context and the user types a ^C).
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
5157c478bd9Sstevel@tonic-gate 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		if (qwait_sig(q) == 0) {
5187c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_flags = 0;
5197c478bd9Sstevel@tonic-gate 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
5207c478bd9Sstevel@tonic-gate 			qprocsoff(q);
5217c478bd9Sstevel@tonic-gate 			kmem_free(usbkbmd, sizeof (*usbkbmd));
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			return (EINTR);
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	/*
5287c478bd9Sstevel@tonic-gate 	 * In case of non-self identifying keyboards the country code
5297c478bd9Sstevel@tonic-gate 	 *  has value 0. In this case we will set the layout to default US
5307c478bd9Sstevel@tonic-gate 	 *  if the usbkbm_layout is 0.
5317c478bd9Sstevel@tonic-gate 	 */
5327c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_report_descr != NULL) {
5337c478bd9Sstevel@tonic-gate 		if ((hidparser_get_country_code(usbkbmd->usbkbm_report_descr,
5347c478bd9Sstevel@tonic-gate 			(uint16_t *)&usbkbmd->usbkbm_layout) ==
5357c478bd9Sstevel@tonic-gate 			HIDPARSER_FAILURE) || (usbkbmd->usbkbm_layout == 0)) {
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 			if (!usbkbm_layout) {
5387c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_OPEN,
5397c478bd9Sstevel@tonic-gate 				    usbkbm_log_handle, "get_country_code failed"
5407c478bd9Sstevel@tonic-gate 				    "setting default layout(0x21)");
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 				/* Setting to default layout = US */
5437c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_layout = 0x21;
5447c478bd9Sstevel@tonic-gate 			} else
5457c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_layout = usbkbm_layout;
5467c478bd9Sstevel@tonic-gate 		}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 		if (hidparser_get_packet_size(usbkbmd->usbkbm_report_descr,
5497c478bd9Sstevel@tonic-gate 			0, HIDPARSER_ITEM_INPUT, (uint32_t *)&packet_size) ==
5507c478bd9Sstevel@tonic-gate 			HIDPARSER_FAILURE) {
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_OPEN,
5537c478bd9Sstevel@tonic-gate 				usbkbm_log_handle, "get_packet_size failed"
5547c478bd9Sstevel@tonic-gate 				"setting default packet size(8)");
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 			/* Setting to default packet size = 8 */
5577c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_packet_size =
5587c478bd9Sstevel@tonic-gate 				USB_KBD_DEFAULT_PACKET_SIZE;
5597c478bd9Sstevel@tonic-gate 		} else {
5607c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_packet_size = packet_size/8;
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 	} else {
5637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5647c478bd9Sstevel@tonic-gate 			"usbkbm: Invalid HID Descriptor Tree."
5657c478bd9Sstevel@tonic-gate 			"setting default layout(0x21) & packet_size(8)");
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 			if (!usbkbm_layout) {
5687c478bd9Sstevel@tonic-gate 				/* Setting to default = US */
5697c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_layout = 0x21;
5707c478bd9Sstevel@tonic-gate 			} else
5717c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_layout = usbkbm_layout;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_packet_size =
5747c478bd9Sstevel@tonic-gate 				USB_KBD_DEFAULT_PACKET_SIZE;
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
577*6d9a41ffSqz150045 	/*
578*6d9a41ffSqz150045 	 * Although Sun Japanese type6 and type7 keyboards have the same
579*6d9a41ffSqz150045 	 * layout number(15), they should be recognized for loading the
580*6d9a41ffSqz150045 	 * different keytables on upper apps (e.g. X). The new layout
581*6d9a41ffSqz150045 	 * number (271) is defined for the Sun Japanese type6 keyboards.
582*6d9a41ffSqz150045 	 * The layout number (15) specified in HID spec is used for other
583*6d9a41ffSqz150045 	 * Japanese keyboards. It is a workaround for the old Sun Japanese
584*6d9a41ffSqz150045 	 * type6 keyboards defect.
585*6d9a41ffSqz150045 	 */
586*6d9a41ffSqz150045 	if (usbkbmd->usbkbm_layout == SUN_JAPANESE_TYPE7) {
587*6d9a41ffSqz150045 
588*6d9a41ffSqz150045 		if ((ret = usbkbm_get_vid_pid(usbkbmd)) != 0) {
589*6d9a41ffSqz150045 
590*6d9a41ffSqz150045 			return (ret);
591*6d9a41ffSqz150045 		}
592*6d9a41ffSqz150045 
593*6d9a41ffSqz150045 		if ((usbkbmd->usbkbm_vid_pid.VendorId ==
594*6d9a41ffSqz150045 			HID_SUN_JAPANESE_TYPE6_KBD_VID) &&
595*6d9a41ffSqz150045 			(usbkbmd->usbkbm_vid_pid.ProductId ==
596*6d9a41ffSqz150045 			HID_SUN_JAPANESE_TYPE6_KBD_PID)) {
597*6d9a41ffSqz150045 			usbkbmd->usbkbm_layout = SUN_JAPANESE_TYPE6;
598*6d9a41ffSqz150045 		}
599*6d9a41ffSqz150045 	}
600*6d9a41ffSqz150045 
6017c478bd9Sstevel@tonic-gate 	kbtrans_streams_set_keyboard(usbkbmd->usbkbm_kbtrans, KB_USB,
6027c478bd9Sstevel@tonic-gate 					usbkbm_keyindex);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = USBKBM_OPEN;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	kbtrans_streams_enable(usbkbmd->usbkbm_kbtrans);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
6097c478bd9Sstevel@tonic-gate 			"usbkbm_open exiting");
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * usbkbm_close :
6167c478bd9Sstevel@tonic-gate  *	Close a keyboard.
6177c478bd9Sstevel@tonic-gate  */
6187c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
6197c478bd9Sstevel@tonic-gate static int
6207c478bd9Sstevel@tonic-gate usbkbm_close(register queue_t *q, int flag, cred_t *crp)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate 	usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/* If a beep is in progress, stop that */
6257c478bd9Sstevel@tonic-gate 	beeper_off();
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	qprocsoff(q);
6307c478bd9Sstevel@tonic-gate 	/*
6317c478bd9Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
6327c478bd9Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
6337c478bd9Sstevel@tonic-gate 	 * and try to use that data.
6347c478bd9Sstevel@tonic-gate 	 */
6357c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = 0;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	kmem_free(usbkbmd, sizeof (usbkbm_state_t));
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbkbm_log_handle,
6407c478bd9Sstevel@tonic-gate 		"usbkbm_close exiting");
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	return (0);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate  * usbkbm_wput :
6487c478bd9Sstevel@tonic-gate  *	usb keyboard module output queue put procedure: handles M_IOCTL
6497c478bd9Sstevel@tonic-gate  *	messages.
6507c478bd9Sstevel@tonic-gate  */
6517c478bd9Sstevel@tonic-gate static void
6527c478bd9Sstevel@tonic-gate usbkbm_wput(register queue_t *q, register mblk_t *mp)
6537c478bd9Sstevel@tonic-gate {
6547c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
6557c478bd9Sstevel@tonic-gate 	enum kbtrans_message_response	ret;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6587c478bd9Sstevel@tonic-gate 				"usbkbm_wput entering");
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	/* First, see if kbtrans will handle the message */
6637c478bd9Sstevel@tonic-gate 	ret = kbtrans_streams_message(usbkbmd->usbkbm_kbtrans, mp);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if (ret == KBTRANS_MESSAGE_HANDLED) {
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6687c478bd9Sstevel@tonic-gate 			"usbkbm_wput exiting:2");
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		return;
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/* kbtrans didn't handle the message.  Try to handle it here */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	case M_FLUSH:
6787c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
6797c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
6807c478bd9Sstevel@tonic-gate 		}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
6837c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		break;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	case M_IOCTL:
6897c478bd9Sstevel@tonic-gate 		ret = usbkbm_ioctl(q, mp);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		if (ret == KBTRANS_MESSAGE_HANDLED) {
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6947c478bd9Sstevel@tonic-gate 				"usbkbm_wput exiting:1");
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 			return;
6977c478bd9Sstevel@tonic-gate 		}
6987c478bd9Sstevel@tonic-gate 	default:
6997c478bd9Sstevel@tonic-gate 		break;
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/*
7037c478bd9Sstevel@tonic-gate 	 * The message has not been handled
7047c478bd9Sstevel@tonic-gate 	 * by kbtrans or this module.  Pass it down the stream
7057c478bd9Sstevel@tonic-gate 	 */
7067c478bd9Sstevel@tonic-gate 	putnext(q, mp);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
7097c478bd9Sstevel@tonic-gate 		"usbkbm_wput exiting:3");
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate /*
7137c478bd9Sstevel@tonic-gate  * usbkbm_ioctl :
7147c478bd9Sstevel@tonic-gate  *	Handles the ioctls sent from upper module. Returns
7157c478bd9Sstevel@tonic-gate  *	ACK/NACK back.
7167c478bd9Sstevel@tonic-gate  */
7177c478bd9Sstevel@tonic-gate static enum kbtrans_message_response
7187c478bd9Sstevel@tonic-gate usbkbm_ioctl(register queue_t *q, register mblk_t *mp)
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
7217c478bd9Sstevel@tonic-gate 	struct iocblk		mctlmsg;
7227c478bd9Sstevel@tonic-gate 	struct iocblk		*iocp;
7237c478bd9Sstevel@tonic-gate 	mblk_t			*datap, *mctl_ptr;
7247c478bd9Sstevel@tonic-gate 	size_t			ioctlrespsize;
7257c478bd9Sstevel@tonic-gate 	int			err;
7267c478bd9Sstevel@tonic-gate 	int			tmp;
7277c478bd9Sstevel@tonic-gate 	char			command;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	err = 0;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
7327c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
7357c478bd9Sstevel@tonic-gate 	case CONSSETKBDTYPE:
7367c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7377c478bd9Sstevel@tonic-gate 		if (err != 0) {
7387c478bd9Sstevel@tonic-gate 			break;
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		tmp = *(int *)mp->b_cont->b_rptr;
7417c478bd9Sstevel@tonic-gate 		if (tmp != KB_PC && tmp != KB_USB) {
7427c478bd9Sstevel@tonic-gate 			err = EINVAL;
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 		}
7457c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_vkbd_type = tmp;
7467c478bd9Sstevel@tonic-gate 		break;
7477c478bd9Sstevel@tonic-gate 	case KIOCLAYOUT:
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 		datap = allocb(sizeof (int), BPRI_HI);
7507c478bd9Sstevel@tonic-gate 		if (datap == NULL) {
7517c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 			goto allocfailure;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = usbkbmd->usbkbm_layout;
7577c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
7627c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	case KIOCSLAYOUT:
7667c478bd9Sstevel@tonic-gate 		/*
7677c478bd9Sstevel@tonic-gate 		 * Supply a layout if not specified by the hardware, or
7687c478bd9Sstevel@tonic-gate 		 * override any that was specified.
7697c478bd9Sstevel@tonic-gate 		 */
7707c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
7717c478bd9Sstevel@tonic-gate 			err = EINVAL;
7727c478bd9Sstevel@tonic-gate 			break;
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_layout = *(intptr_t *)mp->b_cont->b_rptr;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/*
7787c478bd9Sstevel@tonic-gate 		 * Save the layout in usbkbm_layout so as to handle the
7797c478bd9Sstevel@tonic-gate 		 * the case when the user has re-plugged in the non-self
7807c478bd9Sstevel@tonic-gate 		 * identifying non US keyboard. In this the layout is saved
7817c478bd9Sstevel@tonic-gate 		 * in global variable, so the user does not have to run
7827c478bd9Sstevel@tonic-gate 		 * kdmconfig again after the X server reset
7837c478bd9Sstevel@tonic-gate 		 */
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		usbkbm_layout = usbkbmd->usbkbm_layout;
7867c478bd9Sstevel@tonic-gate 		break;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	case KIOCCMD:
7897c478bd9Sstevel@tonic-gate 		/*
7907c478bd9Sstevel@tonic-gate 		 * Check if we have at least the subcommand field; any
7917c478bd9Sstevel@tonic-gate 		 * other argument validation has to occur inside
7927c478bd9Sstevel@tonic-gate 		 * usbkbm_kioccmd().
7937c478bd9Sstevel@tonic-gate 		 */
7947c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7957c478bd9Sstevel@tonic-gate 		if (err != 0)
7967c478bd9Sstevel@tonic-gate 			break;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		/* Subcommand */
7997c478bd9Sstevel@tonic-gate 		command = (char)(*(int *)mp->b_cont->b_rptr);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		/*
8027c478bd9Sstevel@tonic-gate 		 * Check if this ioctl is followed by a previous
8037c478bd9Sstevel@tonic-gate 		 * KBD_CMD_SETLED command, in which case we take
8047c478bd9Sstevel@tonic-gate 		 * the command byte as the data for setting the LED
8057c478bd9Sstevel@tonic-gate 		 */
8067c478bd9Sstevel@tonic-gate 		if (usbkbmd->usbkbm_setled_second_byte) {
8077c478bd9Sstevel@tonic-gate 			usbkbm_streams_setled((struct kbtrans_hardware *)
8087c478bd9Sstevel@tonic-gate 						usbkbmd, command);
8097c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_setled_second_byte = 0;
8107c478bd9Sstevel@tonic-gate 			break;
8117c478bd9Sstevel@tonic-gate 		}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		/*
8147c478bd9Sstevel@tonic-gate 		 * In  case of allocb failure, this will
8157c478bd9Sstevel@tonic-gate 		 * return the size of the allocation which
8167c478bd9Sstevel@tonic-gate 		 * failed so that it can be allocated later
8177c478bd9Sstevel@tonic-gate 		 * through bufcall.
8187c478bd9Sstevel@tonic-gate 		 */
8197c478bd9Sstevel@tonic-gate 		ioctlrespsize = 0;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		err = usbkbm_kioccmd(usbkbmd, mp, command, &ioctlrespsize);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 		if (ioctlrespsize != 0) {
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 			goto allocfailure;
8267c478bd9Sstevel@tonic-gate 		}
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		break;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	case CONSOPENPOLLEDIO:
8317c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8327c478bd9Sstevel@tonic-gate 			"usbkbm_ioctl CONSOPENPOLLEDIO");
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct cons_polledio *));
8357c478bd9Sstevel@tonic-gate 		if (err != 0) {
8367c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, usbkbm_log_handle,
8377c478bd9Sstevel@tonic-gate 			    "usbkbm_ioctl: malformed request");
8387c478bd9Sstevel@tonic-gate 			break;
8397c478bd9Sstevel@tonic-gate 		}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		/*
8447c478bd9Sstevel@tonic-gate 		 * Get the polled input structure from hid
8457c478bd9Sstevel@tonic-gate 		 */
8467c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_OPEN_POLLED_INPUT;
8477c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8487c478bd9Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8497c478bd9Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8507c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 			goto allocfailure;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 		/*
8587c478bd9Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8597c478bd9Sstevel@tonic-gate 		 * result of HID_OPEN_POLLED_INPUT
8607c478bd9Sstevel@tonic-gate 		 */
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	case CONSCLOSEPOLLEDIO:
8657c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8667c478bd9Sstevel@tonic-gate 			"usbkbm_ioctl CONSCLOSEPOLLEDIO mp = 0x%p", (void *)mp);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		/*
8717c478bd9Sstevel@tonic-gate 		 * Get the polled input structure from hid
8727c478bd9Sstevel@tonic-gate 		 */
8737c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_CLOSE_POLLED_INPUT;
8747c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8757c478bd9Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8767c478bd9Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8777c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 			goto allocfailure;
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		/*
8857c478bd9Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8867c478bd9Sstevel@tonic-gate 		 * result of HID_CLOSE_POLLED_INPUT
8877c478bd9Sstevel@tonic-gate 		 */
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	case CONSSETABORTENABLE:
8927c478bd9Sstevel@tonic-gate 		/*
8937c478bd9Sstevel@tonic-gate 		 * Nothing special to do for USB.
8947c478bd9Sstevel@tonic-gate 		 */
8957c478bd9Sstevel@tonic-gate 		break;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	default:
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_NOT_HANDLED);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9047c478bd9Sstevel@tonic-gate 	 * Send ACK/NACK to upper module for
9057c478bd9Sstevel@tonic-gate 	 * the messages that have been handled.
9067c478bd9Sstevel@tonic-gate 	 */
9077c478bd9Sstevel@tonic-gate 	if (err != 0) {
9087c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9097c478bd9Sstevel@tonic-gate 		iocp->ioc_error = err;
9107c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
9117c478bd9Sstevel@tonic-gate 	} else {
9127c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9137c478bd9Sstevel@tonic-gate 		iocp->ioc_error = 0;	/* brain rot */
9147c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/* Send the response back up the stream */
9187c478bd9Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_readq, mp);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	return (KBTRANS_MESSAGE_HANDLED);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate allocfailure:
9237c478bd9Sstevel@tonic-gate 	/*
9247c478bd9Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
9257c478bd9Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
9267c478bd9Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
9277c478bd9Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
9287c478bd9Sstevel@tonic-gate 	 * must have timed out.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	freemsg(usbkbmd->usbkbm_streams_iocpending);
9317c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_iocpending = mp;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_streams_bufcallid) {
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 		qunbufcall(usbkbmd->usbkbm_readq,
9367c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_streams_bufcallid);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_bufcallid =
9397c478bd9Sstevel@tonic-gate 		qbufcall(usbkbmd->usbkbm_readq, ioctlrespsize, BPRI_HI,
9407c478bd9Sstevel@tonic-gate 			usbkbm_reioctl, usbkbmd);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	return (KBTRANS_MESSAGE_HANDLED);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * usbkbm_kioccmd :
9477c478bd9Sstevel@tonic-gate  *	Handles KIOCCMD ioctl.
9487c478bd9Sstevel@tonic-gate  */
9497c478bd9Sstevel@tonic-gate static int
9507c478bd9Sstevel@tonic-gate usbkbm_kioccmd(usbkbm_state_t *usbkbmd, register mblk_t *mp,
9517c478bd9Sstevel@tonic-gate 		char command, size_t *ioctlrepsize)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	register mblk_t			*datap;
9547c478bd9Sstevel@tonic-gate 	register struct iocblk		*iocp;
9557c478bd9Sstevel@tonic-gate 	int				err = 0;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	switch (command) {
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 		/* Keyboard layout command */
9627c478bd9Sstevel@tonic-gate 		case KBD_CMD_GETLAYOUT:
9637c478bd9Sstevel@tonic-gate 			/* layout learned at attached time. */
9647c478bd9Sstevel@tonic-gate 			datap = allocb(sizeof (int), BPRI_HI);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 			/* Return error  on allocation failure */
9677c478bd9Sstevel@tonic-gate 			if (datap == NULL) {
9687c478bd9Sstevel@tonic-gate 				*ioctlrepsize = sizeof (int);
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 				return (EIO);
9717c478bd9Sstevel@tonic-gate 			}
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 			*(int *)datap->b_wptr = usbkbmd->usbkbm_layout;
9747c478bd9Sstevel@tonic-gate 			datap->b_wptr += sizeof (int);
9757c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
9767c478bd9Sstevel@tonic-gate 			mp->b_cont = datap;
9777c478bd9Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
9787c478bd9Sstevel@tonic-gate 			break;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		case KBD_CMD_SETLED:
9817c478bd9Sstevel@tonic-gate 			/*
9827c478bd9Sstevel@tonic-gate 			 * Emulate type 4 keyboard :
9837c478bd9Sstevel@tonic-gate 			 * Ignore this ioctl; the following
9847c478bd9Sstevel@tonic-gate 			 * ioctl will specify the data byte for
9857c478bd9Sstevel@tonic-gate 			 * setting the LEDs; setting usbkbm_setled_second_byte
9867c478bd9Sstevel@tonic-gate 			 * will help recognizing that ioctl
9877c478bd9Sstevel@tonic-gate 			 */
9887c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_setled_second_byte = 1;
9897c478bd9Sstevel@tonic-gate 			break;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		case KBD_CMD_RESET:
9927c478bd9Sstevel@tonic-gate 			break;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 		case KBD_CMD_BELL:
9957c478bd9Sstevel@tonic-gate 			/*
9967c478bd9Sstevel@tonic-gate 			 * USB keyboards do not have a beeper
9977c478bd9Sstevel@tonic-gate 			 * in it, the generic beeper interface
9987c478bd9Sstevel@tonic-gate 			 * is used. Turn the beeper on.
9997c478bd9Sstevel@tonic-gate 			 */
10007c478bd9Sstevel@tonic-gate 			beeper_on(BEEP_TYPE4);
10017c478bd9Sstevel@tonic-gate 			break;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 		case KBD_CMD_NOBELL:
10047c478bd9Sstevel@tonic-gate 			/*
10057c478bd9Sstevel@tonic-gate 			 * USB keyboards do not have a beeper
10067c478bd9Sstevel@tonic-gate 			 * in it, the generic beeper interface
10077c478bd9Sstevel@tonic-gate 			 * is used. Turn the beeper off.
10087c478bd9Sstevel@tonic-gate 			 */
10097c478bd9Sstevel@tonic-gate 			beeper_off();
10107c478bd9Sstevel@tonic-gate 			break;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 		case KBD_CMD_CLICK:
10137c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
10147c478bd9Sstevel@tonic-gate 		case KBD_CMD_NOCLICK:
10157c478bd9Sstevel@tonic-gate 			break;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 		default:
10187c478bd9Sstevel@tonic-gate 			err = EIO;
10197c478bd9Sstevel@tonic-gate 			break;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	return (err);
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate /*
10287c478bd9Sstevel@tonic-gate  * usbkbm_rput :
10297c478bd9Sstevel@tonic-gate  *	Put procedure for input from driver end of stream (read queue).
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate static void
10327c478bd9Sstevel@tonic-gate usbkbm_rput(register queue_t *q, register mblk_t *mp)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
10397c478bd9Sstevel@tonic-gate 		"usbkbm_rput");
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if (usbkbmd == 0) {
10427c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* nobody's listening */
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		return;
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	case M_FLUSH:
10507c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
10517c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
10527c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
10537c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 		freemsg(mp);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 		return;
10587c478bd9Sstevel@tonic-gate 	case M_BREAK:
10597c478bd9Sstevel@tonic-gate 		/*
10607c478bd9Sstevel@tonic-gate 		 * Will get M_BREAK only if this is not the system
10617c478bd9Sstevel@tonic-gate 		 * keyboard, otherwise serial port will eat break
10627c478bd9Sstevel@tonic-gate 		 * and call kmdb/OBP, without passing anything up.
10637c478bd9Sstevel@tonic-gate 		 */
10647c478bd9Sstevel@tonic-gate 		freemsg(mp);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 		return;
10677c478bd9Sstevel@tonic-gate 	case M_DATA:
10687c478bd9Sstevel@tonic-gate 		if (!(usbkbmd->usbkbm_flags & USBKBM_OPEN)) {
10697c478bd9Sstevel@tonic-gate 			freemsg(mp);	/* not ready to listen */
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 			return;
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 		break;
10757c478bd9Sstevel@tonic-gate 	case M_CTL:
10767c478bd9Sstevel@tonic-gate 		usbkbm_mctl_receive(q, mp);
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 		return;
10797c478bd9Sstevel@tonic-gate 	case M_ERROR:
10807c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
10817c478bd9Sstevel@tonic-gate 		freemsg(mp);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 		return;
10847c478bd9Sstevel@tonic-gate 	case M_IOCACK:
10857c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
10867c478bd9Sstevel@tonic-gate 		putnext(q, mp);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		return;
10897c478bd9Sstevel@tonic-gate 	default:
10907c478bd9Sstevel@tonic-gate 		putnext(q, mp);
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 		return;
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	/*
10967c478bd9Sstevel@tonic-gate 	 * A data message, consisting of bytes from the keyboard.
10977c478bd9Sstevel@tonic-gate 	 * Ram them through the translator, only if there are
10987c478bd9Sstevel@tonic-gate 	 * correct no. of bytes.
10997c478bd9Sstevel@tonic-gate 	 */
11007c478bd9Sstevel@tonic-gate 	if ((mp->b_wptr - mp->b_rptr) == usbkbmd->usbkbm_packet_size) {
11017c478bd9Sstevel@tonic-gate 		usbkbm_unpack_usb_packet(usbkbmd, usbkbm_streams_callback,
11027c478bd9Sstevel@tonic-gate 		    (uchar_t *)mp->b_rptr, usbkbmd->usbkbm_packet_size);
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	freemsg(mp);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate /*
11097c478bd9Sstevel@tonic-gate  * usbkbm_mctl_receive :
11107c478bd9Sstevel@tonic-gate  *	Handle M_CTL messages from hid. If we don't understand
11117c478bd9Sstevel@tonic-gate  *	the command, send it up.
11127c478bd9Sstevel@tonic-gate  */
11137c478bd9Sstevel@tonic-gate static void
11147c478bd9Sstevel@tonic-gate usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
11157c478bd9Sstevel@tonic-gate {
11167c478bd9Sstevel@tonic-gate 	register usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
11177c478bd9Sstevel@tonic-gate 	register struct iocblk *iocp, mctlmsg;
11187c478bd9Sstevel@tonic-gate 	caddr_t  data = NULL;
11197c478bd9Sstevel@tonic-gate 	mblk_t	*reply_mp, *mctl_ptr;
11207c478bd9Sstevel@tonic-gate 	uchar_t	new_buffer[USBKBM_MAXPKTSIZE];
11217c478bd9Sstevel@tonic-gate 	size_t   size;
11227c478bd9Sstevel@tonic-gate 	hid_req_t buf;
11237c478bd9Sstevel@tonic-gate 	size_t len = sizeof (buf);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
11287c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL)
11297c478bd9Sstevel@tonic-gate 		data = (caddr_t)mp->b_cont->b_rptr;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	case HID_SET_REPORT:
11347c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
11357c478bd9Sstevel@tonic-gate 			"usbkbm_mctl_receive HID_SET mctl");
11367c478bd9Sstevel@tonic-gate 		freemsg(mp);
11377c478bd9Sstevel@tonic-gate 		/* Setting of the LED is not waiting for this message */
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 		break;
11407c478bd9Sstevel@tonic-gate 	case HID_SET_PROTOCOL:
11417c478bd9Sstevel@tonic-gate 		freemsg(mp);
11427c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 		break;
11457c478bd9Sstevel@tonic-gate 	case HID_GET_PARSER_HANDLE:
11467c478bd9Sstevel@tonic-gate 		if ((data != NULL) &&
11477c478bd9Sstevel@tonic-gate 		    (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
11487c478bd9Sstevel@tonic-gate 		    ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
11497c478bd9Sstevel@tonic-gate 		    iocp->ioc_count)) {
11507c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr =
11517c478bd9Sstevel@tonic-gate 			    *(hidparser_handle_t *)data;
11527c478bd9Sstevel@tonic-gate 		} else {
11537c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr = NULL;
11547c478bd9Sstevel@tonic-gate 		}
11557c478bd9Sstevel@tonic-gate 		freemsg(mp);
11567c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 		break;
1159*6d9a41ffSqz150045 	case HID_GET_VID_PID:
1160*6d9a41ffSqz150045 		if ((data != NULL) &&
1161*6d9a41ffSqz150045 		    (iocp->ioc_count == sizeof (hid_vid_pid_t)) &&
1162*6d9a41ffSqz150045 		    ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
1163*6d9a41ffSqz150045 		    iocp->ioc_count)) {
1164*6d9a41ffSqz150045 			bcopy(data, &usbkbmd->usbkbm_vid_pid, iocp->ioc_count);
1165*6d9a41ffSqz150045 		}
1166*6d9a41ffSqz150045 		freemsg(mp);
1167*6d9a41ffSqz150045 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
1168*6d9a41ffSqz150045 
1169*6d9a41ffSqz150045 		break;
11707c478bd9Sstevel@tonic-gate 	case HID_OPEN_POLLED_INPUT:
11717c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
11727c478bd9Sstevel@tonic-gate 			"usbkbm_mctl_receive HID_OPEN_POLLED_INPUT");
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		size = sizeof (hid_polled_input_callback_t);
11757c478bd9Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
11767c478bd9Sstevel@tonic-gate 		if ((data != NULL) &&
11777c478bd9Sstevel@tonic-gate 		    (iocp->ioc_count == size) &&
11787c478bd9Sstevel@tonic-gate 		    ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) == size)) {
11797c478bd9Sstevel@tonic-gate 			/*
11807c478bd9Sstevel@tonic-gate 			 *  Copy the information from hid into the
11817c478bd9Sstevel@tonic-gate 			 * state structure
11827c478bd9Sstevel@tonic-gate 			 */
11837c478bd9Sstevel@tonic-gate 			bcopy(data, &usbkbmd->usbkbm_hid_callback, size);
11847c478bd9Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCACK;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 			/*
11877c478bd9Sstevel@tonic-gate 			 * We are given an appropriate-sized data block,
11887c478bd9Sstevel@tonic-gate 			 * and return a pointer to our structure in it.
11897c478bd9Sstevel@tonic-gate 			 * The structure is saved in the states structure
11907c478bd9Sstevel@tonic-gate 			 */
11917c478bd9Sstevel@tonic-gate 			*(cons_polledio_t **)reply_mp->b_cont->b_rptr =
11927c478bd9Sstevel@tonic-gate 				&usbkbmd->usbkbm_polled_info;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 		} else {
11957c478bd9Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCNAK;
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 		freemsg(mp);
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 		putnext(q, reply_mp);
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		break;
12047c478bd9Sstevel@tonic-gate 	case HID_CLOSE_POLLED_INPUT:
12057c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12067c478bd9Sstevel@tonic-gate 			"usbkbm_mctl_receive HID_CLOSE_POLLED_INPUT");
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		bzero(&usbkbmd->usbkbm_hid_callback,
12107c478bd9Sstevel@tonic-gate 				sizeof (hid_polled_input_callback_t));
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 		freemsg(mp);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)reply_mp->b_rptr;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12197c478bd9Sstevel@tonic-gate 			"usbkbm_mctl_receive reply reply_mp 0x%p cmd 0x%x",
12207c478bd9Sstevel@tonic-gate 			(void *)reply_mp, iocp->ioc_cmd);
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		reply_mp->b_datap->db_type = M_IOCACK;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 		putnext(q, reply_mp);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 		break;
12307c478bd9Sstevel@tonic-gate 	case HID_DISCONNECT_EVENT :
12317c478bd9Sstevel@tonic-gate 	case HID_POWER_OFF:
12327c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12337c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_DISCONNECT_EVENT/HID_POWER_OFF");
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 		/* Indicate all keys have been released */
12367c478bd9Sstevel@tonic-gate 		bzero(new_buffer, USBKBM_MAXPKTSIZE);
12377c478bd9Sstevel@tonic-gate 		usbkbm_unpack_usb_packet(usbkbmd, usbkbm_streams_callback,
12387c478bd9Sstevel@tonic-gate 		    new_buffer, usbkbmd->usbkbm_packet_size);
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		freemsg(mp);
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 		break;
12437c478bd9Sstevel@tonic-gate 	case HID_CONNECT_EVENT:
12447c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_SET_PROTOCOL;
12457c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
12467c478bd9Sstevel@tonic-gate 		buf.hid_req_version_no = HID_VERSION_V_0;
12477c478bd9Sstevel@tonic-gate 		buf.hid_req_wValue = SET_BOOT_PROTOCOL;
12487c478bd9Sstevel@tonic-gate 		buf.hid_req_wLength = 0;
12497c478bd9Sstevel@tonic-gate 		buf.hid_req_data = NULL;
12507c478bd9Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, &buf, len);
12517c478bd9Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
12527c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, usbkbm_log_handle,
12537c478bd9Sstevel@tonic-gate 			    "usbkbm_mctl_receive HID_CONNECT_EVENT: "
12547c478bd9Sstevel@tonic-gate 			    "Set protocol failed");
12557c478bd9Sstevel@tonic-gate 		} else {
12567c478bd9Sstevel@tonic-gate 			putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
12577c478bd9Sstevel@tonic-gate 		}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
12607c478bd9Sstevel@tonic-gate 	case HID_FULL_POWER :
12617c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12627c478bd9Sstevel@tonic-gate 			"usbkbm_mctl_receive restore LEDs");
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		/* send setled command down to restore LED states */
12657c478bd9Sstevel@tonic-gate 		usbkbm_streams_setled((struct kbtrans_hardware *)usbkbmd,
12667c478bd9Sstevel@tonic-gate 					usbkbm_led_state);
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 		freemsg(mp);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		break;
12717c478bd9Sstevel@tonic-gate 	default:
12727c478bd9Sstevel@tonic-gate 		putnext(q, mp);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 		break;
12757c478bd9Sstevel@tonic-gate 	}
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*
12807c478bd9Sstevel@tonic-gate  * usbkbm_streams_setled :
12817c478bd9Sstevel@tonic-gate  *	Update the keyboard LEDs to match the current keyboard state.
12827c478bd9Sstevel@tonic-gate  *	Send LED state downstreams to hid driver.
12837c478bd9Sstevel@tonic-gate  */
12847c478bd9Sstevel@tonic-gate static void
12857c478bd9Sstevel@tonic-gate usbkbm_streams_setled(struct kbtrans_hardware *kbtrans_hw, int state)
12867c478bd9Sstevel@tonic-gate {
12877c478bd9Sstevel@tonic-gate 	struct iocblk	mctlmsg;
12887c478bd9Sstevel@tonic-gate 	mblk_t		*LED_message, *mctl_ptr;
12897c478bd9Sstevel@tonic-gate 	hid_req_t	*LED_report;
12907c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
12917c478bd9Sstevel@tonic-gate 	uchar_t		led_state;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	usbkbm_led_state = (uchar_t)state;
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)kbtrans_hw;
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	LED_report = kmem_zalloc(sizeof (hid_req_t), KM_NOSLEEP);
12987c478bd9Sstevel@tonic-gate 	if (LED_report == NULL) {
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		return;
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	/*
13047c478bd9Sstevel@tonic-gate 	 * Send the request to the hid driver to set LED.
13057c478bd9Sstevel@tonic-gate 	 */
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	/* Create an mblk_t */
13087c478bd9Sstevel@tonic-gate 	LED_message = allocb(sizeof (uchar_t), BPRI_HI);
13097c478bd9Sstevel@tonic-gate 	if (LED_message == NULL) {
13107c478bd9Sstevel@tonic-gate 		kmem_free(LED_report, sizeof (hid_req_t));
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 		return;
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	led_state = 0;
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	/*
13187c478bd9Sstevel@tonic-gate 	 * Set the led state based on the state that is passed in.
13197c478bd9Sstevel@tonic-gate 	 */
13207c478bd9Sstevel@tonic-gate 	if (state & LED_NUM_LOCK) {
13217c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_NUM_LOCK;
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	if (state & LED_COMPOSE) {
13257c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_COMPOSE;
13267c478bd9Sstevel@tonic-gate 	}
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 	if (state & LED_SCROLL_LOCK) {
13297c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_SCROLL_LOCK;
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	if (state & LED_CAPS_LOCK) {
13337c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_CAPS_LOCK;
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	if (state & LED_KANA) {
13377c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_KANA;
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	bcopy((void *)&led_state, (void *)LED_message->b_wptr, 1);
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	LED_message->b_wptr = LED_message->b_wptr + 1;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
13457c478bd9Sstevel@tonic-gate 		"usbkbm: Send Ctrl Request. Data is 0x%x",
13467c478bd9Sstevel@tonic-gate 		(uchar_t)*LED_message->b_rptr);
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	LED_report->hid_req_version_no = HID_VERSION_V_0;
13497c478bd9Sstevel@tonic-gate 	LED_report->hid_req_wValue = REPORT_TYPE_OUTPUT;
13507c478bd9Sstevel@tonic-gate 	LED_report->hid_req_wLength = sizeof (uchar_t);
13517c478bd9Sstevel@tonic-gate 	LED_report->hid_req_data = LED_message;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_SET_REPORT;
13547c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_count = sizeof (LED_report);
13557c478bd9Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, LED_report, sizeof (hid_req_t));
13567c478bd9Sstevel@tonic-gate 	if (mctl_ptr != NULL) {
13577c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
13587c478bd9Sstevel@tonic-gate 	} else {
13597c478bd9Sstevel@tonic-gate 		freemsg(LED_message);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	/*
13637c478bd9Sstevel@tonic-gate 	 * We are not waiting for response of HID_SET_REPORT
13647c478bd9Sstevel@tonic-gate 	 * mctl for setting the LED.
13657c478bd9Sstevel@tonic-gate 	 */
13667c478bd9Sstevel@tonic-gate 	kmem_free(LED_report, sizeof (hid_req_t));
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate /*
13717c478bd9Sstevel@tonic-gate  * usbkbm_polled_keycheck :
13727c478bd9Sstevel@tonic-gate  *	This routine is called to determine if there is a scancode that
13737c478bd9Sstevel@tonic-gate  *	is available for input.  This routine is called at poll time and
13747c478bd9Sstevel@tonic-gate  *	returns a key/state pair to the caller.  If there are characters
13757c478bd9Sstevel@tonic-gate  *	buffered up, the routine returns right away with the key/state pair.
13767c478bd9Sstevel@tonic-gate  *	Otherwise, the routine calls down to check for characters and returns
13777c478bd9Sstevel@tonic-gate  *	the first key/state pair if there are any characters pending.
13787c478bd9Sstevel@tonic-gate  */
13797c478bd9Sstevel@tonic-gate static boolean_t
13807c478bd9Sstevel@tonic-gate usbkbm_polled_keycheck(struct kbtrans_hardware *hw,
13817c478bd9Sstevel@tonic-gate 	int *key, enum keystate *state)
13827c478bd9Sstevel@tonic-gate {
13837c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
13847c478bd9Sstevel@tonic-gate 	uchar_t				*buffer;
13857c478bd9Sstevel@tonic-gate 	unsigned			num_keys;
13867c478bd9Sstevel@tonic-gate 	hid_polled_handle_t		hid_polled_handle;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)hw;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	/*
13917c478bd9Sstevel@tonic-gate 	 * If there are already characters buffered up, then we are done.
13927c478bd9Sstevel@tonic-gate 	 */
13937c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 		return (B_TRUE);
13987c478bd9Sstevel@tonic-gate 	}
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	hid_polled_handle =
14017c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	num_keys = (usbkbmd->usbkbm_hid_callback.hid_polled_read)
14047c478bd9Sstevel@tonic-gate 				(hid_polled_handle, &buffer);
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	/*
14077c478bd9Sstevel@tonic-gate 	 * If we don't get any characters back then indicate that, and we
14087c478bd9Sstevel@tonic-gate 	 * are done.
14097c478bd9Sstevel@tonic-gate 	 */
14107c478bd9Sstevel@tonic-gate 	if (num_keys == 0) {
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 		return (B_FALSE);
14137c478bd9Sstevel@tonic-gate 	}
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	/*
14167c478bd9Sstevel@tonic-gate 	 * We have a usb packet, so pass this packet to
14177c478bd9Sstevel@tonic-gate 	 * usbkbm_unpack_usb_packet so that it can be broken up into
14187c478bd9Sstevel@tonic-gate 	 * individual key/state values.
14197c478bd9Sstevel@tonic-gate 	 */
14207c478bd9Sstevel@tonic-gate 	usbkbm_unpack_usb_packet(usbkbmd, usbkbm_poll_callback,
14217c478bd9Sstevel@tonic-gate 		buffer, num_keys);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	/*
14247c478bd9Sstevel@tonic-gate 	 * If a scancode was returned as a result of this packet,
14257c478bd9Sstevel@tonic-gate 	 * then translate the scancode.
14267c478bd9Sstevel@tonic-gate 	 */
14277c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		return (B_TRUE);
14327c478bd9Sstevel@tonic-gate 	}
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	return (B_FALSE);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *usbkbmd)
14387c478bd9Sstevel@tonic-gate {
14397c478bd9Sstevel@tonic-gate 	ushort_t	ret;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	ASSERT(usbkbmd->usbkbm_vkbd_type == KB_PC ||
14427c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_vkbd_type == KB_USB);
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_vkbd_type == KB_PC)
14457c478bd9Sstevel@tonic-gate 		ret = INDEXTO_PC;
14467c478bd9Sstevel@tonic-gate 	else
14477c478bd9Sstevel@tonic-gate 		ret = INDEXTO_USB;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	return (ret);
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate /*
14527c478bd9Sstevel@tonic-gate  * usbkbm_streams_callback :
14537c478bd9Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14547c478bd9Sstevel@tonic-gate  *	usb packets for normal streams-based input.  We pass a pointer
14557c478bd9Sstevel@tonic-gate  *	to this routine to usbkbm_unpack_usb_packet.  This routine will
14567c478bd9Sstevel@tonic-gate  *	get called with an unpacked key (scancode) and state (press/release).
14577c478bd9Sstevel@tonic-gate  *	We pass it to the generic keyboard module.
14587c478bd9Sstevel@tonic-gate  *
14597c478bd9Sstevel@tonic-gate  * 	'index' and the function pointers:
14607c478bd9Sstevel@tonic-gate  *	Map USB scancodes to PC scancodes by lookup table.
14617c478bd9Sstevel@tonic-gate  *	This fix is mainly meant for x86 platforms. For SPARC systems
14627c478bd9Sstevel@tonic-gate  *	this fix doesn't change the way in which the scancodes are processed.
14637c478bd9Sstevel@tonic-gate  */
14647c478bd9Sstevel@tonic-gate static void
14657c478bd9Sstevel@tonic-gate usbkbm_streams_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	ushort_t index = usbkbm_get_state(usbkbmd);
14687c478bd9Sstevel@tonic-gate 	(*usbkbm_xlate[index])(usbkbmd, key, state);
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate /*
14727c478bd9Sstevel@tonic-gate  * Don't do any translations. Send to 'kbtrans' for processing.
14737c478bd9Sstevel@tonic-gate  */
14747c478bd9Sstevel@tonic-gate static void
14757c478bd9Sstevel@tonic-gate usbkbm_wrap_kbtrans(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14767c478bd9Sstevel@tonic-gate {
14777c478bd9Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate  * Translate USB scancodes to PC scancodes before sending it to 'kbtrans'
14827c478bd9Sstevel@tonic-gate  */
14837c478bd9Sstevel@tonic-gate void
14847c478bd9Sstevel@tonic-gate usbkbm_usb2pc_xlate(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	key = kbtrans_keycode_usb2pc(key);
14877c478bd9Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14887c478bd9Sstevel@tonic-gate }
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate  * usbkbm_poll_callback :
14927c478bd9Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14937c478bd9Sstevel@tonic-gate  *	usb packets for polled input.  We pass a pointer to this routine
14947c478bd9Sstevel@tonic-gate  *	to usbkbm_unpack_usb_packet.  This routine will get called with
14957c478bd9Sstevel@tonic-gate  *	an unpacked key (scancode) and state (press/release).  We will
14967c478bd9Sstevel@tonic-gate  *	store the key/state pair into a circular buffer so that it can
14977c478bd9Sstevel@tonic-gate  *	be translated into an ascii key later.
14987c478bd9Sstevel@tonic-gate  */
14997c478bd9Sstevel@tonic-gate static void
15007c478bd9Sstevel@tonic-gate usbkbm_poll_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	/*
15037c478bd9Sstevel@tonic-gate 	 * Check to make sure that the buffer isn't already full
15047c478bd9Sstevel@tonic-gate 	 */
15057c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters ==
15067c478bd9Sstevel@tonic-gate 		USB_POLLED_BUFFER_SIZE) {
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 		/*
15097c478bd9Sstevel@tonic-gate 		 * The buffer is full, we will drop this character.
15107c478bd9Sstevel@tonic-gate 		 */
15117c478bd9Sstevel@tonic-gate 		return;
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	/*
15157c478bd9Sstevel@tonic-gate 	 * Save the scancode in the buffer
15167c478bd9Sstevel@tonic-gate 	 */
15177c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_key = key;
15187c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_state = state;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	/*
15217c478bd9Sstevel@tonic-gate 	 * We have one more character in the buffer
15227c478bd9Sstevel@tonic-gate 	 */
15237c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters++;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	/*
15267c478bd9Sstevel@tonic-gate 	 * Increment to the next available slot.
15277c478bd9Sstevel@tonic-gate 	 */
15287c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head++;
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/*
15317c478bd9Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15327c478bd9Sstevel@tonic-gate 	 */
15337c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_head -
15347c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_scancode_buffer ==
15357c478bd9Sstevel@tonic-gate 			USB_POLLED_BUFFER_SIZE) {
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_head =
15387c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_polled_scancode_buffer;
15397c478bd9Sstevel@tonic-gate 	}
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate /*
15437c478bd9Sstevel@tonic-gate  * usbkbm_get_scancode :
15447c478bd9Sstevel@tonic-gate  *	This routine retreives a key/state pair from the circular buffer.
15457c478bd9Sstevel@tonic-gate  *	The pair was put in the buffer by usbkbm_poll_callback when a
15467c478bd9Sstevel@tonic-gate  *	USB packet was translated into a key/state by usbkbm_unpack_usb_packet.
15477c478bd9Sstevel@tonic-gate  */
15487c478bd9Sstevel@tonic-gate static void
15497c478bd9Sstevel@tonic-gate usbkbm_get_scancode(usbkbm_state_t *usbkbmd, int *key, enum keystate *state)
15507c478bd9Sstevel@tonic-gate {
15517c478bd9Sstevel@tonic-gate 	/*
15527c478bd9Sstevel@tonic-gate 	 * Copy the character.
15537c478bd9Sstevel@tonic-gate 	 */
15547c478bd9Sstevel@tonic-gate 	*key = usbkbmd->usbkbm_polled_buffer_tail->poll_key;
15557c478bd9Sstevel@tonic-gate 	*state = usbkbmd->usbkbm_polled_buffer_tail->poll_state;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	/*
15587c478bd9Sstevel@tonic-gate 	 * Increment to the next character to be copied from
15597c478bd9Sstevel@tonic-gate 	 * and to.
15607c478bd9Sstevel@tonic-gate 	 */
15617c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail++;
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	/*
15647c478bd9Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15657c478bd9Sstevel@tonic-gate 	 */
15667c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_tail -
15677c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_scancode_buffer ==
15687c478bd9Sstevel@tonic-gate 			USB_POLLED_BUFFER_SIZE) {
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_tail =
15717c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_polled_scancode_buffer;
15727c478bd9Sstevel@tonic-gate 	}
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	/*
15757c478bd9Sstevel@tonic-gate 	 * We have one less character in the buffer.
15767c478bd9Sstevel@tonic-gate 	 */
15777c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters--;
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate  * usbkbm_polled_setled :
15827c478bd9Sstevel@tonic-gate  *	This routine is a place holder.  Someday, we may want to allow led
15837c478bd9Sstevel@tonic-gate  *	state to be updated from within polled mode.
15847c478bd9Sstevel@tonic-gate  */
15857c478bd9Sstevel@tonic-gate /* ARGSUSED */
15867c478bd9Sstevel@tonic-gate static void
15877c478bd9Sstevel@tonic-gate usbkbm_polled_setled(struct kbtrans_hardware *hw, int led_state)
15887c478bd9Sstevel@tonic-gate {
15897c478bd9Sstevel@tonic-gate 	/* nothing to do for now */
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate /*
15937c478bd9Sstevel@tonic-gate  * This is a pass-thru routine to get a character at poll time.
15947c478bd9Sstevel@tonic-gate  */
15957c478bd9Sstevel@tonic-gate static int
15967c478bd9Sstevel@tonic-gate usbkbm_polled_getchar(struct cons_polledio_arg *arg)
15977c478bd9Sstevel@tonic-gate {
15987c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	return (kbtrans_getchar(usbkbmd->usbkbm_kbtrans));
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate /*
16067c478bd9Sstevel@tonic-gate  * This is a pass-thru routine to test if character is available for reading
16077c478bd9Sstevel@tonic-gate  * at poll time.
16087c478bd9Sstevel@tonic-gate  */
16097c478bd9Sstevel@tonic-gate static boolean_t
16107c478bd9Sstevel@tonic-gate usbkbm_polled_ischar(struct cons_polledio_arg *arg)
16117c478bd9Sstevel@tonic-gate {
16127c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 	return (kbtrans_ischar(usbkbmd->usbkbm_kbtrans));
16177c478bd9Sstevel@tonic-gate }
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate /*
16207c478bd9Sstevel@tonic-gate  * usbkbm_polled_input_enter :
16217c478bd9Sstevel@tonic-gate  *	This is a pass-thru initialization routine for the lower layer drivers.
16227c478bd9Sstevel@tonic-gate  *	This routine is called at poll time to set the state for polled input.
16237c478bd9Sstevel@tonic-gate  */
16247c478bd9Sstevel@tonic-gate static void
16257c478bd9Sstevel@tonic-gate usbkbm_polled_enter(struct cons_polledio_arg *arg)
16267c478bd9Sstevel@tonic-gate {
16277c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
16287c478bd9Sstevel@tonic-gate 	hid_polled_handle_t		hid_polled_handle;
16297c478bd9Sstevel@tonic-gate 	uint_t				uindex;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	/*
16347c478bd9Sstevel@tonic-gate 	 * Before switching to POLLED mode, copy the contents of
16357c478bd9Sstevel@tonic-gate 	 * usbkbm_pendingusbpacket to usbkbm_lastusbpacket since
16367c478bd9Sstevel@tonic-gate 	 * usbkbm_pendingusbpacket field has currently processed
16377c478bd9Sstevel@tonic-gate 	 * key events of the current OS mode usb keyboard packet.
16387c478bd9Sstevel@tonic-gate 	 */
16397c478bd9Sstevel@tonic-gate 	for (uindex = 2; uindex < USBKBM_MAXPKTSIZE; uindex ++) {
16407c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_lastusbpacket[uindex] =
16417c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_pendingusbpacket[uindex];
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 	hid_polled_handle =
16477c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	(void) (usbkbmd->usbkbm_hid_callback.hid_polled_input_enter)
16507c478bd9Sstevel@tonic-gate 					(hid_polled_handle);
16517c478bd9Sstevel@tonic-gate }
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate /*
16547c478bd9Sstevel@tonic-gate  * usbkbm_polled_input_exit :
16557c478bd9Sstevel@tonic-gate  *	This is a pass-thru restoration routine for the lower layer drivers.
16567c478bd9Sstevel@tonic-gate  *	This routine is called at poll time to reset the state back to streams
16577c478bd9Sstevel@tonic-gate  *	input.
16587c478bd9Sstevel@tonic-gate  */
16597c478bd9Sstevel@tonic-gate static void
16607c478bd9Sstevel@tonic-gate usbkbm_polled_exit(struct cons_polledio_arg *arg)
16617c478bd9Sstevel@tonic-gate {
16627c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
16637c478bd9Sstevel@tonic-gate 	hid_polled_handle_t		hid_polled_handle;
16647c478bd9Sstevel@tonic-gate 	uint_t				uindex;
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	/*
16697c478bd9Sstevel@tonic-gate 	 * Before returning to OS mode, copy the contents of
16707c478bd9Sstevel@tonic-gate 	 * usbkbm_lastusbpacket to usbkbm_pendingusbpacket since
16717c478bd9Sstevel@tonic-gate 	 * usbkbm_lastusbpacket field has processed key events
16727c478bd9Sstevel@tonic-gate 	 * of the last POLLED mode usb keyboard packet.
16737c478bd9Sstevel@tonic-gate 	 */
16747c478bd9Sstevel@tonic-gate 	for (uindex = 2; uindex < USBKBM_MAXPKTSIZE; uindex ++) {
16757c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] =
16767c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_lastusbpacket[uindex];
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_lastusbpacket[uindex] = 0;
16797c478bd9Sstevel@tonic-gate 	}
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 	hid_polled_handle =
16827c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	(void) (usbkbmd->usbkbm_hid_callback.hid_polled_input_exit)
16857c478bd9Sstevel@tonic-gate 			(hid_polled_handle);
16867c478bd9Sstevel@tonic-gate }
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate /*
16897c478bd9Sstevel@tonic-gate  * usbkbm_unpack_usb_packet :
16907c478bd9Sstevel@tonic-gate  *	USB key packets contain 8 bytes while in boot protocol mode.
16917c478bd9Sstevel@tonic-gate  *	The first byte contains bit packed modifier key information.
16927c478bd9Sstevel@tonic-gate  *	Second byte is reserved. The last 6 bytes contain bytes of
16937c478bd9Sstevel@tonic-gate  *	currently pressed keys. If a key was not recorded on the
16947c478bd9Sstevel@tonic-gate  *	previous packet, but present in the current packet, then set
16957c478bd9Sstevel@tonic-gate  *	state to KEY_PRESSED. If a key was recorded in the previous packet,
16967c478bd9Sstevel@tonic-gate  *	but not present in the current packet, then state to KEY_RELEASED
16977c478bd9Sstevel@tonic-gate  *	Follow a similar algorithm for bit packed modifier keys.
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate static void
17007c478bd9Sstevel@tonic-gate usbkbm_unpack_usb_packet(usbkbm_state_t *usbkbmd, process_key_callback_t func,
17017c478bd9Sstevel@tonic-gate 	uchar_t *usbpacket, int packet_size)
17027c478bd9Sstevel@tonic-gate {
17037c478bd9Sstevel@tonic-gate 	uchar_t		mkb;
17047c478bd9Sstevel@tonic-gate 	uchar_t		lastmkb;
17057c478bd9Sstevel@tonic-gate 	uchar_t		*lastusbpacket = usbkbmd->usbkbm_lastusbpacket;
17067c478bd9Sstevel@tonic-gate 	int		uindex, lindex, rollover;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	mkb = usbpacket[0];
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	lastmkb = lastusbpacket[0];
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	for (uindex = 0; uindex < packet_size; uindex++) {
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
17157c478bd9Sstevel@tonic-gate 			" %x ", usbpacket[uindex]);
17167c478bd9Sstevel@tonic-gate 	}
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
17197c478bd9Sstevel@tonic-gate 			" is the usbkeypacket");
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	/* check to see if modifier keys are different */
17227c478bd9Sstevel@tonic-gate 	if (mkb != lastmkb) {
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LSHIFTBIT) != (lastmkb & USB_LSHIFTBIT)) {
17257c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LSHIFTKEY, (mkb&USB_LSHIFTBIT) ?
17267c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17277c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17287c478bd9Sstevel@tonic-gate 				"unpack: sending USB_LSHIFTKEY");
17297c478bd9Sstevel@tonic-gate 		}
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LCTLBIT) != (lastmkb & USB_LCTLBIT)) {
17327c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LCTLCKEY, mkb&USB_LCTLBIT ?
17337c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17347c478bd9Sstevel@tonic-gate 		}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LALTBIT) != (lastmkb & USB_LALTBIT)) {
17377c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LALTKEY, mkb&USB_LALTBIT ?
17387c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17397c478bd9Sstevel@tonic-gate 		}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LMETABIT) != (lastmkb & USB_LMETABIT)) {
17427c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LMETAKEY, mkb&USB_LMETABIT ?
17437c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17447c478bd9Sstevel@tonic-gate 		}
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RMETABIT) != (lastmkb & USB_RMETABIT)) {
17477c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RMETAKEY, mkb&USB_RMETABIT ?
17487c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17497c478bd9Sstevel@tonic-gate 		}
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RALTBIT) != (lastmkb & USB_RALTBIT)) {
17527c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RALTKEY, mkb&USB_RALTBIT ?
17537c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17547c478bd9Sstevel@tonic-gate 		}
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RCTLBIT) != (lastmkb & USB_RCTLBIT)) {
17577c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RCTLCKEY, mkb&USB_RCTLBIT ?
17587c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17597c478bd9Sstevel@tonic-gate 		}
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RSHIFTBIT) != (lastmkb & USB_RSHIFTBIT)) {
17627c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RSHIFTKEY, mkb&USB_RSHIFTBIT ?
17637c478bd9Sstevel@tonic-gate 				KEY_PRESSED : KEY_RELEASED);
17647c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17657c478bd9Sstevel@tonic-gate 				"unpack: sending USB_RSHIFTKEY");
17667c478bd9Sstevel@tonic-gate 		}
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	/* save modifier bits */
17707c478bd9Sstevel@tonic-gate 	lastusbpacket[0] = usbpacket[0];
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	/* Check Keyboard rollover error. */
17737c478bd9Sstevel@tonic-gate 	if (usbpacket[2] == USB_ERRORROLLOVER) {
17747c478bd9Sstevel@tonic-gate 		rollover = 1;
17757c478bd9Sstevel@tonic-gate 		for (uindex = 3; uindex < packet_size;
17767c478bd9Sstevel@tonic-gate 			uindex++) {
17777c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] != USB_ERRORROLLOVER) {
17787c478bd9Sstevel@tonic-gate 				rollover = 0;
17797c478bd9Sstevel@tonic-gate 				break;
17807c478bd9Sstevel@tonic-gate 			}
17817c478bd9Sstevel@tonic-gate 		}
17827c478bd9Sstevel@tonic-gate 		if (rollover) {
17837c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17847c478bd9Sstevel@tonic-gate 				"unpack: errorrollover");
17857c478bd9Sstevel@tonic-gate 			return;
17867c478bd9Sstevel@tonic-gate 		}
17877c478bd9Sstevel@tonic-gate 	}
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	/* check for released keys */
17907c478bd9Sstevel@tonic-gate 	for (lindex = 2; lindex < packet_size; lindex++) {
17917c478bd9Sstevel@tonic-gate 		int released = 1;
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 		if (lastusbpacket[lindex] == 0) {
17947c478bd9Sstevel@tonic-gate 			continue;
17957c478bd9Sstevel@tonic-gate 		}
17967c478bd9Sstevel@tonic-gate 		for (uindex = 2; uindex < packet_size; uindex++)
17977c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
17987c478bd9Sstevel@tonic-gate 				released = 0;
17997c478bd9Sstevel@tonic-gate 				break;
18007c478bd9Sstevel@tonic-gate 			}
18017c478bd9Sstevel@tonic-gate 		if (released) {
18027c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, lastusbpacket[lindex], KEY_RELEASED);
18037c478bd9Sstevel@tonic-gate 		}
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	/* check for new presses */
18077c478bd9Sstevel@tonic-gate 	for (uindex = 2; uindex < packet_size; uindex++) {
18087c478bd9Sstevel@tonic-gate 		int newkey = 1;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = usbpacket[uindex];
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		if (usbpacket[uindex] == 0) {
18137c478bd9Sstevel@tonic-gate 			continue;
18147c478bd9Sstevel@tonic-gate 		}
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 		for (lindex = 2; lindex < packet_size; lindex++) {
18177c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
18187c478bd9Sstevel@tonic-gate 				newkey = 0;
18197c478bd9Sstevel@tonic-gate 				break;
18207c478bd9Sstevel@tonic-gate 			}
18217c478bd9Sstevel@tonic-gate 		}
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 		if (newkey) {
18247c478bd9Sstevel@tonic-gate 			/*
18257c478bd9Sstevel@tonic-gate 			 * Modifier keys can be present as part of both the
18267c478bd9Sstevel@tonic-gate 			 * first byte and as separate key bytes. In the sec-
18277c478bd9Sstevel@tonic-gate 			 * ond case ignore it.
18287c478bd9Sstevel@tonic-gate 			 */
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 			if (!usbkbm_is_modkey(usbpacket[uindex])) {
18317c478bd9Sstevel@tonic-gate 				(*func)(usbkbmd, usbpacket[uindex],
18327c478bd9Sstevel@tonic-gate 						    KEY_PRESSED);
18337c478bd9Sstevel@tonic-gate 			} else {
18347c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 				continue;
18377c478bd9Sstevel@tonic-gate 			}
18387c478bd9Sstevel@tonic-gate 		}
18397c478bd9Sstevel@tonic-gate 	}
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	/*
18427c478bd9Sstevel@tonic-gate 	 * Copy the processed key events of the current usb keyboard
18437c478bd9Sstevel@tonic-gate 	 * packet, which is saved in the usbkbm_pendingusbpacket field
18447c478bd9Sstevel@tonic-gate 	 * to the usbkbm_lastusbpacket field.
18457c478bd9Sstevel@tonic-gate 	 */
18467c478bd9Sstevel@tonic-gate 	for (uindex = 2; uindex < USBKBM_MAXPKTSIZE; uindex++) {
18477c478bd9Sstevel@tonic-gate 		lastusbpacket[uindex] =
18487c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_pendingusbpacket[uindex];
18497c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18507c478bd9Sstevel@tonic-gate 	}
18517c478bd9Sstevel@tonic-gate }
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate static boolean_t
18547c478bd9Sstevel@tonic-gate usbkbm_is_modkey(uchar_t key)
18557c478bd9Sstevel@tonic-gate {
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 	switch (key) {
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	case USB_LSHIFTKEY:
18607c478bd9Sstevel@tonic-gate 	case USB_LCTLCKEY:
18617c478bd9Sstevel@tonic-gate 	case USB_LALTKEY:
18627c478bd9Sstevel@tonic-gate 	case USB_LMETAKEY:
18637c478bd9Sstevel@tonic-gate 	case USB_RCTLCKEY:
18647c478bd9Sstevel@tonic-gate 	case USB_RSHIFTKEY:
18657c478bd9Sstevel@tonic-gate 	case USB_RMETAKEY:
18667c478bd9Sstevel@tonic-gate 	case USB_RALTKEY:
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 		return (B_TRUE);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	default:
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 		break;
18737c478bd9Sstevel@tonic-gate 	}
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	return (B_FALSE);
18767c478bd9Sstevel@tonic-gate }
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate /*
18797c478bd9Sstevel@tonic-gate  * usbkbm_reioctl :
18807c478bd9Sstevel@tonic-gate  *	This function is set up as call-back function should an ioctl fail.
18817c478bd9Sstevel@tonic-gate  *	It retries the ioctl
18827c478bd9Sstevel@tonic-gate  */
18837c478bd9Sstevel@tonic-gate static void
18847c478bd9Sstevel@tonic-gate usbkbm_reioctl(void	*arg)
18857c478bd9Sstevel@tonic-gate {
18867c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
18877c478bd9Sstevel@tonic-gate 	mblk_t *mp;
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_bufcallid = 0;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	if ((mp = usbkbmd->usbkbm_streams_iocpending) != NULL) {
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		/* not pending any more */
18967c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_streams_iocpending = NULL;
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 		(void) usbkbm_ioctl(usbkbmd->usbkbm_writeq, mp);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate /*
19047c478bd9Sstevel@tonic-gate  * usbkbm_set_protocol
19057c478bd9Sstevel@tonic-gate  *	Issue an M_CTL to hid to set the desired protocol
19067c478bd9Sstevel@tonic-gate  */
19077c478bd9Sstevel@tonic-gate static int
19087c478bd9Sstevel@tonic-gate usbkbm_set_protocol(usbkbm_state_t *usbkbmd, uint16_t protocol)
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate 	struct iocblk mctlmsg;
19117c478bd9Sstevel@tonic-gate 	hid_req_t buf;
19127c478bd9Sstevel@tonic-gate 	mblk_t *mctl_ptr;
19137c478bd9Sstevel@tonic-gate 	size_t len = sizeof (buf);
19147c478bd9Sstevel@tonic-gate 	queue_t *q = usbkbmd->usbkbm_readq;
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_SET_PROTOCOL;
19177c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_count = 0;
19187c478bd9Sstevel@tonic-gate 	buf.hid_req_version_no = HID_VERSION_V_0;
19197c478bd9Sstevel@tonic-gate 	buf.hid_req_wValue = protocol;
19207c478bd9Sstevel@tonic-gate 	buf.hid_req_wLength = 0;
19217c478bd9Sstevel@tonic-gate 	buf.hid_req_data = NULL;
19227c478bd9Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, &buf, len);
19237c478bd9Sstevel@tonic-gate 	if (mctl_ptr == NULL) {
19247c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags = 0;
19257c478bd9Sstevel@tonic-gate 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
19267c478bd9Sstevel@tonic-gate 		qprocsoff(q);
19277c478bd9Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (usbkbm_state_t));
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 		return (ENOMEM);
19307c478bd9Sstevel@tonic-gate 	}
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
19337c478bd9Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
19367c478bd9Sstevel@tonic-gate 		if (qwait_sig(q) == 0) {
19377c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_flags = 0;
19387c478bd9Sstevel@tonic-gate 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
19397c478bd9Sstevel@tonic-gate 			qprocsoff(q);
19407c478bd9Sstevel@tonic-gate 			kmem_free(usbkbmd, sizeof (usbkbm_state_t));
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 			return (EINTR);
19437c478bd9Sstevel@tonic-gate 		}
19447c478bd9Sstevel@tonic-gate 	}
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	return (0);
19477c478bd9Sstevel@tonic-gate }
1948*6d9a41ffSqz150045 
1949*6d9a41ffSqz150045 
1950*6d9a41ffSqz150045 /*
1951*6d9a41ffSqz150045  * usbkbm_get_vid_pid
1952*6d9a41ffSqz150045  *	Issue a M_CTL to hid to get the device info
1953*6d9a41ffSqz150045  */
1954*6d9a41ffSqz150045 static int
1955*6d9a41ffSqz150045 usbkbm_get_vid_pid(usbkbm_state_t *usbkbmd)
1956*6d9a41ffSqz150045 {
1957*6d9a41ffSqz150045 	struct iocblk mctlmsg;
1958*6d9a41ffSqz150045 	mblk_t *mctl_ptr;
1959*6d9a41ffSqz150045 	queue_t *q = usbkbmd->usbkbm_readq;
1960*6d9a41ffSqz150045 
1961*6d9a41ffSqz150045 	mctlmsg.ioc_cmd = HID_GET_VID_PID;
1962*6d9a41ffSqz150045 	mctlmsg.ioc_count = 0;
1963*6d9a41ffSqz150045 
1964*6d9a41ffSqz150045 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
1965*6d9a41ffSqz150045 	if (mctl_ptr == NULL) {
1966*6d9a41ffSqz150045 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
1967*6d9a41ffSqz150045 		qprocsoff(q);
1968*6d9a41ffSqz150045 		kmem_free(usbkbmd, sizeof (usbkbm_state_t));
1969*6d9a41ffSqz150045 
1970*6d9a41ffSqz150045 		return (ENOMEM);
1971*6d9a41ffSqz150045 	}
1972*6d9a41ffSqz150045 
1973*6d9a41ffSqz150045 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
1974*6d9a41ffSqz150045 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
1975*6d9a41ffSqz150045 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
1976*6d9a41ffSqz150045 		if (qwait_sig(q) == 0) {
1977*6d9a41ffSqz150045 			usbkbmd->usbkbm_flags = 0;
1978*6d9a41ffSqz150045 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
1979*6d9a41ffSqz150045 			qprocsoff(q);
1980*6d9a41ffSqz150045 			kmem_free(usbkbmd, sizeof (usbkbm_state_t));
1981*6d9a41ffSqz150045 
1982*6d9a41ffSqz150045 			return (EINTR);
1983*6d9a41ffSqz150045 		}
1984*6d9a41ffSqz150045 	}
1985*6d9a41ffSqz150045 
1986*6d9a41ffSqz150045 	return (0);
1987*6d9a41ffSqz150045 }
1988