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