xref: /illumos-gate/usr/src/uts/common/io/usb/clients/hid/hid.c (revision cfe80fe3)
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
5f3b88bd2Scg  * Common Development and Distribution License (the "License").
6f3b88bd2Scg  * 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  */
21f3b88bd2Scg 
227c478bd9Sstevel@tonic-gate /*
23f67c0a39Sfei feng - Sun Microsystems - Beijing China  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24*cfe80fe3SAlex Wilson  * Copyright 2017 Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Human Interface Device driver (HID)
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * The HID driver is a software driver which acts as a class
327c478bd9Sstevel@tonic-gate  * driver for USB human input devices like keyboard, mouse,
337c478bd9Sstevel@tonic-gate  * joystick etc and provides the class-specific interfaces
347c478bd9Sstevel@tonic-gate  * between these client driver modules and the Universal Serial
357c478bd9Sstevel@tonic-gate  * Bus Driver(USBA).
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * NOTE: This driver is not DDI compliant in that it uses undocumented
387c478bd9Sstevel@tonic-gate  * functions for logging (USB_DPRINTF_L*, usb_alloc_log_hdl, usb_free_log_hdl).
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * Undocumented functions may go away in a future Solaris OS release.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * Please see the DDK for sample code of these functions, and for the usbskel
437c478bd9Sstevel@tonic-gate  * skeleton template driver which contains scaled-down versions of these
447c478bd9Sstevel@tonic-gate  * functions written in a DDI-compliant way.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	USBDRV_MAJOR_VER	2
487c478bd9Sstevel@tonic-gate #define	USBDRV_MINOR_VER	0
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
517c478bd9Sstevel@tonic-gate #include <sys/usb/usba/genconsole.h>
527c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid.h>
537c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hid_polled.h>
547c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hidparser.h>
557c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hidvar.h>
567c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hid/hidminor.h>
577c478bd9Sstevel@tonic-gate #include <sys/usb/clients/hidparser/hid_parser_driver.h>
587c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
59f3b88bd2Scg #include <sys/sunddi.h>
60ddee57faSrui zang - Sun Microsystems - Beijing China #include <sys/stream.h>
61ddee57faSrui zang - Sun Microsystems - Beijing China #include <sys/strsun.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
64f3b88bd2Scg 
657c478bd9Sstevel@tonic-gate /* Debugging support */
664610e4a0Sfrits uint_t	hid_errmask	= (uint_t)PRINT_MASK_ALL;
674610e4a0Sfrits uint_t	hid_errlevel	= USB_LOG_L4;
684610e4a0Sfrits uint_t	hid_instance_debug = (uint_t)-1;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* tunables */
717c478bd9Sstevel@tonic-gate int	hid_default_pipe_drain_timeout = HID_DEFAULT_PIPE_DRAIN_TIMEOUT;
726f6c7d2bSVincent Wang int	hid_pm_mouse = 1; /* enable remote_wakeup for USB mouse/keyboard */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* soft state structures */
757c478bd9Sstevel@tonic-gate #define	HID_INITIAL_SOFT_SPACE	4
767c478bd9Sstevel@tonic-gate static void *hid_statep;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /* Callbacks */
797c478bd9Sstevel@tonic-gate static void hid_interrupt_pipe_callback(usb_pipe_handle_t,
807c478bd9Sstevel@tonic-gate 		usb_intr_req_t *);
817c478bd9Sstevel@tonic-gate static void hid_default_pipe_callback(usb_pipe_handle_t, usb_ctrl_req_t *);
827c478bd9Sstevel@tonic-gate static void hid_interrupt_pipe_exception_callback(usb_pipe_handle_t,
837c478bd9Sstevel@tonic-gate 		usb_intr_req_t *);
847c478bd9Sstevel@tonic-gate static void hid_default_pipe_exception_callback(usb_pipe_handle_t,
857c478bd9Sstevel@tonic-gate 		usb_ctrl_req_t *);
867c478bd9Sstevel@tonic-gate static int hid_restore_state_event_callback(dev_info_t *);
877c478bd9Sstevel@tonic-gate static int hid_disconnect_event_callback(dev_info_t *);
887c478bd9Sstevel@tonic-gate static int hid_cpr_suspend(hid_state_t *hidp);
897c478bd9Sstevel@tonic-gate static void hid_cpr_resume(hid_state_t *hidp);
907c478bd9Sstevel@tonic-gate static void hid_power_change_callback(void *arg, int rval);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* Supporting routines */
937c478bd9Sstevel@tonic-gate static size_t hid_parse_hid_descr(usb_hid_descr_t *, size_t,
947c478bd9Sstevel@tonic-gate 		usb_alt_if_data_t *, usb_ep_data_t *);
957c478bd9Sstevel@tonic-gate static int hid_parse_hid_descr_failure(hid_state_t *);
967c478bd9Sstevel@tonic-gate static int hid_handle_report_descriptor(hid_state_t *, int);
977c478bd9Sstevel@tonic-gate static void hid_set_idle(hid_state_t *);
987c478bd9Sstevel@tonic-gate static void hid_set_protocol(hid_state_t *, int);
997c478bd9Sstevel@tonic-gate static void hid_detach_cleanup(dev_info_t *, hid_state_t *);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static int hid_start_intr_polling(hid_state_t *);
1027c478bd9Sstevel@tonic-gate static void hid_close_intr_pipe(hid_state_t *);
103ac9468f8Spengcheng chen - Sun Microsystems - Beijing China static int hid_mctl_execute_cmd(queue_t *, int, hid_req_t *,
104ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		mblk_t *);
1057c478bd9Sstevel@tonic-gate static int hid_mctl_receive(queue_t *, mblk_t *);
106ac9468f8Spengcheng chen - Sun Microsystems - Beijing China static int hid_send_async_ctrl_request(hid_default_pipe_arg_t *, hid_req_t *,
107ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		uchar_t, int, ushort_t);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static void hid_create_pm_components(dev_info_t *, hid_state_t *);
1107c478bd9Sstevel@tonic-gate static int hid_is_pm_enabled(dev_info_t *);
1117c478bd9Sstevel@tonic-gate static void hid_restore_device_state(dev_info_t *, hid_state_t *);
1127c478bd9Sstevel@tonic-gate static void hid_save_device_state(hid_state_t *);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static void hid_qreply_merror(queue_t *, mblk_t *, uchar_t);
1157c478bd9Sstevel@tonic-gate static mblk_t *hid_data2mblk(uchar_t *, int);
1167c478bd9Sstevel@tonic-gate static void hid_flush(queue_t *);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int hid_pwrlvl0(hid_state_t *);
1197c478bd9Sstevel@tonic-gate static int hid_pwrlvl1(hid_state_t *);
1207c478bd9Sstevel@tonic-gate static int hid_pwrlvl2(hid_state_t *);
1217c478bd9Sstevel@tonic-gate static int hid_pwrlvl3(hid_state_t *);
1227c478bd9Sstevel@tonic-gate static void hid_pm_busy_component(hid_state_t *);
1237c478bd9Sstevel@tonic-gate static void hid_pm_idle_component(hid_state_t *);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static int hid_polled_read(hid_polled_handle_t, uchar_t **);
1267c478bd9Sstevel@tonic-gate static int hid_polled_input_enter(hid_polled_handle_t);
1277c478bd9Sstevel@tonic-gate static int hid_polled_input_exit(hid_polled_handle_t);
1287c478bd9Sstevel@tonic-gate static int hid_polled_input_init(hid_state_t *);
1297c478bd9Sstevel@tonic-gate static int hid_polled_input_fini(hid_state_t *);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /* Streams entry points */
1327c478bd9Sstevel@tonic-gate static int	hid_open(queue_t *, dev_t *, int, int, cred_t *);
1337c478bd9Sstevel@tonic-gate static int	hid_close(queue_t *, int, cred_t *);
1347c478bd9Sstevel@tonic-gate static int	hid_wput(queue_t *, mblk_t *);
1357c478bd9Sstevel@tonic-gate static int	hid_wsrv(queue_t *);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /* dev_ops entry points */
1387c478bd9Sstevel@tonic-gate static int	hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1397c478bd9Sstevel@tonic-gate static int	hid_attach(dev_info_t *, ddi_attach_cmd_t);
1407c478bd9Sstevel@tonic-gate static int	hid_detach(dev_info_t *, ddi_detach_cmd_t);
1417c478bd9Sstevel@tonic-gate static int	hid_power(dev_info_t *, int, int);
142*cfe80fe3SAlex Wilson /* These are to enable ugen support: */
143*cfe80fe3SAlex Wilson static int	hid_chropen(dev_t *, int, int, cred_t *);
144*cfe80fe3SAlex Wilson static int	hid_chrclose(dev_t, int, int, cred_t *);
145*cfe80fe3SAlex Wilson static int	hid_read(dev_t, struct uio *, cred_t *);
146*cfe80fe3SAlex Wilson static int	hid_write(dev_t, struct uio *, cred_t *);
147*cfe80fe3SAlex Wilson static int	hid_poll(dev_t, short, int, short *, struct pollhead **);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Warlock is not aware of the automatic locking mechanisms for
1517c478bd9Sstevel@tonic-gate  * streams drivers.  The hid streams enter points are protected by
1527c478bd9Sstevel@tonic-gate  * a per module perimeter.  If the locking in hid is a bottleneck
1537c478bd9Sstevel@tonic-gate  * per queue pair or per queue locking may be used.  Since warlock
1547c478bd9Sstevel@tonic-gate  * is not aware of the streams perimeters, these notes have been added.
1557c478bd9Sstevel@tonic-gate  *
1567c478bd9Sstevel@tonic-gate  * Note that the perimeters do not protect the driver from callbacks
1577c478bd9Sstevel@tonic-gate  * happening while a streams entry point is executing.	So, the hid_mutex
1587c478bd9Sstevel@tonic-gate  * has been created to protect the data.
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
1617c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
1627c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
1637c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", queue))
1647c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
1657c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /* module information */
1687c478bd9Sstevel@tonic-gate static struct module_info hid_mod_info = {
1697c478bd9Sstevel@tonic-gate 	0x0ffff,			/* module id number */
1707c478bd9Sstevel@tonic-gate 	"hid",				/* module name */
1717c478bd9Sstevel@tonic-gate 	0,				/* min packet size accepted */
1727c478bd9Sstevel@tonic-gate 	INFPSZ,				/* max packet size accepted */
1737c478bd9Sstevel@tonic-gate 	512,				/* hi-water mark */
1747c478bd9Sstevel@tonic-gate 	128				/* lo-water mark */
1757c478bd9Sstevel@tonic-gate };
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* read queue information structure */
1787c478bd9Sstevel@tonic-gate static struct qinit rinit = {
1797c478bd9Sstevel@tonic-gate 	NULL,				/* put procedure not needed */
1807c478bd9Sstevel@tonic-gate 	NULL,				/* service procedure not needed */
1817c478bd9Sstevel@tonic-gate 	hid_open,			/* called on startup */
1827c478bd9Sstevel@tonic-gate 	hid_close,			/* called on finish */
1837c478bd9Sstevel@tonic-gate 	NULL,				/* for future use */
1847c478bd9Sstevel@tonic-gate 	&hid_mod_info,			/* module information structure */
1857c478bd9Sstevel@tonic-gate 	NULL				/* module statistics structure */
1867c478bd9Sstevel@tonic-gate };
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /* write queue information structure */
1897c478bd9Sstevel@tonic-gate static struct qinit winit = {
1907c478bd9Sstevel@tonic-gate 	hid_wput,			/* put procedure */
1917c478bd9Sstevel@tonic-gate 	hid_wsrv,			/* service procedure */
1927c478bd9Sstevel@tonic-gate 	NULL,				/* open not used on write side */
1937c478bd9Sstevel@tonic-gate 	NULL,				/* close not used on write side */
1947c478bd9Sstevel@tonic-gate 	NULL,				/* for future use */
1957c478bd9Sstevel@tonic-gate 	&hid_mod_info,			/* module information structure */
1967c478bd9Sstevel@tonic-gate 	NULL				/* module statistics structure */
1977c478bd9Sstevel@tonic-gate };
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate struct streamtab hid_streamtab = {
2007c478bd9Sstevel@tonic-gate 	&rinit,
2017c478bd9Sstevel@tonic-gate 	&winit,
2027c478bd9Sstevel@tonic-gate 	NULL,			/* not a MUX */
2037c478bd9Sstevel@tonic-gate 	NULL			/* not a MUX */
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate struct cb_ops hid_cb_ops = {
207*cfe80fe3SAlex Wilson 	hid_chropen,		/* open  */
208*cfe80fe3SAlex Wilson 	hid_chrclose,		/* close */
2097c478bd9Sstevel@tonic-gate 	nulldev,		/* strategy */
2107c478bd9Sstevel@tonic-gate 	nulldev,		/* print */
2117c478bd9Sstevel@tonic-gate 	nulldev,		/* dump */
212*cfe80fe3SAlex Wilson 	hid_read,		/* read */
213*cfe80fe3SAlex Wilson 	hid_write,		/* write */
2147c478bd9Sstevel@tonic-gate 	nulldev,		/* ioctl */
2157c478bd9Sstevel@tonic-gate 	nulldev,		/* devmap */
2167c478bd9Sstevel@tonic-gate 	nulldev,		/* mmap */
2177c478bd9Sstevel@tonic-gate 	nulldev,		/* segmap */
218*cfe80fe3SAlex Wilson 	hid_poll,		/* poll */
2197c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
2207c478bd9Sstevel@tonic-gate 	&hid_streamtab,		/* streamtab  */
2217c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERQ
2227c478bd9Sstevel@tonic-gate };
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static struct dev_ops hid_ops = {
2267c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
2277c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
2287c478bd9Sstevel@tonic-gate 	hid_info,		/* info */
2297c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
2307c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
2317c478bd9Sstevel@tonic-gate 	hid_attach,		/* attach */
2327c478bd9Sstevel@tonic-gate 	hid_detach,		/* detach */
2337c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
2347c478bd9Sstevel@tonic-gate 	&hid_cb_ops,		/* driver operations */
2357c478bd9Sstevel@tonic-gate 	NULL,			/* bus operations */
23619397407SSherry Moore 	hid_power,		/* power */
23719397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
2387c478bd9Sstevel@tonic-gate };
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate static struct modldrv hidmodldrv =	{
2417c478bd9Sstevel@tonic-gate 	&mod_driverops,
24277e51571Sgongtian zhao - Sun Microsystems - Beijing China 	"USB HID Client Driver",
2437c478bd9Sstevel@tonic-gate 	&hid_ops			/* driver ops */
2447c478bd9Sstevel@tonic-gate };
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2477c478bd9Sstevel@tonic-gate 	MODREV_1,
2487c478bd9Sstevel@tonic-gate 	&hidmodldrv,
2497c478bd9Sstevel@tonic-gate 	NULL,
2507c478bd9Sstevel@tonic-gate };
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate static usb_event_t hid_events = {
2537c478bd9Sstevel@tonic-gate 	hid_disconnect_event_callback,
2547c478bd9Sstevel@tonic-gate 	hid_restore_state_event_callback,
2557c478bd9Sstevel@tonic-gate 	NULL,
2567c478bd9Sstevel@tonic-gate 	NULL,
2577c478bd9Sstevel@tonic-gate };
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate int
_init(void)2617c478bd9Sstevel@tonic-gate _init(void)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	int rval;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (((rval = ddi_soft_state_init(&hid_statep, sizeof (hid_state_t),
2667c478bd9Sstevel@tonic-gate 	    HID_INITIAL_SOFT_SPACE)) != 0)) {
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		return (rval);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
2727c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&hid_statep);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	return (rval);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate int
_fini(void)2807c478bd9Sstevel@tonic-gate _fini(void)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	int rval;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) != 0) {
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		return (rval);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&hid_statep);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	return (rval);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * hid_info :
3047c478bd9Sstevel@tonic-gate  *	Get minor number, soft state structure etc.
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3077c478bd9Sstevel@tonic-gate static int
hid_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)308993e3fafSRobert Mustacchi hid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp = NULL;
3117c478bd9Sstevel@tonic-gate 	int		error = DDI_FAILURE;
3127c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
3137c478bd9Sstevel@tonic-gate 	int		instance = HID_MINOR_TO_INSTANCE(minor);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	switch (infocmd) {
3167c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3177c478bd9Sstevel@tonic-gate 		if ((hidp = ddi_get_soft_state(hid_statep, instance)) != NULL) {
3187c478bd9Sstevel@tonic-gate 			*result = hidp->hid_dip;
3197c478bd9Sstevel@tonic-gate 			if (*result != NULL) {
3207c478bd9Sstevel@tonic-gate 				error = DDI_SUCCESS;
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 		} else
3237c478bd9Sstevel@tonic-gate 			*result = NULL;
3247c478bd9Sstevel@tonic-gate 		break;
3257c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3267c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
3277c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
3287c478bd9Sstevel@tonic-gate 		break;
3297c478bd9Sstevel@tonic-gate 	default:
3307c478bd9Sstevel@tonic-gate 		break;
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	return (error);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * hid_attach :
3397c478bd9Sstevel@tonic-gate  *	Gets called at the time of attach. Do allocation,
3407c478bd9Sstevel@tonic-gate  *	and initialization of the software structure.
3417c478bd9Sstevel@tonic-gate  *	Get all the descriptors, setup the
3427c478bd9Sstevel@tonic-gate  *	report descriptor tree by calling hidparser
3437c478bd9Sstevel@tonic-gate  *	function.
3447c478bd9Sstevel@tonic-gate  */
3457c478bd9Sstevel@tonic-gate static int
hid_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3467c478bd9Sstevel@tonic-gate hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
3507c478bd9Sstevel@tonic-gate 	int			parse_hid_descr_error = 0;
3517c478bd9Sstevel@tonic-gate 	hid_state_t		*hidp = NULL;
3527c478bd9Sstevel@tonic-gate 	uint32_t		usage_page;
3537c478bd9Sstevel@tonic-gate 	uint32_t		usage;
3547c478bd9Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data;
3557c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
3567c478bd9Sstevel@tonic-gate 	char			minor_name[HID_MINOR_NAME_LEN];
3577c478bd9Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
358*cfe80fe3SAlex Wilson 	usb_ugen_info_t		usb_ugen_info;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	switch (cmd) {
3617c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
3627c478bd9Sstevel@tonic-gate 			break;
3637c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
3647c478bd9Sstevel@tonic-gate 			hidp = ddi_get_soft_state(hid_statep, instance);
3657c478bd9Sstevel@tonic-gate 			hid_cpr_resume(hidp);
3667c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
3677c478bd9Sstevel@tonic-gate 		default:
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/*
3737c478bd9Sstevel@tonic-gate 	 * Allocate softstate information and get softstate pointer
3747c478bd9Sstevel@tonic-gate 	 */
3757c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(hid_statep, instance) == DDI_SUCCESS) {
3767c478bd9Sstevel@tonic-gate 		hidp = ddi_get_soft_state(hid_statep, instance);
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 	if (hidp == NULL) {
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		goto fail;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	hidp->hid_log_handle = usb_alloc_log_hdl(dip, NULL, &hid_errlevel,
384112116d8Sfb 	    &hid_errmask, &hid_instance_debug, 0);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	hidp->hid_instance = instance;
3877c478bd9Sstevel@tonic-gate 	hidp->hid_dip = dip;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * Register with USBA. Just retrieve interface descriptor
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
3937c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
3947c478bd9Sstevel@tonic-gate 		    "hid_attach: client attach failed");
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		goto fail;
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
4007c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
4037c478bd9Sstevel@tonic-gate 		    "hid_attach: usb_get_dev_data() failed");
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		goto fail;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* initialize mutex */
4097c478bd9Sstevel@tonic-gate 	mutex_init(&hidp->hid_mutex, NULL, MUTEX_DRIVER,
410112116d8Sfb 	    dev_data->dev_iblock_cookie);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	hidp->hid_attach_flags	|= HID_LOCK_INIT;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* get interface data for alternate 0 */
4157c478bd9Sstevel@tonic-gate 	altif_data = &dev_data->dev_curr_cfg->
416112116d8Sfb 	    cfg_if[dev_data->dev_curr_if].if_alt[0];
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
4197c478bd9Sstevel@tonic-gate 	hidp->hid_dev_data	= dev_data;
4207c478bd9Sstevel@tonic-gate 	hidp->hid_dev_descr	= dev_data->dev_descr;
4217c478bd9Sstevel@tonic-gate 	hidp->hid_interfaceno	= dev_data->dev_curr_if;
4227c478bd9Sstevel@tonic-gate 	hidp->hid_if_descr	= altif_data->altif_descr;
4230fc2d926Sqz 	/*
4240fc2d926Sqz 	 * Make sure that the bInterfaceProtocol only has meaning to
4250fc2d926Sqz 	 * Boot Interface Subclass.
4260fc2d926Sqz 	 */
4270fc2d926Sqz 	if (hidp->hid_if_descr.bInterfaceSubClass != BOOT_INTERFACE)
4280fc2d926Sqz 		hidp->hid_if_descr.bInterfaceProtocol = NONE_PROTOCOL;
4297c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data,
4327c478bd9Sstevel@tonic-gate 	    hidp->hid_interfaceno, 0, 0,
4337c478bd9Sstevel@tonic-gate 	    (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
4367c478bd9Sstevel@tonic-gate 		    "no interrupt IN endpoint found");
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		goto fail;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
442993e3fafSRobert Mustacchi 	if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION, dip, ep_data,
443993e3fafSRobert Mustacchi 	    &hidp->hid_ep_intr_xdescr) != USB_SUCCESS) {
444db1c88f6SSebastian Wiedenroth 		mutex_exit(&hidp->hid_mutex);
445993e3fafSRobert Mustacchi 
446993e3fafSRobert Mustacchi 		goto fail;
447993e3fafSRobert Mustacchi 	}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/*
4507c478bd9Sstevel@tonic-gate 	 * Attempt to find the hid descriptor, it could be after interface
4517c478bd9Sstevel@tonic-gate 	 * or after endpoint descriptors
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (hid_parse_hid_descr(&hidp->hid_hid_descr, USB_HID_DESCR_SIZE,
4547c478bd9Sstevel@tonic-gate 	    altif_data, ep_data) != USB_HID_DESCR_SIZE) {
4557c478bd9Sstevel@tonic-gate 		/*
4567c478bd9Sstevel@tonic-gate 		 * If parsing of hid descriptor failed and
4577c478bd9Sstevel@tonic-gate 		 * the device is a keyboard or mouse, use predefined
4587c478bd9Sstevel@tonic-gate 		 * length and packet size.
4597c478bd9Sstevel@tonic-gate 		 */
4607c478bd9Sstevel@tonic-gate 		if (hid_parse_hid_descr_failure(hidp) == USB_FAILURE) {
4617c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 			goto fail;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		/*
4677c478bd9Sstevel@tonic-gate 		 * hid descriptor was bad but since
4687c478bd9Sstevel@tonic-gate 		 * the device is a keyboard or mouse,
4697c478bd9Sstevel@tonic-gate 		 * we will use the default length
4707c478bd9Sstevel@tonic-gate 		 * and packet size.
4717c478bd9Sstevel@tonic-gate 		 */
4727c478bd9Sstevel@tonic-gate 		parse_hid_descr_error = HID_BAD_DESCR;
4737c478bd9Sstevel@tonic-gate 	} else {
4747c478bd9Sstevel@tonic-gate 		/* Parse hid descriptor successful */
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
4777c478bd9Sstevel@tonic-gate 		    "Hid descriptor:\n\t"
4787c478bd9Sstevel@tonic-gate 		    "bLength = 0x%x bDescriptorType = 0x%x "
4797c478bd9Sstevel@tonic-gate 		    "bcdHID = 0x%x\n\t"
4807c478bd9Sstevel@tonic-gate 		    "bCountryCode = 0x%x bNumDescriptors = 0x%x\n\t"
4817c478bd9Sstevel@tonic-gate 		    "bReportDescriptorType = 0x%x\n\t"
4827c478bd9Sstevel@tonic-gate 		    "wReportDescriptorLength = 0x%x",
4837c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bLength,
4847c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bDescriptorType,
4857c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bcdHID,
4867c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bCountryCode,
4877c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bNumDescriptors,
4887c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.bReportDescriptorType,
4897c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.wReportDescriptorLength);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	/*
4937c478bd9Sstevel@tonic-gate 	 * Save a copy of the default pipe for easy reference
4947c478bd9Sstevel@tonic-gate 	 */
4957c478bd9Sstevel@tonic-gate 	hidp->hid_default_pipe = hidp->hid_dev_data->dev_default_ph;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* we copied the descriptors we need, free the dev_data */
4987c478bd9Sstevel@tonic-gate 	usb_free_dev_data(dip, dev_data);
4997c478bd9Sstevel@tonic-gate 	hidp->hid_dev_data = NULL;
5007c478bd9Sstevel@tonic-gate 
501*cfe80fe3SAlex Wilson 	if (usb_owns_device(dip)) {
502*cfe80fe3SAlex Wilson 		/* Get a ugen handle. */
503*cfe80fe3SAlex Wilson 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
504*cfe80fe3SAlex Wilson 
505*cfe80fe3SAlex Wilson 		usb_ugen_info.usb_ugen_flags = 0;
506*cfe80fe3SAlex Wilson 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
507*cfe80fe3SAlex Wilson 		    (dev_t)HID_MINOR_UGEN_BITS_MASK;
508*cfe80fe3SAlex Wilson 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
509*cfe80fe3SAlex Wilson 		    (dev_t)HID_MINOR_INSTANCE_MASK;
510*cfe80fe3SAlex Wilson 		hidp->hid_ugen_hdl = usb_ugen_get_hdl(dip, &usb_ugen_info);
511*cfe80fe3SAlex Wilson 
512*cfe80fe3SAlex Wilson 		if (usb_ugen_attach(hidp->hid_ugen_hdl, cmd) !=
513*cfe80fe3SAlex Wilson 		    USB_SUCCESS) {
514*cfe80fe3SAlex Wilson 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
515*cfe80fe3SAlex Wilson 			    hidp->hid_log_handle,
516*cfe80fe3SAlex Wilson 			    "usb_ugen_attach failed");
517*cfe80fe3SAlex Wilson 
518*cfe80fe3SAlex Wilson 			usb_ugen_release_hdl(hidp->hid_ugen_hdl);
519*cfe80fe3SAlex Wilson 			hidp->hid_ugen_hdl = NULL;
520*cfe80fe3SAlex Wilson 		}
521*cfe80fe3SAlex Wilson 	}
522*cfe80fe3SAlex Wilson 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * Don't get the report descriptor if parsing hid descriptor earlier
5257c478bd9Sstevel@tonic-gate 	 * failed since device probably won't return valid report descriptor
5267c478bd9Sstevel@tonic-gate 	 * either. Though parsing of hid descriptor failed, we have reached
5277c478bd9Sstevel@tonic-gate 	 * this point because the device has been identified as a
5287c478bd9Sstevel@tonic-gate 	 * keyboard or a mouse successfully and the default packet
5297c478bd9Sstevel@tonic-gate 	 * size and layout(in case of keyboard only) will be used, so it
5307c478bd9Sstevel@tonic-gate 	 * is ok to go ahead even if parsing of hid descriptor failed and
5317c478bd9Sstevel@tonic-gate 	 * we will not try to get the report descriptor.
5327c478bd9Sstevel@tonic-gate 	 */
5337c478bd9Sstevel@tonic-gate 	if (parse_hid_descr_error != HID_BAD_DESCR) {
5347c478bd9Sstevel@tonic-gate 		/*
5357c478bd9Sstevel@tonic-gate 		 * Sun mouse rev 105 is a bit slow in responding to this
5367c478bd9Sstevel@tonic-gate 		 * request and requires multiple retries
5377c478bd9Sstevel@tonic-gate 		 */
5387c478bd9Sstevel@tonic-gate 		int retry;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		/*
5417c478bd9Sstevel@tonic-gate 		 * Get and parse the report descriptor.
5427c478bd9Sstevel@tonic-gate 		 * Set the packet size if parsing is successful.
5437c478bd9Sstevel@tonic-gate 		 * Note that we start retry at 1 to have a delay
5447c478bd9Sstevel@tonic-gate 		 * in the first iteration.
5457c478bd9Sstevel@tonic-gate 		 */
5467c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
5477c478bd9Sstevel@tonic-gate 		for (retry = 1; retry < HID_RETRY; retry++) {
5487c478bd9Sstevel@tonic-gate 			if (hid_handle_report_descriptor(hidp,
5497c478bd9Sstevel@tonic-gate 			    hidp->hid_interfaceno) == USB_SUCCESS) {
5507c478bd9Sstevel@tonic-gate 				break;
5517c478bd9Sstevel@tonic-gate 			}
5527c478bd9Sstevel@tonic-gate 			delay(retry * drv_usectohz(1000));
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		if (retry >= HID_RETRY) {
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 			goto fail;
5577c478bd9Sstevel@tonic-gate 		}
5587c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		/*
5617c478bd9Sstevel@tonic-gate 		 * If packet size is zero, but the device is identified
5627c478bd9Sstevel@tonic-gate 		 * as a mouse or a keyboard, use predefined packet
5637c478bd9Sstevel@tonic-gate 		 * size.
5647c478bd9Sstevel@tonic-gate 		 */
5657c478bd9Sstevel@tonic-gate 		if (hidp->hid_packet_size == 0) {
5667c478bd9Sstevel@tonic-gate 			if (hidp->hid_if_descr.bInterfaceProtocol ==
5677c478bd9Sstevel@tonic-gate 			    KEYBOARD_PROTOCOL) {
5687c478bd9Sstevel@tonic-gate 				/* device is a keyboard */
5697c478bd9Sstevel@tonic-gate 				hidp->hid_packet_size = USBKPSZ;
5707c478bd9Sstevel@tonic-gate 			} else if (hidp->
5717c478bd9Sstevel@tonic-gate 			    hid_if_descr.bInterfaceProtocol ==
5727c478bd9Sstevel@tonic-gate 			    MOUSE_PROTOCOL) {
5737c478bd9Sstevel@tonic-gate 				/* device is a mouse */
5747c478bd9Sstevel@tonic-gate 				hidp->hid_packet_size = USBMSSZ;
5757c478bd9Sstevel@tonic-gate 			} else {
5767c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
5777c478bd9Sstevel@tonic-gate 				    hidp->hid_log_handle,
5787c478bd9Sstevel@tonic-gate 				    "Failed to find hid packet size");
5797c478bd9Sstevel@tonic-gate 				mutex_exit(&hidp->hid_mutex);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 				goto fail;
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/*
5877c478bd9Sstevel@tonic-gate 	 * initialize the pipe policy for the interrupt pipe.
5887c478bd9Sstevel@tonic-gate 	 */
5897c478bd9Sstevel@tonic-gate 	hidp->hid_intr_pipe_policy.pp_max_async_reqs = 1;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/*
5927c478bd9Sstevel@tonic-gate 	 * Make a clas specific request to SET_IDLE
5937c478bd9Sstevel@tonic-gate 	 * In this case send no reports if state has not changed.
5947c478bd9Sstevel@tonic-gate 	 * See HID 7.2.4.
5957c478bd9Sstevel@tonic-gate 	 */
5967c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
5977c478bd9Sstevel@tonic-gate 	hid_set_idle(hidp);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	/* always initialize to report protocol */
6007c478bd9Sstevel@tonic-gate 	hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
6017c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/*
6047c478bd9Sstevel@tonic-gate 	 * Create minor node based on information from the
6057c478bd9Sstevel@tonic-gate 	 * descriptors
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	switch (hidp->hid_if_descr.bInterfaceProtocol) {
6087c478bd9Sstevel@tonic-gate 	case KEYBOARD_PROTOCOL:
6097c478bd9Sstevel@tonic-gate 		(void) strcpy(minor_name, "keyboard");
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		break;
6127c478bd9Sstevel@tonic-gate 	case MOUSE_PROTOCOL:
6137c478bd9Sstevel@tonic-gate 		(void) strcpy(minor_name, "mouse");
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		break;
6167c478bd9Sstevel@tonic-gate 	default:
617827f5d6bSStrony Zhang - Solaris China Team 		/*
618827f5d6bSStrony Zhang - Solaris China Team 		 * If the report descriptor has the GD mouse collection in
619827f5d6bSStrony Zhang - Solaris China Team 		 * its multiple collection, create a minor node and support it.
620827f5d6bSStrony Zhang - Solaris China Team 		 * It is used on some advanced keyboard/mouse set.
621827f5d6bSStrony Zhang - Solaris China Team 		 */
622827f5d6bSStrony Zhang - Solaris China Team 		if (hidparser_lookup_usage_collection(
623827f5d6bSStrony Zhang - Solaris China Team 		    hidp->hid_report_descr, HID_GENERIC_DESKTOP,
624827f5d6bSStrony Zhang - Solaris China Team 		    HID_GD_MOUSE) != HIDPARSER_FAILURE) {
625827f5d6bSStrony Zhang - Solaris China Team 			(void) strcpy(minor_name, "mouse");
626827f5d6bSStrony Zhang - Solaris China Team 
627827f5d6bSStrony Zhang - Solaris China Team 			break;
628827f5d6bSStrony Zhang - Solaris China Team 		}
629827f5d6bSStrony Zhang - Solaris China Team 
6307c478bd9Sstevel@tonic-gate 		if (hidparser_get_top_level_collection_usage(
6317c478bd9Sstevel@tonic-gate 		    hidp->hid_report_descr, &usage_page, &usage) !=
6327c478bd9Sstevel@tonic-gate 		    HIDPARSER_FAILURE) {
6337c478bd9Sstevel@tonic-gate 			switch (usage_page) {
6347c478bd9Sstevel@tonic-gate 			case HID_CONSUMER:
6357c478bd9Sstevel@tonic-gate 				switch (usage) {
6367c478bd9Sstevel@tonic-gate 				case HID_CONSUMER_CONTROL:
6377c478bd9Sstevel@tonic-gate 					(void) strcpy(minor_name,
6387c478bd9Sstevel@tonic-gate 					    "consumer_control");
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 					break;
6417c478bd9Sstevel@tonic-gate 				default:
6427c478bd9Sstevel@tonic-gate 					(void) sprintf(minor_name,
6437c478bd9Sstevel@tonic-gate 					    "hid_%d_%d", usage_page, usage);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 					break;
6467c478bd9Sstevel@tonic-gate 				}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 				break;
6497c478bd9Sstevel@tonic-gate 			case HID_GENERIC_DESKTOP:
6507c478bd9Sstevel@tonic-gate 				switch (usage) {
6517c478bd9Sstevel@tonic-gate 				case HID_GD_POINTER:
6527c478bd9Sstevel@tonic-gate 					(void) strcpy(minor_name,
6537c478bd9Sstevel@tonic-gate 					    "pointer");
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 					break;
6567c478bd9Sstevel@tonic-gate 				case HID_GD_MOUSE:
6577c478bd9Sstevel@tonic-gate 					(void) strcpy(minor_name,
6587c478bd9Sstevel@tonic-gate 					    "mouse");
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 					break;
6617c478bd9Sstevel@tonic-gate 				case HID_GD_KEYBOARD:
6627c478bd9Sstevel@tonic-gate 					(void) strcpy(minor_name,
6637c478bd9Sstevel@tonic-gate 					    "keyboard");
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 					break;
6667c478bd9Sstevel@tonic-gate 				default:
6677c478bd9Sstevel@tonic-gate 					(void) sprintf(minor_name,
6687c478bd9Sstevel@tonic-gate 					    "hid_%d_%d", usage_page, usage);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 					break;
6717c478bd9Sstevel@tonic-gate 				}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 				break;
6747c478bd9Sstevel@tonic-gate 			default:
6757c478bd9Sstevel@tonic-gate 				(void) sprintf(minor_name,
6767c478bd9Sstevel@tonic-gate 				    "hid_%d_%d", usage_page, usage);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 				break;
6797c478bd9Sstevel@tonic-gate 			}
6807c478bd9Sstevel@tonic-gate 		} else {
6817c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
6827c478bd9Sstevel@tonic-gate 			    "hid_attach: Unsupported HID device");
6837c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 			goto fail;
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		break;
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	if ((ddi_create_minor_node(dip, minor_name, S_IFCHR,
6947c478bd9Sstevel@tonic-gate 	    HID_CONSTRUCT_EXTERNAL_MINOR(instance),
6957c478bd9Sstevel@tonic-gate 	    DDI_PSEUDO, 0)) != DDI_SUCCESS) {
696d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
6977c478bd9Sstevel@tonic-gate 		    "hid_attach: Could not create minor node");
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		goto fail;
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/* create internal path for virtual */
7037c478bd9Sstevel@tonic-gate 	if (strcmp(minor_name, "mouse") == 0) {
7047c478bd9Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
7057c478bd9Sstevel@tonic-gate 		    HID_CONSTRUCT_INTERNAL_MINOR(instance)) != DDI_SUCCESS) {
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 			goto fail;
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	if (strcmp(minor_name, "keyboard") == 0) {
7127c478bd9Sstevel@tonic-gate 		if (ddi_create_internal_pathname(dip, "internal_keyboard",
7137c478bd9Sstevel@tonic-gate 		    S_IFCHR, HID_CONSTRUCT_INTERNAL_MINOR(instance)) !=
7147c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 			goto fail;
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
7217c478bd9Sstevel@tonic-gate 	hidp->hid_attach_flags |= HID_MINOR_NODES;
7227c478bd9Sstevel@tonic-gate 	hidp->hid_dev_state = USB_DEV_ONLINE;
7237c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/* register for all events */
7267c478bd9Sstevel@tonic-gate 	if (usb_register_event_cbs(dip, &hid_events, 0) != USB_SUCCESS) {
727d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
7287c478bd9Sstevel@tonic-gate 		    "usb_register_event_cbs failed");
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		goto fail;
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/* now create components to power manage this device */
7347c478bd9Sstevel@tonic-gate 	hid_create_pm_components(dip, hidp);
7357c478bd9Sstevel@tonic-gate 	hid_pm_busy_component(hidp);
7367c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
7377c478bd9Sstevel@tonic-gate 	hid_pm_idle_component(hidp);
7387c478bd9Sstevel@tonic-gate 
739ddee57faSrui zang - Sun Microsystems - Beijing China 	hidp->hid_internal_rq = hidp->hid_external_rq = NULL;
740ddee57faSrui zang - Sun Microsystems - Beijing China 	hidp->hid_internal_flag = hidp->hid_external_flag = 0;
741ddee57faSrui zang - Sun Microsystems - Beijing China 	hidp->hid_inuse_rq = NULL;
742ddee57faSrui zang - Sun Microsystems - Beijing China 
7437c478bd9Sstevel@tonic-gate 	/*
7447c478bd9Sstevel@tonic-gate 	 * report device
7457c478bd9Sstevel@tonic-gate 	 */
7467c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
7497c478bd9Sstevel@tonic-gate 	    "hid_attach: End");
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate fail:
7547c478bd9Sstevel@tonic-gate 	if (hidp) {
7557c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
7567c478bd9Sstevel@tonic-gate 		    "hid_attach: fail");
7577c478bd9Sstevel@tonic-gate 		hid_detach_cleanup(dip, hidp);
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate  * hid_detach :
7667c478bd9Sstevel@tonic-gate  *	Gets called at the time of detach.
7677c478bd9Sstevel@tonic-gate  */
7687c478bd9Sstevel@tonic-gate static int
hid_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)769993e3fafSRobert Mustacchi hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
7727c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp;
7737c478bd9Sstevel@tonic-gate 	int		rval = DDI_FAILURE;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	hidp = ddi_get_soft_state(hid_statep, instance);
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle, "hid_detach");
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	switch (cmd) {
7807c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
7817c478bd9Sstevel@tonic-gate 		/*
7827c478bd9Sstevel@tonic-gate 		 * Undo	what we	did in client_attach, freeing resources
7837c478bd9Sstevel@tonic-gate 		 * and removing	things we installed.  The system
7847c478bd9Sstevel@tonic-gate 		 * framework guarantees	we are not active with this devinfo
7857c478bd9Sstevel@tonic-gate 		 * node	in any other entry points at this time.
7867c478bd9Sstevel@tonic-gate 		 */
7877c478bd9Sstevel@tonic-gate 		hid_detach_cleanup(dip, hidp);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7907c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
7917c478bd9Sstevel@tonic-gate 		rval = hid_cpr_suspend(hidp);
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 		return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
7947c478bd9Sstevel@tonic-gate 	default:
7957c478bd9Sstevel@tonic-gate 		break;
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	return (rval);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate 
801*cfe80fe3SAlex Wilson static int
hid_chropen(dev_t * devp,int flag,int sflag,cred_t * credp)802*cfe80fe3SAlex Wilson hid_chropen(dev_t *devp, int flag, int sflag, cred_t *credp)
803*cfe80fe3SAlex Wilson {
804*cfe80fe3SAlex Wilson 	int rval;
805*cfe80fe3SAlex Wilson 	minor_t minor = getminor(*devp);
806*cfe80fe3SAlex Wilson 	int instance;
807*cfe80fe3SAlex Wilson 	hid_state_t *hidp;
808*cfe80fe3SAlex Wilson 
809*cfe80fe3SAlex Wilson 	instance = HID_MINOR_TO_INSTANCE(minor);
810*cfe80fe3SAlex Wilson 
811*cfe80fe3SAlex Wilson 	hidp = ddi_get_soft_state(hid_statep, instance);
812*cfe80fe3SAlex Wilson 	if (hidp == NULL) {
813*cfe80fe3SAlex Wilson 		return (ENXIO);
814*cfe80fe3SAlex Wilson 	}
815*cfe80fe3SAlex Wilson 
816*cfe80fe3SAlex Wilson 	if (!HID_IS_UGEN_OPEN(minor)) {
817*cfe80fe3SAlex Wilson 		return (ENXIO);
818*cfe80fe3SAlex Wilson 	}
819*cfe80fe3SAlex Wilson 
820*cfe80fe3SAlex Wilson 	hid_pm_busy_component(hidp);
821*cfe80fe3SAlex Wilson 	(void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
822*cfe80fe3SAlex Wilson 
823*cfe80fe3SAlex Wilson 	mutex_enter(&hidp->hid_mutex);
824*cfe80fe3SAlex Wilson 
825*cfe80fe3SAlex Wilson 	rval = usb_ugen_open(hidp->hid_ugen_hdl, devp, flag,
826*cfe80fe3SAlex Wilson 	    sflag, credp);
827*cfe80fe3SAlex Wilson 
828*cfe80fe3SAlex Wilson 	mutex_exit(&hidp->hid_mutex);
829*cfe80fe3SAlex Wilson 
830*cfe80fe3SAlex Wilson 	if (rval != 0) {
831*cfe80fe3SAlex Wilson 		hid_pm_idle_component(hidp);
832*cfe80fe3SAlex Wilson 	}
833*cfe80fe3SAlex Wilson 
834*cfe80fe3SAlex Wilson 	return (rval);
835*cfe80fe3SAlex Wilson }
836*cfe80fe3SAlex Wilson 
837*cfe80fe3SAlex Wilson static int
hid_chrclose(dev_t dev,int flag,int otyp,cred_t * credp)838*cfe80fe3SAlex Wilson hid_chrclose(dev_t dev, int flag, int otyp, cred_t *credp)
839*cfe80fe3SAlex Wilson {
840*cfe80fe3SAlex Wilson 	int rval;
841*cfe80fe3SAlex Wilson 	minor_t minor = getminor(dev);
842*cfe80fe3SAlex Wilson 	int instance;
843*cfe80fe3SAlex Wilson 	hid_state_t *hidp;
844*cfe80fe3SAlex Wilson 
845*cfe80fe3SAlex Wilson 	instance = HID_MINOR_TO_INSTANCE(minor);
846*cfe80fe3SAlex Wilson 
847*cfe80fe3SAlex Wilson 	hidp = ddi_get_soft_state(hid_statep, instance);
848*cfe80fe3SAlex Wilson 	if (hidp == NULL) {
849*cfe80fe3SAlex Wilson 		return (ENXIO);
850*cfe80fe3SAlex Wilson 	}
851*cfe80fe3SAlex Wilson 
852*cfe80fe3SAlex Wilson 	if (!HID_IS_UGEN_OPEN(minor)) {
853*cfe80fe3SAlex Wilson 		return (ENXIO);
854*cfe80fe3SAlex Wilson 	}
855*cfe80fe3SAlex Wilson 
856*cfe80fe3SAlex Wilson 	mutex_enter(&hidp->hid_mutex);
857*cfe80fe3SAlex Wilson 
858*cfe80fe3SAlex Wilson 	rval = usb_ugen_close(hidp->hid_ugen_hdl, dev, flag,
859*cfe80fe3SAlex Wilson 	    otyp, credp);
860*cfe80fe3SAlex Wilson 
861*cfe80fe3SAlex Wilson 	mutex_exit(&hidp->hid_mutex);
862*cfe80fe3SAlex Wilson 
863*cfe80fe3SAlex Wilson 	if (rval == 0) {
864*cfe80fe3SAlex Wilson 		hid_pm_idle_component(hidp);
865*cfe80fe3SAlex Wilson 	}
866*cfe80fe3SAlex Wilson 
867*cfe80fe3SAlex Wilson 	return (rval);
868*cfe80fe3SAlex Wilson }
869*cfe80fe3SAlex Wilson 
870*cfe80fe3SAlex Wilson static int
hid_read(dev_t dev,struct uio * uiop,cred_t * credp)871*cfe80fe3SAlex Wilson hid_read(dev_t dev, struct uio *uiop, cred_t *credp)
872*cfe80fe3SAlex Wilson {
873*cfe80fe3SAlex Wilson 	int rval;
874*cfe80fe3SAlex Wilson 	minor_t minor = getminor(dev);
875*cfe80fe3SAlex Wilson 	int instance;
876*cfe80fe3SAlex Wilson 	hid_state_t *hidp;
877*cfe80fe3SAlex Wilson 
878*cfe80fe3SAlex Wilson 	instance = HID_MINOR_TO_INSTANCE(minor);
879*cfe80fe3SAlex Wilson 
880*cfe80fe3SAlex Wilson 	hidp = ddi_get_soft_state(hid_statep, instance);
881*cfe80fe3SAlex Wilson 	if (hidp == NULL) {
882*cfe80fe3SAlex Wilson 		return (ENXIO);
883*cfe80fe3SAlex Wilson 	}
884*cfe80fe3SAlex Wilson 
885*cfe80fe3SAlex Wilson 	if (!HID_IS_UGEN_OPEN(minor)) {
886*cfe80fe3SAlex Wilson 		return (ENXIO);
887*cfe80fe3SAlex Wilson 	}
888*cfe80fe3SAlex Wilson 
889*cfe80fe3SAlex Wilson 	rval = usb_ugen_read(hidp->hid_ugen_hdl, dev, uiop, credp);
890*cfe80fe3SAlex Wilson 
891*cfe80fe3SAlex Wilson 	return (rval);
892*cfe80fe3SAlex Wilson }
893*cfe80fe3SAlex Wilson 
894*cfe80fe3SAlex Wilson static int
hid_write(dev_t dev,struct uio * uiop,cred_t * credp)895*cfe80fe3SAlex Wilson hid_write(dev_t dev, struct uio *uiop, cred_t *credp)
896*cfe80fe3SAlex Wilson {
897*cfe80fe3SAlex Wilson 	int rval;
898*cfe80fe3SAlex Wilson 	minor_t minor = getminor(dev);
899*cfe80fe3SAlex Wilson 	int instance;
900*cfe80fe3SAlex Wilson 	hid_state_t *hidp;
901*cfe80fe3SAlex Wilson 
902*cfe80fe3SAlex Wilson 	instance = HID_MINOR_TO_INSTANCE(minor);
903*cfe80fe3SAlex Wilson 
904*cfe80fe3SAlex Wilson 	hidp = ddi_get_soft_state(hid_statep, instance);
905*cfe80fe3SAlex Wilson 	if (hidp == NULL) {
906*cfe80fe3SAlex Wilson 		return (ENXIO);
907*cfe80fe3SAlex Wilson 	}
908*cfe80fe3SAlex Wilson 
909*cfe80fe3SAlex Wilson 	if (!HID_IS_UGEN_OPEN(minor)) {
910*cfe80fe3SAlex Wilson 		return (ENXIO);
911*cfe80fe3SAlex Wilson 	}
912*cfe80fe3SAlex Wilson 
913*cfe80fe3SAlex Wilson 	rval = usb_ugen_write(hidp->hid_ugen_hdl, dev, uiop, credp);
914*cfe80fe3SAlex Wilson 
915*cfe80fe3SAlex Wilson 	return (rval);
916*cfe80fe3SAlex Wilson }
917*cfe80fe3SAlex Wilson 
918*cfe80fe3SAlex Wilson static int
hid_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)919*cfe80fe3SAlex Wilson hid_poll(dev_t dev, short events, int anyyet, short *reventsp,
920*cfe80fe3SAlex Wilson     struct pollhead **phpp)
921*cfe80fe3SAlex Wilson {
922*cfe80fe3SAlex Wilson 	int rval;
923*cfe80fe3SAlex Wilson 	minor_t minor = getminor(dev);
924*cfe80fe3SAlex Wilson 	int instance;
925*cfe80fe3SAlex Wilson 	hid_state_t *hidp;
926*cfe80fe3SAlex Wilson 
927*cfe80fe3SAlex Wilson 	instance = HID_MINOR_TO_INSTANCE(minor);
928*cfe80fe3SAlex Wilson 
929*cfe80fe3SAlex Wilson 	hidp = ddi_get_soft_state(hid_statep, instance);
930*cfe80fe3SAlex Wilson 	if (hidp == NULL) {
931*cfe80fe3SAlex Wilson 		return (ENXIO);
932*cfe80fe3SAlex Wilson 	}
933*cfe80fe3SAlex Wilson 
934*cfe80fe3SAlex Wilson 	if (!HID_IS_UGEN_OPEN(minor)) {
935*cfe80fe3SAlex Wilson 		return (ENXIO);
936*cfe80fe3SAlex Wilson 	}
937*cfe80fe3SAlex Wilson 
938*cfe80fe3SAlex Wilson 	rval = usb_ugen_poll(hidp->hid_ugen_hdl, dev, events, anyyet,
939*cfe80fe3SAlex Wilson 	    reventsp, phpp);
940*cfe80fe3SAlex Wilson 
941*cfe80fe3SAlex Wilson 	return (rval);
942*cfe80fe3SAlex Wilson }
943*cfe80fe3SAlex Wilson 
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate  * hid_open :
9467c478bd9Sstevel@tonic-gate  *	Open entry point: Opens the interrupt pipe.  Sets up queues.
9477c478bd9Sstevel@tonic-gate  */
9487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9497c478bd9Sstevel@tonic-gate static int
hid_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)9507c478bd9Sstevel@tonic-gate hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate 	int no_of_ep = 0;
9537c478bd9Sstevel@tonic-gate 	int rval;
9547c478bd9Sstevel@tonic-gate 	int instance;
9557c478bd9Sstevel@tonic-gate 	hid_state_t *hidp;
9567c478bd9Sstevel@tonic-gate 	minor_t minor = getminor(*devp);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	instance = HID_MINOR_TO_INSTANCE(minor);
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	hidp = ddi_get_soft_state(hid_statep, instance);
9617c478bd9Sstevel@tonic-gate 	if (hidp == NULL) {
9627c478bd9Sstevel@tonic-gate 		return (ENXIO);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle,
9667c478bd9Sstevel@tonic-gate 	    "hid_open: Begin");
9677c478bd9Sstevel@tonic-gate 
968*cfe80fe3SAlex Wilson 	/*
969*cfe80fe3SAlex Wilson 	 * If this is a ugen device, return ENOSTR (no streams). This will
970*cfe80fe3SAlex Wilson 	 * cause spec_open to try hid_chropen from our regular ops_cb instead
971*cfe80fe3SAlex Wilson 	 * (and thus treat us as a plain character device).
972*cfe80fe3SAlex Wilson 	 */
973*cfe80fe3SAlex Wilson 	if (HID_IS_UGEN_OPEN(minor)) {
974*cfe80fe3SAlex Wilson 		return (ENOSTR);
975*cfe80fe3SAlex Wilson 	}
976*cfe80fe3SAlex Wilson 
9777c478bd9Sstevel@tonic-gate 	if (sflag) {
9787c478bd9Sstevel@tonic-gate 		/* clone open NOT supported here */
9797c478bd9Sstevel@tonic-gate 		return (ENXIO);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
982ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (!(flag & FREAD)) {
983ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		return (EIO);
984ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
9857c478bd9Sstevel@tonic-gate 
986*cfe80fe3SAlex Wilson 	mutex_enter(&hidp->hid_mutex);
987*cfe80fe3SAlex Wilson 
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * This is a workaround:
9907c478bd9Sstevel@tonic-gate 	 *	Currently, if we open an already disconnected device, and send
9917c478bd9Sstevel@tonic-gate 	 *	a CONSOPENPOLL ioctl to it, the system will panic, please refer
9927c478bd9Sstevel@tonic-gate 	 *	to the processing HID_OPEN_POLLED_INPUT ioctl in the routine
9937c478bd9Sstevel@tonic-gate 	 *	hid_mctl_receive().
9947c478bd9Sstevel@tonic-gate 	 *	The consconfig_dacf module need this interface to detect if the
9957c478bd9Sstevel@tonic-gate 	 *	device is already disconnnected.
9967c478bd9Sstevel@tonic-gate 	 */
9975321cfb7Spengcheng chen - Sun Microsystems - Beijing China 	if (HID_IS_INTERNAL_OPEN(minor) &&
9985321cfb7Spengcheng chen - Sun Microsystems - Beijing China 	    (hidp->hid_dev_state == USB_DEV_DISCONNECTED)) {
9997c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
10007c478bd9Sstevel@tonic-gate 		return (ENODEV);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
1003ddee57faSrui zang - Sun Microsystems - Beijing China 	if (HID_IS_INTERNAL_OPEN(minor) &&
1004ddee57faSrui zang - Sun Microsystems - Beijing China 	    (hidp->hid_internal_rq != NULL)) {
1005ddee57faSrui zang - Sun Microsystems - Beijing China 		ASSERT(hidp->hid_internal_rq == q);
1006ddee57faSrui zang - Sun Microsystems - Beijing China 
1007ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
1008ddee57faSrui zang - Sun Microsystems - Beijing China 		return (0);
1009ddee57faSrui zang - Sun Microsystems - Beijing China 	}
1010ddee57faSrui zang - Sun Microsystems - Beijing China 
1011ddee57faSrui zang - Sun Microsystems - Beijing China 	if ((!HID_IS_INTERNAL_OPEN(minor)) &&
1012ddee57faSrui zang - Sun Microsystems - Beijing China 	    (hidp->hid_external_rq != NULL)) {
1013ddee57faSrui zang - Sun Microsystems - Beijing China 		ASSERT(hidp->hid_external_rq == q);
1014ddee57faSrui zang - Sun Microsystems - Beijing China 
1015ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
1016ddee57faSrui zang - Sun Microsystems - Beijing China 		return (0);
1017ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
1018ddee57faSrui zang - Sun Microsystems - Beijing China 
1019ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_exit(&hidp->hid_mutex);
10207c478bd9Sstevel@tonic-gate 
1021ddee57faSrui zang - Sun Microsystems - Beijing China 	q->q_ptr = hidp;
1022ddee57faSrui zang - Sun Microsystems - Beijing China 	WR(q)->q_ptr = hidp;
10237c478bd9Sstevel@tonic-gate 
1024ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_enter(&hidp->hid_mutex);
1025ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_inuse_rq != NULL) {
1026ddee57faSrui zang - Sun Microsystems - Beijing China 		/* Pipe has already been setup */
1027ddee57faSrui zang - Sun Microsystems - Beijing China 
1028ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_INTERNAL_OPEN(minor)) {
1029ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_internal_flag = HID_STREAMS_OPEN;
1030ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
1031ddee57faSrui zang - Sun Microsystems - Beijing China 		} else {
1032ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_external_flag = HID_STREAMS_OPEN;
1033ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_inuse_rq = hidp->hid_external_rq = q;
1034ddee57faSrui zang - Sun Microsystems - Beijing China 		}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
1037ddee57faSrui zang - Sun Microsystems - Beijing China 
1038ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		qprocson(q);
1039ddee57faSrui zang - Sun Microsystems - Beijing China 
1040ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		return (0);
10417c478bd9Sstevel@tonic-gate 	}
10427c478bd9Sstevel@tonic-gate 
1043ddee57faSrui zang - Sun Microsystems - Beijing China 	/* Pipe only needs to be opened once */
1044ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	hidp->hid_interrupt_pipe = NULL;
1045ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	no_of_ep = hidp->hid_if_descr.bNumEndpoints;
1046ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_exit(&hidp->hid_mutex);
10477c478bd9Sstevel@tonic-gate 
1048ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	/* Check if interrupt endpoint exists */
1049ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (no_of_ep > 0) {
1050ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		/* Open the interrupt pipe */
1051993e3fafSRobert Mustacchi 		if (usb_pipe_xopen(hidp->hid_dip,
1052993e3fafSRobert Mustacchi 		    &hidp->hid_ep_intr_xdescr,
1053ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		    &hidp->hid_intr_pipe_policy, USB_FLAGS_SLEEP,
1054ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		    &hidp->hid_interrupt_pipe) !=
1055ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		    USB_SUCCESS) {
10567c478bd9Sstevel@tonic-gate 
1057ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			q->q_ptr = NULL;
1058ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			WR(q)->q_ptr = NULL;
1059ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			return (EIO);
10607c478bd9Sstevel@tonic-gate 		}
10617c478bd9Sstevel@tonic-gate 	}
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	hid_pm_busy_component(hidp);
10647c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
1067ddee57faSrui zang - Sun Microsystems - Beijing China 	if (HID_IS_INTERNAL_OPEN(minor)) {
1068ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_internal_flag = HID_STREAMS_OPEN;
1069ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_inuse_rq = hidp->hid_internal_rq = q;
1070ddee57faSrui zang - Sun Microsystems - Beijing China 	} else {
1071ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_external_flag = HID_STREAMS_OPEN;
1072ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_inuse_rq = hidp->hid_external_rq = q;
1073ddee57faSrui zang - Sun Microsystems - Beijing China 	}
1074ddee57faSrui zang - Sun Microsystems - Beijing China 
10757c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	qprocson(q);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
10827c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hidp->hid_log_handle,
10837c478bd9Sstevel@tonic-gate 		    "unable to start intr pipe polling. rval = %d", rval);
10847c478bd9Sstevel@tonic-gate 
1085ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_INTERNAL_OPEN(minor))
1086ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
1087ddee57faSrui zang - Sun Microsystems - Beijing China 		else
1088ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
10897c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 		usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
10927c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP, NULL, NULL);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
10957c478bd9Sstevel@tonic-gate 		hidp->hid_interrupt_pipe = NULL;
10967c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		qprocsoff(q);
1099ddee57faSrui zang - Sun Microsystems - Beijing China 
1100ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_enter(&hidp->hid_mutex);
1101ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_INTERNAL_OPEN(minor)) {
1102ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_internal_flag = 0;
1103ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_internal_rq = NULL;
1104ddee57faSrui zang - Sun Microsystems - Beijing China 			if (hidp->hid_external_flag == HID_STREAMS_OPEN)
1105ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = hidp->hid_external_rq;
1106ddee57faSrui zang - Sun Microsystems - Beijing China 			else
1107ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = NULL;
1108ddee57faSrui zang - Sun Microsystems - Beijing China 		} else {
1109ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_external_flag = 0;
1110ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_external_rq = NULL;
1111ddee57faSrui zang - Sun Microsystems - Beijing China 			if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
1112ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = hidp->hid_internal_rq;
1113ddee57faSrui zang - Sun Microsystems - Beijing China 			else
1114ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = NULL;
1115ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1116ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
1117ddee57faSrui zang - Sun Microsystems - Beijing China 
1118ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		q->q_ptr = NULL;
1119ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		WR(q)->q_ptr = NULL;
1120ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
11217c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 		return (EIO);
11247c478bd9Sstevel@tonic-gate 	}
11257c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle, "hid_open: End");
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/*
11307c478bd9Sstevel@tonic-gate 	 * Keyboard and mouse is Power managed by device activity.
11317c478bd9Sstevel@tonic-gate 	 * All other devices go busy on open and idle on close.
11327c478bd9Sstevel@tonic-gate 	 */
11337c478bd9Sstevel@tonic-gate 	switch (hidp->hid_pm->hid_pm_strategy) {
11347c478bd9Sstevel@tonic-gate 	case HID_PM_ACTIVITY:
11357c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 		break;
11387c478bd9Sstevel@tonic-gate 	default:
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 		break;
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	return (0);
11447c478bd9Sstevel@tonic-gate }
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * hid_close :
11497c478bd9Sstevel@tonic-gate  *	Close entry point.
11507c478bd9Sstevel@tonic-gate  */
11517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11527c478bd9Sstevel@tonic-gate static int
hid_close(queue_t * q,int flag,cred_t * credp)11537c478bd9Sstevel@tonic-gate hid_close(queue_t *q, int flag, cred_t *credp)
11547c478bd9Sstevel@tonic-gate {
1155ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
11567c478bd9Sstevel@tonic-gate 	queue_t		*wq;
11577c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle, "hid_close:");
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
1162ddee57faSrui zang - Sun Microsystems - Beijing China 
1163ddee57faSrui zang - Sun Microsystems - Beijing China 	ASSERT((hidp->hid_internal_rq == q) ||
1164ddee57faSrui zang - Sun Microsystems - Beijing China 	    (hidp->hid_external_rq == q));
1165ddee57faSrui zang - Sun Microsystems - Beijing China 
1166ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_internal_rq == q)
1167ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_internal_flag = HID_STREAMS_DISMANTLING;
1168ddee57faSrui zang - Sun Microsystems - Beijing China 	else
1169ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_external_flag = HID_STREAMS_DISMANTLING;
1170ddee57faSrui zang - Sun Microsystems - Beijing China 
11717c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	/*
11747c478bd9Sstevel@tonic-gate 	 * In case there are any outstanding requests on
11757c478bd9Sstevel@tonic-gate 	 * the default pipe, wait forever for them to complete.
11767c478bd9Sstevel@tonic-gate 	 */
11777c478bd9Sstevel@tonic-gate 	(void) usb_pipe_drain_reqs(hidp->hid_dip,
11787c478bd9Sstevel@tonic-gate 	    hidp->hid_default_pipe, 0, USB_FLAGS_SLEEP, NULL, 0);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
1181ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	wq = WR(q);
1182ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	/* drain any M_CTLS on the WQ */
11837c478bd9Sstevel@tonic-gate 	while (mp = getq(wq)) {
11847c478bd9Sstevel@tonic-gate 		hid_qreply_merror(wq, mp, EIO);
11857c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
11867c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
11877c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	qprocsoff(q);
1192ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
11937c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
1194ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	wq->q_ptr = NULL;
1195ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
1196ddee57faSrui zang - Sun Microsystems - Beijing China 	mutex_enter(&hidp->hid_mutex);
1197ddee57faSrui zang - Sun Microsystems - Beijing China 
1198ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_internal_rq == q) {
1199ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_internal_rq = NULL;
1200ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_internal_flag = 0;
1201ddee57faSrui zang - Sun Microsystems - Beijing China 		if (hidp->hid_inuse_rq == q) {
1202ddee57faSrui zang - Sun Microsystems - Beijing China 			/* We are closing the active stream */
1203ddee57faSrui zang - Sun Microsystems - Beijing China 			if (hidp->hid_external_flag == HID_STREAMS_OPEN)
1204ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = hidp->hid_external_rq;
1205ddee57faSrui zang - Sun Microsystems - Beijing China 			else
1206ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = NULL;
1207ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1208ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	} else {
1209ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_external_rq = NULL;
1210ddee57faSrui zang - Sun Microsystems - Beijing China 		hidp->hid_external_flag = 0;
1211ddee57faSrui zang - Sun Microsystems - Beijing China 		if (hidp->hid_inuse_rq == q) {
1212ddee57faSrui zang - Sun Microsystems - Beijing China 			/* We are closing the active stream */
1213ddee57faSrui zang - Sun Microsystems - Beijing China 			if (hidp->hid_internal_flag == HID_STREAMS_OPEN)
1214ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = hidp->hid_internal_rq;
1215ddee57faSrui zang - Sun Microsystems - Beijing China 			else
1216ddee57faSrui zang - Sun Microsystems - Beijing China 				hidp->hid_inuse_rq = NULL;
1217ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1218ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
1219ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
1220ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_inuse_rq != NULL) {
1221ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
1222ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		return (0);
1223ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
1224ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
1225ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	/* all queues are closed, close USB pipes */
1226ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	hid_close_intr_pipe(hidp);
1227ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_exit(&hidp->hid_mutex);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	/*
12307c478bd9Sstevel@tonic-gate 	 * Devices other than keyboard/mouse go idle on close.
12317c478bd9Sstevel@tonic-gate 	 */
12327c478bd9Sstevel@tonic-gate 	switch (hidp->hid_pm->hid_pm_strategy) {
12337c478bd9Sstevel@tonic-gate 	case HID_PM_ACTIVITY:
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 		break;
12367c478bd9Sstevel@tonic-gate 	default:
12377c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 		break;
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
12427c478bd9Sstevel@tonic-gate 	    "hid_close: End");
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	return (0);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate  * hid_wput :
12507c478bd9Sstevel@tonic-gate  *	write put routine for the hid module
12517c478bd9Sstevel@tonic-gate  */
12527c478bd9Sstevel@tonic-gate static int
hid_wput(queue_t * q,mblk_t * mp)12537c478bd9Sstevel@tonic-gate hid_wput(queue_t *q, mblk_t *mp)
12547c478bd9Sstevel@tonic-gate {
1255ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
12567c478bd9Sstevel@tonic-gate 	int		error = USB_SUCCESS;
1257db1c88f6SSebastian Wiedenroth 	struct iocblk	*iocbp;
1258ddee57faSrui zang - Sun Microsystems - Beijing China 	mblk_t		*datap;
1259ddee57faSrui zang - Sun Microsystems - Beijing China 	int		direction;
1260ddee57faSrui zang - Sun Microsystems - Beijing China 	struct copyresp *crp;
1261db1c88f6SSebastian Wiedenroth 	queue_t		*tmpq;
1262ddee57faSrui zang - Sun Microsystems - Beijing China 	int		flag;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
12657c478bd9Sstevel@tonic-gate 	    "hid_wput: Begin");
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	/* See if the upper module is passing the right thing */
12687c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
12697c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap != NULL);
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
12727c478bd9Sstevel@tonic-gate 	case M_FLUSH:  /* Canonical flush handling */
12737c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
12747c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
12757c478bd9Sstevel@tonic-gate 		}
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		/* read queue not used so just send up */
12787c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
12797c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
12807c478bd9Sstevel@tonic-gate 			qreply(q, mp);
12817c478bd9Sstevel@tonic-gate 		} else {
12827c478bd9Sstevel@tonic-gate 			freemsg(mp);
12837c478bd9Sstevel@tonic-gate 		}
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 		break;
12867c478bd9Sstevel@tonic-gate 	case M_IOCTL:
1287ddee57faSrui zang - Sun Microsystems - Beijing China 		iocbp = (struct iocblk *)mp->b_rptr;
1288ddee57faSrui zang - Sun Microsystems - Beijing China 
1289ddee57faSrui zang - Sun Microsystems - Beijing China 		/* Only accept transparent ioctls */
1290ddee57faSrui zang - Sun Microsystems - Beijing China 		if (iocbp->ioc_count != TRANSPARENT) {
1291ddee57faSrui zang - Sun Microsystems - Beijing China 			miocnak(q, mp, 0, EINVAL);
1292ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1293ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1294ddee57faSrui zang - Sun Microsystems - Beijing China 
1295ddee57faSrui zang - Sun Microsystems - Beijing China 		switch (iocbp->ioc_cmd) {
1296ddee57faSrui zang - Sun Microsystems - Beijing China 		case HIDIOCKMGDIRECT:
1297ddee57faSrui zang - Sun Microsystems - Beijing China 
1298ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
1299ddee57faSrui zang - Sun Microsystems - Beijing China 			ASSERT(hidp->hid_inuse_rq != NULL);
1300ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
1301ddee57faSrui zang - Sun Microsystems - Beijing China 
1302ddee57faSrui zang - Sun Microsystems - Beijing China 			if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
1303ddee57faSrui zang - Sun Microsystems - Beijing China 				miocnak(q, mp, 0, ENOMEM);
1304ddee57faSrui zang - Sun Microsystems - Beijing China 				break;
1305ddee57faSrui zang - Sun Microsystems - Beijing China 			}
1306ddee57faSrui zang - Sun Microsystems - Beijing China 
1307ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
1308ddee57faSrui zang - Sun Microsystems - Beijing China 			if (hidp->hid_inuse_rq == hidp->hid_internal_rq) {
1309ddee57faSrui zang - Sun Microsystems - Beijing China 				*(int *)datap->b_wptr = 0;
1310ddee57faSrui zang - Sun Microsystems - Beijing China 				datap->b_wptr += sizeof (int);
1311ddee57faSrui zang - Sun Microsystems - Beijing China 			} else {
1312ddee57faSrui zang - Sun Microsystems - Beijing China 				ASSERT(hidp->hid_inuse_rq ==
1313ddee57faSrui zang - Sun Microsystems - Beijing China 				    hidp->hid_external_rq);
1314ddee57faSrui zang - Sun Microsystems - Beijing China 				*(int *)datap->b_wptr = 1;
1315ddee57faSrui zang - Sun Microsystems - Beijing China 				datap->b_wptr += sizeof (int);
1316ddee57faSrui zang - Sun Microsystems - Beijing China 			}
1317ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
1318ddee57faSrui zang - Sun Microsystems - Beijing China 
1319ddee57faSrui zang - Sun Microsystems - Beijing China 			mcopyout(mp, NULL, sizeof (int), NULL, datap);
1320ddee57faSrui zang - Sun Microsystems - Beijing China 			qreply(q, mp);
1321ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1322ddee57faSrui zang - Sun Microsystems - Beijing China 
1323ddee57faSrui zang - Sun Microsystems - Beijing China 		case HIDIOCKMSDIRECT:
1324ddee57faSrui zang - Sun Microsystems - Beijing China 			mcopyin(mp, NULL, sizeof (int), NULL);
1325ddee57faSrui zang - Sun Microsystems - Beijing China 			qreply(q, mp);
1326ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1327ddee57faSrui zang - Sun Microsystems - Beijing China 
1328ddee57faSrui zang - Sun Microsystems - Beijing China 		default:
1329ddee57faSrui zang - Sun Microsystems - Beijing China 			miocnak(q, mp, 0, ENOTTY);
1330ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1331ddee57faSrui zang - Sun Microsystems - Beijing China 
1332ddee57faSrui zang - Sun Microsystems - Beijing China 		break;
1333ddee57faSrui zang - Sun Microsystems - Beijing China 
1334ddee57faSrui zang - Sun Microsystems - Beijing China 	case M_IOCDATA:
1335ddee57faSrui zang - Sun Microsystems - Beijing China 
1336ddee57faSrui zang - Sun Microsystems - Beijing China 		crp = (void *)mp->b_rptr;
1337ddee57faSrui zang - Sun Microsystems - Beijing China 
1338ddee57faSrui zang - Sun Microsystems - Beijing China 		if (crp->cp_rval != 0) {
1339ddee57faSrui zang - Sun Microsystems - Beijing China 			miocnak(q, mp, 0, EIO);
1340ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1341ddee57faSrui zang - Sun Microsystems - Beijing China 		}
1342ddee57faSrui zang - Sun Microsystems - Beijing China 
1343ddee57faSrui zang - Sun Microsystems - Beijing China 		switch (crp->cp_cmd) {
1344ddee57faSrui zang - Sun Microsystems - Beijing China 		case HIDIOCKMGDIRECT:
1345ddee57faSrui zang - Sun Microsystems - Beijing China 			miocack(q, mp, 0, 0);
1346ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1347ddee57faSrui zang - Sun Microsystems - Beijing China 
1348ddee57faSrui zang - Sun Microsystems - Beijing China 		case HIDIOCKMSDIRECT:
1349ddee57faSrui zang - Sun Microsystems - Beijing China 			direction = *(int *)mp->b_cont->b_rptr;
1350ddee57faSrui zang - Sun Microsystems - Beijing China 
1351ddee57faSrui zang - Sun Microsystems - Beijing China 			if ((direction != 0) && (direction != 1)) {
1352ddee57faSrui zang - Sun Microsystems - Beijing China 				miocnak(q, mp, 0, EINVAL);
1353ddee57faSrui zang - Sun Microsystems - Beijing China 				break;
1354ddee57faSrui zang - Sun Microsystems - Beijing China 			}
1355ddee57faSrui zang - Sun Microsystems - Beijing China 
1356ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
1357ddee57faSrui zang - Sun Microsystems - Beijing China 
1358ddee57faSrui zang - Sun Microsystems - Beijing China 			if (direction == 0) {
1359ddee57faSrui zang - Sun Microsystems - Beijing China 				/* The internal stream is made active */
1360ddee57faSrui zang - Sun Microsystems - Beijing China 				flag = hidp->hid_internal_flag;
1361ddee57faSrui zang - Sun Microsystems - Beijing China 				tmpq = hidp->hid_internal_rq;
1362ddee57faSrui zang - Sun Microsystems - Beijing China 			} else {
1363ddee57faSrui zang - Sun Microsystems - Beijing China 				/* The external stream is made active */
1364ddee57faSrui zang - Sun Microsystems - Beijing China 				flag = hidp->hid_external_flag;
1365ddee57faSrui zang - Sun Microsystems - Beijing China 				tmpq = hidp->hid_external_rq;
1366ddee57faSrui zang - Sun Microsystems - Beijing China 			}
1367ddee57faSrui zang - Sun Microsystems - Beijing China 
1368ddee57faSrui zang - Sun Microsystems - Beijing China 			if (flag != HID_STREAMS_OPEN) {
1369ddee57faSrui zang - Sun Microsystems - Beijing China 				mutex_exit(&hidp->hid_mutex);
1370ddee57faSrui zang - Sun Microsystems - Beijing China 				miocnak(q, mp, 0, EIO);
1371ddee57faSrui zang - Sun Microsystems - Beijing China 				break;
1372ddee57faSrui zang - Sun Microsystems - Beijing China 			}
1373ddee57faSrui zang - Sun Microsystems - Beijing China 
1374ddee57faSrui zang - Sun Microsystems - Beijing China 			hidp->hid_inuse_rq = tmpq;
1375ddee57faSrui zang - Sun Microsystems - Beijing China 
1376ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
1377ddee57faSrui zang - Sun Microsystems - Beijing China 			miocack(q, mp, 0, 0);
1378ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1379ddee57faSrui zang - Sun Microsystems - Beijing China 
1380ddee57faSrui zang - Sun Microsystems - Beijing China 		default:
1381ddee57faSrui zang - Sun Microsystems - Beijing China 			miocnak(q, mp, 0, ENOTTY);
1382ddee57faSrui zang - Sun Microsystems - Beijing China 			break;
1383ddee57faSrui zang - Sun Microsystems - Beijing China 		}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 		break;
1386ddee57faSrui zang - Sun Microsystems - Beijing China 
13877c478bd9Sstevel@tonic-gate 	case M_CTL:
13887c478bd9Sstevel@tonic-gate 		/* we are busy now */
13897c478bd9Sstevel@tonic-gate 		hid_pm_busy_component(hidp);
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 		if (q->q_first) {
13927c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
13937c478bd9Sstevel@tonic-gate 		} else {
13947c478bd9Sstevel@tonic-gate 			error = hid_mctl_receive(q, mp);
13957c478bd9Sstevel@tonic-gate 			switch (error) {
13967c478bd9Sstevel@tonic-gate 			case HID_ENQUEUE:
13977c478bd9Sstevel@tonic-gate 				/*
13987c478bd9Sstevel@tonic-gate 				 * put this mblk on the WQ for the wsrv to
13997c478bd9Sstevel@tonic-gate 				 * process
14007c478bd9Sstevel@tonic-gate 				 */
14017c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 				break;
14047c478bd9Sstevel@tonic-gate 			case HID_INPROGRESS:
14057c478bd9Sstevel@tonic-gate 				/* request has been queued to the device */
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 				break;
14087c478bd9Sstevel@tonic-gate 			case HID_SUCCESS:
14097c478bd9Sstevel@tonic-gate 				/*
14107c478bd9Sstevel@tonic-gate 				 * returned by M_CTLS that are processed
14117c478bd9Sstevel@tonic-gate 				 * immediately
14127c478bd9Sstevel@tonic-gate 				 */
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 				/* FALLTHRU */
14157c478bd9Sstevel@tonic-gate 			case HID_FAILURE:
14167c478bd9Sstevel@tonic-gate 			default:
14177c478bd9Sstevel@tonic-gate 				hid_pm_idle_component(hidp);
14187c478bd9Sstevel@tonic-gate 				break;
14197c478bd9Sstevel@tonic-gate 			}
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 		break;
14227c478bd9Sstevel@tonic-gate 	default:
14237c478bd9Sstevel@tonic-gate 		hid_qreply_merror(q, mp, EINVAL);
14247c478bd9Sstevel@tonic-gate 		error = USB_FAILURE;
14257c478bd9Sstevel@tonic-gate 		break;
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14297c478bd9Sstevel@tonic-gate 	    "hid_wput: End");
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate /*
14367c478bd9Sstevel@tonic-gate  * hid_wsrv :
14377c478bd9Sstevel@tonic-gate  *	Write service routine for hid. When a message arrives through
14387c478bd9Sstevel@tonic-gate  *	hid_wput(), it is kept in write queue to be serviced later.
14397c478bd9Sstevel@tonic-gate  */
14407c478bd9Sstevel@tonic-gate static int
hid_wsrv(queue_t * q)14417c478bd9Sstevel@tonic-gate hid_wsrv(queue_t *q)
14427c478bd9Sstevel@tonic-gate {
1443ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
14447c478bd9Sstevel@tonic-gate 	int		error;
14457c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14487c478bd9Sstevel@tonic-gate 	    "hid_wsrv: Begin");
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
14517c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14527c478bd9Sstevel@tonic-gate 	    "hid_wsrv: dev_state: %s",
14537c478bd9Sstevel@tonic-gate 	    usb_str_dev_state(hidp->hid_dev_state));
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/*
14567c478bd9Sstevel@tonic-gate 	 * raise power if we are powered down. It is OK to block here since
14577c478bd9Sstevel@tonic-gate 	 * we have a separate thread to process this STREAM
14587c478bd9Sstevel@tonic-gate 	 */
14597c478bd9Sstevel@tonic-gate 	if (hidp->hid_dev_state == USB_DEV_PWRED_DOWN) {
14607c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
14617c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
14627c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	/*
14667c478bd9Sstevel@tonic-gate 	 * continue servicing all the M_CTL's till the queue is empty
14677c478bd9Sstevel@tonic-gate 	 * or the device gets disconnected or till a hid_close()
14687c478bd9Sstevel@tonic-gate 	 */
14697c478bd9Sstevel@tonic-gate 	while ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
1470ddee57faSrui zang - Sun Microsystems - Beijing China 	    (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) &&
14717c478bd9Sstevel@tonic-gate 	    ((mp = getq(q)) != NULL)) {
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 		/* Send a message down */
14747c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
14757c478bd9Sstevel@tonic-gate 		error = hid_mctl_receive(q, mp);
14767c478bd9Sstevel@tonic-gate 		switch (error) {
14777c478bd9Sstevel@tonic-gate 		case HID_ENQUEUE:
14787c478bd9Sstevel@tonic-gate 			/* put this mblk back on q to preserve order */
14797c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 			break;
14827c478bd9Sstevel@tonic-gate 		case HID_INPROGRESS:
14837c478bd9Sstevel@tonic-gate 			/* request has been queued to the device */
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 			break;
14867c478bd9Sstevel@tonic-gate 		case HID_SUCCESS:
14877c478bd9Sstevel@tonic-gate 		case HID_FAILURE:
14887c478bd9Sstevel@tonic-gate 		default:
14897c478bd9Sstevel@tonic-gate 			hid_pm_idle_component(hidp);
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 			break;
14927c478bd9Sstevel@tonic-gate 		}
14937c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
14947c478bd9Sstevel@tonic-gate 	}
14957c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
14967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
14977c478bd9Sstevel@tonic-gate 	    "hid_wsrv: End");
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate /*
15047c478bd9Sstevel@tonic-gate  * hid_power:
15057c478bd9Sstevel@tonic-gate  *	power entry point
15067c478bd9Sstevel@tonic-gate  */
15077c478bd9Sstevel@tonic-gate static int
hid_power(dev_info_t * dip,int comp,int level)15087c478bd9Sstevel@tonic-gate hid_power(dev_info_t *dip, int comp, int level)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
15117c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp;
15127c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
15137c478bd9Sstevel@tonic-gate 	int		retval;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	hidp = ddi_get_soft_state(hid_statep, instance);
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle, "hid_power:"
15187c478bd9Sstevel@tonic-gate 	    " hid_state: comp=%d level=%d", comp, level);
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	/* check if we are transitioning to a legal power level */
15217c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
15227c478bd9Sstevel@tonic-gate 	hidpm = hidp->hid_pm;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(hidpm->hid_pwr_states, level)) {
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
15277c478bd9Sstevel@tonic-gate 		    "hid_power: illegal level=%d hid_pwr_states=%d",
15287c478bd9Sstevel@tonic-gate 		    level, hidpm->hid_pwr_states);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15337c478bd9Sstevel@tonic-gate 	}
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	switch (level) {
15367c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF:
15377c478bd9Sstevel@tonic-gate 		retval = hid_pwrlvl0(hidp);
15387c478bd9Sstevel@tonic-gate 		break;
15397c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1:
15407c478bd9Sstevel@tonic-gate 		retval = hid_pwrlvl1(hidp);
15417c478bd9Sstevel@tonic-gate 		break;
15427c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2:
15437c478bd9Sstevel@tonic-gate 		retval = hid_pwrlvl2(hidp);
15447c478bd9Sstevel@tonic-gate 		break;
15457c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR:
15467c478bd9Sstevel@tonic-gate 		retval = hid_pwrlvl3(hidp);
15477c478bd9Sstevel@tonic-gate 		break;
15487c478bd9Sstevel@tonic-gate 	default:
15497c478bd9Sstevel@tonic-gate 		retval = USB_FAILURE;
15507c478bd9Sstevel@tonic-gate 		break;
15517c478bd9Sstevel@tonic-gate 	}
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate /*
15607c478bd9Sstevel@tonic-gate  * hid_interrupt_pipe_callback:
15617c478bd9Sstevel@tonic-gate  *	Callback function for the hid intr pipe. This function is called by
15627c478bd9Sstevel@tonic-gate  *	USBA when a buffer has been filled. This driver does not cook the data,
15637c478bd9Sstevel@tonic-gate  *	it just sends the message up.
15647c478bd9Sstevel@tonic-gate  */
15657c478bd9Sstevel@tonic-gate static void
hid_interrupt_pipe_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)15667c478bd9Sstevel@tonic-gate hid_interrupt_pipe_callback(usb_pipe_handle_t pipe, usb_intr_req_t *req)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	hid_state_t *hidp = (hid_state_t *)req->intr_client_private;
15697c478bd9Sstevel@tonic-gate 	queue_t	*q;
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
1572112116d8Sfb 	    "hid_interrupt_pipe_callback: ph = 0x%p req = 0x%p",
1573112116d8Sfb 	    (void *)pipe, (void *)req);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	hid_pm_busy_component(hidp);
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	/*
15807c478bd9Sstevel@tonic-gate 	 * If hid_close() is in progress, we shouldn't try accessing queue
15817c478bd9Sstevel@tonic-gate 	 * Otherwise indicate that a putnext is going to happen, so
15827c478bd9Sstevel@tonic-gate 	 * if close after this, that should wait for the putnext to finish.
15837c478bd9Sstevel@tonic-gate 	 */
1584ddee57faSrui zang - Sun Microsystems - Beijing China 	if (HID_STREAMS_FLAG(hidp->hid_inuse_rq, hidp) ==
1585ddee57faSrui zang - Sun Microsystems - Beijing China 	    HID_STREAMS_OPEN) {
15867c478bd9Sstevel@tonic-gate 		/*
15877c478bd9Sstevel@tonic-gate 		 * Check if data can be put to the next queue.
15887c478bd9Sstevel@tonic-gate 		 */
1589ddee57faSrui zang - Sun Microsystems - Beijing China 		if (!canputnext(hidp->hid_inuse_rq)) {
15907c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
15917c478bd9Sstevel@tonic-gate 			    "Buffer flushed when overflowed.");
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 			/* Flush the queue above */
1594ddee57faSrui zang - Sun Microsystems - Beijing China 			hid_flush(hidp->hid_inuse_rq);
15957c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
15967c478bd9Sstevel@tonic-gate 		} else {
1597ddee57faSrui zang - Sun Microsystems - Beijing China 			q = hidp->hid_inuse_rq;
15987c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 			/* Put data upstream */
16017c478bd9Sstevel@tonic-gate 			putnext(q, req->intr_data);
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 			/* usb_free_intr_req should not free data */
16047c478bd9Sstevel@tonic-gate 			req->intr_data = NULL;
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 	} else {
16077c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
16087c478bd9Sstevel@tonic-gate 	}
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/* free request and data */
16117c478bd9Sstevel@tonic-gate 	usb_free_intr_req(req);
16127c478bd9Sstevel@tonic-gate 	hid_pm_idle_component(hidp);
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate  * hid_default_pipe_callback :
16187c478bd9Sstevel@tonic-gate  *	Callback routine for the asynchronous control transfer
16197c478bd9Sstevel@tonic-gate  *	Called from hid_send_async_ctrl_request() where we open
16207c478bd9Sstevel@tonic-gate  *	the pipe in exclusive mode
16217c478bd9Sstevel@tonic-gate  */
16227c478bd9Sstevel@tonic-gate static void
hid_default_pipe_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)16237c478bd9Sstevel@tonic-gate hid_default_pipe_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *req)
16247c478bd9Sstevel@tonic-gate {
16257c478bd9Sstevel@tonic-gate 	hid_default_pipe_arg_t *hid_default_pipe_arg =
16267c478bd9Sstevel@tonic-gate 	    (hid_default_pipe_arg_t *)req->ctrl_client_private;
1627ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	queue_t		*wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1628ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	queue_t		*rq = RD(wq);
1629ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)rq->q_ptr;
16307c478bd9Sstevel@tonic-gate 	mblk_t		*mctl_mp;
16317c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
16347c478bd9Sstevel@tonic-gate 	    "hid_default_pipe_callback: "
1635112116d8Sfb 	    "ph = 0x%p, req = 0x%p, data= 0x%p",
1636112116d8Sfb 	    (void *)pipe, (void *)req, (void *)data);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	if (req->ctrl_data) {
16417c478bd9Sstevel@tonic-gate 		data = req->ctrl_data;
16427c478bd9Sstevel@tonic-gate 		req->ctrl_data = NULL;
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	/*
16467c478bd9Sstevel@tonic-gate 	 * Free the b_cont of the original message that was sent down.
16477c478bd9Sstevel@tonic-gate 	 */
16487c478bd9Sstevel@tonic-gate 	mctl_mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
16497c478bd9Sstevel@tonic-gate 	freemsg(mctl_mp->b_cont);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	/* chain the mblk received to the original & send it up */
16527c478bd9Sstevel@tonic-gate 	mctl_mp->b_cont = data;
1653ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
1654ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (canputnext(rq)) {
1655ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		putnext(rq, mctl_mp);
16567c478bd9Sstevel@tonic-gate 	} else {
16577c478bd9Sstevel@tonic-gate 		freemsg(mctl_mp); /* avoid leak */
16587c478bd9Sstevel@tonic-gate 	}
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	/*
16617c478bd9Sstevel@tonic-gate 	 * Free the argument for the asynchronous callback
16627c478bd9Sstevel@tonic-gate 	 */
16637c478bd9Sstevel@tonic-gate 	kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/*
16667c478bd9Sstevel@tonic-gate 	 * Free the control pipe request structure.
16677c478bd9Sstevel@tonic-gate 	 */
16687c478bd9Sstevel@tonic-gate 	usb_free_ctrl_req(req);
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
16717c478bd9Sstevel@tonic-gate 	hidp->hid_default_pipe_req--;
16727c478bd9Sstevel@tonic-gate 	ASSERT(hidp->hid_default_pipe_req >= 0);
16737c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	hid_pm_idle_component(hidp);
1676ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	qenable(wq);
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate /*
16817c478bd9Sstevel@tonic-gate  * hid_interrupt_pipe_exception_callback:
16827c478bd9Sstevel@tonic-gate  *	Exception callback routine for interrupt pipe. If there is any data,
16837c478bd9Sstevel@tonic-gate  *	destroy it. No threads are waiting for the exception callback.
16847c478bd9Sstevel@tonic-gate  */
16857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16867c478bd9Sstevel@tonic-gate static void
hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,usb_intr_req_t * req)16877c478bd9Sstevel@tonic-gate hid_interrupt_pipe_exception_callback(usb_pipe_handle_t pipe,
16887c478bd9Sstevel@tonic-gate     usb_intr_req_t *req)
16897c478bd9Sstevel@tonic-gate {
16907c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp = (hid_state_t *)req->intr_client_private;
16917c478bd9Sstevel@tonic-gate 	mblk_t		*data = req->intr_data;
16927c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	flags = req->intr_cb_flags;
16937c478bd9Sstevel@tonic-gate 	int		rval;
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
16967c478bd9Sstevel@tonic-gate 	    "hid_interrupt_pipe_exception_callback: "
16977c478bd9Sstevel@tonic-gate 	    "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
16987c478bd9Sstevel@tonic-gate 	    req->intr_completion_reason, (void *)data, req->intr_cb_flags);
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	ASSERT((req->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	if (((flags & USB_CB_FUNCTIONAL_STALL) != 0) &&
17037c478bd9Sstevel@tonic-gate 	    ((flags & USB_CB_STALL_CLEARED) == 0)) {
17047c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,
17057c478bd9Sstevel@tonic-gate 		    hidp->hid_log_handle,
17067c478bd9Sstevel@tonic-gate 		    "hid_interrupt_pipe_exception_callback: "
17077c478bd9Sstevel@tonic-gate 		    "unable to clear stall.  flags = 0x%x",
17087c478bd9Sstevel@tonic-gate 		    req->intr_cb_flags);
17097c478bd9Sstevel@tonic-gate 	}
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	switch (req->intr_completion_reason) {
17147c478bd9Sstevel@tonic-gate 	case USB_CR_STOPPED_POLLING:
17157c478bd9Sstevel@tonic-gate 	case USB_CR_PIPE_CLOSING:
17167c478bd9Sstevel@tonic-gate 	default:
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 		break;
17197c478bd9Sstevel@tonic-gate 	case USB_CR_PIPE_RESET:
17207c478bd9Sstevel@tonic-gate 	case USB_CR_NO_RESOURCES:
17217c478bd9Sstevel@tonic-gate 		if ((hidp->hid_dev_state == USB_DEV_ONLINE) &&
17227c478bd9Sstevel@tonic-gate 		    ((rval = hid_start_intr_polling(hidp)) !=
17237c478bd9Sstevel@tonic-gate 		    USB_SUCCESS)) {
17247c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
17257c478bd9Sstevel@tonic-gate 			    "unable to restart interrupt poll. rval = %d",
17267c478bd9Sstevel@tonic-gate 			    rval);
17277c478bd9Sstevel@tonic-gate 		}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 		break;
17307c478bd9Sstevel@tonic-gate 	}
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	usb_free_intr_req(req);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate /*
17397c478bd9Sstevel@tonic-gate  * hid_default_pipe_exception_callback:
17407c478bd9Sstevel@tonic-gate  *	Exception callback routine for default pipe.
17417c478bd9Sstevel@tonic-gate  */
17427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17437c478bd9Sstevel@tonic-gate static void
hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,usb_ctrl_req_t * req)17447c478bd9Sstevel@tonic-gate hid_default_pipe_exception_callback(usb_pipe_handle_t pipe,
17457c478bd9Sstevel@tonic-gate     usb_ctrl_req_t *req)
17467c478bd9Sstevel@tonic-gate {
17477c478bd9Sstevel@tonic-gate 	hid_default_pipe_arg_t *hid_default_pipe_arg =
17487c478bd9Sstevel@tonic-gate 	    (hid_default_pipe_arg_t *)req->ctrl_client_private;
1749ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	queue_t		*wq = hid_default_pipe_arg->hid_default_pipe_arg_queue;
1750ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	queue_t		*rq = RD(wq);
1751ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)rq->q_ptr;
17527c478bd9Sstevel@tonic-gate 	usb_cr_t	ctrl_completion_reason = req->ctrl_completion_reason;
1753ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mblk_t		*mp, *data = NULL;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
17567c478bd9Sstevel@tonic-gate 	    "hid_default_pipe_exception_callback: "
17577c478bd9Sstevel@tonic-gate 	    "completion_reason = 0x%x, data = 0x%p, flag = 0x%x",
17587c478bd9Sstevel@tonic-gate 	    ctrl_completion_reason, (void *)data, req->ctrl_cb_flags);
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	ASSERT((req->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0);
17617c478bd9Sstevel@tonic-gate 
1762ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mp = hid_default_pipe_arg->hid_default_pipe_arg_mblk;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	/*
17657c478bd9Sstevel@tonic-gate 	 * Pass an error message up. Reuse existing mblk.
17667c478bd9Sstevel@tonic-gate 	 */
1767ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (canputnext(rq)) {
17687c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_ERROR;
17697c478bd9Sstevel@tonic-gate 		mp->b_rptr = mp->b_datap->db_base;
17707c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (char);
17717c478bd9Sstevel@tonic-gate 		*mp->b_rptr = EIO;
1772ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		putnext(rq, mp);
17737c478bd9Sstevel@tonic-gate 	} else {
1774ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		freemsg(mp);
17757c478bd9Sstevel@tonic-gate 	}
1776ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
17777c478bd9Sstevel@tonic-gate 	kmem_free(hid_default_pipe_arg, sizeof (hid_default_pipe_arg_t));
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
17807c478bd9Sstevel@tonic-gate 	hidp->hid_default_pipe_req--;
17817c478bd9Sstevel@tonic-gate 	ASSERT(hidp->hid_default_pipe_req >= 0);
17827c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
17837c478bd9Sstevel@tonic-gate 
1784ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	qenable(wq);
17857c478bd9Sstevel@tonic-gate 	usb_free_ctrl_req(req);
17867c478bd9Sstevel@tonic-gate 	hid_pm_idle_component(hidp);
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate /*
17917c478bd9Sstevel@tonic-gate  * event handling:
17927c478bd9Sstevel@tonic-gate  *
17937c478bd9Sstevel@tonic-gate  * hid_reconnect_event_callback:
17947c478bd9Sstevel@tonic-gate  *	the device was disconnected but this instance not detached, probably
17957c478bd9Sstevel@tonic-gate  *	because the device was busy
17967c478bd9Sstevel@tonic-gate  *
17977c478bd9Sstevel@tonic-gate  *	If the same device, continue with restoring state
17987c478bd9Sstevel@tonic-gate  */
17997c478bd9Sstevel@tonic-gate static int
hid_restore_state_event_callback(dev_info_t * dip)18007c478bd9Sstevel@tonic-gate hid_restore_state_event_callback(dev_info_t *dip)
18017c478bd9Sstevel@tonic-gate {
18027c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
1803112116d8Sfb 	    ddi_get_instance(dip));
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	ASSERT(hidp != NULL);
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1808112116d8Sfb 	    "hid_restore_state_event_callback: dip=0x%p", (void *)dip);
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	hid_restore_device_state(dip, hidp);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate /*
18177c478bd9Sstevel@tonic-gate  * hid_cpr_suspend
18187c478bd9Sstevel@tonic-gate  *	Fail suspend if we can't finish outstanding i/o activity.
18197c478bd9Sstevel@tonic-gate  */
18207c478bd9Sstevel@tonic-gate static int
hid_cpr_suspend(hid_state_t * hidp)18217c478bd9Sstevel@tonic-gate hid_cpr_suspend(hid_state_t *hidp)
18227c478bd9Sstevel@tonic-gate {
18237c478bd9Sstevel@tonic-gate 	int		rval, prev_state;
18247c478bd9Sstevel@tonic-gate 	int		retval = USB_FAILURE;
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1827112116d8Sfb 	    "hid_cpr_suspend: dip=0x%p", (void *)hidp->hid_dip);
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
18307c478bd9Sstevel@tonic-gate 	switch (hidp->hid_dev_state) {
18317c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
18327c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
18337c478bd9Sstevel@tonic-gate 		prev_state = hidp->hid_dev_state;
18347c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_SUSPENDED;
18357c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 		/* drain all request outstanding on the default control pipe */
18387c478bd9Sstevel@tonic-gate 		rval = usb_pipe_drain_reqs(hidp->hid_dip,
18397c478bd9Sstevel@tonic-gate 		    hidp->hid_default_pipe, hid_default_pipe_drain_timeout,
18407c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP, NULL, 0);
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 		/* fail checkpoint if we haven't finished the job yet */
18437c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
18447c478bd9Sstevel@tonic-gate 		if ((rval != USB_SUCCESS) || (hidp->hid_default_pipe_req > 0)) {
18457c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
18467c478bd9Sstevel@tonic-gate 			    "hid_cpr_suspend: "
18477c478bd9Sstevel@tonic-gate 			    "device busy - can't checkpoint");
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 			/* fall back to previous state */
18507c478bd9Sstevel@tonic-gate 			hidp->hid_dev_state = prev_state;
18517c478bd9Sstevel@tonic-gate 		} else {
18527c478bd9Sstevel@tonic-gate 			retval = USB_SUCCESS;
18537c478bd9Sstevel@tonic-gate 			hid_save_device_state(hidp);
18547c478bd9Sstevel@tonic-gate 		}
18557c478bd9Sstevel@tonic-gate 
1856f67c0a39Sfei feng - Sun Microsystems - Beijing China 		break;
1857f67c0a39Sfei feng - Sun Microsystems - Beijing China 	case USB_DEV_DISCONNECTED:
1858f67c0a39Sfei feng - Sun Microsystems - Beijing China 		hidp->hid_dev_state = USB_DEV_SUSPENDED;
1859f67c0a39Sfei feng - Sun Microsystems - Beijing China 		hid_save_device_state(hidp);
1860f67c0a39Sfei feng - Sun Microsystems - Beijing China 		retval = USB_SUCCESS;
18617c478bd9Sstevel@tonic-gate 		break;
18627c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
18637c478bd9Sstevel@tonic-gate 	default:
18647c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
18657c478bd9Sstevel@tonic-gate 		    "hid_cpr_suspend: Illegal dev state: %d",
18667c478bd9Sstevel@tonic-gate 		    hidp->hid_dev_state);
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 		break;
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
18717c478bd9Sstevel@tonic-gate 
1872*cfe80fe3SAlex Wilson 	if ((retval == USB_SUCCESS) && hidp->hid_ugen_hdl != NULL) {
1873*cfe80fe3SAlex Wilson 		retval = usb_ugen_detach(hidp->hid_ugen_hdl,
1874*cfe80fe3SAlex Wilson 		    DDI_SUSPEND);
1875*cfe80fe3SAlex Wilson 	}
1876*cfe80fe3SAlex Wilson 
18777c478bd9Sstevel@tonic-gate 	return (retval);
18787c478bd9Sstevel@tonic-gate }
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate static void
hid_cpr_resume(hid_state_t * hidp)18827c478bd9Sstevel@tonic-gate hid_cpr_resume(hid_state_t *hidp)
18837c478bd9Sstevel@tonic-gate {
18847c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1885112116d8Sfb 	    "hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip);
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	hid_restore_device_state(hidp->hid_dip, hidp);
1888*cfe80fe3SAlex Wilson 
1889*cfe80fe3SAlex Wilson 	if (hidp->hid_ugen_hdl != NULL) {
1890*cfe80fe3SAlex Wilson 		(void) usb_ugen_attach(hidp->hid_ugen_hdl, DDI_RESUME);
1891*cfe80fe3SAlex Wilson 	}
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate /*
18967c478bd9Sstevel@tonic-gate  * hid_disconnect_event_callback:
18977c478bd9Sstevel@tonic-gate  *	The device has been disconnected. We either wait for
18987c478bd9Sstevel@tonic-gate  *	detach or a reconnect event. Close all pipes and timeouts.
18997c478bd9Sstevel@tonic-gate  */
19007c478bd9Sstevel@tonic-gate static int
hid_disconnect_event_callback(dev_info_t * dip)19017c478bd9Sstevel@tonic-gate hid_disconnect_event_callback(dev_info_t *dip)
19027c478bd9Sstevel@tonic-gate {
19037c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp;
1904ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mblk_t		*mp;
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	hidp = (hid_state_t *)ddi_get_soft_state(hid_statep,
19077c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
19087c478bd9Sstevel@tonic-gate 	ASSERT(hidp != NULL);
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
1911112116d8Sfb 	    "hid_disconnect_event_callback: dip=0x%p", (void *)dip);
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
19147c478bd9Sstevel@tonic-gate 	switch (hidp->hid_dev_state) {
19157c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
19167c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
19177c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_DISCONNECTED;
1918ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_OPEN(hidp)) {
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
19217c478bd9Sstevel@tonic-gate 			    "busy device has been disconnected");
19227c478bd9Sstevel@tonic-gate 		}
19237c478bd9Sstevel@tonic-gate 		hid_save_device_state(hidp);
19247c478bd9Sstevel@tonic-gate 
1925ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		/*
1926ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 * Notify applications about device removal, this only
1927ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 * applies to an external (aka. physical) open. For an
1928ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 * internal open, consconfig_dacf closes the queue.
1929ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 */
1930ddee57faSrui zang - Sun Microsystems - Beijing China 		if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
1931ddee57faSrui zang - Sun Microsystems - Beijing China 			queue_t *q = hidp->hid_external_rq;
1932ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
1933ddee57faSrui zang - Sun Microsystems - Beijing China 			mp = allocb(sizeof (uchar_t), BPRI_HI);
1934ddee57faSrui zang - Sun Microsystems - Beijing China 			if (mp != NULL) {
1935ddee57faSrui zang - Sun Microsystems - Beijing China 				mp->b_datap->db_type = M_ERROR;
1936ddee57faSrui zang - Sun Microsystems - Beijing China 				mp->b_rptr = mp->b_datap->db_base;
1937ddee57faSrui zang - Sun Microsystems - Beijing China 				mp->b_wptr = mp->b_rptr + sizeof (char);
1938ddee57faSrui zang - Sun Microsystems - Beijing China 				*mp->b_rptr = ENODEV;
1939ddee57faSrui zang - Sun Microsystems - Beijing China 				putnext(q, mp);
1940ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			}
1941ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
1942ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		}
1943ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
19447c478bd9Sstevel@tonic-gate 		break;
19457c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
19467c478bd9Sstevel@tonic-gate 		/* we remain suspended */
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 		break;
19497c478bd9Sstevel@tonic-gate 	default:
19507c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
19517c478bd9Sstevel@tonic-gate 		    "hid_disconnect_event_callback: Illegal dev state: %d",
19527c478bd9Sstevel@tonic-gate 		    hidp->hid_dev_state);
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 		break;
19557c478bd9Sstevel@tonic-gate 	}
19567c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate  * hid_power_change_callback:
19647c478bd9Sstevel@tonic-gate  *	Async callback function to notify pm_raise_power completion
19657c478bd9Sstevel@tonic-gate  *	after hid_power entry point is called.
19667c478bd9Sstevel@tonic-gate  */
19677c478bd9Sstevel@tonic-gate static void
hid_power_change_callback(void * arg,int rval)19687c478bd9Sstevel@tonic-gate hid_power_change_callback(void *arg, int rval)
19697c478bd9Sstevel@tonic-gate {
19707c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp;
19717c478bd9Sstevel@tonic-gate 	queue_t		*wq;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	hidp = (hid_state_t *)arg;
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
19767c478bd9Sstevel@tonic-gate 	    "hid_power_change_callback - rval: %d", rval);
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
19797c478bd9Sstevel@tonic-gate 	hidp->hid_pm->hid_raise_power = B_FALSE;
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	if (hidp->hid_dev_state == USB_DEV_ONLINE) {
1982ddee57faSrui zang - Sun Microsystems - Beijing China 		wq = WR(hidp->hid_inuse_rq);
19837c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 		qenable(wq);
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	} else {
19887c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
19897c478bd9Sstevel@tonic-gate 	}
19907c478bd9Sstevel@tonic-gate }
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate /*
19947c478bd9Sstevel@tonic-gate  * hid_parse_hid_descr:
19957c478bd9Sstevel@tonic-gate  *	Parse the hid descriptor, check after interface and after
19967c478bd9Sstevel@tonic-gate  *	endpoint descriptor
19977c478bd9Sstevel@tonic-gate  */
19987c478bd9Sstevel@tonic-gate static size_t
hid_parse_hid_descr(usb_hid_descr_t * ret_descr,size_t ret_buf_len,usb_alt_if_data_t * altif_data,usb_ep_data_t * ep_data)1999993e3fafSRobert Mustacchi hid_parse_hid_descr(usb_hid_descr_t *ret_descr,	size_t ret_buf_len,
2000993e3fafSRobert Mustacchi     usb_alt_if_data_t *altif_data, usb_ep_data_t *ep_data)
20017c478bd9Sstevel@tonic-gate {
20027c478bd9Sstevel@tonic-gate 	usb_cvs_data_t *cvs;
20037c478bd9Sstevel@tonic-gate 	int		which_cvs;
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 	for (which_cvs = 0; which_cvs < altif_data->altif_n_cvs; which_cvs++) {
20067c478bd9Sstevel@tonic-gate 		cvs = &altif_data->altif_cvs[which_cvs];
20077c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf == NULL) {
20087c478bd9Sstevel@tonic-gate 			continue;
20097c478bd9Sstevel@tonic-gate 		}
20107c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
20117c478bd9Sstevel@tonic-gate 			return (usb_parse_data("ccscccs",
2012112116d8Sfb 			    cvs->cvs_buf, cvs->cvs_buf_len,
2013112116d8Sfb 			    (void *)ret_descr,
2014112116d8Sfb 			    (size_t)ret_buf_len));
20157c478bd9Sstevel@tonic-gate 		}
20167c478bd9Sstevel@tonic-gate 	}
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	/* now try after endpoint */
20197c478bd9Sstevel@tonic-gate 	for (which_cvs = 0; which_cvs < ep_data->ep_n_cvs; which_cvs++) {
20207c478bd9Sstevel@tonic-gate 		cvs = &ep_data->ep_cvs[which_cvs];
20217c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf == NULL) {
20227c478bd9Sstevel@tonic-gate 			continue;
20237c478bd9Sstevel@tonic-gate 		}
20247c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf[1] == USB_DESCR_TYPE_HID) {
20257c478bd9Sstevel@tonic-gate 			return (usb_parse_data("ccscccs",
2026112116d8Sfb 			    cvs->cvs_buf, cvs->cvs_buf_len,
2027112116d8Sfb 			    (void *)ret_descr,
2028112116d8Sfb 			    (size_t)ret_buf_len));
20297c478bd9Sstevel@tonic-gate 		}
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	return (USB_PARSE_ERROR);
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate /*
20377c478bd9Sstevel@tonic-gate  * hid_parse_hid_descr_failure:
20387c478bd9Sstevel@tonic-gate  *	If parsing of hid descriptor failed and the device is
20397c478bd9Sstevel@tonic-gate  *	a keyboard or mouse, use predefined length and packet size.
20407c478bd9Sstevel@tonic-gate  */
20417c478bd9Sstevel@tonic-gate static int
hid_parse_hid_descr_failure(hid_state_t * hidp)20427c478bd9Sstevel@tonic-gate hid_parse_hid_descr_failure(hid_state_t	*hidp)
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate 	/*
20457c478bd9Sstevel@tonic-gate 	 * Parsing hid descriptor failed, probably because the
20467c478bd9Sstevel@tonic-gate 	 * device did not return a valid hid descriptor. Check to
20477c478bd9Sstevel@tonic-gate 	 * see if this is a keyboard or mouse. If so, use the
20487c478bd9Sstevel@tonic-gate 	 * predefined hid descriptor length and packet size.
20497c478bd9Sstevel@tonic-gate 	 * Otherwise, detach and return failure.
20507c478bd9Sstevel@tonic-gate 	 */
20517c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
20527c478bd9Sstevel@tonic-gate 	    "Parsing of hid descriptor failed");
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	if (hidp->hid_if_descr.bInterfaceProtocol == KEYBOARD_PROTOCOL) {
20557c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20567c478bd9Sstevel@tonic-gate 		    "Set hid descriptor length to predefined "
20577c478bd9Sstevel@tonic-gate 		    "USB_KB_HID_DESCR_LENGTH for keyboard.");
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 		/* device is a keyboard */
20607c478bd9Sstevel@tonic-gate 		hidp->hid_hid_descr.wReportDescriptorLength =
2061112116d8Sfb 		    USB_KB_HID_DESCR_LENGTH;
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 		hidp->hid_packet_size = USBKPSZ;
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	} else if (hidp->hid_if_descr.bInterfaceProtocol ==
20667c478bd9Sstevel@tonic-gate 	    MOUSE_PROTOCOL) {
20677c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
20687c478bd9Sstevel@tonic-gate 		    "Set hid descriptor length to predefined "
20697c478bd9Sstevel@tonic-gate 		    "USB_MS_HID_DESCR_LENGTH for mouse.");
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 		/* device is a mouse */
20727c478bd9Sstevel@tonic-gate 		hidp->hid_hid_descr.wReportDescriptorLength =
2073112116d8Sfb 		    USB_MS_HID_DESCR_LENGTH;
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 		hidp->hid_packet_size = USBMSSZ;
20767c478bd9Sstevel@tonic-gate 	} else {
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
20797c478bd9Sstevel@tonic-gate 	}
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate /*
20867c478bd9Sstevel@tonic-gate  * hid_handle_report_descriptor:
20877c478bd9Sstevel@tonic-gate  *	Get the report descriptor, call hidparser routine to parse
20887c478bd9Sstevel@tonic-gate  *	it and query the hidparser tree to get the packet size
20897c478bd9Sstevel@tonic-gate  */
20907c478bd9Sstevel@tonic-gate static int
hid_handle_report_descriptor(hid_state_t * hidp,int interface)2091993e3fafSRobert Mustacchi hid_handle_report_descriptor(hid_state_t *hidp, int interface)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
20947c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
20957c478bd9Sstevel@tonic-gate 	mblk_t			*data = NULL;
20967c478bd9Sstevel@tonic-gate 	hidparser_packet_info_t	hpack;
20977c478bd9Sstevel@tonic-gate 	int			i;
20987c478bd9Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
20997c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |	/* bmRequestType */
2100112116d8Sfb 	    USB_DEV_REQ_RCPT_IF,
21017c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,		/* bRequest */
21027c478bd9Sstevel@tonic-gate 	    USB_CLASS_DESCR_TYPE_REPORT, /* wValue */
21037c478bd9Sstevel@tonic-gate 	    0,				/* wIndex: interface, fill in later */
21047c478bd9Sstevel@tonic-gate 	    0,				/* wLength, fill in later  */
21057c478bd9Sstevel@tonic-gate 	    0				/* attributes */
2106112116d8Sfb 	    };
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	/*
21097c478bd9Sstevel@tonic-gate 	 * Parsing hid desciptor was successful earlier.
21107c478bd9Sstevel@tonic-gate 	 * Get Report Descriptor
21117c478bd9Sstevel@tonic-gate 	 */
21127c478bd9Sstevel@tonic-gate 	setup.wIndex = (uint16_t)interface;
21137c478bd9Sstevel@tonic-gate 	setup.wLength = hidp->hid_hid_descr.wReportDescriptorLength;
21147c478bd9Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(hidp->hid_default_pipe,
21157c478bd9Sstevel@tonic-gate 	    &setup,
21167c478bd9Sstevel@tonic-gate 	    &data,				/* data */
21177c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
21187c478bd9Sstevel@tonic-gate 
2119d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
2120112116d8Sfb 		    "Failed to receive the Report Descriptor");
21217c478bd9Sstevel@tonic-gate 		freemsg(data);
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	} else {
21267c478bd9Sstevel@tonic-gate 		int n =  hidp->hid_hid_descr.wReportDescriptorLength;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 		ASSERT(data);
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 		/* Print the report descriptor */
21317c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
21327c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
2133112116d8Sfb 			    "Index = %d\tvalue =0x%x", i,
2134112116d8Sfb 			    (int)(data->b_rptr[i]));
21357c478bd9Sstevel@tonic-gate 		}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 		/* Get Report Descriptor was successful */
21387c478bd9Sstevel@tonic-gate 		if (hidparser_parse_report_descriptor(
21397c478bd9Sstevel@tonic-gate 		    data->b_rptr,
21407c478bd9Sstevel@tonic-gate 		    hidp->hid_hid_descr.wReportDescriptorLength,
21417c478bd9Sstevel@tonic-gate 		    &hidp->hid_hid_descr,
21427c478bd9Sstevel@tonic-gate 		    &hidp->hid_report_descr) == HIDPARSER_SUCCESS) {
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 			/* find max intr-in xfer length */
21457c478bd9Sstevel@tonic-gate 			hidparser_find_max_packet_size_from_report_descriptor(
21467c478bd9Sstevel@tonic-gate 			    hidp->hid_report_descr, &hpack);
21477c478bd9Sstevel@tonic-gate 			/* round up to the nearest byte */
21487c478bd9Sstevel@tonic-gate 			hidp->hid_packet_size = (hpack.max_packet_size + 7) / 8;
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 			/* if report id is used, add more more byte for it */
21517c478bd9Sstevel@tonic-gate 			if (hpack.report_id != HID_REPORT_ID_UNDEFINED) {
21527c478bd9Sstevel@tonic-gate 				hidp->hid_packet_size++;
21537c478bd9Sstevel@tonic-gate 			}
21547c478bd9Sstevel@tonic-gate 		} else {
21557c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_ATTA, hidp->hid_log_handle,
21567c478bd9Sstevel@tonic-gate 			    "Invalid Report Descriptor");
21577c478bd9Sstevel@tonic-gate 			freemsg(data);
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
21607c478bd9Sstevel@tonic-gate 		}
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 		freemsg(data);
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate /*
21707c478bd9Sstevel@tonic-gate  * hid_set_idle:
21717c478bd9Sstevel@tonic-gate  *	Make a clas specific request to SET_IDLE.
21727c478bd9Sstevel@tonic-gate  *	In this case send no reports if state has not changed.
21737c478bd9Sstevel@tonic-gate  *	See HID 7.2.4.
21747c478bd9Sstevel@tonic-gate  */
21757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21767c478bd9Sstevel@tonic-gate static void
hid_set_idle(hid_state_t * hidp)2177993e3fafSRobert Mustacchi hid_set_idle(hid_state_t *hidp)
21787c478bd9Sstevel@tonic-gate {
21797c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
21807c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
21817c478bd9Sstevel@tonic-gate 	usb_ctrl_setup_t setup = {
21827c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_HOST_TO_DEV |	/* bmRequestType */
2183112116d8Sfb 	    USB_DEV_REQ_TYPE_CLASS |
2184112116d8Sfb 	    USB_DEV_REQ_RCPT_IF,
21857c478bd9Sstevel@tonic-gate 	    SET_IDLE,			/* bRequest */
21867c478bd9Sstevel@tonic-gate 	    DURATION,			/* wValue */
21877c478bd9Sstevel@tonic-gate 	    0,				/* wIndex: interface, fill in later */
21887c478bd9Sstevel@tonic-gate 	    0,				/* wLength */
21897c478bd9Sstevel@tonic-gate 	    0				/* attributes */
2190112116d8Sfb 	    };
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
21937c478bd9Sstevel@tonic-gate 	    "hid_set_idle: Begin");
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
21967c478bd9Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(
21977c478bd9Sstevel@tonic-gate 	    hidp->hid_default_pipe,
21987c478bd9Sstevel@tonic-gate 	    &setup,
21997c478bd9Sstevel@tonic-gate 	    NULL,			/* no data to send. */
22007c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
22037c478bd9Sstevel@tonic-gate 		    "Failed while trying to set idle,"
22047c478bd9Sstevel@tonic-gate 		    "cr = %d, cb_flags = 0x%x\n",
22057c478bd9Sstevel@tonic-gate 		    completion_reason, cb_flags);
22067c478bd9Sstevel@tonic-gate 	}
22077c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2208112116d8Sfb 	    "hid_set_idle: End");
22097c478bd9Sstevel@tonic-gate }
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate /*
22137c478bd9Sstevel@tonic-gate  * hid_set_protocol:
22147c478bd9Sstevel@tonic-gate  *	Initialize the device to set the preferred protocol
22157c478bd9Sstevel@tonic-gate  */
22167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22177c478bd9Sstevel@tonic-gate static void
hid_set_protocol(hid_state_t * hidp,int protocol)22187c478bd9Sstevel@tonic-gate hid_set_protocol(hid_state_t *hidp, int protocol)
22197c478bd9Sstevel@tonic-gate {
22207c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
22217c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
22227c478bd9Sstevel@tonic-gate 	usb_ctrl_setup_t setup;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
22257c478bd9Sstevel@tonic-gate 	    "hid_set_protocol(%d): Begin", protocol);
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	/* initialize the setup request */
22287c478bd9Sstevel@tonic-gate 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
22297c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
22307c478bd9Sstevel@tonic-gate 	setup.bRequest = SET_PROTOCOL;
2231d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	setup.wValue = (uint16_t)protocol;
22327c478bd9Sstevel@tonic-gate 	setup.wIndex = hidp->hid_if_descr.bInterfaceNumber;
22337c478bd9Sstevel@tonic-gate 	setup.wLength = 0;
22347c478bd9Sstevel@tonic-gate 	setup.attrs = 0;
22357c478bd9Sstevel@tonic-gate 	if (usb_pipe_ctrl_xfer_wait(
22367c478bd9Sstevel@tonic-gate 	    hidp->hid_default_pipe,	/* bmRequestType */
22377c478bd9Sstevel@tonic-gate 	    &setup,
22387c478bd9Sstevel@tonic-gate 	    NULL,			/* no data to send */
22397c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
22407c478bd9Sstevel@tonic-gate 		/*
22417c478bd9Sstevel@tonic-gate 		 * Some devices fail to follow the specification
22427c478bd9Sstevel@tonic-gate 		 * and instead of STALLing, they continously
22437c478bd9Sstevel@tonic-gate 		 * NAK the SET_IDLE command. We need to reset
22447c478bd9Sstevel@tonic-gate 		 * the pipe then, so that ohci doesn't panic.
22457c478bd9Sstevel@tonic-gate 		 */
22467c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hidp->hid_log_handle,
22477c478bd9Sstevel@tonic-gate 		    "Failed while trying to set protocol:%d,"
22487c478bd9Sstevel@tonic-gate 		    "cr =  %d cb_flags = 0x%x\n",
22497c478bd9Sstevel@tonic-gate 		    completion_reason, cb_flags, protocol);
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
2253112116d8Sfb 	    "hid_set_protocol: End");
22547c478bd9Sstevel@tonic-gate }
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate /*
22587c478bd9Sstevel@tonic-gate  * hid_detach_cleanup:
22597c478bd9Sstevel@tonic-gate  *	called by attach and detach for cleanup.
22607c478bd9Sstevel@tonic-gate  */
22617c478bd9Sstevel@tonic-gate static void
hid_detach_cleanup(dev_info_t * dip,hid_state_t * hidp)22627c478bd9Sstevel@tonic-gate hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp)
22637c478bd9Sstevel@tonic-gate {
22647c478bd9Sstevel@tonic-gate 	int	flags = hidp->hid_attach_flags;
22657c478bd9Sstevel@tonic-gate 	int	rval;
22667c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
22697c478bd9Sstevel@tonic-gate 	    "hid_detach_cleanup: Begin");
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	if ((hidp->hid_attach_flags & HID_LOCK_INIT) == 0) {
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 		goto done;
22747c478bd9Sstevel@tonic-gate 	}
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 	/*
22777c478bd9Sstevel@tonic-gate 	 * Disable the event callbacks first, after this point, event
22787c478bd9Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
22797c478bd9Sstevel@tonic-gate 	 * mutex while unregistering events because there may be a
22807c478bd9Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
22817c478bd9Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
22827c478bd9Sstevel@tonic-gate 	 */
22837c478bd9Sstevel@tonic-gate 	usb_unregister_event_cbs(dip, &hid_events);
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	hidpm = hidp->hid_pm;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
2290112116d8Sfb 	    "hid_detach_cleanup: hidpm=0x%p", (void *)hidpm);
22917c478bd9Sstevel@tonic-gate 
22927c478bd9Sstevel@tonic-gate 	if (hidpm && (hidp->hid_dev_state != USB_DEV_DISCONNECTED)) {
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
22957c478bd9Sstevel@tonic-gate 		hid_pm_busy_component(hidp);
22967c478bd9Sstevel@tonic-gate 		if (hid_is_pm_enabled(dip) == USB_SUCCESS) {
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 			if (hidpm->hid_wakeup_enabled) {
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 				/* First bring the device to full power */
23017c478bd9Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
23027c478bd9Sstevel@tonic-gate 				    USB_DEV_OS_FULL_PWR);
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 				/* Disable remote wakeup */
23057c478bd9Sstevel@tonic-gate 				rval = usb_handle_remote_wakeup(dip,
23067c478bd9Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE);
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate 				if (rval != DDI_SUCCESS) {
23097c478bd9Sstevel@tonic-gate 					USB_DPRINTF_L2(PRINT_MASK_ALL,
23107c478bd9Sstevel@tonic-gate 					    hidp->hid_log_handle,
23117c478bd9Sstevel@tonic-gate 					    "hid_detach_cleanup: "
23127c478bd9Sstevel@tonic-gate 					    "disble remote wakeup failed, "
23137c478bd9Sstevel@tonic-gate 					    "rval= %d", rval);
23147c478bd9Sstevel@tonic-gate 				}
23157c478bd9Sstevel@tonic-gate 			}
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
23187c478bd9Sstevel@tonic-gate 		}
23197c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
23207c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
23217c478bd9Sstevel@tonic-gate 	}
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	if (hidpm) {
23247c478bd9Sstevel@tonic-gate 		freemsg(hidpm->hid_pm_pwrup);
23257c478bd9Sstevel@tonic-gate 		kmem_free(hidpm, sizeof (hid_power_t));
23267c478bd9Sstevel@tonic-gate 		hidp->hid_pm = NULL;
23277c478bd9Sstevel@tonic-gate 	}
23287c478bd9Sstevel@tonic-gate 
2329*cfe80fe3SAlex Wilson 	if (hidp->hid_ugen_hdl != NULL) {
2330*cfe80fe3SAlex Wilson 		rval = usb_ugen_detach(hidp->hid_ugen_hdl, DDI_DETACH);
2331*cfe80fe3SAlex Wilson 		VERIFY0(rval);
2332*cfe80fe3SAlex Wilson 		usb_ugen_release_hdl(hidp->hid_ugen_hdl);
2333*cfe80fe3SAlex Wilson 	}
2334*cfe80fe3SAlex Wilson 
23357c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	if (hidp->hid_report_descr != NULL) {
23387c478bd9Sstevel@tonic-gate 		(void) hidparser_free_report_descriptor_handle(
2339112116d8Sfb 		    hidp->hid_report_descr);
23407c478bd9Sstevel@tonic-gate 	}
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	if (flags & HID_MINOR_NODES) {
23437c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	mutex_destroy(&hidp->hid_mutex);
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
23497c478bd9Sstevel@tonic-gate 	    "hid_detach_cleanup: End");
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate done:
23527c478bd9Sstevel@tonic-gate 	usb_client_detach(dip, hidp->hid_dev_data);
23537c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(hidp->hid_log_handle);
23547c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(hid_statep, hidp->hid_instance);
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
23577c478bd9Sstevel@tonic-gate }
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate /*
23617c478bd9Sstevel@tonic-gate  * hid_start_intr_polling:
23627c478bd9Sstevel@tonic-gate  *	Allocate an interrupt request structure, initialize,
23637c478bd9Sstevel@tonic-gate  *	and start interrupt transfers.
23647c478bd9Sstevel@tonic-gate  */
23657c478bd9Sstevel@tonic-gate static int
hid_start_intr_polling(hid_state_t * hidp)23667c478bd9Sstevel@tonic-gate hid_start_intr_polling(hid_state_t *hidp)
23677c478bd9Sstevel@tonic-gate {
23687c478bd9Sstevel@tonic-gate 	usb_intr_req_t	*req;
23697c478bd9Sstevel@tonic-gate 	int rval = USB_SUCCESS;
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
23727c478bd9Sstevel@tonic-gate 	    "hid_start_intr_polling: "
2373ddee57faSrui zang - Sun Microsystems - Beijing China 	    "dev_state=%s internal_str_flag=%d external_str_flag=%d ph=0x%p",
2374ddee57faSrui zang - Sun Microsystems - Beijing China 	    usb_str_dev_state(hidp->hid_dev_state), hidp->hid_internal_flag,
2375ddee57faSrui zang - Sun Microsystems - Beijing China 	    hidp->hid_external_flag, (void *)hidp->hid_interrupt_pipe);
23767c478bd9Sstevel@tonic-gate 
2377ddee57faSrui zang - Sun Microsystems - Beijing China 	if (HID_IS_OPEN(hidp) && (hidp->hid_interrupt_pipe != NULL)) {
23787c478bd9Sstevel@tonic-gate 		/*
23797c478bd9Sstevel@tonic-gate 		 * initialize interrupt pipe request structure
23807c478bd9Sstevel@tonic-gate 		 */
23817c478bd9Sstevel@tonic-gate 		req = usb_alloc_intr_req(hidp->hid_dip, 0, USB_FLAGS_SLEEP);
23827c478bd9Sstevel@tonic-gate 		req->intr_client_private = (usb_opaque_t)hidp;
23837c478bd9Sstevel@tonic-gate 		req->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
2384112116d8Sfb 		    USB_ATTRS_AUTOCLEARING;
23857c478bd9Sstevel@tonic-gate 		req->intr_len = hidp->hid_packet_size;
23867c478bd9Sstevel@tonic-gate 		req->intr_cb = hid_interrupt_pipe_callback;
23877c478bd9Sstevel@tonic-gate 		req->intr_exc_cb = hid_interrupt_pipe_exception_callback;
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 		/*
23907c478bd9Sstevel@tonic-gate 		 * Start polling on the interrupt pipe.
23917c478bd9Sstevel@tonic-gate 		 */
23927c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 		if ((rval = usb_pipe_intr_xfer(hidp->hid_interrupt_pipe, req,
23957c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP)) != USB_SUCCESS) {
23967c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_PM, hidp->hid_log_handle,
23977c478bd9Sstevel@tonic-gate 			    "hid_start_intr_polling failed: rval = %d",
23987c478bd9Sstevel@tonic-gate 			    rval);
23997c478bd9Sstevel@tonic-gate 			usb_free_intr_req(req);
24007c478bd9Sstevel@tonic-gate 		}
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
24037c478bd9Sstevel@tonic-gate 	}
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
24067c478bd9Sstevel@tonic-gate 	    "hid_start_intr_polling: done, rval = %d", rval);
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	return (rval);
24097c478bd9Sstevel@tonic-gate }
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate /*
24137c478bd9Sstevel@tonic-gate  * hid_close_intr_pipe:
24147c478bd9Sstevel@tonic-gate  *	close the interrupt pipe after draining all callbacks
24157c478bd9Sstevel@tonic-gate  */
24167c478bd9Sstevel@tonic-gate static void
hid_close_intr_pipe(hid_state_t * hidp)24177c478bd9Sstevel@tonic-gate hid_close_intr_pipe(hid_state_t *hidp)
24187c478bd9Sstevel@tonic-gate {
24197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
24207c478bd9Sstevel@tonic-gate 	    "hid_close_intr_pipe: Begin");
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 	if (hidp->hid_interrupt_pipe) {
24237c478bd9Sstevel@tonic-gate 		/*
24247c478bd9Sstevel@tonic-gate 		 * Close the interrupt pipe
24257c478bd9Sstevel@tonic-gate 		 */
24267c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
24277c478bd9Sstevel@tonic-gate 		usb_pipe_close(hidp->hid_dip, hidp->hid_interrupt_pipe,
24287c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP, NULL, NULL);
24297c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
24307c478bd9Sstevel@tonic-gate 		hidp->hid_interrupt_pipe = NULL;
24317c478bd9Sstevel@tonic-gate 	}
24327c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hidp->hid_log_handle,
24337c478bd9Sstevel@tonic-gate 	    "hid_close_intr_pipe: End");
24347c478bd9Sstevel@tonic-gate }
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate /*
24387c478bd9Sstevel@tonic-gate  * hid_mctl_receive:
24397c478bd9Sstevel@tonic-gate  *	Handle M_CTL messages from upper stream.  If
24407c478bd9Sstevel@tonic-gate  *	we don't understand the command, free message.
24417c478bd9Sstevel@tonic-gate  */
24427c478bd9Sstevel@tonic-gate static int
hid_mctl_receive(register queue_t * q,register mblk_t * mp)24437c478bd9Sstevel@tonic-gate hid_mctl_receive(register queue_t *q, register mblk_t *mp)
24447c478bd9Sstevel@tonic-gate {
2445ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
24467c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
24477c478bd9Sstevel@tonic-gate 	int		error = HID_FAILURE;
24487c478bd9Sstevel@tonic-gate 	uchar_t		request_type;
24497c478bd9Sstevel@tonic-gate 	hid_req_t	*hid_req_data = NULL;
24507c478bd9Sstevel@tonic-gate 	hid_polled_input_callback_t hid_polled_input;
24516d9a41ffSqz 	hid_vid_pid_t	hid_vid_pid;
24527c478bd9Sstevel@tonic-gate 
24537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
24547c478bd9Sstevel@tonic-gate 	    "hid_mctl_receive");
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
24597c478bd9Sstevel@tonic-gate 	case HID_SET_REPORT:
24607c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
24617c478bd9Sstevel@tonic-gate 	case HID_SET_IDLE:
24627c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
24637c478bd9Sstevel@tonic-gate 	case HID_SET_PROTOCOL:
24647c478bd9Sstevel@tonic-gate 		request_type = USB_DEV_REQ_HOST_TO_DEV |
24657c478bd9Sstevel@tonic-gate 		    USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 		break;
24687c478bd9Sstevel@tonic-gate 	case HID_GET_REPORT:
24697c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
24707c478bd9Sstevel@tonic-gate 	case HID_GET_IDLE:
24717c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
24727c478bd9Sstevel@tonic-gate 	case HID_GET_PROTOCOL:
24737c478bd9Sstevel@tonic-gate 		request_type = USB_DEV_REQ_DEV_TO_HOST |
24747c478bd9Sstevel@tonic-gate 		    USB_DEV_REQ_RCPT_IF | USB_DEV_REQ_TYPE_CLASS;
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 		break;
24777c478bd9Sstevel@tonic-gate 	case HID_GET_PARSER_HANDLE:
24787c478bd9Sstevel@tonic-gate 		if (canputnext(RD(q))) {
24797c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
24807c478bd9Sstevel@tonic-gate 			mp->b_cont = hid_data2mblk(
24817c478bd9Sstevel@tonic-gate 			    (uchar_t *)&hidp->hid_report_descr,
24827c478bd9Sstevel@tonic-gate 			    sizeof (hidp->hid_report_descr));
24837c478bd9Sstevel@tonic-gate 			if (mp->b_cont == NULL) {
24847c478bd9Sstevel@tonic-gate 				/*
24857c478bd9Sstevel@tonic-gate 				 * can't allocate mblk, indicate
24867c478bd9Sstevel@tonic-gate 				 * that nothing is returned
24877c478bd9Sstevel@tonic-gate 				 */
24887c478bd9Sstevel@tonic-gate 				iocp->ioc_count = 0;
24897c478bd9Sstevel@tonic-gate 			} else {
24907c478bd9Sstevel@tonic-gate 				iocp->ioc_count =
24917c478bd9Sstevel@tonic-gate 				    sizeof (hidp->hid_report_descr);
24927c478bd9Sstevel@tonic-gate 			}
24937c478bd9Sstevel@tonic-gate 			qreply(q, mp);
24947c478bd9Sstevel@tonic-gate 
24956d9a41ffSqz 			return (HID_SUCCESS);
24966d9a41ffSqz 		} else {
24976d9a41ffSqz 
24986d9a41ffSqz 			/* retry */
24996d9a41ffSqz 			return (HID_ENQUEUE);
25006d9a41ffSqz 		}
25016d9a41ffSqz 	case HID_GET_VID_PID:
25026d9a41ffSqz 		if (canputnext(RD(q))) {
25036d9a41ffSqz 			freemsg(mp->b_cont);
25046d9a41ffSqz 
25056d9a41ffSqz 			hid_vid_pid.VendorId =
2506112116d8Sfb 			    hidp->hid_dev_descr->idVendor;
25076d9a41ffSqz 			hid_vid_pid.ProductId =
2508112116d8Sfb 			    hidp->hid_dev_descr->idProduct;
25096d9a41ffSqz 
25106d9a41ffSqz 			mp->b_cont = hid_data2mblk(
25116d9a41ffSqz 			    (uchar_t *)&hid_vid_pid, sizeof (hid_vid_pid_t));
25126d9a41ffSqz 			if (mp->b_cont == NULL) {
25136d9a41ffSqz 				/*
25146d9a41ffSqz 				 * can't allocate mblk, indicate that nothing
25156d9a41ffSqz 				 * is being returned.
25166d9a41ffSqz 				 */
25176d9a41ffSqz 				iocp->ioc_count = 0;
25186d9a41ffSqz 			} else {
25196d9a41ffSqz 				iocp->ioc_count =
25206d9a41ffSqz 				    sizeof (hid_vid_pid_t);
25216d9a41ffSqz 			}
25226d9a41ffSqz 			qreply(q, mp);
25236d9a41ffSqz 
25247c478bd9Sstevel@tonic-gate 			return (HID_SUCCESS);
25257c478bd9Sstevel@tonic-gate 		} else {
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 			/* retry */
25287c478bd9Sstevel@tonic-gate 			return (HID_ENQUEUE);
25297c478bd9Sstevel@tonic-gate 		}
25307c478bd9Sstevel@tonic-gate 	case HID_OPEN_POLLED_INPUT:
25317c478bd9Sstevel@tonic-gate 		if (canputnext(RD(q))) {
25327c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 			/* Initialize the structure */
25357c478bd9Sstevel@tonic-gate 			hid_polled_input.hid_polled_version =
2536112116d8Sfb 			    HID_POLLED_INPUT_V0;
25377c478bd9Sstevel@tonic-gate 			hid_polled_input.hid_polled_read = hid_polled_read;
25387c478bd9Sstevel@tonic-gate 			hid_polled_input.hid_polled_input_enter =
2539112116d8Sfb 			    hid_polled_input_enter;
25407c478bd9Sstevel@tonic-gate 			hid_polled_input.hid_polled_input_exit =
2541112116d8Sfb 			    hid_polled_input_exit;
25427c478bd9Sstevel@tonic-gate 			hid_polled_input.hid_polled_input_handle =
2543112116d8Sfb 			    (hid_polled_handle_t)hidp;
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 			mp->b_cont = hid_data2mblk(
25467c478bd9Sstevel@tonic-gate 			    (uchar_t *)&hid_polled_input,
25477c478bd9Sstevel@tonic-gate 			    sizeof (hid_polled_input_callback_t));
25487c478bd9Sstevel@tonic-gate 			if (mp->b_cont == NULL) {
25497c478bd9Sstevel@tonic-gate 				/*
25507c478bd9Sstevel@tonic-gate 				 * can't allocate mblk, indicate that nothing
25517c478bd9Sstevel@tonic-gate 				 * is being returned.
25527c478bd9Sstevel@tonic-gate 				 */
25537c478bd9Sstevel@tonic-gate 				iocp->ioc_count = 0;
25547c478bd9Sstevel@tonic-gate 			} else {
25557c478bd9Sstevel@tonic-gate 				/* Call down into USBA */
25567c478bd9Sstevel@tonic-gate 				(void) hid_polled_input_init(hidp);
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 				iocp->ioc_count =
25597c478bd9Sstevel@tonic-gate 				    sizeof (hid_polled_input_callback_t);
25607c478bd9Sstevel@tonic-gate 			}
25617c478bd9Sstevel@tonic-gate 			qreply(q, mp);
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 			return (HID_SUCCESS);
25647c478bd9Sstevel@tonic-gate 		} else {
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 			/* retry */
25677c478bd9Sstevel@tonic-gate 			return (HID_ENQUEUE);
25687c478bd9Sstevel@tonic-gate 		}
25697c478bd9Sstevel@tonic-gate 	case HID_CLOSE_POLLED_INPUT:
25707c478bd9Sstevel@tonic-gate 		/* Call down into USBA */
25717c478bd9Sstevel@tonic-gate 		(void) hid_polled_input_fini(hidp);
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;
25747c478bd9Sstevel@tonic-gate 		qreply(q, mp);
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 		return (HID_SUCCESS);
25777c478bd9Sstevel@tonic-gate 	default:
25787c478bd9Sstevel@tonic-gate 		hid_qreply_merror(q, mp, EINVAL);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 		return (HID_FAILURE);
25817c478bd9Sstevel@tonic-gate 	}
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 	/*
25847c478bd9Sstevel@tonic-gate 	 * These (device executable) commands require a hid_req_t.
25857c478bd9Sstevel@tonic-gate 	 * Make sure one is present
25867c478bd9Sstevel@tonic-gate 	 */
25877c478bd9Sstevel@tonic-gate 	if (mp->b_cont == NULL) {
25887c478bd9Sstevel@tonic-gate 		hid_qreply_merror(q, mp, EINVAL);
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 		return (error);
25917c478bd9Sstevel@tonic-gate 	} else {
25927c478bd9Sstevel@tonic-gate 		hid_req_data = (hid_req_t *)mp->b_cont->b_rptr;
25937c478bd9Sstevel@tonic-gate 		if ((iocp->ioc_cmd == HID_SET_REPORT) &&
259459c81845Sgc 		    (hid_req_data->hid_req_wLength == 0)) {
25957c478bd9Sstevel@tonic-gate 			hid_qreply_merror(q, mp, EINVAL);
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 			return (error);
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 	}
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	/*
26027c478bd9Sstevel@tonic-gate 	 * Check is version no. is correct. This
26037c478bd9Sstevel@tonic-gate 	 * is coming from the user
26047c478bd9Sstevel@tonic-gate 	 */
26057c478bd9Sstevel@tonic-gate 	if (hid_req_data->hid_req_version_no != HID_VERSION_V_0) {
26067c478bd9Sstevel@tonic-gate 		hid_qreply_merror(q, mp, EINVAL);
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 		return (error);
26097c478bd9Sstevel@tonic-gate 	}
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
26127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
26137c478bd9Sstevel@tonic-gate 	    "hid_mctl_receive: dev_state=%s",
26147c478bd9Sstevel@tonic-gate 	    usb_str_dev_state(hidp->hid_dev_state));
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	switch (hidp->hid_dev_state) {
26177c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
26187c478bd9Sstevel@tonic-gate 		/*
26197c478bd9Sstevel@tonic-gate 		 * get the device full powered. We get a callback
26207c478bd9Sstevel@tonic-gate 		 * which enables the WQ and kicks off IO
26217c478bd9Sstevel@tonic-gate 		 */
26227c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_HID_POWER_CHANGE;
26237c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
26247c478bd9Sstevel@tonic-gate 		if (usb_req_raise_power(hidp->hid_dip, 0,
26257c478bd9Sstevel@tonic-gate 		    USB_DEV_OS_FULL_PWR, hid_power_change_callback,
26267c478bd9Sstevel@tonic-gate 		    hidp, 0) != USB_SUCCESS) {
26277c478bd9Sstevel@tonic-gate 			/* we retry raising power in wsrv */
26287c478bd9Sstevel@tonic-gate 			mutex_enter(&hidp->hid_mutex);
26297c478bd9Sstevel@tonic-gate 			hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
26307c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
26317c478bd9Sstevel@tonic-gate 		}
26327c478bd9Sstevel@tonic-gate 		error = HID_ENQUEUE;
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 		break;
26357c478bd9Sstevel@tonic-gate 	case USB_DEV_HID_POWER_CHANGE:
26367c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
26377c478bd9Sstevel@tonic-gate 		error = HID_ENQUEUE;
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 		break;
26407c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
2641ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_STREAMS_FLAG(q, hidp) != HID_STREAMS_DISMANTLING) {
26427c478bd9Sstevel@tonic-gate 			/* Send a message down */
26437c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
2644ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			error = hid_mctl_execute_cmd(q, request_type,
26457c478bd9Sstevel@tonic-gate 			    hid_req_data, mp);
26467c478bd9Sstevel@tonic-gate 			if (error == HID_FAILURE) {
26477c478bd9Sstevel@tonic-gate 				hid_qreply_merror(q, mp, EIO);
26487c478bd9Sstevel@tonic-gate 			}
26497c478bd9Sstevel@tonic-gate 		} else {
26507c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
26517c478bd9Sstevel@tonic-gate 			hid_qreply_merror(q, mp, EIO);
26527c478bd9Sstevel@tonic-gate 		}
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 		break;
26557c478bd9Sstevel@tonic-gate 	default:
26567c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
26577c478bd9Sstevel@tonic-gate 		hid_qreply_merror(q, mp, EIO);
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 		break;
26607c478bd9Sstevel@tonic-gate 	}
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	return (error);
26637c478bd9Sstevel@tonic-gate }
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate /*
26677c478bd9Sstevel@tonic-gate  * hid_mctl_execute_cmd:
26687c478bd9Sstevel@tonic-gate  *	Send the command to the device.
26697c478bd9Sstevel@tonic-gate  */
26707c478bd9Sstevel@tonic-gate static int
hid_mctl_execute_cmd(queue_t * q,int request_type,hid_req_t * hid_req_data,mblk_t * mp)2671ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hid_mctl_execute_cmd(queue_t *q, int request_type, hid_req_t *hid_req_data,
2672ac9468f8Spengcheng chen - Sun Microsystems - Beijing China     mblk_t *mp)
26737c478bd9Sstevel@tonic-gate {
26747c478bd9Sstevel@tonic-gate 	int		request_index;
26757c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
26767c478bd9Sstevel@tonic-gate 	hid_default_pipe_arg_t	*def_pipe_arg;
2677ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
26807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
2681112116d8Sfb 	    "hid_mctl_execute_cmd: iocp=0x%p", (void *)iocp);
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate 	request_index = hidp->hid_if_descr.bInterfaceNumber;
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	/*
26867c478bd9Sstevel@tonic-gate 	 * Set up the argument to be passed back to hid
26877c478bd9Sstevel@tonic-gate 	 * when the asynchronous control callback is
26887c478bd9Sstevel@tonic-gate 	 * executed.
26897c478bd9Sstevel@tonic-gate 	 */
26907c478bd9Sstevel@tonic-gate 	def_pipe_arg = kmem_zalloc(sizeof (hid_default_pipe_arg_t), 0);
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 	if (def_pipe_arg == NULL) {
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 		return (HID_FAILURE);
26957c478bd9Sstevel@tonic-gate 	}
26967c478bd9Sstevel@tonic-gate 
2697ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	def_pipe_arg->hid_default_pipe_arg_queue = q;
26987c478bd9Sstevel@tonic-gate 	def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_cmd = iocp->ioc_cmd;
26997c478bd9Sstevel@tonic-gate 	def_pipe_arg->hid_default_pipe_arg_mctlmsg.ioc_count = 0;
27007c478bd9Sstevel@tonic-gate 	def_pipe_arg->hid_default_pipe_arg_mblk = mp;
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	/*
27037c478bd9Sstevel@tonic-gate 	 * Send the command down to USBA through default
27047c478bd9Sstevel@tonic-gate 	 * pipe.
27057c478bd9Sstevel@tonic-gate 	 */
2706ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	if (hid_send_async_ctrl_request(def_pipe_arg, hid_req_data,
2707ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	    request_type, iocp->ioc_cmd, request_index) != USB_SUCCESS) {
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 		kmem_free(def_pipe_arg, sizeof (hid_default_pipe_arg_t));
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate 		return (HID_FAILURE);
27127c478bd9Sstevel@tonic-gate 	}
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 	return (HID_INPROGRESS);
27157c478bd9Sstevel@tonic-gate }
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate /*
27197c478bd9Sstevel@tonic-gate  * hid_send_async_ctrl_request:
27207c478bd9Sstevel@tonic-gate  *	Send an asynchronous control request to USBA.  Since hid is a STREAMS
27217c478bd9Sstevel@tonic-gate  *	driver, it is not allowed to wait in its entry points except for the
27227c478bd9Sstevel@tonic-gate  *	open and close entry points.  Therefore, hid must use the asynchronous
27237c478bd9Sstevel@tonic-gate  *	USBA calls.
27247c478bd9Sstevel@tonic-gate  */
27257c478bd9Sstevel@tonic-gate static int
hid_send_async_ctrl_request(hid_default_pipe_arg_t * hid_default_pipe_arg,hid_req_t * hid_request,uchar_t request_type,int request_request,ushort_t request_index)2726ac9468f8Spengcheng chen - Sun Microsystems - Beijing China hid_send_async_ctrl_request(hid_default_pipe_arg_t *hid_default_pipe_arg,
2727993e3fafSRobert Mustacchi     hid_req_t *hid_request, uchar_t request_type, int request_request,
2728993e3fafSRobert Mustacchi     ushort_t request_index)
27297c478bd9Sstevel@tonic-gate {
2730ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	queue_t		*q = hid_default_pipe_arg->hid_default_pipe_arg_queue;
2731ddee57faSrui zang - Sun Microsystems - Beijing China 	hid_state_t	*hidp = (hid_state_t *)q->q_ptr;
27327c478bd9Sstevel@tonic-gate 	usb_ctrl_req_t	*ctrl_req;
27337c478bd9Sstevel@tonic-gate 	int		rval;
27347c478bd9Sstevel@tonic-gate 	size_t		length = 0;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
27377c478bd9Sstevel@tonic-gate 	    "hid_send_async_ctrl_request: "
27387c478bd9Sstevel@tonic-gate 	    "rq_type=%d rq_rq=%d index=%d",
27397c478bd9Sstevel@tonic-gate 	    request_type, request_request, request_index);
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
27427c478bd9Sstevel@tonic-gate 	hidp->hid_default_pipe_req++;
27437c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 	/*
27467c478bd9Sstevel@tonic-gate 	 * Note that ctrl_req->ctrl_data should be allocated by usba
27477c478bd9Sstevel@tonic-gate 	 * only for IN requests. OUT request(e.g SET_REPORT) can have a
27487c478bd9Sstevel@tonic-gate 	 * non-zero wLength value but ctrl_data would be allocated by
27497c478bd9Sstevel@tonic-gate 	 * client for them.
27507c478bd9Sstevel@tonic-gate 	 */
275159c81845Sgc 	if (hid_request->hid_req_wLength >= MAX_REPORT_DATA) {
275259c81845Sgc 		USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
275359c81845Sgc 		    "hid_req_wLength is exceeded");
275459c81845Sgc 		return (USB_FAILURE);
275559c81845Sgc 	}
275659c81845Sgc 	if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_DEV_TO_HOST) {
275759c81845Sgc 		length = hid_request->hid_req_wLength;
27587c478bd9Sstevel@tonic-gate 	}
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate 	if ((ctrl_req = usb_alloc_ctrl_req(hidp->hid_dip, length, 0)) == NULL) {
27617c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
27627c478bd9Sstevel@tonic-gate 		    "unable to alloc ctrl req. async trans failed");
27637c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
27647c478bd9Sstevel@tonic-gate 		hidp->hid_default_pipe_req--;
27657c478bd9Sstevel@tonic-gate 		ASSERT(hidp->hid_default_pipe_req >= 0);
27667c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
27697c478bd9Sstevel@tonic-gate 	}
27707c478bd9Sstevel@tonic-gate 
277159c81845Sgc 	if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
27727c478bd9Sstevel@tonic-gate 		ASSERT((length == 0) && (ctrl_req->ctrl_data == NULL));
27737c478bd9Sstevel@tonic-gate 	}
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_bmRequestType	= request_type;
2776db1c88f6SSebastian Wiedenroth 	ctrl_req->ctrl_bRequest		= (uint8_t)request_request;
27777c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_wValue		= hid_request->hid_req_wValue;
27787c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_wIndex		= request_index;
27797c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_wLength		= hid_request->hid_req_wLength;
278059c81845Sgc 	/* host to device: create a msg from hid_req_data */
278159c81845Sgc 	if ((request_type & USB_DEV_REQ_DIR_MASK) == USB_DEV_REQ_HOST_TO_DEV) {
278259c81845Sgc 		mblk_t *pblk = allocb(hid_request->hid_req_wLength, BPRI_HI);
278359c81845Sgc 		if (pblk == NULL) {
278459c81845Sgc 			usb_free_ctrl_req(ctrl_req);
278559c81845Sgc 			return (USB_FAILURE);
278659c81845Sgc 		}
278759c81845Sgc 		bcopy(hid_request->hid_req_data, pblk->b_wptr,
2788112116d8Sfb 		    hid_request->hid_req_wLength);
278959c81845Sgc 		pblk->b_wptr += hid_request->hid_req_wLength;
279059c81845Sgc 		ctrl_req->ctrl_data = pblk;
279159c81845Sgc 	}
27927c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_attributes	= USB_ATTRS_AUTOCLEARING;
27937c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_client_private	= (usb_opaque_t)hid_default_pipe_arg;
27947c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_cb		= hid_default_pipe_callback;
27957c478bd9Sstevel@tonic-gate 	ctrl_req->ctrl_exc_cb		= hid_default_pipe_exception_callback;
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate 	if ((rval = usb_pipe_ctrl_xfer(hidp->hid_default_pipe,
27987c478bd9Sstevel@tonic-gate 	    ctrl_req, 0)) != USB_SUCCESS) {
27997c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
28007c478bd9Sstevel@tonic-gate 		hidp->hid_default_pipe_req--;
28017c478bd9Sstevel@tonic-gate 		ASSERT(hidp->hid_default_pipe_req >= 0);
28027c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 		usb_free_ctrl_req(ctrl_req);
28057c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, hidp->hid_log_handle,
28067c478bd9Sstevel@tonic-gate 		    "usb_pipe_ctrl_xfer() failed. rval = %d", rval);
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
28097c478bd9Sstevel@tonic-gate 	}
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
28127c478bd9Sstevel@tonic-gate }
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate /*
28157c478bd9Sstevel@tonic-gate  * hid_create_pm_components:
28167c478bd9Sstevel@tonic-gate  *	Create the pm components required for power management.
28177c478bd9Sstevel@tonic-gate  *	For keyboard/mouse, the components is created only if the device
28187c478bd9Sstevel@tonic-gate  *	supports a remote wakeup.
28197c478bd9Sstevel@tonic-gate  *	For other hid devices they are created unconditionally.
28207c478bd9Sstevel@tonic-gate  */
28217c478bd9Sstevel@tonic-gate static void
hid_create_pm_components(dev_info_t * dip,hid_state_t * hidp)28227c478bd9Sstevel@tonic-gate hid_create_pm_components(dev_info_t *dip, hid_state_t *hidp)
28237c478bd9Sstevel@tonic-gate {
28247c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
28257c478bd9Sstevel@tonic-gate 	uint_t		pwr_states;
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
28287c478bd9Sstevel@tonic-gate 	    "hid_create_pm_components: Begin");
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	/* Allocate the state structure */
28317c478bd9Sstevel@tonic-gate 	hidpm = kmem_zalloc(sizeof (hid_power_t), KM_SLEEP);
28327c478bd9Sstevel@tonic-gate 	hidp->hid_pm = hidpm;
28337c478bd9Sstevel@tonic-gate 	hidpm->hid_state = hidp;
28347c478bd9Sstevel@tonic-gate 	hidpm->hid_raise_power = B_FALSE;
28357c478bd9Sstevel@tonic-gate 	hidpm->hid_pm_capabilities = 0;
28367c478bd9Sstevel@tonic-gate 	hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 	switch (hidp->hid_if_descr.bInterfaceProtocol) {
28397c478bd9Sstevel@tonic-gate 	case KEYBOARD_PROTOCOL:
28407c478bd9Sstevel@tonic-gate 	case MOUSE_PROTOCOL:
28417c478bd9Sstevel@tonic-gate 		hidpm->hid_pm_strategy = HID_PM_ACTIVITY;
28427c478bd9Sstevel@tonic-gate 		if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
28437c478bd9Sstevel@tonic-gate 		    (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
28447c478bd9Sstevel@tonic-gate 		    USB_SUCCESS)) {
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_PM, hidp->hid_log_handle,
28477c478bd9Sstevel@tonic-gate 			    "hid_create_pm_components: Remote Wakeup Enabled");
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 			if (usb_create_pm_components(dip, &pwr_states) ==
28507c478bd9Sstevel@tonic-gate 			    USB_SUCCESS) {
28517c478bd9Sstevel@tonic-gate 				hidpm->hid_wakeup_enabled = 1;
28527c478bd9Sstevel@tonic-gate 				hidpm->hid_pwr_states = (uint8_t)pwr_states;
28537c478bd9Sstevel@tonic-gate 			}
28547c478bd9Sstevel@tonic-gate 		}
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 		break;
28577c478bd9Sstevel@tonic-gate 	default:
28587c478bd9Sstevel@tonic-gate 		hidpm->hid_pm_strategy = HID_PM_OPEN_CLOSE;
28597c478bd9Sstevel@tonic-gate 		if ((hid_is_pm_enabled(dip) == USB_SUCCESS) &&
28607c478bd9Sstevel@tonic-gate 		    (usb_create_pm_components(dip, &pwr_states) ==
28617c478bd9Sstevel@tonic-gate 		    USB_SUCCESS)) {
28627c478bd9Sstevel@tonic-gate 			hidpm->hid_wakeup_enabled = 0;
28637c478bd9Sstevel@tonic-gate 			hidpm->hid_pwr_states = (uint8_t)pwr_states;
28647c478bd9Sstevel@tonic-gate 		}
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 		break;
28677c478bd9Sstevel@tonic-gate 	}
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, hidp->hid_log_handle,
2870112116d8Sfb 	    "hid_create_pm_components: END");
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate /*
28757c478bd9Sstevel@tonic-gate  * hid_is_pm_enabled
28767c478bd9Sstevel@tonic-gate  *	Check if the device is pm enabled. Always enable
28777c478bd9Sstevel@tonic-gate  *	pm on the new SUN mouse
28787c478bd9Sstevel@tonic-gate  */
28797c478bd9Sstevel@tonic-gate static int
hid_is_pm_enabled(dev_info_t * dip)28807c478bd9Sstevel@tonic-gate hid_is_pm_enabled(dev_info_t *dip)
28817c478bd9Sstevel@tonic-gate {
28827c478bd9Sstevel@tonic-gate 	hid_state_t	*hidp = ddi_get_soft_state(hid_statep,
2883112116d8Sfb 	    ddi_get_instance(dip));
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(dip), "mouse") == 0) {
28864610e4a0Sfrits 		/* check for overrides first */
28874610e4a0Sfrits 		if (hid_pm_mouse ||
28884610e4a0Sfrits 		    (ddi_prop_exists(DDI_DEV_T_ANY, dip,
28894610e4a0Sfrits 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28904610e4a0Sfrits 		    "hid-mouse-pm-enable") == 1)) {
28914610e4a0Sfrits 
28924610e4a0Sfrits 			return (USB_SUCCESS);
28934610e4a0Sfrits 		}
28944610e4a0Sfrits 
28957c478bd9Sstevel@tonic-gate 		/*
28964610e4a0Sfrits 		 * Always enable PM for 1.05 or greater SUN mouse
28977c478bd9Sstevel@tonic-gate 		 * hidp->hid_dev_descr won't be NULL.
28987c478bd9Sstevel@tonic-gate 		 */
28994610e4a0Sfrits 		if ((hidp->hid_dev_descr->idVendor ==
29007c478bd9Sstevel@tonic-gate 		    HID_SUN_MOUSE_VENDOR_ID) &&
29017c478bd9Sstevel@tonic-gate 		    (hidp->hid_dev_descr->idProduct ==
29027c478bd9Sstevel@tonic-gate 		    HID_SUN_MOUSE_PROD_ID) &&
29037c478bd9Sstevel@tonic-gate 		    (hidp->hid_dev_descr->bcdDevice >=
29044610e4a0Sfrits 		    HID_SUN_MOUSE_BCDDEVICE)) {
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate 			return (USB_SUCCESS);
29077c478bd9Sstevel@tonic-gate 		}
29087c478bd9Sstevel@tonic-gate 	} else {
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
29117c478bd9Sstevel@tonic-gate 	}
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
29147c478bd9Sstevel@tonic-gate }
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 
29177c478bd9Sstevel@tonic-gate /*
29187c478bd9Sstevel@tonic-gate  * hid_save_device_state
29197c478bd9Sstevel@tonic-gate  *	Save the current device/driver state.
29207c478bd9Sstevel@tonic-gate  */
29217c478bd9Sstevel@tonic-gate static void
hid_save_device_state(hid_state_t * hidp)29227c478bd9Sstevel@tonic-gate hid_save_device_state(hid_state_t *hidp)
29237c478bd9Sstevel@tonic-gate {
29247c478bd9Sstevel@tonic-gate 	struct iocblk	*mctlmsg;
29257c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
29267c478bd9Sstevel@tonic-gate 	queue_t		*q;
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, hidp->hid_log_handle,
29297c478bd9Sstevel@tonic-gate 	    "hid_save_device_state");
29307c478bd9Sstevel@tonic-gate 
2931ddee57faSrui zang - Sun Microsystems - Beijing China 	if (!(HID_IS_OPEN(hidp)))
2932ddee57faSrui zang - Sun Microsystems - Beijing China 		return;
2933ddee57faSrui zang - Sun Microsystems - Beijing China 
2934ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
29357c478bd9Sstevel@tonic-gate 		/*
2936ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 * Send MCTLs up indicating that the device
2937ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		 * will loose its state
29387c478bd9Sstevel@tonic-gate 		 */
2939ddee57faSrui zang - Sun Microsystems - Beijing China 		q = hidp->hid_internal_rq;
2940ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
2941ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
2942ddee57faSrui zang - Sun Microsystems - Beijing China 		if (canputnext(q)) {
2943ddee57faSrui zang - Sun Microsystems - Beijing China 			mp = allocb(sizeof (struct iocblk), BPRI_HI);
2944ddee57faSrui zang - Sun Microsystems - Beijing China 			if (mp != NULL) {
2945ddee57faSrui zang - Sun Microsystems - Beijing China 				mp->b_datap->db_type = M_CTL;
2946ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg = (struct iocblk *)
2947ddee57faSrui zang - Sun Microsystems - Beijing China 				    mp->b_datap->db_base;
2948ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2949ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg->ioc_count = 0;
2950ddee57faSrui zang - Sun Microsystems - Beijing China 				putnext(q, mp);
29517c478bd9Sstevel@tonic-gate 			}
29527c478bd9Sstevel@tonic-gate 		}
2953ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_enter(&hidp->hid_mutex);
2954ddee57faSrui zang - Sun Microsystems - Beijing China 	}
2955ddee57faSrui zang - Sun Microsystems - Beijing China 
2956ddee57faSrui zang - Sun Microsystems - Beijing China 	if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
2957ddee57faSrui zang - Sun Microsystems - Beijing China 		/*
2958ddee57faSrui zang - Sun Microsystems - Beijing China 		 * Send MCTLs up indicating that the device
2959ddee57faSrui zang - Sun Microsystems - Beijing China 		 * will loose its state
2960ddee57faSrui zang - Sun Microsystems - Beijing China 		 */
2961ddee57faSrui zang - Sun Microsystems - Beijing China 		q = hidp->hid_external_rq;
2962ddee57faSrui zang - Sun Microsystems - Beijing China 
2963ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
2964ddee57faSrui zang - Sun Microsystems - Beijing China 		if (canputnext(q)) {
2965ddee57faSrui zang - Sun Microsystems - Beijing China 			mp = allocb(sizeof (struct iocblk), BPRI_HI);
2966ddee57faSrui zang - Sun Microsystems - Beijing China 			if (mp != NULL) {
2967ddee57faSrui zang - Sun Microsystems - Beijing China 				mp->b_datap->db_type = M_CTL;
2968ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg = (struct iocblk *)
2969ddee57faSrui zang - Sun Microsystems - Beijing China 				    mp->b_datap->db_base;
2970ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg->ioc_cmd = HID_DISCONNECT_EVENT;
2971ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg->ioc_count = 0;
2972ddee57faSrui zang - Sun Microsystems - Beijing China 				putnext(q, mp);
2973ddee57faSrui zang - Sun Microsystems - Beijing China 			}
2974ddee57faSrui zang - Sun Microsystems - Beijing China 		}
29757c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
29767c478bd9Sstevel@tonic-gate 	}
2977ddee57faSrui zang - Sun Microsystems - Beijing China 
2978ddee57faSrui zang - Sun Microsystems - Beijing China 	mutex_exit(&hidp->hid_mutex);
2979ddee57faSrui zang - Sun Microsystems - Beijing China 	/* stop polling on the intr pipe */
2980ddee57faSrui zang - Sun Microsystems - Beijing China 	usb_pipe_stop_intr_polling(hidp->hid_interrupt_pipe, USB_FLAGS_SLEEP);
2981ddee57faSrui zang - Sun Microsystems - Beijing China 	mutex_enter(&hidp->hid_mutex);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate /*
29867c478bd9Sstevel@tonic-gate  * hid_restore_device_state:
29877c478bd9Sstevel@tonic-gate  *	Set original configuration of the device.
29887c478bd9Sstevel@tonic-gate  *	Reopen intr pipe.
29897c478bd9Sstevel@tonic-gate  *	Enable wrq - this starts new transactions on the control pipe.
29907c478bd9Sstevel@tonic-gate  */
29917c478bd9Sstevel@tonic-gate static void
hid_restore_device_state(dev_info_t * dip,hid_state_t * hidp)29927c478bd9Sstevel@tonic-gate hid_restore_device_state(dev_info_t *dip, hid_state_t *hidp)
29937c478bd9Sstevel@tonic-gate {
29947c478bd9Sstevel@tonic-gate 	int		rval;
29957c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
29967c478bd9Sstevel@tonic-gate 	struct iocblk	*mctlmsg;
29977c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
2998ddee57faSrui zang - Sun Microsystems - Beijing China 	queue_t		*q;
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	hid_pm_busy_component(hidp);
30017c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
30027c478bd9Sstevel@tonic-gate 
30037c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hidp->hid_log_handle,
30047c478bd9Sstevel@tonic-gate 	    "hid_restore_device_state: %s",
30057c478bd9Sstevel@tonic-gate 	    usb_str_dev_state(hidp->hid_dev_state));
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	hidpm = hidp->hid_pm;
30087c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	/* First bring the device to full power */
30117c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
30147c478bd9Sstevel@tonic-gate 	if (hidp->hid_dev_state == USB_DEV_ONLINE) {
30157c478bd9Sstevel@tonic-gate 		/*
30167c478bd9Sstevel@tonic-gate 		 * We failed the checkpoint, there is no need to restore
30177c478bd9Sstevel@tonic-gate 		 * the device state
30187c478bd9Sstevel@tonic-gate 		 */
30197c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
30207c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate 		return;
30237c478bd9Sstevel@tonic-gate 	}
30247c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	/* Check if we are talking to the same device */
30287c478bd9Sstevel@tonic-gate 	if (usb_check_same_device(dip, hidp->hid_log_handle, USB_LOG_L2,
30297c478bd9Sstevel@tonic-gate 	    PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 		/* change the device state from suspended to disconnected */
30327c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
30337c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_DISCONNECTED;
30347c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
30357c478bd9Sstevel@tonic-gate 		hid_pm_idle_component(hidp);
3036ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 		goto nodev;
30377c478bd9Sstevel@tonic-gate 	}
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	hid_set_idle(hidp);
30407c478bd9Sstevel@tonic-gate 	hid_set_protocol(hidp, SET_REPORT_PROTOCOL);
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate 	mutex_enter(&hidp->hid_mutex);
30437c478bd9Sstevel@tonic-gate 	/* if the device had remote wakeup earlier, enable it again */
30447c478bd9Sstevel@tonic-gate 	if (hidpm->hid_wakeup_enabled) {
30457c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
30467c478bd9Sstevel@tonic-gate 
30477c478bd9Sstevel@tonic-gate 		if ((rval = usb_handle_remote_wakeup(hidp->hid_dip,
30487c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
30497c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
30507c478bd9Sstevel@tonic-gate 			    hidp->hid_log_handle,
30517c478bd9Sstevel@tonic-gate 			    "usb_handle_remote_wakeup failed (%d)", rval);
30527c478bd9Sstevel@tonic-gate 		}
30537c478bd9Sstevel@tonic-gate 
30547c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
30557c478bd9Sstevel@tonic-gate 	}
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate 	/*
30587c478bd9Sstevel@tonic-gate 	 * restart polling on the interrupt pipe only if the device
30597c478bd9Sstevel@tonic-gate 	 * was previously operational (open)
30607c478bd9Sstevel@tonic-gate 	 */
3061ddee57faSrui zang - Sun Microsystems - Beijing China 	if (HID_IS_OPEN(hidp)) {
30627c478bd9Sstevel@tonic-gate 		if ((rval = hid_start_intr_polling(hidp)) != USB_SUCCESS) {
30637c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA, hidp->hid_log_handle,
30647c478bd9Sstevel@tonic-gate 			    "hid_restore_device_state:"
30657c478bd9Sstevel@tonic-gate 			    "unable to restart intr pipe poll"
30667c478bd9Sstevel@tonic-gate 			    " rval = %d ", rval);
30677c478bd9Sstevel@tonic-gate 			/*
30687c478bd9Sstevel@tonic-gate 			 * change the device state from
30697c478bd9Sstevel@tonic-gate 			 * suspended to disconnected
30707c478bd9Sstevel@tonic-gate 			 */
30717c478bd9Sstevel@tonic-gate 			hidp->hid_dev_state = USB_DEV_DISCONNECTED;
30727c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
30737c478bd9Sstevel@tonic-gate 			hid_pm_idle_component(hidp);
3074ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			goto nodev;
30757c478bd9Sstevel@tonic-gate 		}
30767c478bd9Sstevel@tonic-gate 
30777c478bd9Sstevel@tonic-gate 		if (hidp->hid_dev_state == USB_DEV_DISCONNECTED) {
30787c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
30797c478bd9Sstevel@tonic-gate 			    "device is being re-connected");
30807c478bd9Sstevel@tonic-gate 		}
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 		/* set the device state ONLINE */
30837c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_ONLINE;
30847c478bd9Sstevel@tonic-gate 
30857c478bd9Sstevel@tonic-gate 		/* inform upstream modules that the device is back */
3086ddee57faSrui zang - Sun Microsystems - Beijing China 		if (hidp->hid_internal_flag == HID_STREAMS_OPEN) {
3087ddee57faSrui zang - Sun Microsystems - Beijing China 			q = hidp->hid_internal_rq;
3088ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
3089ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
3090ddee57faSrui zang - Sun Microsystems - Beijing China 			if (canputnext(q)) {
3091ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 				mp = allocb(sizeof (struct iocblk), BPRI_HI);
3092ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 				if (mp != NULL) {
3093ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 					mp->b_datap->db_type = M_CTL;
3094ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 					mctlmsg = (struct iocblk *)
3095ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 					    mp->b_datap->db_base;
3096ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 					mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
3097ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 					mctlmsg->ioc_count = 0;
3098ddee57faSrui zang - Sun Microsystems - Beijing China 					putnext(q, mp);
3099ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 				}
31007c478bd9Sstevel@tonic-gate 			}
3101ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			/* enable write side q */
3102ddee57faSrui zang - Sun Microsystems - Beijing China 			qenable(WR(q));
3103ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
3104ddee57faSrui zang - Sun Microsystems - Beijing China 		}
3105ddee57faSrui zang - Sun Microsystems - Beijing China 
3106ddee57faSrui zang - Sun Microsystems - Beijing China 		if (hidp->hid_external_flag == HID_STREAMS_OPEN) {
3107ddee57faSrui zang - Sun Microsystems - Beijing China 			q = hidp->hid_external_rq;
3108ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
3109ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_exit(&hidp->hid_mutex);
3110ddee57faSrui zang - Sun Microsystems - Beijing China 			if (canputnext(q)) {
3111ddee57faSrui zang - Sun Microsystems - Beijing China 				mp = allocb(sizeof (struct iocblk), BPRI_HI);
3112ddee57faSrui zang - Sun Microsystems - Beijing China 				if (mp != NULL) {
3113ddee57faSrui zang - Sun Microsystems - Beijing China 					mp->b_datap->db_type = M_CTL;
3114ddee57faSrui zang - Sun Microsystems - Beijing China 					mctlmsg = (struct iocblk *)
3115ddee57faSrui zang - Sun Microsystems - Beijing China 					    mp->b_datap->db_base;
3116ddee57faSrui zang - Sun Microsystems - Beijing China 					mctlmsg->ioc_cmd = HID_CONNECT_EVENT;
3117ddee57faSrui zang - Sun Microsystems - Beijing China 					mctlmsg->ioc_count = 0;
3118ddee57faSrui zang - Sun Microsystems - Beijing China 					putnext(q, mp);
3119ddee57faSrui zang - Sun Microsystems - Beijing China 				}
3120ddee57faSrui zang - Sun Microsystems - Beijing China 			}
3121ddee57faSrui zang - Sun Microsystems - Beijing China 			/* enable write side q */
3122ddee57faSrui zang - Sun Microsystems - Beijing China 			qenable(WR(q));
3123ddee57faSrui zang - Sun Microsystems - Beijing China 			mutex_enter(&hidp->hid_mutex);
31247c478bd9Sstevel@tonic-gate 		}
31257c478bd9Sstevel@tonic-gate 	} else {
31267c478bd9Sstevel@tonic-gate 		/* set the device state ONLINE */
31277c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_ONLINE;
31287c478bd9Sstevel@tonic-gate 	}
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate 	mutex_exit(&hidp->hid_mutex);
31317c478bd9Sstevel@tonic-gate 	hid_pm_idle_component(hidp);
3132ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	return;
3133ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 
3134ac9468f8Spengcheng chen - Sun Microsystems - Beijing China nodev:
3135ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	/*
3136ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * Notify applications about device removal. This only
3137ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * applies to an external (aka. physical) open. Not sure how to
3138ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 * notify consconfig to close the internal minor node.
3139ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	 */
3140ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_enter(&hidp->hid_mutex);
3141ddee57faSrui zang - Sun Microsystems - Beijing China 
3142ddee57faSrui zang - Sun Microsystems - Beijing China 	if ((q = hidp->hid_external_rq) == NULL) {
3143ddee57faSrui zang - Sun Microsystems - Beijing China 		mutex_exit(&hidp->hid_mutex);
3144ddee57faSrui zang - Sun Microsystems - Beijing China 		return;
3145ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	}
3146ddee57faSrui zang - Sun Microsystems - Beijing China 
3147ac9468f8Spengcheng chen - Sun Microsystems - Beijing China 	mutex_exit(&hidp->hid_mutex);
3148ddee57faSrui zang - Sun Microsystems - Beijing China 	mp = allocb(sizeof (uchar_t), BPRI_HI);
3149ddee57faSrui zang - Sun Microsystems - Beijing China 	if (mp != NULL) {
3150ddee57faSrui zang - Sun Microsystems - Beijing China 		mp->b_datap->db_type = M_ERROR;
3151ddee57faSrui zang - Sun Microsystems - Beijing China 		mp->b_rptr = mp->b_datap->db_base;
3152ddee57faSrui zang - Sun Microsystems - Beijing China 		mp->b_wptr = mp->b_rptr + sizeof (char);
3153ddee57faSrui zang - Sun Microsystems - Beijing China 		*mp->b_rptr = ENODEV;
3154ddee57faSrui zang - Sun Microsystems - Beijing China 		putnext(q, mp);
3155ddee57faSrui zang - Sun Microsystems - Beijing China 	}
31567c478bd9Sstevel@tonic-gate }
31577c478bd9Sstevel@tonic-gate 
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate /*
31607c478bd9Sstevel@tonic-gate  * hid_qreply_merror:
31617c478bd9Sstevel@tonic-gate  *	Pass an error message up.
31627c478bd9Sstevel@tonic-gate  */
31637c478bd9Sstevel@tonic-gate static void
hid_qreply_merror(queue_t * q,mblk_t * mp,uchar_t errval)31647c478bd9Sstevel@tonic-gate hid_qreply_merror(queue_t *q, mblk_t *mp, uchar_t errval)
31657c478bd9Sstevel@tonic-gate {
31667c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_ERROR;
31677c478bd9Sstevel@tonic-gate 	if (mp->b_cont) {
31687c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
31697c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
31707c478bd9Sstevel@tonic-gate 	}
31717c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_datap->db_base;
31727c478bd9Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + sizeof (char);
31737c478bd9Sstevel@tonic-gate 	*mp->b_rptr = errval;
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate 	qreply(q, mp);
31767c478bd9Sstevel@tonic-gate }
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 
31797c478bd9Sstevel@tonic-gate /*
31807c478bd9Sstevel@tonic-gate  * hid_data2mblk:
31817c478bd9Sstevel@tonic-gate  *	Form an mblk from the given data
31827c478bd9Sstevel@tonic-gate  */
31837c478bd9Sstevel@tonic-gate static mblk_t *
hid_data2mblk(uchar_t * buf,int len)31847c478bd9Sstevel@tonic-gate hid_data2mblk(uchar_t *buf, int len)
31857c478bd9Sstevel@tonic-gate {
31867c478bd9Sstevel@tonic-gate 	mblk_t	*mp = NULL;
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 	if (len >= 0) {
31897c478bd9Sstevel@tonic-gate 		mp = allocb(len, BPRI_HI);
31907c478bd9Sstevel@tonic-gate 		if (mp) {
31917c478bd9Sstevel@tonic-gate 			bcopy(buf, mp->b_datap->db_base, len);
31927c478bd9Sstevel@tonic-gate 			mp->b_wptr += len;
31937c478bd9Sstevel@tonic-gate 		}
31947c478bd9Sstevel@tonic-gate 	}
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 	return (mp);
31977c478bd9Sstevel@tonic-gate }
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate /*
32017c478bd9Sstevel@tonic-gate  * hid_flush :
32027c478bd9Sstevel@tonic-gate  *	Flush data already sent upstreams to client module.
32037c478bd9Sstevel@tonic-gate  */
32047c478bd9Sstevel@tonic-gate static void
hid_flush(queue_t * q)32057c478bd9Sstevel@tonic-gate hid_flush(queue_t *q)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate 	/*
32087c478bd9Sstevel@tonic-gate 	 * Flush pending data already sent upstream
32097c478bd9Sstevel@tonic-gate 	 */
32107c478bd9Sstevel@tonic-gate 	if ((q != NULL) && (q->q_next != NULL)) {
32117c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
32127c478bd9Sstevel@tonic-gate 	}
32137c478bd9Sstevel@tonic-gate }
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate static void
hid_pm_busy_component(hid_state_t * hid_statep)32177c478bd9Sstevel@tonic-gate hid_pm_busy_component(hid_state_t *hid_statep)
32187c478bd9Sstevel@tonic-gate {
32197c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&hid_statep->hid_mutex));
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 	if (hid_statep->hid_pm != NULL) {
32227c478bd9Sstevel@tonic-gate 		mutex_enter(&hid_statep->hid_mutex);
32237c478bd9Sstevel@tonic-gate 		hid_statep->hid_pm->hid_pm_busy++;
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM, hid_statep->hid_log_handle,
32267c478bd9Sstevel@tonic-gate 		    "hid_pm_busy_component: %d",
32277c478bd9Sstevel@tonic-gate 		    hid_statep->hid_pm->hid_pm_busy);
32287c478bd9Sstevel@tonic-gate 
32297c478bd9Sstevel@tonic-gate 		mutex_exit(&hid_statep->hid_mutex);
32307c478bd9Sstevel@tonic-gate 		if (pm_busy_component(hid_statep->hid_dip, 0) != DDI_SUCCESS) {
32317c478bd9Sstevel@tonic-gate 			mutex_enter(&hid_statep->hid_mutex);
32327c478bd9Sstevel@tonic-gate 			hid_statep->hid_pm->hid_pm_busy--;
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_PM,
32357c478bd9Sstevel@tonic-gate 			    hid_statep->hid_log_handle,
32367c478bd9Sstevel@tonic-gate 			    "hid_pm_busy_component failed: %d",
32377c478bd9Sstevel@tonic-gate 			    hid_statep->hid_pm->hid_pm_busy);
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate 			mutex_exit(&hid_statep->hid_mutex);
32407c478bd9Sstevel@tonic-gate 		}
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	}
32437c478bd9Sstevel@tonic-gate }
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate static void
hid_pm_idle_component(hid_state_t * hid_statep)32477c478bd9Sstevel@tonic-gate hid_pm_idle_component(hid_state_t *hid_statep)
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&hid_statep->hid_mutex));
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	if (hid_statep->hid_pm != NULL) {
32527c478bd9Sstevel@tonic-gate 		if (pm_idle_component(hid_statep->hid_dip, 0) == DDI_SUCCESS) {
32537c478bd9Sstevel@tonic-gate 			mutex_enter(&hid_statep->hid_mutex);
32547c478bd9Sstevel@tonic-gate 			ASSERT(hid_statep->hid_pm->hid_pm_busy > 0);
32557c478bd9Sstevel@tonic-gate 			hid_statep->hid_pm->hid_pm_busy--;
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_PM,
32587c478bd9Sstevel@tonic-gate 			    hid_statep->hid_log_handle,
32597c478bd9Sstevel@tonic-gate 			    "hid_pm_idle_component: %d",
32607c478bd9Sstevel@tonic-gate 			    hid_statep->hid_pm->hid_pm_busy);
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 			mutex_exit(&hid_statep->hid_mutex);
32637c478bd9Sstevel@tonic-gate 		}
32647c478bd9Sstevel@tonic-gate 	}
32657c478bd9Sstevel@tonic-gate }
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate 
32687c478bd9Sstevel@tonic-gate /*
32697c478bd9Sstevel@tonic-gate  * hid_pwrlvl0:
32707c478bd9Sstevel@tonic-gate  *	Functions to handle power transition for various levels
32717c478bd9Sstevel@tonic-gate  *	These functions act as place holders to issue USB commands
32727c478bd9Sstevel@tonic-gate  *	to the devices to change their power levels
32737c478bd9Sstevel@tonic-gate  */
32747c478bd9Sstevel@tonic-gate static int
hid_pwrlvl0(hid_state_t * hidp)32757c478bd9Sstevel@tonic-gate hid_pwrlvl0(hid_state_t *hidp)
32767c478bd9Sstevel@tonic-gate {
32777c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
32787c478bd9Sstevel@tonic-gate 	int		rval;
32797c478bd9Sstevel@tonic-gate 	struct iocblk	*mctlmsg;
32807c478bd9Sstevel@tonic-gate 	mblk_t		*mp_lowpwr, *mp_fullpwr;
32817c478bd9Sstevel@tonic-gate 	queue_t		*q;
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 	hidpm = hidp->hid_pm;
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate 	switch (hidp->hid_dev_state) {
32867c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
32877c478bd9Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
32887c478bd9Sstevel@tonic-gate 		if (hidpm->hid_pm_busy != 0) {
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
32917c478bd9Sstevel@tonic-gate 		}
32927c478bd9Sstevel@tonic-gate 
3293ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_OPEN(hidp)) {
3294ddee57faSrui zang - Sun Microsystems - Beijing China 			q = hidp->hid_inuse_rq;
32957c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
32967c478bd9Sstevel@tonic-gate 			if (canputnext(q)) {
32977c478bd9Sstevel@tonic-gate 				/* try to preallocate mblks */
32987c478bd9Sstevel@tonic-gate 				mp_lowpwr = allocb(
32997c478bd9Sstevel@tonic-gate 				    (int)sizeof (struct iocblk), BPRI_HI);
33007c478bd9Sstevel@tonic-gate 				mp_fullpwr = allocb(
33017c478bd9Sstevel@tonic-gate 				    (int)sizeof (struct iocblk), BPRI_HI);
33027c478bd9Sstevel@tonic-gate 				if ((mp_lowpwr != NULL) &&
33037c478bd9Sstevel@tonic-gate 				    (mp_fullpwr != NULL)) {
33047c478bd9Sstevel@tonic-gate 					/* stop polling */
33057c478bd9Sstevel@tonic-gate 					usb_pipe_stop_intr_polling(
33067c478bd9Sstevel@tonic-gate 					    hidp->hid_interrupt_pipe,
33077c478bd9Sstevel@tonic-gate 					    USB_FLAGS_SLEEP);
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate 					/*
33107c478bd9Sstevel@tonic-gate 					 * Send an MCTL up indicating that
33117c478bd9Sstevel@tonic-gate 					 * we are powering off
33127c478bd9Sstevel@tonic-gate 					 */
33137c478bd9Sstevel@tonic-gate 					mp_lowpwr->b_datap->db_type = M_CTL;
33147c478bd9Sstevel@tonic-gate 					mctlmsg = (struct iocblk *)
33157c478bd9Sstevel@tonic-gate 					    mp_lowpwr->b_datap->db_base;
33167c478bd9Sstevel@tonic-gate 					mctlmsg->ioc_cmd = HID_POWER_OFF;
33177c478bd9Sstevel@tonic-gate 					mctlmsg->ioc_count = 0;
33187c478bd9Sstevel@tonic-gate 					putnext(q, mp_lowpwr);
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 					/* save the full powr mblk */
33217c478bd9Sstevel@tonic-gate 					mutex_enter(&hidp->hid_mutex);
33227c478bd9Sstevel@tonic-gate 					hidpm->hid_pm_pwrup = mp_fullpwr;
33237c478bd9Sstevel@tonic-gate 				} else {
33247c478bd9Sstevel@tonic-gate 					/*
33257c478bd9Sstevel@tonic-gate 					 * Since we failed to allocate one
33267c478bd9Sstevel@tonic-gate 					 * or more mblks, we fail attempt
33277c478bd9Sstevel@tonic-gate 					 * to go into low power this time
33287c478bd9Sstevel@tonic-gate 					 */
33297c478bd9Sstevel@tonic-gate 					freemsg(mp_lowpwr);
33307c478bd9Sstevel@tonic-gate 					freemsg(mp_fullpwr);
33317c478bd9Sstevel@tonic-gate 					mutex_enter(&hidp->hid_mutex);
33327c478bd9Sstevel@tonic-gate 
33337c478bd9Sstevel@tonic-gate 					return (USB_FAILURE);
33347c478bd9Sstevel@tonic-gate 				}
33357c478bd9Sstevel@tonic-gate 			} else {
33367c478bd9Sstevel@tonic-gate 				/*
33377c478bd9Sstevel@tonic-gate 				 * Since we can't send an mblk up,
33387c478bd9Sstevel@tonic-gate 				 * we fail this attempt to go to low power
33397c478bd9Sstevel@tonic-gate 				 */
33407c478bd9Sstevel@tonic-gate 				mutex_enter(&hidp->hid_mutex);
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
33437c478bd9Sstevel@tonic-gate 			}
33447c478bd9Sstevel@tonic-gate 		}
3345ddee57faSrui zang - Sun Microsystems - Beijing China 
33467c478bd9Sstevel@tonic-gate 		mutex_exit(&hidp->hid_mutex);
33477c478bd9Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
33487c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(hidp->hid_dip);
33497c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate 		mutex_enter(&hidp->hid_mutex);
33527c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_PWRED_DOWN;
33537c478bd9Sstevel@tonic-gate 		hidpm->hid_current_power = USB_DEV_OS_PWR_OFF;
33547c478bd9Sstevel@tonic-gate 
33557c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
33567c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
33577c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
33587c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
33597c478bd9Sstevel@tonic-gate 	default:
33607c478bd9Sstevel@tonic-gate 		break;
33617c478bd9Sstevel@tonic-gate 	}
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate /* ARGSUSED */
33687c478bd9Sstevel@tonic-gate static int
hid_pwrlvl1(hid_state_t * hidp)33697c478bd9Sstevel@tonic-gate hid_pwrlvl1(hid_state_t *hidp)
33707c478bd9Sstevel@tonic-gate {
33717c478bd9Sstevel@tonic-gate 	int		rval;
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
33747c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(hidp->hid_dip);
33757c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
33787c478bd9Sstevel@tonic-gate }
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate 
33817c478bd9Sstevel@tonic-gate /* ARGSUSED */
33827c478bd9Sstevel@tonic-gate static int
hid_pwrlvl2(hid_state_t * hidp)33837c478bd9Sstevel@tonic-gate hid_pwrlvl2(hid_state_t *hidp)
33847c478bd9Sstevel@tonic-gate {
33857c478bd9Sstevel@tonic-gate 	int		rval;
33867c478bd9Sstevel@tonic-gate 
33877c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(hidp->hid_dip);
33887c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
33917c478bd9Sstevel@tonic-gate }
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate static int
hid_pwrlvl3(hid_state_t * hidp)33957c478bd9Sstevel@tonic-gate hid_pwrlvl3(hid_state_t *hidp)
33967c478bd9Sstevel@tonic-gate {
33977c478bd9Sstevel@tonic-gate 	hid_power_t	*hidpm;
33987c478bd9Sstevel@tonic-gate 	int		rval;
33997c478bd9Sstevel@tonic-gate 	struct iocblk	*mctlmsg;
34007c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
34017c478bd9Sstevel@tonic-gate 	queue_t		*q;
34027c478bd9Sstevel@tonic-gate 
34037c478bd9Sstevel@tonic-gate 	hidpm = hidp->hid_pm;
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate 	switch (hidp->hid_dev_state) {
34067c478bd9Sstevel@tonic-gate 	case USB_DEV_HID_POWER_CHANGE:
34077c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
34087c478bd9Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
34097c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(hidp->hid_dip);
34107c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
34117c478bd9Sstevel@tonic-gate 
3412ddee57faSrui zang - Sun Microsystems - Beijing China 		if (HID_IS_OPEN(hidp)) {
34137c478bd9Sstevel@tonic-gate 			/* restart polling on intr pipe */
34147c478bd9Sstevel@tonic-gate 			rval = hid_start_intr_polling(hidp);
34157c478bd9Sstevel@tonic-gate 			if (rval != USB_SUCCESS) {
34167c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_EVENTS,
34177c478bd9Sstevel@tonic-gate 				    hidp->hid_log_handle,
34187c478bd9Sstevel@tonic-gate 				    "unable to restart intr polling rval = %d",
34197c478bd9Sstevel@tonic-gate 				    rval);
34207c478bd9Sstevel@tonic-gate 
34217c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
34227c478bd9Sstevel@tonic-gate 			}
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 			/* Send an MCTL up indicating device in full  power */
3425ddee57faSrui zang - Sun Microsystems - Beijing China 			q = hidp->hid_inuse_rq;
34267c478bd9Sstevel@tonic-gate 			mp = hidpm->hid_pm_pwrup;
34277c478bd9Sstevel@tonic-gate 			hidpm->hid_pm_pwrup = NULL;
34287c478bd9Sstevel@tonic-gate 			mutex_exit(&hidp->hid_mutex);
34297c478bd9Sstevel@tonic-gate 			if (canputnext(q)) {
34307c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_CTL;
3431ddee57faSrui zang - Sun Microsystems - Beijing China 				mctlmsg = (struct iocblk *)
3432ddee57faSrui zang - Sun Microsystems - Beijing China 				    mp->b_datap->db_base;
34337c478bd9Sstevel@tonic-gate 				mctlmsg->ioc_cmd = HID_FULL_POWER;
34347c478bd9Sstevel@tonic-gate 				mctlmsg->ioc_count = 0;
34357c478bd9Sstevel@tonic-gate 				putnext(q, mp);
34367c478bd9Sstevel@tonic-gate 			} else {
34377c478bd9Sstevel@tonic-gate 				freemsg(mp);
34387c478bd9Sstevel@tonic-gate 			}
34397c478bd9Sstevel@tonic-gate 			mutex_enter(&hidp->hid_mutex);
34407c478bd9Sstevel@tonic-gate 		}
3441ddee57faSrui zang - Sun Microsystems - Beijing China 
34427c478bd9Sstevel@tonic-gate 		hidp->hid_dev_state = USB_DEV_ONLINE;
34437c478bd9Sstevel@tonic-gate 		hidpm->hid_current_power = USB_DEV_OS_FULL_PWR;
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
34467c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
34477c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
34487c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
34517c478bd9Sstevel@tonic-gate 	default:
34527c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_EVENTS, hidp->hid_log_handle,
34537c478bd9Sstevel@tonic-gate 		    "hid_pwrlvl3: Improper State");
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
34567c478bd9Sstevel@tonic-gate 	}
34577c478bd9Sstevel@tonic-gate }
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 
34607c478bd9Sstevel@tonic-gate /*
34617c478bd9Sstevel@tonic-gate  * hid_polled_input_init :
34627c478bd9Sstevel@tonic-gate  *	This routine calls down to the lower layers to initialize any state
34637c478bd9Sstevel@tonic-gate  *	information.  This routine initializes the lower layers for input.
34647c478bd9Sstevel@tonic-gate  */
34657c478bd9Sstevel@tonic-gate static int
hid_polled_input_init(hid_state_t * hidp)34667c478bd9Sstevel@tonic-gate hid_polled_input_init(hid_state_t *hidp)
34677c478bd9Sstevel@tonic-gate {
34687c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
34697c478bd9Sstevel@tonic-gate 	    "hid_polled_input_init");
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate 	/*
34727c478bd9Sstevel@tonic-gate 	 * Call the lower layers to intialize any state information
34737c478bd9Sstevel@tonic-gate 	 * that they will need to provide the polled characters.
34747c478bd9Sstevel@tonic-gate 	 */
34757c478bd9Sstevel@tonic-gate 	if (usb_console_input_init(hidp->hid_dip, hidp->hid_interrupt_pipe,
34767c478bd9Sstevel@tonic-gate 	    &hidp->hid_polled_raw_buf,
34777c478bd9Sstevel@tonic-gate 	    &hidp->hid_polled_console_info) != USB_SUCCESS) {
34787c478bd9Sstevel@tonic-gate 		/*
34797c478bd9Sstevel@tonic-gate 		 * If for some reason the lower layers cannot initialized, then
34807c478bd9Sstevel@tonic-gate 		 * bail.
34817c478bd9Sstevel@tonic-gate 		 */
34827c478bd9Sstevel@tonic-gate 		(void) hid_polled_input_fini(hidp);
34837c478bd9Sstevel@tonic-gate 
34847c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
34857c478bd9Sstevel@tonic-gate 	}
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
34887c478bd9Sstevel@tonic-gate }
34897c478bd9Sstevel@tonic-gate 
34907c478bd9Sstevel@tonic-gate 
34917c478bd9Sstevel@tonic-gate /*
34927c478bd9Sstevel@tonic-gate  * hid_polled_input_fini:
34937c478bd9Sstevel@tonic-gate  *	This routine is called when we are done using this device as an input
34947c478bd9Sstevel@tonic-gate  *	device.
34957c478bd9Sstevel@tonic-gate  */
34967c478bd9Sstevel@tonic-gate static int
hid_polled_input_fini(hid_state_t * hidp)34977c478bd9Sstevel@tonic-gate hid_polled_input_fini(hid_state_t *hidp)
34987c478bd9Sstevel@tonic-gate {
34997c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, hidp->hid_log_handle,
35007c478bd9Sstevel@tonic-gate 	    "hid_polled_input_fini");
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	/*
35037c478bd9Sstevel@tonic-gate 	 * Call the lower layers to free any state information
35047c478bd9Sstevel@tonic-gate 	 * only if polled input has been initialised.
35057c478bd9Sstevel@tonic-gate 	 */
35067c478bd9Sstevel@tonic-gate 	if ((hidp->hid_polled_console_info) &&
35077c478bd9Sstevel@tonic-gate 	    (usb_console_input_fini(hidp->hid_polled_console_info) !=
35087c478bd9Sstevel@tonic-gate 	    USB_SUCCESS)) {
35097c478bd9Sstevel@tonic-gate 
35107c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
35117c478bd9Sstevel@tonic-gate 	}
35127c478bd9Sstevel@tonic-gate 	hidp->hid_polled_console_info = NULL;
35137c478bd9Sstevel@tonic-gate 
35147c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
35157c478bd9Sstevel@tonic-gate }
35167c478bd9Sstevel@tonic-gate 
35177c478bd9Sstevel@tonic-gate 
35187c478bd9Sstevel@tonic-gate /*
35197c478bd9Sstevel@tonic-gate  * hid_polled_input_enter:
35207c478bd9Sstevel@tonic-gate  *	This is the routine that is called in polled mode to save the USB
35217c478bd9Sstevel@tonic-gate  *	state information before using the USB keyboard as an input device.
35227c478bd9Sstevel@tonic-gate  *	This routine, and all of the routines that it calls, are responsible
35237c478bd9Sstevel@tonic-gate  *	for saving any state information so that it can be restored when
35247c478bd9Sstevel@tonic-gate  *	polling mode is over.
35257c478bd9Sstevel@tonic-gate  */
35267c478bd9Sstevel@tonic-gate static int
35277c478bd9Sstevel@tonic-gate /* ARGSUSED */
hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)35287c478bd9Sstevel@tonic-gate hid_polled_input_enter(hid_polled_handle_t hid_polled_inputp)
35297c478bd9Sstevel@tonic-gate {
35307c478bd9Sstevel@tonic-gate 	hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate 	/*
35337c478bd9Sstevel@tonic-gate 	 * Call the lower layers to tell them to save any state information.
35347c478bd9Sstevel@tonic-gate 	 */
35357c478bd9Sstevel@tonic-gate 	(void) usb_console_input_enter(hidp->hid_polled_console_info);
35367c478bd9Sstevel@tonic-gate 
35377c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
35387c478bd9Sstevel@tonic-gate }
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate /*
35427c478bd9Sstevel@tonic-gate  * hid_polled_read :
35437c478bd9Sstevel@tonic-gate  *	This is the routine that is called in polled mode when it wants to read
35447c478bd9Sstevel@tonic-gate  *	a character.  We will call to the lower layers to see if there is any
35457c478bd9Sstevel@tonic-gate  *	input data available.  If there is USB scancodes available, we will
35467c478bd9Sstevel@tonic-gate  *	give them back.
35477c478bd9Sstevel@tonic-gate  */
35487c478bd9Sstevel@tonic-gate static int
hid_polled_read(hid_polled_handle_t hid_polled_input,uchar_t ** buffer)35497c478bd9Sstevel@tonic-gate hid_polled_read(hid_polled_handle_t hid_polled_input, uchar_t **buffer)
35507c478bd9Sstevel@tonic-gate {
35517c478bd9Sstevel@tonic-gate 	hid_state_t *hidp = (hid_state_t *)hid_polled_input;
35527c478bd9Sstevel@tonic-gate 	uint_t			num_bytes;
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 	/*
35557c478bd9Sstevel@tonic-gate 	 * Call the lower layers to get the character from the controller.
35567c478bd9Sstevel@tonic-gate 	 * The lower layers will return the number of characters that
35577c478bd9Sstevel@tonic-gate 	 * were put in the raw buffer.	The address of the raw buffer
35587c478bd9Sstevel@tonic-gate 	 * was passed down to the lower layers during hid_polled_init.
35597c478bd9Sstevel@tonic-gate 	 */
35607c478bd9Sstevel@tonic-gate 	if (usb_console_read(hidp->hid_polled_console_info,
35617c478bd9Sstevel@tonic-gate 	    &num_bytes) != USB_SUCCESS) {
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 		return (0);
35647c478bd9Sstevel@tonic-gate 	}
35657c478bd9Sstevel@tonic-gate 
35667c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
35677c478bd9Sstevel@tonic-gate 
35687c478bd9Sstevel@tonic-gate 	*buffer = hidp->hid_polled_raw_buf;
35697c478bd9Sstevel@tonic-gate 
35707c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate 	/*
35737c478bd9Sstevel@tonic-gate 	 * Return the number of characters that were copied into the
35747c478bd9Sstevel@tonic-gate 	 * polled buffer.
35757c478bd9Sstevel@tonic-gate 	 */
35767c478bd9Sstevel@tonic-gate 	return (num_bytes);
35777c478bd9Sstevel@tonic-gate }
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate /*
35817c478bd9Sstevel@tonic-gate  * hid_polled_input_exit :
35827c478bd9Sstevel@tonic-gate  *	This is the routine that is called in polled mode  when it is giving up
35837c478bd9Sstevel@tonic-gate  *	control of the USB keyboard.  This routine, and the lower layer routines
35847c478bd9Sstevel@tonic-gate  *	that it calls, are responsible for restoring the controller state to the
35857c478bd9Sstevel@tonic-gate  *	state it was in before polled mode.
35867c478bd9Sstevel@tonic-gate  */
35877c478bd9Sstevel@tonic-gate static int
hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)35887c478bd9Sstevel@tonic-gate hid_polled_input_exit(hid_polled_handle_t hid_polled_inputp)
35897c478bd9Sstevel@tonic-gate {
35907c478bd9Sstevel@tonic-gate 	hid_state_t *hidp = (hid_state_t *)hid_polled_inputp;
35917c478bd9Sstevel@tonic-gate 
35927c478bd9Sstevel@tonic-gate 	/*
35937c478bd9Sstevel@tonic-gate 	 * Call the lower layers to restore any state information.
35947c478bd9Sstevel@tonic-gate 	 */
35957c478bd9Sstevel@tonic-gate 	(void) usb_console_input_exit(hidp->hid_polled_console_info);
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate 	return (0);
35987c478bd9Sstevel@tonic-gate }
3599