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
45void usba_free_evdata(usba_evdata_t *);
46
47/* Debugging support */
48uint_t usb_mid_errlevel = USB_LOG_L4;
49uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL;
50uint_t usb_mid_instance_debug = (uint_t)-1;
51uint_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 */
65static int usb_mid_open(dev_t *, int, int, cred_t *);
66static int usb_mid_close(dev_t, int, int, cred_t *);
67static int usb_mid_read(dev_t, struct uio *, cred_t *);
68static int usb_mid_write(dev_t, struct uio *, cred_t *);
69static int usb_mid_poll(dev_t, short, int,  short *,
70					struct pollhead **);
71
72static 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
90static int usb_mid_busop_get_eventcookie(dev_info_t *dip,
91			dev_info_t *rdip,
92			char *eventname,
93			ddi_eventcookie_t *cookie);
94static 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);
101static int usb_mid_busop_remove_eventcall(dev_info_t *dip,
102			ddi_callback_id_t cb_id);
103static int usb_mid_busop_post_event(dev_info_t *dip,
104			dev_info_t *rdip,
105			ddi_eventcookie_t cookie,
106			void *bus_impldata);
107static 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);
112static 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 */
121static int	usb_mid_info(dev_info_t *, ddi_info_cmd_t,
122				void *, void **);
123static int	usb_mid_attach(dev_info_t *, ddi_attach_cmd_t);
124static int	usb_mid_detach(dev_info_t *, ddi_detach_cmd_t);
125
126/* other routines */
127static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *);
128static int usb_mid_bus_ctl(dev_info_t *, dev_info_t	*,
129				ddi_ctl_enum_t, void *, void *);
130static int usb_mid_power(dev_info_t *, int, int);
131static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *);
132static usb_mid_t  *usb_mid_obtain_state(dev_info_t *);
133static void usb_mid_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
134
135/*
136 * Busops vector
137 */
138static 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
170static 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	ddi_quiesce_not_needed,		/* quiesce */
183};
184
185static struct modldrv modldrv = {
186	&mod_driverops, /* Type of module. This one is a driver */
187	"USB Multi Interface Driver", /* Name of the module. */
188	&usb_mid_ops,	/* driver ops */
189};
190
191static struct modlinkage modlinkage = {
192	MODREV_1, (void *)&modldrv, NULL
193};
194
195#define	USB_MID_INITIAL_SOFT_SPACE 4
196static	void	*usb_mid_statep;
197
198
199/*
200 * prototypes
201 */
202static void usb_mid_create_children(usb_mid_t *usb_mid);
203static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t	*usb_mid);
204
205/*
206 * event definition
207 */
208static 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
222static	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 */
229int
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
249int
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
266int
267_info(struct modinfo *modinfop)
268{
269	return (mod_info(&modlinkage, modinfop));
270}
271
272
273/*ARGSUSED*/
274static int
275usb_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 */
310static void
311usb_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
332static void
333usb_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*/
364static int
365usb_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 */
429static int
430usb_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
457static int
458usb_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 */
526static int
527usb_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 */
565static int
566usb_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
698fail:
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 */
711static int
712usb_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 * 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*/
753static int
754usb_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
849done:
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
866static void
867usb_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 */
913static void
914usb_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 */
1044static int
1045usb_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
1064static int
1065usb_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
1112static int
1113usb_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
1137static int
1138usb_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 */
1165static int
1166usb_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 */
1216static void
1217usb_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 */
1367static void
1368usb_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 */
1431usb_mid_t *
1432usb_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 */
1447static int
1448usb_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 */
1487static int
1488usb_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
1512static int
1513usb_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
1527static int
1528usb_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
1542static int
1543usb_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