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.
25 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
30 * USBA: Solaris USB Architecture support
32 #define USBA_FRAMEWORK
33 #include <sys/usb/usba/usba_impl.h>
34 #include <sys/usb/usba/hcdi_impl.h>
35 #include <sys/usb/hubd/hub.h>
36 #include <sys/fs/dv_node.h>
38 static int usba_str_startcmp(char *, char *);
41 * USBA private variables and tunables
43 static kmutex_t usba_mutex
;
45 /* mutex to protect usba_root_hubs */
46 static kmutex_t usba_hub_mutex
;
48 typedef struct usba_root_hub_ent
{
50 struct usba_root_hub_ent
*next
;
53 static usba_root_hub_ent_t
*usba_root_hubs
= NULL
;
56 * ddivs forced binding:
58 * usbc usbc_xhubs usbc_xaddress node name
60 * 0 x x class name or "device"
63 * 1 0 >1 ddivs_usbc except device
65 * 1 1 0 ddivs_usbc except hubs
66 * 1 1 >1 ddivs_usbc except hubs and
67 * device at usbc_xaddress
69 uint_t usba_ddivs_usbc
;
70 uint_t usba_ddivs_usbc_xhubs
;
71 uint_t usba_ddivs_usbc_xaddress
;
73 uint_t usba_ugen_force_binding
;
76 * compatible name handling
79 * allowing for 15 compat names, plus one force bind name and
80 * one possible specified client driver name
82 #define USBA_MAX_COMPAT_NAMES 17
83 #define USBA_MAX_COMPAT_NAME_LEN 64
85 /* double linked list for usba_devices */
86 usba_list_entry_t usba_device_list
;
88 _NOTE(MUTEX_PROTECTS_DATA(usba_mutex
, usba_device_list
))
94 static struct modlmisc modlmisc
= {
95 &mod_miscops
, /* Type of module */
96 "USBA: USB Architecture 2.0 1.66"
99 static struct modlinkage modlinkage
= {
100 MODREV_1
, (void *)&modlmisc
, NULL
104 static usb_log_handle_t usba_log_handle
;
105 uint_t usba_errlevel
= USB_LOG_L4
;
106 uint_t usba_errmask
= (uint_t
)-1;
108 extern usb_log_handle_t hubdi_log_handle
;
116 * usbai providing log support needs to be init'ed first
119 usba_usbai_initialization();
120 usba_usba_initialization();
121 usba_usbai_register_initialization();
122 usba_hcdi_initialization();
123 usba_hubdi_initialization();
124 usba_devdb_initialization();
126 if ((rval
= mod_install(&modlinkage
)) != 0) {
127 usba_devdb_destroy();
128 usba_hubdi_destroy();
130 usba_usbai_register_destroy();
132 usba_usbai_destroy();
143 if ((rval
= mod_remove(&modlinkage
)) == 0) {
144 usba_devdb_destroy();
145 usba_hubdi_destroy();
147 usba_usbai_register_destroy();
149 usba_usbai_destroy();
156 _info(struct modinfo
*modinfop
)
158 return (mod_info(&modlinkage
, modinfop
));
162 usba_owns_ia(dev_info_t
*dip
)
164 int if_count
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
165 "interface-count", 0);
167 return ((if_count
) ? B_TRUE
: B_FALSE
);
171 * common bus ctl for hcd, usb_mid, and hubd
174 usba_bus_ctl(dev_info_t
*dip
,
180 dev_info_t
*child_dip
= (dev_info_t
*)arg
;
181 usba_device_t
*usba_device
;
182 usba_hcdi_t
*usba_hcdi
;
183 usba_hcdi_ops_t
*usba_hcdi_ops
;
185 USB_DPRINTF_L4(DPRINT_MASK_USBA
, hubdi_log_handle
,
186 "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip
),
187 ddi_get_instance(rdip
), ddi_node_name(dip
),
188 ddi_get_instance(dip
), op
);
192 case DDI_CTLOPS_REPORTDEV
:
194 char *name
, compat_name
[64], *speed
;
195 usba_device_t
*hub_usba_device
;
198 usba_device
= usba_get_usba_device(rdip
);
200 /* find the parent hub */
201 hubdip
= ddi_get_parent(rdip
);
202 while ((strcmp(ddi_driver_name(hubdip
), "hubd") != 0) &&
203 !(usba_is_root_hub(hubdip
))) {
204 hubdip
= ddi_get_parent(hubdip
);
207 hub_usba_device
= usba_get_usba_device(hubdip
);
210 if (usb_owns_device(rdip
)) {
211 (void) snprintf(compat_name
,
212 sizeof (compat_name
),
214 usba_device
->usb_dev_descr
->idVendor
,
215 usba_device
->usb_dev_descr
->idProduct
);
216 } else if (usba_owns_ia(rdip
)) {
217 (void) snprintf(compat_name
,
218 sizeof (compat_name
),
219 "usbia%x,%x.config%x.%x",
220 usba_device
->usb_dev_descr
->idVendor
,
221 usba_device
->usb_dev_descr
->idProduct
,
222 usba_device
->usb_cfg_value
,
223 usb_get_if_number(rdip
));
225 (void) snprintf(compat_name
,
226 sizeof (compat_name
),
227 "usbif%x,%x.config%x.%x",
228 usba_device
->usb_dev_descr
->idVendor
,
229 usba_device
->usb_dev_descr
->idProduct
,
230 usba_device
->usb_cfg_value
,
231 usb_get_if_number(rdip
));
233 switch (usba_device
->usb_port_status
) {
234 case USBA_HIGH_SPEED_DEV
:
235 speed
= "hi speed (USB 2.x)";
238 case USBA_LOW_SPEED_DEV
:
239 speed
= "low speed (USB 1.x)";
242 case USBA_FULL_SPEED_DEV
:
244 speed
= "full speed (USB 1.x)";
250 "?USB %x.%x %s (%s) operating at %s on "
252 "%s@%s, %s%d at bus address %d\n",
253 (usba_device
->usb_dev_descr
->bcdUSB
& 0xff00) >> 8,
254 usba_device
->usb_dev_descr
->bcdUSB
& 0xff,
255 (usb_owns_device(rdip
) ? "device" :
256 ((usba_owns_ia(rdip
) ? "interface-association" :
259 (hub_usba_device
->usb_dev_descr
->bcdUSB
&
261 hub_usba_device
->usb_dev_descr
->bcdUSB
& 0xff,
262 usba_is_root_hub(hubdip
) ? "root" : "external",
263 ddi_node_name(rdip
), ddi_get_name_addr(rdip
),
264 ddi_driver_name(rdip
),
265 ddi_get_instance(rdip
), usba_device
->usb_addr
);
267 name
= kmem_alloc(MAXNAMELEN
, KM_SLEEP
);
268 (void) usba_get_mfg_prod_sn_str(rdip
, name
, MAXNAMELEN
);
269 if (name
[0] != '\0') {
270 cmn_err(CE_CONT
, "?\t%s\n", name
);
272 kmem_free(name
, MAXNAMELEN
);
274 } else { /* harden USBA against this case; if it happens */
277 "?USB-device: %s@%s, %s%d\n",
278 ddi_node_name(rdip
), ddi_get_name_addr(rdip
),
279 ddi_driver_name(rdip
), ddi_get_instance(rdip
));
282 return (DDI_SUCCESS
);
285 case DDI_CTLOPS_INITCHILD
:
292 int len
= sizeof (usb_addr
);
294 usba_hcdi
= usba_hcdi_get_hcdi(dip
);
295 usba_hcdi_ops
= usba_hcdi
->hcdi_ops
;
296 ASSERT(usba_hcdi_ops
!= NULL
);
299 * as long as the dip exists, it should have
300 * usba_device structure associated with it
302 usba_device
= usba_get_usba_device(child_dip
);
303 if (usba_device
== NULL
) {
305 USB_DPRINTF_L2(DPRINT_MASK_USBA
, hubdi_log_handle
,
306 "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
307 ddi_node_name(child_dip
), (void *)child_dip
);
309 return (DDI_NOT_WELL_FORMED
);
312 /* the dip should have an address and reg property */
313 if (ddi_prop_op(DDI_DEV_T_NONE
, child_dip
, PROP_LEN_AND_VAL_BUF
,
314 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
, "assigned-address",
315 (caddr_t
)&usb_addr
, &len
) != DDI_SUCCESS
) {
317 USB_DPRINTF_L2(DPRINT_MASK_USBA
, hubdi_log_handle
,
319 "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
320 ddi_node_name(rdip
), ddi_get_instance(rdip
),
321 ddi_node_name(dip
), ddi_get_instance(dip
), op
,
322 (void *)rdip
, (void *)dip
);
324 USB_DPRINTF_L2(DPRINT_MASK_USBA
, hubdi_log_handle
,
325 "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
326 ddi_node_name(child_dip
), (void *)child_dip
);
328 return (DDI_NOT_WELL_FORMED
);
331 if ((rval
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, child_dip
,
332 DDI_PROP_DONTPASS
, "reg",
333 &data
, &n
)) != DDI_SUCCESS
) {
335 USB_DPRINTF_L2(DPRINT_MASK_USBA
, hubdi_log_handle
,
336 "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval
);
338 return (DDI_NOT_WELL_FORMED
);
343 * if the configuration is 1, the unit address is
344 * just the interface number
346 if ((n
== 1) || ((n
> 1) && (data
[1] == 1))) {
347 (void) sprintf(name
, "%x", data
[0]);
349 (void) sprintf(name
, "%x,%x", data
[0], data
[1]);
352 USB_DPRINTF_L3(DPRINT_MASK_USBA
,
353 hubdi_log_handle
, "usba_bus_ctl: name = %s", name
);
356 ddi_set_name_addr(child_dip
, name
);
359 * increment the reference count for each child using this
360 * usba_device structure
362 mutex_enter(&usba_device
->usb_mutex
);
363 usba_device
->usb_ref_count
++;
365 USB_DPRINTF_L3(DPRINT_MASK_USBA
, hubdi_log_handle
,
366 "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
367 (void *)usba_device
, usba_device
->usb_ref_count
);
369 mutex_exit(&usba_device
->usb_mutex
);
371 return (DDI_SUCCESS
);
374 case DDI_CTLOPS_UNINITCHILD
:
376 usba_device
= usba_get_usba_device(child_dip
);
378 if (usba_device
!= NULL
) {
380 * decrement the reference count for each child
381 * using this usba_device structure
383 mutex_enter(&usba_device
->usb_mutex
);
384 usba_device
->usb_ref_count
--;
386 USB_DPRINTF_L3(DPRINT_MASK_USBA
, hubdi_log_handle
,
387 "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
389 (void *)usba_device
, usba_device
->usb_ref_count
);
391 mutex_exit(&usba_device
->usb_mutex
);
393 ddi_set_name_addr(child_dip
, NULL
);
395 return (DDI_SUCCESS
);
398 case DDI_CTLOPS_IOMIN
:
400 return (DDI_SUCCESS
);
403 * These ops correspond to functions that "shouldn't" be called
404 * by a USB client driver. So we whine when we're called.
406 case DDI_CTLOPS_DMAPMAPC
:
407 case DDI_CTLOPS_REPORTINT
:
408 case DDI_CTLOPS_REGSIZE
:
409 case DDI_CTLOPS_NREGS
:
410 case DDI_CTLOPS_SIDDEV
:
411 case DDI_CTLOPS_SLAVEONLY
:
412 case DDI_CTLOPS_AFFINITY
:
413 case DDI_CTLOPS_POKE
:
414 case DDI_CTLOPS_PEEK
:
415 cmn_err(CE_CONT
, "%s%d: invalid op (%d) from %s%d",
416 ddi_node_name(dip
), ddi_get_instance(dip
),
417 op
, ddi_node_name(rdip
), ddi_get_instance(rdip
));
418 return (DDI_FAILURE
);
421 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
424 return (ddi_ctlops(dip
, rdip
, op
, arg
, result
));
430 * initialize and destroy USBA module
433 usba_usba_initialization()
435 usba_log_handle
= usb_alloc_log_hdl(NULL
, "usba", &usba_errlevel
,
436 &usba_errmask
, NULL
, 0);
438 USB_DPRINTF_L4(DPRINT_MASK_USBA
,
439 usba_log_handle
, "usba_usba_initialization");
441 mutex_init(&usba_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
442 mutex_init(&usba_hub_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
443 usba_init_list(&usba_device_list
, NULL
, NULL
);
450 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
, "usba_usba_destroy");
452 mutex_destroy(&usba_hub_mutex
);
453 mutex_destroy(&usba_mutex
);
454 usba_destroy_list(&usba_device_list
);
456 usb_free_log_hdl(usba_log_handle
);
461 * usba_set_usb_address:
462 * set usb address in usba_device structure
465 usba_set_usb_address(usba_device_t
*usba_device
)
470 char *usb_address_in_use
;
472 mutex_enter(&usba_device
->usb_mutex
);
474 hcdi
= usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
476 mutex_enter(&hcdi
->hcdi_mutex
);
477 usb_address_in_use
= hcdi
->hcdi_usb_address_in_use
;
479 for (address
= ROOT_HUB_ADDR
+ 1;
480 address
<= USBA_MAX_ADDRESS
; address
++) {
481 if (usb_address_in_use
[address
/s
] & (1 << (address
% s
))) {
484 usb_address_in_use
[address
/s
] |= (1 << (address
% s
));
485 hcdi
->hcdi_device_count
++;
486 HCDI_HOTPLUG_STATS_DATA(hcdi
)->hcdi_device_count
.value
.ui64
++;
487 mutex_exit(&hcdi
->hcdi_mutex
);
489 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
490 "usba_set_usb_address: %d", address
);
492 usba_device
->usb_addr
= address
;
494 mutex_exit(&usba_device
->usb_mutex
);
496 return (USB_SUCCESS
);
499 usba_device
->usb_addr
= 0;
501 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
502 "no usb address available");
504 mutex_exit(&hcdi
->hcdi_mutex
);
505 mutex_exit(&usba_device
->usb_mutex
);
507 return (USB_FAILURE
);
512 * usba_unset_usb_address:
513 * unset usb_address in usba_device structure
516 usba_unset_usb_address(usba_device_t
*usba_device
)
521 char *usb_address_in_use
;
523 mutex_enter(&usba_device
->usb_mutex
);
524 address
= usba_device
->usb_addr
;
525 hcdi
= usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
527 if (address
> ROOT_HUB_ADDR
) {
528 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
529 "usba_unset_usb_address: address=%d", address
);
531 mutex_enter(&hcdi
->hcdi_mutex
);
532 usb_address_in_use
= hcdi
->hcdi_usb_address_in_use
;
534 ASSERT(usb_address_in_use
[address
/s
] & (1 << (address
% s
)));
536 usb_address_in_use
[address
/s
] &= ~(1 << (address
% s
));
538 hcdi
->hcdi_device_count
--;
539 HCDI_HOTPLUG_STATS_DATA(hcdi
)->hcdi_device_count
.value
.ui64
--;
541 mutex_exit(&hcdi
->hcdi_mutex
);
543 usba_device
->usb_addr
= 0;
545 mutex_exit(&usba_device
->usb_mutex
);
550 usba_get_evdata(dev_info_t
*dip
)
552 usba_evdata_t
*evdata
;
553 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
555 /* called when dip attaches */
556 ASSERT(usba_device
!= NULL
);
558 mutex_enter(&usba_device
->usb_mutex
);
559 evdata
= usba_device
->usb_evdata
;
561 if (evdata
->ev_dip
== dip
) {
562 mutex_exit(&usba_device
->usb_mutex
);
566 evdata
= evdata
->ev_next
;
569 evdata
= kmem_zalloc(sizeof (usba_evdata_t
), KM_SLEEP
);
570 evdata
->ev_dip
= dip
;
571 evdata
->ev_next
= usba_device
->usb_evdata
;
572 usba_device
->usb_evdata
= evdata
;
573 mutex_exit(&usba_device
->usb_mutex
);
580 * allocate a usb device structure and link it in the list
583 usba_alloc_usba_device(dev_info_t
*root_hub_dip
)
585 usba_device_t
*usba_device
;
587 ddi_iblock_cookie_t iblock_cookie
=
588 usba_hcdi_get_hcdi(root_hub_dip
)->hcdi_iblock_cookie
;
591 * create a new usba_device structure
593 usba_device
= kmem_zalloc(sizeof (usba_device_t
), KM_SLEEP
);
596 * initialize usba_device
598 mutex_init(&usba_device
->usb_mutex
, NULL
, MUTEX_DRIVER
,
601 usba_init_list(&usba_device
->usb_device_list
, (usb_opaque_t
)usba_device
,
603 usba_init_list(&usba_device
->usb_allocated
, (usb_opaque_t
)usba_device
,
605 mutex_enter(&usba_device
->usb_mutex
);
606 usba_device
->usb_root_hub_dip
= root_hub_dip
;
609 * add to list of usba_devices
611 usba_add_to_list(&usba_device_list
, &usba_device
->usb_device_list
);
613 /* init mutex in each usba_ph_impl structure */
614 for (ep_idx
= 0; ep_idx
< USBA_N_ENDPOINTS
; ep_idx
++) {
615 mutex_init(&usba_device
->usb_ph_list
[ep_idx
].usba_ph_mutex
,
616 NULL
, MUTEX_DRIVER
, iblock_cookie
);
619 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
620 "allocated usba_device 0x%p", (void *)usba_device
);
622 mutex_exit(&usba_device
->usb_mutex
);
624 return (usba_device
);
628 /* free NDI event data associated with usba_device */
630 usba_free_evdata(usba_evdata_t
*evdata
)
635 next
= evdata
->ev_next
;
636 kmem_free(evdata
, sizeof (usba_evdata_t
));
643 * free usb device structure
646 usba_free_usba_device(usba_device_t
*usba_device
)
649 usb_pipe_handle_t def_ph
;
651 if (usba_device
== NULL
) {
656 mutex_enter(&usba_device
->usb_mutex
);
657 if (usba_device
->usb_ref_count
) {
658 mutex_exit(&usba_device
->usb_mutex
);
663 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
664 "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
665 (void *)usba_device
, usba_device
->usb_addr
,
666 usba_device
->usb_ref_count
);
668 usba_free_evdata(usba_device
->usb_evdata
);
669 mutex_exit(&usba_device
->usb_mutex
);
671 def_ph
= usba_usbdev_to_dflt_pipe_handle(usba_device
);
672 if (def_ph
!= NULL
) {
673 usba_pipe_handle_data_t
*ph_data
= usba_get_ph_data(def_ph
);
676 usb_pipe_close(ph_data
->p_dip
, def_ph
,
677 USB_FLAGS_SLEEP
| USBA_FLAGS_PRIVILEGED
,
682 mutex_enter(&usba_mutex
);
684 /* destroy mutex in each usba_ph_impl structure */
685 for (ep_idx
= 0; ep_idx
< USBA_N_ENDPOINTS
; ep_idx
++) {
686 mutex_destroy(&usba_device
->usb_ph_list
[ep_idx
].usba_ph_mutex
);
689 (void) usba_rm_from_list(&usba_device_list
,
690 &usba_device
->usb_device_list
);
692 mutex_exit(&usba_mutex
);
694 usba_destroy_list(&usba_device
->usb_device_list
);
695 usba_destroy_list(&usba_device
->usb_allocated
);
697 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
698 "deallocating usba_device = 0x%p, address = 0x%x",
699 (void *)usba_device
, usba_device
->usb_addr
);
702 * ohci allocates descriptors for root hub so we can't
703 * deallocate these here
706 if (usba_device
->usb_addr
!= ROOT_HUB_ADDR
) {
707 if (usba_device
->usb_cfg_array
) {
708 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
709 "deallocating usb_config_array: 0x%p",
710 (void *)usba_device
->usb_cfg_array
);
711 mutex_enter(&usba_device
->usb_mutex
);
713 i
< usba_device
->usb_dev_descr
->bNumConfigurations
;
715 if (usba_device
->usb_cfg_array
[i
]) {
717 usba_device
->usb_cfg_array
[i
],
718 usba_device
->usb_cfg_array_len
[i
]);
722 /* free the array pointers */
723 kmem_free(usba_device
->usb_cfg_array
,
724 usba_device
->usb_cfg_array_length
);
725 kmem_free(usba_device
->usb_cfg_array_len
,
726 usba_device
->usb_cfg_array_len_length
);
728 mutex_exit(&usba_device
->usb_mutex
);
731 if (usba_device
->usb_cfg_str_descr
) {
732 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
733 "deallocating usb_cfg_str_descr: 0x%p",
734 (void *)usba_device
->usb_cfg_str_descr
);
736 i
< usba_device
->usb_dev_descr
->bNumConfigurations
;
738 if (usba_device
->usb_cfg_str_descr
[i
]) {
740 usba_device
->usb_cfg_str_descr
[i
],
742 usb_cfg_str_descr
[i
]) + 1);
745 /* free the array pointers */
746 kmem_free(usba_device
->usb_cfg_str_descr
,
747 sizeof (uchar_t
*) * usba_device
->usb_n_cfgs
);
750 if (usba_device
->usb_dev_descr
) {
751 kmem_free(usba_device
->usb_dev_descr
,
752 sizeof (usb_dev_descr_t
));
755 if (usba_device
->usb_mfg_str
) {
756 kmem_free(usba_device
->usb_mfg_str
,
757 strlen(usba_device
->usb_mfg_str
) + 1);
760 if (usba_device
->usb_product_str
) {
761 kmem_free(usba_device
->usb_product_str
,
762 strlen(usba_device
->usb_product_str
) + 1);
765 if (usba_device
->usb_serialno_str
) {
766 kmem_free(usba_device
->usb_serialno_str
,
767 strlen(usba_device
->usb_serialno_str
) + 1);
770 usba_unset_usb_address(usba_device
);
774 ASSERT(usba_device
->usb_client_dev_data_list
.cddl_next
== NULL
);
777 if (usba_device
->usb_client_flags
) {
781 for (i
= 0; i
< usba_device
->usb_n_ifs
; i
++) {
782 ASSERT(usba_device
->usb_client_flags
[i
] == 0);
785 kmem_free(usba_device
->usb_client_flags
,
786 usba_device
->usb_n_ifs
* USBA_CLIENT_FLAG_SIZE
);
790 if (usba_device
->usb_client_attach_list
) {
791 kmem_free(usba_device
->usb_client_attach_list
,
792 usba_device
->usb_n_ifs
*
793 sizeof (*usba_device
->usb_client_attach_list
));
795 if (usba_device
->usb_client_ev_cb_list
) {
796 kmem_free(usba_device
->usb_client_ev_cb_list
,
797 usba_device
->usb_n_ifs
*
798 sizeof (*usba_device
->usb_client_ev_cb_list
));
802 * finally ready to destroy the structure
804 mutex_destroy(&usba_device
->usb_mutex
);
806 kmem_free((caddr_t
)usba_device
, sizeof (usba_device_t
));
810 /* clear the data toggle for all endpoints on this device */
812 usba_clear_data_toggle(usba_device_t
*usba_device
)
816 if (usba_device
!= NULL
) {
817 mutex_enter(&usba_device
->usb_mutex
);
818 for (i
= 0; i
< USBA_N_ENDPOINTS
; i
++) {
819 usba_device
->usb_ph_list
[i
].usba_ph_flags
&=
820 ~USBA_PH_DATA_TOGGLE
;
822 mutex_exit(&usba_device
->usb_mutex
);
828 * usba_create_child_devi():
829 * create a child devinfo node, usba_device, attach properties.
830 * the usba_device structure is shared between all interfaces
833 usba_create_child_devi(dev_info_t
*dip
,
835 usba_hcdi_ops_t
*usba_hcdi_ops
,
836 dev_info_t
*usb_root_hub_dip
,
837 usb_port_status_t port_status
,
838 usba_device_t
*usba_device
,
839 dev_info_t
**child_dip
)
841 int rval
= USB_FAILURE
;
842 int usba_device_allocated
= 0;
845 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
846 "usba_create_child_devi: %s usba_device=0x%p "
847 "port status=0x%x", node_name
,
848 (void *)usba_device
, port_status
);
850 ndi_devi_alloc_sleep(dip
, node_name
, (pnode_t
)DEVI_SID_NODEID
,
853 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
854 "child dip=0x%p", (void *)*child_dip
);
856 if (usba_device
== NULL
) {
858 usba_device
= usba_alloc_usba_device(usb_root_hub_dip
);
860 /* grab the mutex to keep warlock happy */
861 mutex_enter(&usba_device
->usb_mutex
);
862 usba_device
->usb_hcdi_ops
= usba_hcdi_ops
;
863 usba_device
->usb_port_status
= port_status
;
864 mutex_exit(&usba_device
->usb_mutex
);
866 usba_device_allocated
++;
868 mutex_enter(&usba_device
->usb_mutex
);
870 ASSERT(usba_device
->usb_hcdi_ops
== usba_hcdi_ops
);
872 if (usb_root_hub_dip
) {
873 ASSERT(usba_device
->usb_root_hub_dip
==
877 usba_device
->usb_port_status
= port_status
;
879 mutex_exit(&usba_device
->usb_mutex
);
882 if (usba_device
->usb_addr
== 0) {
883 if (usba_set_usb_address(usba_device
) == USB_FAILURE
) {
886 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
887 "cannot set usb address for dip=0x%p",
893 address
= usba_device
->usb_addr
;
895 /* attach properties */
896 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, *child_dip
,
897 "assigned-address", address
);
898 if (rval
!= DDI_PROP_SUCCESS
) {
899 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
900 "cannot set usb address property for dip=0x%p",
908 * store the usba_device point in the dip
910 usba_set_usba_device(*child_dip
, usba_device
);
912 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
913 "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
914 (void *)*child_dip
, ddi_driver_name(*child_dip
),
915 (void *)usba_device
);
917 return (USB_SUCCESS
);
921 int rval
= usba_destroy_child_devi(*child_dip
, NDI_DEVI_REMOVE
);
922 ASSERT(rval
== USB_SUCCESS
);
926 if (usba_device_allocated
) {
927 usba_free_usba_device(usba_device
);
928 } else if (address
&& usba_device
) {
929 usba_unset_usb_address(usba_device
);
932 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
933 "usba_create_child_devi failed: rval=%d", rval
);
940 usba_destroy_child_devi(dev_info_t
*dip
, uint_t flag
)
942 usba_device_t
*usba_device
;
943 int rval
= NDI_SUCCESS
;
945 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
946 "usba_destroy_child_devi: %s%d (0x%p)",
947 ddi_driver_name(dip
), ddi_get_instance(dip
), (void *)dip
);
949 usba_device
= usba_get_usba_device(dip
);
952 * if the child hasn't been bound yet, we can just
955 if (i_ddi_node_state(dip
) < DS_INITIALIZED
) {
957 * do not call ndi_devi_free() since it might
960 rval
= ddi_remove_child(dip
, 0);
963 char *devnm
= kmem_alloc(MAXNAMELEN
+ 1, KM_SLEEP
);
964 dev_info_t
*pdip
= ddi_get_parent(dip
);
966 (void) ddi_deviname(dip
, devnm
);
968 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
969 "usba_destroy_child_devi:\n\t"
970 "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip
,
971 (void *)usba_device
, devnm
);
973 (void) devfs_clean(pdip
, NULL
, DV_CLEAN_FORCE
);
974 rval
= ndi_devi_unconfig_one(pdip
, devnm
+ 1, NULL
,
975 flag
| NDI_UNCONFIG
| NDI_DEVI_OFFLINE
);
976 if (rval
!= NDI_SUCCESS
) {
977 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
978 " ndi_devi_unconfig_one %s%d failed (%d)",
979 ddi_driver_name(dip
), ddi_get_instance(dip
),
982 kmem_free(devnm
, MAXNAMELEN
+ 1);
985 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
986 "usba_destroy_child_devi: rval=%d", rval
);
988 return (rval
== NDI_SUCCESS
? USB_SUCCESS
: USB_FAILURE
);
996 usba_init_list(usba_list_entry_t
*element
, usb_opaque_t
private,
997 ddi_iblock_cookie_t iblock_cookie
)
999 mutex_init(&element
->list_mutex
, NULL
, MUTEX_DRIVER
,
1001 mutex_enter(&element
->list_mutex
);
1002 element
->private = private;
1003 mutex_exit(&element
->list_mutex
);
1008 usba_destroy_list(usba_list_entry_t
*head
)
1010 mutex_enter(&head
->list_mutex
);
1011 ASSERT(head
->next
== NULL
);
1012 ASSERT(head
->prev
== NULL
);
1013 mutex_exit(&head
->list_mutex
);
1015 mutex_destroy(&head
->list_mutex
);
1020 usba_add_to_list(usba_list_entry_t
*head
, usba_list_entry_t
*element
)
1022 usba_list_entry_t
*next
;
1025 mutex_enter(&head
->list_mutex
);
1026 mutex_enter(&element
->list_mutex
);
1028 remaining
= head
->count
;
1030 /* check if it is not in another list */
1031 ASSERT(element
->next
== NULL
);
1032 ASSERT(element
->prev
== NULL
);
1036 * only verify the list when not in interrupt context, we
1037 * have to trust the HCD
1039 if (!servicing_interrupt()) {
1041 /* check if not already in this list */
1042 for (next
= head
->next
; (next
!= NULL
);
1043 next
= next
->next
) {
1044 if (next
== element
) {
1045 USB_DPRINTF_L0(DPRINT_MASK_USBA
,
1047 "Attempt to corrupt USB list at 0x%p",
1049 ASSERT(next
== element
);
1056 * Detect incorrect circ links or found
1057 * unexpected elements.
1059 if ((next
->next
&& (remaining
== 0)) ||
1060 ((next
->next
== NULL
) && remaining
)) {
1061 panic("Corrupted USB list at 0x%p",
1069 if (head
->next
== NULL
) {
1070 head
->prev
= head
->next
= element
;
1073 head
->prev
->next
= element
;
1074 element
->prev
= head
->prev
;
1075 head
->prev
= element
;
1080 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
1081 "usba_add_to_list: head=0x%p element=0x%p count=%d",
1082 (void *)head
, (void *)element
, head
->count
);
1085 mutex_exit(&head
->list_mutex
);
1086 mutex_exit(&element
->list_mutex
);
1091 usba_rm_from_list(usba_list_entry_t
*head
, usba_list_entry_t
*element
)
1093 usba_list_entry_t
*e
;
1097 /* find the element in the list first */
1098 mutex_enter(&head
->list_mutex
);
1100 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
1101 "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1102 (void *)head
, (void *)element
, head
->count
);
1104 remaining
= head
->count
;
1116 /* Detect incorrect circ links or found unexpected elements. */
1117 if ((e
&& (remaining
== 0)) ||
1118 ((e
== NULL
) && (remaining
))) {
1119 panic("Corrupted USB list at 0x%p", (void *)head
);
1125 mutex_exit(&head
->list_mutex
);
1127 return (USB_FAILURE
);
1130 /* now remove the element */
1131 mutex_enter(&element
->list_mutex
);
1133 if (element
->next
) {
1134 element
->next
->prev
= element
->prev
;
1136 if (element
->prev
) {
1137 element
->prev
->next
= element
->next
;
1139 if (head
->next
== element
) {
1140 head
->next
= element
->next
;
1142 if (head
->prev
== element
) {
1143 head
->prev
= element
->prev
;
1146 element
->prev
= element
->next
= NULL
;
1147 if (head
->next
== NULL
) {
1148 ASSERT(head
->prev
== NULL
);
1150 ASSERT(head
->next
->prev
== NULL
);
1152 if (head
->prev
== NULL
) {
1153 ASSERT(head
->next
== NULL
);
1155 ASSERT(head
->prev
->next
== NULL
);
1160 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
1161 "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1162 (void *)head
, (void *)element
, head
->count
);
1164 mutex_exit(&element
->list_mutex
);
1165 mutex_exit(&head
->list_mutex
);
1167 return (USB_SUCCESS
);
1172 usba_rm_first_from_list(usba_list_entry_t
*head
)
1174 usba_list_entry_t
*element
= NULL
;
1177 mutex_enter(&head
->list_mutex
);
1178 element
= head
->next
;
1180 /* now remove the element */
1181 mutex_enter(&element
->list_mutex
);
1182 head
->next
= element
->next
;
1184 head
->next
->prev
= NULL
;
1186 if (head
->prev
== element
) {
1187 head
->prev
= element
->next
;
1189 element
->prev
= element
->next
= NULL
;
1190 mutex_exit(&element
->list_mutex
);
1193 if (head
->next
== NULL
) {
1194 ASSERT(head
->prev
== NULL
);
1196 ASSERT(head
->next
->prev
== NULL
);
1198 if (head
->prev
== NULL
) {
1199 ASSERT(head
->next
== NULL
);
1201 ASSERT(head
->prev
->next
== NULL
);
1203 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
1204 "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1205 (void *)head
, (void *)element
, head
->count
);
1207 mutex_exit(&head
->list_mutex
);
1215 usba_rm_first_pvt_from_list(usba_list_entry_t
*head
)
1217 usba_list_entry_t
*element
= usba_rm_first_from_list(head
);
1218 usb_opaque_t
private = NULL
;
1221 mutex_enter(&element
->list_mutex
);
1222 private = element
->private;
1223 mutex_exit(&element
->list_mutex
);
1231 * move list to new list and zero original list
1234 usba_move_list(usba_list_entry_t
*head
, usba_list_entry_t
*new,
1235 ddi_iblock_cookie_t iblock_cookie
)
1237 usba_init_list(new, NULL
, iblock_cookie
);
1238 mutex_enter(&head
->list_mutex
);
1239 mutex_enter(&new->list_mutex
);
1241 new->next
= head
->next
;
1242 new->prev
= head
->prev
;
1243 new->count
= head
->count
;
1244 new->private = head
->private;
1249 head
->private = NULL
;
1250 mutex_exit(&head
->list_mutex
);
1251 mutex_exit(&new->list_mutex
);
1256 usba_check_in_list(usba_list_entry_t
*head
, usba_list_entry_t
*element
)
1258 int rval
= USB_FAILURE
;
1260 usba_list_entry_t
*next
;
1262 mutex_enter(&head
->list_mutex
);
1263 remaining
= head
->count
;
1265 mutex_enter(&element
->list_mutex
);
1266 for (next
= head
->next
; next
!= NULL
; next
= next
->next
) {
1267 if (next
== element
) {
1273 /* Detect incorrect circ links or found unexpected elements. */
1274 if ((next
->next
&& (remaining
== 0)) ||
1275 ((next
->next
== NULL
) && remaining
)) {
1276 panic("Corrupted USB list at 0x%p", (void *)head
);
1280 mutex_exit(&element
->list_mutex
);
1281 mutex_exit(&head
->list_mutex
);
1288 usba_list_entry_leaks(usba_list_entry_t
*head
, char *what
)
1292 usba_list_entry_t
*next
;
1294 mutex_enter(&head
->list_mutex
);
1295 remaining
= head
->count
;
1296 for (next
= head
->next
; next
!= NULL
; next
= next
->next
) {
1297 USB_DPRINTF_L2(DPRINT_MASK_HCDI
, usba_log_handle
,
1298 "leaking %s 0x%p", what
, (void *)next
->private);
1303 /* Detect incorrect circ links or found unexpected elements. */
1304 if ((next
->next
&& (remaining
== 0)) ||
1305 ((next
->next
== NULL
) && remaining
)) {
1306 panic("Corrupted USB list at 0x%p", (void *)head
);
1310 ASSERT(count
== head
->count
);
1311 mutex_exit(&head
->list_mutex
);
1314 USB_DPRINTF_L2(DPRINT_MASK_HCDI
, usba_log_handle
,
1315 "usba_list_entry_count: leaking %d", count
);
1323 usba_list_entry_count(usba_list_entry_t
*head
)
1327 mutex_enter(&head
->list_mutex
);
1328 count
= head
->count
;
1329 mutex_exit(&head
->list_mutex
);
1334 /* add a new root hub to the usba_root_hubs list */
1337 usba_add_root_hub(dev_info_t
*dip
)
1339 usba_root_hub_ent_t
*hub
;
1341 hub
= (usba_root_hub_ent_t
*)
1342 kmem_zalloc(sizeof (usba_root_hub_ent_t
), KM_SLEEP
);
1344 mutex_enter(&usba_hub_mutex
);
1346 hub
->next
= usba_root_hubs
;
1347 usba_root_hubs
= hub
;
1348 mutex_exit(&usba_hub_mutex
);
1351 /* remove a root hub from the usba_root_hubs list */
1354 usba_rem_root_hub(dev_info_t
*dip
)
1356 usba_root_hub_ent_t
**hubp
, *hub
;
1358 mutex_enter(&usba_hub_mutex
);
1359 hubp
= &usba_root_hubs
;
1361 if ((*hubp
)->dip
== dip
) {
1364 kmem_free(hub
, sizeof (struct usba_root_hub_ent
));
1365 mutex_exit(&usba_hub_mutex
);
1369 hubp
= &(*hubp
)->next
;
1371 mutex_exit(&usba_hub_mutex
);
1375 * check whether this dip is the root hub. Any root hub known by
1376 * usba is recorded in the linked list pointed to by usba_root_hubs
1379 usba_is_root_hub(dev_info_t
*dip
)
1381 usba_root_hub_ent_t
*hub
;
1383 mutex_enter(&usba_hub_mutex
);
1384 hub
= usba_root_hubs
;
1386 if (hub
->dip
== dip
) {
1387 mutex_exit(&usba_hub_mutex
);
1393 mutex_exit(&usba_hub_mutex
);
1399 * get and store usba_device pointer in the devi
1402 usba_get_usba_device(dev_info_t
*dip
)
1405 * we cannot use parent_data in the usb node because its
1406 * bus parent (eg. PCI nexus driver) uses this data
1408 * we cannot use driver data in the other usb nodes since
1409 * usb drivers may need to use this
1411 if (usba_is_root_hub(dip
)) {
1412 usba_hcdi_t
*hcdi
= usba_hcdi_get_hcdi(dip
);
1414 return (hcdi
->hcdi_usba_device
);
1417 return (ddi_get_parent_data(dip
));
1423 * Retrieve the usba_device pointer from the dev without checking for
1424 * the root hub first. This function is only used in polled mode.
1427 usba_polled_get_usba_device(dev_info_t
*dip
)
1430 * Don't call usba_is_root_hub() to find out if this is
1431 * the root hub usba_is_root_hub() calls into the DDI
1432 * where there are locking issues. The dip sent in during
1433 * polled mode will never be the root hub, so just get
1434 * the usba_device pointer from the dip.
1436 return (ddi_get_parent_data(dip
));
1441 usba_set_usba_device(dev_info_t
*dip
, usba_device_t
*usba_device
)
1443 if (usba_is_root_hub(dip
)) {
1444 usba_hcdi_t
*hcdi
= usba_hcdi_get_hcdi(dip
);
1445 /* no locking is needed here */
1446 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi
->hcdi_usba_device
))
1447 hcdi
->hcdi_usba_device
= usba_device
;
1448 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi
->hcdi_usba_device
))
1450 ddi_set_parent_data(dip
, usba_device
);
1456 * usba_set_node_name() according to class, subclass, and protocol
1457 * following the 1275 USB binding tables.
1460 /* device node table, refer to section 3.2.2.1 of 1275 binding */
1461 static node_name_entry_t device_node_name_table
[] = {
1462 { USB_CLASS_COMM
, DONTCARE
, DONTCARE
, "communications" },
1463 { USB_CLASS_HUB
, DONTCARE
, DONTCARE
, "hub" },
1464 { USB_CLASS_DIAG
, DONTCARE
, DONTCARE
, "diagnostics" },
1465 { USB_CLASS_MISC
, DONTCARE
, DONTCARE
, "miscellaneous" },
1466 { DONTCARE
, DONTCARE
, DONTCARE
, "device" }
1469 /* interface-association node table */
1470 static node_name_entry_t ia_node_name_table
[] = {
1471 { USB_CLASS_AUDIO
, DONTCARE
, DONTCARE
, "audio" },
1472 { USB_CLASS_VIDEO
, DONTCARE
, DONTCARE
, "video" },
1473 { USB_CLASS_WIRELESS
, USB_SUBCLS_WUSB_2
, USB_PROTO_WUSB_DWA
,
1474 "device-wire-adaptor" },
1475 { USB_CLASS_WIRELESS
, DONTCARE
, DONTCARE
, "wireless-controller" },
1476 { DONTCARE
, DONTCARE
, DONTCARE
, "interface-association" }
1479 /* interface node table, refer to section 3.3.2.1 */
1480 static node_name_entry_t if_node_name_table
[] = {
1481 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_CONTROL
, DONTCARE
, "sound-control" },
1482 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_STREAMING
, DONTCARE
, "sound" },
1483 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_MIDI_STREAMING
, DONTCARE
, "midi" },
1484 { USB_CLASS_AUDIO
, DONTCARE
, DONTCARE
, "sound" },
1486 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_DIRECT_LINE
, DONTCARE
, "line" },
1487 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ABSTRCT_CTRL
, DONTCARE
, "modem" },
1488 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_PHONE_CTRL
, DONTCARE
, "telephone" },
1489 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_MULTCNL_ISDN
, DONTCARE
, "isdn" },
1490 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ISDN
, DONTCARE
, "isdn" },
1491 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ETHERNET
, DONTCARE
, "ethernet" },
1492 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ATM_NETWORK
, DONTCARE
, "atm-network" },
1493 { USB_CLASS_COMM
, DONTCARE
, DONTCARE
, "communications" },
1495 { USB_CLASS_HID
, USB_SUBCLS_HID_1
, USB_PROTO_HID_KEYBOARD
, "keyboard" },
1496 { USB_CLASS_HID
, USB_SUBCLS_HID_1
, USB_PROTO_HID_MOUSE
, "mouse" },
1497 { USB_CLASS_HID
, DONTCARE
, DONTCARE
, "input" },
1499 { USB_CLASS_HUB
, DONTCARE
, DONTCARE
, "hub" },
1501 { USB_CLASS_PHYSICAL
, DONTCARE
, DONTCARE
, "physical" },
1503 { USB_CLASS_IMAGE
, DONTCARE
, DONTCARE
, "image" },
1505 { USB_CLASS_PRINTER
, DONTCARE
, DONTCARE
, "printer" },
1507 { USB_CLASS_MASS_STORAGE
, DONTCARE
, DONTCARE
, "storage" },
1509 { USB_CLASS_CDC_DATA
, DONTCARE
, DONTCARE
, "data" },
1511 { USB_CLASS_SECURITY
, DONTCARE
, DONTCARE
, "security" },
1513 { USB_CLASS_VIDEO
, USB_SUBCLS_VIDEO_CONTROL
, DONTCARE
, "video-control" },
1514 { USB_CLASS_VIDEO
, USB_SUBCLS_VIDEO_STREAM
, DONTCARE
, "video-stream" },
1515 { USB_CLASS_VIDEO
, DONTCARE
, DONTCARE
, "video" },
1517 { USB_CLASS_APP
, USB_SUBCLS_APP_FIRMWARE
, DONTCARE
, "firmware" },
1518 { USB_CLASS_APP
, USB_SUBCLS_APP_IRDA
, DONTCARE
, "IrDa" },
1519 { USB_CLASS_APP
, USB_SUBCLS_APP_TEST
, DONTCARE
, "test" },
1521 { USB_CLASS_MISC
, USB_SUBCLS_CBAF
, USB_PROTO_CBAF
, "wusb_ca"},
1522 { USB_CLASS_WIRELESS
, USB_SUBCLS_WUSB_1
, USB_PROTO_WUSB_RC
, "hwa-radio" },
1523 { USB_CLASS_WIRELESS
, USB_SUBCLS_WUSB_2
, USB_PROTO_WUSB_HWA
, "hwa-host" },
1524 { USB_CLASS_WIRELESS
, USB_SUBCLS_WUSB_2
, USB_PROTO_WUSB_DWA
, "dwa-control" },
1525 { USB_CLASS_WIRELESS
, USB_SUBCLS_WUSB_2
, USB_PROTO_WUSB_DWA_ISO
, "dwa-isoc" },
1526 { USB_CLASS_WIRELESS
, DONTCARE
, DONTCARE
, "wireless" },
1528 { DONTCARE
, DONTCARE
, DONTCARE
, "interface" },
1532 /* combined node table, refer to section 3.4.2.1 */
1533 static node_name_entry_t combined_node_name_table
[] = {
1534 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_CONTROL
, DONTCARE
, "sound-control" },
1535 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_STREAMING
, DONTCARE
, "sound" },
1536 { USB_CLASS_AUDIO
, USB_SUBCLS_AUD_MIDI_STREAMING
, DONTCARE
, "midi" },
1537 { USB_CLASS_AUDIO
, DONTCARE
, DONTCARE
, "sound" },
1539 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_DIRECT_LINE
, DONTCARE
, "line" },
1540 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ABSTRCT_CTRL
, DONTCARE
, "modem" },
1541 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_PHONE_CTRL
, DONTCARE
, "telephone" },
1542 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_MULTCNL_ISDN
, DONTCARE
, "isdn" },
1543 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ISDN
, DONTCARE
, "isdn" },
1544 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ETHERNET
, DONTCARE
, "ethernet" },
1545 { USB_CLASS_COMM
, USB_SUBCLS_CDCC_ATM_NETWORK
, DONTCARE
, "atm-network" },
1546 { USB_CLASS_COMM
, DONTCARE
, DONTCARE
, "communications" },
1548 { USB_CLASS_HID
, USB_SUBCLS_HID_1
, USB_PROTO_HID_KEYBOARD
, "keyboard" },
1549 { USB_CLASS_HID
, USB_SUBCLS_HID_1
, USB_PROTO_HID_MOUSE
, "mouse" },
1550 { USB_CLASS_HID
, DONTCARE
, DONTCARE
, "input" },
1552 { USB_CLASS_PHYSICAL
, DONTCARE
, DONTCARE
, "physical" },
1554 { USB_CLASS_IMAGE
, DONTCARE
, DONTCARE
, "image" },
1556 { USB_CLASS_PRINTER
, DONTCARE
, DONTCARE
, "printer" },
1558 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_RBC_T10
, DONTCARE
, "storage" },
1559 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_SFF8020I
, DONTCARE
, "cdrom" },
1560 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_QIC_157
, DONTCARE
, "tape" },
1561 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_UFI
, DONTCARE
, "floppy" },
1562 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_SFF8070I
, DONTCARE
, "storage" },
1563 { USB_CLASS_MASS_STORAGE
, USB_SUBCLS_MS_SCSI
, DONTCARE
, "storage" },
1564 { USB_CLASS_MASS_STORAGE
, DONTCARE
, DONTCARE
, "storage" },
1566 { USB_CLASS_CDC_DATA
, DONTCARE
, DONTCARE
, "data" },
1568 { USB_CLASS_SECURITY
, DONTCARE
, DONTCARE
, "security" },
1570 { USB_CLASS_VIDEO
, USB_SUBCLS_VIDEO_CONTROL
, DONTCARE
, "video-control" },
1571 { USB_CLASS_VIDEO
, USB_SUBCLS_VIDEO_STREAM
, DONTCARE
, "video-stream" },
1572 { USB_CLASS_VIDEO
, DONTCARE
, DONTCARE
, "video" },
1574 { USB_CLASS_APP
, USB_SUBCLS_APP_FIRMWARE
, DONTCARE
, "firmware" },
1575 { USB_CLASS_APP
, USB_SUBCLS_APP_IRDA
, DONTCARE
, "IrDa" },
1576 { USB_CLASS_APP
, USB_SUBCLS_APP_TEST
, DONTCARE
, "test" },
1578 { USB_CLASS_COMM
, DONTCARE
, DONTCARE
, "communications" },
1579 { USB_CLASS_HUB
, DONTCARE
, DONTCARE
, "hub" },
1580 { USB_CLASS_DIAG
, DONTCARE
, DONTCARE
, "diagnostics" },
1581 { USB_CLASS_MISC
, DONTCARE
, DONTCARE
, "miscellaneous" },
1582 { DONTCARE
, DONTCARE
, DONTCARE
, "device" }
1585 static size_t device_node_name_table_size
=
1586 sizeof (device_node_name_table
)/sizeof (struct node_name_entry
);
1587 static size_t ia_node_name_table_size
=
1588 sizeof (ia_node_name_table
)/sizeof (struct node_name_entry
);
1589 static size_t if_node_name_table_size
=
1590 sizeof (if_node_name_table
)/sizeof (struct node_name_entry
);
1591 static size_t combined_node_name_table_size
=
1592 sizeof (combined_node_name_table
)/sizeof (struct node_name_entry
);
1596 usba_set_node_name(dev_info_t
*dip
, uint8_t class, uint8_t subclass
,
1597 uint8_t protocol
, uint_t flag
)
1601 node_name_entry_t
*node_name_table
;
1604 /* interface share node names with interface-association */
1605 case FLAG_INTERFACE_ASSOCIATION_NODE
:
1606 node_name_table
= ia_node_name_table
;
1607 size
= ia_node_name_table_size
;
1609 case FLAG_INTERFACE_NODE
:
1610 node_name_table
= if_node_name_table
;
1611 size
= if_node_name_table_size
;
1613 case FLAG_DEVICE_NODE
:
1614 node_name_table
= device_node_name_table
;
1615 size
= device_node_name_table_size
;
1617 case FLAG_COMBINED_NODE
:
1618 node_name_table
= combined_node_name_table
;
1619 size
= combined_node_name_table_size
;
1626 for (i
= 0; i
< size
; i
++) {
1627 int16_t c
= node_name_table
[i
].class;
1628 int16_t s
= node_name_table
[i
].subclass
;
1629 int16_t p
= node_name_table
[i
].protocol
;
1631 if (((c
== DONTCARE
) || (c
== class)) &&
1632 ((s
== DONTCARE
) || (s
== subclass
)) &&
1633 ((p
== DONTCARE
) || (p
== protocol
))) {
1634 char *name
= node_name_table
[i
].name
;
1636 (void) ndi_devi_set_nodename(dip
, name
, 0);
1645 * walk the children of the parent of this devi and compare the
1646 * name and reg property of each child. If there is a match
1650 usba_find_existing_node(dev_info_t
*odip
)
1652 dev_info_t
*ndip
, *child
, *pdip
;
1654 uint_t n_odata
, n_ndata
;
1657 pdip
= ddi_get_parent(odip
);
1658 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
,
1659 odip
, DDI_PROP_DONTPASS
, "reg",
1660 &odata
, &n_odata
) != DDI_SUCCESS
) {
1661 USB_DPRINTF_L2(DPRINT_MASK_HCDI
, usba_log_handle
,
1662 "usba_find_existing_node: "
1663 "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip
));
1668 ndi_devi_enter(pdip
, &circular
);
1669 ndip
= (dev_info_t
*)(DEVI(pdip
)->devi_child
);
1670 while ((child
= ndip
) != NULL
) {
1672 ndip
= (dev_info_t
*)(DEVI(child
)->devi_sibling
);
1674 if (child
== odip
) {
1678 if (strcmp(DEVI(child
)->devi_node_name
,
1679 DEVI(odip
)->devi_node_name
)) {
1683 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
,
1684 child
, DDI_PROP_DONTPASS
, "reg",
1685 &ndata
, &n_ndata
) != DDI_SUCCESS
) {
1687 USB_DPRINTF_L2(DPRINT_MASK_HCDI
, usba_log_handle
,
1688 "usba_find_existing_node: "
1689 "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child
));
1691 } else if (n_ndata
&& n_odata
&& (bcmp(odata
, ndata
,
1692 max(n_odata
, n_ndata
) * sizeof (int)) == 0)) {
1694 USB_DPRINTF_L3(DPRINT_MASK_HCDI
, usba_log_handle
,
1695 "usba_find_existing_node: found %s%d (%p)",
1696 ddi_driver_name(child
),
1697 ddi_get_instance(child
), (void *)child
);
1699 USB_DPRINTF_L3(DPRINT_MASK_HCDI
, usba_log_handle
,
1700 "usba_find_existing_node: "
1701 "reg: %x %x %x - %x %x %x",
1702 n_odata
, odata
[0], odata
[1],
1703 n_ndata
, ndata
[0], ndata
[1]);
1705 ddi_prop_free(ndata
);
1709 ddi_prop_free(ndata
);
1713 ndi_devi_exit(pdip
, circular
);
1715 ddi_prop_free(odata
);
1721 /* change all unprintable characters to spaces */
1723 usba_filter_string(char *instr
, char *outstr
)
1726 if ((*instr
>= ' ') && (*instr
<= '~')) {
1739 * lookup ugen binding specified in property in
1743 usba_get_ugen_binding(dev_info_t
*dip
)
1745 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
1747 usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
1749 return (hcdi
->hcdi_ugen_default_binding
);
1754 * driver binding support at device level
1757 usba_ready_device_node(dev_info_t
*child_dip
)
1761 usba_device_t
*usba_device
= usba_get_usba_device(child_dip
);
1762 usb_dev_descr_t
*usb_dev_descr
;
1763 uint_t n_cfgs
; /* number of configs */
1764 uint_t n_ifs
; /* number of interfaces */
1765 uint_t port
, bus_num
;
1766 size_t usb_config_length
;
1767 uchar_t
*usb_config
;
1769 usb_addr_t address
= usb_get_addr(child_dip
);
1770 usb_if_descr_t if_descr
;
1772 int combined_node
= 0;
1775 char *force_bind
= NULL
;
1776 char *usba_name_buf
= NULL
;
1777 char *usba_name
[USBA_MAX_COMPAT_NAMES
];
1779 usb_config
= usb_get_raw_cfg_data(child_dip
, &usb_config_length
);
1781 mutex_enter(&usba_device
->usb_mutex
);
1782 mutex_enter(&usba_mutex
);
1784 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
1785 "usba_ready_device_node: child=0x%p", (void *)child_dip
);
1787 port
= usba_device
->usb_port
;
1788 usb_dev_descr
= usba_device
->usb_dev_descr
;
1789 n_cfgs
= usba_device
->usb_n_cfgs
;
1790 n_ifs
= usba_device
->usb_n_ifs
;
1791 bus_num
= usba_device
->usb_addr
;
1793 if (address
!= ROOT_HUB_ADDR
) {
1794 size
= usb_parse_if_descr(
1797 0, /* interface index */
1798 0, /* alt interface index */
1802 if (size
!= USB_IF_DESCR_SIZE
) {
1803 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
1804 "parsing interface: "
1805 "size (%lu) != USB_IF_DESCR_SIZE (%d)",
1806 size
, USB_IF_DESCR_SIZE
);
1808 mutex_exit(&usba_mutex
);
1809 mutex_exit(&usba_device
->usb_mutex
);
1814 /* fake an interface descriptor for the root hub */
1815 bzero(&if_descr
, sizeof (if_descr
));
1817 if_descr
.bInterfaceClass
= USB_CLASS_HUB
;
1822 mutex_exit(&usba_mutex
);
1823 mutex_exit(&usba_device
->usb_mutex
);
1825 rval
= ndi_prop_update_int_array(
1826 DDI_DEV_T_NONE
, child_dip
, "reg", reg
, 1);
1828 if (rval
!= DDI_PROP_SUCCESS
) {
1829 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
1830 "usba_ready_device_node: property update failed");
1835 combined_node
= ((n_cfgs
== 1) && (n_ifs
== 1) &&
1836 ((usb_dev_descr
->bDeviceClass
== USB_CLASS_HUB
) ||
1837 (usb_dev_descr
->bDeviceClass
== 0)));
1839 is_hub
= (if_descr
.bInterfaceClass
== USB_CLASS_HUB
) ||
1840 (usb_dev_descr
->bDeviceClass
== USB_CLASS_HUB
);
1843 if (combined_node
) {
1844 usba_set_node_name(child_dip
,
1845 if_descr
.bInterfaceClass
,
1846 if_descr
.bInterfaceSubClass
,
1847 if_descr
.bInterfaceProtocol
,
1848 FLAG_COMBINED_NODE
);
1850 usba_set_node_name(child_dip
,
1851 usb_dev_descr
->bDeviceClass
,
1852 usb_dev_descr
->bDeviceSubClass
,
1853 usb_dev_descr
->bDeviceProtocol
,
1858 * check force binding rules
1860 if ((address
!= ROOT_HUB_ADDR
) && usba_ddivs_usbc
&&
1861 (address
!= usba_ddivs_usbc_xaddress
) &&
1862 (!(usba_ddivs_usbc_xhubs
&& is_hub
))) {
1863 force_bind
= "ddivs_usbc";
1864 (void) ndi_devi_set_nodename(child_dip
, "ddivs_usbc", 0);
1866 } else if (usba_device
->usb_preferred_driver
) {
1867 force_bind
= usba_device
->usb_preferred_driver
;
1869 } else if ((address
!= ROOT_HUB_ADDR
) &&
1870 ((usba_ugen_force_binding
== USBA_UGEN_DEVICE_BINDING
) ||
1871 ((usba_ugen_force_binding
== USBA_UGEN_INTERFACE_BINDING
) &&
1872 combined_node
)) && (!is_hub
)) {
1873 force_bind
= "ugen";
1878 * check whether there is another dip with this name and address
1879 * If the dip contains usba_device, it is held by the previous
1880 * round of configuration.
1882 ASSERT(usba_find_existing_node(child_dip
) == NULL
);
1885 usba_name_buf
= kmem_zalloc(USBA_MAX_COMPAT_NAMES
*
1886 USBA_MAX_COMPAT_NAME_LEN
, KM_SLEEP
);
1888 for (i
= 0; i
< USBA_MAX_COMPAT_NAMES
; i
++) {
1889 usba_name
[i
] = usba_name_buf
+ (i
* USBA_MAX_COMPAT_NAME_LEN
);
1893 (void) ndi_devi_set_nodename(child_dip
, force_bind
, 0);
1894 (void) strncpy(usba_name
[n
++], force_bind
,
1895 USBA_MAX_COMPAT_NAME_LEN
);
1899 * If the callback function of specified driver is registered,
1900 * it will be called here to check whether to take over the device.
1902 if (usb_cap
.usba_dev_driver_cb
!= NULL
) {
1903 char *dev_drv
= NULL
;
1904 usb_dev_str_t dev_str
;
1905 char *pathname
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1907 dev_str
.usb_mfg
= usba_device
->usb_mfg_str
;
1908 dev_str
.usb_product
= usba_device
->usb_product_str
;
1909 dev_str
.usb_serialno
= usba_device
->usb_serialno_str
;
1911 (void) ddi_pathname(child_dip
, pathname
);
1913 if ((usb_cap
.usba_dev_driver_cb(usb_dev_descr
, &dev_str
,
1914 pathname
, bus_num
, port
, &dev_drv
, NULL
) == USB_SUCCESS
) &&
1915 (dev_drv
!= NULL
)) {
1916 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
1917 "usba_ready_device_node: dev_driver=%s, port =%d,"
1918 "bus =%d, path=%s\n\t",
1919 dev_drv
, port
, bus_num
, pathname
);
1921 (void) strncpy(usba_name
[n
++], dev_drv
,
1922 USBA_MAX_COMPAT_NAME_LEN
);
1924 kmem_free(pathname
, MAXPATHLEN
);
1927 /* create compatible names */
1928 if (combined_node
) {
1930 /* 1. usbVID,PID.REV */
1931 (void) sprintf(usba_name
[n
++],
1933 usb_dev_descr
->idVendor
,
1934 usb_dev_descr
->idProduct
,
1935 usb_dev_descr
->bcdDevice
);
1938 (void) sprintf(usba_name
[n
++],
1940 usb_dev_descr
->idVendor
,
1941 usb_dev_descr
->idProduct
);
1943 if (usb_dev_descr
->bDeviceClass
!= 0) {
1944 /* 3. usbVID,classDC.DSC.DPROTO */
1945 (void) sprintf(usba_name
[n
++],
1946 "usb%x,class%x.%x.%x",
1947 usb_dev_descr
->idVendor
,
1948 usb_dev_descr
->bDeviceClass
,
1949 usb_dev_descr
->bDeviceSubClass
,
1950 usb_dev_descr
->bDeviceProtocol
);
1952 /* 4. usbVID,classDC.DSC */
1953 (void) sprintf(usba_name
[n
++],
1955 usb_dev_descr
->idVendor
,
1956 usb_dev_descr
->bDeviceClass
,
1957 usb_dev_descr
->bDeviceSubClass
);
1959 /* 5. usbVID,classDC */
1960 (void) sprintf(usba_name
[n
++],
1962 usb_dev_descr
->idVendor
,
1963 usb_dev_descr
->bDeviceClass
);
1965 /* 6. usb,classDC.DSC.DPROTO */
1966 (void) sprintf(usba_name
[n
++],
1967 "usb,class%x.%x.%x",
1968 usb_dev_descr
->bDeviceClass
,
1969 usb_dev_descr
->bDeviceSubClass
,
1970 usb_dev_descr
->bDeviceProtocol
);
1972 /* 7. usb,classDC.DSC */
1973 (void) sprintf(usba_name
[n
++],
1975 usb_dev_descr
->bDeviceClass
,
1976 usb_dev_descr
->bDeviceSubClass
);
1978 /* 8. usb,classDC */
1979 (void) sprintf(usba_name
[n
++],
1981 usb_dev_descr
->bDeviceClass
);
1984 if (if_descr
.bInterfaceClass
!= 0) {
1985 /* 9. usbifVID,classIC.ISC.IPROTO */
1986 (void) sprintf(usba_name
[n
++],
1987 "usbif%x,class%x.%x.%x",
1988 usb_dev_descr
->idVendor
,
1989 if_descr
.bInterfaceClass
,
1990 if_descr
.bInterfaceSubClass
,
1991 if_descr
.bInterfaceProtocol
);
1993 /* 10. usbifVID,classIC.ISC */
1994 (void) sprintf(usba_name
[n
++],
1995 "usbif%x,class%x.%x",
1996 usb_dev_descr
->idVendor
,
1997 if_descr
.bInterfaceClass
,
1998 if_descr
.bInterfaceSubClass
);
2000 /* 11. usbifVID,classIC */
2001 (void) sprintf(usba_name
[n
++],
2003 usb_dev_descr
->idVendor
,
2004 if_descr
.bInterfaceClass
);
2006 /* 12. usbif,classIC.ISC.IPROTO */
2007 (void) sprintf(usba_name
[n
++],
2008 "usbif,class%x.%x.%x",
2009 if_descr
.bInterfaceClass
,
2010 if_descr
.bInterfaceSubClass
,
2011 if_descr
.bInterfaceProtocol
);
2013 /* 13. usbif,classIC.ISC */
2014 (void) sprintf(usba_name
[n
++],
2016 if_descr
.bInterfaceClass
,
2017 if_descr
.bInterfaceSubClass
);
2019 /* 14. usbif,classIC */
2020 (void) sprintf(usba_name
[n
++],
2022 if_descr
.bInterfaceClass
);
2025 /* 15. ugen or usb_mid */
2026 if (usba_get_ugen_binding(child_dip
) ==
2027 USBA_UGEN_DEVICE_BINDING
) {
2028 (void) sprintf(usba_name
[n
++], "ugen");
2030 (void) sprintf(usba_name
[n
++], "usb,device");
2035 /* 1. usbVID,PID.REV.configCN */
2036 (void) sprintf(usba_name
[n
++],
2037 "usb%x,%x.%x.config%x",
2038 usb_dev_descr
->idVendor
,
2039 usb_dev_descr
->idProduct
,
2040 usb_dev_descr
->bcdDevice
,
2041 usba_device
->usb_cfg_value
);
2044 /* 2. usbVID,PID.REV */
2045 (void) sprintf(usba_name
[n
++],
2047 usb_dev_descr
->idVendor
,
2048 usb_dev_descr
->idProduct
,
2049 usb_dev_descr
->bcdDevice
);
2051 /* 3. usbVID,PID.configCN */
2053 (void) sprintf(usba_name
[n
++],
2055 usb_dev_descr
->idVendor
,
2056 usb_dev_descr
->idProduct
,
2057 usba_device
->usb_cfg_value
);
2061 (void) sprintf(usba_name
[n
++],
2063 usb_dev_descr
->idVendor
,
2064 usb_dev_descr
->idProduct
);
2066 if (usb_dev_descr
->bDeviceClass
!= 0) {
2067 /* 5. usbVID,classDC.DSC.DPROTO */
2068 (void) sprintf(usba_name
[n
++],
2069 "usb%x,class%x.%x.%x",
2070 usb_dev_descr
->idVendor
,
2071 usb_dev_descr
->bDeviceClass
,
2072 usb_dev_descr
->bDeviceSubClass
,
2073 usb_dev_descr
->bDeviceProtocol
);
2075 /* 6. usbVID,classDC.DSC */
2076 (void) sprintf(usba_name
[n
++],
2078 usb_dev_descr
->idVendor
,
2079 usb_dev_descr
->bDeviceClass
,
2080 usb_dev_descr
->bDeviceSubClass
);
2082 /* 7. usbVID,classDC */
2083 (void) sprintf(usba_name
[n
++],
2085 usb_dev_descr
->idVendor
,
2086 usb_dev_descr
->bDeviceClass
);
2088 /* 8. usb,classDC.DSC.DPROTO */
2089 (void) sprintf(usba_name
[n
++],
2090 "usb,class%x.%x.%x",
2091 usb_dev_descr
->bDeviceClass
,
2092 usb_dev_descr
->bDeviceSubClass
,
2093 usb_dev_descr
->bDeviceProtocol
);
2095 /* 9. usb,classDC.DSC */
2096 (void) sprintf(usba_name
[n
++],
2098 usb_dev_descr
->bDeviceClass
,
2099 usb_dev_descr
->bDeviceSubClass
);
2101 /* 10. usb,classDC */
2102 (void) sprintf(usba_name
[n
++],
2104 usb_dev_descr
->bDeviceClass
);
2107 if (usba_get_ugen_binding(child_dip
) ==
2108 USBA_UGEN_DEVICE_BINDING
) {
2110 (void) sprintf(usba_name
[n
++], "ugen");
2112 /* 11. usb,device */
2113 (void) sprintf(usba_name
[n
++], "usb,device");
2117 for (i
= 0; i
< n
; i
+= 2) {
2118 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
2119 "compatible name:\t%s\t%s", usba_name
[i
],
2120 (((i
+1) < n
)? usba_name
[i
+1] : ""));
2123 rval
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, child_dip
,
2124 "compatible", (char **)usba_name
, n
);
2126 kmem_free(usba_name_buf
, USBA_MAX_COMPAT_NAMES
*
2127 USBA_MAX_COMPAT_NAME_LEN
);
2129 if (rval
!= DDI_PROP_SUCCESS
) {
2131 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2132 "usba_ready_device_node: property update failed");
2137 /* update the address property */
2138 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2139 "assigned-address", usba_device
->usb_addr
);
2140 if (rval
!= DDI_PROP_SUCCESS
) {
2141 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2142 "usba_ready_device_node: address update failed");
2145 /* update the usb device properties (PSARC/2000/454) */
2146 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2147 "usb-vendor-id", usb_dev_descr
->idVendor
);
2148 if (rval
!= DDI_PROP_SUCCESS
) {
2149 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2150 "usba_ready_device_node: usb-vendor-id update failed");
2153 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2154 "usb-product-id", usb_dev_descr
->idProduct
);
2155 if (rval
!= DDI_PROP_SUCCESS
) {
2156 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2157 "usba_ready_device_node: usb-product-id update failed");
2160 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2161 "usb-revision-id", usb_dev_descr
->bcdDevice
);
2162 if (rval
!= DDI_PROP_SUCCESS
) {
2163 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2164 "usba_ready_device_node: usb-revision-id update failed");
2167 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2168 "usb-num-configs", usb_dev_descr
->bNumConfigurations
);
2169 if (rval
!= DDI_PROP_SUCCESS
) {
2170 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2171 "usba_ready_device_node: usb-num-configs update failed");
2174 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2175 "usb-release", usb_dev_descr
->bcdUSB
);
2176 if (rval
!= DDI_PROP_SUCCESS
) {
2177 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2178 "usba_ready_device_node: usb-release update failed");
2181 rval
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, child_dip
,
2182 "usb-dev-descriptor", (uchar_t
*)usb_dev_descr
,
2183 sizeof (usb_dev_descr_t
));
2184 if (rval
!= DDI_PROP_SUCCESS
) {
2185 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2186 "usba_ready_device_node: usb-descriptor update failed");
2189 rval
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, child_dip
,
2190 "usb-raw-cfg-descriptors", usb_config
, usb_config_length
);
2191 if (rval
!= DDI_PROP_SUCCESS
) {
2192 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2193 "usba_ready_device_node: usb-raw-cfg-descriptors update "
2197 devprop_str
= kmem_zalloc(USB_MAXSTRINGLEN
, KM_SLEEP
);
2199 if (usba_device
->usb_serialno_str
) {
2200 usba_filter_string(usba_device
->usb_serialno_str
, devprop_str
);
2201 rval
= ndi_prop_update_string(DDI_DEV_T_NONE
, child_dip
,
2202 "usb-serialno", devprop_str
);
2203 if (rval
!= DDI_PROP_SUCCESS
) {
2204 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2205 "usba_ready_device_node: "
2206 "usb-serialno update failed");
2210 if (usba_device
->usb_mfg_str
) {
2211 usba_filter_string(usba_device
->usb_mfg_str
, devprop_str
);
2212 rval
= ndi_prop_update_string(DDI_DEV_T_NONE
, child_dip
,
2213 "usb-vendor-name", devprop_str
);
2214 if (rval
!= DDI_PROP_SUCCESS
) {
2215 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2216 "usba_ready_device_node: "
2217 "usb-vendor-name update failed");
2221 if (usba_device
->usb_product_str
) {
2222 usba_filter_string(usba_device
->usb_product_str
, devprop_str
);
2223 rval
= ndi_prop_update_string(DDI_DEV_T_NONE
, child_dip
,
2224 "usb-product-name", devprop_str
);
2225 if (rval
!= DDI_PROP_SUCCESS
) {
2226 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2227 "usba_ready_device_node: "
2228 "usb-product-name update failed");
2232 kmem_free(devprop_str
, USB_MAXSTRINGLEN
);
2234 if (!combined_node
) {
2235 /* update the configuration property */
2236 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2237 "configuration#", usba_device
->usb_cfg_value
);
2238 if (rval
!= DDI_PROP_SUCCESS
) {
2239 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2240 "usba_ready_device_node: "
2241 "config prop update failed");
2245 if (usba_device
->usb_port_status
== USBA_LOW_SPEED_DEV
) {
2246 /* create boolean property */
2247 rval
= ndi_prop_create_boolean(DDI_DEV_T_NONE
, child_dip
,
2249 if (rval
!= DDI_PROP_SUCCESS
) {
2250 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2251 "usba_ready_device_node: "
2252 "low speed prop update failed");
2256 if (usba_device
->usb_port_status
== USBA_HIGH_SPEED_DEV
) {
2257 /* create boolean property */
2258 rval
= ndi_prop_create_boolean(DDI_DEV_T_NONE
, child_dip
,
2260 if (rval
!= DDI_PROP_SUCCESS
) {
2261 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2262 "usba_ready_device_node: "
2263 "high speed prop update failed");
2267 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
2268 "%s%d at port %d: %s, dip=0x%p",
2269 ddi_node_name(ddi_get_parent(child_dip
)),
2270 ddi_get_instance(ddi_get_parent(child_dip
)),
2271 port
, ddi_node_name(child_dip
), (void *)child_dip
);
2273 usba_set_usba_device(child_dip
, usba_device
);
2275 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip
)->usb_mutex
)));
2282 * driver binding at interface association level. the first arg is the parent
2283 * dip. if_count returns amount of interfaces which are associated within
2284 * this interface-association that starts from first_if.
2288 usba_ready_interface_association_node(dev_info_t
*dip
,
2292 dev_info_t
*child_dip
= NULL
;
2293 usba_device_t
*child_ud
= usba_get_usba_device(dip
);
2294 usb_dev_descr_t
*usb_dev_descr
;
2295 size_t usb_cfg_length
;
2297 usb_ia_descr_t ia_descr
;
2301 usb_port_status_t port_status
;
2302 char *force_bind
= NULL
;
2303 char *usba_name_buf
= NULL
;
2304 char *usba_name
[USBA_MAX_COMPAT_NAMES
];
2306 usb_cfg
= usb_get_raw_cfg_data(dip
, &usb_cfg_length
);
2308 mutex_enter(&child_ud
->usb_mutex
);
2310 usb_dev_descr
= child_ud
->usb_dev_descr
;
2313 * for each interface association, determine all compatible names
2315 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
2316 "usba_ready_ia_node: "
2317 "port %d, interface = %d, port_status = %x",
2318 child_ud
->usb_port
, first_if
, child_ud
->usb_port_status
);
2320 /* Parse the interface descriptor */
2321 size
= usb_parse_ia_descr(
2324 first_if
, /* interface index */
2329 if (size
!= USB_IA_DESCR_SIZE
) {
2330 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2331 "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2332 size
, USB_IA_DESCR_SIZE
);
2333 mutex_exit(&child_ud
->usb_mutex
);
2338 port_status
= child_ud
->usb_port_status
;
2340 /* create reg property */
2342 reg
[1] = child_ud
->usb_cfg_value
;
2344 mutex_exit(&child_ud
->usb_mutex
);
2346 /* clone this dip */
2347 rval
= usba_create_child_devi(dip
,
2348 "interface-association",
2349 NULL
, /* usba_hcdi ops */
2350 NULL
, /* root hub dip */
2351 port_status
, /* port status */
2352 child_ud
, /* share this usba_device */
2355 if (rval
!= USB_SUCCESS
) {
2360 rval
= ndi_prop_update_int_array(
2361 DDI_DEV_T_NONE
, child_dip
, "reg", reg
, 2);
2363 if (rval
!= DDI_PROP_SUCCESS
) {
2368 usba_set_node_name(child_dip
, ia_descr
.bFunctionClass
,
2369 ia_descr
.bFunctionSubClass
, ia_descr
.bFunctionProtocol
,
2370 FLAG_INTERFACE_ASSOCIATION_NODE
);
2372 /* check force binding */
2373 if (usba_ugen_force_binding
==
2374 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING
) {
2375 force_bind
= "ugen";
2379 * check whether there is another dip with this name and address
2381 ASSERT(usba_find_existing_node(child_dip
) == NULL
);
2383 usba_name_buf
= kmem_zalloc(USBA_MAX_COMPAT_NAMES
*
2384 USBA_MAX_COMPAT_NAME_LEN
, KM_SLEEP
);
2386 for (i
= 0; i
< USBA_MAX_COMPAT_NAMES
; i
++) {
2387 usba_name
[i
] = usba_name_buf
+ (i
* USBA_MAX_COMPAT_NAME_LEN
);
2393 (void) ndi_devi_set_nodename(child_dip
, force_bind
, 0);
2394 (void) strncpy(usba_name
[n
++], force_bind
,
2395 USBA_MAX_COMPAT_NAME_LEN
);
2398 /* 1) usbiaVID,PID.REV.configCN.FN */
2399 (void) sprintf(usba_name
[n
++],
2400 "usbia%x,%x.%x.config%x.%x",
2401 usb_dev_descr
->idVendor
,
2402 usb_dev_descr
->idProduct
,
2403 usb_dev_descr
->bcdDevice
,
2404 child_ud
->usb_cfg_value
,
2407 /* 2) usbiaVID,PID.configCN.FN */
2408 (void) sprintf(usba_name
[n
++],
2409 "usbia%x,%x.config%x.%x",
2410 usb_dev_descr
->idVendor
,
2411 usb_dev_descr
->idProduct
,
2412 child_ud
->usb_cfg_value
,
2416 if (ia_descr
.bFunctionClass
) {
2417 /* 3) usbiaVID,classFC.FSC.FPROTO */
2418 (void) sprintf(usba_name
[n
++],
2419 "usbia%x,class%x.%x.%x",
2420 usb_dev_descr
->idVendor
,
2421 ia_descr
.bFunctionClass
,
2422 ia_descr
.bFunctionSubClass
,
2423 ia_descr
.bFunctionProtocol
);
2425 /* 4) usbiaVID,classFC.FSC */
2426 (void) sprintf(usba_name
[n
++],
2427 "usbia%x,class%x.%x",
2428 usb_dev_descr
->idVendor
,
2429 ia_descr
.bFunctionClass
,
2430 ia_descr
.bFunctionSubClass
);
2432 /* 5) usbiaVID,classFC */
2433 (void) sprintf(usba_name
[n
++],
2435 usb_dev_descr
->idVendor
,
2436 ia_descr
.bFunctionClass
);
2438 /* 6) usbia,classFC.FSC.FPROTO */
2439 (void) sprintf(usba_name
[n
++],
2440 "usbia,class%x.%x.%x",
2441 ia_descr
.bFunctionClass
,
2442 ia_descr
.bFunctionSubClass
,
2443 ia_descr
.bFunctionProtocol
);
2445 /* 7) usbia,classFC.FSC */
2446 (void) sprintf(usba_name
[n
++],
2448 ia_descr
.bFunctionClass
,
2449 ia_descr
.bFunctionSubClass
);
2451 /* 8) usbia,classFC */
2452 (void) sprintf(usba_name
[n
++],
2454 ia_descr
.bFunctionClass
);
2457 if (usba_get_ugen_binding(child_dip
) ==
2458 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING
) {
2460 (void) sprintf(usba_name
[n
++], "ugen");
2463 (void) sprintf(usba_name
[n
++], "usb,ia");
2466 for (i
= 0; i
< n
; i
+= 2) {
2467 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
2468 "compatible name:\t%s\t%s", usba_name
[i
],
2469 (((i
+1) < n
)? usba_name
[i
+1] : ""));
2472 /* create compatible property */
2473 rval
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, child_dip
,
2474 "compatible", (char **)usba_name
, n
);
2476 kmem_free(usba_name_buf
, USBA_MAX_COMPAT_NAMES
*
2477 USBA_MAX_COMPAT_NAME_LEN
);
2479 if (rval
!= DDI_PROP_SUCCESS
) {
2484 /* update the address property */
2485 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2486 "assigned-address", child_ud
->usb_addr
);
2487 if (rval
!= DDI_PROP_SUCCESS
) {
2488 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2489 "usba_ready_interface_node: address update failed");
2492 /* create property with first interface number */
2493 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2494 "interface", ia_descr
.bFirstInterface
);
2496 if (rval
!= DDI_PROP_SUCCESS
) {
2501 /* create property with the count of interfaces in this ia */
2502 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2503 "interface-count", ia_descr
.bInterfaceCount
);
2505 if (rval
!= DDI_PROP_SUCCESS
) {
2510 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2511 "%s%d port %d: %s, dip = 0x%p",
2512 ddi_node_name(ddi_get_parent(dip
)),
2513 ddi_get_instance(ddi_get_parent(dip
)),
2514 child_ud
->usb_port
, ddi_node_name(child_dip
), (void *)child_dip
);
2516 *if_count
= ia_descr
.bInterfaceCount
;
2517 usba_set_usba_device(child_dip
, child_ud
);
2518 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip
)->usb_mutex
)));
2523 (void) usba_destroy_child_devi(child_dip
, NDI_DEVI_REMOVE
);
2530 * driver binding at interface level, the first arg will be the
2535 usba_ready_interface_node(dev_info_t
*dip
, uint_t intf
)
2537 dev_info_t
*child_dip
= NULL
;
2538 usba_device_t
*child_ud
= usba_get_usba_device(dip
);
2539 usb_dev_descr_t
*usb_dev_descr
;
2540 size_t usb_cfg_length
;
2542 usb_if_descr_t if_descr
;
2546 usb_port_status_t port_status
;
2547 char *force_bind
= NULL
;
2548 char *usba_name_buf
= NULL
;
2549 char *usba_name
[USBA_MAX_COMPAT_NAMES
];
2551 usb_cfg
= usb_get_raw_cfg_data(dip
, &usb_cfg_length
);
2553 mutex_enter(&child_ud
->usb_mutex
);
2555 usb_dev_descr
= child_ud
->usb_dev_descr
;
2558 * for each interface, determine all compatible names
2560 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
2561 "usba_ready_interface_node: "
2562 "port %d, interface = %d port status = %x",
2563 child_ud
->usb_port
, intf
, child_ud
->usb_port_status
);
2565 /* Parse the interface descriptor */
2566 size
= usb_parse_if_descr(
2569 intf
, /* interface index */
2570 0, /* alt interface index */
2574 if (size
!= USB_IF_DESCR_SIZE
) {
2575 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2576 "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
2577 size
, USB_IF_DESCR_SIZE
);
2578 mutex_exit(&child_ud
->usb_mutex
);
2583 port_status
= child_ud
->usb_port_status
;
2585 /* create reg property */
2587 reg
[1] = child_ud
->usb_cfg_value
;
2589 mutex_exit(&child_ud
->usb_mutex
);
2591 /* clone this dip */
2592 rval
= usba_create_child_devi(dip
,
2594 NULL
, /* usba_hcdi ops */
2595 NULL
, /* root hub dip */
2596 port_status
, /* port status */
2597 child_ud
, /* share this usba_device */
2600 if (rval
!= USB_SUCCESS
) {
2605 rval
= ndi_prop_update_int_array(
2606 DDI_DEV_T_NONE
, child_dip
, "reg", reg
, 2);
2608 if (rval
!= DDI_PROP_SUCCESS
) {
2613 usba_set_node_name(child_dip
, if_descr
.bInterfaceClass
,
2614 if_descr
.bInterfaceSubClass
, if_descr
.bInterfaceProtocol
,
2615 FLAG_INTERFACE_NODE
);
2617 /* check force binding */
2618 if (usba_ugen_force_binding
== USBA_UGEN_INTERFACE_BINDING
) {
2619 force_bind
= "ugen";
2623 * check whether there is another dip with this name and address
2625 ASSERT(usba_find_existing_node(child_dip
) == NULL
);
2627 usba_name_buf
= kmem_zalloc(USBA_MAX_COMPAT_NAMES
*
2628 USBA_MAX_COMPAT_NAME_LEN
, KM_SLEEP
);
2630 for (i
= 0; i
< USBA_MAX_COMPAT_NAMES
; i
++) {
2631 usba_name
[i
] = usba_name_buf
+ (i
* USBA_MAX_COMPAT_NAME_LEN
);
2637 (void) ndi_devi_set_nodename(child_dip
, force_bind
, 0);
2638 (void) strncpy(usba_name
[n
++], force_bind
,
2639 USBA_MAX_COMPAT_NAME_LEN
);
2642 /* 1) usbifVID,PID.REV.configCN.IN */
2643 (void) sprintf(usba_name
[n
++],
2644 "usbif%x,%x.%x.config%x.%x",
2645 usb_dev_descr
->idVendor
,
2646 usb_dev_descr
->idProduct
,
2647 usb_dev_descr
->bcdDevice
,
2648 child_ud
->usb_cfg_value
,
2651 /* 2) usbifVID,PID.configCN.IN */
2652 (void) sprintf(usba_name
[n
++],
2653 "usbif%x,%x.config%x.%x",
2654 usb_dev_descr
->idVendor
,
2655 usb_dev_descr
->idProduct
,
2656 child_ud
->usb_cfg_value
,
2660 if (if_descr
.bInterfaceClass
) {
2661 /* 3) usbifVID,classIC.ISC.IPROTO */
2662 (void) sprintf(usba_name
[n
++],
2663 "usbif%x,class%x.%x.%x",
2664 usb_dev_descr
->idVendor
,
2665 if_descr
.bInterfaceClass
,
2666 if_descr
.bInterfaceSubClass
,
2667 if_descr
.bInterfaceProtocol
);
2669 /* 4) usbifVID,classIC.ISC */
2670 (void) sprintf(usba_name
[n
++],
2671 "usbif%x,class%x.%x",
2672 usb_dev_descr
->idVendor
,
2673 if_descr
.bInterfaceClass
,
2674 if_descr
.bInterfaceSubClass
);
2676 /* 5) usbifVID,classIC */
2677 (void) sprintf(usba_name
[n
++],
2679 usb_dev_descr
->idVendor
,
2680 if_descr
.bInterfaceClass
);
2682 /* 6) usbif,classIC.ISC.IPROTO */
2683 (void) sprintf(usba_name
[n
++],
2684 "usbif,class%x.%x.%x",
2685 if_descr
.bInterfaceClass
,
2686 if_descr
.bInterfaceSubClass
,
2687 if_descr
.bInterfaceProtocol
);
2689 /* 7) usbif,classIC.ISC */
2690 (void) sprintf(usba_name
[n
++],
2692 if_descr
.bInterfaceClass
,
2693 if_descr
.bInterfaceSubClass
);
2695 /* 8) usbif,classIC */
2696 (void) sprintf(usba_name
[n
++],
2698 if_descr
.bInterfaceClass
);
2701 if (usba_get_ugen_binding(child_dip
) ==
2702 USBA_UGEN_INTERFACE_BINDING
) {
2704 (void) sprintf(usba_name
[n
++], "ugen");
2707 for (i
= 0; i
< n
; i
+= 2) {
2708 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
2709 "compatible name:\t%s\t%s", usba_name
[i
],
2710 (((i
+1) < n
)? usba_name
[i
+1] : ""));
2713 /* create compatible property */
2714 rval
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, child_dip
,
2715 "compatible", (char **)usba_name
, n
);
2717 kmem_free(usba_name_buf
, USBA_MAX_COMPAT_NAMES
*
2718 USBA_MAX_COMPAT_NAME_LEN
);
2720 if (rval
!= DDI_PROP_SUCCESS
) {
2725 /* update the address property */
2726 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2727 "assigned-address", child_ud
->usb_addr
);
2728 if (rval
!= DDI_PROP_SUCCESS
) {
2729 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2730 "usba_ready_interface_node: address update failed");
2733 /* create property with if number */
2734 rval
= ndi_prop_update_int(DDI_DEV_T_NONE
, child_dip
,
2737 if (rval
!= DDI_PROP_SUCCESS
) {
2742 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
2743 "%s%d port %d: %s, dip = 0x%p",
2744 ddi_node_name(ddi_get_parent(dip
)),
2745 ddi_get_instance(ddi_get_parent(dip
)),
2746 child_ud
->usb_port
, ddi_node_name(child_dip
), (void *)child_dip
);
2748 usba_set_usba_device(child_dip
, child_ud
);
2749 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip
)->usb_mutex
)));
2754 (void) usba_destroy_child_devi(child_dip
, NDI_DEVI_REMOVE
);
2761 * retrieve string descriptors for manufacturer, vendor and serial
2765 usba_get_dev_string_descrs(dev_info_t
*dip
, usba_device_t
*ud
)
2769 usb_dev_descr_t
*usb_dev_descr
= ud
->usb_dev_descr
;
2772 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
2773 "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
2774 usb_dev_descr
->iManufacturer
,
2775 usb_dev_descr
->iProduct
,
2776 usb_dev_descr
->iSerialNumber
);
2778 tmpbuf
= kmem_zalloc(USB_MAXSTRINGLEN
, KM_SLEEP
);
2780 /* fetch manufacturer string */
2781 if ((ud
->usb_mfg_str
== NULL
) && usb_dev_descr
->iManufacturer
&&
2782 (usb_get_string_descr(dip
, USB_LANG_ID
,
2783 usb_dev_descr
->iManufacturer
, tmpbuf
, USB_MAXSTRINGLEN
) ==
2788 str
= kmem_zalloc(l
+ 1, KM_SLEEP
);
2789 mutex_enter(&ud
->usb_mutex
);
2790 ud
->usb_mfg_str
= str
;
2791 (void) strcpy(ud
->usb_mfg_str
, tmpbuf
);
2792 mutex_exit(&ud
->usb_mutex
);
2796 /* fetch product string */
2797 if ((ud
->usb_product_str
== NULL
) && usb_dev_descr
->iProduct
&&
2798 (usb_get_string_descr(dip
, USB_LANG_ID
, usb_dev_descr
->iProduct
,
2799 tmpbuf
, USB_MAXSTRINGLEN
) ==
2804 str
= kmem_zalloc(l
+ 1, KM_SLEEP
);
2805 mutex_enter(&ud
->usb_mutex
);
2806 ud
->usb_product_str
= str
;
2807 (void) strcpy(ud
->usb_product_str
, tmpbuf
);
2808 mutex_exit(&ud
->usb_mutex
);
2812 /* fetch device serial number string */
2813 if ((ud
->usb_serialno_str
== NULL
) && usb_dev_descr
->iSerialNumber
&&
2814 (usb_get_string_descr(dip
, USB_LANG_ID
,
2815 usb_dev_descr
->iSerialNumber
, tmpbuf
, USB_MAXSTRINGLEN
) ==
2820 str
= kmem_zalloc(l
+ 1, KM_SLEEP
);
2821 mutex_enter(&ud
->usb_mutex
);
2822 ud
->usb_serialno_str
= str
;
2823 (void) strcpy(ud
->usb_serialno_str
, tmpbuf
);
2824 mutex_exit(&ud
->usb_mutex
);
2828 kmem_free(tmpbuf
, USB_MAXSTRINGLEN
);
2833 * usba_str_startcmp:
2834 * Return the number of characters duplicated from the beginning of the
2835 * string. Return -1 if a complete duplicate.
2838 * Two strings to compare.
2840 static int usba_str_startcmp(char *first
, char *second
)
2842 int num_same_chars
= 0;
2843 while (*first
== *second
++) {
2844 if (*first
++ == '\0') {
2850 return (num_same_chars
);
2855 * usba_get_mfg_prod_sn_str:
2856 * Return a string containing mfg, product, serial number strings.
2857 * Remove duplicates if some strings are the same.
2860 * dip - pointer to dev info
2861 * buffer - Where string is returned
2862 * buflen - Length of buffer
2865 * Same as second arg.
2868 usba_get_mfg_prod_sn_str(
2873 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
2879 buffer
[buflen
-1] = '\0';
2881 if ((usba_device
->usb_mfg_str
) &&
2882 ((len
= strlen(usba_device
->usb_mfg_str
)) != 0)) {
2883 (void) strncpy(buffer
, usba_device
->usb_mfg_str
, buflen
- 1);
2884 return_len
= min(buflen
- 1, len
);
2887 /* Product string exists to append. */
2888 if ((usba_device
->usb_product_str
) &&
2889 ((len
= strlen(usba_device
->usb_product_str
)) != 0)) {
2891 /* Append only parts of string that don't match mfg string. */
2892 duplen
= usba_str_startcmp(buffer
,
2893 usba_device
->usb_product_str
);
2895 if (duplen
!= -1) { /* Not a complete match. */
2896 if (return_len
> 0) {
2897 buffer
[return_len
++] = ' ';
2900 /* Skip over the dup part of the concat'ed string. */
2902 (void) strncpy(&buffer
[return_len
],
2903 &usba_device
->usb_product_str
[duplen
],
2904 buflen
- return_len
- 1);
2905 return_len
= min(buflen
- 1, return_len
+ len
);
2909 if ((usba_device
->usb_serialno_str
) &&
2910 ((len
= strlen(usba_device
->usb_serialno_str
)) != 0)) {
2911 if (return_len
> 0) {
2912 buffer
[return_len
++] = ' ';
2914 (void) strncpy(&buffer
[return_len
],
2915 usba_device
->usb_serialno_str
,
2916 buflen
- return_len
- 1);
2924 * USB enumeration statistic functions
2928 * Increments the hotplug statistics based on flags.
2931 usba_update_hotplug_stats(dev_info_t
*dip
, usb_flags_t flags
)
2933 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
2935 usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
2937 mutex_enter(&hcdi
->hcdi_mutex
);
2938 if (flags
& USBA_TOTAL_HOTPLUG_SUCCESS
) {
2939 hcdi
->hcdi_total_hotplug_success
++;
2940 HCDI_HOTPLUG_STATS_DATA(hcdi
)->
2941 hcdi_hotplug_total_success
.value
.ui64
++;
2943 if (flags
& USBA_HOTPLUG_SUCCESS
) {
2944 hcdi
->hcdi_hotplug_success
++;
2945 HCDI_HOTPLUG_STATS_DATA(hcdi
)->
2946 hcdi_hotplug_success
.value
.ui64
++;
2948 if (flags
& USBA_TOTAL_HOTPLUG_FAILURE
) {
2949 hcdi
->hcdi_total_hotplug_failure
++;
2950 HCDI_HOTPLUG_STATS_DATA(hcdi
)->
2951 hcdi_hotplug_total_failure
.value
.ui64
++;
2953 if (flags
& USBA_HOTPLUG_FAILURE
) {
2954 hcdi
->hcdi_hotplug_failure
++;
2955 HCDI_HOTPLUG_STATS_DATA(hcdi
)->
2956 hcdi_hotplug_failure
.value
.ui64
++;
2958 mutex_exit(&hcdi
->hcdi_mutex
);
2963 * Retrieve the current enumeration statistics
2966 usba_get_hotplug_stats(dev_info_t
*dip
, ulong_t
*total_success
,
2967 ulong_t
*success
, ulong_t
*total_failure
, ulong_t
*failure
,
2968 uchar_t
*device_count
)
2970 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
2972 usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
2974 mutex_enter(&hcdi
->hcdi_mutex
);
2975 *total_success
= hcdi
->hcdi_total_hotplug_success
;
2976 *success
= hcdi
->hcdi_hotplug_success
;
2977 *total_failure
= hcdi
->hcdi_total_hotplug_failure
;
2978 *failure
= hcdi
->hcdi_hotplug_failure
;
2979 *device_count
= hcdi
->hcdi_device_count
;
2980 mutex_exit(&hcdi
->hcdi_mutex
);
2985 * Reset the resetable hotplug stats
2988 usba_reset_hotplug_stats(dev_info_t
*dip
)
2990 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
2992 usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
2993 hcdi_hotplug_stats_t
*hsp
;
2995 mutex_enter(&hcdi
->hcdi_mutex
);
2996 hcdi
->hcdi_hotplug_success
= 0;
2997 hcdi
->hcdi_hotplug_failure
= 0;
2999 hsp
= HCDI_HOTPLUG_STATS_DATA(hcdi
);
3000 hsp
->hcdi_hotplug_success
.value
.ui64
= 0;
3001 hsp
->hcdi_hotplug_failure
.value
.ui64
= 0;
3002 mutex_exit(&hcdi
->hcdi_mutex
);
3007 * usba_bind_driver():
3008 * This function calls ndi_devi_bind_driver() which tries to
3009 * bind a driver to the device. If the driver binding fails
3010 * we get an rval of NDI_UNBOUD and report an error to the
3011 * syslog that the driver failed binding.
3012 * If rval is something other than NDI_UNBOUND we report an
3013 * error to the console.
3015 * This function returns USB_SUCCESS if no errors were
3016 * encountered while binding.
3019 usba_bind_driver(dev_info_t
*dip
)
3023 uint8_t if_num
= usba_get_ifno(dip
);
3025 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
3026 "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip
, if_num
);
3028 name
= kmem_zalloc(MAXNAMELEN
, KM_SLEEP
);
3030 /* bind device to the driver */
3031 if ((rval
= ndi_devi_bind_driver(dip
, 0)) != NDI_SUCCESS
) {
3032 /* if we fail to bind report an error */
3033 (void) usba_get_mfg_prod_sn_str(dip
, name
, MAXNAMELEN
);
3034 if (name
[0] != '\0') {
3035 if (!usb_owns_device(dip
)) {
3036 USB_DPRINTF_L1(DPRINT_MASK_USBA
,
3038 "no driver found for "
3039 "interface %d (nodename: '%s') of %s",
3040 if_num
, ddi_node_name(dip
), name
);
3042 USB_DPRINTF_L1(DPRINT_MASK_USBA
,
3044 "no driver found for device %s", name
);
3047 (void) ddi_pathname(dip
, name
);
3048 USB_DPRINTF_L1(DPRINT_MASK_USBA
,
3050 "no driver found for device %s", name
);
3053 kmem_free(name
, MAXNAMELEN
);
3055 return (USB_FAILURE
);
3057 kmem_free(name
, MAXNAMELEN
);
3059 return ((rval
== NDI_SUCCESS
) ? USB_SUCCESS
: USB_FAILURE
);
3064 * usba_get_hc_dma_attr:
3065 * function returning dma attributes of the HCD
3068 * dip - pointer to devinfo of the client
3074 usba_get_hc_dma_attr(dev_info_t
*dip
)
3076 usba_device_t
*usba_device
= usba_get_usba_device(dip
);
3077 usba_hcdi_t
*hcdi
= usba_hcdi_get_hcdi(usba_device
->usb_root_hub_dip
);
3079 return (hcdi
->hcdi_dma_attr
);
3084 * usba_check_for_leaks:
3085 * check usba_device structure for leaks
3088 * usba_device - usba_device structure pointer
3091 usba_check_for_leaks(usba_device_t
*usba_device
)
3093 int i
, ph_open_cnt
, req_wrp_leaks
, iface
;
3096 USB_DPRINTF_L4(DPRINT_MASK_USBA
, usba_log_handle
,
3097 "usba_check_for_leaks: %s%d usba_device=0x%p",
3098 ddi_driver_name(usba_device
->usb_dip
),
3099 ddi_get_instance(usba_device
->usb_dip
), (void *)usba_device
);
3102 * default pipe is still open
3103 * all other pipes should be closed
3105 for (ph_open_cnt
= 0, i
= 1; i
< USBA_N_ENDPOINTS
; i
++) {
3106 usba_ph_impl_t
*ph_impl
=
3107 &usba_device
->usb_ph_list
[i
];
3108 if (ph_impl
->usba_ph_data
) {
3109 USB_DPRINTF_L2(DPRINT_MASK_USBA
,
3111 "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
3112 ddi_driver_name(ph_impl
->usba_ph_data
->p_dip
),
3113 ddi_get_instance(ph_impl
->usba_ph_data
->p_dip
),
3115 (void *)ph_impl
->usba_ph_data
,
3116 ph_impl
->usba_ph_ep
.bEndpointAddress
);
3120 usb_pipe_close(ph_impl
->usba_ph_data
->p_dip
,
3121 (usb_pipe_handle_t
)ph_impl
, USB_FLAGS_SLEEP
,
3126 req_wrp_leaks
= usba_list_entry_leaks(&usba_device
->
3127 usb_allocated
, "request wrappers");
3129 ASSERT(ph_open_cnt
== 0);
3130 ASSERT(req_wrp_leaks
== 0);
3132 if (req_wrp_leaks
) {
3133 usba_list_entry_t
*entry
;
3135 while ((entry
= usba_rm_first_from_list(
3136 &usba_device
->usb_allocated
)) != NULL
) {
3137 usba_req_wrapper_t
*wrp
;
3139 mutex_enter(&entry
->list_mutex
);
3140 wrp
= (usba_req_wrapper_t
*)entry
->private;
3141 mutex_exit(&entry
->list_mutex
);
3144 USB_DPRINTF_L2(DPRINT_MASK_USBA
,
3146 "%s%d: leaking request 0x%p",
3147 ddi_driver_name(wrp
->wr_dip
),
3148 ddi_get_instance(wrp
->wr_dip
),
3149 (void *)wrp
->wr_req
);
3152 * put it back, usba_req_wrapper_free
3153 * expects it on the list
3155 usba_add_to_list(&usba_device
->usb_allocated
,
3156 &wrp
->wr_allocated_list
);
3158 usba_req_wrapper_free(wrp
);
3162 mutex_enter(&usba_device
->usb_mutex
);
3163 for (iface
= 0; iface
< usba_device
->usb_n_ifs
; iface
++) {
3164 USB_DPRINTF_L3(DPRINT_MASK_USBA
, usba_log_handle
,
3165 "usba_check_for_leaks: if=%d client_flags=0x%x",
3166 iface
, usba_device
->usb_client_flags
[iface
]);
3168 if (usba_device
->usb_client_flags
[iface
] &
3169 USBA_CLIENT_FLAG_DEV_DATA
) {
3170 usb_client_dev_data_list_t
*entry
=
3171 usba_device
->usb_client_dev_data_list
.cddl_next
;
3172 usb_client_dev_data_list_t
*next
;
3173 usb_client_dev_data_t
*dev_data
;
3176 dev_info_t
*dip
= entry
->cddl_dip
;
3177 next
= entry
->cddl_next
;
3178 dev_data
= entry
->cddl_dev_data
;
3181 if (!i_ddi_devi_attached(dip
)) {
3182 USB_DPRINTF_L2(DPRINT_MASK_USBA
,
3184 "%s%d: leaking dev_data 0x%p",
3185 ddi_driver_name(dip
),
3186 ddi_get_instance(dip
),
3191 mutex_exit(&usba_device
->usb_mutex
);
3192 usb_free_dev_data(dip
, dev_data
);
3193 mutex_enter(&usba_device
->usb_mutex
);
3199 if (usba_device
->usb_client_flags
[iface
] &
3200 USBA_CLIENT_FLAG_ATTACH
) {
3201 dev_info_t
*dip
= usba_device
->
3202 usb_client_attach_list
[iface
].dip
;
3204 USB_DPRINTF_L2(DPRINT_MASK_USBA
,
3206 "%s%d: did no usb_client_detach",
3207 ddi_driver_name(dip
), ddi_get_instance(dip
));
3210 mutex_exit(&usba_device
->usb_mutex
);
3211 usb_client_detach(dip
, NULL
);
3212 mutex_enter(&usba_device
->usb_mutex
);
3215 usb_client_attach_list
[iface
].dip
= NULL
;
3217 usba_device
->usb_client_flags
[iface
] &=
3218 ~USBA_CLIENT_FLAG_ATTACH
;
3221 if (usba_device
->usb_client_flags
[iface
] &
3222 USBA_CLIENT_FLAG_EV_CBS
) {
3224 usba_device
->usb_client_ev_cb_list
[iface
].
3226 usb_event_t
*ev_data
=
3227 usba_device
->usb_client_ev_cb_list
[iface
].
3230 USB_DPRINTF_L2(DPRINT_MASK_USBA
,
3232 "%s%d: did no usb_unregister_event_cbs",
3233 ddi_driver_name(dip
), ddi_get_instance(dip
));
3236 mutex_exit(&usba_device
->usb_mutex
);
3237 usb_unregister_event_cbs(dip
, ev_data
);
3238 mutex_enter(&usba_device
->usb_mutex
);
3240 usba_device
->usb_client_ev_cb_list
[iface
].
3242 usba_device
->usb_client_ev_cb_list
[iface
].
3244 usba_device
->usb_client_flags
[iface
] &=
3245 ~USBA_CLIENT_FLAG_EV_CBS
;
3248 mutex_exit(&usba_device
->usb_mutex
);
3251 USB_DPRINTF_L2(DPRINT_MASK_USBA
, usba_log_handle
,
3252 "all %d leaks fixed", leaks
);