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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
27  */
28 
29 /*
30  * Copyright 2023 Oxide Computer Company
31  */
32 
33 /*
34  * usb interface association driver
35  *
36  *	this driver attempts to the interface association node and
37  *	creates/manages child nodes for the included interfaces.
38  */
39 
40 #if defined(lint) && !defined(DEBUG)
41 #define	DEBUG	1
42 #endif
43 #include <sys/usb/usba/usbai_version.h>
44 #include <sys/usb/usba.h>
45 #include <sys/usb/usba/usba_types.h>
46 #include <sys/usb/usba/usba_impl.h>
47 #include <sys/usb/usb_ia/usb_iavar.h>
48 
49 /* Debugging support */
50 uint_t usb_ia_errlevel = USB_LOG_L4;
51 uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL;
52 uint_t usb_ia_instance_debug = (uint_t)-1;
53 uint_t usb_ia_bus_config_debug = 0;
54 
55 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel))
56 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask))
57 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug))
58 
59 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
60 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
61 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
62 
63 static struct cb_ops usb_ia_cb_ops = {
64 	nodev,		/* open */
65 	nodev,		/* close */
66 	nodev,		/* strategy */
67 	nodev,		/* print */
68 	nodev,		/* dump */
69 	nodev,		/* read */
70 	nodev,		/* write */
71 	nodev,		/* ioctl */
72 	nodev,		/* devmap */
73 	nodev,		/* mmap */
74 	nodev,		/* segmap */
75 	nochpoll,	/* poll */
76 	ddi_prop_op,	/* prop_op */
77 	NULL,		/* aread */
78 	D_MP
79 };
80 
81 static int usb_ia_busop_get_eventcookie(dev_info_t *dip,
82 			dev_info_t *rdip,
83 			char *eventname,
84 			ddi_eventcookie_t *cookie);
85 static int usb_ia_busop_add_eventcall(dev_info_t *dip,
86 			dev_info_t *rdip,
87 			ddi_eventcookie_t cookie,
88 			ddi_event_cb_f,
89 			void *arg, ddi_callback_id_t *cb_id);
90 static int usb_ia_busop_remove_eventcall(dev_info_t *dip,
91 			ddi_callback_id_t cb_id);
92 static int usb_ia_busop_post_event(dev_info_t *dip,
93 			dev_info_t *rdip,
94 			ddi_eventcookie_t cookie,
95 			void *bus_impldata);
96 static int usb_ia_bus_config(dev_info_t *dip,
97 			uint_t flag,
98 			ddi_bus_config_op_t op,
99 			void *arg,
100 			dev_info_t **child);
101 static int usb_ia_bus_unconfig(dev_info_t *dip,
102 			uint_t flag,
103 			ddi_bus_config_op_t op,
104 			void *arg);
105 
106 /*
107  * autoconfiguration data and routines.
108  */
109 static int	usb_ia_info(dev_info_t *, ddi_info_cmd_t,
110 				void *, void **);
111 static int	usb_ia_attach(dev_info_t *, ddi_attach_cmd_t);
112 static int	usb_ia_detach(dev_info_t *, ddi_detach_cmd_t);
113 
114 /* other routines */
115 static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *);
116 static int usb_ia_bus_ctl(dev_info_t *, dev_info_t	*,
117 				ddi_ctl_enum_t, void *, void *);
118 static int usb_ia_power(dev_info_t *, int, int);
119 static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *);
120 static usb_ia_t  *usb_ia_obtain_state(dev_info_t *);
121 static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
122 
123 /* prototypes */
124 static void usb_ia_create_children(usb_ia_t *);
125 static int usb_ia_cleanup(usb_ia_t *);
126 
127 /*
128  * Busops vector
129  */
130 static struct bus_ops usb_ia_busops = {
131 	BUSO_REV,
132 	nullbusmap,			/* bus_map */
133 	NULL,				/* bus_get_intrspec */
134 	NULL,				/* bus_add_intrspec */
135 	NULL,				/* bus_remove_intrspec */
136 	NULL,				/* XXXX bus_map_fault */
137 	NULL,				/* bus_dma_map */
138 	ddi_dma_allochdl,
139 	ddi_dma_freehdl,
140 	ddi_dma_bindhdl,
141 	ddi_dma_unbindhdl,
142 	ddi_dma_flush,
143 	ddi_dma_win,
144 	ddi_dma_mctl,			/* bus_dma_ctl */
145 	usb_ia_bus_ctl,		/* bus_ctl */
146 	ddi_bus_prop_op,		/* bus_prop_op */
147 	usb_ia_busop_get_eventcookie,
148 	usb_ia_busop_add_eventcall,
149 	usb_ia_busop_remove_eventcall,
150 	usb_ia_busop_post_event,	/* bus_post_event */
151 	NULL,				/* bus_intr_ctl */
152 	usb_ia_bus_config,		/* bus_config */
153 	usb_ia_bus_unconfig,		/* bus_unconfig */
154 	NULL,				/* bus_fm_init */
155 	NULL,				/* bus_fm_fini */
156 	NULL,				/* bus_fm_access_enter */
157 	NULL,				/* bus_fm_access_exit */
158 	NULL				/* bus_power */
159 };
160 
161 
162 static struct dev_ops usb_ia_ops = {
163 	DEVO_REV,		/* devo_rev, */
164 	0,			/* refcnt  */
165 	usb_ia_info,		/* info */
166 	nulldev,		/* identify */
167 	nulldev,		/* probe */
168 	usb_ia_attach,		/* attach */
169 	usb_ia_detach,		/* detach */
170 	nodev,			/* reset */
171 	&usb_ia_cb_ops,	/* driver operations */
172 	&usb_ia_busops,	/* bus operations */
173 	usb_ia_power,		/* power */
174 	ddi_quiesce_not_needed,	/* devo_quiesce */
175 };
176 
177 static struct modldrv modldrv = {
178 	&mod_driverops, /* Type of module. This one is a driver */
179 	"USB Interface Association Driver", /* Name of the module. */
180 	&usb_ia_ops,	/* driver ops */
181 };
182 
183 static struct modlinkage modlinkage = {
184 	MODREV_1, (void *)&modldrv, NULL
185 };
186 
187 #define	USB_IA_INITIAL_SOFT_SPACE 4
188 static	void	*usb_ia_statep;
189 
190 /*
191  * event definition
192  */
193 static ndi_event_definition_t usb_ia_ndi_event_defs[] = {
194 	{USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
195 						NDI_EVENT_POST_TO_ALL},
196 	{USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
197 						NDI_EVENT_POST_TO_ALL},
198 	{USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
199 						NDI_EVENT_POST_TO_ALL},
200 	{USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
201 						NDI_EVENT_POST_TO_ALL}
202 };
203 
204 #define	USB_IA_N_NDI_EVENTS \
205 	(sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
206 
207 static	ndi_event_set_t usb_ia_ndi_events = {
208 	NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs};
209 
210 
211 /*
212  * standard driver entry points
213  */
214 int
_init(void)215 _init(void)
216 {
217 	int rval;
218 
219 	rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia),
220 	    USB_IA_INITIAL_SOFT_SPACE);
221 	if (rval != 0) {
222 		return (rval);
223 	}
224 
225 	if ((rval = mod_install(&modlinkage)) != 0) {
226 		ddi_soft_state_fini(&usb_ia_statep);
227 		return (rval);
228 	}
229 
230 	return (rval);
231 }
232 
233 
234 int
_fini(void)235 _fini(void)
236 {
237 	int	rval;
238 
239 	rval = mod_remove(&modlinkage);
240 
241 	if (rval) {
242 		return (rval);
243 	}
244 
245 	ddi_soft_state_fini(&usb_ia_statep);
246 
247 	return (rval);
248 }
249 
250 
251 int
_info(struct modinfo * modinfop)252 _info(struct modinfo *modinfop)
253 {
254 	return (mod_info(&modlinkage, modinfop));
255 }
256 
257 
258 /*ARGSUSED*/
259 static int
usb_ia_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)260 usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
261 {
262 	usb_ia_t	*usb_ia;
263 	int		instance = getminor((dev_t)arg);
264 	int		error = DDI_FAILURE;
265 
266 	switch (infocmd) {
267 	case DDI_INFO_DEVT2DEVINFO:
268 		if ((usb_ia = ddi_get_soft_state(usb_ia_statep,
269 		    instance)) != NULL) {
270 			*result = (void *)usb_ia->ia_dip;
271 			if (*result != NULL) {
272 				error = DDI_SUCCESS;
273 			}
274 		} else {
275 			*result = NULL;
276 		}
277 		break;
278 
279 	case DDI_INFO_DEVT2INSTANCE:
280 		*result = (void *)(intptr_t)instance;
281 		error = DDI_SUCCESS;
282 		break;
283 	default:
284 		break;
285 	}
286 
287 	return (error);
288 }
289 
290 
291 /*
292  * child  post attach/detach notification
293  */
294 static void
usb_ia_post_attach(usb_ia_t * usb_ia,uint8_t ifno,struct attachspec * as)295 usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as)
296 {
297 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
298 	    "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result);
299 
300 }
301 
302 
303 static void
usb_ia_post_detach(usb_ia_t * usb_ia,uint8_t ifno,struct detachspec * ds)304 usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds)
305 {
306 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
307 	    "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result);
308 
309 }
310 
311 
312 /*
313  * bus ctl support. we handle notifications here and the
314  * rest goes up to root hub/hcd
315  */
316 /*ARGSUSED*/
317 static int
usb_ia_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)318 usb_ia_bus_ctl(dev_info_t *dip,
319     dev_info_t	*rdip,
320     ddi_ctl_enum_t	op,
321     void		*arg,
322     void		*result)
323 {
324 	usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
325 	dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
326 	usb_ia_t  *usb_ia;
327 	struct attachspec *as;
328 	struct detachspec *ds;
329 
330 	usb_ia = usb_ia_obtain_state(dip);
331 
332 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
333 	    "usb_ia_bus_ctl:\n\t"
334 	    "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
335 	    (void *)dip, (void *)rdip, op, arg);
336 
337 	switch (op) {
338 	case DDI_CTLOPS_ATTACH:
339 		as = (struct attachspec *)arg;
340 
341 		switch (as->when) {
342 		case DDI_PRE :
343 			/* nothing to do basically */
344 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
345 			    "DDI_PRE DDI_CTLOPS_ATTACH");
346 			break;
347 		case DDI_POST :
348 			usb_ia_post_attach(usb_ia, usba_get_ifno(rdip),
349 			    (struct attachspec *)arg);
350 			break;
351 		}
352 
353 		break;
354 	case DDI_CTLOPS_DETACH:
355 		ds = (struct detachspec *)arg;
356 
357 		switch (ds->when) {
358 		case DDI_PRE :
359 			/* nothing to do basically */
360 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
361 			    "DDI_PRE DDI_CTLOPS_DETACH");
362 			break;
363 		case DDI_POST :
364 			usb_ia_post_detach(usb_ia, usba_get_ifno(rdip),
365 			    (struct detachspec *)arg);
366 			break;
367 		}
368 
369 		break;
370 	default:
371 		/* pass to root hub to handle */
372 		return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
373 	}
374 
375 	return (DDI_SUCCESS);
376 }
377 
378 
379 /*
380  * bus enumeration entry points
381  */
382 static int
usb_ia_bus_config(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg,dev_info_t ** child)383 usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
384     void *arg, dev_info_t **child)
385 {
386 	int		rval;
387 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
388 
389 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
390 	    "usb_ia_bus_config: op=%d", op);
391 
392 	if (usb_ia_bus_config_debug) {
393 		flag |= NDI_DEVI_DEBUG;
394 	}
395 
396 	ndi_devi_enter(dip);
397 
398 	/* enumerate each interface below us */
399 	mutex_enter(&usb_ia->ia_mutex);
400 	usb_ia_create_children(usb_ia);
401 	mutex_exit(&usb_ia->ia_mutex);
402 
403 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
404 	ndi_devi_exit(dip);
405 
406 	return (rval);
407 }
408 
409 
410 static int
usb_ia_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)411 usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
412     void *arg)
413 {
414 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
415 
416 	dev_info_t	*cdip, *mdip;
417 	int		interface;
418 	int		rval = NDI_SUCCESS;
419 
420 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
421 	    "usb_ia_bus_unconfig: op=%d", op);
422 
423 	if (usb_ia_bus_config_debug) {
424 		flag |= NDI_DEVI_DEBUG;
425 	}
426 
427 	/*
428 	 * first offline and if offlining successful, then
429 	 * remove children
430 	 */
431 	if (op == BUS_UNCONFIG_ALL) {
432 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
433 	}
434 
435 	ndi_devi_enter(dip);
436 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
437 
438 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
439 	    (flag & NDI_AUTODETACH) == 0) {
440 		flag |= NDI_DEVI_REMOVE;
441 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
442 	}
443 
444 	/* update children's list */
445 	mutex_enter(&usb_ia->ia_mutex);
446 	for (interface = 0; usb_ia->ia_children_dips &&
447 	    (interface < usb_ia->ia_n_ifs); interface++) {
448 		mdip = usb_ia->ia_children_dips[interface];
449 
450 		/* now search if this dip still exists */
451 		for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
452 			cdip = ddi_get_next_sibling(cdip);
453 
454 		if (cdip != mdip) {
455 			/* we lost the dip on this interface */
456 			usb_ia->ia_children_dips[interface] = NULL;
457 		} else if (cdip) {
458 			/*
459 			 * keep in DS_INITALIZED to prevent parent
460 			 * from detaching
461 			 */
462 			(void) ddi_initchild(ddi_get_parent(cdip), cdip);
463 		}
464 	}
465 	mutex_exit(&usb_ia->ia_mutex);
466 
467 	ndi_devi_exit(dip);
468 
469 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
470 	    "usb_ia_bus_config: rval=%d", rval);
471 
472 	return (rval);
473 }
474 
475 
476 /* power entry point */
477 /* ARGSUSED */
478 static int
usb_ia_power(dev_info_t * dip,int comp,int level)479 usb_ia_power(dev_info_t *dip, int comp, int level)
480 {
481 	usb_ia_t		*usb_ia;
482 	usb_common_power_t	*pm;
483 	int			rval = DDI_FAILURE;
484 
485 	usb_ia = usb_ia_obtain_state(dip);
486 
487 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
488 	    "usb_ia_power: Begin: usb_ia = %p, level = %d",
489 	    (void *)usb_ia, level);
490 
491 	mutex_enter(&usb_ia->ia_mutex);
492 	pm = usb_ia->ia_pm;
493 
494 	/* check if we are transitioning to a legal power level */
495 	if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) {
496 		USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
497 		    "usb_ia_power: illegal power level = %d "
498 		    "uc_pwr_states = %x", level, pm->uc_pwr_states);
499 
500 		mutex_exit(&usb_ia->ia_mutex);
501 
502 		return (rval);
503 	}
504 
505 	rval = usba_common_power(dip, &(pm->uc_current_power),
506 	    &(usb_ia->ia_dev_state), level);
507 
508 	mutex_exit(&usb_ia->ia_mutex);
509 
510 	return (rval);
511 }
512 
513 /*
514  * attach/resume entry point
515  */
516 static int
usb_ia_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)517 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
518 {
519 	int		instance = ddi_get_instance(dip);
520 	usb_ia_t	*usb_ia = NULL;
521 	uint_t		n_ifs;
522 	size_t		size;
523 
524 	switch (cmd) {
525 	case DDI_ATTACH:
526 
527 		break;
528 	case DDI_RESUME:
529 		usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
530 		(void) usb_ia_restore_device_state(dip, usb_ia);
531 
532 		return (DDI_SUCCESS);
533 	default:
534 
535 		return (DDI_FAILURE);
536 	}
537 
538 	/*
539 	 * Attach:
540 	 *
541 	 * Allocate soft state and initialize
542 	 */
543 	if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) {
544 		goto fail;
545 	}
546 
547 	usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
548 	if (usb_ia == NULL) {
549 
550 		goto fail;
551 	}
552 
553 	/* allocate handle for logging of messages */
554 	usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia",
555 	    &usb_ia_errlevel,
556 	    &usb_ia_errmask, &usb_ia_instance_debug,
557 	    0);
558 
559 	usb_ia->ia_dip	= dip;
560 	usb_ia->ia_instance = instance;
561 	usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
562 	    DDI_PROP_DONTPASS, "interface", -1);
563 	usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
564 	    DDI_PROP_DONTPASS, "interface-count", -1);
565 
566 	if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) {
567 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
568 		    "interface-association property failed");
569 
570 		goto fail;
571 	}
572 
573 	/* attach client driver to USBA */
574 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
575 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
576 		    "usb_client_attach failed");
577 		goto fail;
578 	}
579 	if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE,
580 	    0) != USB_SUCCESS) {
581 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
582 		    "usb_get_dev_data failed");
583 		goto fail;
584 	}
585 
586 	mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER,
587 	    usb_ia->ia_dev_data->dev_iblock_cookie);
588 
589 	usb_free_dev_data(dip, usb_ia->ia_dev_data);
590 	usb_ia->ia_dev_data = NULL;
591 
592 	usb_ia->ia_init_state |= USB_IA_LOCK_INIT;
593 
594 	if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance,
595 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
596 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
597 		    "cannot create devctl minor node");
598 		goto fail;
599 	}
600 
601 	usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED;
602 
603 	/*
604 	 * allocate array for keeping track of child dips
605 	 */
606 	n_ifs = usb_ia->ia_n_ifs;
607 	usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
608 
609 	usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP);
610 	usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
611 	    KM_SLEEP);
612 	/*
613 	 * Event handling: definition and registration
614 	 * get event handle for events that we have defined
615 	 */
616 	(void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl,
617 	    NDI_SLEEP);
618 
619 	/* bind event set to the handle */
620 	if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events,
621 	    NDI_SLEEP)) {
622 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
623 		    "usb_ia_attach: binding event set failed");
624 
625 		goto fail;
626 	}
627 
628 	usb_ia->ia_dev_state = USB_DEV_ONLINE;
629 
630 	/*
631 	 * now create components to power manage this device
632 	 * before attaching children
633 	 */
634 	usb_ia_create_pm_components(dip, usb_ia);
635 
636 	/* event registration for events from our parent */
637 	usba_common_register_events(dip, n_ifs, usb_ia_event_cb);
638 
639 	usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED;
640 
641 	ddi_report_dev(dip);
642 
643 	return (DDI_SUCCESS);
644 
645 fail:
646 	USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach",
647 	    instance);
648 
649 	if (usb_ia) {
650 		(void) usb_ia_cleanup(usb_ia);
651 	}
652 
653 	return (DDI_FAILURE);
654 }
655 
656 
657 /* detach or suspend this instance */
658 static int
usb_ia_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)659 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
660 {
661 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
662 
663 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
664 	    "usb_ia_detach: cmd = 0x%x", cmd);
665 
666 	switch (cmd) {
667 	case DDI_DETACH:
668 
669 		return (usb_ia_cleanup(usb_ia));
670 	case DDI_SUSPEND:
671 		/* nothing to do */
672 		mutex_enter(&usb_ia->ia_mutex);
673 		usb_ia->ia_dev_state = USB_DEV_SUSPENDED;
674 		mutex_exit(&usb_ia->ia_mutex);
675 
676 		return (DDI_SUCCESS);
677 	default:
678 
679 		return (DDI_FAILURE);
680 	}
681 
682 	_NOTE(NOT_REACHED)
683 	/* NOTREACHED */
684 }
685 
686 
687 /*
688  * usb_ia_cleanup:
689  *	cleanup usb_ia and deallocate. this function is called for
690  *	handling attach failures and detaching including dynamic
691  *	reconfiguration
692  */
693 /*ARGSUSED*/
694 static int
usb_ia_cleanup(usb_ia_t * usb_ia)695 usb_ia_cleanup(usb_ia_t *usb_ia)
696 {
697 	usb_common_power_t	*iapm;
698 	int			rval;
699 	dev_info_t	*dip = usb_ia->ia_dip;
700 
701 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
702 	    "usb_ia_cleanup:");
703 
704 	if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) {
705 
706 		goto done;
707 	}
708 
709 	/*
710 	 * deallocate events, if events are still registered
711 	 * (ie. children still attached) then we have to fail the detach
712 	 */
713 	if (usb_ia->ia_ndi_event_hdl &&
714 	    (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) {
715 
716 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
717 		    "usb_ia_cleanup: ndi_event_free_hdl failed");
718 
719 		return (DDI_FAILURE);
720 	}
721 
722 	/*
723 	 * Disable the event callbacks, after this point, event
724 	 * callbacks will never get called. Note we shouldn't hold
725 	 * mutex while unregistering events because there may be a
726 	 * competing event callback thread. Event callbacks are done
727 	 * with ndi mutex held and this can cause a potential deadlock.
728 	 * Note that cleanup can't fail after deregistration of events.
729 	 */
730 	if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) {
731 
732 		usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs);
733 	}
734 
735 	iapm = usb_ia->ia_pm;
736 
737 	mutex_enter(&usb_ia->ia_mutex);
738 
739 	if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) {
740 
741 		mutex_exit(&usb_ia->ia_mutex);
742 
743 		(void) pm_busy_component(dip, 0);
744 		if (iapm->uc_wakeup_enabled) {
745 
746 			/* First bring the device to full power */
747 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
748 
749 			rval = usb_handle_remote_wakeup(dip,
750 			    USB_REMOTE_WAKEUP_DISABLE);
751 
752 			if (rval != DDI_SUCCESS) {
753 				USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
754 				    usb_ia->ia_log_handle,
755 				    "usb_cleanup: disable remote "
756 				    "wakeup failed, rval=%d", rval);
757 			}
758 		}
759 
760 		(void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF);
761 		(void) pm_idle_component(dip, 0);
762 	} else {
763 		mutex_exit(&usb_ia->ia_mutex);
764 	}
765 
766 	if (iapm) {
767 		kmem_free(iapm, sizeof (usb_common_power_t));
768 	}
769 
770 	/* free children list */
771 	if (usb_ia->ia_children_dips) {
772 		kmem_free(usb_ia->ia_children_dips,
773 		    usb_ia->ia_cd_list_length);
774 	}
775 
776 	if (usb_ia->ia_child_events) {
777 		kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) *
778 		    usb_ia->ia_n_ifs);
779 	}
780 
781 	if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) {
782 		ddi_remove_minor_node(dip, NULL);
783 	}
784 
785 	mutex_destroy(&usb_ia->ia_mutex);
786 
787 done:
788 	usb_client_detach(dip, usb_ia->ia_dev_data);
789 
790 	usb_free_log_hdl(usb_ia->ia_log_handle);
791 	ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip));
792 
793 	ddi_prop_remove_all(dip);
794 
795 	return (DDI_SUCCESS);
796 }
797 
798 /*
799  * usb_ia_create_children:
800  */
801 static void
usb_ia_create_children(usb_ia_t * usb_ia)802 usb_ia_create_children(usb_ia_t *usb_ia)
803 {
804 	usba_device_t		*usba_device;
805 	uint_t			n_ifs, first_if;
806 	uint_t			i;
807 	dev_info_t		*cdip;
808 
809 	usba_device = usba_get_usba_device(usb_ia->ia_dip);
810 
811 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
812 	    "usb_ia_attach_child_drivers: port = %d, address = %d",
813 	    usba_device->usb_port, usba_device->usb_addr);
814 
815 	n_ifs = usb_ia->ia_n_ifs;
816 	first_if = usb_ia->ia_first_if;
817 
818 	/*
819 	 * create all children if not already present
820 	 */
821 	for (i = 0; i < n_ifs; i++) {
822 		if (usb_ia->ia_children_dips[i] != NULL) {
823 
824 			continue;
825 		}
826 
827 		mutex_exit(&usb_ia->ia_mutex);
828 		cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i);
829 		mutex_enter(&usb_ia->ia_mutex);
830 
831 		if (cdip != NULL) {
832 			(void) usba_bind_driver(cdip);
833 			usb_ia->ia_children_dips[i] = cdip;
834 		}
835 	}
836 
837 }
838 
839 
840 /*
841  * event support
842  */
843 static int
usb_ia_busop_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * cookie)844 usb_ia_busop_get_eventcookie(dev_info_t *dip,
845     dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
846 {
847 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
848 
849 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
850 	    "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
851 	    "event=%s", (void *)dip, (void *)rdip, eventname);
852 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
853 	    "(dip=%s%d rdip=%s%d)",
854 	    ddi_driver_name(dip), ddi_get_instance(dip),
855 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
856 
857 	/* return event cookie, iblock cookie, and level */
858 	return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl,
859 	    rdip, eventname, cookie, NDI_EVENT_NOPASS));
860 }
861 
862 
863 static int
usb_ia_busop_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,ddi_event_cb_f callback,void * arg,ddi_callback_id_t * cb_id)864 usb_ia_busop_add_eventcall(dev_info_t *dip,
865     dev_info_t *rdip,
866     ddi_eventcookie_t cookie,
867     ddi_event_cb_f callback,
868     void *arg, ddi_callback_id_t *cb_id)
869 {
870 	int	ifno;
871 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
872 
873 	mutex_enter(&usb_ia->ia_mutex);
874 	ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if;
875 	mutex_exit(&usb_ia->ia_mutex);
876 
877 	if (ifno < 0) {
878 		ifno = 0;
879 	}
880 
881 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
882 	    "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p "
883 	    "cookie=0x%p, cb=0x%p, arg=0x%p",
884 	    (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
885 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
886 	    "(dip=%s%d rdip=%s%d event=%s)",
887 	    ddi_driver_name(dip), ddi_get_instance(dip),
888 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
889 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
890 
891 	/* Set flag on children registering events */
892 	switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) {
893 	case USBA_EVENT_TAG_HOT_REMOVAL:
894 		mutex_enter(&usb_ia->ia_mutex);
895 		usb_ia->ia_child_events[ifno] |=
896 		    USB_IA_CHILD_EVENT_DISCONNECT;
897 		mutex_exit(&usb_ia->ia_mutex);
898 
899 		break;
900 	case USBA_EVENT_TAG_PRE_SUSPEND:
901 		mutex_enter(&usb_ia->ia_mutex);
902 		usb_ia->ia_child_events[ifno] |=
903 		    USB_IA_CHILD_EVENT_PRESUSPEND;
904 		mutex_exit(&usb_ia->ia_mutex);
905 
906 		break;
907 	default:
908 
909 		break;
910 	}
911 	/* add callback (perform registration) */
912 	return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl,
913 	    rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
914 }
915 
916 
917 static int
usb_ia_busop_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)918 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
919 {
920 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
921 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
922 
923 	ASSERT(cb);
924 
925 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
926 	    "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
927 	    "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
928 	    (void *)cb->ndi_evtcb_cookie);
929 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
930 	    "(dip=%s%d rdip=%s%d event=%s)",
931 	    ddi_driver_name(dip), ddi_get_instance(dip),
932 	    ddi_driver_name(cb->ndi_evtcb_dip),
933 	    ddi_get_instance(cb->ndi_evtcb_dip),
934 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl,
935 	    cb->ndi_evtcb_cookie));
936 
937 	/* remove event registration from our event set */
938 	return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id));
939 }
940 
941 
942 static int
usb_ia_busop_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * bus_impldata)943 usb_ia_busop_post_event(dev_info_t *dip,
944     dev_info_t *rdip,
945     ddi_eventcookie_t cookie,
946     void *bus_impldata)
947 {
948 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
949 
950 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
951 	    "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p "
952 	    "cookie=0x%p, impl=0x%p",
953 	    (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
954 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
955 	    "(dip=%s%d rdip=%s%d event=%s)",
956 	    ddi_driver_name(dip), ddi_get_instance(dip),
957 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
958 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
959 
960 	/* post event to all children registered for this event */
961 	return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip,
962 	    cookie, bus_impldata));
963 }
964 
965 
966 /*
967  * usb_ia_restore_device_state
968  *	set the original configuration of the device
969  */
970 static int
usb_ia_restore_device_state(dev_info_t * dip,usb_ia_t * usb_ia)971 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia)
972 {
973 	usb_common_power_t	*iapm;
974 
975 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
976 	    "usb_ia_restore_device_state: usb_ia = %p", (void *)usb_ia);
977 
978 	mutex_enter(&usb_ia->ia_mutex);
979 	iapm = usb_ia->ia_pm;
980 	mutex_exit(&usb_ia->ia_mutex);
981 
982 	/* First bring the device to full power */
983 	(void) pm_busy_component(dip, 0);
984 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
985 
986 	if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0,
987 	    DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
988 
989 		/* change the device state from suspended to disconnected */
990 		mutex_enter(&usb_ia->ia_mutex);
991 		usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
992 		mutex_exit(&usb_ia->ia_mutex);
993 		(void) pm_idle_component(dip, 0);
994 
995 		return (USB_FAILURE);
996 	}
997 
998 	/*
999 	 * if the device had remote wakeup earlier,
1000 	 * enable it again
1001 	 */
1002 	if (iapm->uc_wakeup_enabled) {
1003 		(void) usb_handle_remote_wakeup(usb_ia->ia_dip,
1004 		    USB_REMOTE_WAKEUP_ENABLE);
1005 	}
1006 
1007 	mutex_enter(&usb_ia->ia_mutex);
1008 	usb_ia->ia_dev_state = USB_DEV_ONLINE;
1009 	mutex_exit(&usb_ia->ia_mutex);
1010 
1011 	(void) pm_idle_component(dip, 0);
1012 
1013 	return (USB_SUCCESS);
1014 }
1015 
1016 
1017 /*
1018  * usb_ia_event_cb()
1019  *	handle disconnect and connect events
1020  */
1021 static void
usb_ia_event_cb(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)1022 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1023     void *arg, void *bus_impldata)
1024 {
1025 	int		i, tag;
1026 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
1027 	dev_info_t	*child_dip;
1028 	ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1029 
1030 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1031 	    "usb_ia_event_cb: dip=0x%p, cookie=0x%p, "
1032 	    "arg=0x%p, impl=0x%p",
1033 	    (void *)dip, (void *)cookie, arg, bus_impldata);
1034 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1035 	    "(dip=%s%d event=%s)",
1036 	    ddi_driver_name(dip), ddi_get_instance(dip),
1037 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
1038 
1039 	tag = NDI_EVENT_TAG(cookie);
1040 	rm_cookie = ndi_event_tag_to_cookie(
1041 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1042 	suspend_cookie = ndi_event_tag_to_cookie(
1043 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1044 	ins_cookie = ndi_event_tag_to_cookie(
1045 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1046 	resume_cookie = ndi_event_tag_to_cookie(
1047 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1048 
1049 	mutex_enter(&usb_ia->ia_mutex);
1050 	switch (tag) {
1051 	case USBA_EVENT_TAG_HOT_REMOVAL:
1052 		if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) {
1053 			USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1054 			    usb_ia->ia_log_handle,
1055 			    "usb_ia_event_cb: Device already disconnected");
1056 		} else {
1057 			/* we are disconnected so set our state now */
1058 			usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
1059 			for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1060 				usb_ia->ia_child_events[i] &= ~
1061 				    USB_IA_CHILD_EVENT_DISCONNECT;
1062 			}
1063 			mutex_exit(&usb_ia->ia_mutex);
1064 
1065 			/* pass disconnect event to all the children */
1066 			(void) ndi_event_run_callbacks(
1067 			    usb_ia->ia_ndi_event_hdl, NULL,
1068 			    rm_cookie, bus_impldata);
1069 
1070 			mutex_enter(&usb_ia->ia_mutex);
1071 		}
1072 		break;
1073 	case USBA_EVENT_TAG_PRE_SUSPEND:
1074 		/* set our state *after* suspending children */
1075 		mutex_exit(&usb_ia->ia_mutex);
1076 
1077 		/* pass pre_suspend event to all the children */
1078 		(void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1079 		    NULL, suspend_cookie, bus_impldata);
1080 
1081 		mutex_enter(&usb_ia->ia_mutex);
1082 		for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1083 			usb_ia->ia_child_events[i] &= ~
1084 			    USB_IA_CHILD_EVENT_PRESUSPEND;
1085 		}
1086 		break;
1087 	case USBA_EVENT_TAG_HOT_INSERTION:
1088 		mutex_exit(&usb_ia->ia_mutex);
1089 		if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) {
1090 
1091 			/*
1092 			 * Check to see if this child has missed the disconnect
1093 			 * event before it registered for event cb
1094 			 */
1095 			mutex_enter(&usb_ia->ia_mutex);
1096 			for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1097 				if (usb_ia->ia_child_events[i] &
1098 				    USB_IA_CHILD_EVENT_DISCONNECT) {
1099 					usb_ia->ia_child_events[i] &=
1100 					    ~USB_IA_CHILD_EVENT_DISCONNECT;
1101 					child_dip =
1102 					    usb_ia->ia_children_dips[i];
1103 					mutex_exit(&usb_ia->ia_mutex);
1104 
1105 					/* post the missed disconnect */
1106 					(void) ndi_event_do_callback(
1107 					    usb_ia->ia_ndi_event_hdl,
1108 					    child_dip,
1109 					    rm_cookie,
1110 					    bus_impldata);
1111 					mutex_enter(&usb_ia->ia_mutex);
1112 				}
1113 			}
1114 			mutex_exit(&usb_ia->ia_mutex);
1115 
1116 			/* pass reconnect event to all the children */
1117 			(void) ndi_event_run_callbacks(
1118 			    usb_ia->ia_ndi_event_hdl, NULL,
1119 			    ins_cookie, bus_impldata);
1120 
1121 		}
1122 		mutex_enter(&usb_ia->ia_mutex);
1123 		break;
1124 	case USBA_EVENT_TAG_POST_RESUME:
1125 		/*
1126 		 * Check to see if this child has missed the pre-suspend
1127 		 * event before it registered for event cb
1128 		 */
1129 		for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1130 			if (usb_ia->ia_child_events[i] &
1131 			    USB_IA_CHILD_EVENT_PRESUSPEND) {
1132 				usb_ia->ia_child_events[i] &=
1133 				    ~USB_IA_CHILD_EVENT_PRESUSPEND;
1134 				child_dip = usb_ia->ia_children_dips[i];
1135 				mutex_exit(&usb_ia->ia_mutex);
1136 
1137 				/* post the missed pre-suspend event */
1138 				(void) ndi_event_do_callback(
1139 				    usb_ia->ia_ndi_event_hdl,
1140 				    child_dip, suspend_cookie,
1141 				    bus_impldata);
1142 				mutex_enter(&usb_ia->ia_mutex);
1143 			}
1144 		}
1145 		mutex_exit(&usb_ia->ia_mutex);
1146 
1147 		/* pass post_resume event to all the children */
1148 		(void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1149 		    NULL, resume_cookie, bus_impldata);
1150 
1151 		mutex_enter(&usb_ia->ia_mutex);
1152 		break;
1153 	}
1154 	mutex_exit(&usb_ia->ia_mutex);
1155 
1156 }
1157 
1158 /*
1159  * create the pm components required for power management
1160  */
1161 static void
usb_ia_create_pm_components(dev_info_t * dip,usb_ia_t * usb_ia)1162 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia)
1163 {
1164 	usb_common_power_t	*iapm;
1165 	uint_t			pwr_states;
1166 
1167 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1168 	    "usb_ia_create_pm_components: Begin");
1169 
1170 	/* Allocate the PM state structure */
1171 	iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
1172 
1173 	mutex_enter(&usb_ia->ia_mutex);
1174 	usb_ia->ia_pm = iapm;
1175 	iapm->uc_usb_statep = usb_ia;
1176 	iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
1177 	iapm->uc_current_power = USB_DEV_OS_FULL_PWR;
1178 	mutex_exit(&usb_ia->ia_mutex);
1179 
1180 	/*
1181 	 * By not enabling parental notification, PM enforces
1182 	 * "strict parental dependency" meaning, usb_ia won't
1183 	 * power off until any of its children are in full power.
1184 	 */
1185 
1186 	/*
1187 	 * there are 3 scenarios:
1188 	 * 1. a well behaved device should have remote wakeup
1189 	 * at interface and device level. If the interface
1190 	 * wakes up, usb_ia will wake up
1191 	 * 2. if the device doesn't have remote wake up and
1192 	 * the interface has, PM will still work, ie.
1193 	 * the interfaces wakes up and usb_ia wakes up
1194 	 * 3. if neither the interface nor device has remote
1195 	 * wakeup, the interface will wake up when it is opened
1196 	 * and goes to sleep after being closed for a while
1197 	 * In this case usb_ia should also go to sleep shortly
1198 	 * thereafter
1199 	 * In all scenarios it doesn't really matter whether
1200 	 * remote wakeup at the device level is enabled or not
1201 	 * but we do it anyways
1202 	 */
1203 	if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1204 	    USB_SUCCESS) {
1205 		USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1206 		    "usb_ia_create_pm_components: "
1207 		    "Remote Wakeup Enabled");
1208 		iapm->uc_wakeup_enabled = 1;
1209 	}
1210 
1211 	if (usb_create_pm_components(dip, &pwr_states) ==
1212 	    USB_SUCCESS) {
1213 		iapm->uc_pwr_states = (uint8_t)pwr_states;
1214 		(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1215 	}
1216 
1217 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1218 	    "usb_ia_create_pm_components: End");
1219 }
1220 
1221 
1222 /*
1223  * usb_ia_obtain_state:
1224  */
1225 static usb_ia_t *
usb_ia_obtain_state(dev_info_t * dip)1226 usb_ia_obtain_state(dev_info_t *dip)
1227 {
1228 	int instance = ddi_get_instance(dip);
1229 	usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance);
1230 
1231 	ASSERT(statep != NULL);
1232 
1233 	return (statep);
1234 }
1235