1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * usb multi interface and common class driver
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  *	this driver attempts to attach each interface to a driver
32*7c478bd9Sstevel@tonic-gate  *	and may eventually handle common class features such as
33*7c478bd9Sstevel@tonic-gate  *	shared endpoints
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
37*7c478bd9Sstevel@tonic-gate #define	DEBUG	1
38*7c478bd9Sstevel@tonic-gate #endif
39*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/usb/usb_mid/usb_midvar.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate void usba_free_evdata(usba_evdata_t *);
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /* Debugging support */
49*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_errlevel = USB_LOG_L4;
50*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL;
51*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_instance_debug = (uint_t)-1;
52*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_bus_config_debug = 0;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel))
55*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask))
56*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug))
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
59*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
60*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * Hotplug support
64*7c478bd9Sstevel@tonic-gate  * Leaf ops (hotplug controls for client devices)
65*7c478bd9Sstevel@tonic-gate  */
66*7c478bd9Sstevel@tonic-gate static int usb_mid_open(dev_t *, int, int, cred_t *);
67*7c478bd9Sstevel@tonic-gate static int usb_mid_close(dev_t, int, int, cred_t *);
68*7c478bd9Sstevel@tonic-gate static int usb_mid_read(dev_t, struct uio *, cred_t *);
69*7c478bd9Sstevel@tonic-gate static int usb_mid_write(dev_t, struct uio *, cred_t *);
70*7c478bd9Sstevel@tonic-gate static int usb_mid_poll(dev_t, short, int,  short *,
71*7c478bd9Sstevel@tonic-gate 					struct pollhead **);
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate static struct cb_ops usb_mid_cb_ops = {
74*7c478bd9Sstevel@tonic-gate 	usb_mid_open,
75*7c478bd9Sstevel@tonic-gate 	usb_mid_close,
76*7c478bd9Sstevel@tonic-gate 	nodev,		/* strategy */
77*7c478bd9Sstevel@tonic-gate 	nodev,		/* print */
78*7c478bd9Sstevel@tonic-gate 	nodev,		/* dump */
79*7c478bd9Sstevel@tonic-gate 	usb_mid_read,	/* read */
80*7c478bd9Sstevel@tonic-gate 	usb_mid_write,	/* write */
81*7c478bd9Sstevel@tonic-gate 	nodev,
82*7c478bd9Sstevel@tonic-gate 	nodev,		/* devmap */
83*7c478bd9Sstevel@tonic-gate 	nodev,		/* mmap */
84*7c478bd9Sstevel@tonic-gate 	nodev,		/* segmap */
85*7c478bd9Sstevel@tonic-gate 	usb_mid_poll,	/* poll */
86*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,	/* prop_op */
87*7c478bd9Sstevel@tonic-gate 	NULL,
88*7c478bd9Sstevel@tonic-gate 	D_MP
89*7c478bd9Sstevel@tonic-gate };
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_get_eventcookie(dev_info_t *dip,
92*7c478bd9Sstevel@tonic-gate 			dev_info_t *rdip,
93*7c478bd9Sstevel@tonic-gate 			char *eventname,
94*7c478bd9Sstevel@tonic-gate 			ddi_eventcookie_t *cookie);
95*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_add_eventcall(dev_info_t *dip,
96*7c478bd9Sstevel@tonic-gate 			dev_info_t *rdip,
97*7c478bd9Sstevel@tonic-gate 			ddi_eventcookie_t cookie,
98*7c478bd9Sstevel@tonic-gate 			void (*callback)(dev_info_t *dip,
99*7c478bd9Sstevel@tonic-gate 				ddi_eventcookie_t cookie, void *arg,
100*7c478bd9Sstevel@tonic-gate 				void *bus_impldata),
101*7c478bd9Sstevel@tonic-gate 			void *arg, ddi_callback_id_t *cb_id);
102*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_remove_eventcall(dev_info_t *dip,
103*7c478bd9Sstevel@tonic-gate 			ddi_callback_id_t cb_id);
104*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_post_event(dev_info_t *dip,
105*7c478bd9Sstevel@tonic-gate 			dev_info_t *rdip,
106*7c478bd9Sstevel@tonic-gate 			ddi_eventcookie_t cookie,
107*7c478bd9Sstevel@tonic-gate 			void *bus_impldata);
108*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_config(dev_info_t *dip,
109*7c478bd9Sstevel@tonic-gate 			uint_t flag,
110*7c478bd9Sstevel@tonic-gate 			ddi_bus_config_op_t op,
111*7c478bd9Sstevel@tonic-gate 			void *arg,
112*7c478bd9Sstevel@tonic-gate 			dev_info_t **child);
113*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_unconfig(dev_info_t *dip,
114*7c478bd9Sstevel@tonic-gate 			uint_t flag,
115*7c478bd9Sstevel@tonic-gate 			ddi_bus_config_op_t op,
116*7c478bd9Sstevel@tonic-gate 			void *arg);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate  * autoconfiguration data and routines.
121*7c478bd9Sstevel@tonic-gate  */
122*7c478bd9Sstevel@tonic-gate static int	usb_mid_info(dev_info_t *, ddi_info_cmd_t,
123*7c478bd9Sstevel@tonic-gate 				void *, void **);
124*7c478bd9Sstevel@tonic-gate static int	usb_mid_attach(dev_info_t *, ddi_attach_cmd_t);
125*7c478bd9Sstevel@tonic-gate static int	usb_mid_detach(dev_info_t *, ddi_detach_cmd_t);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /* other routines */
128*7c478bd9Sstevel@tonic-gate static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *);
129*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_ctl(dev_info_t *, dev_info_t	*,
130*7c478bd9Sstevel@tonic-gate 				ddi_ctl_enum_t, void *, void *);
131*7c478bd9Sstevel@tonic-gate static int usb_mid_power(dev_info_t *, int, int);
132*7c478bd9Sstevel@tonic-gate static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *);
133*7c478bd9Sstevel@tonic-gate static usb_mid_t  *usb_mid_obtain_state(dev_info_t *);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate /*
136*7c478bd9Sstevel@tonic-gate  * Busops vector
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate static struct bus_ops usb_mid_busops = {
139*7c478bd9Sstevel@tonic-gate 	BUSO_REV,
140*7c478bd9Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
141*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
142*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_add_intrspec */
143*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_remove_intrspec */
144*7c478bd9Sstevel@tonic-gate 	NULL,				/* XXXX bus_map_fault */
145*7c478bd9Sstevel@tonic-gate 	ddi_dma_map,			/* bus_dma_map */
146*7c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
147*7c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
148*7c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
149*7c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
150*7c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
151*7c478bd9Sstevel@tonic-gate 	ddi_dma_win,
152*7c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,			/* bus_dma_ctl */
153*7c478bd9Sstevel@tonic-gate 	usb_mid_bus_ctl,		/* bus_ctl */
154*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
155*7c478bd9Sstevel@tonic-gate 	usb_mid_busop_get_eventcookie,
156*7c478bd9Sstevel@tonic-gate 	usb_mid_busop_add_eventcall,
157*7c478bd9Sstevel@tonic-gate 	usb_mid_busop_remove_eventcall,
158*7c478bd9Sstevel@tonic-gate 	usb_mid_busop_post_event,	/* bus_post_event */
159*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
160*7c478bd9Sstevel@tonic-gate 	usb_mid_bus_config,		/* bus_config */
161*7c478bd9Sstevel@tonic-gate 	usb_mid_bus_unconfig,		/* bus_unconfig */
162*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
163*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
164*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
165*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
166*7c478bd9Sstevel@tonic-gate 	NULL				/* bus_power */
167*7c478bd9Sstevel@tonic-gate };
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate static struct dev_ops usb_mid_ops = {
171*7c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
172*7c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
173*7c478bd9Sstevel@tonic-gate 	usb_mid_info,		/* info */
174*7c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
175*7c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
176*7c478bd9Sstevel@tonic-gate 	usb_mid_attach,		/* attach */
177*7c478bd9Sstevel@tonic-gate 	usb_mid_detach,		/* detach */
178*7c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
179*7c478bd9Sstevel@tonic-gate 	&usb_mid_cb_ops,	/* driver operations */
180*7c478bd9Sstevel@tonic-gate 	&usb_mid_busops,	/* bus operations */
181*7c478bd9Sstevel@tonic-gate 	usb_mid_power		/* power */
182*7c478bd9Sstevel@tonic-gate };
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
185*7c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module. This one is a driver */
186*7c478bd9Sstevel@tonic-gate 	"USB Multi Interface Driver %I%", /* Name of the module. */
187*7c478bd9Sstevel@tonic-gate 	&usb_mid_ops,	/* driver ops */
188*7c478bd9Sstevel@tonic-gate };
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
191*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
192*7c478bd9Sstevel@tonic-gate };
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate #define	USB_MID_INITIAL_SOFT_SPACE 4
195*7c478bd9Sstevel@tonic-gate static	void	*usb_mid_statep;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate  * prototypes
200*7c478bd9Sstevel@tonic-gate  */
201*7c478bd9Sstevel@tonic-gate static void usb_mid_create_children(usb_mid_t *usb_mid);
202*7c478bd9Sstevel@tonic-gate static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t	*usb_mid);
203*7c478bd9Sstevel@tonic-gate static void usb_mid_register_events(usb_mid_t *usb_mid);
204*7c478bd9Sstevel@tonic-gate static void usb_mid_unregister_events(usb_mid_t *usb_mid);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /* usbai private */
207*7c478bd9Sstevel@tonic-gate char	*usba_get_mfg_prod_sn_str(dev_info_t  *dip,
208*7c478bd9Sstevel@tonic-gate 					char *buffer, int buflen);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * event definition
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate static ndi_event_definition_t usb_mid_ndi_event_defs[] = {
214*7c478bd9Sstevel@tonic-gate 	{USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
215*7c478bd9Sstevel@tonic-gate 						NDI_EVENT_POST_TO_ALL},
216*7c478bd9Sstevel@tonic-gate 	{USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
217*7c478bd9Sstevel@tonic-gate 						NDI_EVENT_POST_TO_ALL},
218*7c478bd9Sstevel@tonic-gate 	{USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
219*7c478bd9Sstevel@tonic-gate 						NDI_EVENT_POST_TO_ALL},
220*7c478bd9Sstevel@tonic-gate 	{USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
221*7c478bd9Sstevel@tonic-gate 						NDI_EVENT_POST_TO_ALL}
222*7c478bd9Sstevel@tonic-gate };
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate #define	USB_MID_N_NDI_EVENTS \
225*7c478bd9Sstevel@tonic-gate 	(sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t))
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate static	ndi_event_set_t usb_mid_ndi_events = {
228*7c478bd9Sstevel@tonic-gate 	NDI_EVENTS_REV1, USB_MID_N_NDI_EVENTS, usb_mid_ndi_event_defs};
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate /*
232*7c478bd9Sstevel@tonic-gate  * standard driver entry points
233*7c478bd9Sstevel@tonic-gate  */
234*7c478bd9Sstevel@tonic-gate int
235*7c478bd9Sstevel@tonic-gate _init(void)
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	int rval;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	rval = ddi_soft_state_init(&usb_mid_statep, sizeof (struct usb_mid),
240*7c478bd9Sstevel@tonic-gate 	    USB_MID_INITIAL_SOFT_SPACE);
241*7c478bd9Sstevel@tonic-gate 	if (rval != 0) {
242*7c478bd9Sstevel@tonic-gate 		return (rval);
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
246*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&usb_mid_statep);
247*7c478bd9Sstevel@tonic-gate 		return (rval);
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	return (rval);
251*7c478bd9Sstevel@tonic-gate }
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate int
255*7c478bd9Sstevel@tonic-gate _fini(void)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	int	rval;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	rval = mod_remove(&modlinkage);
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	if (rval) {
262*7c478bd9Sstevel@tonic-gate 		return (rval);
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&usb_mid_statep);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	return (rval);
268*7c478bd9Sstevel@tonic-gate }
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate int
272*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
279*7c478bd9Sstevel@tonic-gate static int
280*7c478bd9Sstevel@tonic-gate usb_mid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
281*7c478bd9Sstevel@tonic-gate {
282*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid;
283*7c478bd9Sstevel@tonic-gate 	int		instance =
284*7c478bd9Sstevel@tonic-gate 			USB_MID_MINOR_TO_INSTANCE(getminor((dev_t)arg));
285*7c478bd9Sstevel@tonic-gate 	int		error = DDI_FAILURE;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
288*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
289*7c478bd9Sstevel@tonic-gate 		if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
290*7c478bd9Sstevel@tonic-gate 		    instance)) != NULL) {
291*7c478bd9Sstevel@tonic-gate 			*result = (void *)usb_mid->mi_dip;
292*7c478bd9Sstevel@tonic-gate 			if (*result != NULL) {
293*7c478bd9Sstevel@tonic-gate 				error = DDI_SUCCESS;
294*7c478bd9Sstevel@tonic-gate 			}
295*7c478bd9Sstevel@tonic-gate 		} else {
296*7c478bd9Sstevel@tonic-gate 			*result = NULL;
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 		break;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
301*7c478bd9Sstevel@tonic-gate 		*result = (void *)(intptr_t)instance;
302*7c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
303*7c478bd9Sstevel@tonic-gate 		break;
304*7c478bd9Sstevel@tonic-gate 	default:
305*7c478bd9Sstevel@tonic-gate 		break;
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	return (error);
309*7c478bd9Sstevel@tonic-gate }
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate /*
313*7c478bd9Sstevel@tonic-gate  * child  post attach/detach notification
314*7c478bd9Sstevel@tonic-gate  */
315*7c478bd9Sstevel@tonic-gate static void
316*7c478bd9Sstevel@tonic-gate usb_mid_post_attach(usb_mid_t *usb_mid, uint8_t ifno, struct attachspec *as)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
319*7c478bd9Sstevel@tonic-gate 	    "usb_mid_post_attach: ifno = %d result = %d", ifno, as->result);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	/* if child successfully attached, set power */
322*7c478bd9Sstevel@tonic-gate 	if (as->result == DDI_SUCCESS) {
323*7c478bd9Sstevel@tonic-gate 		/*
324*7c478bd9Sstevel@tonic-gate 		 * Check if the child created wants to be power managed.
325*7c478bd9Sstevel@tonic-gate 		 * If yes, the childs power level gets automatically tracked
326*7c478bd9Sstevel@tonic-gate 		 * by DDI_CTLOPS_POWER busctl.
327*7c478bd9Sstevel@tonic-gate 		 * If no, we set power of the new child by default
328*7c478bd9Sstevel@tonic-gate 		 * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
329*7c478bd9Sstevel@tonic-gate 		 */
330*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
331*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_attach_count++;
332*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate }
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate static void
338*7c478bd9Sstevel@tonic-gate usb_mid_post_detach(usb_mid_t *usb_mid, uint8_t ifno, struct detachspec *ds)
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
341*7c478bd9Sstevel@tonic-gate 	    "usb_mid_post_detach: ifno = %d result = %d", ifno, ds->result);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/*
344*7c478bd9Sstevel@tonic-gate 	 * if the device is successfully detached,
345*7c478bd9Sstevel@tonic-gate 	 * mark component as idle
346*7c478bd9Sstevel@tonic-gate 	 */
347*7c478bd9Sstevel@tonic-gate 	if (ds->result == DDI_SUCCESS) {
348*7c478bd9Sstevel@tonic-gate 		usba_device_t *usba_device =
349*7c478bd9Sstevel@tonic-gate 				usba_get_usba_device(usb_mid->mi_dip);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 		/* check for leaks except when where is a ugen open */
354*7c478bd9Sstevel@tonic-gate 		if ((ds->cmd == DDI_DETACH) &&
355*7c478bd9Sstevel@tonic-gate 		    (--usb_mid->mi_attach_count == 0) && usba_device &&
356*7c478bd9Sstevel@tonic-gate 		    (usb_mid->mi_ugen_open_count == 0)) {
357*7c478bd9Sstevel@tonic-gate 			usba_check_for_leaks(usba_device);
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate }
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate /*
365*7c478bd9Sstevel@tonic-gate  * bus ctl support. we handle notifications here and the
366*7c478bd9Sstevel@tonic-gate  * rest goes up to root hub/hcd
367*7c478bd9Sstevel@tonic-gate  */
368*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
369*7c478bd9Sstevel@tonic-gate static int
370*7c478bd9Sstevel@tonic-gate usb_mid_bus_ctl(dev_info_t *dip,
371*7c478bd9Sstevel@tonic-gate 	dev_info_t	*rdip,
372*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t	op,
373*7c478bd9Sstevel@tonic-gate 	void		*arg,
374*7c478bd9Sstevel@tonic-gate 	void		*result)
375*7c478bd9Sstevel@tonic-gate {
376*7c478bd9Sstevel@tonic-gate 	usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
377*7c478bd9Sstevel@tonic-gate 	dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
378*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid;
379*7c478bd9Sstevel@tonic-gate 	struct attachspec *as;
380*7c478bd9Sstevel@tonic-gate 	struct detachspec *ds;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	usb_mid = usb_mid_obtain_state(dip);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
385*7c478bd9Sstevel@tonic-gate 	    "usb_mid_bus_ctl:\n\t"
386*7c478bd9Sstevel@tonic-gate 	    "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
387*7c478bd9Sstevel@tonic-gate 	    dip, rdip, op, arg);
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	switch (op) {
390*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
391*7c478bd9Sstevel@tonic-gate 		as = (struct attachspec *)arg;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		switch (as->when) {
394*7c478bd9Sstevel@tonic-gate 		case DDI_PRE :
395*7c478bd9Sstevel@tonic-gate 			/* nothing to do basically */
396*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
397*7c478bd9Sstevel@tonic-gate 			    "DDI_PRE DDI_CTLOPS_ATTACH");
398*7c478bd9Sstevel@tonic-gate 			break;
399*7c478bd9Sstevel@tonic-gate 		case DDI_POST :
400*7c478bd9Sstevel@tonic-gate 			usb_mid_post_attach(usb_mid, usba_get_ifno(rdip),
401*7c478bd9Sstevel@tonic-gate 			    (struct attachspec *)arg);
402*7c478bd9Sstevel@tonic-gate 			break;
403*7c478bd9Sstevel@tonic-gate 		}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		break;
406*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
407*7c478bd9Sstevel@tonic-gate 		ds = (struct detachspec *)arg;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 		switch (ds->when) {
410*7c478bd9Sstevel@tonic-gate 		case DDI_PRE :
411*7c478bd9Sstevel@tonic-gate 			/* nothing to do basically */
412*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
413*7c478bd9Sstevel@tonic-gate 			    "DDI_PRE DDI_CTLOPS_DETACH");
414*7c478bd9Sstevel@tonic-gate 			break;
415*7c478bd9Sstevel@tonic-gate 		case DDI_POST :
416*7c478bd9Sstevel@tonic-gate 			usb_mid_post_detach(usb_mid, usba_get_ifno(rdip),
417*7c478bd9Sstevel@tonic-gate 			    (struct detachspec *)arg);
418*7c478bd9Sstevel@tonic-gate 			break;
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		break;
422*7c478bd9Sstevel@tonic-gate 	default:
423*7c478bd9Sstevel@tonic-gate 		/* pass to root hub to handle */
424*7c478bd9Sstevel@tonic-gate 		return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
425*7c478bd9Sstevel@tonic-gate 	}
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
428*7c478bd9Sstevel@tonic-gate }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate /*
432*7c478bd9Sstevel@tonic-gate  * bus enumeration entry points
433*7c478bd9Sstevel@tonic-gate  */
434*7c478bd9Sstevel@tonic-gate static int
435*7c478bd9Sstevel@tonic-gate usb_mid_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
436*7c478bd9Sstevel@tonic-gate     void *arg, dev_info_t **child)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	int		rval, circ;
439*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid = usb_mid_obtain_state(dip);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
442*7c478bd9Sstevel@tonic-gate 	    "usb_mid_bus_config: op=%d", op);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	if (usb_mid_bus_config_debug) {
445*7c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/* enumerate each interface below us */
451*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
452*7c478bd9Sstevel@tonic-gate 	usb_mid_create_children(usb_mid);
453*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
456*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	return (rval);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate static int
463*7c478bd9Sstevel@tonic-gate usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
464*7c478bd9Sstevel@tonic-gate     void *arg)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip, *mdip;
469*7c478bd9Sstevel@tonic-gate 	int		interface, circular_count;
470*7c478bd9Sstevel@tonic-gate 	int		 rval = NDI_SUCCESS;
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
473*7c478bd9Sstevel@tonic-gate 	    "usb_mid_bus_unconfig: op=%d", op);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if (usb_mid_bus_config_debug) {
476*7c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
477*7c478bd9Sstevel@tonic-gate 	}
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	/*
480*7c478bd9Sstevel@tonic-gate 	 * first offline and if offlining successful, then
481*7c478bd9Sstevel@tonic-gate 	 * remove children
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL) {
484*7c478bd9Sstevel@tonic-gate 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(dip, &circular_count);
488*7c478bd9Sstevel@tonic-gate 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
491*7c478bd9Sstevel@tonic-gate 	    (flag & NDI_AUTODETACH) == 0) {
492*7c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_REMOVE;
493*7c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
494*7c478bd9Sstevel@tonic-gate 	}
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/* update children's list */
497*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
498*7c478bd9Sstevel@tonic-gate 	for (interface = 0; usb_mid->mi_children_dips &&
499*7c478bd9Sstevel@tonic-gate 	    (interface < usb_mid->mi_n_ifs); interface++) {
500*7c478bd9Sstevel@tonic-gate 		mdip = usb_mid->mi_children_dips[interface];
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 		/* now search if this dip still exists */
503*7c478bd9Sstevel@tonic-gate 		for (cdip = ddi_get_child(dip); cdip && (cdip != mdip);
504*7c478bd9Sstevel@tonic-gate 		    cdip = ddi_get_next_sibling(cdip));
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 		if (cdip != mdip) {
507*7c478bd9Sstevel@tonic-gate 			/* we lost the dip on this interface */
508*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_children_dips[interface] = NULL;
509*7c478bd9Sstevel@tonic-gate 		} else if (cdip) {
510*7c478bd9Sstevel@tonic-gate 			/*
511*7c478bd9Sstevel@tonic-gate 			 * keep in DS_INITALIZED to prevent parent
512*7c478bd9Sstevel@tonic-gate 			 * from detaching
513*7c478bd9Sstevel@tonic-gate 			 */
514*7c478bd9Sstevel@tonic-gate 			(void) ddi_initchild(ddi_get_parent(cdip), cdip);
515*7c478bd9Sstevel@tonic-gate 		}
516*7c478bd9Sstevel@tonic-gate 	}
517*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(dip, circular_count);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
522*7c478bd9Sstevel@tonic-gate 	    "usb_mid_bus_config: rval=%d", rval);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	return (rval);
525*7c478bd9Sstevel@tonic-gate }
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate /*
528*7c478bd9Sstevel@tonic-gate  * functions to handle power transition for OS levels 0 -> 3
529*7c478bd9Sstevel@tonic-gate  */
530*7c478bd9Sstevel@tonic-gate static int
531*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl0(usb_mid_t *usb_mid)
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	int	rval;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	switch (usb_mid->mi_dev_state) {
536*7c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
537*7c478bd9Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
538*7c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(usb_mid->mi_dip);
539*7c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_dev_state = USB_DEV_PWRED_DOWN;
542*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_pm->mip_current_power =
543*7c478bd9Sstevel@tonic-gate 					USB_DEV_OS_PWR_OFF;
544*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
545*7c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
546*7c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
547*7c478bd9Sstevel@tonic-gate 		/* allow a disconnected/cpr'ed device to go to low pwr */
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
550*7c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
551*7c478bd9Sstevel@tonic-gate 	default:
552*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
558*7c478bd9Sstevel@tonic-gate static int
559*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl1(usb_mid_t *usb_mid)
560*7c478bd9Sstevel@tonic-gate {
561*7c478bd9Sstevel@tonic-gate 	int	rval;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
564*7c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(usb_mid->mi_dip);
565*7c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
568*7c478bd9Sstevel@tonic-gate }
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
572*7c478bd9Sstevel@tonic-gate static int
573*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl2(usb_mid_t *usb_mid)
574*7c478bd9Sstevel@tonic-gate {
575*7c478bd9Sstevel@tonic-gate 	int	rval;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
578*7c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(usb_mid->mi_dip);
579*7c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
582*7c478bd9Sstevel@tonic-gate }
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate static int
586*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl3(usb_mid_t *usb_mid)
587*7c478bd9Sstevel@tonic-gate {
588*7c478bd9Sstevel@tonic-gate 	int	rval;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	switch (usb_mid->mi_dev_state) {
591*7c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
592*7c478bd9Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
593*7c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(usb_mid->mi_dip);
594*7c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_dev_state = USB_DEV_ONLINE;
597*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_pm->mip_current_power = USB_DEV_OS_FULL_PWR;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
600*7c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
601*7c478bd9Sstevel@tonic-gate 		/* we are already in full power */
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
604*7c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
605*7c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
606*7c478bd9Sstevel@tonic-gate 		/* allow a disconnected/cpr'ed device to go to low power */
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
609*7c478bd9Sstevel@tonic-gate 	default:
610*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
611*7c478bd9Sstevel@tonic-gate 		    "usb_mid_pwrlvl3: Illegal state (%s)",
612*7c478bd9Sstevel@tonic-gate 		    usb_str_dev_state(usb_mid->mi_dev_state));
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate /* power entry point */
620*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
621*7c478bd9Sstevel@tonic-gate static int
622*7c478bd9Sstevel@tonic-gate usb_mid_power(dev_info_t *dip, int comp, int level)
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid;
625*7c478bd9Sstevel@tonic-gate 	usb_mid_power_t	*midpm;
626*7c478bd9Sstevel@tonic-gate 	int		rval = DDI_FAILURE;
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	usb_mid =  usb_mid_obtain_state(dip);
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
631*7c478bd9Sstevel@tonic-gate 	    "usb_mid_power: Begin: usb_mid = %p, level = %d", usb_mid, level);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
634*7c478bd9Sstevel@tonic-gate 	midpm = usb_mid->mi_pm;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	/* check if we are transitioning to a legal power level */
637*7c478bd9Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(midpm->mip_pwr_states, level)) {
638*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
639*7c478bd9Sstevel@tonic-gate 		    "usb_mid_power: illegal power level = %d "
640*7c478bd9Sstevel@tonic-gate 		    "mip_pwr_states = %x", level, midpm->mip_pwr_states);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		return (rval);
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	switch (level) {
648*7c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF:
649*7c478bd9Sstevel@tonic-gate 		rval = usb_mid_pwrlvl0(usb_mid);
650*7c478bd9Sstevel@tonic-gate 		break;
651*7c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1:
652*7c478bd9Sstevel@tonic-gate 		rval = usb_mid_pwrlvl1(usb_mid);
653*7c478bd9Sstevel@tonic-gate 		break;
654*7c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2:
655*7c478bd9Sstevel@tonic-gate 		rval = usb_mid_pwrlvl2(usb_mid);
656*7c478bd9Sstevel@tonic-gate 		break;
657*7c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR:
658*7c478bd9Sstevel@tonic-gate 		rval = usb_mid_pwrlvl3(usb_mid);
659*7c478bd9Sstevel@tonic-gate 		break;
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
665*7c478bd9Sstevel@tonic-gate }
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate /*
669*7c478bd9Sstevel@tonic-gate  * attach/resume entry point
670*7c478bd9Sstevel@tonic-gate  */
671*7c478bd9Sstevel@tonic-gate static int
672*7c478bd9Sstevel@tonic-gate usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
675*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid = NULL;
676*7c478bd9Sstevel@tonic-gate 	uint_t		n_ifs;
677*7c478bd9Sstevel@tonic-gate 	size_t		size;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
680*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 		break;
683*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
684*7c478bd9Sstevel@tonic-gate 		usb_mid = (usb_mid_t *)ddi_get_soft_state(usb_mid_statep,
685*7c478bd9Sstevel@tonic-gate 		    instance);
686*7c478bd9Sstevel@tonic-gate 		(void) usb_mid_restore_device_state(dip, usb_mid);
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		if (usb_mid->mi_ugen_hdl) {
689*7c478bd9Sstevel@tonic-gate 			(void) usb_ugen_attach(usb_mid->mi_ugen_hdl,
690*7c478bd9Sstevel@tonic-gate 						DDI_RESUME);
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
694*7c478bd9Sstevel@tonic-gate 	default:
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
697*7c478bd9Sstevel@tonic-gate 	}
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	/*
700*7c478bd9Sstevel@tonic-gate 	 * Attach:
701*7c478bd9Sstevel@tonic-gate 	 *
702*7c478bd9Sstevel@tonic-gate 	 * Allocate soft state and initialize
703*7c478bd9Sstevel@tonic-gate 	 */
704*7c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(usb_mid_statep, instance) != DDI_SUCCESS) {
705*7c478bd9Sstevel@tonic-gate 		goto fail;
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	usb_mid = ddi_get_soft_state(usb_mid_statep, instance);
709*7c478bd9Sstevel@tonic-gate 	if (usb_mid == NULL) {
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 		goto fail;
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	/* allocate handle for logging of messages */
715*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_log_handle = usb_alloc_log_hdl(dip, "mid",
716*7c478bd9Sstevel@tonic-gate 				&usb_mid_errlevel,
717*7c478bd9Sstevel@tonic-gate 				&usb_mid_errmask, &usb_mid_instance_debug,
718*7c478bd9Sstevel@tonic-gate 				0);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_usba_device = usba_get_usba_device(dip);
721*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_dip	= dip;
722*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_instance = instance;
723*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_n_ifs = usb_mid->mi_usba_device->usb_n_ifs;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	/* attach client driver to USBA */
726*7c478bd9Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
727*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
728*7c478bd9Sstevel@tonic-gate 		    "usb_client_attach failed");
729*7c478bd9Sstevel@tonic-gate 		goto fail;
730*7c478bd9Sstevel@tonic-gate 	}
731*7c478bd9Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &usb_mid->mi_dev_data, USB_PARSE_LVL_NONE,
732*7c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
733*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
734*7c478bd9Sstevel@tonic-gate 		    "usb_get_dev_data failed");
735*7c478bd9Sstevel@tonic-gate 		goto fail;
736*7c478bd9Sstevel@tonic-gate 	}
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	mutex_init(&usb_mid->mi_mutex, NULL, MUTEX_DRIVER,
739*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_dev_data->dev_iblock_cookie);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	usb_free_dev_data(dip, usb_mid->mi_dev_data);
742*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_dev_data = NULL;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_init_state |= USB_MID_LOCK_INIT;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "usb_mid", S_IFCHR,
747*7c478bd9Sstevel@tonic-gate 	    instance << USB_MID_MINOR_INSTANCE_SHIFT,
748*7c478bd9Sstevel@tonic-gate 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
749*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
750*7c478bd9Sstevel@tonic-gate 		    "cannot create devctl minor node");
751*7c478bd9Sstevel@tonic-gate 		goto fail;
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_init_state |= USB_MID_MINOR_NODE_CREATED;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	/*
757*7c478bd9Sstevel@tonic-gate 	 * allocate array for keeping track of child dips
758*7c478bd9Sstevel@tonic-gate 	 */
759*7c478bd9Sstevel@tonic-gate 	n_ifs = usb_mid->mi_n_ifs;
760*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP);
763*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
764*7c478bd9Sstevel@tonic-gate 								KM_SLEEP);
765*7c478bd9Sstevel@tonic-gate 	/*
766*7c478bd9Sstevel@tonic-gate 	 * Event handling: definition and registration
767*7c478bd9Sstevel@tonic-gate 	 * get event handle for events that we have defined
768*7c478bd9Sstevel@tonic-gate 	 */
769*7c478bd9Sstevel@tonic-gate 	(void) ndi_event_alloc_hdl(dip, 0, &usb_mid->mi_ndi_event_hdl,
770*7c478bd9Sstevel@tonic-gate 								NDI_SLEEP);
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	/* bind event set to the handle */
773*7c478bd9Sstevel@tonic-gate 	if (ndi_event_bind_set(usb_mid->mi_ndi_event_hdl, &usb_mid_ndi_events,
774*7c478bd9Sstevel@tonic-gate 	    NDI_SLEEP)) {
775*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
776*7c478bd9Sstevel@tonic-gate 		    "usb_mid_attach: binding event set failed");
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 		goto fail;
779*7c478bd9Sstevel@tonic-gate 	}
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_dev_state = USB_DEV_ONLINE;
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	/*
784*7c478bd9Sstevel@tonic-gate 	 * now create components to power manage this device
785*7c478bd9Sstevel@tonic-gate 	 * before attaching children
786*7c478bd9Sstevel@tonic-gate 	 */
787*7c478bd9Sstevel@tonic-gate 	usb_mid_create_pm_components(dip, usb_mid);
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	/* event registration for events from our parent */
790*7c478bd9Sstevel@tonic-gate 	usb_mid_register_events(usb_mid);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED;
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate fail:
799*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_ATTA, NULL, "usb_mid%d cannot attach",
800*7c478bd9Sstevel@tonic-gate 	    instance);
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	if (usb_mid) {
803*7c478bd9Sstevel@tonic-gate 		(void) usb_mid_cleanup(dip, usb_mid);
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
807*7c478bd9Sstevel@tonic-gate }
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate /* detach or suspend this instance */
811*7c478bd9Sstevel@tonic-gate static int
812*7c478bd9Sstevel@tonic-gate usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
813*7c478bd9Sstevel@tonic-gate {
814*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid = usb_mid_obtain_state(dip);
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
817*7c478bd9Sstevel@tonic-gate 	    "usb_mid_detach: cmd = 0x%x", cmd);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
820*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 		return (usb_mid_cleanup(dip, usb_mid));
823*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
824*7c478bd9Sstevel@tonic-gate 		/* nothing to do */
825*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
826*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_dev_state = USB_DEV_SUSPENDED;
827*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 		if (usb_mid->mi_ugen_hdl) {
830*7c478bd9Sstevel@tonic-gate 			int rval = usb_ugen_detach(usb_mid->mi_ugen_hdl,
831*7c478bd9Sstevel@tonic-gate 						DDI_SUSPEND);
832*7c478bd9Sstevel@tonic-gate 			return (rval == USB_SUCCESS ? DDI_SUCCESS :
833*7c478bd9Sstevel@tonic-gate 						DDI_FAILURE);
834*7c478bd9Sstevel@tonic-gate 		}
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
837*7c478bd9Sstevel@tonic-gate 	default:
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
840*7c478bd9Sstevel@tonic-gate 	}
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	_NOTE(NOT_REACHED)
843*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
844*7c478bd9Sstevel@tonic-gate }
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate /*
848*7c478bd9Sstevel@tonic-gate  * usb_mid_cleanup:
849*7c478bd9Sstevel@tonic-gate  *	cleanup usb_mid and deallocate. this function is called for
850*7c478bd9Sstevel@tonic-gate  *	handling attach failures and detaching including dynamic
851*7c478bd9Sstevel@tonic-gate  *	reconfiguration
852*7c478bd9Sstevel@tonic-gate  */
853*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
854*7c478bd9Sstevel@tonic-gate static int
855*7c478bd9Sstevel@tonic-gate usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	usb_mid_power_t	*midpm;
858*7c478bd9Sstevel@tonic-gate 	int		rval;
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
861*7c478bd9Sstevel@tonic-gate 	    "usb_mid_cleanup:");
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	if ((usb_mid->mi_init_state & USB_MID_LOCK_INIT) == 0) {
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 		goto done;
866*7c478bd9Sstevel@tonic-gate 	}
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	/*
869*7c478bd9Sstevel@tonic-gate 	 * deallocate events, if events are still registered
870*7c478bd9Sstevel@tonic-gate 	 * (ie. children still attached) then we have to fail the detach
871*7c478bd9Sstevel@tonic-gate 	 */
872*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_ndi_event_hdl &&
873*7c478bd9Sstevel@tonic-gate 	    (ndi_event_free_hdl(usb_mid->mi_ndi_event_hdl) != NDI_SUCCESS)) {
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
876*7c478bd9Sstevel@tonic-gate 		    "usb_mid_cleanup: ndi_event_free_hdl failed");
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
879*7c478bd9Sstevel@tonic-gate 	}
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	/*
882*7c478bd9Sstevel@tonic-gate 	 * Disable the event callbacks, after this point, event
883*7c478bd9Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
884*7c478bd9Sstevel@tonic-gate 	 * mutex while unregistering events because there may be a
885*7c478bd9Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
886*7c478bd9Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
887*7c478bd9Sstevel@tonic-gate 	 * Note that cleanup can't fail after deregistration of events.
888*7c478bd9Sstevel@tonic-gate 	 */
889*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) {
890*7c478bd9Sstevel@tonic-gate 		usb_mid_unregister_events(usb_mid);
891*7c478bd9Sstevel@tonic-gate 	}
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	midpm = usb_mid->mi_pm;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	if ((midpm) && (usb_mid->mi_dev_state != USB_DEV_DISCONNECTED)) {
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 		(void) pm_busy_component(dip, 0);
902*7c478bd9Sstevel@tonic-gate 		if (midpm->mip_wakeup_enabled) {
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 			/* First bring the device to full power */
905*7c478bd9Sstevel@tonic-gate 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 			rval = usb_handle_remote_wakeup(dip,
908*7c478bd9Sstevel@tonic-gate 			    USB_REMOTE_WAKEUP_DISABLE);
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 			if (rval != DDI_SUCCESS) {
911*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
912*7c478bd9Sstevel@tonic-gate 				    usb_mid->mi_log_handle,
913*7c478bd9Sstevel@tonic-gate 				    "usb_cleanup: disable remote "
914*7c478bd9Sstevel@tonic-gate 				    "wakeup failed, rval=%d", rval);
915*7c478bd9Sstevel@tonic-gate 			}
916*7c478bd9Sstevel@tonic-gate 		}
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 		(void) pm_lower_power(usb_mid->mi_dip, 0, USB_DEV_OS_PWR_OFF);
919*7c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(dip, 0);
920*7c478bd9Sstevel@tonic-gate 	} else {
921*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	if (midpm) {
925*7c478bd9Sstevel@tonic-gate 		kmem_free(midpm, sizeof (usb_mid_power_t));
926*7c478bd9Sstevel@tonic-gate 	}
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	/* free children list */
929*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_children_dips) {
930*7c478bd9Sstevel@tonic-gate 		kmem_free(usb_mid->mi_children_dips,
931*7c478bd9Sstevel@tonic-gate 					usb_mid->mi_cd_list_length);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_child_events) {
935*7c478bd9Sstevel@tonic-gate 		kmem_free(usb_mid->mi_child_events, sizeof (uint8_t) *
936*7c478bd9Sstevel@tonic-gate 		    usb_mid->mi_n_ifs);
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) {
940*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&usb_mid->mi_mutex);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate done:
946*7c478bd9Sstevel@tonic-gate 	usb_client_detach(dip, usb_mid->mi_dev_data);
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_ugen_hdl) {
949*7c478bd9Sstevel@tonic-gate 		(void) usb_ugen_detach(usb_mid->mi_ugen_hdl, DDI_DETACH);
950*7c478bd9Sstevel@tonic-gate 		usb_ugen_release_hdl(usb_mid->mi_ugen_hdl);
951*7c478bd9Sstevel@tonic-gate 	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usb_mid->mi_log_handle);
954*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(usb_mid_statep, ddi_get_instance(dip));
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
959*7c478bd9Sstevel@tonic-gate }
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate int
963*7c478bd9Sstevel@tonic-gate usb_mid_devi_bind_driver(usb_mid_t *usb_mid, dev_info_t *dip)
964*7c478bd9Sstevel@tonic-gate {
965*7c478bd9Sstevel@tonic-gate 	char	*name;
966*7c478bd9Sstevel@tonic-gate 	uint8_t if_num = usba_get_ifno(dip);
967*7c478bd9Sstevel@tonic-gate 	int	rval = USB_SUCCESS;
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
970*7c478bd9Sstevel@tonic-gate 	    "usb_mid_devi_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num);
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	/* bind device to the driver */
975*7c478bd9Sstevel@tonic-gate 	if (ndi_devi_bind_driver(dip, 0) != NDI_SUCCESS) {
976*7c478bd9Sstevel@tonic-gate 		/* if we fail to bind report an error */
977*7c478bd9Sstevel@tonic-gate 		(void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
978*7c478bd9Sstevel@tonic-gate 		if (name[0] != '\0') {
979*7c478bd9Sstevel@tonic-gate 			if (!usb_owns_device(dip)) {
980*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_ATTA,
981*7c478bd9Sstevel@tonic-gate 				    usb_mid->mi_log_handle,
982*7c478bd9Sstevel@tonic-gate 				    "no driver found for "
983*7c478bd9Sstevel@tonic-gate 				    "interface %d (nodename: '%s') of %s",
984*7c478bd9Sstevel@tonic-gate 				    if_num, ddi_node_name(dip), name);
985*7c478bd9Sstevel@tonic-gate 			} else {
986*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_ATTA,
987*7c478bd9Sstevel@tonic-gate 				    usb_mid->mi_log_handle,
988*7c478bd9Sstevel@tonic-gate 				    "no driver found for device %s", name);
989*7c478bd9Sstevel@tonic-gate 			}
990*7c478bd9Sstevel@tonic-gate 		} else {
991*7c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(dip, name);
992*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_ATTA,
993*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_log_handle,
994*7c478bd9Sstevel@tonic-gate 			    "no driver found for device %s", name);
995*7c478bd9Sstevel@tonic-gate 		}
996*7c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
997*7c478bd9Sstevel@tonic-gate 	}
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	kmem_free(name, MAXNAMELEN);
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	return (rval);
1002*7c478bd9Sstevel@tonic-gate }
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate static void
1006*7c478bd9Sstevel@tonic-gate usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children)
1007*7c478bd9Sstevel@tonic-gate {
1008*7c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_ugen_hdl == NULL) {
1011*7c478bd9Sstevel@tonic-gate 		usb_ugen_info_t usb_ugen_info;
1012*7c478bd9Sstevel@tonic-gate 		int		rval;
1013*7c478bd9Sstevel@tonic-gate 		usb_ugen_hdl_t	hdl;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
1016*7c478bd9Sstevel@tonic-gate 			"usb_mid_ugen_attach: get handle");
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = (remove_children ?
1021*7c478bd9Sstevel@tonic-gate 				USB_UGEN_REMOVE_CHILDREN : 0);
1022*7c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
1023*7c478bd9Sstevel@tonic-gate 				(dev_t)USB_MID_MINOR_UGEN_BITS_MASK;
1024*7c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
1025*7c478bd9Sstevel@tonic-gate 				(dev_t)~USB_MID_MINOR_UGEN_BITS_MASK;
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1028*7c478bd9Sstevel@tonic-gate 		hdl = usb_ugen_get_hdl(usb_mid->mi_dip,
1029*7c478bd9Sstevel@tonic-gate 						&usb_ugen_info);
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 		if ((rval = usb_ugen_attach(hdl, DDI_ATTACH)) != USB_SUCCESS) {
1032*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
1033*7c478bd9Sstevel@tonic-gate 			    "failed to create ugen support (%d)", rval);
1034*7c478bd9Sstevel@tonic-gate 			usb_ugen_release_hdl(hdl);
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_mid->mi_mutex);
1037*7c478bd9Sstevel@tonic-gate 		} else {
1038*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_mid->mi_mutex);
1039*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_ugen_hdl = hdl;
1040*7c478bd9Sstevel@tonic-gate 		}
1041*7c478bd9Sstevel@tonic-gate 	}
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate /*
1048*7c478bd9Sstevel@tonic-gate  * usb_mid_create_children:
1049*7c478bd9Sstevel@tonic-gate  */
1050*7c478bd9Sstevel@tonic-gate static void
1051*7c478bd9Sstevel@tonic-gate usb_mid_create_children(usb_mid_t *usb_mid)
1052*7c478bd9Sstevel@tonic-gate {
1053*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1054*7c478bd9Sstevel@tonic-gate 	uint_t			n_ifs;
1055*7c478bd9Sstevel@tonic-gate 	uint_t			i;
1056*7c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip;
1057*7c478bd9Sstevel@tonic-gate 	uint_t			ugen_bound = 0;
1058*7c478bd9Sstevel@tonic-gate 	uint_t			bound_children = 0;
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(usb_mid->mi_dip);
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
1063*7c478bd9Sstevel@tonic-gate 	    "usb_mid_attach_child_drivers: port = %d, address = %d",
1064*7c478bd9Sstevel@tonic-gate 	    usba_device->usb_port, usba_device->usb_addr);
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	if (usb_mid->mi_removed_children) {
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 			return;
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	n_ifs = usb_mid->mi_n_ifs;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
1074*7c478bd9Sstevel@tonic-gate 	    "usb_mid_create_children: #interfaces = %d", n_ifs);
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	/*
1077*7c478bd9Sstevel@tonic-gate 	 * create all children if not already present
1078*7c478bd9Sstevel@tonic-gate 	 */
1079*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_ifs; i++) {
1080*7c478bd9Sstevel@tonic-gate 		if (usb_mid->mi_children_dips[i] != NULL) {
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 			continue;
1083*7c478bd9Sstevel@tonic-gate 		}
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1086*7c478bd9Sstevel@tonic-gate 		cdip = usba_ready_interface_node(usb_mid->mi_dip, i);
1087*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1088*7c478bd9Sstevel@tonic-gate 		if (cdip != NULL) {
1089*7c478bd9Sstevel@tonic-gate 			if (usb_mid_devi_bind_driver(usb_mid, cdip) ==
1090*7c478bd9Sstevel@tonic-gate 			    USB_SUCCESS) {
1091*7c478bd9Sstevel@tonic-gate 				bound_children++;
1092*7c478bd9Sstevel@tonic-gate 				if (strcmp(ddi_driver_name(cdip),
1093*7c478bd9Sstevel@tonic-gate 				    "ugen") == 0) {
1094*7c478bd9Sstevel@tonic-gate 					ugen_bound++;
1095*7c478bd9Sstevel@tonic-gate 				}
1096*7c478bd9Sstevel@tonic-gate 			}
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_children_dips[i] = cdip;
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 		}
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE);
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	/*
1106*7c478bd9Sstevel@tonic-gate 	 * if there are no ugen interface children, create ugen support at
1107*7c478bd9Sstevel@tonic-gate 	 * device level, use a separate thread because we may be at interrupt
1108*7c478bd9Sstevel@tonic-gate 	 * level
1109*7c478bd9Sstevel@tonic-gate 	 */
1110*7c478bd9Sstevel@tonic-gate 	if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) {
1111*7c478bd9Sstevel@tonic-gate 		/*
1112*7c478bd9Sstevel@tonic-gate 		 * we only need to remove the children if there are
1113*7c478bd9Sstevel@tonic-gate 		 * multiple configurations which would fail if there
1114*7c478bd9Sstevel@tonic-gate 		 * are child interfaces
1115*7c478bd9Sstevel@tonic-gate 		 */
1116*7c478bd9Sstevel@tonic-gate 		if ((usb_mid->mi_removed_children == B_FALSE) &&
1117*7c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_cfgs > 1)) {
1118*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_ATTA,
1119*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_log_handle,
1120*7c478bd9Sstevel@tonic-gate 			    "can't support ugen for multiple "
1121*7c478bd9Sstevel@tonic-gate 			    "configurations devices that have attached "
1122*7c478bd9Sstevel@tonic-gate 			    "child interface drivers");
1123*7c478bd9Sstevel@tonic-gate 		} else {
1124*7c478bd9Sstevel@tonic-gate 			usb_mid_ugen_attach(usb_mid,
1125*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_removed_children);
1126*7c478bd9Sstevel@tonic-gate 		}
1127*7c478bd9Sstevel@tonic-gate 	}
1128*7c478bd9Sstevel@tonic-gate }
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate /*
1132*7c478bd9Sstevel@tonic-gate  * event support
1133*7c478bd9Sstevel@tonic-gate  */
1134*7c478bd9Sstevel@tonic-gate static int
1135*7c478bd9Sstevel@tonic-gate usb_mid_busop_get_eventcookie(dev_info_t *dip,
1136*7c478bd9Sstevel@tonic-gate 	dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
1137*7c478bd9Sstevel@tonic-gate {
1138*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1141*7c478bd9Sstevel@tonic-gate 	    "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
1142*7c478bd9Sstevel@tonic-gate 	    "event=%s", (void *)dip, (void *)rdip, eventname);
1143*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1144*7c478bd9Sstevel@tonic-gate 	    "(dip=%s%d rdip=%s%d)",
1145*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
1146*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	/* return event cookie, iblock cookie, and level */
1149*7c478bd9Sstevel@tonic-gate 	return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl,
1150*7c478bd9Sstevel@tonic-gate 		rdip, eventname, cookie, NDI_EVENT_NOPASS));
1151*7c478bd9Sstevel@tonic-gate }
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate static int
1155*7c478bd9Sstevel@tonic-gate usb_mid_busop_add_eventcall(dev_info_t *dip,
1156*7c478bd9Sstevel@tonic-gate 	dev_info_t *rdip,
1157*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie,
1158*7c478bd9Sstevel@tonic-gate 	void (*callback)(dev_info_t *dip,
1159*7c478bd9Sstevel@tonic-gate 	    ddi_eventcookie_t cookie, void *arg,
1160*7c478bd9Sstevel@tonic-gate 	    void *bus_impldata),
1161*7c478bd9Sstevel@tonic-gate 	void *arg, ddi_callback_id_t *cb_id)
1162*7c478bd9Sstevel@tonic-gate {
1163*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1164*7c478bd9Sstevel@tonic-gate 	int	ifno = usba_get_ifno(rdip);
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1167*7c478bd9Sstevel@tonic-gate 	    "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p "
1168*7c478bd9Sstevel@tonic-gate 	    "cookie=0x%p, cb=0x%p, arg=0x%p",
1169*7c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
1170*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1171*7c478bd9Sstevel@tonic-gate 	    "(dip=%s%d rdip=%s%d event=%s)",
1172*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
1173*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
1174*7c478bd9Sstevel@tonic-gate 	    ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate 	/* Set flag on children registering events */
1177*7c478bd9Sstevel@tonic-gate 	switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) {
1178*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_HOT_REMOVAL:
1179*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1180*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_child_events[ifno] |=
1181*7c478bd9Sstevel@tonic-gate 		    USB_MID_CHILD_EVENT_DISCONNECT;
1182*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 		break;
1185*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_PRE_SUSPEND:
1186*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1187*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_child_events[ifno] |=
1188*7c478bd9Sstevel@tonic-gate 		    USB_MID_CHILD_EVENT_PRESUSPEND;
1189*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 		break;
1192*7c478bd9Sstevel@tonic-gate 	default:
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 		break;
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 	/* add callback (perform registration) */
1197*7c478bd9Sstevel@tonic-gate 	return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl,
1198*7c478bd9Sstevel@tonic-gate 		rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
1199*7c478bd9Sstevel@tonic-gate }
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate static int
1203*7c478bd9Sstevel@tonic-gate usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
1204*7c478bd9Sstevel@tonic-gate {
1205*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1206*7c478bd9Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	ASSERT(cb);
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1211*7c478bd9Sstevel@tonic-gate 	    "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
1212*7c478bd9Sstevel@tonic-gate 	    "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip,
1213*7c478bd9Sstevel@tonic-gate 	    cb->ndi_evtcb_cookie);
1214*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1215*7c478bd9Sstevel@tonic-gate 	    "(dip=%s%d rdip=%s%d event=%s)",
1216*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
1217*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(cb->ndi_evtcb_dip),
1218*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(cb->ndi_evtcb_dip),
1219*7c478bd9Sstevel@tonic-gate 	    ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl,
1220*7c478bd9Sstevel@tonic-gate 	    cb->ndi_evtcb_cookie));
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	/* remove event registration from our event set */
1223*7c478bd9Sstevel@tonic-gate 	return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id));
1224*7c478bd9Sstevel@tonic-gate }
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate static int
1228*7c478bd9Sstevel@tonic-gate usb_mid_busop_post_event(dev_info_t *dip,
1229*7c478bd9Sstevel@tonic-gate 	dev_info_t *rdip,
1230*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie,
1231*7c478bd9Sstevel@tonic-gate 	void *bus_impldata)
1232*7c478bd9Sstevel@tonic-gate {
1233*7c478bd9Sstevel@tonic-gate 	usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1236*7c478bd9Sstevel@tonic-gate 	    "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p "
1237*7c478bd9Sstevel@tonic-gate 	    "cookie=0x%p, impl=0x%p",
1238*7c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
1239*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1240*7c478bd9Sstevel@tonic-gate 	    "(dip=%s%d rdip=%s%d event=%s)",
1241*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
1242*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
1243*7c478bd9Sstevel@tonic-gate 	    ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 	/* post event to all children registered for this event */
1246*7c478bd9Sstevel@tonic-gate 	return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip,
1247*7c478bd9Sstevel@tonic-gate 		    cookie, bus_impldata));
1248*7c478bd9Sstevel@tonic-gate }
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate /*
1252*7c478bd9Sstevel@tonic-gate  * usb_mid_restore_device_state
1253*7c478bd9Sstevel@tonic-gate  *	set the original configuration of the device
1254*7c478bd9Sstevel@tonic-gate  */
1255*7c478bd9Sstevel@tonic-gate static int
1256*7c478bd9Sstevel@tonic-gate usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid)
1257*7c478bd9Sstevel@tonic-gate {
1258*7c478bd9Sstevel@tonic-gate 	usb_mid_power_t		*midpm;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1261*7c478bd9Sstevel@tonic-gate 	    "usb_mid_restore_device_state: usb_mid = %p", usb_mid);
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
1264*7c478bd9Sstevel@tonic-gate 	midpm = usb_mid->mi_pm;
1265*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	/* First bring the device to full power */
1268*7c478bd9Sstevel@tonic-gate 	(void) pm_busy_component(dip, 0);
1269*7c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0,
1272*7c478bd9Sstevel@tonic-gate 	    DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 		/* change the device state from suspended to disconnected */
1275*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1276*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1277*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1278*7c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(dip, 0);
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1281*7c478bd9Sstevel@tonic-gate 	}
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/*
1284*7c478bd9Sstevel@tonic-gate 	 * if the device had remote wakeup earlier,
1285*7c478bd9Sstevel@tonic-gate 	 * enable it again
1286*7c478bd9Sstevel@tonic-gate 	 */
1287*7c478bd9Sstevel@tonic-gate 	if (midpm->mip_wakeup_enabled) {
1288*7c478bd9Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(usb_mid->mi_dip,
1289*7c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
1293*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_dev_state = USB_DEV_ONLINE;
1294*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	(void) pm_idle_component(dip, 0);
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1299*7c478bd9Sstevel@tonic-gate }
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate /*
1303*7c478bd9Sstevel@tonic-gate  * usb_mid_event_cb()
1304*7c478bd9Sstevel@tonic-gate  *	handle disconnect and connect events
1305*7c478bd9Sstevel@tonic-gate  */
1306*7c478bd9Sstevel@tonic-gate static void
1307*7c478bd9Sstevel@tonic-gate usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1308*7c478bd9Sstevel@tonic-gate 	void *arg, void *bus_impldata)
1309*7c478bd9Sstevel@tonic-gate {
1310*7c478bd9Sstevel@tonic-gate 	int		i, tag;
1311*7c478bd9Sstevel@tonic-gate 	usb_mid_t	*usb_mid = usb_mid_obtain_state(dip);
1312*7c478bd9Sstevel@tonic-gate 	dev_info_t	*child_dip;
1313*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1316*7c478bd9Sstevel@tonic-gate 	    "usb_mid_event_cb: dip=0x%p, cookie=0x%p, "
1317*7c478bd9Sstevel@tonic-gate 	    "arg=0x%p, impl=0x%p",
1318*7c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)cookie, arg, bus_impldata);
1319*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1320*7c478bd9Sstevel@tonic-gate 	    "(dip=%s%d event=%s)",
1321*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
1322*7c478bd9Sstevel@tonic-gate 	    ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	tag = NDI_EVENT_TAG(cookie);
1325*7c478bd9Sstevel@tonic-gate 	rm_cookie = ndi_event_tag_to_cookie(
1326*7c478bd9Sstevel@tonic-gate 	    usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1327*7c478bd9Sstevel@tonic-gate 	suspend_cookie = ndi_event_tag_to_cookie(
1328*7c478bd9Sstevel@tonic-gate 	    usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1329*7c478bd9Sstevel@tonic-gate 	ins_cookie = ndi_event_tag_to_cookie(
1330*7c478bd9Sstevel@tonic-gate 	    usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1331*7c478bd9Sstevel@tonic-gate 	resume_cookie = ndi_event_tag_to_cookie(
1332*7c478bd9Sstevel@tonic-gate 	    usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
1335*7c478bd9Sstevel@tonic-gate 	switch (tag) {
1336*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_HOT_REMOVAL:
1337*7c478bd9Sstevel@tonic-gate 		if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) {
1338*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1339*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_log_handle,
1340*7c478bd9Sstevel@tonic-gate 			    "usb_mid_event_cb: Device already disconnected");
1341*7c478bd9Sstevel@tonic-gate 		} else {
1342*7c478bd9Sstevel@tonic-gate 			/* we are disconnected so set our state now */
1343*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1344*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1345*7c478bd9Sstevel@tonic-gate 				usb_mid->mi_child_events[i] &= ~
1346*7c478bd9Sstevel@tonic-gate 				    USB_MID_CHILD_EVENT_DISCONNECT;
1347*7c478bd9Sstevel@tonic-gate 			}
1348*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usb_mid->mi_mutex);
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 			/* pass disconnect event to all the children */
1351*7c478bd9Sstevel@tonic-gate 			(void) ndi_event_run_callbacks(
1352*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_ndi_event_hdl, NULL,
1353*7c478bd9Sstevel@tonic-gate 			    rm_cookie, bus_impldata);
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 			if (usb_mid->mi_ugen_hdl) {
1356*7c478bd9Sstevel@tonic-gate 				(void) usb_ugen_disconnect_ev_cb(
1357*7c478bd9Sstevel@tonic-gate 						usb_mid->mi_ugen_hdl);
1358*7c478bd9Sstevel@tonic-gate 			}
1359*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_mid->mi_mutex);
1360*7c478bd9Sstevel@tonic-gate 		}
1361*7c478bd9Sstevel@tonic-gate 		break;
1362*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_PRE_SUSPEND:
1363*7c478bd9Sstevel@tonic-gate 		/* set our state *after* suspending children */
1364*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate 		/* pass pre_suspend event to all the children */
1367*7c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1368*7c478bd9Sstevel@tonic-gate 		    NULL, suspend_cookie, bus_impldata);
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1371*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1372*7c478bd9Sstevel@tonic-gate 			usb_mid->mi_child_events[i] &= ~
1373*7c478bd9Sstevel@tonic-gate 			    USB_MID_CHILD_EVENT_PRESUSPEND;
1374*7c478bd9Sstevel@tonic-gate 		}
1375*7c478bd9Sstevel@tonic-gate 		break;
1376*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_HOT_INSERTION:
1377*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1378*7c478bd9Sstevel@tonic-gate 		if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) {
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 			/*
1381*7c478bd9Sstevel@tonic-gate 			 * Check to see if this child has missed the disconnect
1382*7c478bd9Sstevel@tonic-gate 			 * event before it registered for event cb
1383*7c478bd9Sstevel@tonic-gate 			 */
1384*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_mid->mi_mutex);
1385*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1386*7c478bd9Sstevel@tonic-gate 				if (usb_mid->mi_child_events[i] &
1387*7c478bd9Sstevel@tonic-gate 				    USB_MID_CHILD_EVENT_DISCONNECT) {
1388*7c478bd9Sstevel@tonic-gate 					usb_mid->mi_child_events[i] &=
1389*7c478bd9Sstevel@tonic-gate 					    ~USB_MID_CHILD_EVENT_DISCONNECT;
1390*7c478bd9Sstevel@tonic-gate 					child_dip =
1391*7c478bd9Sstevel@tonic-gate 					    usb_mid->mi_children_dips[i];
1392*7c478bd9Sstevel@tonic-gate 					mutex_exit(&usb_mid->mi_mutex);
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate 					/* post the missed disconnect */
1395*7c478bd9Sstevel@tonic-gate 					(void) ndi_event_do_callback(
1396*7c478bd9Sstevel@tonic-gate 					    usb_mid->mi_ndi_event_hdl,
1397*7c478bd9Sstevel@tonic-gate 					    child_dip,
1398*7c478bd9Sstevel@tonic-gate 					    rm_cookie,
1399*7c478bd9Sstevel@tonic-gate 					    bus_impldata);
1400*7c478bd9Sstevel@tonic-gate 					mutex_enter(&usb_mid->mi_mutex);
1401*7c478bd9Sstevel@tonic-gate 				}
1402*7c478bd9Sstevel@tonic-gate 			}
1403*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usb_mid->mi_mutex);
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 			/* pass reconnect event to all the children */
1406*7c478bd9Sstevel@tonic-gate 			(void) ndi_event_run_callbacks(
1407*7c478bd9Sstevel@tonic-gate 			    usb_mid->mi_ndi_event_hdl, NULL,
1408*7c478bd9Sstevel@tonic-gate 			    ins_cookie, bus_impldata);
1409*7c478bd9Sstevel@tonic-gate 
1410*7c478bd9Sstevel@tonic-gate 			if (usb_mid->mi_ugen_hdl) {
1411*7c478bd9Sstevel@tonic-gate 				(void) usb_ugen_reconnect_ev_cb(
1412*7c478bd9Sstevel@tonic-gate 						usb_mid->mi_ugen_hdl);
1413*7c478bd9Sstevel@tonic-gate 			}
1414*7c478bd9Sstevel@tonic-gate 		}
1415*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1416*7c478bd9Sstevel@tonic-gate 		break;
1417*7c478bd9Sstevel@tonic-gate 	case USBA_EVENT_TAG_POST_RESUME:
1418*7c478bd9Sstevel@tonic-gate 		/*
1419*7c478bd9Sstevel@tonic-gate 		 * Check to see if this child has missed the pre-suspend
1420*7c478bd9Sstevel@tonic-gate 		 * event before it registered for event cb
1421*7c478bd9Sstevel@tonic-gate 		 */
1422*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1423*7c478bd9Sstevel@tonic-gate 			if (usb_mid->mi_child_events[i] &
1424*7c478bd9Sstevel@tonic-gate 			    USB_MID_CHILD_EVENT_PRESUSPEND) {
1425*7c478bd9Sstevel@tonic-gate 				usb_mid->mi_child_events[i] &=
1426*7c478bd9Sstevel@tonic-gate 				    ~USB_MID_CHILD_EVENT_PRESUSPEND;
1427*7c478bd9Sstevel@tonic-gate 				child_dip = usb_mid->mi_children_dips[i];
1428*7c478bd9Sstevel@tonic-gate 				mutex_exit(&usb_mid->mi_mutex);
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 				/* post the missed pre-suspend event */
1431*7c478bd9Sstevel@tonic-gate 				(void) ndi_event_do_callback(
1432*7c478bd9Sstevel@tonic-gate 				    usb_mid->mi_ndi_event_hdl,
1433*7c478bd9Sstevel@tonic-gate 				    child_dip, suspend_cookie,
1434*7c478bd9Sstevel@tonic-gate 				    bus_impldata);
1435*7c478bd9Sstevel@tonic-gate 				mutex_enter(&usb_mid->mi_mutex);
1436*7c478bd9Sstevel@tonic-gate 			}
1437*7c478bd9Sstevel@tonic-gate 		}
1438*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate 		/* pass post_resume event to all the children */
1441*7c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1442*7c478bd9Sstevel@tonic-gate 		    NULL, resume_cookie, bus_impldata);
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1445*7c478bd9Sstevel@tonic-gate 		break;
1446*7c478bd9Sstevel@tonic-gate 	}
1447*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate }
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate /*
1453*7c478bd9Sstevel@tonic-gate  * register and unregister for events from our parent
1454*7c478bd9Sstevel@tonic-gate  *
1455*7c478bd9Sstevel@tonic-gate  * Note: usb_mid doesn't use the cookie fields in usba_device structure.
1456*7c478bd9Sstevel@tonic-gate  *	They are used/shared by children of usb_mid.
1457*7c478bd9Sstevel@tonic-gate  */
1458*7c478bd9Sstevel@tonic-gate static void
1459*7c478bd9Sstevel@tonic-gate usb_mid_register_events(usb_mid_t *usb_mid)
1460*7c478bd9Sstevel@tonic-gate {
1461*7c478bd9Sstevel@tonic-gate 	int rval;
1462*7c478bd9Sstevel@tonic-gate 	usba_evdata_t *evdata;
1463*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1466*7c478bd9Sstevel@tonic-gate 	    "usb_mid_register_events:");
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	evdata = usba_get_evdata(usb_mid->mi_dip);
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 	/* get event cookie, discard level and icookie for now */
1471*7c478bd9Sstevel@tonic-gate 	rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_REMOVE_EVENT,
1472*7c478bd9Sstevel@tonic-gate 		&cookie);
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
1475*7c478bd9Sstevel@tonic-gate 		rval = ddi_add_event_handler(usb_mid->mi_dip,
1476*7c478bd9Sstevel@tonic-gate 		    cookie, usb_mid_event_cb, NULL, &evdata->ev_rm_cb_id);
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_SUCCESS) {
1479*7c478bd9Sstevel@tonic-gate 
1480*7c478bd9Sstevel@tonic-gate 			goto fail;
1481*7c478bd9Sstevel@tonic-gate 		}
1482*7c478bd9Sstevel@tonic-gate 	}
1483*7c478bd9Sstevel@tonic-gate 	rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_INSERT_EVENT,
1484*7c478bd9Sstevel@tonic-gate 		&cookie);
1485*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
1486*7c478bd9Sstevel@tonic-gate 		rval = ddi_add_event_handler(usb_mid->mi_dip,
1487*7c478bd9Sstevel@tonic-gate 		    cookie, usb_mid_event_cb, NULL, &evdata->ev_ins_cb_id);
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_SUCCESS) {
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 			goto fail;
1492*7c478bd9Sstevel@tonic-gate 		}
1493*7c478bd9Sstevel@tonic-gate 	}
1494*7c478bd9Sstevel@tonic-gate 	rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_PRE_SUSPEND_EVENT,
1495*7c478bd9Sstevel@tonic-gate 		&cookie);
1496*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
1497*7c478bd9Sstevel@tonic-gate 		rval = ddi_add_event_handler(usb_mid->mi_dip,
1498*7c478bd9Sstevel@tonic-gate 		    cookie, usb_mid_event_cb, NULL, &evdata->ev_suspend_cb_id);
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_SUCCESS) {
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 			goto fail;
1503*7c478bd9Sstevel@tonic-gate 		}
1504*7c478bd9Sstevel@tonic-gate 	}
1505*7c478bd9Sstevel@tonic-gate 	rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_POST_RESUME_EVENT,
1506*7c478bd9Sstevel@tonic-gate 		&cookie);
1507*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
1508*7c478bd9Sstevel@tonic-gate 		rval = ddi_add_event_handler(usb_mid->mi_dip,
1509*7c478bd9Sstevel@tonic-gate 		    cookie, usb_mid_event_cb, NULL,
1510*7c478bd9Sstevel@tonic-gate 		    &evdata->ev_resume_cb_id);
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_SUCCESS) {
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate 			goto fail;
1515*7c478bd9Sstevel@tonic-gate 		}
1516*7c478bd9Sstevel@tonic-gate 	}
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	return;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 
1521*7c478bd9Sstevel@tonic-gate fail:
1522*7c478bd9Sstevel@tonic-gate 	usb_mid_unregister_events(usb_mid);
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate }
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate static void
1528*7c478bd9Sstevel@tonic-gate usb_mid_unregister_events(usb_mid_t *usb_mid)
1529*7c478bd9Sstevel@tonic-gate {
1530*7c478bd9Sstevel@tonic-gate 	int rval;
1531*7c478bd9Sstevel@tonic-gate 	usba_evdata_t *evdata;
1532*7c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(usb_mid->mi_dip);
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1535*7c478bd9Sstevel@tonic-gate 	    "usb_mid_unregister_events:");
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 	evdata = usba_get_evdata(usb_mid->mi_dip);
1538*7c478bd9Sstevel@tonic-gate 	if (evdata) {
1539*7c478bd9Sstevel@tonic-gate 		if (evdata->ev_rm_cb_id) {
1540*7c478bd9Sstevel@tonic-gate 			rval = ddi_remove_event_handler(evdata->ev_rm_cb_id);
1541*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1542*7c478bd9Sstevel@tonic-gate 		}
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 		if (evdata->ev_ins_cb_id) {
1545*7c478bd9Sstevel@tonic-gate 			rval = ddi_remove_event_handler(evdata->ev_ins_cb_id);
1546*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1547*7c478bd9Sstevel@tonic-gate 		}
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		if (evdata->ev_resume_cb_id) {
1550*7c478bd9Sstevel@tonic-gate 			rval =
1551*7c478bd9Sstevel@tonic-gate 			    ddi_remove_event_handler(evdata->ev_resume_cb_id);
1552*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1553*7c478bd9Sstevel@tonic-gate 		}
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 		if (evdata->ev_suspend_cb_id) {
1556*7c478bd9Sstevel@tonic-gate 			rval =
1557*7c478bd9Sstevel@tonic-gate 			    ddi_remove_event_handler(evdata->ev_suspend_cb_id);
1558*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1559*7c478bd9Sstevel@tonic-gate 		}
1560*7c478bd9Sstevel@tonic-gate 	}
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	/* clear event data for children, required for cfgmadm unconfigure */
1563*7c478bd9Sstevel@tonic-gate 	usba_free_evdata(usba_device->usb_evdata);
1564*7c478bd9Sstevel@tonic-gate 	usba_device->usb_evdata = NULL;
1565*7c478bd9Sstevel@tonic-gate 	usba_device->rm_cookie = NULL;
1566*7c478bd9Sstevel@tonic-gate 	usba_device->ins_cookie = NULL;
1567*7c478bd9Sstevel@tonic-gate 	usba_device->suspend_cookie = NULL;
1568*7c478bd9Sstevel@tonic-gate 	usba_device->resume_cookie = NULL;
1569*7c478bd9Sstevel@tonic-gate }
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate /*
1573*7c478bd9Sstevel@tonic-gate  * create the pm components required for power management
1574*7c478bd9Sstevel@tonic-gate  */
1575*7c478bd9Sstevel@tonic-gate static void
1576*7c478bd9Sstevel@tonic-gate usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid)
1577*7c478bd9Sstevel@tonic-gate {
1578*7c478bd9Sstevel@tonic-gate 	usb_mid_power_t	*midpm;
1579*7c478bd9Sstevel@tonic-gate 	uint_t		pwr_states;
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1582*7c478bd9Sstevel@tonic-gate 	    "usb_mid_create_pm_components: Begin");
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 	/* Allocate the PM state structure */
1585*7c478bd9Sstevel@tonic-gate 	midpm = kmem_zalloc(sizeof (usb_mid_power_t), KM_SLEEP);
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usb_mid->mi_mutex);
1588*7c478bd9Sstevel@tonic-gate 	usb_mid->mi_pm = midpm;
1589*7c478bd9Sstevel@tonic-gate 	midpm->mip_usb_mid = usb_mid;
1590*7c478bd9Sstevel@tonic-gate 	midpm->mip_pm_capabilities = 0; /* XXXX should this be 0?? */
1591*7c478bd9Sstevel@tonic-gate 	midpm->mip_current_power = USB_DEV_OS_FULL_PWR;
1592*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usb_mid->mi_mutex);
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	/*
1595*7c478bd9Sstevel@tonic-gate 	 * By not enabling parental notification, PM enforces
1596*7c478bd9Sstevel@tonic-gate 	 * "strict parental dependency" meaning, usb_mid won't
1597*7c478bd9Sstevel@tonic-gate 	 * power off until any of its children are in full power.
1598*7c478bd9Sstevel@tonic-gate 	 */
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	/*
1601*7c478bd9Sstevel@tonic-gate 	 * there are 3 scenarios:
1602*7c478bd9Sstevel@tonic-gate 	 * 1. a well behaved device should have remote wakeup
1603*7c478bd9Sstevel@tonic-gate 	 * at interface and device level. If the interface
1604*7c478bd9Sstevel@tonic-gate 	 * wakes up, usb_mid will wake up
1605*7c478bd9Sstevel@tonic-gate 	 * 2. if the device doesn't have remote wake up and
1606*7c478bd9Sstevel@tonic-gate 	 * the interface has, PM will still work, ie.
1607*7c478bd9Sstevel@tonic-gate 	 * the interfaces wakes up and usb_mid wakes up
1608*7c478bd9Sstevel@tonic-gate 	 * 3. if neither the interface nor device has remote
1609*7c478bd9Sstevel@tonic-gate 	 * wakeup, the interface will wake up when it is opened
1610*7c478bd9Sstevel@tonic-gate 	 * and goes to sleep after being closed for a while
1611*7c478bd9Sstevel@tonic-gate 	 * In this case usb_mid should also go to sleep shortly
1612*7c478bd9Sstevel@tonic-gate 	 * thereafter
1613*7c478bd9Sstevel@tonic-gate 	 * In all scenarios it doesn't really matter whether
1614*7c478bd9Sstevel@tonic-gate 	 * remote wakeup at the device level is enabled or not
1615*7c478bd9Sstevel@tonic-gate 	 * but we do it anyways
1616*7c478bd9Sstevel@tonic-gate 	 */
1617*7c478bd9Sstevel@tonic-gate 	if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1618*7c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
1619*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1620*7c478bd9Sstevel@tonic-gate 		    "usb_mid_create_pm_components: "
1621*7c478bd9Sstevel@tonic-gate 		    "Remote Wakeup Enabled");
1622*7c478bd9Sstevel@tonic-gate 		midpm->mip_wakeup_enabled = 1;
1623*7c478bd9Sstevel@tonic-gate 	}
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
1626*7c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
1627*7c478bd9Sstevel@tonic-gate 		midpm->mip_pwr_states = (uint8_t)pwr_states;
1628*7c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1629*7c478bd9Sstevel@tonic-gate 	}
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1632*7c478bd9Sstevel@tonic-gate 	    "usb_mid_create_pm_components: End");
1633*7c478bd9Sstevel@tonic-gate }
1634*7c478bd9Sstevel@tonic-gate 
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate /*
1637*7c478bd9Sstevel@tonic-gate  * usb_mid_obtain_state:
1638*7c478bd9Sstevel@tonic-gate  */
1639*7c478bd9Sstevel@tonic-gate usb_mid_t *
1640*7c478bd9Sstevel@tonic-gate usb_mid_obtain_state(dev_info_t *dip)
1641*7c478bd9Sstevel@tonic-gate {
1642*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
1643*7c478bd9Sstevel@tonic-gate 	usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance);
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 	ASSERT(statep != NULL);
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	return (statep);
1648*7c478bd9Sstevel@tonic-gate }
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate /*
1652*7c478bd9Sstevel@tonic-gate  * ugen support
1653*7c478bd9Sstevel@tonic-gate  */
1654*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
1655*7c478bd9Sstevel@tonic-gate static int
1656*7c478bd9Sstevel@tonic-gate usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1657*7c478bd9Sstevel@tonic-gate {
1658*7c478bd9Sstevel@tonic-gate 	struct usb_mid *usb_mid;
1659*7c478bd9Sstevel@tonic-gate 	int	rval;
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 	if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1662*7c478bd9Sstevel@tonic-gate 	    USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1665*7c478bd9Sstevel@tonic-gate 	}
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle,
1668*7c478bd9Sstevel@tonic-gate 	    "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx", usb_mid, *devp);
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate 	/* First bring the device to full power */
1671*7c478bd9Sstevel@tonic-gate 	(void) pm_busy_component(usb_mid->mi_dip, 0);
1672*7c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR);
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp,
1676*7c478bd9Sstevel@tonic-gate 								credp);
1677*7c478bd9Sstevel@tonic-gate 	if (rval) {
1678*7c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(usb_mid->mi_dip, 0);
1679*7c478bd9Sstevel@tonic-gate 	} else {
1680*7c478bd9Sstevel@tonic-gate 		/*
1681*7c478bd9Sstevel@tonic-gate 		 * since all ugen opens are exclusive we can count the
1682*7c478bd9Sstevel@tonic-gate 		 * opens
1683*7c478bd9Sstevel@tonic-gate 		 */
1684*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1685*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_ugen_open_count++;
1686*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1687*7c478bd9Sstevel@tonic-gate 	}
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 	return (rval);
1690*7c478bd9Sstevel@tonic-gate }
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1694*7c478bd9Sstevel@tonic-gate static int
1695*7c478bd9Sstevel@tonic-gate usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp)
1696*7c478bd9Sstevel@tonic-gate {
1697*7c478bd9Sstevel@tonic-gate 	struct usb_mid *usb_mid;
1698*7c478bd9Sstevel@tonic-gate 	int rval;
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1701*7c478bd9Sstevel@tonic-gate 	    USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1704*7c478bd9Sstevel@tonic-gate 	}
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 	rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp,
1707*7c478bd9Sstevel@tonic-gate 								credp);
1708*7c478bd9Sstevel@tonic-gate 	if (rval == 0) {
1709*7c478bd9Sstevel@tonic-gate 		(void) pm_idle_component(usb_mid->mi_dip, 0);
1710*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_mid->mi_mutex);
1711*7c478bd9Sstevel@tonic-gate 		usb_mid->mi_ugen_open_count--;
1712*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_mid->mi_mutex);
1713*7c478bd9Sstevel@tonic-gate 	}
1714*7c478bd9Sstevel@tonic-gate 
1715*7c478bd9Sstevel@tonic-gate 	return (rval);
1716*7c478bd9Sstevel@tonic-gate }
1717*7c478bd9Sstevel@tonic-gate 
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate static int
1720*7c478bd9Sstevel@tonic-gate usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp)
1721*7c478bd9Sstevel@tonic-gate {
1722*7c478bd9Sstevel@tonic-gate 	struct usb_mid *usb_mid;
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 	if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1725*7c478bd9Sstevel@tonic-gate 	    USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1728*7c478bd9Sstevel@tonic-gate 	}
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate 	return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp));
1731*7c478bd9Sstevel@tonic-gate }
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate static int
1735*7c478bd9Sstevel@tonic-gate usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp)
1736*7c478bd9Sstevel@tonic-gate {
1737*7c478bd9Sstevel@tonic-gate 	struct usb_mid *usb_mid;
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 	if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1740*7c478bd9Sstevel@tonic-gate 	    USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1741*7c478bd9Sstevel@tonic-gate 
1742*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1743*7c478bd9Sstevel@tonic-gate 	}
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 	return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp));
1746*7c478bd9Sstevel@tonic-gate }
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate static int
1750*7c478bd9Sstevel@tonic-gate usb_mid_poll(dev_t dev, short events, int anyyet,  short *reventsp,
1751*7c478bd9Sstevel@tonic-gate     struct pollhead **phpp)
1752*7c478bd9Sstevel@tonic-gate {
1753*7c478bd9Sstevel@tonic-gate 	struct usb_mid *usb_mid;
1754*7c478bd9Sstevel@tonic-gate 
1755*7c478bd9Sstevel@tonic-gate 	if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1756*7c478bd9Sstevel@tonic-gate 	    USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1759*7c478bd9Sstevel@tonic-gate 	}
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 	return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events,
1762*7c478bd9Sstevel@tonic-gate 						anyyet, reventsp, phpp));
1763*7c478bd9Sstevel@tonic-gate }
1764