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 2008 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 multi interface and common class driver
33 * this driver attempts to attach each interface to a driver
34 * and may eventually handle common class features such as
38 #include <sys/usb/usba/usbai_version.h>
39 #include <sys/usb/usba.h>
40 #include <sys/usb/usba/usba_types.h>
41 #include <sys/usb/usba/usba_impl.h>
42 #include <sys/usb/usba/usba_ugen.h>
43 #include <sys/usb/usb_mid/usb_midvar.h>
45 void usba_free_evdata(usba_evdata_t
*);
47 /* Debugging support */
48 uint_t usb_mid_errlevel
= USB_LOG_L4
;
49 uint_t usb_mid_errmask
= (uint_t
)DPRINT_MASK_ALL
;
50 uint_t usb_mid_instance_debug
= (uint_t
)-1;
51 uint_t usb_mid_bus_config_debug
= 0;
53 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel
))
54 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask
))
55 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug
))
57 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb
))
58 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info
))
59 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy
))
63 * Leaf ops (hotplug controls for client devices)
65 static int usb_mid_open(dev_t
*, int, int, cred_t
*);
66 static int usb_mid_close(dev_t
, int, int, cred_t
*);
67 static int usb_mid_read(dev_t
, struct uio
*, cred_t
*);
68 static int usb_mid_write(dev_t
, struct uio
*, cred_t
*);
69 static int usb_mid_poll(dev_t
, short, int, short *,
72 static struct cb_ops usb_mid_cb_ops
= {
78 usb_mid_read
, /* read */
79 usb_mid_write
, /* write */
84 usb_mid_poll
, /* poll */
85 ddi_prop_op
, /* prop_op */
90 static int usb_mid_busop_get_eventcookie(dev_info_t
*dip
,
93 ddi_eventcookie_t
*cookie
);
94 static int usb_mid_busop_add_eventcall(dev_info_t
*dip
,
96 ddi_eventcookie_t cookie
,
97 void (*callback
)(dev_info_t
*dip
,
98 ddi_eventcookie_t cookie
, void *arg
,
100 void *arg
, ddi_callback_id_t
*cb_id
);
101 static int usb_mid_busop_remove_eventcall(dev_info_t
*dip
,
102 ddi_callback_id_t cb_id
);
103 static int usb_mid_busop_post_event(dev_info_t
*dip
,
105 ddi_eventcookie_t cookie
,
107 static int usb_mid_bus_config(dev_info_t
*dip
,
109 ddi_bus_config_op_t op
,
112 static int usb_mid_bus_unconfig(dev_info_t
*dip
,
114 ddi_bus_config_op_t op
,
119 * autoconfiguration data and routines.
121 static int usb_mid_info(dev_info_t
*, ddi_info_cmd_t
,
123 static int usb_mid_attach(dev_info_t
*, ddi_attach_cmd_t
);
124 static int usb_mid_detach(dev_info_t
*, ddi_detach_cmd_t
);
127 static void usb_mid_create_pm_components(dev_info_t
*, usb_mid_t
*);
128 static int usb_mid_bus_ctl(dev_info_t
*, dev_info_t
*,
129 ddi_ctl_enum_t
, void *, void *);
130 static int usb_mid_power(dev_info_t
*, int, int);
131 static int usb_mid_restore_device_state(dev_info_t
*, usb_mid_t
*);
132 static usb_mid_t
*usb_mid_obtain_state(dev_info_t
*);
133 static void usb_mid_event_cb(dev_info_t
*, ddi_eventcookie_t
, void *, void *);
138 static struct bus_ops usb_mid_busops
= {
140 nullbusmap
, /* bus_map */
141 NULL
, /* bus_get_intrspec */
142 NULL
, /* bus_add_intrspec */
143 NULL
, /* bus_remove_intrspec */
144 NULL
, /* XXXX bus_map_fault */
145 NULL
, /* bus_dma_map */
152 ddi_dma_mctl
, /* bus_dma_ctl */
153 usb_mid_bus_ctl
, /* bus_ctl */
154 ddi_bus_prop_op
, /* bus_prop_op */
155 usb_mid_busop_get_eventcookie
,
156 usb_mid_busop_add_eventcall
,
157 usb_mid_busop_remove_eventcall
,
158 usb_mid_busop_post_event
, /* bus_post_event */
159 NULL
, /* bus_intr_ctl */
160 usb_mid_bus_config
, /* bus_config */
161 usb_mid_bus_unconfig
, /* bus_unconfig */
162 NULL
, /* bus_fm_init */
163 NULL
, /* bus_fm_fini */
164 NULL
, /* bus_fm_access_enter */
165 NULL
, /* bus_fm_access_exit */
170 static struct dev_ops usb_mid_ops
= {
171 DEVO_REV
, /* devo_rev, */
173 usb_mid_info
, /* info */
174 nulldev
, /* identify */
176 usb_mid_attach
, /* attach */
177 usb_mid_detach
, /* detach */
179 &usb_mid_cb_ops
, /* driver operations */
180 &usb_mid_busops
, /* bus operations */
181 usb_mid_power
, /* power */
182 ddi_quiesce_not_needed
, /* quiesce */
185 static struct modldrv modldrv
= {
186 &mod_driverops
, /* Type of module. This one is a driver */
187 "USB Multi Interface Driver", /* Name of the module. */
188 &usb_mid_ops
, /* driver ops */
191 static struct modlinkage modlinkage
= {
192 MODREV_1
, (void *)&modldrv
, NULL
195 #define USB_MID_INITIAL_SOFT_SPACE 4
196 static void *usb_mid_statep
;
202 static void usb_mid_create_children(usb_mid_t
*usb_mid
);
203 static int usb_mid_cleanup(dev_info_t
*dip
, usb_mid_t
*usb_mid
);
208 static ndi_event_definition_t usb_mid_ndi_event_defs
[] = {
209 {USBA_EVENT_TAG_HOT_REMOVAL
, DDI_DEVI_REMOVE_EVENT
, EPL_KERNEL
,
210 NDI_EVENT_POST_TO_ALL
},
211 {USBA_EVENT_TAG_HOT_INSERTION
, DDI_DEVI_INSERT_EVENT
, EPL_KERNEL
,
212 NDI_EVENT_POST_TO_ALL
},
213 {USBA_EVENT_TAG_POST_RESUME
, USBA_POST_RESUME_EVENT
, EPL_KERNEL
,
214 NDI_EVENT_POST_TO_ALL
},
215 {USBA_EVENT_TAG_PRE_SUSPEND
, USBA_PRE_SUSPEND_EVENT
, EPL_KERNEL
,
216 NDI_EVENT_POST_TO_ALL
}
219 #define USB_MID_N_NDI_EVENTS \
220 (sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t))
222 static ndi_event_set_t usb_mid_ndi_events
= {
223 NDI_EVENTS_REV1
, USB_MID_N_NDI_EVENTS
, usb_mid_ndi_event_defs
};
227 * standard driver entry points
234 rval
= ddi_soft_state_init(&usb_mid_statep
, sizeof (struct usb_mid
),
235 USB_MID_INITIAL_SOFT_SPACE
);
240 if ((rval
= mod_install(&modlinkage
)) != 0) {
241 ddi_soft_state_fini(&usb_mid_statep
);
254 rval
= mod_remove(&modlinkage
);
260 ddi_soft_state_fini(&usb_mid_statep
);
267 _info(struct modinfo
*modinfop
)
269 return (mod_info(&modlinkage
, modinfop
));
275 usb_mid_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
279 USB_MID_MINOR_TO_INSTANCE(getminor((dev_t
)arg
));
280 int error
= DDI_FAILURE
;
283 case DDI_INFO_DEVT2DEVINFO
:
284 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
285 instance
)) != NULL
) {
286 *result
= (void *)usb_mid
->mi_dip
;
287 if (*result
!= NULL
) {
295 case DDI_INFO_DEVT2INSTANCE
:
296 *result
= (void *)(intptr_t)instance
;
308 * child post attach/detach notification
311 usb_mid_post_attach(usb_mid_t
*usb_mid
, uint8_t ifno
, struct attachspec
*as
)
313 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
314 "usb_mid_post_attach: ifno = %d result = %d", ifno
, as
->result
);
316 /* if child successfully attached, set power */
317 if (as
->result
== DDI_SUCCESS
) {
319 * Check if the child created wants to be power managed.
320 * If yes, the childs power level gets automatically tracked
321 * by DDI_CTLOPS_POWER busctl.
322 * If no, we set power of the new child by default
323 * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
325 mutex_enter(&usb_mid
->mi_mutex
);
326 usb_mid
->mi_attach_count
++;
327 mutex_exit(&usb_mid
->mi_mutex
);
333 usb_mid_post_detach(usb_mid_t
*usb_mid
, uint8_t ifno
, struct detachspec
*ds
)
335 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
336 "usb_mid_post_detach: ifno = %d result = %d", ifno
, ds
->result
);
339 * if the device is successfully detached,
340 * mark component as idle
342 if (ds
->result
== DDI_SUCCESS
) {
343 usba_device_t
*usba_device
=
344 usba_get_usba_device(usb_mid
->mi_dip
);
346 mutex_enter(&usb_mid
->mi_mutex
);
348 /* check for leaks except when where is a ugen open */
349 if ((ds
->cmd
== DDI_DETACH
) &&
350 (--usb_mid
->mi_attach_count
== 0) && usba_device
&&
351 (usb_mid
->mi_ugen_open_count
== 0)) {
352 usba_check_for_leaks(usba_device
);
354 mutex_exit(&usb_mid
->mi_mutex
);
360 * bus ctl support. we handle notifications here and the
361 * rest goes up to root hub/hcd
365 usb_mid_bus_ctl(dev_info_t
*dip
,
371 usba_device_t
*hub_usba_device
= usba_get_usba_device(rdip
);
372 dev_info_t
*root_hub_dip
= hub_usba_device
->usb_root_hub_dip
;
374 struct attachspec
*as
;
375 struct detachspec
*ds
;
377 usb_mid
= usb_mid_obtain_state(dip
);
379 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
380 "usb_mid_bus_ctl:\n\t"
381 "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
382 (void *)dip
, (void *)rdip
, op
, arg
);
385 case DDI_CTLOPS_ATTACH
:
386 as
= (struct attachspec
*)arg
;
390 /* nothing to do basically */
391 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
392 "DDI_PRE DDI_CTLOPS_ATTACH");
395 usb_mid_post_attach(usb_mid
, usba_get_ifno(rdip
),
396 (struct attachspec
*)arg
);
401 case DDI_CTLOPS_DETACH
:
402 ds
= (struct detachspec
*)arg
;
406 /* nothing to do basically */
407 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
408 "DDI_PRE DDI_CTLOPS_DETACH");
411 usb_mid_post_detach(usb_mid
, usba_get_ifno(rdip
),
412 (struct detachspec
*)arg
);
418 /* pass to root hub to handle */
419 return (usba_bus_ctl(root_hub_dip
, rdip
, op
, arg
, result
));
422 return (DDI_SUCCESS
);
427 * bus enumeration entry points
430 usb_mid_bus_config(dev_info_t
*dip
, uint_t flag
, ddi_bus_config_op_t op
,
431 void *arg
, dev_info_t
**child
)
434 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
436 USB_DPRINTF_L2(DPRINT_MASK_ALL
, usb_mid
->mi_log_handle
,
437 "usb_mid_bus_config: op=%d", op
);
439 if (usb_mid_bus_config_debug
) {
440 flag
|= NDI_DEVI_DEBUG
;
443 ndi_devi_enter(dip
, &circ
);
445 /* enumerate each interface below us */
446 mutex_enter(&usb_mid
->mi_mutex
);
447 usb_mid_create_children(usb_mid
);
448 mutex_exit(&usb_mid
->mi_mutex
);
450 rval
= ndi_busop_bus_config(dip
, flag
, op
, arg
, child
, 0);
451 ndi_devi_exit(dip
, circ
);
458 usb_mid_bus_unconfig(dev_info_t
*dip
, uint_t flag
, ddi_bus_config_op_t op
,
461 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
463 dev_info_t
*cdip
, *mdip
;
464 int interface
, circular_count
;
465 int rval
= NDI_SUCCESS
;
467 USB_DPRINTF_L4(DPRINT_MASK_ALL
, usb_mid
->mi_log_handle
,
468 "usb_mid_bus_unconfig: op=%d", op
);
470 if (usb_mid_bus_config_debug
) {
471 flag
|= NDI_DEVI_DEBUG
;
475 * first offline and if offlining successful, then
478 if (op
== BUS_UNCONFIG_ALL
) {
479 flag
&= ~(NDI_DEVI_REMOVE
| NDI_UNCONFIG
);
482 ndi_devi_enter(dip
, &circular_count
);
483 rval
= ndi_busop_bus_unconfig(dip
, flag
, op
, arg
);
485 if (op
== BUS_UNCONFIG_ALL
&& rval
== NDI_SUCCESS
&&
486 (flag
& NDI_AUTODETACH
) == 0) {
487 flag
|= NDI_DEVI_REMOVE
;
488 rval
= ndi_busop_bus_unconfig(dip
, flag
, op
, arg
);
491 /* update children's list */
492 mutex_enter(&usb_mid
->mi_mutex
);
493 for (interface
= 0; usb_mid
->mi_children_dips
&&
494 (interface
< usb_mid
->mi_n_ifs
) &&
495 (usb_mid
->mi_children_ifs
[interface
]); interface
++) {
496 mdip
= usb_mid
->mi_children_dips
[interface
];
498 /* now search if this dip still exists */
499 for (cdip
= ddi_get_child(dip
); cdip
&& (cdip
!= mdip
); )
500 cdip
= ddi_get_next_sibling(cdip
);
503 /* we lost the dip on this interface */
504 usb_mid
->mi_children_dips
[interface
] = NULL
;
507 * keep in DS_INITALIZED to prevent parent
510 (void) ddi_initchild(ddi_get_parent(cdip
), cdip
);
513 mutex_exit(&usb_mid
->mi_mutex
);
515 ndi_devi_exit(dip
, circular_count
);
517 USB_DPRINTF_L4(DPRINT_MASK_ALL
, usb_mid
->mi_log_handle
,
518 "usb_mid_bus_config: rval=%d", rval
);
524 /* power entry point */
527 usb_mid_power(dev_info_t
*dip
, int comp
, int level
)
530 usb_common_power_t
*midpm
;
531 int rval
= DDI_FAILURE
;
533 usb_mid
= usb_mid_obtain_state(dip
);
535 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
536 "usb_mid_power: Begin: usb_mid = %p, level = %d",
537 (void *)usb_mid
, level
);
539 mutex_enter(&usb_mid
->mi_mutex
);
540 midpm
= usb_mid
->mi_pm
;
542 /* check if we are transitioning to a legal power level */
543 if (USB_DEV_PWRSTATE_OK(midpm
->uc_pwr_states
, level
)) {
544 USB_DPRINTF_L2(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
545 "usb_mid_power: illegal power level = %d "
546 "uc_pwr_states = %x", level
, midpm
->uc_pwr_states
);
548 mutex_exit(&usb_mid
->mi_mutex
);
553 rval
= usba_common_power(dip
, &(midpm
->uc_current_power
),
554 &(usb_mid
->mi_dev_state
), level
);
556 mutex_exit(&usb_mid
->mi_mutex
);
563 * attach/resume entry point
566 usb_mid_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
568 int instance
= ddi_get_instance(dip
);
569 usb_mid_t
*usb_mid
= NULL
;
578 usb_mid
= (usb_mid_t
*)ddi_get_soft_state(usb_mid_statep
,
580 (void) usb_mid_restore_device_state(dip
, usb_mid
);
582 if (usb_mid
->mi_ugen_hdl
) {
583 (void) usb_ugen_attach(usb_mid
->mi_ugen_hdl
,
587 return (DDI_SUCCESS
);
590 return (DDI_FAILURE
);
596 * Allocate soft state and initialize
598 if (ddi_soft_state_zalloc(usb_mid_statep
, instance
) != DDI_SUCCESS
) {
602 usb_mid
= ddi_get_soft_state(usb_mid_statep
, instance
);
603 if (usb_mid
== NULL
) {
608 /* allocate handle for logging of messages */
609 usb_mid
->mi_log_handle
= usb_alloc_log_hdl(dip
, "mid",
611 &usb_mid_errmask
, &usb_mid_instance_debug
,
614 usb_mid
->mi_usba_device
= usba_get_usba_device(dip
);
615 usb_mid
->mi_dip
= dip
;
616 usb_mid
->mi_instance
= instance
;
617 usb_mid
->mi_n_ifs
= usb_mid
->mi_usba_device
->usb_n_ifs
;
619 /* attach client driver to USBA */
620 if (usb_client_attach(dip
, USBDRV_VERSION
, 0) != USB_SUCCESS
) {
621 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
622 "usb_client_attach failed");
625 if (usb_get_dev_data(dip
, &usb_mid
->mi_dev_data
, USB_PARSE_LVL_NONE
,
627 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
628 "usb_get_dev_data failed");
632 mutex_init(&usb_mid
->mi_mutex
, NULL
, MUTEX_DRIVER
,
633 usb_mid
->mi_dev_data
->dev_iblock_cookie
);
635 usb_free_dev_data(dip
, usb_mid
->mi_dev_data
);
636 usb_mid
->mi_dev_data
= NULL
;
638 usb_mid
->mi_init_state
|= USB_MID_LOCK_INIT
;
640 if (ddi_create_minor_node(dip
, "usb_mid", S_IFCHR
,
641 instance
<< USB_MID_MINOR_INSTANCE_SHIFT
,
642 DDI_NT_NEXUS
, 0) != DDI_SUCCESS
) {
643 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
644 "cannot create devctl minor node");
648 usb_mid
->mi_init_state
|= USB_MID_MINOR_NODE_CREATED
;
651 * allocate array for keeping track of child dips
653 n_ifs
= usb_mid
->mi_n_ifs
;
654 usb_mid
->mi_cd_list_length
= size
= (sizeof (dev_info_t
*)) * n_ifs
;
656 usb_mid
->mi_children_dips
= kmem_zalloc(size
, KM_SLEEP
);
657 usb_mid
->mi_child_events
= kmem_zalloc(sizeof (uint8_t) * n_ifs
,
659 usb_mid
->mi_children_ifs
= kmem_zalloc(sizeof (uint_t
) * n_ifs
,
661 for (i
= 0; i
< n_ifs
; i
++) {
662 usb_mid
->mi_children_ifs
[i
] = 1;
666 * Event handling: definition and registration
667 * get event handle for events that we have defined
669 (void) ndi_event_alloc_hdl(dip
, 0, &usb_mid
->mi_ndi_event_hdl
,
672 /* bind event set to the handle */
673 if (ndi_event_bind_set(usb_mid
->mi_ndi_event_hdl
, &usb_mid_ndi_events
,
675 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
676 "usb_mid_attach: binding event set failed");
681 usb_mid
->mi_dev_state
= USB_DEV_ONLINE
;
684 * now create components to power manage this device
685 * before attaching children
687 usb_mid_create_pm_components(dip
, usb_mid
);
689 /* event registration for events from our parent */
690 usba_common_register_events(usb_mid
->mi_dip
, 1, usb_mid_event_cb
);
692 usb_mid
->mi_init_state
|= USB_MID_EVENTS_REGISTERED
;
696 return (DDI_SUCCESS
);
699 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, NULL
, "usb_mid%d cannot attach",
703 (void) usb_mid_cleanup(dip
, usb_mid
);
706 return (DDI_FAILURE
);
710 /* detach or suspend this instance */
712 usb_mid_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
714 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
716 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
717 "usb_mid_detach: cmd = 0x%x", cmd
);
722 return (usb_mid_cleanup(dip
, usb_mid
));
725 mutex_enter(&usb_mid
->mi_mutex
);
726 usb_mid
->mi_dev_state
= USB_DEV_SUSPENDED
;
727 mutex_exit(&usb_mid
->mi_mutex
);
729 if (usb_mid
->mi_ugen_hdl
) {
730 int rval
= usb_ugen_detach(usb_mid
->mi_ugen_hdl
,
732 return (rval
== USB_SUCCESS
? DDI_SUCCESS
:
736 return (DDI_SUCCESS
);
739 return (DDI_FAILURE
);
748 * cleanup usb_mid and deallocate. this function is called for
749 * handling attach failures and detaching including dynamic
754 usb_mid_cleanup(dev_info_t
*dip
, usb_mid_t
*usb_mid
)
756 usb_common_power_t
*midpm
;
759 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
762 if ((usb_mid
->mi_init_state
& USB_MID_LOCK_INIT
) == 0) {
768 * deallocate events, if events are still registered
769 * (ie. children still attached) then we have to fail the detach
771 if (usb_mid
->mi_ndi_event_hdl
&&
772 (ndi_event_free_hdl(usb_mid
->mi_ndi_event_hdl
) != NDI_SUCCESS
)) {
774 USB_DPRINTF_L2(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
775 "usb_mid_cleanup: ndi_event_free_hdl failed");
777 return (DDI_FAILURE
);
781 * Disable the event callbacks, after this point, event
782 * callbacks will never get called. Note we shouldn't hold
783 * mutex while unregistering events because there may be a
784 * competing event callback thread. Event callbacks are done
785 * with ndi mutex held and this can cause a potential deadlock.
786 * Note that cleanup can't fail after deregistration of events.
788 if (usb_mid
->mi_init_state
& USB_MID_EVENTS_REGISTERED
) {
789 usba_common_unregister_events(usb_mid
->mi_dip
, 1);
792 midpm
= usb_mid
->mi_pm
;
794 mutex_enter(&usb_mid
->mi_mutex
);
796 if ((midpm
) && (usb_mid
->mi_dev_state
!= USB_DEV_DISCONNECTED
)) {
798 mutex_exit(&usb_mid
->mi_mutex
);
800 (void) pm_busy_component(dip
, 0);
801 if (midpm
->uc_wakeup_enabled
) {
803 /* First bring the device to full power */
804 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
806 rval
= usb_handle_remote_wakeup(dip
,
807 USB_REMOTE_WAKEUP_DISABLE
);
809 if (rval
!= DDI_SUCCESS
) {
810 USB_DPRINTF_L2(DPRINT_MASK_EVENTS
,
811 usb_mid
->mi_log_handle
,
812 "usb_cleanup: disable remote "
813 "wakeup failed, rval=%d", rval
);
817 (void) pm_lower_power(usb_mid
->mi_dip
, 0, USB_DEV_OS_PWR_OFF
);
818 (void) pm_idle_component(dip
, 0);
820 mutex_exit(&usb_mid
->mi_mutex
);
824 kmem_free(midpm
, sizeof (usb_common_power_t
));
827 /* free children list */
828 if (usb_mid
->mi_children_dips
) {
829 kmem_free(usb_mid
->mi_children_dips
,
830 usb_mid
->mi_cd_list_length
);
833 if (usb_mid
->mi_child_events
) {
834 kmem_free(usb_mid
->mi_child_events
, sizeof (uint8_t) *
838 if (usb_mid
->mi_children_ifs
) {
839 kmem_free(usb_mid
->mi_children_ifs
, sizeof (uint_t
) *
843 if (usb_mid
->mi_init_state
& USB_MID_MINOR_NODE_CREATED
) {
844 ddi_remove_minor_node(dip
, NULL
);
847 mutex_destroy(&usb_mid
->mi_mutex
);
850 usb_client_detach(dip
, usb_mid
->mi_dev_data
);
852 if (usb_mid
->mi_ugen_hdl
) {
853 (void) usb_ugen_detach(usb_mid
->mi_ugen_hdl
, DDI_DETACH
);
854 usb_ugen_release_hdl(usb_mid
->mi_ugen_hdl
);
857 usb_free_log_hdl(usb_mid
->mi_log_handle
);
858 ddi_soft_state_free(usb_mid_statep
, ddi_get_instance(dip
));
860 ddi_prop_remove_all(dip
);
862 return (DDI_SUCCESS
);
867 usb_mid_ugen_attach(usb_mid_t
*usb_mid
, boolean_t remove_children
)
869 _NOTE(NO_COMPETING_THREADS_NOW
);
871 if (usb_mid
->mi_ugen_hdl
== NULL
) {
872 usb_ugen_info_t usb_ugen_info
;
876 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
877 "usb_mid_ugen_attach: get handle");
879 bzero(&usb_ugen_info
, sizeof (usb_ugen_info
));
881 usb_ugen_info
.usb_ugen_flags
= (remove_children
?
882 USB_UGEN_REMOVE_CHILDREN
: 0);
883 usb_ugen_info
.usb_ugen_minor_node_ugen_bits_mask
=
884 (dev_t
)USB_MID_MINOR_UGEN_BITS_MASK
;
885 usb_ugen_info
.usb_ugen_minor_node_instance_mask
=
886 (dev_t
)~USB_MID_MINOR_UGEN_BITS_MASK
;
888 mutex_exit(&usb_mid
->mi_mutex
);
889 hdl
= usb_ugen_get_hdl(usb_mid
->mi_dip
,
892 if ((rval
= usb_ugen_attach(hdl
, DDI_ATTACH
)) != USB_SUCCESS
) {
893 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
894 "failed to create ugen support (%d)", rval
);
895 usb_ugen_release_hdl(hdl
);
897 mutex_enter(&usb_mid
->mi_mutex
);
899 mutex_enter(&usb_mid
->mi_mutex
);
900 usb_mid
->mi_ugen_hdl
= hdl
;
904 _NOTE(COMPETING_THREADS_NOW
);
909 * usb_mid_create_children:
912 usb_mid_create_children(usb_mid_t
*usb_mid
)
914 usba_device_t
*usba_device
;
915 uint_t n_ifs
, if_count
;
917 dev_info_t
*cdip
, *ia_dip
;
918 uint_t ugen_bound
= 0;
919 uint_t bound_children
= 0;
921 usba_device
= usba_get_usba_device(usb_mid
->mi_dip
);
923 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
924 "usb_mid_attach_child_drivers: port = %d, address = %d",
925 usba_device
->usb_port
, usba_device
->usb_addr
);
927 if (usb_mid
->mi_removed_children
) {
932 n_ifs
= usb_mid
->mi_n_ifs
;
935 USB_DPRINTF_L4(DPRINT_MASK_ATTA
, usb_mid
->mi_log_handle
,
936 "usb_mid_create_children: #interfaces = %d", n_ifs
);
939 * create all children if not already present
941 for (i
= 0; i
< n_ifs
; i
+= if_count
) {
943 /* ignore since this if is included by an ia */
944 if (usb_mid
->mi_children_ifs
[i
] == 0) {
949 if (usb_mid
->mi_children_dips
[i
] != NULL
) {
950 if (i_ddi_node_state(
951 usb_mid
->mi_children_dips
[i
]) >=
959 mutex_exit(&usb_mid
->mi_mutex
);
960 ia_dip
= usba_ready_interface_association_node(usb_mid
->mi_dip
,
963 if (ia_dip
!= NULL
) {
964 if (usba_bind_driver(ia_dip
) == USB_SUCCESS
) {
966 if (strcmp(ddi_driver_name(ia_dip
),
973 * IA node owns if_count interfaces.
974 * The rest interfaces own none.
976 mutex_enter(&usb_mid
->mi_mutex
);
977 usb_mid
->mi_children_dips
[i
] = ia_dip
;
978 usb_mid
->mi_children_ifs
[i
] = if_count
;
979 for (j
= i
+ 1; j
< i
+ if_count
; j
++) {
980 usb_mid
->mi_children_ifs
[j
] = 0;
986 cdip
= usba_ready_interface_node(usb_mid
->mi_dip
, i
);
989 if (usba_bind_driver(cdip
) ==
992 if (strcmp(ddi_driver_name(cdip
),
999 * interface node owns 1 interface always.
1001 mutex_enter(&usb_mid
->mi_mutex
);
1002 usb_mid
->mi_children_dips
[i
] = cdip
;
1003 usb_mid
->mi_children_ifs
[i
] = 1;
1004 mutex_exit(&usb_mid
->mi_mutex
);
1008 mutex_enter(&usb_mid
->mi_mutex
);
1011 usb_mid
->mi_removed_children
= (bound_children
? B_FALSE
: B_TRUE
);
1014 * if there are no ugen interface children, create ugen support at
1015 * device level, use a separate thread because we may be at interrupt
1018 if ((ugen_bound
== 0) && (usb_mid
->mi_ugen_hdl
== NULL
)) {
1020 * we only need to remove the children if there are
1021 * multiple configurations which would fail if there
1022 * are child interfaces
1024 if ((usb_mid
->mi_removed_children
== B_FALSE
) &&
1025 (usba_device
->usb_n_cfgs
> 1)) {
1026 USB_DPRINTF_L1(DPRINT_MASK_ATTA
,
1027 usb_mid
->mi_log_handle
,
1028 "can't support ugen for multiple "
1029 "configurations devices that have attached "
1030 "child interface drivers");
1032 usb_mid_ugen_attach(usb_mid
,
1033 usb_mid
->mi_removed_children
);
1043 usb_mid_busop_get_eventcookie(dev_info_t
*dip
,
1044 dev_info_t
*rdip
, char *eventname
, ddi_eventcookie_t
*cookie
)
1046 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
1048 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1049 "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
1050 "event=%s", (void *)dip
, (void *)rdip
, eventname
);
1051 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1052 "(dip=%s%d rdip=%s%d)",
1053 ddi_driver_name(dip
), ddi_get_instance(dip
),
1054 ddi_driver_name(rdip
), ddi_get_instance(rdip
));
1056 /* return event cookie, iblock cookie, and level */
1057 return (ndi_event_retrieve_cookie(usb_mid
->mi_ndi_event_hdl
,
1058 rdip
, eventname
, cookie
, NDI_EVENT_NOPASS
));
1063 usb_mid_busop_add_eventcall(dev_info_t
*dip
,
1065 ddi_eventcookie_t cookie
,
1066 void (*callback
)(dev_info_t
*dip
,
1067 ddi_eventcookie_t cookie
, void *arg
,
1068 void *bus_impldata
),
1069 void *arg
, ddi_callback_id_t
*cb_id
)
1071 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
1072 int ifno
= usba_get_ifno(rdip
);
1074 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1075 "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p "
1076 "cookie=0x%p, cb=0x%p, arg=0x%p",
1077 (void *)dip
, (void *)rdip
, (void *)cookie
, (void *)callback
, arg
);
1078 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1079 "(dip=%s%d rdip=%s%d event=%s)",
1080 ddi_driver_name(dip
), ddi_get_instance(dip
),
1081 ddi_driver_name(rdip
), ddi_get_instance(rdip
),
1082 ndi_event_cookie_to_name(usb_mid
->mi_ndi_event_hdl
, cookie
));
1084 /* Set flag on children registering events */
1085 switch (ndi_event_cookie_to_tag(usb_mid
->mi_ndi_event_hdl
, cookie
)) {
1086 case USBA_EVENT_TAG_HOT_REMOVAL
:
1087 mutex_enter(&usb_mid
->mi_mutex
);
1088 usb_mid
->mi_child_events
[ifno
] |=
1089 USB_MID_CHILD_EVENT_DISCONNECT
;
1090 mutex_exit(&usb_mid
->mi_mutex
);
1093 case USBA_EVENT_TAG_PRE_SUSPEND
:
1094 mutex_enter(&usb_mid
->mi_mutex
);
1095 usb_mid
->mi_child_events
[ifno
] |=
1096 USB_MID_CHILD_EVENT_PRESUSPEND
;
1097 mutex_exit(&usb_mid
->mi_mutex
);
1104 /* add callback (perform registration) */
1105 return (ndi_event_add_callback(usb_mid
->mi_ndi_event_hdl
,
1106 rdip
, cookie
, callback
, arg
, NDI_SLEEP
, cb_id
));
1111 usb_mid_busop_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
)
1113 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
1114 ndi_event_callbacks_t
*cb
= (ndi_event_callbacks_t
*)cb_id
;
1118 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1119 "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
1120 "cookie=0x%p", (void *)dip
, (void *)cb
->ndi_evtcb_dip
,
1121 (void *)cb
->ndi_evtcb_cookie
);
1122 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1123 "(dip=%s%d rdip=%s%d event=%s)",
1124 ddi_driver_name(dip
), ddi_get_instance(dip
),
1125 ddi_driver_name(cb
->ndi_evtcb_dip
),
1126 ddi_get_instance(cb
->ndi_evtcb_dip
),
1127 ndi_event_cookie_to_name(usb_mid
->mi_ndi_event_hdl
,
1128 cb
->ndi_evtcb_cookie
));
1130 /* remove event registration from our event set */
1131 return (ndi_event_remove_callback(usb_mid
->mi_ndi_event_hdl
, cb_id
));
1136 usb_mid_busop_post_event(dev_info_t
*dip
,
1138 ddi_eventcookie_t cookie
,
1141 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
1143 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1144 "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p "
1145 "cookie=0x%p, impl=0x%p",
1146 (void *)dip
, (void *)rdip
, (void *)cookie
, bus_impldata
);
1147 USB_DPRINTF_L3(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1148 "(dip=%s%d rdip=%s%d event=%s)",
1149 ddi_driver_name(dip
), ddi_get_instance(dip
),
1150 ddi_driver_name(rdip
), ddi_get_instance(rdip
),
1151 ndi_event_cookie_to_name(usb_mid
->mi_ndi_event_hdl
, cookie
));
1153 /* post event to all children registered for this event */
1154 return (ndi_event_run_callbacks(usb_mid
->mi_ndi_event_hdl
, rdip
,
1155 cookie
, bus_impldata
));
1160 * usb_mid_restore_device_state
1161 * set the original configuration of the device
1164 usb_mid_restore_device_state(dev_info_t
*dip
, usb_mid_t
*usb_mid
)
1166 usb_common_power_t
*midpm
;
1168 USB_DPRINTF_L4(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1169 "usb_mid_restore_device_state: usb_mid = %p", (void *)usb_mid
);
1171 mutex_enter(&usb_mid
->mi_mutex
);
1172 midpm
= usb_mid
->mi_pm
;
1173 mutex_exit(&usb_mid
->mi_mutex
);
1175 /* First bring the device to full power */
1176 (void) pm_busy_component(dip
, 0);
1177 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
1179 if (usb_check_same_device(dip
, usb_mid
->mi_log_handle
, USB_LOG_L0
,
1180 DPRINT_MASK_EVENTS
, USB_CHK_VIDPID
, NULL
) != USB_SUCCESS
) {
1182 /* change the device state from suspended to disconnected */
1183 mutex_enter(&usb_mid
->mi_mutex
);
1184 usb_mid
->mi_dev_state
= USB_DEV_DISCONNECTED
;
1185 mutex_exit(&usb_mid
->mi_mutex
);
1186 (void) pm_idle_component(dip
, 0);
1188 return (USB_FAILURE
);
1192 * if the device had remote wakeup earlier,
1195 if (midpm
->uc_wakeup_enabled
) {
1196 (void) usb_handle_remote_wakeup(usb_mid
->mi_dip
,
1197 USB_REMOTE_WAKEUP_ENABLE
);
1200 mutex_enter(&usb_mid
->mi_mutex
);
1201 usb_mid
->mi_dev_state
= USB_DEV_ONLINE
;
1202 mutex_exit(&usb_mid
->mi_mutex
);
1204 (void) pm_idle_component(dip
, 0);
1206 return (USB_SUCCESS
);
1211 * usb_mid_event_cb()
1212 * handle disconnect and connect events
1215 usb_mid_event_cb(dev_info_t
*dip
, ddi_eventcookie_t cookie
,
1216 void *arg
, void *bus_impldata
)
1219 usb_mid_t
*usb_mid
= usb_mid_obtain_state(dip
);
1220 dev_info_t
*child_dip
;
1221 ddi_eventcookie_t rm_cookie
, ins_cookie
, suspend_cookie
, resume_cookie
;
1223 USB_DPRINTF_L4(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1224 "usb_mid_event_cb: dip=0x%p, cookie=0x%p, "
1225 "arg=0x%p, impl=0x%p",
1226 (void *)dip
, (void *)cookie
, arg
, bus_impldata
);
1227 USB_DPRINTF_L4(DPRINT_MASK_EVENTS
, usb_mid
->mi_log_handle
,
1228 "(dip=%s%d event=%s)",
1229 ddi_driver_name(dip
), ddi_get_instance(dip
),
1230 ndi_event_cookie_to_name(usb_mid
->mi_ndi_event_hdl
, cookie
));
1232 tag
= NDI_EVENT_TAG(cookie
);
1233 rm_cookie
= ndi_event_tag_to_cookie(
1234 usb_mid
->mi_ndi_event_hdl
, USBA_EVENT_TAG_HOT_REMOVAL
);
1235 suspend_cookie
= ndi_event_tag_to_cookie(
1236 usb_mid
->mi_ndi_event_hdl
, USBA_EVENT_TAG_PRE_SUSPEND
);
1237 ins_cookie
= ndi_event_tag_to_cookie(
1238 usb_mid
->mi_ndi_event_hdl
, USBA_EVENT_TAG_HOT_INSERTION
);
1239 resume_cookie
= ndi_event_tag_to_cookie(
1240 usb_mid
->mi_ndi_event_hdl
, USBA_EVENT_TAG_POST_RESUME
);
1242 mutex_enter(&usb_mid
->mi_mutex
);
1244 case USBA_EVENT_TAG_HOT_REMOVAL
:
1245 if (usb_mid
->mi_dev_state
== USB_DEV_DISCONNECTED
) {
1246 USB_DPRINTF_L2(DPRINT_MASK_EVENTS
,
1247 usb_mid
->mi_log_handle
,
1248 "usb_mid_event_cb: Device already disconnected");
1250 /* we are disconnected so set our state now */
1251 usb_mid
->mi_dev_state
= USB_DEV_DISCONNECTED
;
1252 for (i
= 0; i
< usb_mid
->mi_n_ifs
; i
++) {
1253 usb_mid
->mi_child_events
[i
] &= ~
1254 USB_MID_CHILD_EVENT_DISCONNECT
;
1256 mutex_exit(&usb_mid
->mi_mutex
);
1258 /* pass disconnect event to all the children */
1259 (void) ndi_event_run_callbacks(
1260 usb_mid
->mi_ndi_event_hdl
, NULL
,
1261 rm_cookie
, bus_impldata
);
1263 if (usb_mid
->mi_ugen_hdl
) {
1264 (void) usb_ugen_disconnect_ev_cb(
1265 usb_mid
->mi_ugen_hdl
);
1267 mutex_enter(&usb_mid
->mi_mutex
);
1270 case USBA_EVENT_TAG_PRE_SUSPEND
:
1271 /* set our state *after* suspending children */
1272 mutex_exit(&usb_mid
->mi_mutex
);
1274 /* pass pre_suspend event to all the children */
1275 (void) ndi_event_run_callbacks(usb_mid
->mi_ndi_event_hdl
,
1276 NULL
, suspend_cookie
, bus_impldata
);
1278 mutex_enter(&usb_mid
->mi_mutex
);
1279 for (i
= 0; i
< usb_mid
->mi_n_ifs
; i
++) {
1280 usb_mid
->mi_child_events
[i
] &= ~
1281 USB_MID_CHILD_EVENT_PRESUSPEND
;
1284 case USBA_EVENT_TAG_HOT_INSERTION
:
1285 mutex_exit(&usb_mid
->mi_mutex
);
1286 if (usb_mid_restore_device_state(dip
, usb_mid
) == USB_SUCCESS
) {
1289 * Check to see if this child has missed the disconnect
1290 * event before it registered for event cb
1292 mutex_enter(&usb_mid
->mi_mutex
);
1293 for (i
= 0; i
< usb_mid
->mi_n_ifs
; i
++) {
1294 if ((usb_mid
->mi_child_events
[i
] &
1295 USB_MID_CHILD_EVENT_DISCONNECT
) &&
1296 usb_mid
->mi_children_ifs
[i
]) {
1297 usb_mid
->mi_child_events
[i
] &=
1298 ~USB_MID_CHILD_EVENT_DISCONNECT
;
1300 usb_mid
->mi_children_dips
[i
];
1301 mutex_exit(&usb_mid
->mi_mutex
);
1303 /* post the missed disconnect */
1304 (void) ndi_event_do_callback(
1305 usb_mid
->mi_ndi_event_hdl
,
1309 mutex_enter(&usb_mid
->mi_mutex
);
1312 mutex_exit(&usb_mid
->mi_mutex
);
1314 /* pass reconnect event to all the children */
1315 (void) ndi_event_run_callbacks(
1316 usb_mid
->mi_ndi_event_hdl
, NULL
,
1317 ins_cookie
, bus_impldata
);
1319 if (usb_mid
->mi_ugen_hdl
) {
1320 (void) usb_ugen_reconnect_ev_cb(
1321 usb_mid
->mi_ugen_hdl
);
1324 mutex_enter(&usb_mid
->mi_mutex
);
1326 case USBA_EVENT_TAG_POST_RESUME
:
1328 * Check to see if this child has missed the pre-suspend
1329 * event before it registered for event cb
1331 for (i
= 0; i
< usb_mid
->mi_n_ifs
; i
++) {
1332 if ((usb_mid
->mi_child_events
[i
] &
1333 USB_MID_CHILD_EVENT_PRESUSPEND
) &&
1334 usb_mid
->mi_children_ifs
[i
]) {
1335 usb_mid
->mi_child_events
[i
] &=
1336 ~USB_MID_CHILD_EVENT_PRESUSPEND
;
1337 child_dip
= usb_mid
->mi_children_dips
[i
];
1338 mutex_exit(&usb_mid
->mi_mutex
);
1340 /* post the missed pre-suspend event */
1341 (void) ndi_event_do_callback(
1342 usb_mid
->mi_ndi_event_hdl
,
1343 child_dip
, suspend_cookie
,
1345 mutex_enter(&usb_mid
->mi_mutex
);
1348 mutex_exit(&usb_mid
->mi_mutex
);
1350 /* pass post_resume event to all the children */
1351 (void) ndi_event_run_callbacks(usb_mid
->mi_ndi_event_hdl
,
1352 NULL
, resume_cookie
, bus_impldata
);
1354 mutex_enter(&usb_mid
->mi_mutex
);
1357 mutex_exit(&usb_mid
->mi_mutex
);
1363 * create the pm components required for power management
1366 usb_mid_create_pm_components(dev_info_t
*dip
, usb_mid_t
*usb_mid
)
1368 usb_common_power_t
*midpm
;
1371 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
1372 "usb_mid_create_pm_components: Begin");
1374 /* Allocate the PM state structure */
1375 midpm
= kmem_zalloc(sizeof (usb_common_power_t
), KM_SLEEP
);
1377 mutex_enter(&usb_mid
->mi_mutex
);
1378 usb_mid
->mi_pm
= midpm
;
1379 midpm
->uc_usb_statep
= usb_mid
;
1380 midpm
->uc_pm_capabilities
= 0; /* XXXX should this be 0?? */
1381 midpm
->uc_current_power
= USB_DEV_OS_FULL_PWR
;
1382 mutex_exit(&usb_mid
->mi_mutex
);
1385 * By not enabling parental notification, PM enforces
1386 * "strict parental dependency" meaning, usb_mid won't
1387 * power off until any of its children are in full power.
1391 * there are 3 scenarios:
1392 * 1. a well behaved device should have remote wakeup
1393 * at interface and device level. If the interface
1394 * wakes up, usb_mid will wake up
1395 * 2. if the device doesn't have remote wake up and
1396 * the interface has, PM will still work, ie.
1397 * the interfaces wakes up and usb_mid wakes up
1398 * 3. if neither the interface nor device has remote
1399 * wakeup, the interface will wake up when it is opened
1400 * and goes to sleep after being closed for a while
1401 * In this case usb_mid should also go to sleep shortly
1403 * In all scenarios it doesn't really matter whether
1404 * remote wakeup at the device level is enabled or not
1405 * but we do it anyways
1407 if (usb_handle_remote_wakeup(dip
, USB_REMOTE_WAKEUP_ENABLE
) ==
1409 USB_DPRINTF_L3(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
1410 "usb_mid_create_pm_components: "
1411 "Remote Wakeup Enabled");
1412 midpm
->uc_wakeup_enabled
= 1;
1415 if (usb_create_pm_components(dip
, &pwr_states
) ==
1417 midpm
->uc_pwr_states
= (uint8_t)pwr_states
;
1418 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
1421 USB_DPRINTF_L4(DPRINT_MASK_PM
, usb_mid
->mi_log_handle
,
1422 "usb_mid_create_pm_components: End");
1427 * usb_mid_obtain_state:
1430 usb_mid_obtain_state(dev_info_t
*dip
)
1432 int instance
= ddi_get_instance(dip
);
1433 usb_mid_t
*statep
= ddi_get_soft_state(usb_mid_statep
, instance
);
1435 ASSERT(statep
!= NULL
);
1446 usb_mid_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
1448 struct usb_mid
*usb_mid
;
1451 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
1452 USB_MID_MINOR_TO_INSTANCE(getminor(*devp
)))) == NULL
) {
1457 USB_DPRINTF_L4(DPRINT_MASK_CBOPS
, usb_mid
->mi_log_handle
,
1458 "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx",
1459 (void *)usb_mid
, *devp
);
1461 /* First bring the device to full power */
1462 (void) pm_busy_component(usb_mid
->mi_dip
, 0);
1463 (void) pm_raise_power(usb_mid
->mi_dip
, 0, USB_DEV_OS_FULL_PWR
);
1466 rval
= usb_ugen_open(usb_mid
->mi_ugen_hdl
, devp
, flags
, otyp
,
1469 (void) pm_idle_component(usb_mid
->mi_dip
, 0);
1472 * since all ugen opens are exclusive we can count the
1475 mutex_enter(&usb_mid
->mi_mutex
);
1476 usb_mid
->mi_ugen_open_count
++;
1477 mutex_exit(&usb_mid
->mi_mutex
);
1486 usb_mid_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
1488 struct usb_mid
*usb_mid
;
1491 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
1492 USB_MID_MINOR_TO_INSTANCE(getminor(dev
)))) == NULL
) {
1497 rval
= usb_ugen_close(usb_mid
->mi_ugen_hdl
, dev
, flag
, otyp
,
1500 (void) pm_idle_component(usb_mid
->mi_dip
, 0);
1501 mutex_enter(&usb_mid
->mi_mutex
);
1502 usb_mid
->mi_ugen_open_count
--;
1503 mutex_exit(&usb_mid
->mi_mutex
);
1511 usb_mid_read(dev_t dev
, struct uio
*uio
, cred_t
*credp
)
1513 struct usb_mid
*usb_mid
;
1515 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
1516 USB_MID_MINOR_TO_INSTANCE(getminor(dev
)))) == NULL
) {
1521 return (usb_ugen_read(usb_mid
->mi_ugen_hdl
, dev
, uio
, credp
));
1526 usb_mid_write(dev_t dev
, struct uio
*uio
, cred_t
*credp
)
1528 struct usb_mid
*usb_mid
;
1530 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
1531 USB_MID_MINOR_TO_INSTANCE(getminor(dev
)))) == NULL
) {
1536 return (usb_ugen_write(usb_mid
->mi_ugen_hdl
, dev
, uio
, credp
));
1541 usb_mid_poll(dev_t dev
, short events
, int anyyet
, short *reventsp
,
1542 struct pollhead
**phpp
)
1544 struct usb_mid
*usb_mid
;
1546 if ((usb_mid
= ddi_get_soft_state(usb_mid_statep
,
1547 USB_MID_MINOR_TO_INSTANCE(getminor(dev
)))) == NULL
) {
1552 return (usb_ugen_poll(usb_mid
->mi_ugen_hdl
, dev
, events
,
1553 anyyet
, reventsp
, phpp
));