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