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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
31 * usb interface association driver
33 * this driver attempts to the interface association node and
34 * creates/manages child nodes for the included interfaces.
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>
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;
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
))
53 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb
))
54 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info
))
55 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy
))
57 static struct cb_ops usb_ia_cb_ops
= {
70 ddi_prop_op
, /* prop_op */
75 static int usb_ia_busop_get_eventcookie(dev_info_t
*dip
,
78 ddi_eventcookie_t
*cookie
);
79 static int usb_ia_busop_add_eventcall(dev_info_t
*dip
,
81 ddi_eventcookie_t cookie
,
82 void (*callback
)(dev_info_t
*dip
,
83 ddi_eventcookie_t cookie
, void *arg
,
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
,
90 ddi_eventcookie_t cookie
,
92 static int usb_ia_bus_config(dev_info_t
*dip
,
94 ddi_bus_config_op_t op
,
97 static int usb_ia_bus_unconfig(dev_info_t
*dip
,
99 ddi_bus_config_op_t op
,
103 * autoconfiguration data and routines.
105 static int usb_ia_info(dev_info_t
*, ddi_info_cmd_t
,
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
);
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 *);
120 static void usb_ia_create_children(usb_ia_t
*);
121 static int usb_ia_cleanup(usb_ia_t
*);
126 static struct bus_ops usb_ia_busops
= {
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 NULL
, /* bus_dma_map */
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 */
158 static struct dev_ops usb_ia_ops
= {
159 DEVO_REV
, /* devo_rev, */
161 usb_ia_info
, /* info */
162 nulldev
, /* identify */
164 usb_ia_attach
, /* attach */
165 usb_ia_detach
, /* detach */
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 */
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 */
179 static struct modlinkage modlinkage
= {
180 MODREV_1
, (void *)&modldrv
, NULL
183 #define USB_IA_INITIAL_SOFT_SPACE 4
184 static void *usb_ia_statep
;
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
}
200 #define USB_IA_N_NDI_EVENTS \
201 (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
203 static ndi_event_set_t usb_ia_ndi_events
= {
204 NDI_EVENTS_REV1
, USB_IA_N_NDI_EVENTS
, usb_ia_ndi_event_defs
};
208 * standard driver entry points
215 rval
= ddi_soft_state_init(&usb_ia_statep
, sizeof (struct usb_ia
),
216 USB_IA_INITIAL_SOFT_SPACE
);
221 if ((rval
= mod_install(&modlinkage
)) != 0) {
222 ddi_soft_state_fini(&usb_ia_statep
);
235 rval
= mod_remove(&modlinkage
);
241 ddi_soft_state_fini(&usb_ia_statep
);
248 _info(struct modinfo
*modinfop
)
250 return (mod_info(&modlinkage
, modinfop
));
256 usb_ia_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
259 int instance
= getminor((dev_t
)arg
);
260 int error
= DDI_FAILURE
;
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
) {
275 case DDI_INFO_DEVT2INSTANCE
:
276 *result
= (void *)(intptr_t)instance
;
288 * child post attach/detach notification
291 usb_ia_post_attach(usb_ia_t
*usb_ia
, uint8_t ifno
, struct attachspec
*as
)
293 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
294 "usb_ia_post_attach: ifno = %d result = %d", ifno
, as
->result
);
300 usb_ia_post_detach(usb_ia_t
*usb_ia
, uint8_t ifno
, struct detachspec
*ds
)
302 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
303 "usb_ia_post_detach: ifno = %d result = %d", ifno
, ds
->result
);
309 * bus ctl support. we handle notifications here and the
310 * rest goes up to root hub/hcd
314 usb_ia_bus_ctl(dev_info_t
*dip
,
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
;
323 struct attachspec
*as
;
324 struct detachspec
*ds
;
326 usb_ia
= usb_ia_obtain_state(dip
);
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
);
334 case DDI_CTLOPS_ATTACH
:
335 as
= (struct attachspec
*)arg
;
339 /* nothing to do basically */
340 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
341 "DDI_PRE DDI_CTLOPS_ATTACH");
344 usb_ia_post_attach(usb_ia
, usba_get_ifno(rdip
),
345 (struct attachspec
*)arg
);
350 case DDI_CTLOPS_DETACH
:
351 ds
= (struct detachspec
*)arg
;
355 /* nothing to do basically */
356 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
357 "DDI_PRE DDI_CTLOPS_DETACH");
360 usb_ia_post_detach(usb_ia
, usba_get_ifno(rdip
),
361 (struct detachspec
*)arg
);
367 /* pass to root hub to handle */
368 return (usba_bus_ctl(root_hub_dip
, rdip
, op
, arg
, result
));
371 return (DDI_SUCCESS
);
376 * bus enumeration entry points
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
)
383 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
385 USB_DPRINTF_L4(DPRINT_MASK_ALL
, usb_ia
->ia_log_handle
,
386 "usb_ia_bus_config: op=%d", op
);
388 if (usb_ia_bus_config_debug
) {
389 flag
|= NDI_DEVI_DEBUG
;
392 ndi_devi_enter(dip
, &circ
);
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
);
399 rval
= ndi_busop_bus_config(dip
, flag
, op
, arg
, child
, 0);
400 ndi_devi_exit(dip
, circ
);
407 usb_ia_bus_unconfig(dev_info_t
*dip
, uint_t flag
, ddi_bus_config_op_t op
,
410 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
412 dev_info_t
*cdip
, *mdip
;
413 int interface
, circular_count
;
414 int rval
= NDI_SUCCESS
;
416 USB_DPRINTF_L4(DPRINT_MASK_ALL
, usb_ia
->ia_log_handle
,
417 "usb_ia_bus_unconfig: op=%d", op
);
419 if (usb_ia_bus_config_debug
) {
420 flag
|= NDI_DEVI_DEBUG
;
424 * first offline and if offlining successful, then
427 if (op
== BUS_UNCONFIG_ALL
) {
428 flag
&= ~(NDI_DEVI_REMOVE
| NDI_UNCONFIG
);
431 ndi_devi_enter(dip
, &circular_count
);
432 rval
= ndi_busop_bus_unconfig(dip
, flag
, op
, arg
);
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
);
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
];
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
);
451 /* we lost the dip on this interface */
452 usb_ia
->ia_children_dips
[interface
] = NULL
;
455 * keep in DS_INITALIZED to prevent parent
458 (void) ddi_initchild(ddi_get_parent(cdip
), cdip
);
461 mutex_exit(&usb_ia
->ia_mutex
);
463 ndi_devi_exit(dip
, circular_count
);
465 USB_DPRINTF_L4(DPRINT_MASK_ALL
, usb_ia
->ia_log_handle
,
466 "usb_ia_bus_config: rval=%d", rval
);
472 /* power entry point */
475 usb_ia_power(dev_info_t
*dip
, int comp
, int level
)
478 usb_common_power_t
*pm
;
479 int rval
= DDI_FAILURE
;
481 usb_ia
= usb_ia_obtain_state(dip
);
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
);
487 mutex_enter(&usb_ia
->ia_mutex
);
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
);
496 mutex_exit(&usb_ia
->ia_mutex
);
501 rval
= usba_common_power(dip
, &(pm
->uc_current_power
),
502 &(usb_ia
->ia_dev_state
), level
);
504 mutex_exit(&usb_ia
->ia_mutex
);
510 * attach/resume entry point
513 usb_ia_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
515 int instance
= ddi_get_instance(dip
);
516 usb_ia_t
*usb_ia
= NULL
;
525 usb_ia
= ddi_get_soft_state(usb_ia_statep
, instance
);
526 (void) usb_ia_restore_device_state(dip
, usb_ia
);
528 return (DDI_SUCCESS
);
531 return (DDI_FAILURE
);
537 * Allocate soft state and initialize
539 if (ddi_soft_state_zalloc(usb_ia_statep
, instance
) != DDI_SUCCESS
) {
543 usb_ia
= ddi_get_soft_state(usb_ia_statep
, instance
);
544 if (usb_ia
== NULL
) {
549 /* allocate handle for logging of messages */
550 usb_ia
->ia_log_handle
= usb_alloc_log_hdl(dip
, "ia",
552 &usb_ia_errmask
, &usb_ia_instance_debug
,
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);
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");
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");
575 if (usb_get_dev_data(dip
, &usb_ia
->ia_dev_data
, USB_PARSE_LVL_NONE
,
577 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_ia
->ia_log_handle
,
578 "usb_get_dev_data failed");
582 mutex_init(&usb_ia
->ia_mutex
, NULL
, MUTEX_DRIVER
,
583 usb_ia
->ia_dev_data
->dev_iblock_cookie
);
585 usb_free_dev_data(dip
, usb_ia
->ia_dev_data
);
586 usb_ia
->ia_dev_data
= NULL
;
588 usb_ia
->ia_init_state
|= USB_IA_LOCK_INIT
;
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");
597 usb_ia
->ia_init_state
|= USB_IA_MINOR_NODE_CREATED
;
600 * allocate array for keeping track of child dips
602 n_ifs
= usb_ia
->ia_n_ifs
;
603 usb_ia
->ia_cd_list_length
= size
= (sizeof (dev_info_t
*)) * n_ifs
;
605 usb_ia
->ia_children_dips
= kmem_zalloc(size
, KM_SLEEP
);
606 usb_ia
->ia_child_events
= kmem_zalloc(sizeof (uint8_t) * n_ifs
,
609 * Event handling: definition and registration
610 * get event handle for events that we have defined
612 (void) ndi_event_alloc_hdl(dip
, 0, &usb_ia
->ia_ndi_event_hdl
,
615 /* bind event set to the handle */
616 if (ndi_event_bind_set(usb_ia
->ia_ndi_event_hdl
, &usb_ia_ndi_events
,
618 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_ia
->ia_log_handle
,
619 "usb_ia_attach: binding event set failed");
624 usb_ia
->ia_dev_state
= USB_DEV_ONLINE
;
627 * now create components to power manage this device
628 * before attaching children
630 usb_ia_create_pm_components(dip
, usb_ia
);
632 /* event registration for events from our parent */
633 usba_common_register_events(dip
, n_ifs
, usb_ia_event_cb
);
635 usb_ia
->ia_init_state
|= USB_IA_EVENTS_REGISTERED
;
639 return (DDI_SUCCESS
);
642 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, NULL
, "usb_ia%d cannot attach",
646 (void) usb_ia_cleanup(usb_ia
);
649 return (DDI_FAILURE
);
653 /* detach or suspend this instance */
655 usb_ia_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
657 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
659 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_ia
->ia_log_handle
,
660 "usb_ia_detach: cmd = 0x%x", cmd
);
665 return (usb_ia_cleanup(usb_ia
));
668 mutex_enter(&usb_ia
->ia_mutex
);
669 usb_ia
->ia_dev_state
= USB_DEV_SUSPENDED
;
670 mutex_exit(&usb_ia
->ia_mutex
);
672 return (DDI_SUCCESS
);
675 return (DDI_FAILURE
);
685 * cleanup usb_ia and deallocate. this function is called for
686 * handling attach failures and detaching including dynamic
691 usb_ia_cleanup(usb_ia_t
*usb_ia
)
693 usb_common_power_t
*iapm
;
695 dev_info_t
*dip
= usb_ia
->ia_dip
;
697 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_ia
->ia_log_handle
,
700 if ((usb_ia
->ia_init_state
& USB_IA_LOCK_INIT
) == 0) {
706 * deallocate events, if events are still registered
707 * (ie. children still attached) then we have to fail the detach
709 if (usb_ia
->ia_ndi_event_hdl
&&
710 (ndi_event_free_hdl(usb_ia
->ia_ndi_event_hdl
) != NDI_SUCCESS
)) {
712 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_ia
->ia_log_handle
,
713 "usb_ia_cleanup: ndi_event_free_hdl failed");
715 return (DDI_FAILURE
);
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.
726 if (usb_ia
->ia_init_state
& USB_IA_EVENTS_REGISTERED
) {
728 usba_common_unregister_events(usb_ia
->ia_dip
, usb_ia
->ia_n_ifs
);
731 iapm
= usb_ia
->ia_pm
;
733 mutex_enter(&usb_ia
->ia_mutex
);
735 if ((iapm
) && (usb_ia
->ia_dev_state
!= USB_DEV_DISCONNECTED
)) {
737 mutex_exit(&usb_ia
->ia_mutex
);
739 (void) pm_busy_component(dip
, 0);
740 if (iapm
->uc_wakeup_enabled
) {
742 /* First bring the device to full power */
743 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
745 rval
= usb_handle_remote_wakeup(dip
,
746 USB_REMOTE_WAKEUP_DISABLE
);
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
);
756 (void) pm_lower_power(usb_ia
->ia_dip
, 0, USB_DEV_OS_PWR_OFF
);
757 (void) pm_idle_component(dip
, 0);
759 mutex_exit(&usb_ia
->ia_mutex
);
763 kmem_free(iapm
, sizeof (usb_common_power_t
));
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
);
772 if (usb_ia
->ia_child_events
) {
773 kmem_free(usb_ia
->ia_child_events
, sizeof (uint8_t) *
777 if (usb_ia
->ia_init_state
& USB_IA_MINOR_NODE_CREATED
) {
778 ddi_remove_minor_node(dip
, NULL
);
781 mutex_destroy(&usb_ia
->ia_mutex
);
784 usb_client_detach(dip
, usb_ia
->ia_dev_data
);
786 usb_free_log_hdl(usb_ia
->ia_log_handle
);
787 ddi_soft_state_free(usb_ia_statep
, ddi_get_instance(dip
));
789 ddi_prop_remove_all(dip
);
791 return (DDI_SUCCESS
);
795 * usb_ia_create_children:
798 usb_ia_create_children(usb_ia_t
*usb_ia
)
800 usba_device_t
*usba_device
;
801 uint_t n_ifs
, first_if
;
805 usba_device
= usba_get_usba_device(usb_ia
->ia_dip
);
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
);
811 n_ifs
= usb_ia
->ia_n_ifs
;
812 first_if
= usb_ia
->ia_first_if
;
815 * create all children if not already present
817 for (i
= 0; i
< n_ifs
; i
++) {
818 if (usb_ia
->ia_children_dips
[i
] != NULL
) {
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
);
828 (void) usba_bind_driver(cdip
);
829 usb_ia
->ia_children_dips
[i
] = cdip
;
840 usb_ia_busop_get_eventcookie(dev_info_t
*dip
,
841 dev_info_t
*rdip
, char *eventname
, ddi_eventcookie_t
*cookie
)
843 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
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
));
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
));
860 usb_ia_busop_add_eventcall(dev_info_t
*dip
,
862 ddi_eventcookie_t cookie
,
863 void (*callback
)(dev_info_t
*dip
,
864 ddi_eventcookie_t cookie
, void *arg
,
866 void *arg
, ddi_callback_id_t
*cb_id
)
869 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
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
);
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
));
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
);
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
);
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
));
916 usb_ia_busop_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
)
918 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
919 ndi_event_callbacks_t
*cb
= (ndi_event_callbacks_t
*)cb_id
;
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
));
935 /* remove event registration from our event set */
936 return (ndi_event_remove_callback(usb_ia
->ia_ndi_event_hdl
, cb_id
));
941 usb_ia_busop_post_event(dev_info_t
*dip
,
943 ddi_eventcookie_t cookie
,
946 usb_ia_t
*usb_ia
= usb_ia_obtain_state(dip
);
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
));
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
));
965 * usb_ia_restore_device_state
966 * set the original configuration of the device
969 usb_ia_restore_device_state(dev_info_t
*dip
, usb_ia_t
*usb_ia
)
971 usb_common_power_t
*iapm
;
973 USB_DPRINTF_L4(DPRINT_MASK_EVENTS
, usb_ia
->ia_log_handle
,
974 "usb_ia_restore_device_state: usb_ia = %p", (void *)usb_ia
);
976 mutex_enter(&usb_ia
->ia_mutex
);
977 iapm
= usb_ia
->ia_pm
;
978 mutex_exit(&usb_ia
->ia_mutex
);
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
);
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
) {
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);
993 return (USB_FAILURE
);
997 * if the device had remote wakeup earlier,
1000 if (iapm
->uc_wakeup_enabled
) {
1001 (void) usb_handle_remote_wakeup(usb_ia
->ia_dip
,
1002 USB_REMOTE_WAKEUP_ENABLE
);
1005 mutex_enter(&usb_ia
->ia_mutex
);
1006 usb_ia
->ia_dev_state
= USB_DEV_ONLINE
;
1007 mutex_exit(&usb_ia
->ia_mutex
);
1009 (void) pm_idle_component(dip
, 0);
1011 return (USB_SUCCESS
);
1017 * handle disconnect and connect events
1020 usb_ia_event_cb(dev_info_t
*dip
, ddi_eventcookie_t cookie
,
1021 void *arg
, void *bus_impldata
)
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
;
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
));
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
);
1047 mutex_enter(&usb_ia
->ia_mutex
);
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");
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
;
1061 mutex_exit(&usb_ia
->ia_mutex
);
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
);
1068 mutex_enter(&usb_ia
->ia_mutex
);
1071 case USBA_EVENT_TAG_PRE_SUSPEND
:
1072 /* set our state *after* suspending children */
1073 mutex_exit(&usb_ia
->ia_mutex
);
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
);
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
;
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
) {
1090 * Check to see if this child has missed the disconnect
1091 * event before it registered for event cb
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
;
1100 usb_ia
->ia_children_dips
[i
];
1101 mutex_exit(&usb_ia
->ia_mutex
);
1103 /* post the missed disconnect */
1104 (void) ndi_event_do_callback(
1105 usb_ia
->ia_ndi_event_hdl
,
1109 mutex_enter(&usb_ia
->ia_mutex
);
1112 mutex_exit(&usb_ia
->ia_mutex
);
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
);
1120 mutex_enter(&usb_ia
->ia_mutex
);
1122 case USBA_EVENT_TAG_POST_RESUME
:
1124 * Check to see if this child has missed the pre-suspend
1125 * event before it registered for event cb
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
);
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
,
1140 mutex_enter(&usb_ia
->ia_mutex
);
1143 mutex_exit(&usb_ia
->ia_mutex
);
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
);
1149 mutex_enter(&usb_ia
->ia_mutex
);
1152 mutex_exit(&usb_ia
->ia_mutex
);
1157 * create the pm components required for power management
1160 usb_ia_create_pm_components(dev_info_t
*dip
, usb_ia_t
*usb_ia
)
1162 usb_common_power_t
*iapm
;
1165 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
1166 "usb_ia_create_pm_components: Begin");
1168 /* Allocate the PM state structure */
1169 iapm
= kmem_zalloc(sizeof (usb_common_power_t
), KM_SLEEP
);
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
);
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.
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
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
1201 if (usb_handle_remote_wakeup(dip
, USB_REMOTE_WAKEUP_ENABLE
) ==
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;
1209 if (usb_create_pm_components(dip
, &pwr_states
) ==
1211 iapm
->uc_pwr_states
= (uint8_t)pwr_states
;
1212 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
1215 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_ia
->ia_log_handle
,
1216 "usb_ia_create_pm_components: End");
1221 * usb_ia_obtain_state:
1224 usb_ia_obtain_state(dev_info_t
*dip
)
1226 int instance
= ddi_get_instance(dip
);
1227 usb_ia_t
*statep
= ddi_get_soft_state(usb_ia_statep
, instance
);
1229 ASSERT(statep
!= NULL
);