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