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