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