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
5281f0747Slt200341  * Common Development and Distribution License (the "License").
6281f0747Slt200341  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22827f5d6bSStrony Zhang - Solaris China Team  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * USB keyboard input streams module - processes USB keypacket
297c478bd9Sstevel@tonic-gate  * received from HID driver below to either ASCII or event
307c478bd9Sstevel@tonic-gate  * format for windowing system.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #define	KEYMAP_SIZE_VARIABLE
357c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
367c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
377c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
387c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
397c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
407c478bd9Sstevel@tonic-gate #include <sys/stream.h>
417c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
427c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
437c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
447c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
457c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
467c478bd9Sstevel@tonic-gate #include <sys/kbtrans.h>
477c478bd9Sstevel@tonic-gate #include <sys/usb/clients/usbkbm/usbkbm.h>
487c478bd9Sstevel@tonic-gate #include <sys/beep.h>
49c35aa225Smarx #include <sys/inttypes.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* debugging information */
524610e4a0Sfrits uint_t	usbkbm_errmask = (uint_t)PRINT_MASK_ALL;
534610e4a0Sfrits uint_t	usbkbm_errlevel = USB_LOG_L2;
547c478bd9Sstevel@tonic-gate static usb_log_handle_t usbkbm_log_handle;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate typedef void (*process_key_callback_t)(usbkbm_state_t *, int, enum keystate);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * Internal Function Prototypes
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate static void usbkbm_streams_setled(struct kbtrans_hardware *, int);
627c478bd9Sstevel@tonic-gate static void usbkbm_polled_setled(struct kbtrans_hardware *, int);
637c478bd9Sstevel@tonic-gate static boolean_t usbkbm_polled_keycheck(struct kbtrans_hardware *,
647c478bd9Sstevel@tonic-gate     int *, enum keystate *);
657c478bd9Sstevel@tonic-gate static void usbkbm_poll_callback(usbkbm_state_t *, int, enum keystate);
667c478bd9Sstevel@tonic-gate static void usbkbm_streams_callback(usbkbm_state_t *, int, enum keystate);
677c478bd9Sstevel@tonic-gate static void usbkbm_unpack_usb_packet(usbkbm_state_t *, process_key_callback_t,
684db52957Spengcheng chen - Sun Microsystems - Beijing China     uchar_t *);
697c478bd9Sstevel@tonic-gate static boolean_t usbkbm_is_modkey(uchar_t);
707c478bd9Sstevel@tonic-gate static void usbkbm_reioctl(void	*);
71281f0747Slt200341 static int usbkbm_polled_getchar(cons_polledio_arg_t);
72281f0747Slt200341 static boolean_t usbkbm_polled_ischar(cons_polledio_arg_t);
73281f0747Slt200341 static void usbkbm_polled_enter(cons_polledio_arg_t);
74281f0747Slt200341 static void usbkbm_polled_exit(cons_polledio_arg_t);
757c478bd9Sstevel@tonic-gate static void usbkbm_mctl_receive(queue_t *, mblk_t *);
767c478bd9Sstevel@tonic-gate static enum kbtrans_message_response usbkbm_ioctl(queue_t *, mblk_t *);
777c478bd9Sstevel@tonic-gate static int usbkbm_kioccmd(usbkbm_state_t *, mblk_t *, char, size_t *);
787c478bd9Sstevel@tonic-gate static void	usbkbm_usb2pc_xlate(usbkbm_state_t *, int, enum keystate);
797c478bd9Sstevel@tonic-gate static void	usbkbm_wrap_kbtrans(usbkbm_state_t *, int, enum keystate);
804db52957Spengcheng chen - Sun Microsystems - Beijing China static int	usbkbm_get_input_format(usbkbm_state_t *);
816d9a41ffSqz150045 static int	usbkbm_get_vid_pid(usbkbm_state_t *);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* stream qinit functions defined here */
847c478bd9Sstevel@tonic-gate static int	usbkbm_open(queue_t *, dev_t *, int, int, cred_t *);
857c478bd9Sstevel@tonic-gate static int	usbkbm_close(queue_t *, int, cred_t *);
863bb8546dSToomas Soome static int	usbkbm_wput(queue_t *, mblk_t *);
873bb8546dSToomas Soome static int	usbkbm_rput(queue_t *, mblk_t *);
88*100e26fcSToomas Soome static int	usbkbm_rsrv(queue_t *);
897c478bd9Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *);
907c478bd9Sstevel@tonic-gate static void	usbkbm_get_scancode(usbkbm_state_t *, int *, enum keystate *);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static struct keyboard *usbkbm_keyindex;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /* External Functions */
957c478bd9Sstevel@tonic-gate extern void space_free(char *);
967c478bd9Sstevel@tonic-gate extern uintptr_t space_fetch(char *);
977c478bd9Sstevel@tonic-gate extern int space_store(char *, uintptr_t);
987c478bd9Sstevel@tonic-gate extern struct keyboard *kbtrans_usbkb_maptab_init(void);
997c478bd9Sstevel@tonic-gate extern void kbtrans_usbkb_maptab_fini(struct keyboard **);
1007c478bd9Sstevel@tonic-gate extern keymap_entry_t kbtrans_keycode_usb2pc(int);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * Structure to setup callbacks
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate struct kbtrans_callbacks kbd_usb_callbacks = {
1067c478bd9Sstevel@tonic-gate 	usbkbm_streams_setled,
1077c478bd9Sstevel@tonic-gate 	usbkbm_polled_setled,
1087c478bd9Sstevel@tonic-gate 	usbkbm_polled_keycheck,
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Global Variables
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* This variable saves the LED state across hotplugging. */
1167c478bd9Sstevel@tonic-gate static uchar_t	usbkbm_led_state = 0;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /* This variable saves the layout state */
1196d9a41ffSqz150045 static uint16_t usbkbm_layout = 0;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Function pointer array for mapping of scancodes.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate void (*usbkbm_xlate[2])(usbkbm_state_t *, int, enum keystate) = {
1257c478bd9Sstevel@tonic-gate 	usbkbm_wrap_kbtrans,
1267c478bd9Sstevel@tonic-gate 	usbkbm_usb2pc_xlate
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static struct streamtab usbkbm_info;
1307c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
1317c478bd9Sstevel@tonic-gate 	"usbkbm",
1327c478bd9Sstevel@tonic-gate 	&usbkbm_info,
1337c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD
1347c478bd9Sstevel@tonic-gate };
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1397c478bd9Sstevel@tonic-gate  */
1407c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
1417c478bd9Sstevel@tonic-gate 	&mod_strmodops,
1422e83744eSsethg 	"USB keyboard streams 1.44",
1437c478bd9Sstevel@tonic-gate 	&fsw
1447c478bd9Sstevel@tonic-gate };
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1477c478bd9Sstevel@tonic-gate 	MODREV_1,
1487c478bd9Sstevel@tonic-gate 	(void *)&modlstrmod,
1497c478bd9Sstevel@tonic-gate 	NULL
1507c478bd9Sstevel@tonic-gate };
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate int
_init(void)1547c478bd9Sstevel@tonic-gate _init(void)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	int	rval = mod_install(&modlinkage);
1577c478bd9Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (rval != 0) {
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 		return (rval);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	usbkbm_keyindex = kbtrans_usbkb_maptab_init();
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	usbkbm_log_handle = usb_alloc_log_hdl(NULL, "usbkbm",
1677c478bd9Sstevel@tonic-gate 	    &usbkbm_errlevel, &usbkbm_errmask, NULL, 0);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	sp = (usbkbm_save_state_t *)space_fetch("SUNW,usbkbm_state");
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		return (0);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* Restore LED information */
1777c478bd9Sstevel@tonic-gate 	usbkbm_led_state = sp->usbkbm_save_led;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/* Restore the Layout */
1807c478bd9Sstevel@tonic-gate 	usbkbm_layout = sp->usbkbm_layout;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* Restore abort information */
1837c478bd9Sstevel@tonic-gate 	usbkbm_keyindex->k_abort1 =
1847c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_abort1;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	usbkbm_keyindex->k_abort2 =
1877c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_abort2;
1887c478bd9Sstevel@tonic-gate 
189e4603304Sqz150045 	usbkbm_keyindex->k_newabort1 =
190e4603304Sqz150045 	    sp->usbkbm_save_keyindex.k_newabort1;
191e4603304Sqz150045 
192e4603304Sqz150045 	usbkbm_keyindex->k_newabort2 =
193e4603304Sqz150045 	    sp->usbkbm_save_keyindex.k_newabort2;
194e4603304Sqz150045 
1957c478bd9Sstevel@tonic-gate 	/* Restore keytables */
1967c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_normal,
1977c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_normal, USB_KEYTABLE_SIZE);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_shifted,
2007c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_shifted, USB_KEYTABLE_SIZE);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_caps,
2037c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_caps, USB_KEYTABLE_SIZE);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_altgraph,
2067c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_altgraph, USB_KEYTABLE_SIZE);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_numlock,
2097c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_numlock, USB_KEYTABLE_SIZE);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_control,
2127c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_control, USB_KEYTABLE_SIZE);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	bcopy(sp->usbkbm_save_keyindex.k_up,
2157c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex->k_up, USB_KEYTABLE_SIZE);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_normal,
2187c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2197c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_shifted,
2207c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2217c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_caps,
2227c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2237c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_altgraph,
2247c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2257c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_numlock,
2267c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2277c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_control,
2287c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2297c478bd9Sstevel@tonic-gate 	kmem_free(sp->usbkbm_save_keyindex.k_up,
2307c478bd9Sstevel@tonic-gate 	    USB_KEYTABLE_SIZE);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (usbkbm_save_state_t));
2337c478bd9Sstevel@tonic-gate 	space_free("SUNW,usbkbm_state");
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (0);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate int
_fini(void)2397c478bd9Sstevel@tonic-gate _fini(void)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	usbkbm_save_state_t *sp;
2427c478bd9Sstevel@tonic-gate 	int sval;
2437c478bd9Sstevel@tonic-gate 	int rval;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (usbkbm_save_state_t), KM_SLEEP);
2467c478bd9Sstevel@tonic-gate 	sval = space_store("SUNW,usbkbm_state", (uintptr_t)sp);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/*
2497c478bd9Sstevel@tonic-gate 	 * If it's not possible to store the state, return
2507c478bd9Sstevel@tonic-gate 	 * EBUSY.
2517c478bd9Sstevel@tonic-gate 	 */
2527c478bd9Sstevel@tonic-gate 	if (sval != 0) {
2537c478bd9Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 		return (EBUSY);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	rval = mod_remove(&modlinkage);
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	if (rval != 0) {
2617c478bd9Sstevel@tonic-gate 		kmem_free(sp, sizeof (usbkbm_save_state_t));
2627c478bd9Sstevel@tonic-gate 		space_free("SUNW,usbkbm_state");
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		return (rval);
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usbkbm_log_handle);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/* Save the LED state */
2707c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_led = usbkbm_led_state;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/* Save the layout */
273d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	sp->usbkbm_layout = (uchar_t)usbkbm_layout;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/*
2767c478bd9Sstevel@tonic-gate 	 * Save entries of the keyboard structure that
2777c478bd9Sstevel@tonic-gate 	 * have changed.
2787c478bd9Sstevel@tonic-gate 	 */
2797c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort1 = usbkbm_keyindex->k_abort1;
2807c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_abort2 = usbkbm_keyindex->k_abort2;
2817c478bd9Sstevel@tonic-gate 
282e4603304Sqz150045 	sp->usbkbm_save_keyindex.k_newabort1 = usbkbm_keyindex->k_newabort1;
283e4603304Sqz150045 	sp->usbkbm_save_keyindex.k_newabort2 = usbkbm_keyindex->k_newabort2;
284e4603304Sqz150045 
2857c478bd9Sstevel@tonic-gate 	/* Allocate space for keytables to be stored */
2867c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_normal =
2877c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2887c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_shifted =
2897c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2907c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_caps =
2917c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2927c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_altgraph =
2937c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2947c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_numlock =
2957c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2967c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_control =
2977c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
2987c478bd9Sstevel@tonic-gate 	sp->usbkbm_save_keyindex.k_up =
2997c478bd9Sstevel@tonic-gate 	    kmem_alloc(USB_KEYTABLE_SIZE, KM_SLEEP);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/* Copy over the keytables */
3027c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_normal,
3037c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_normal, USB_KEYTABLE_SIZE);
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_shifted,
3067c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_shifted, USB_KEYTABLE_SIZE);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_caps,
3097c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_caps, USB_KEYTABLE_SIZE);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_altgraph,
3127c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_altgraph, USB_KEYTABLE_SIZE);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_numlock,
3157c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_numlock, USB_KEYTABLE_SIZE);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_control,
3187c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_control, USB_KEYTABLE_SIZE);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	bcopy(usbkbm_keyindex->k_up,
3217c478bd9Sstevel@tonic-gate 	    sp->usbkbm_save_keyindex.k_up, USB_KEYTABLE_SIZE);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	kbtrans_usbkb_maptab_fini(&usbkbm_keyindex);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	return (0);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)3297c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * Module qinit functions
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate static struct module_info usbkbm_minfo = {
3397c478bd9Sstevel@tonic-gate 	0,		/* module id number */
3407c478bd9Sstevel@tonic-gate 	"usbkbm",	/* module name */
3417c478bd9Sstevel@tonic-gate 	0,		/* min packet size accepted */
3427c478bd9Sstevel@tonic-gate 	INFPSZ,		/* max packet size accepted */
3437c478bd9Sstevel@tonic-gate 	2048,		/* hi-water mark */
3447c478bd9Sstevel@tonic-gate 	128		/* lo-water mark */
3457c478bd9Sstevel@tonic-gate 	};
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /* read side for key data and ioctl replies */
3487c478bd9Sstevel@tonic-gate static struct qinit usbkbm_rinit = {
3493bb8546dSToomas Soome 	usbkbm_rput,
350*100e26fcSToomas Soome 	usbkbm_rsrv,
3517c478bd9Sstevel@tonic-gate 	usbkbm_open,
3527c478bd9Sstevel@tonic-gate 	usbkbm_close,
3533bb8546dSToomas Soome 	NULL,
3547c478bd9Sstevel@tonic-gate 	&usbkbm_minfo
3557c478bd9Sstevel@tonic-gate 	};
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /* write side for ioctls */
3587c478bd9Sstevel@tonic-gate static struct qinit usbkbm_winit = {
3593bb8546dSToomas Soome 	usbkbm_wput,
3603bb8546dSToomas Soome 	NULL,
3617c478bd9Sstevel@tonic-gate 	usbkbm_open,
3627c478bd9Sstevel@tonic-gate 	usbkbm_close,
3633bb8546dSToomas Soome 	NULL,
3647c478bd9Sstevel@tonic-gate 	&usbkbm_minfo
3657c478bd9Sstevel@tonic-gate 	};
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate static struct streamtab usbkbm_info = {
3687c478bd9Sstevel@tonic-gate 	&usbkbm_rinit,
3697c478bd9Sstevel@tonic-gate 	&usbkbm_winit,
3707c478bd9Sstevel@tonic-gate 	NULL,		/* for muxes */
3717c478bd9Sstevel@tonic-gate 	NULL,		/* for muxes */
3727c478bd9Sstevel@tonic-gate };
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * usbkbm_open :
3767c478bd9Sstevel@tonic-gate  *	Open a keyboard
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate /* ARGSUSED */
3797c478bd9Sstevel@tonic-gate static int
usbkbm_open(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)3807c478bd9Sstevel@tonic-gate usbkbm_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
3837c478bd9Sstevel@tonic-gate 	struct iocblk	mctlmsg;
3847c478bd9Sstevel@tonic-gate 	mblk_t		*mctl_ptr;
385ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	uintptr_t	abortable = (uintptr_t)B_TRUE;
3867c478bd9Sstevel@tonic-gate 	int		error, ret;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (q->q_ptr) {
3897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
3907c478bd9Sstevel@tonic-gate 		    "usbkbm_open already opened");
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 		return (0); /* already opened */
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	switch (sflag) {
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	case MODOPEN:
3987c478bd9Sstevel@tonic-gate 		break;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	case CLONEOPEN:
4017c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4027c478bd9Sstevel@tonic-gate 		    "usbkbm_open: Clone open not supported");
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4057c478bd9Sstevel@tonic-gate 	default:
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		return (EINVAL);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/* allocate usb keyboard state structure */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	usbkbmd = kmem_zalloc(sizeof (usbkbm_state_t), KM_SLEEP);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4157c478bd9Sstevel@tonic-gate 	    "usbkbm_state= %p", (void *)usbkbmd);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * Set up private data.
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_readq = q;
4217c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_writeq = WR(q);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_vkbd_type = KB_USB;
4247c478bd9Sstevel@tonic-gate 	/*
4257c478bd9Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
4267c478bd9Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	q->q_ptr = (caddr_t)usbkbmd;
4297c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (caddr_t)usbkbmd;
4307c478bd9Sstevel@tonic-gate 
431cd2135d0Spengcheng chen - Sun Microsystems - Beijing China 	error = kbtrans_streams_init(q, sflag,
4327c478bd9Sstevel@tonic-gate 	    (struct kbtrans_hardware *)usbkbmd, &kbd_usb_callbacks,
4337c478bd9Sstevel@tonic-gate 	    &usbkbmd->usbkbm_kbtrans, usbkbm_led_state, 0);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (error != 0) {
4367c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
4377c478bd9Sstevel@tonic-gate 		    "kbdopen:  kbtrans_streams_init failed\n");
4387c478bd9Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		return (error);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/*
4447c478bd9Sstevel@tonic-gate 	 * Set the polled information in the state structure.
4457c478bd9Sstevel@tonic-gate 	 * This information is set once, and doesn't change
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_version =
4487c478bd9Sstevel@tonic-gate 	    CONSPOLLEDIO_V1;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_argument =
451281f0747Slt200341 	    (cons_polledio_arg_t)usbkbmd;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_putchar = NULL;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_getchar =
4567c478bd9Sstevel@tonic-gate 	    usbkbm_polled_getchar;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_ischar =
4597c478bd9Sstevel@tonic-gate 	    usbkbm_polled_ischar;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_enter =
4627c478bd9Sstevel@tonic-gate 	    usbkbm_polled_enter;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_exit =
4657c478bd9Sstevel@tonic-gate 	    usbkbm_polled_exit;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_setled =
468281f0747Slt200341 	    (void (*)(cons_polledio_arg_t, int))usbkbm_polled_setled;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_info.cons_polledio_keycheck =
471281f0747Slt200341 	    (boolean_t (*)(cons_polledio_arg_t, int *,
4727c478bd9Sstevel@tonic-gate 	    enum keystate *))usbkbm_polled_keycheck;
4737c478bd9Sstevel@tonic-gate 	/*
4747c478bd9Sstevel@tonic-gate 	 * The head and the tail pointing at the same byte means empty or
4757c478bd9Sstevel@tonic-gate 	 * full. usbkbm_polled_buffer_num_characters is used to
4767c478bd9Sstevel@tonic-gate 	 * tell the difference.
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head =
4797c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_polled_scancode_buffer;
4807c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail =
4817c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_polled_scancode_buffer;
4827c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters = 0;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	qprocson(q);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/* request hid report descriptor from HID */
4877c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
4887c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_count = 0;
4897c478bd9Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
4907c478bd9Sstevel@tonic-gate 	if (mctl_ptr == NULL) {
4917c478bd9Sstevel@tonic-gate 		/* failure to allocate M_CTL message */
4927c478bd9Sstevel@tonic-gate 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
4937c478bd9Sstevel@tonic-gate 		qprocsoff(q);
4947c478bd9Sstevel@tonic-gate 		kmem_free(usbkbmd, sizeof (*usbkbmd));
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/* send message to hid */
5007c478bd9Sstevel@tonic-gate 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * Now that M_CTL has been sent, wait for report descriptor.  Cleanup
5047c478bd9Sstevel@tonic-gate 	 * if user signals in the mean time (as when this gets opened in an
5057c478bd9Sstevel@tonic-gate 	 * inappropriate context and the user types a ^C).
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
5087c478bd9Sstevel@tonic-gate 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 		if (qwait_sig(q) == 0) {
5117c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_flags = 0;
5127c478bd9Sstevel@tonic-gate 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
5137c478bd9Sstevel@tonic-gate 			qprocsoff(q);
5147c478bd9Sstevel@tonic-gate 			kmem_free(usbkbmd, sizeof (*usbkbmd));
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 			return (EINTR);
5177c478bd9Sstevel@tonic-gate 		}
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 
5214db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* get the input format from the hid descriptor */
5224db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (usbkbm_get_input_format(usbkbmd) != USB_SUCCESS) {
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5257c478bd9Sstevel@tonic-gate 		    "usbkbm: Invalid HID Descriptor Tree."
5264db52957Spengcheng chen - Sun Microsystems - Beijing China 		    "setting default report format");
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5296d9a41ffSqz150045 	/*
5306d9a41ffSqz150045 	 * Although Sun Japanese type6 and type7 keyboards have the same
5316d9a41ffSqz150045 	 * layout number(15), they should be recognized for loading the
5326d9a41ffSqz150045 	 * different keytables on upper apps (e.g. X). The new layout
5336d9a41ffSqz150045 	 * number (271) is defined for the Sun Japanese type6 keyboards.
5346d9a41ffSqz150045 	 * The layout number (15) specified in HID spec is used for other
5356d9a41ffSqz150045 	 * Japanese keyboards. It is a workaround for the old Sun Japanese
5366d9a41ffSqz150045 	 * type6 keyboards defect.
5376d9a41ffSqz150045 	 */
5386d9a41ffSqz150045 	if (usbkbmd->usbkbm_layout == SUN_JAPANESE_TYPE7) {
5396d9a41ffSqz150045 
5406d9a41ffSqz150045 		if ((ret = usbkbm_get_vid_pid(usbkbmd)) != 0) {
5416d9a41ffSqz150045 
5426d9a41ffSqz150045 			return (ret);
5436d9a41ffSqz150045 		}
5446d9a41ffSqz150045 
5456d9a41ffSqz150045 		if ((usbkbmd->usbkbm_vid_pid.VendorId ==
5466d9a41ffSqz150045 		    HID_SUN_JAPANESE_TYPE6_KBD_VID) &&
5476d9a41ffSqz150045 		    (usbkbmd->usbkbm_vid_pid.ProductId ==
5486d9a41ffSqz150045 		    HID_SUN_JAPANESE_TYPE6_KBD_PID)) {
5496d9a41ffSqz150045 			usbkbmd->usbkbm_layout = SUN_JAPANESE_TYPE6;
5506d9a41ffSqz150045 		}
5516d9a41ffSqz150045 	}
5526d9a41ffSqz150045 
5537c478bd9Sstevel@tonic-gate 	kbtrans_streams_set_keyboard(usbkbmd->usbkbm_kbtrans, KB_USB,
5547c478bd9Sstevel@tonic-gate 	    usbkbm_keyindex);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = USBKBM_OPEN;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	kbtrans_streams_enable(usbkbmd->usbkbm_kbtrans);
5597c478bd9Sstevel@tonic-gate 
560ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	/*
561ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * Enable abort sequence on inital. For an internal open, conskbd
562ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * will disable driver abort handling (later through M_IOCTL) and
563ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * handle it by itself.
564ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * For an external (aka. physical) open, this is necessary since
565ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * no STREAMS module linked on top of usbkbm handles abort sequence.
566ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 */
567ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mctlmsg.ioc_cmd = CONSSETABORTENABLE;
568ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mctlmsg.ioc_count = TRANSPARENT;
569ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mctl_ptr = usba_mk_mctl(mctlmsg, &abortable, sizeof (abortable));
570ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (mctl_ptr != NULL) {
571ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		DB_TYPE(mctl_ptr) = M_IOCTL;
572ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		if (kbtrans_streams_message(usbkbmd->usbkbm_kbtrans, mctl_ptr)
573ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		    != KBTRANS_MESSAGE_HANDLED) {
574ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			freemsg(mctl_ptr);
575ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		}
576ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	} else {
577ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
578ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		    "usbkbm: enable abort sequence failed");
579ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
580ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
5817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
5827c478bd9Sstevel@tonic-gate 	    "usbkbm_open exiting");
5837c478bd9Sstevel@tonic-gate 	return (0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * usbkbm_close :
5897c478bd9Sstevel@tonic-gate  *	Close a keyboard.
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
5927c478bd9Sstevel@tonic-gate static int
usbkbm_close(register queue_t * q,int flag,cred_t * crp)5937c478bd9Sstevel@tonic-gate usbkbm_close(register queue_t *q, int flag, cred_t *crp)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	/* If a beep is in progress, stop that */
598c35aa225Smarx 	(void) beeper_off();
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	qprocsoff(q);
6037c478bd9Sstevel@tonic-gate 	/*
6047c478bd9Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
6057c478bd9Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
6067c478bd9Sstevel@tonic-gate 	 * and try to use that data.
6077c478bd9Sstevel@tonic-gate 	 */
6087c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_flags = 0;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	kmem_free(usbkbmd, sizeof (usbkbm_state_t));
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbkbm_log_handle,
6137c478bd9Sstevel@tonic-gate 	    "usbkbm_close exiting");
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	return (0);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * usbkbm_wput :
6217c478bd9Sstevel@tonic-gate  *	usb keyboard module output queue put procedure: handles M_IOCTL
6227c478bd9Sstevel@tonic-gate  *	messages.
6237c478bd9Sstevel@tonic-gate  */
6243bb8546dSToomas Soome static int
usbkbm_wput(register queue_t * q,register mblk_t * mp)6257c478bd9Sstevel@tonic-gate usbkbm_wput(register queue_t *q, register mblk_t *mp)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
6287c478bd9Sstevel@tonic-gate 	enum kbtrans_message_response	ret;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6317c478bd9Sstevel@tonic-gate 	    "usbkbm_wput entering");
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/* First, see if kbtrans will handle the message */
6367c478bd9Sstevel@tonic-gate 	ret = kbtrans_streams_message(usbkbmd->usbkbm_kbtrans, mp);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (ret == KBTRANS_MESSAGE_HANDLED) {
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6417c478bd9Sstevel@tonic-gate 		    "usbkbm_wput exiting:2");
6427c478bd9Sstevel@tonic-gate 
6433bb8546dSToomas Soome 		return (0);
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/* kbtrans didn't handle the message.  Try to handle it here */
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	case M_FLUSH:
6517c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
6527c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
6537c478bd9Sstevel@tonic-gate 		}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
6567c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		break;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	case M_IOCTL:
6627c478bd9Sstevel@tonic-gate 		ret = usbkbm_ioctl(q, mp);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		if (ret == KBTRANS_MESSAGE_HANDLED) {
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6677c478bd9Sstevel@tonic-gate 			    "usbkbm_wput exiting:1");
6687c478bd9Sstevel@tonic-gate 
6693bb8546dSToomas Soome 			return (0);
6707c478bd9Sstevel@tonic-gate 		}
6717c478bd9Sstevel@tonic-gate 	default:
6727c478bd9Sstevel@tonic-gate 		break;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 * The message has not been handled
6777c478bd9Sstevel@tonic-gate 	 * by kbtrans or this module.  Pass it down the stream
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	putnext(q, mp);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
6827c478bd9Sstevel@tonic-gate 	    "usbkbm_wput exiting:3");
6833bb8546dSToomas Soome 	return (0);
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate /*
6877c478bd9Sstevel@tonic-gate  * usbkbm_ioctl :
6887c478bd9Sstevel@tonic-gate  *	Handles the ioctls sent from upper module. Returns
6897c478bd9Sstevel@tonic-gate  *	ACK/NACK back.
6907c478bd9Sstevel@tonic-gate  */
6917c478bd9Sstevel@tonic-gate static enum kbtrans_message_response
usbkbm_ioctl(register queue_t * q,register mblk_t * mp)6927c478bd9Sstevel@tonic-gate usbkbm_ioctl(register queue_t *q, register mblk_t *mp)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
6957c478bd9Sstevel@tonic-gate 	struct iocblk		mctlmsg;
6967c478bd9Sstevel@tonic-gate 	struct iocblk		*iocp;
6977c478bd9Sstevel@tonic-gate 	mblk_t			*datap, *mctl_ptr;
6987c478bd9Sstevel@tonic-gate 	size_t			ioctlrespsize;
6997c478bd9Sstevel@tonic-gate 	int			err;
7007c478bd9Sstevel@tonic-gate 	int			tmp;
701c35aa225Smarx 	int			cycles;
702c35aa225Smarx 	int			frequency;
703c35aa225Smarx 	int			msecs;
7047c478bd9Sstevel@tonic-gate 	char			command;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	err = 0;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
7097c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
7127c478bd9Sstevel@tonic-gate 	case CONSSETKBDTYPE:
7137c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7147c478bd9Sstevel@tonic-gate 		if (err != 0) {
7157c478bd9Sstevel@tonic-gate 			break;
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 		tmp = *(int *)mp->b_cont->b_rptr;
7187c478bd9Sstevel@tonic-gate 		if (tmp != KB_PC && tmp != KB_USB) {
7197c478bd9Sstevel@tonic-gate 			err = EINVAL;
7207c478bd9Sstevel@tonic-gate 			break;
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_vkbd_type = tmp;
7237c478bd9Sstevel@tonic-gate 		break;
7247c478bd9Sstevel@tonic-gate 	case KIOCLAYOUT:
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		datap = allocb(sizeof (int), BPRI_HI);
7277c478bd9Sstevel@tonic-gate 		if (datap == NULL) {
7287c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 			goto allocfailure;
7317c478bd9Sstevel@tonic-gate 		}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = usbkbmd->usbkbm_layout;
7347c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
7397c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7407c478bd9Sstevel@tonic-gate 		break;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	case KIOCSLAYOUT:
7437c478bd9Sstevel@tonic-gate 		/*
7447c478bd9Sstevel@tonic-gate 		 * Supply a layout if not specified by the hardware, or
7457c478bd9Sstevel@tonic-gate 		 * override any that was specified.
7467c478bd9Sstevel@tonic-gate 		 */
7477c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
7487c478bd9Sstevel@tonic-gate 			err = EINVAL;
7497c478bd9Sstevel@tonic-gate 			break;
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_layout = *(intptr_t *)mp->b_cont->b_rptr;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 		/*
7557c478bd9Sstevel@tonic-gate 		 * Save the layout in usbkbm_layout so as to handle the
7567c478bd9Sstevel@tonic-gate 		 * the case when the user has re-plugged in the non-self
7577c478bd9Sstevel@tonic-gate 		 * identifying non US keyboard. In this the layout is saved
7587c478bd9Sstevel@tonic-gate 		 * in global variable, so the user does not have to run
7597c478bd9Sstevel@tonic-gate 		 * kdmconfig again after the X server reset
7607c478bd9Sstevel@tonic-gate 		 */
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		usbkbm_layout = usbkbmd->usbkbm_layout;
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	case KIOCCMD:
7667c478bd9Sstevel@tonic-gate 		/*
7677c478bd9Sstevel@tonic-gate 		 * Check if we have at least the subcommand field; any
7687c478bd9Sstevel@tonic-gate 		 * other argument validation has to occur inside
7697c478bd9Sstevel@tonic-gate 		 * usbkbm_kioccmd().
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7727c478bd9Sstevel@tonic-gate 		if (err != 0)
7737c478bd9Sstevel@tonic-gate 			break;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		/* Subcommand */
7767c478bd9Sstevel@tonic-gate 		command = (char)(*(int *)mp->b_cont->b_rptr);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 		/*
7797c478bd9Sstevel@tonic-gate 		 * Check if this ioctl is followed by a previous
7807c478bd9Sstevel@tonic-gate 		 * KBD_CMD_SETLED command, in which case we take
7817c478bd9Sstevel@tonic-gate 		 * the command byte as the data for setting the LED
7827c478bd9Sstevel@tonic-gate 		 */
7837c478bd9Sstevel@tonic-gate 		if (usbkbmd->usbkbm_setled_second_byte) {
7847c478bd9Sstevel@tonic-gate 			usbkbm_streams_setled((struct kbtrans_hardware *)
7857c478bd9Sstevel@tonic-gate 			    usbkbmd, command);
7867c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_setled_second_byte = 0;
7877c478bd9Sstevel@tonic-gate 			break;
7887c478bd9Sstevel@tonic-gate 		}
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 		/*
7917c478bd9Sstevel@tonic-gate 		 * In  case of allocb failure, this will
7927c478bd9Sstevel@tonic-gate 		 * return the size of the allocation which
7937c478bd9Sstevel@tonic-gate 		 * failed so that it can be allocated later
7947c478bd9Sstevel@tonic-gate 		 * through bufcall.
7957c478bd9Sstevel@tonic-gate 		 */
7967c478bd9Sstevel@tonic-gate 		ioctlrespsize = 0;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		err = usbkbm_kioccmd(usbkbmd, mp, command, &ioctlrespsize);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 		if (ioctlrespsize != 0) {
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 			goto allocfailure;
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		break;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	case CONSOPENPOLLEDIO:
8087c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8097c478bd9Sstevel@tonic-gate 		    "usbkbm_ioctl CONSOPENPOLLEDIO");
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct cons_polledio *));
8127c478bd9Sstevel@tonic-gate 		if (err != 0) {
8137c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, usbkbm_log_handle,
8147c478bd9Sstevel@tonic-gate 			    "usbkbm_ioctl: malformed request");
8157c478bd9Sstevel@tonic-gate 			break;
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		/*
8217c478bd9Sstevel@tonic-gate 		 * Get the polled input structure from hid
8227c478bd9Sstevel@tonic-gate 		 */
8237c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_OPEN_POLLED_INPUT;
8247c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8257c478bd9Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8267c478bd9Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8277c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 			goto allocfailure;
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		/*
8357c478bd9Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8367c478bd9Sstevel@tonic-gate 		 * result of HID_OPEN_POLLED_INPUT
8377c478bd9Sstevel@tonic-gate 		 */
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	case CONSCLOSEPOLLEDIO:
8427c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
8437c478bd9Sstevel@tonic-gate 		    "usbkbm_ioctl CONSCLOSEPOLLEDIO mp = 0x%p", (void *)mp);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = mp;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		/*
8487c478bd9Sstevel@tonic-gate 		 * Get the polled input structure from hid
8497c478bd9Sstevel@tonic-gate 		 */
8507c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_cmd = HID_CLOSE_POLLED_INPUT;
8517c478bd9Sstevel@tonic-gate 		mctlmsg.ioc_count = 0;
8527c478bd9Sstevel@tonic-gate 		mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
8537c478bd9Sstevel@tonic-gate 		if (mctl_ptr == NULL) {
8547c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (mctlmsg);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 			goto allocfailure;
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		/*
8627c478bd9Sstevel@tonic-gate 		 * Do not ack or nack the message, we will wait for the
8637c478bd9Sstevel@tonic-gate 		 * result of HID_CLOSE_POLLED_INPUT
8647c478bd9Sstevel@tonic-gate 		 */
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		return (KBTRANS_MESSAGE_HANDLED);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	case CONSSETABORTENABLE:
8697c478bd9Sstevel@tonic-gate 		/*
8707c478bd9Sstevel@tonic-gate 		 * Nothing special to do for USB.
8717c478bd9Sstevel@tonic-gate 		 */
8727c478bd9Sstevel@tonic-gate 		break;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 
875c35aa225Smarx 	case KIOCMKTONE:
876c35aa225Smarx 		if (iocp->ioc_count != TRANSPARENT) {
877c35aa225Smarx 			err = EINVAL;
878c35aa225Smarx 			break;
879c35aa225Smarx 		}
880c35aa225Smarx 
881c35aa225Smarx 		tmp = (int)(*(intptr_t *)mp->b_cont->b_rptr);
882c35aa225Smarx 		cycles = tmp & 0xffff;
883c35aa225Smarx 		msecs = (tmp >> 16) & 0xffff;
884c35aa225Smarx 
885c35aa225Smarx 		if (cycles == 0)
886c35aa225Smarx 			frequency = UINT16_MAX;
887*100e26fcSToomas Soome 		else if (cycles == UINT16_MAX) {
888c35aa225Smarx 			frequency = 0;
889*100e26fcSToomas Soome 		} else {
890c35aa225Smarx 			frequency = (PIT_HZ + cycles / 2) / cycles;
891c35aa225Smarx 			if (frequency > UINT16_MAX)
892c35aa225Smarx 				frequency = UINT16_MAX;
893c35aa225Smarx 		}
894c35aa225Smarx 
895c35aa225Smarx 		err = beep_mktone(frequency, msecs);
896c35aa225Smarx 		break;
897c35aa225Smarx 
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
usbkbm_kioccmd(usbkbm_state_t * usbkbmd,register mblk_t * mp,char command,size_t * ioctlrepsize)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 			 */
1000c35aa225Smarx 			(void) 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 			 */
1009c35aa225Smarx 			(void) 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  * usbkbm_rput :
10287c478bd9Sstevel@tonic-gate  *	Put procedure for input from driver end of stream (read queue).
10297c478bd9Sstevel@tonic-gate  */
10303bb8546dSToomas Soome static int
usbkbm_rput(queue_t * q,mblk_t * mp)1031*100e26fcSToomas Soome usbkbm_rput(queue_t *q, mblk_t *mp)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	usbkbm_state_t		*usbkbmd;
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
10387c478bd9Sstevel@tonic-gate 	    "usbkbm_rput");
10397c478bd9Sstevel@tonic-gate 
1040*100e26fcSToomas Soome 	if (usbkbmd == NULL) {
10417c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* nobody's listening */
10423bb8546dSToomas Soome 		return (0);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	case M_FLUSH:
10487c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
10497c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
10507c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
10517c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 		freemsg(mp);
10547c478bd9Sstevel@tonic-gate 
10553bb8546dSToomas Soome 		return (0);
10567c478bd9Sstevel@tonic-gate 	case M_BREAK:
10577c478bd9Sstevel@tonic-gate 		/*
10587c478bd9Sstevel@tonic-gate 		 * Will get M_BREAK only if this is not the system
10597c478bd9Sstevel@tonic-gate 		 * keyboard, otherwise serial port will eat break
10607c478bd9Sstevel@tonic-gate 		 * and call kmdb/OBP, without passing anything up.
10617c478bd9Sstevel@tonic-gate 		 */
10627c478bd9Sstevel@tonic-gate 		freemsg(mp);
10637c478bd9Sstevel@tonic-gate 
10643bb8546dSToomas Soome 		return (0);
10657c478bd9Sstevel@tonic-gate 	case M_DATA:
10667c478bd9Sstevel@tonic-gate 		if (!(usbkbmd->usbkbm_flags & USBKBM_OPEN)) {
10677c478bd9Sstevel@tonic-gate 			freemsg(mp);	/* not ready to listen */
10687c478bd9Sstevel@tonic-gate 
10693bb8546dSToomas Soome 			return (0);
10707c478bd9Sstevel@tonic-gate 		}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		break;
10737c478bd9Sstevel@tonic-gate 	case M_CTL:
10747c478bd9Sstevel@tonic-gate 		usbkbm_mctl_receive(q, mp);
10757c478bd9Sstevel@tonic-gate 
10763bb8546dSToomas Soome 		return (0);
10777c478bd9Sstevel@tonic-gate 	case M_ERROR:
10787c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
1079ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		if (*mp->b_rptr == ENODEV) {
1080ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			putnext(q, mp);
1081ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		} else {
10827c478bd9Sstevel@tonic-gate 			freemsg(mp);
1083ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		}
10847c478bd9Sstevel@tonic-gate 
10853bb8546dSToomas Soome 		return (0);
10867c478bd9Sstevel@tonic-gate 	case M_IOCACK:
10877c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
10887c478bd9Sstevel@tonic-gate 		putnext(q, mp);
10897c478bd9Sstevel@tonic-gate 
10903bb8546dSToomas Soome 		return (0);
10917c478bd9Sstevel@tonic-gate 	default:
10927c478bd9Sstevel@tonic-gate 		putnext(q, mp);
10937c478bd9Sstevel@tonic-gate 
10943bb8546dSToomas Soome 		return (0);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 
1097*100e26fcSToomas Soome 	if (putq(q, mp) == 0)
1098*100e26fcSToomas Soome 		freemsg(mp);
1099*100e26fcSToomas Soome 	return (0);
1100*100e26fcSToomas Soome }
1101*100e26fcSToomas Soome 
1102*100e26fcSToomas Soome static int
usbkbm_rsrv(queue_t * q)1103*100e26fcSToomas Soome usbkbm_rsrv(queue_t *q)
1104*100e26fcSToomas Soome {
1105*100e26fcSToomas Soome 	usbkbm_state_t		*usbkbmd;
1106*100e26fcSToomas Soome 	mblk_t *mp;
1107*100e26fcSToomas Soome 
1108*100e26fcSToomas Soome 	usbkbmd = (usbkbm_state_t *)q->q_ptr;
1109*100e26fcSToomas Soome 
1110*100e26fcSToomas Soome 	if (usbkbmd == NULL)
1111*100e26fcSToomas Soome 		return (0);
1112*100e26fcSToomas Soome 
1113*100e26fcSToomas Soome 	while ((mp = getq(q)) != NULL) {
1114*100e26fcSToomas Soome 		/* usbkbm_rput() should have filtered anything but M_DATA. */
1115*100e26fcSToomas Soome 
1116*100e26fcSToomas Soome 		if (mp->b_datap->db_type != M_DATA) {
1117*100e26fcSToomas Soome 			freemsg(mp);
1118*100e26fcSToomas Soome 			continue;
1119*100e26fcSToomas Soome 		}
1120*100e26fcSToomas Soome 
11217c478bd9Sstevel@tonic-gate 		/*
11227c478bd9Sstevel@tonic-gate 		 * A data message, consisting of bytes from the keyboard.
11237c478bd9Sstevel@tonic-gate 		 * Ram them through the translator, only if there are
11247c478bd9Sstevel@tonic-gate 		 * correct no. of bytes.
11257c478bd9Sstevel@tonic-gate 		 */
11264db52957Spengcheng chen - Sun Microsystems - Beijing China 		if (MBLKL(mp) == usbkbmd->usbkbm_report_format.tlen) {
11274db52957Spengcheng chen - Sun Microsystems - Beijing China 			if (usbkbmd->usbkbm_report_format.keyid !=
11284db52957Spengcheng chen - Sun Microsystems - Beijing China 			    HID_REPORT_ID_UNDEFINED) {
11294db52957Spengcheng chen - Sun Microsystems - Beijing China 				if (*(mp->b_rptr) !=
11304db52957Spengcheng chen - Sun Microsystems - Beijing China 				    usbkbmd->usbkbm_report_format.keyid) {
11314db52957Spengcheng chen - Sun Microsystems - Beijing China 					freemsg(mp);
1132*100e26fcSToomas Soome 					continue;
11334db52957Spengcheng chen - Sun Microsystems - Beijing China 				} else {
11344db52957Spengcheng chen - Sun Microsystems - Beijing China 					/* We skip the report id prefix */
11354db52957Spengcheng chen - Sun Microsystems - Beijing China 					mp->b_rptr++;
11364db52957Spengcheng chen - Sun Microsystems - Beijing China 				}
11374db52957Spengcheng chen - Sun Microsystems - Beijing China 			}
1138*100e26fcSToomas Soome 			usbkbm_unpack_usb_packet(usbkbmd,
1139*100e26fcSToomas Soome 			    usbkbm_streams_callback, mp->b_rptr);
11407c478bd9Sstevel@tonic-gate 		}
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 		freemsg(mp);
1143*100e26fcSToomas Soome 	}
11443bb8546dSToomas Soome 	return (0);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * usbkbm_mctl_receive :
11497c478bd9Sstevel@tonic-gate  *	Handle M_CTL messages from hid. If we don't understand
11507c478bd9Sstevel@tonic-gate  *	the command, send it up.
11517c478bd9Sstevel@tonic-gate  */
11527c478bd9Sstevel@tonic-gate static void
usbkbm_mctl_receive(register queue_t * q,register mblk_t * mp)11537c478bd9Sstevel@tonic-gate usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate 	register usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
1156827f5d6bSStrony Zhang - Solaris China Team 	register struct iocblk *iocp;
11577c478bd9Sstevel@tonic-gate 	caddr_t  data = NULL;
1158827f5d6bSStrony Zhang - Solaris China Team 	mblk_t	*reply_mp;
11597c478bd9Sstevel@tonic-gate 	uchar_t	new_buffer[USBKBM_MAXPKTSIZE];
11607c478bd9Sstevel@tonic-gate 	size_t	 size;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
11637c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL)
11647c478bd9Sstevel@tonic-gate 		data = (caddr_t)mp->b_cont->b_rptr;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	case HID_SET_REPORT:
11697c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
11707c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_SET mctl");
11717c478bd9Sstevel@tonic-gate 		freemsg(mp);
11727c478bd9Sstevel@tonic-gate 		/* Setting of the LED is not waiting for this message */
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		break;
11757c478bd9Sstevel@tonic-gate 	case HID_GET_PARSER_HANDLE:
11767c478bd9Sstevel@tonic-gate 		if ((data != NULL) &&
11777c478bd9Sstevel@tonic-gate 		    (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
1178d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
11797c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr =
11807c478bd9Sstevel@tonic-gate 			    *(hidparser_handle_t *)data;
11817c478bd9Sstevel@tonic-gate 		} else {
11827c478bd9Sstevel@tonic-gate 			usbkbmd->usbkbm_report_descr = NULL;
11837c478bd9Sstevel@tonic-gate 		}
11847c478bd9Sstevel@tonic-gate 		freemsg(mp);
11857c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		break;
11886d9a41ffSqz150045 	case HID_GET_VID_PID:
11896d9a41ffSqz150045 		if ((data != NULL) &&
11906d9a41ffSqz150045 		    (iocp->ioc_count == sizeof (hid_vid_pid_t)) &&
1191d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
11926d9a41ffSqz150045 			bcopy(data, &usbkbmd->usbkbm_vid_pid, iocp->ioc_count);
11936d9a41ffSqz150045 		}
11946d9a41ffSqz150045 		freemsg(mp);
11956d9a41ffSqz150045 		usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
11966d9a41ffSqz150045 
11976d9a41ffSqz150045 		break;
11987c478bd9Sstevel@tonic-gate 	case HID_OPEN_POLLED_INPUT:
11997c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12007c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_OPEN_POLLED_INPUT");
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 		size = sizeof (hid_polled_input_callback_t);
12037c478bd9Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
12047c478bd9Sstevel@tonic-gate 		if ((data != NULL) &&
12057c478bd9Sstevel@tonic-gate 		    (iocp->ioc_count == size) &&
1206d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    (MBLKL(mp->b_cont) == size)) {
12077c478bd9Sstevel@tonic-gate 			/*
12087c478bd9Sstevel@tonic-gate 			 *  Copy the information from hid into the
12097c478bd9Sstevel@tonic-gate 			 * state structure
12107c478bd9Sstevel@tonic-gate 			 */
12117c478bd9Sstevel@tonic-gate 			bcopy(data, &usbkbmd->usbkbm_hid_callback, size);
12127c478bd9Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCACK;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 			/*
12157c478bd9Sstevel@tonic-gate 			 * We are given an appropriate-sized data block,
12167c478bd9Sstevel@tonic-gate 			 * and return a pointer to our structure in it.
12177c478bd9Sstevel@tonic-gate 			 * The structure is saved in the states structure
12187c478bd9Sstevel@tonic-gate 			 */
12197c478bd9Sstevel@tonic-gate 			*(cons_polledio_t **)reply_mp->b_cont->b_rptr =
12207c478bd9Sstevel@tonic-gate 			    &usbkbmd->usbkbm_polled_info;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 		} else {
12237c478bd9Sstevel@tonic-gate 			reply_mp->b_datap->db_type = M_IOCNAK;
12247c478bd9Sstevel@tonic-gate 		}
12257c478bd9Sstevel@tonic-gate 		freemsg(mp);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 		putnext(q, reply_mp);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		break;
12327c478bd9Sstevel@tonic-gate 	case HID_CLOSE_POLLED_INPUT:
12337c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12347c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_CLOSE_POLLED_INPUT");
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 		bzero(&usbkbmd->usbkbm_hid_callback,
12387c478bd9Sstevel@tonic-gate 		    sizeof (hid_polled_input_callback_t));
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		freemsg(mp);
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 		reply_mp = usbkbmd->usbkbm_pending_link;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)reply_mp->b_rptr;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12477c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive reply reply_mp 0x%p cmd 0x%x",
12487c478bd9Sstevel@tonic-gate 		    (void *)reply_mp, iocp->ioc_cmd);
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		reply_mp->b_datap->db_type = M_IOCACK;
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pending_link = NULL;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 		putnext(q, reply_mp);
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 		break;
12587c478bd9Sstevel@tonic-gate 	case HID_DISCONNECT_EVENT :
12597c478bd9Sstevel@tonic-gate 	case HID_POWER_OFF:
12607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12617c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive HID_DISCONNECT_EVENT/HID_POWER_OFF");
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 		/* Indicate all keys have been released */
12647c478bd9Sstevel@tonic-gate 		bzero(new_buffer, USBKBM_MAXPKTSIZE);
12657c478bd9Sstevel@tonic-gate 		usbkbm_unpack_usb_packet(usbkbmd, usbkbm_streams_callback,
12664db52957Spengcheng chen - Sun Microsystems - Beijing China 		    new_buffer);
12677c478bd9Sstevel@tonic-gate 		freemsg(mp);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		break;
12707c478bd9Sstevel@tonic-gate 	case HID_CONNECT_EVENT:
12717c478bd9Sstevel@tonic-gate 	case HID_FULL_POWER :
12727c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
12737c478bd9Sstevel@tonic-gate 		    "usbkbm_mctl_receive restore LEDs");
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 		/* send setled command down to restore LED states */
12767c478bd9Sstevel@tonic-gate 		usbkbm_streams_setled((struct kbtrans_hardware *)usbkbmd,
12777c478bd9Sstevel@tonic-gate 		    usbkbm_led_state);
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 		freemsg(mp);
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 		break;
12827c478bd9Sstevel@tonic-gate 	default:
12837c478bd9Sstevel@tonic-gate 		putnext(q, mp);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 		break;
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate }
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate /*
12917c478bd9Sstevel@tonic-gate  * usbkbm_streams_setled :
12927c478bd9Sstevel@tonic-gate  *	Update the keyboard LEDs to match the current keyboard state.
12937c478bd9Sstevel@tonic-gate  *	Send LED state downstreams to hid driver.
12947c478bd9Sstevel@tonic-gate  */
12957c478bd9Sstevel@tonic-gate static void
usbkbm_streams_setled(struct kbtrans_hardware * kbtrans_hw,int state)12967c478bd9Sstevel@tonic-gate usbkbm_streams_setled(struct kbtrans_hardware *kbtrans_hw, int state)
12977c478bd9Sstevel@tonic-gate {
12987c478bd9Sstevel@tonic-gate 	struct iocblk	mctlmsg;
129959c81845Sgc161489 	mblk_t		*mctl_ptr;
13007c478bd9Sstevel@tonic-gate 	hid_req_t	*LED_report;
13017c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
13024db52957Spengcheng chen - Sun Microsystems - Beijing China 	uchar_t		led_id, led_state;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	usbkbm_led_state = (uchar_t)state;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)kbtrans_hw;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	LED_report = kmem_zalloc(sizeof (hid_req_t), KM_NOSLEEP);
13097c478bd9Sstevel@tonic-gate 	if (LED_report == NULL) {
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		return;
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	/*
13157c478bd9Sstevel@tonic-gate 	 * Send the request to the hid driver to set LED.
13167c478bd9Sstevel@tonic-gate 	 */
13174db52957Spengcheng chen - Sun Microsystems - Beijing China 	led_id = usbkbmd->usbkbm_report_format.keyid;
13187c478bd9Sstevel@tonic-gate 	led_state = 0;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	/*
13217c478bd9Sstevel@tonic-gate 	 * Set the led state based on the state that is passed in.
13227c478bd9Sstevel@tonic-gate 	 */
13237c478bd9Sstevel@tonic-gate 	if (state & LED_NUM_LOCK) {
13247c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_NUM_LOCK;
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	if (state & LED_COMPOSE) {
13287c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_COMPOSE;
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (state & LED_SCROLL_LOCK) {
13327c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_SCROLL_LOCK;
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (state & LED_CAPS_LOCK) {
13367c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_CAPS_LOCK;
13377c478bd9Sstevel@tonic-gate 	}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	if (state & LED_KANA) {
13407c478bd9Sstevel@tonic-gate 		led_state |= USB_LED_KANA;
13417c478bd9Sstevel@tonic-gate 	}
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	LED_report->hid_req_version_no = HID_VERSION_V_0;
13444db52957Spengcheng chen - Sun Microsystems - Beijing China 	LED_report->hid_req_wValue = REPORT_TYPE_OUTPUT | led_id;
13457c478bd9Sstevel@tonic-gate 	LED_report->hid_req_wLength = sizeof (uchar_t);
134659c81845Sgc161489 	LED_report->hid_req_data[0] = led_state;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_cmd = HID_SET_REPORT;
13497c478bd9Sstevel@tonic-gate 	mctlmsg.ioc_count = sizeof (LED_report);
13507c478bd9Sstevel@tonic-gate 	mctl_ptr = usba_mk_mctl(mctlmsg, LED_report, sizeof (hid_req_t));
13517c478bd9Sstevel@tonic-gate 	if (mctl_ptr != NULL) {
13527c478bd9Sstevel@tonic-gate 		putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/*
13567c478bd9Sstevel@tonic-gate 	 * We are not waiting for response of HID_SET_REPORT
13577c478bd9Sstevel@tonic-gate 	 * mctl for setting the LED.
13587c478bd9Sstevel@tonic-gate 	 */
13597c478bd9Sstevel@tonic-gate 	kmem_free(LED_report, sizeof (hid_req_t));
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate /*
13647c478bd9Sstevel@tonic-gate  * usbkbm_polled_keycheck :
13657c478bd9Sstevel@tonic-gate  *	This routine is called to determine if there is a scancode that
13667c478bd9Sstevel@tonic-gate  *	is available for input.  This routine is called at poll time and
13677c478bd9Sstevel@tonic-gate  *	returns a key/state pair to the caller.  If there are characters
13687c478bd9Sstevel@tonic-gate  *	buffered up, the routine returns right away with the key/state pair.
13697c478bd9Sstevel@tonic-gate  *	Otherwise, the routine calls down to check for characters and returns
13707c478bd9Sstevel@tonic-gate  *	the first key/state pair if there are any characters pending.
13717c478bd9Sstevel@tonic-gate  */
13727c478bd9Sstevel@tonic-gate static boolean_t
usbkbm_polled_keycheck(struct kbtrans_hardware * hw,int * key,enum keystate * state)13737c478bd9Sstevel@tonic-gate usbkbm_polled_keycheck(struct kbtrans_hardware *hw,
13747c478bd9Sstevel@tonic-gate     int *key, enum keystate *state)
13757c478bd9Sstevel@tonic-gate {
13767c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
13777c478bd9Sstevel@tonic-gate 	uchar_t				*buffer;
13784db52957Spengcheng chen - Sun Microsystems - Beijing China 	unsigned			size;
13797c478bd9Sstevel@tonic-gate 	hid_polled_handle_t		hid_polled_handle;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)hw;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	/*
13847c478bd9Sstevel@tonic-gate 	 * If there are already characters buffered up, then we are done.
13857c478bd9Sstevel@tonic-gate 	 */
13867c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 		return (B_TRUE);
13917c478bd9Sstevel@tonic-gate 	}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	hid_polled_handle =
13947c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
13957c478bd9Sstevel@tonic-gate 
13964db52957Spengcheng chen - Sun Microsystems - Beijing China 	size = (usbkbmd->usbkbm_hid_callback.hid_polled_read)
13977c478bd9Sstevel@tonic-gate 	    (hid_polled_handle, &buffer);
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	/*
14004db52957Spengcheng chen - Sun Microsystems - Beijing China 	 * If we don't get a valid input report then indicate that,
14014db52957Spengcheng chen - Sun Microsystems - Beijing China 	 * and we are done.
14027c478bd9Sstevel@tonic-gate 	 */
14034db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (size != usbkbmd->usbkbm_report_format.tlen) {
14047c478bd9Sstevel@tonic-gate 		return (B_FALSE);
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	/*
14087c478bd9Sstevel@tonic-gate 	 * We have a usb packet, so pass this packet to
14097c478bd9Sstevel@tonic-gate 	 * usbkbm_unpack_usb_packet so that it can be broken up into
14107c478bd9Sstevel@tonic-gate 	 * individual key/state values.
14117c478bd9Sstevel@tonic-gate 	 */
14124db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (usbkbmd->usbkbm_report_format.keyid != HID_REPORT_ID_UNDEFINED) {
14134db52957Spengcheng chen - Sun Microsystems - Beijing China 		if (*buffer != usbkbmd->usbkbm_report_format.keyid) {
14144db52957Spengcheng chen - Sun Microsystems - Beijing China 			return (B_FALSE);
14154db52957Spengcheng chen - Sun Microsystems - Beijing China 		} else {
14164db52957Spengcheng chen - Sun Microsystems - Beijing China 			/* We skip the report id prefix */
14174db52957Spengcheng chen - Sun Microsystems - Beijing China 			buffer++;
14184db52957Spengcheng chen - Sun Microsystems - Beijing China 		}
14194db52957Spengcheng chen - Sun Microsystems - Beijing China 	}
14204db52957Spengcheng chen - Sun Microsystems - Beijing China 	usbkbm_unpack_usb_packet(usbkbmd, usbkbm_poll_callback, buffer);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	/*
14237c478bd9Sstevel@tonic-gate 	 * If a scancode was returned as a result of this packet,
14247c478bd9Sstevel@tonic-gate 	 * then translate the scancode.
14257c478bd9Sstevel@tonic-gate 	 */
14267c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters != 0) {
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		usbkbm_get_scancode(usbkbmd, key, state);
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		return (B_TRUE);
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	return (B_FALSE);
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate 
usbkbm_get_state(usbkbm_state_t * usbkbmd)14367c478bd9Sstevel@tonic-gate static ushort_t	usbkbm_get_state(usbkbm_state_t *usbkbmd)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	ushort_t	ret;
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	ASSERT(usbkbmd->usbkbm_vkbd_type == KB_PC ||
14417c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_vkbd_type == KB_USB);
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_vkbd_type == KB_PC)
14447c478bd9Sstevel@tonic-gate 		ret = INDEXTO_PC;
14457c478bd9Sstevel@tonic-gate 	else
14467c478bd9Sstevel@tonic-gate 		ret = INDEXTO_USB;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	return (ret);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate /*
14517c478bd9Sstevel@tonic-gate  * usbkbm_streams_callback :
14527c478bd9Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14537c478bd9Sstevel@tonic-gate  *	usb packets for normal streams-based input.  We pass a pointer
14547c478bd9Sstevel@tonic-gate  *	to this routine to usbkbm_unpack_usb_packet.  This routine will
14557c478bd9Sstevel@tonic-gate  *	get called with an unpacked key (scancode) and state (press/release).
14567c478bd9Sstevel@tonic-gate  *	We pass it to the generic keyboard module.
14577c478bd9Sstevel@tonic-gate  *
14587c478bd9Sstevel@tonic-gate  *	'index' and the function pointers:
14597c478bd9Sstevel@tonic-gate  *	Map USB scancodes to PC scancodes by lookup table.
14607c478bd9Sstevel@tonic-gate  *	This fix is mainly meant for x86 platforms. For SPARC systems
14617c478bd9Sstevel@tonic-gate  *	this fix doesn't change the way in which the scancodes are processed.
14627c478bd9Sstevel@tonic-gate  */
14637c478bd9Sstevel@tonic-gate static void
usbkbm_streams_callback(usbkbm_state_t * usbkbmd,int key,enum keystate state)14647c478bd9Sstevel@tonic-gate usbkbm_streams_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate 	ushort_t index = usbkbm_get_state(usbkbmd);
14677c478bd9Sstevel@tonic-gate 	(*usbkbm_xlate[index])(usbkbmd, key, state);
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate  * Don't do any translations. Send to 'kbtrans' for processing.
14727c478bd9Sstevel@tonic-gate  */
14737c478bd9Sstevel@tonic-gate static void
usbkbm_wrap_kbtrans(usbkbm_state_t * usbkbmd,int key,enum keystate state)14747c478bd9Sstevel@tonic-gate usbkbm_wrap_kbtrans(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14757c478bd9Sstevel@tonic-gate {
14767c478bd9Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate /*
14807c478bd9Sstevel@tonic-gate  * Translate USB scancodes to PC scancodes before sending it to 'kbtrans'
14817c478bd9Sstevel@tonic-gate  */
14827c478bd9Sstevel@tonic-gate void
usbkbm_usb2pc_xlate(usbkbm_state_t * usbkbmd,int key,enum keystate state)14837c478bd9Sstevel@tonic-gate usbkbm_usb2pc_xlate(usbkbm_state_t *usbkbmd, int key, enum keystate state)
14847c478bd9Sstevel@tonic-gate {
14857c478bd9Sstevel@tonic-gate 	key = kbtrans_keycode_usb2pc(key);
14867c478bd9Sstevel@tonic-gate 	kbtrans_streams_key(usbkbmd->usbkbm_kbtrans, key, state);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate /*
14907c478bd9Sstevel@tonic-gate  * usbkbm_poll_callback :
14917c478bd9Sstevel@tonic-gate  *	This is the routine that is going to be called when unpacking
14927c478bd9Sstevel@tonic-gate  *	usb packets for polled input.  We pass a pointer to this routine
14937c478bd9Sstevel@tonic-gate  *	to usbkbm_unpack_usb_packet.  This routine will get called with
14947c478bd9Sstevel@tonic-gate  *	an unpacked key (scancode) and state (press/release).  We will
14957c478bd9Sstevel@tonic-gate  *	store the key/state pair into a circular buffer so that it can
14967c478bd9Sstevel@tonic-gate  *	be translated into an ascii key later.
14977c478bd9Sstevel@tonic-gate  */
14987c478bd9Sstevel@tonic-gate static void
usbkbm_poll_callback(usbkbm_state_t * usbkbmd,int key,enum keystate state)14997c478bd9Sstevel@tonic-gate usbkbm_poll_callback(usbkbm_state_t *usbkbmd, int key, enum keystate state)
15007c478bd9Sstevel@tonic-gate {
15017c478bd9Sstevel@tonic-gate 	/*
15027c478bd9Sstevel@tonic-gate 	 * Check to make sure that the buffer isn't already full
15037c478bd9Sstevel@tonic-gate 	 */
15047c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_num_characters ==
15057c478bd9Sstevel@tonic-gate 	    USB_POLLED_BUFFER_SIZE) {
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		/*
15087c478bd9Sstevel@tonic-gate 		 * The buffer is full, we will drop this character.
15097c478bd9Sstevel@tonic-gate 		 */
15107c478bd9Sstevel@tonic-gate 		return;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	/*
15147c478bd9Sstevel@tonic-gate 	 * Save the scancode in the buffer
15157c478bd9Sstevel@tonic-gate 	 */
15167c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_key = key;
15177c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head->poll_state = state;
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	/*
15207c478bd9Sstevel@tonic-gate 	 * We have one more character in the buffer
15217c478bd9Sstevel@tonic-gate 	 */
15227c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters++;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	/*
15257c478bd9Sstevel@tonic-gate 	 * Increment to the next available slot.
15267c478bd9Sstevel@tonic-gate 	 */
15277c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_head++;
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	/*
15307c478bd9Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15317c478bd9Sstevel@tonic-gate 	 */
15327c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_head -
15337c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_polled_scancode_buffer ==
15347c478bd9Sstevel@tonic-gate 	    USB_POLLED_BUFFER_SIZE) {
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_head =
15377c478bd9Sstevel@tonic-gate 		    usbkbmd->usbkbm_polled_scancode_buffer;
15387c478bd9Sstevel@tonic-gate 	}
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate  * usbkbm_get_scancode :
15437c478bd9Sstevel@tonic-gate  *	This routine retreives a key/state pair from the circular buffer.
15447c478bd9Sstevel@tonic-gate  *	The pair was put in the buffer by usbkbm_poll_callback when a
15457c478bd9Sstevel@tonic-gate  *	USB packet was translated into a key/state by usbkbm_unpack_usb_packet.
15467c478bd9Sstevel@tonic-gate  */
15477c478bd9Sstevel@tonic-gate static void
usbkbm_get_scancode(usbkbm_state_t * usbkbmd,int * key,enum keystate * state)15487c478bd9Sstevel@tonic-gate usbkbm_get_scancode(usbkbm_state_t *usbkbmd, int *key, enum keystate *state)
15497c478bd9Sstevel@tonic-gate {
15507c478bd9Sstevel@tonic-gate 	/*
15517c478bd9Sstevel@tonic-gate 	 * Copy the character.
15527c478bd9Sstevel@tonic-gate 	 */
15537c478bd9Sstevel@tonic-gate 	*key = usbkbmd->usbkbm_polled_buffer_tail->poll_key;
15547c478bd9Sstevel@tonic-gate 	*state = usbkbmd->usbkbm_polled_buffer_tail->poll_state;
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	/*
15577c478bd9Sstevel@tonic-gate 	 * Increment to the next character to be copied from
15587c478bd9Sstevel@tonic-gate 	 * and to.
15597c478bd9Sstevel@tonic-gate 	 */
15607c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_tail++;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	/*
15637c478bd9Sstevel@tonic-gate 	 * Check to see if the tail has wrapped.
15647c478bd9Sstevel@tonic-gate 	 */
15657c478bd9Sstevel@tonic-gate 	if (usbkbmd->usbkbm_polled_buffer_tail -
15667c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_polled_scancode_buffer ==
15677c478bd9Sstevel@tonic-gate 	    USB_POLLED_BUFFER_SIZE) {
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_polled_buffer_tail =
15707c478bd9Sstevel@tonic-gate 		    usbkbmd->usbkbm_polled_scancode_buffer;
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	/*
15747c478bd9Sstevel@tonic-gate 	 * We have one less character in the buffer.
15757c478bd9Sstevel@tonic-gate 	 */
15767c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_polled_buffer_num_characters--;
15777c478bd9Sstevel@tonic-gate }
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate /*
15807c478bd9Sstevel@tonic-gate  * usbkbm_polled_setled :
15817c478bd9Sstevel@tonic-gate  *	This routine is a place holder.  Someday, we may want to allow led
15827c478bd9Sstevel@tonic-gate  *	state to be updated from within polled mode.
15837c478bd9Sstevel@tonic-gate  */
15847c478bd9Sstevel@tonic-gate /* ARGSUSED */
15857c478bd9Sstevel@tonic-gate static void
usbkbm_polled_setled(struct kbtrans_hardware * hw,int led_state)15867c478bd9Sstevel@tonic-gate usbkbm_polled_setled(struct kbtrans_hardware *hw, int led_state)
15877c478bd9Sstevel@tonic-gate {
15887c478bd9Sstevel@tonic-gate 	/* nothing to do for now */
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate  * This is a pass-thru routine to get a character at poll time.
15937c478bd9Sstevel@tonic-gate  */
15947c478bd9Sstevel@tonic-gate static int
usbkbm_polled_getchar(cons_polledio_arg_t arg)1595281f0747Slt200341 usbkbm_polled_getchar(cons_polledio_arg_t arg)
15967c478bd9Sstevel@tonic-gate {
15977c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	return (kbtrans_getchar(usbkbmd->usbkbm_kbtrans));
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate /*
16057c478bd9Sstevel@tonic-gate  * This is a pass-thru routine to test if character is available for reading
16067c478bd9Sstevel@tonic-gate  * at poll time.
16077c478bd9Sstevel@tonic-gate  */
16087c478bd9Sstevel@tonic-gate static boolean_t
usbkbm_polled_ischar(cons_polledio_arg_t arg)1609281f0747Slt200341 usbkbm_polled_ischar(cons_polledio_arg_t arg)
16107c478bd9Sstevel@tonic-gate {
16117c478bd9Sstevel@tonic-gate 	usbkbm_state_t			*usbkbmd;
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	return (kbtrans_ischar(usbkbmd->usbkbm_kbtrans));
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate /*
16197c478bd9Sstevel@tonic-gate  * usbkbm_polled_input_enter :
16207c478bd9Sstevel@tonic-gate  *	This is a pass-thru initialization routine for the lower layer drivers.
16217c478bd9Sstevel@tonic-gate  *	This routine is called at poll time to set the state for polled input.
16227c478bd9Sstevel@tonic-gate  */
16237c478bd9Sstevel@tonic-gate static void
usbkbm_polled_enter(cons_polledio_arg_t arg)1624281f0747Slt200341 usbkbm_polled_enter(cons_polledio_arg_t arg)
16257c478bd9Sstevel@tonic-gate {
16264db52957Spengcheng chen - Sun Microsystems - Beijing China 	usbkbm_state_t		*usbkbmd = (usbkbm_state_t *)arg;
16277c478bd9Sstevel@tonic-gate 	hid_polled_handle_t	hid_polled_handle;
16284db52957Spengcheng chen - Sun Microsystems - Beijing China 	int			kbstart, kbend, uindex;
16297c478bd9Sstevel@tonic-gate 
16304db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbstart = usbkbmd->usbkbm_report_format.kpos;
16314db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
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 	 */
16394db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (uindex = kbstart + 2; uindex < kbend; 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
usbkbm_polled_exit(cons_polledio_arg_t arg)1660281f0747Slt200341 usbkbm_polled_exit(cons_polledio_arg_t arg)
16617c478bd9Sstevel@tonic-gate {
16624db52957Spengcheng chen - Sun Microsystems - Beijing China 	usbkbm_state_t		*usbkbmd = (usbkbm_state_t *)arg;
16637c478bd9Sstevel@tonic-gate 	hid_polled_handle_t	hid_polled_handle;
16644db52957Spengcheng chen - Sun Microsystems - Beijing China 	int			kbstart, kbend, uindex;
16657c478bd9Sstevel@tonic-gate 
16664db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbstart = usbkbmd->usbkbm_report_format.kpos;
16674db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	/*
16707c478bd9Sstevel@tonic-gate 	 * Before returning to OS mode, copy the contents of
16717c478bd9Sstevel@tonic-gate 	 * usbkbm_lastusbpacket to usbkbm_pendingusbpacket since
16727c478bd9Sstevel@tonic-gate 	 * usbkbm_lastusbpacket field has processed key events
16737c478bd9Sstevel@tonic-gate 	 * of the last POLLED mode usb keyboard packet.
16747c478bd9Sstevel@tonic-gate 	 */
16754db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (uindex = kbstart + 2; uindex < kbend; uindex ++) {
16767c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] =
16777c478bd9Sstevel@tonic-gate 		    usbkbmd->usbkbm_lastusbpacket[uindex];
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_lastusbpacket[uindex] = 0;
16807c478bd9Sstevel@tonic-gate 	}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	hid_polled_handle =
16837c478bd9Sstevel@tonic-gate 	    usbkbmd->usbkbm_hid_callback.hid_polled_input_handle;
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	(void) (usbkbmd->usbkbm_hid_callback.hid_polled_input_exit)
16867c478bd9Sstevel@tonic-gate 	    (hid_polled_handle);
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate /*
16907c478bd9Sstevel@tonic-gate  * usbkbm_unpack_usb_packet :
16912e83744eSsethg  *	USB key packets contain 8 bytes while in boot-protocol mode.
16927c478bd9Sstevel@tonic-gate  *	The first byte contains bit packed modifier key information.
16937c478bd9Sstevel@tonic-gate  *	Second byte is reserved. The last 6 bytes contain bytes of
16947c478bd9Sstevel@tonic-gate  *	currently pressed keys. If a key was not recorded on the
16957c478bd9Sstevel@tonic-gate  *	previous packet, but present in the current packet, then set
16967c478bd9Sstevel@tonic-gate  *	state to KEY_PRESSED. If a key was recorded in the previous packet,
16977c478bd9Sstevel@tonic-gate  *	but not present in the current packet, then state to KEY_RELEASED
16987c478bd9Sstevel@tonic-gate  *	Follow a similar algorithm for bit packed modifier keys.
16997c478bd9Sstevel@tonic-gate  */
17007c478bd9Sstevel@tonic-gate static void
usbkbm_unpack_usb_packet(usbkbm_state_t * usbkbmd,process_key_callback_t func,uchar_t * usbpacket)17017c478bd9Sstevel@tonic-gate usbkbm_unpack_usb_packet(usbkbm_state_t *usbkbmd, process_key_callback_t func,
17024db52957Spengcheng chen - Sun Microsystems - Beijing China     uchar_t *usbpacket)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	uchar_t		mkb;
17057c478bd9Sstevel@tonic-gate 	uchar_t		lastmkb;
17067c478bd9Sstevel@tonic-gate 	uchar_t		*lastusbpacket = usbkbmd->usbkbm_lastusbpacket;
17074db52957Spengcheng chen - Sun Microsystems - Beijing China 	int		packet_size, kbstart, kbend;
17087c478bd9Sstevel@tonic-gate 	int		uindex, lindex, rollover;
17097c478bd9Sstevel@tonic-gate 
17104db52957Spengcheng chen - Sun Microsystems - Beijing China 	packet_size = usbkbmd->usbkbm_report_format.tlen;
17114db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbstart = usbkbmd->usbkbm_report_format.kpos;
17124db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbend = kbstart + usbkbmd->usbkbm_report_format.klen;
17134db52957Spengcheng chen - Sun Microsystems - Beijing China 	mkb = usbpacket[kbstart];
17144db52957Spengcheng chen - Sun Microsystems - Beijing China 	lastmkb = lastusbpacket[kbstart];
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	for (uindex = 0; uindex < packet_size; uindex++) {
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
17197c478bd9Sstevel@tonic-gate 		    " %x ", usbpacket[uindex]);
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PACKET, usbkbm_log_handle,
17237c478bd9Sstevel@tonic-gate 	    " is the usbkeypacket");
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	/* check to see if modifier keys are different */
17267c478bd9Sstevel@tonic-gate 	if (mkb != lastmkb) {
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LSHIFTBIT) != (lastmkb & USB_LSHIFTBIT)) {
17297c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LSHIFTKEY, (mkb & USB_LSHIFTBIT) ?
17307c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17317c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17327c478bd9Sstevel@tonic-gate 			    "unpack: sending USB_LSHIFTKEY");
17337c478bd9Sstevel@tonic-gate 		}
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LCTLBIT) != (lastmkb & USB_LCTLBIT)) {
17367c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LCTLCKEY, mkb & USB_LCTLBIT ?
17377c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17387c478bd9Sstevel@tonic-gate 		}
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LALTBIT) != (lastmkb & USB_LALTBIT)) {
17417c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LALTKEY, mkb & USB_LALTBIT ?
17427c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17437c478bd9Sstevel@tonic-gate 		}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 		if ((mkb & USB_LMETABIT) != (lastmkb & USB_LMETABIT)) {
17467c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_LMETAKEY, mkb & USB_LMETABIT ?
17477c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RMETABIT) != (lastmkb & USB_RMETABIT)) {
17517c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RMETAKEY, mkb & USB_RMETABIT ?
17527c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RALTBIT) != (lastmkb & USB_RALTBIT)) {
17567c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RALTKEY, mkb & USB_RALTBIT ?
17577c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17587c478bd9Sstevel@tonic-gate 		}
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RCTLBIT) != (lastmkb & USB_RCTLBIT)) {
17617c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RCTLCKEY, mkb & USB_RCTLBIT ?
17627c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17637c478bd9Sstevel@tonic-gate 		}
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 		if ((mkb & USB_RSHIFTBIT) != (lastmkb & USB_RSHIFTBIT)) {
17667c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, USB_RSHIFTKEY, mkb & USB_RSHIFTBIT ?
17677c478bd9Sstevel@tonic-gate 			    KEY_PRESSED : KEY_RELEASED);
17687c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17697c478bd9Sstevel@tonic-gate 			    "unpack: sending USB_RSHIFTKEY");
17707c478bd9Sstevel@tonic-gate 		}
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/* save modifier bits */
17744db52957Spengcheng chen - Sun Microsystems - Beijing China 	lastusbpacket[kbstart] = usbpacket[kbstart];
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	/* Check Keyboard rollover error. */
17774db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (usbpacket[kbstart + 2] == USB_ERRORROLLOVER) {
17787c478bd9Sstevel@tonic-gate 		rollover = 1;
17794db52957Spengcheng chen - Sun Microsystems - Beijing China 		for (uindex = kbstart + 3; uindex < kbend;
17807c478bd9Sstevel@tonic-gate 		    uindex++) {
17817c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] != USB_ERRORROLLOVER) {
17827c478bd9Sstevel@tonic-gate 				rollover = 0;
17837c478bd9Sstevel@tonic-gate 				break;
17847c478bd9Sstevel@tonic-gate 			}
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 		if (rollover) {
17877c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
17887c478bd9Sstevel@tonic-gate 			    "unpack: errorrollover");
17897c478bd9Sstevel@tonic-gate 			return;
17907c478bd9Sstevel@tonic-gate 		}
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	/* check for released keys */
17944db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (lindex = kbstart + 2; lindex < kbend; lindex++) {
17957c478bd9Sstevel@tonic-gate 		int released = 1;
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 		if (lastusbpacket[lindex] == 0) {
17987c478bd9Sstevel@tonic-gate 			continue;
17997c478bd9Sstevel@tonic-gate 		}
18004db52957Spengcheng chen - Sun Microsystems - Beijing China 		for (uindex = kbstart + 2; uindex < kbend; uindex++)
18017c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
18027c478bd9Sstevel@tonic-gate 				released = 0;
18037c478bd9Sstevel@tonic-gate 				break;
18047c478bd9Sstevel@tonic-gate 			}
18057c478bd9Sstevel@tonic-gate 		if (released) {
18067c478bd9Sstevel@tonic-gate 			(*func)(usbkbmd, lastusbpacket[lindex], KEY_RELEASED);
18077c478bd9Sstevel@tonic-gate 		}
18087c478bd9Sstevel@tonic-gate 	}
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/* check for new presses */
18114db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (uindex = kbstart + 2; uindex < kbend; uindex++) {
18127c478bd9Sstevel@tonic-gate 		int newkey = 1;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = usbpacket[uindex];
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 		if (usbpacket[uindex] == 0) {
18177c478bd9Sstevel@tonic-gate 			continue;
18187c478bd9Sstevel@tonic-gate 		}
18197c478bd9Sstevel@tonic-gate 
18204db52957Spengcheng chen - Sun Microsystems - Beijing China 		for (lindex = kbstart + 2; lindex < kbend; lindex++) {
18217c478bd9Sstevel@tonic-gate 			if (usbpacket[uindex] == lastusbpacket[lindex]) {
18227c478bd9Sstevel@tonic-gate 				newkey = 0;
18237c478bd9Sstevel@tonic-gate 				break;
18247c478bd9Sstevel@tonic-gate 			}
18257c478bd9Sstevel@tonic-gate 		}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 		if (newkey) {
18287c478bd9Sstevel@tonic-gate 			/*
18297c478bd9Sstevel@tonic-gate 			 * Modifier keys can be present as part of both the
18307c478bd9Sstevel@tonic-gate 			 * first byte and as separate key bytes. In the sec-
18317c478bd9Sstevel@tonic-gate 			 * ond case ignore it.
18327c478bd9Sstevel@tonic-gate 			 */
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 			if (!usbkbm_is_modkey(usbpacket[uindex])) {
18357c478bd9Sstevel@tonic-gate 				(*func)(usbkbmd, usbpacket[uindex],
18367c478bd9Sstevel@tonic-gate 				    KEY_PRESSED);
18377c478bd9Sstevel@tonic-gate 			} else {
18387c478bd9Sstevel@tonic-gate 				usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 				continue;
18417c478bd9Sstevel@tonic-gate 			}
18427c478bd9Sstevel@tonic-gate 		}
18437c478bd9Sstevel@tonic-gate 	}
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	/*
18467c478bd9Sstevel@tonic-gate 	 * Copy the processed key events of the current usb keyboard
18477c478bd9Sstevel@tonic-gate 	 * packet, which is saved in the usbkbm_pendingusbpacket field
18487c478bd9Sstevel@tonic-gate 	 * to the usbkbm_lastusbpacket field.
18497c478bd9Sstevel@tonic-gate 	 */
18504db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (uindex = kbstart + 2; uindex < kbend; uindex++) {
18517c478bd9Sstevel@tonic-gate 		lastusbpacket[uindex] =
18527c478bd9Sstevel@tonic-gate 		    usbkbmd->usbkbm_pendingusbpacket[uindex];
18537c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_pendingusbpacket[uindex] = 0;
18547c478bd9Sstevel@tonic-gate 	}
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate static boolean_t
usbkbm_is_modkey(uchar_t key)18587c478bd9Sstevel@tonic-gate usbkbm_is_modkey(uchar_t key)
18597c478bd9Sstevel@tonic-gate {
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	switch (key) {
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 	case USB_LSHIFTKEY:
18647c478bd9Sstevel@tonic-gate 	case USB_LCTLCKEY:
18657c478bd9Sstevel@tonic-gate 	case USB_LALTKEY:
18667c478bd9Sstevel@tonic-gate 	case USB_LMETAKEY:
18677c478bd9Sstevel@tonic-gate 	case USB_RCTLCKEY:
18687c478bd9Sstevel@tonic-gate 	case USB_RSHIFTKEY:
18697c478bd9Sstevel@tonic-gate 	case USB_RMETAKEY:
18707c478bd9Sstevel@tonic-gate 	case USB_RALTKEY:
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 		return (B_TRUE);
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 	default:
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 		break;
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	return (B_FALSE);
18807c478bd9Sstevel@tonic-gate }
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate /*
18837c478bd9Sstevel@tonic-gate  * usbkbm_reioctl :
18847c478bd9Sstevel@tonic-gate  *	This function is set up as call-back function should an ioctl fail.
18857c478bd9Sstevel@tonic-gate  *	It retries the ioctl
18867c478bd9Sstevel@tonic-gate  */
18877c478bd9Sstevel@tonic-gate static void
usbkbm_reioctl(void * arg)18887c478bd9Sstevel@tonic-gate usbkbm_reioctl(void	*arg)
18897c478bd9Sstevel@tonic-gate {
18907c478bd9Sstevel@tonic-gate 	usbkbm_state_t	*usbkbmd;
18917c478bd9Sstevel@tonic-gate 	mblk_t *mp;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	usbkbmd = (usbkbm_state_t *)arg;
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	usbkbmd->usbkbm_streams_bufcallid = 0;
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	if ((mp = usbkbmd->usbkbm_streams_iocpending) != NULL) {
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		/* not pending any more */
19007c478bd9Sstevel@tonic-gate 		usbkbmd->usbkbm_streams_iocpending = NULL;
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 		(void) usbkbm_ioctl(usbkbmd->usbkbm_writeq, mp);
19037c478bd9Sstevel@tonic-gate 	}
19047c478bd9Sstevel@tonic-gate }
19057c478bd9Sstevel@tonic-gate 
19066d9a41ffSqz150045 /*
19076d9a41ffSqz150045  * usbkbm_get_vid_pid
19086d9a41ffSqz150045  *	Issue a M_CTL to hid to get the device info
19096d9a41ffSqz150045  */
19106d9a41ffSqz150045 static int
usbkbm_get_vid_pid(usbkbm_state_t * usbkbmd)19116d9a41ffSqz150045 usbkbm_get_vid_pid(usbkbm_state_t *usbkbmd)
19126d9a41ffSqz150045 {
19136d9a41ffSqz150045 	struct iocblk mctlmsg;
19146d9a41ffSqz150045 	mblk_t *mctl_ptr;
19156d9a41ffSqz150045 	queue_t *q = usbkbmd->usbkbm_readq;
19166d9a41ffSqz150045 
19176d9a41ffSqz150045 	mctlmsg.ioc_cmd = HID_GET_VID_PID;
19186d9a41ffSqz150045 	mctlmsg.ioc_count = 0;
19196d9a41ffSqz150045 
19206d9a41ffSqz150045 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
19216d9a41ffSqz150045 	if (mctl_ptr == NULL) {
19226d9a41ffSqz150045 		(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
19236d9a41ffSqz150045 		qprocsoff(q);
19246d9a41ffSqz150045 		kmem_free(usbkbmd, sizeof (usbkbm_state_t));
19256d9a41ffSqz150045 
19266d9a41ffSqz150045 		return (ENOMEM);
19276d9a41ffSqz150045 	}
19286d9a41ffSqz150045 
19296d9a41ffSqz150045 	putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
19306d9a41ffSqz150045 	usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
19316d9a41ffSqz150045 	while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
19326d9a41ffSqz150045 		if (qwait_sig(q) == 0) {
19336d9a41ffSqz150045 			usbkbmd->usbkbm_flags = 0;
19346d9a41ffSqz150045 			(void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
19356d9a41ffSqz150045 			qprocsoff(q);
19366d9a41ffSqz150045 			kmem_free(usbkbmd, sizeof (usbkbm_state_t));
19376d9a41ffSqz150045 
19386d9a41ffSqz150045 			return (EINTR);
19396d9a41ffSqz150045 		}
19406d9a41ffSqz150045 	}
19416d9a41ffSqz150045 
19426d9a41ffSqz150045 	return (0);
19436d9a41ffSqz150045 }
1944827f5d6bSStrony Zhang - Solaris China Team 
1945827f5d6bSStrony Zhang - Solaris China Team /*
19464db52957Spengcheng chen - Sun Microsystems - Beijing China  * usbkbm_get_input_format() :
19474db52957Spengcheng chen - Sun Microsystems - Beijing China  *     Get the input report format of keyboard
1948827f5d6bSStrony Zhang - Solaris China Team  */
1949827f5d6bSStrony Zhang - Solaris China Team static int
usbkbm_get_input_format(usbkbm_state_t * usbkbmd)19504db52957Spengcheng chen - Sun Microsystems - Beijing China usbkbm_get_input_format(usbkbm_state_t *usbkbmd)
1951827f5d6bSStrony Zhang - Solaris China Team {
1952827f5d6bSStrony Zhang - Solaris China Team 
19534db52957Spengcheng chen - Sun Microsystems - Beijing China 	hidparser_rpt_t *kb_rpt;
19544db52957Spengcheng chen - Sun Microsystems - Beijing China 	uint_t i, kbd_page = 0, kpos = 0, klen = 0, limit = 0;
19554db52957Spengcheng chen - Sun Microsystems - Beijing China 	uint32_t rptcnt, rptsz;
19564db52957Spengcheng chen - Sun Microsystems - Beijing China 	usbkbm_report_format_t *kbd_fmt = &usbkbmd->usbkbm_report_format;
19574db52957Spengcheng chen - Sun Microsystems - Beijing China 	int rptid, rval;
1958827f5d6bSStrony Zhang - Solaris China Team 
19594db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Setup default input report format */
19604db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->keyid = HID_REPORT_ID_UNDEFINED;
19614db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->tlen = USB_KBD_BOOT_PROTOCOL_PACKET_SIZE;
19624db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->klen = kbd_fmt->tlen;
19634db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->kpos = 0;
1964827f5d6bSStrony Zhang - Solaris China Team 
19654db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (usbkbmd->usbkbm_report_descr == NULL) {
19664db52957Spengcheng chen - Sun Microsystems - Beijing China 		return (USB_FAILURE);
1967827f5d6bSStrony Zhang - Solaris China Team 	}
1968827f5d6bSStrony Zhang - Solaris China Team 
19694db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Get keyboard layout */
19704db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (hidparser_get_country_code(usbkbmd->usbkbm_report_descr,
19714db52957Spengcheng chen - Sun Microsystems - Beijing China 	    (uint16_t *)&usbkbmd->usbkbm_layout) == HIDPARSER_FAILURE) {
1972827f5d6bSStrony Zhang - Solaris China Team 
19734db52957Spengcheng chen - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_OPEN,
19744db52957Spengcheng chen - Sun Microsystems - Beijing China 		    usbkbm_log_handle, "get_country_code failed"
19754db52957Spengcheng chen - Sun Microsystems - Beijing China 		    "setting default layout(0)");
19764db52957Spengcheng chen - Sun Microsystems - Beijing China 
19774db52957Spengcheng chen - Sun Microsystems - Beijing China 		usbkbmd->usbkbm_layout = usbkbm_layout;
19784db52957Spengcheng chen - Sun Microsystems - Beijing China 	}
19794db52957Spengcheng chen - Sun Microsystems - Beijing China 
19804db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Get the id of the report which contains keyboard data */
19814db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (hidparser_get_usage_attribute(
19824db52957Spengcheng chen - Sun Microsystems - Beijing China 	    usbkbmd->usbkbm_report_descr,
19834db52957Spengcheng chen - Sun Microsystems - Beijing China 	    0, /* Doesn't matter */
19844db52957Spengcheng chen - Sun Microsystems - Beijing China 	    HIDPARSER_ITEM_INPUT,
19854db52957Spengcheng chen - Sun Microsystems - Beijing China 	    HID_KEYBOARD_KEYPAD_KEYS,
19864db52957Spengcheng chen - Sun Microsystems - Beijing China 	    0,
19874db52957Spengcheng chen - Sun Microsystems - Beijing China 	    HIDPARSER_ITEM_REPORT_ID,
19884db52957Spengcheng chen - Sun Microsystems - Beijing China 	    &rptid) == HIDPARSER_NOT_FOUND) {
19894db52957Spengcheng chen - Sun Microsystems - Beijing China 
19904db52957Spengcheng chen - Sun Microsystems - Beijing China 		return (USB_SUCCESS);
19914db52957Spengcheng chen - Sun Microsystems - Beijing China 	}
19924db52957Spengcheng chen - Sun Microsystems - Beijing China 
19934db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Allocate hidparser report structure */
19944db52957Spengcheng chen - Sun Microsystems - Beijing China 	kb_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
19954db52957Spengcheng chen - Sun Microsystems - Beijing China 
19964db52957Spengcheng chen - Sun Microsystems - Beijing China 	/*
19974db52957Spengcheng chen - Sun Microsystems - Beijing China 	 * Check what is the total length of the keyboard packet
19984db52957Spengcheng chen - Sun Microsystems - Beijing China 	 * and get the usages and their lengths in order
19994db52957Spengcheng chen - Sun Microsystems - Beijing China 	 */
20004db52957Spengcheng chen - Sun Microsystems - Beijing China 	rval = hidparser_get_usage_list_in_order(
20014db52957Spengcheng chen - Sun Microsystems - Beijing China 	    usbkbmd->usbkbm_report_descr,
20024db52957Spengcheng chen - Sun Microsystems - Beijing China 	    rptid,
20034db52957Spengcheng chen - Sun Microsystems - Beijing China 	    HIDPARSER_ITEM_INPUT,
20044db52957Spengcheng chen - Sun Microsystems - Beijing China 	    kb_rpt);
20054db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (rval != HIDPARSER_SUCCESS) {
20064db52957Spengcheng chen - Sun Microsystems - Beijing China 
20074db52957Spengcheng chen - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
20084db52957Spengcheng chen - Sun Microsystems - Beijing China 		    "get_usage_list_in_order failed");
20094db52957Spengcheng chen - Sun Microsystems - Beijing China 		kmem_free(kb_rpt, sizeof (hidparser_rpt_t));
20104db52957Spengcheng chen - Sun Microsystems - Beijing China 		return (USB_FAILURE);
20114db52957Spengcheng chen - Sun Microsystems - Beijing China 	}
20124db52957Spengcheng chen - Sun Microsystems - Beijing China 
20134db52957Spengcheng chen - Sun Microsystems - Beijing China 	for (i = 0; i < kb_rpt->no_of_usages; i++) {
20144db52957Spengcheng chen - Sun Microsystems - Beijing China 		rptcnt = kb_rpt->usage_descr[i].rptcnt;
20154db52957Spengcheng chen - Sun Microsystems - Beijing China 		rptsz = kb_rpt->usage_descr[i].rptsz;
20164db52957Spengcheng chen - Sun Microsystems - Beijing China 
20174db52957Spengcheng chen - Sun Microsystems - Beijing China 		switch (kb_rpt->usage_descr[i].usage_page) {
20184db52957Spengcheng chen - Sun Microsystems - Beijing China 		case HID_KEYBOARD_KEYPAD_KEYS:
20194db52957Spengcheng chen - Sun Microsystems - Beijing China 			if (!kbd_page) {
20204db52957Spengcheng chen - Sun Microsystems - Beijing China 				kpos = limit;
20214db52957Spengcheng chen - Sun Microsystems - Beijing China 				kbd_page = 1;
20224db52957Spengcheng chen - Sun Microsystems - Beijing China 			}
20234db52957Spengcheng chen - Sun Microsystems - Beijing China 			klen += rptcnt * rptsz;
20244db52957Spengcheng chen - Sun Microsystems - Beijing China 			/*FALLTHRU*/
20254db52957Spengcheng chen - Sun Microsystems - Beijing China 		default:
20264db52957Spengcheng chen - Sun Microsystems - Beijing China 			limit += rptcnt * rptsz;
20274db52957Spengcheng chen - Sun Microsystems - Beijing China 			break;
2028827f5d6bSStrony Zhang - Solaris China Team 		}
2029827f5d6bSStrony Zhang - Solaris China Team 	}
2030827f5d6bSStrony Zhang - Solaris China Team 
20314db52957Spengcheng chen - Sun Microsystems - Beijing China 	kmem_free(kb_rpt, sizeof (hidparser_rpt_t));
20324db52957Spengcheng chen - Sun Microsystems - Beijing China 
20334db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Invalid input report format */
20344db52957Spengcheng chen - Sun Microsystems - Beijing China 	if (!kbd_page || limit > USBKBM_MAXPKTSIZE * 8 ||
20354db52957Spengcheng chen - Sun Microsystems - Beijing China 	    kpos + klen > limit || (kpos % 8 != 0)) {
20364db52957Spengcheng chen - Sun Microsystems - Beijing China 
20374db52957Spengcheng chen - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_OPEN, usbkbm_log_handle,
20384db52957Spengcheng chen - Sun Microsystems - Beijing China 		    "Invalid input report format: kbd_page (%d), limit (%d), "
20394db52957Spengcheng chen - Sun Microsystems - Beijing China 		    "kpos (%d), klen (%d)", kbd_page, limit, kpos, klen);
20404db52957Spengcheng chen - Sun Microsystems - Beijing China 		return (USB_FAILURE);
20414db52957Spengcheng chen - Sun Microsystems - Beijing China 	}
20424db52957Spengcheng chen - Sun Microsystems - Beijing China 
20434db52957Spengcheng chen - Sun Microsystems - Beijing China 	/* Set report format */
20444db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->keyid = (uint8_t)rptid;
20454db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->tlen = limit / 8 + 1;
20464db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->klen = klen / 8;
20474db52957Spengcheng chen - Sun Microsystems - Beijing China 	kbd_fmt->kpos = kpos / 8;
20484db52957Spengcheng chen - Sun Microsystems - Beijing China 
20494db52957Spengcheng chen - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
2050827f5d6bSStrony Zhang - Solaris China Team }
2051