Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / usb / usba / usba.c
blobd7a372faf1000491192a042b8910e9ac790c9c3a
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
26 * Copyright 2016 James S. Blachly, MD <james.blachly@gmail.com>
31 * USBA: Solaris USB Architecture support
33 #define USBA_FRAMEWORK
34 #include <sys/usb/usba/usba_impl.h>
35 #include <sys/usb/usba/hcdi_impl.h>
36 #include <sys/usb/hubd/hub.h>
37 #include <sys/fs/dv_node.h>
40 * USBA private variables and tunables
42 static kmutex_t usba_mutex;
44 /* mutex to protect usba_root_hubs */
45 static kmutex_t usba_hub_mutex;
47 typedef struct usba_root_hub_ent {
48 dev_info_t *dip;
49 struct usba_root_hub_ent *next;
50 }usba_root_hub_ent_t;
52 static usba_root_hub_ent_t *usba_root_hubs = NULL;
55 * ddivs forced binding:
57 * usbc usbc_xhubs usbc_xaddress node name
59 * 0 x x class name or "device"
61 * 1 0 0 ddivs_usbc
62 * 1 0 >1 ddivs_usbc except device
63 * at usbc_xaddress
64 * 1 1 0 ddivs_usbc except hubs
65 * 1 1 >1 ddivs_usbc except hubs and
66 * device at usbc_xaddress
68 uint_t usba_ddivs_usbc;
69 uint_t usba_ddivs_usbc_xhubs;
70 uint_t usba_ddivs_usbc_xaddress;
72 uint_t usba_ugen_force_binding;
75 * compatible name handling
78 * allowing for 15 compat names, plus one force bind name and
79 * one possible specified client driver name
81 #define USBA_MAX_COMPAT_NAMES 17
82 #define USBA_MAX_COMPAT_NAME_LEN 64
84 /* double linked list for usba_devices */
85 usba_list_entry_t usba_device_list;
87 _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
90 * modload support
93 static struct modlmisc modlmisc = {
94 &mod_miscops, /* Type of module */
95 "USBA: USB Architecture 2.0 1.66"
98 static struct modlinkage modlinkage = {
99 MODREV_1, (void *)&modlmisc, NULL
103 static usb_log_handle_t usba_log_handle;
104 uint_t usba_errlevel = USB_LOG_L4;
105 uint_t usba_errmask = (uint_t)-1;
107 extern usb_log_handle_t hubdi_log_handle;
110 _init(void)
112 int rval;
115 * usbai providing log support needs to be init'ed first
116 * and destroyed last
118 usba_usbai_initialization();
119 usba_usba_initialization();
120 usba_usbai_register_initialization();
121 usba_hcdi_initialization();
122 usba_hubdi_initialization();
123 usba_devdb_initialization();
125 if ((rval = mod_install(&modlinkage)) != 0) {
126 usba_devdb_destroy();
127 usba_hubdi_destroy();
128 usba_hcdi_destroy();
129 usba_usbai_register_destroy();
130 usba_usba_destroy();
131 usba_usbai_destroy();
134 return (rval);
138 _fini()
140 int rval;
142 if ((rval = mod_remove(&modlinkage)) == 0) {
143 usba_devdb_destroy();
144 usba_hubdi_destroy();
145 usba_hcdi_destroy();
146 usba_usbai_register_destroy();
147 usba_usba_destroy();
148 usba_usbai_destroy();
151 return (rval);
155 _info(struct modinfo *modinfop)
157 return (mod_info(&modlinkage, modinfop));
160 boolean_t
161 usba_owns_ia(dev_info_t *dip)
163 int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
164 "interface-count", 0);
166 return ((if_count) ? B_TRUE : B_FALSE);
170 * common bus ctl for hcd, usb_mid, and hubd
173 usba_bus_ctl(dev_info_t *dip,
174 dev_info_t *rdip,
175 ddi_ctl_enum_t op,
176 void *arg,
177 void *result)
179 dev_info_t *child_dip = (dev_info_t *)arg;
180 usba_device_t *usba_device;
181 usba_hcdi_t *usba_hcdi;
182 usba_hcdi_ops_t *usba_hcdi_ops;
184 USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
185 "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
186 ddi_get_instance(rdip), ddi_node_name(dip),
187 ddi_get_instance(dip), op);
189 switch (op) {
191 case DDI_CTLOPS_REPORTDEV:
193 char *name, compat_name[64], *speed;
194 usba_device_t *hub_usba_device;
195 dev_info_t *hubdip;
197 usba_device = usba_get_usba_device(rdip);
199 /* find the parent hub */
200 hubdip = ddi_get_parent(rdip);
201 while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
202 !(usba_is_root_hub(hubdip))) {
203 hubdip = ddi_get_parent(hubdip);
206 hub_usba_device = usba_get_usba_device(hubdip);
208 if (usba_device) {
209 if (usb_owns_device(rdip)) {
210 (void) snprintf(compat_name,
211 sizeof (compat_name),
212 "usb%x,%x",
213 usba_device->usb_dev_descr->idVendor,
214 usba_device->usb_dev_descr->idProduct);
215 } else if (usba_owns_ia(rdip)) {
216 (void) snprintf(compat_name,
217 sizeof (compat_name),
218 "usbia%x,%x.config%x.%x",
219 usba_device->usb_dev_descr->idVendor,
220 usba_device->usb_dev_descr->idProduct,
221 usba_device->usb_cfg_value,
222 usb_get_if_number(rdip));
223 } else {
224 (void) snprintf(compat_name,
225 sizeof (compat_name),
226 "usbif%x,%x.config%x.%x",
227 usba_device->usb_dev_descr->idVendor,
228 usba_device->usb_dev_descr->idProduct,
229 usba_device->usb_cfg_value,
230 usb_get_if_number(rdip));
232 switch (usba_device->usb_port_status) {
233 case USBA_SUPER_SPEED_DEV:
234 speed = "super speed (USB 3.x)";
235 break;
236 case USBA_HIGH_SPEED_DEV:
237 speed = "hi speed (USB 2.x)";
238 break;
239 case USBA_LOW_SPEED_DEV:
240 speed = "low speed (USB 1.x)";
241 break;
242 case USBA_FULL_SPEED_DEV:
243 default:
244 speed = "full speed (USB 1.x)";
245 break;
248 cmn_err(CE_CONT,
249 "?USB %x.%x %s (%s) operating at %s on "
250 "USB %x.%x %s hub: "
251 "%s@%s, %s%d at bus address %d\n",
252 (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
253 usba_device->usb_dev_descr->bcdUSB & 0xff,
254 (usb_owns_device(rdip) ? "device" :
255 ((usba_owns_ia(rdip) ? "interface-association" :
256 "interface"))),
257 compat_name, speed,
258 (hub_usba_device->usb_dev_descr->bcdUSB &
259 0xff00) >> 8,
260 hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
261 usba_is_root_hub(hubdip) ? "root" : "external",
262 ddi_node_name(rdip), ddi_get_name_addr(rdip),
263 ddi_driver_name(rdip),
264 ddi_get_instance(rdip), usba_device->usb_addr);
266 name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
267 (void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
268 if (name[0] != '\0') {
269 cmn_err(CE_CONT, "?%s\n", name);
271 kmem_free(name, MAXNAMELEN);
273 } else { /* harden USBA against this case; if it happens */
275 cmn_err(CE_CONT,
276 "?USB-device: %s@%s, %s%d\n",
277 ddi_node_name(rdip), ddi_get_name_addr(rdip),
278 ddi_driver_name(rdip), ddi_get_instance(rdip));
281 return (DDI_SUCCESS);
284 case DDI_CTLOPS_INITCHILD:
286 int usb_addr;
287 uint_t n;
288 char name[32];
289 int *data;
290 int rval;
291 int len = sizeof (usb_addr);
293 usba_hcdi = usba_hcdi_get_hcdi(dip);
294 usba_hcdi_ops = usba_hcdi->hcdi_ops;
295 ASSERT(usba_hcdi_ops != NULL);
298 * as long as the dip exists, it should have
299 * usba_device structure associated with it
301 usba_device = usba_get_usba_device(child_dip);
302 if (usba_device == NULL) {
304 USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
305 "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
306 ddi_node_name(child_dip), (void *)child_dip);
308 return (DDI_NOT_WELL_FORMED);
311 /* the dip should have an address and reg property */
312 if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
313 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "assigned-address",
314 (caddr_t)&usb_addr, &len) != DDI_SUCCESS) {
316 USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
317 "usba_bus_ctl:\n\t"
318 "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
319 ddi_node_name(rdip), ddi_get_instance(rdip),
320 ddi_node_name(dip), ddi_get_instance(dip), op,
321 (void *)rdip, (void *)dip);
323 USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
324 "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
325 ddi_node_name(child_dip), (void *)child_dip);
327 return (DDI_NOT_WELL_FORMED);
330 if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
331 DDI_PROP_DONTPASS, "reg",
332 &data, &n)) != DDI_SUCCESS) {
334 USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
335 "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
337 return (DDI_NOT_WELL_FORMED);
342 * if the configuration is 1, the unit address is
343 * just the interface number
345 if ((n == 1) || ((n > 1) && (data[1] == 1))) {
346 (void) sprintf(name, "%x", data[0]);
347 } else {
348 (void) sprintf(name, "%x,%x", data[0], data[1]);
351 USB_DPRINTF_L3(DPRINT_MASK_USBA,
352 hubdi_log_handle, "usba_bus_ctl: name = %s", name);
354 ddi_prop_free(data);
355 ddi_set_name_addr(child_dip, name);
358 * increment the reference count for each child using this
359 * usba_device structure
361 mutex_enter(&usba_device->usb_mutex);
362 usba_device->usb_ref_count++;
364 USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
365 "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
366 (void *)usba_device, usba_device->usb_ref_count);
368 mutex_exit(&usba_device->usb_mutex);
370 return (DDI_SUCCESS);
373 case DDI_CTLOPS_UNINITCHILD:
375 usba_device = usba_get_usba_device(child_dip);
377 if (usba_device != NULL) {
379 * decrement the reference count for each child
380 * using this usba_device structure
382 mutex_enter(&usba_device->usb_mutex);
383 usba_device->usb_ref_count--;
385 USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
386 "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
387 "ref_count=%d",
388 (void *)usba_device, usba_device->usb_ref_count);
390 mutex_exit(&usba_device->usb_mutex);
392 ddi_set_name_addr(child_dip, NULL);
394 return (DDI_SUCCESS);
397 case DDI_CTLOPS_IOMIN:
398 /* Do nothing */
399 return (DDI_SUCCESS);
402 * These ops correspond to functions that "shouldn't" be called
403 * by a USB client driver. So we whine when we're called.
405 case DDI_CTLOPS_DMAPMAPC:
406 case DDI_CTLOPS_REPORTINT:
407 case DDI_CTLOPS_REGSIZE:
408 case DDI_CTLOPS_NREGS:
409 case DDI_CTLOPS_SIDDEV:
410 case DDI_CTLOPS_SLAVEONLY:
411 case DDI_CTLOPS_AFFINITY:
412 case DDI_CTLOPS_POKE:
413 case DDI_CTLOPS_PEEK:
414 cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d",
415 ddi_node_name(dip), ddi_get_instance(dip),
416 op, ddi_node_name(rdip), ddi_get_instance(rdip));
417 return (DDI_FAILURE);
420 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
422 default:
423 return (ddi_ctlops(dip, rdip, op, arg, result));
429 * initialize and destroy USBA module
431 void
432 usba_usba_initialization()
434 usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
435 &usba_errmask, NULL, 0);
437 USB_DPRINTF_L4(DPRINT_MASK_USBA,
438 usba_log_handle, "usba_usba_initialization");
440 mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
441 mutex_init(&usba_hub_mutex, NULL, MUTEX_DRIVER, NULL);
442 usba_init_list(&usba_device_list, NULL, NULL);
446 void
447 usba_usba_destroy()
449 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
451 mutex_destroy(&usba_hub_mutex);
452 mutex_destroy(&usba_mutex);
453 usba_destroy_list(&usba_device_list);
455 usb_free_log_hdl(usba_log_handle);
460 * usba_set_usb_address:
461 * set usb address in usba_device structure
464 usba_set_usb_address(usba_device_t *usba_device)
466 usb_addr_t address;
467 uchar_t s = 8;
468 usba_hcdi_t *hcdi;
469 char *usb_address_in_use;
471 mutex_enter(&usba_device->usb_mutex);
473 hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
475 mutex_enter(&hcdi->hcdi_mutex);
476 usb_address_in_use = hcdi->hcdi_usb_address_in_use;
478 for (address = ROOT_HUB_ADDR + 1;
479 address <= USBA_MAX_ADDRESS; address++) {
480 if (usb_address_in_use[address/s] & (1 << (address % s))) {
481 continue;
483 usb_address_in_use[address/s] |= (1 << (address % s));
484 hcdi->hcdi_device_count++;
485 HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
486 mutex_exit(&hcdi->hcdi_mutex);
488 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
489 "usba_set_usb_address: %d", address);
491 usba_device->usb_addr = address;
493 mutex_exit(&usba_device->usb_mutex);
495 return (USB_SUCCESS);
498 usba_device->usb_addr = 0;
500 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
501 "no usb address available");
503 mutex_exit(&hcdi->hcdi_mutex);
504 mutex_exit(&usba_device->usb_mutex);
506 return (USB_FAILURE);
511 * usba_unset_usb_address:
512 * unset usb_address in usba_device structure
514 void
515 usba_unset_usb_address(usba_device_t *usba_device)
517 usb_addr_t address;
518 usba_hcdi_t *hcdi;
519 uchar_t s = 8;
520 char *usb_address_in_use;
522 mutex_enter(&usba_device->usb_mutex);
523 address = usba_device->usb_addr;
524 hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
526 if (address > ROOT_HUB_ADDR) {
527 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
528 "usba_unset_usb_address: address=%d", address);
530 mutex_enter(&hcdi->hcdi_mutex);
531 usb_address_in_use = hcdi->hcdi_usb_address_in_use;
533 ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
535 usb_address_in_use[address/s] &= ~(1 << (address % s));
537 hcdi->hcdi_device_count--;
538 HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
540 mutex_exit(&hcdi->hcdi_mutex);
542 usba_device->usb_addr = 0;
544 mutex_exit(&usba_device->usb_mutex);
548 struct usba_evdata *
549 usba_get_evdata(dev_info_t *dip)
551 usba_evdata_t *evdata;
552 usba_device_t *usba_device = usba_get_usba_device(dip);
554 /* called when dip attaches */
555 ASSERT(usba_device != NULL);
557 mutex_enter(&usba_device->usb_mutex);
558 evdata = usba_device->usb_evdata;
559 while (evdata) {
560 if (evdata->ev_dip == dip) {
561 mutex_exit(&usba_device->usb_mutex);
563 return (evdata);
565 evdata = evdata->ev_next;
568 evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
569 evdata->ev_dip = dip;
570 evdata->ev_next = usba_device->usb_evdata;
571 usba_device->usb_evdata = evdata;
572 mutex_exit(&usba_device->usb_mutex);
574 return (evdata);
579 * allocate a usb device structure and link it in the list
581 usba_device_t *
582 usba_alloc_usba_device(dev_info_t *root_hub_dip)
584 usba_device_t *usba_device;
585 int ep_idx;
586 ddi_iblock_cookie_t iblock_cookie =
587 usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
590 * create a new usba_device structure
592 usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
595 * initialize usba_device
597 mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
598 iblock_cookie);
600 usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
601 iblock_cookie);
602 usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
603 iblock_cookie);
604 mutex_enter(&usba_device->usb_mutex);
605 usba_device->usb_root_hub_dip = root_hub_dip;
608 * add to list of usba_devices
610 usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
612 /* init mutex in each usba_ph_impl structure */
613 for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
614 mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
615 NULL, MUTEX_DRIVER, iblock_cookie);
618 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
619 "allocated usba_device 0x%p", (void *)usba_device);
621 mutex_exit(&usba_device->usb_mutex);
623 return (usba_device);
627 /* free NDI event data associated with usba_device */
628 void
629 usba_free_evdata(usba_evdata_t *evdata)
631 usba_evdata_t *next;
633 while (evdata) {
634 next = evdata->ev_next;
635 kmem_free(evdata, sizeof (usba_evdata_t));
636 evdata = next;
642 * free usb device structure
644 void
645 usba_free_usba_device(usba_device_t *usba_device)
647 int i, ep_idx;
648 usb_pipe_handle_t def_ph;
650 if (usba_device == NULL) {
652 return;
655 mutex_enter(&usba_device->usb_mutex);
656 if (usba_device->usb_ref_count) {
657 mutex_exit(&usba_device->usb_mutex);
659 return;
662 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
663 "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
664 (void *)usba_device, usba_device->usb_addr,
665 usba_device->usb_ref_count);
667 usba_free_evdata(usba_device->usb_evdata);
668 mutex_exit(&usba_device->usb_mutex);
670 def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
671 if (def_ph != NULL) {
672 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(def_ph);
674 if (ph_data) {
675 usb_pipe_close(ph_data->p_dip, def_ph,
676 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
677 NULL, NULL);
682 * Give the HCD a chance to clean up this child device before we finish
683 * tearing things down.
685 if (usba_device->usb_hcdi_ops->usba_hcdi_device_fini != NULL) {
686 usba_device->usb_hcdi_ops->usba_hcdi_device_fini(
687 usba_device, usba_device->usb_hcd_private);
688 usba_device->usb_hcd_private = NULL;
691 mutex_enter(&usba_mutex);
693 /* destroy mutex in each usba_ph_impl structure */
694 for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
695 mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
698 (void) usba_rm_from_list(&usba_device_list,
699 &usba_device->usb_device_list);
701 mutex_exit(&usba_mutex);
703 usba_destroy_list(&usba_device->usb_device_list);
704 usba_destroy_list(&usba_device->usb_allocated);
706 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
707 "deallocating usba_device = 0x%p, address = 0x%x",
708 (void *)usba_device, usba_device->usb_addr);
711 * ohci allocates descriptors for root hub so we can't
712 * deallocate these here
715 if (usba_device->usb_addr != ROOT_HUB_ADDR) {
716 if (usba_device->usb_cfg_array) {
717 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
718 "deallocating usb_config_array: 0x%p",
719 (void *)usba_device->usb_cfg_array);
720 mutex_enter(&usba_device->usb_mutex);
721 for (i = 0;
722 i < usba_device->usb_dev_descr->bNumConfigurations;
723 i++) {
724 if (usba_device->usb_cfg_array[i]) {
725 kmem_free(
726 usba_device->usb_cfg_array[i],
727 usba_device->usb_cfg_array_len[i]);
731 /* free the array pointers */
732 kmem_free(usba_device->usb_cfg_array,
733 usba_device->usb_cfg_array_length);
734 kmem_free(usba_device->usb_cfg_array_len,
735 usba_device->usb_cfg_array_len_length);
737 mutex_exit(&usba_device->usb_mutex);
740 if (usba_device->usb_cfg_str_descr) {
741 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
742 "deallocating usb_cfg_str_descr: 0x%p",
743 (void *)usba_device->usb_cfg_str_descr);
744 for (i = 0;
745 i < usba_device->usb_dev_descr->bNumConfigurations;
746 i++) {
747 if (usba_device->usb_cfg_str_descr[i]) {
748 kmem_free(
749 usba_device->usb_cfg_str_descr[i],
750 strlen(usba_device->
751 usb_cfg_str_descr[i]) + 1);
754 /* free the array pointers */
755 kmem_free(usba_device->usb_cfg_str_descr,
756 sizeof (uchar_t *) * usba_device->usb_n_cfgs);
759 if (usba_device->usb_dev_descr) {
760 kmem_free(usba_device->usb_dev_descr,
761 sizeof (usb_dev_descr_t));
764 if (usba_device->usb_mfg_str) {
765 kmem_free(usba_device->usb_mfg_str,
766 strlen(usba_device->usb_mfg_str) + 1);
769 if (usba_device->usb_product_str) {
770 kmem_free(usba_device->usb_product_str,
771 strlen(usba_device->usb_product_str) + 1);
774 if (usba_device->usb_serialno_str) {
775 kmem_free(usba_device->usb_serialno_str,
776 strlen(usba_device->usb_serialno_str) + 1);
779 usba_unset_usb_address(usba_device);
782 ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
784 if (usba_device->usb_client_flags) {
785 int i;
787 for (i = 0; i < usba_device->usb_n_ifs; i++) {
788 ASSERT(usba_device->usb_client_flags[i] == 0);
790 kmem_free(usba_device->usb_client_flags,
791 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
795 if (usba_device->usb_client_attach_list) {
796 kmem_free(usba_device->usb_client_attach_list,
797 usba_device->usb_n_ifs *
798 sizeof (*usba_device->usb_client_attach_list));
800 if (usba_device->usb_client_ev_cb_list) {
801 kmem_free(usba_device->usb_client_ev_cb_list,
802 usba_device->usb_n_ifs *
803 sizeof (*usba_device->usb_client_ev_cb_list));
807 * finally ready to destroy the structure
809 mutex_destroy(&usba_device->usb_mutex);
811 kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
815 /* clear the data toggle for all endpoints on this device */
816 void
817 usba_clear_data_toggle(usba_device_t *usba_device)
819 int i;
821 if (usba_device != NULL) {
822 mutex_enter(&usba_device->usb_mutex);
823 for (i = 0; i < USBA_N_ENDPOINTS; i++) {
824 usba_device->usb_ph_list[i].usba_ph_flags &=
825 ~USBA_PH_DATA_TOGGLE;
827 mutex_exit(&usba_device->usb_mutex);
833 * usba_create_child_devi():
834 * create a child devinfo node, usba_device, attach properties.
835 * the usba_device structure is shared between all interfaces
838 usba_create_child_devi(dev_info_t *dip,
839 char *node_name,
840 usba_hcdi_ops_t *usba_hcdi_ops,
841 dev_info_t *usb_root_hub_dip,
842 usb_port_status_t port_status,
843 usba_device_t *usba_device,
844 dev_info_t **child_dip)
846 int rval = USB_FAILURE;
847 int usba_device_allocated = 0;
848 usb_addr_t address;
850 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
851 "usba_create_child_devi: %s usba_device=0x%p "
852 "port status=0x%x", node_name,
853 (void *)usba_device, port_status);
855 ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
856 child_dip);
858 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
859 "child dip=0x%p", (void *)*child_dip);
861 if (usba_device == NULL) {
863 usba_device = usba_alloc_usba_device(usb_root_hub_dip);
865 /* grab the mutex to keep warlock happy */
866 mutex_enter(&usba_device->usb_mutex);
867 usba_device->usb_hcdi_ops = usba_hcdi_ops;
868 usba_device->usb_port_status = port_status;
869 mutex_exit(&usba_device->usb_mutex);
871 usba_device_allocated++;
872 } else {
873 mutex_enter(&usba_device->usb_mutex);
874 if (usba_hcdi_ops) {
875 ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
877 if (usb_root_hub_dip) {
878 ASSERT(usba_device->usb_root_hub_dip ==
879 usb_root_hub_dip);
882 usba_device->usb_port_status = port_status;
884 mutex_exit(&usba_device->usb_mutex);
887 if (usba_device->usb_addr == 0) {
888 if (usba_set_usb_address(usba_device) == USB_FAILURE) {
889 address = 0;
891 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
892 "cannot set usb address for dip=0x%p",
893 (void *)*child_dip);
895 goto fail;
898 address = usba_device->usb_addr;
900 /* attach properties */
901 rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
902 "assigned-address", address);
903 if (rval != DDI_PROP_SUCCESS) {
904 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
905 "cannot set usb address property for dip=0x%p",
906 (void *)*child_dip);
907 rval = USB_FAILURE;
909 goto fail;
913 * store the usba_device point in the dip
915 usba_set_usba_device(*child_dip, usba_device);
917 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
918 "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
919 (void *)*child_dip, ddi_driver_name(*child_dip),
920 (void *)usba_device);
922 return (USB_SUCCESS);
924 fail:
925 if (*child_dip) {
926 int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
927 ASSERT(rval == USB_SUCCESS);
928 *child_dip = NULL;
931 if (usba_device_allocated) {
932 usba_free_usba_device(usba_device);
933 } else if (address && usba_device) {
934 usba_unset_usb_address(usba_device);
937 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
938 "usba_create_child_devi failed: rval=%d", rval);
940 return (rval);
945 usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
947 usba_device_t *usba_device;
948 int rval = NDI_SUCCESS;
950 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
951 "usba_destroy_child_devi: %s%d (0x%p)",
952 ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip);
954 usba_device = usba_get_usba_device(dip);
957 * if the child hasn't been bound yet, we can just
958 * free the dip
960 if (i_ddi_node_state(dip) < DS_INITIALIZED) {
962 * do not call ndi_devi_free() since it might
963 * deadlock
965 rval = ddi_remove_child(dip, 0);
967 } else {
968 char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
969 dev_info_t *pdip = ddi_get_parent(dip);
971 (void) ddi_deviname(dip, devnm);
973 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
974 "usba_destroy_child_devi:\n\t"
975 "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
976 (void *)usba_device, devnm);
978 (void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
979 rval = ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
980 flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
981 if (rval != NDI_SUCCESS) {
982 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
983 " ndi_devi_unconfig_one %s%d failed (%d)",
984 ddi_driver_name(dip), ddi_get_instance(dip),
985 rval);
987 kmem_free(devnm, MAXNAMELEN + 1);
990 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
991 "usba_destroy_child_devi: rval=%d", rval);
993 return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
998 * list management
1000 void
1001 usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
1002 ddi_iblock_cookie_t iblock_cookie)
1004 mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
1005 iblock_cookie);
1006 mutex_enter(&element->list_mutex);
1007 element->private = private;
1008 mutex_exit(&element->list_mutex);
1012 void
1013 usba_destroy_list(usba_list_entry_t *head)
1015 mutex_enter(&head->list_mutex);
1016 ASSERT(head->next == NULL);
1017 ASSERT(head->prev == NULL);
1018 mutex_exit(&head->list_mutex);
1020 mutex_destroy(&head->list_mutex);
1024 void
1025 usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
1027 usba_list_entry_t *next;
1028 int remaining;
1030 mutex_enter(&head->list_mutex);
1031 mutex_enter(&element->list_mutex);
1033 remaining = head->count;
1035 /* check if it is not in another list */
1036 ASSERT(element->next == NULL);
1037 ASSERT(element->prev == NULL);
1039 #ifdef DEBUG
1041 * only verify the list when not in interrupt context, we
1042 * have to trust the HCD
1044 if (!servicing_interrupt()) {
1046 /* check if not already in this list */
1047 for (next = head->next; (next != NULL);
1048 next = next->next) {
1049 if (next == element) {
1050 USB_DPRINTF_L0(DPRINT_MASK_USBA,
1051 usba_log_handle,
1052 "Attempt to corrupt USB list at 0x%p",
1053 (void *)head);
1054 ASSERT(next == element);
1056 goto done;
1058 remaining--;
1061 * Detect incorrect circ links or found
1062 * unexpected elements.
1064 if ((next->next && (remaining == 0)) ||
1065 ((next->next == NULL) && remaining)) {
1066 panic("Corrupted USB list at 0x%p",
1067 (void *)head);
1068 /*NOTREACHED*/
1072 #endif
1074 if (head->next == NULL) {
1075 head->prev = head->next = element;
1076 } else {
1077 /* add to tail */
1078 head->prev->next = element;
1079 element->prev = head->prev;
1080 head->prev = element;
1083 head->count++;
1085 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1086 "usba_add_to_list: head=0x%p element=0x%p count=%d",
1087 (void *)head, (void *)element, head->count);
1089 done:
1090 mutex_exit(&head->list_mutex);
1091 mutex_exit(&element->list_mutex);
1096 usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
1098 usba_list_entry_t *e;
1099 int found = 0;
1100 int remaining;
1102 /* find the element in the list first */
1103 mutex_enter(&head->list_mutex);
1105 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1106 "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1107 (void *)head, (void *)element, head->count);
1109 remaining = head->count;
1110 e = head->next;
1112 while (e) {
1113 if (e == element) {
1114 found++;
1115 break;
1117 e = e->next;
1119 remaining--;
1121 /* Detect incorrect circ links or found unexpected elements. */
1122 if ((e && (remaining == 0)) ||
1123 ((e == NULL) && (remaining))) {
1124 panic("Corrupted USB list at 0x%p", (void *)head);
1125 /*NOTREACHED*/
1129 if (!found) {
1130 mutex_exit(&head->list_mutex);
1132 return (USB_FAILURE);
1135 /* now remove the element */
1136 mutex_enter(&element->list_mutex);
1138 if (element->next) {
1139 element->next->prev = element->prev;
1141 if (element->prev) {
1142 element->prev->next = element->next;
1144 if (head->next == element) {
1145 head->next = element->next;
1147 if (head->prev == element) {
1148 head->prev = element->prev;
1151 element->prev = element->next = NULL;
1152 if (head->next == NULL) {
1153 ASSERT(head->prev == NULL);
1154 } else {
1155 ASSERT(head->next->prev == NULL);
1157 if (head->prev == NULL) {
1158 ASSERT(head->next == NULL);
1159 } else {
1160 ASSERT(head->prev->next == NULL);
1163 head->count--;
1165 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1166 "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1167 (void *)head, (void *)element, head->count);
1169 mutex_exit(&element->list_mutex);
1170 mutex_exit(&head->list_mutex);
1172 return (USB_SUCCESS);
1176 usba_list_entry_t *
1177 usba_rm_first_from_list(usba_list_entry_t *head)
1179 usba_list_entry_t *element = NULL;
1181 if (head) {
1182 mutex_enter(&head->list_mutex);
1183 element = head->next;
1184 if (element) {
1185 /* now remove the element */
1186 mutex_enter(&element->list_mutex);
1187 head->next = element->next;
1188 if (head->next) {
1189 head->next->prev = NULL;
1191 if (head->prev == element) {
1192 head->prev = element->next;
1194 element->prev = element->next = NULL;
1195 mutex_exit(&element->list_mutex);
1196 head->count--;
1198 if (head->next == NULL) {
1199 ASSERT(head->prev == NULL);
1200 } else {
1201 ASSERT(head->next->prev == NULL);
1203 if (head->prev == NULL) {
1204 ASSERT(head->next == NULL);
1205 } else {
1206 ASSERT(head->prev->next == NULL);
1208 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1209 "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1210 (void *)head, (void *)element, head->count);
1212 mutex_exit(&head->list_mutex);
1215 return (element);
1219 usb_opaque_t
1220 usba_rm_first_pvt_from_list(usba_list_entry_t *head)
1222 usba_list_entry_t *element = usba_rm_first_from_list(head);
1223 usb_opaque_t private = NULL;
1225 if (element) {
1226 mutex_enter(&element->list_mutex);
1227 private = element->private;
1228 mutex_exit(&element->list_mutex);
1231 return (private);
1236 * move list to new list and zero original list
1238 void
1239 usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
1240 ddi_iblock_cookie_t iblock_cookie)
1242 usba_init_list(new, NULL, iblock_cookie);
1243 mutex_enter(&head->list_mutex);
1244 mutex_enter(&new->list_mutex);
1246 new->next = head->next;
1247 new->prev = head->prev;
1248 new->count = head->count;
1249 new->private = head->private;
1251 head->next = NULL;
1252 head->prev = NULL;
1253 head->count = 0;
1254 head->private = NULL;
1255 mutex_exit(&head->list_mutex);
1256 mutex_exit(&new->list_mutex);
1261 usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
1263 int rval = USB_FAILURE;
1264 int remaining;
1265 usba_list_entry_t *next;
1267 mutex_enter(&head->list_mutex);
1268 remaining = head->count;
1270 mutex_enter(&element->list_mutex);
1271 for (next = head->next; next != NULL; next = next->next) {
1272 if (next == element) {
1273 rval = USB_SUCCESS;
1274 break;
1276 remaining--;
1278 /* Detect incorrect circ links or found unexpected elements. */
1279 if ((next->next && (remaining == 0)) ||
1280 ((next->next == NULL) && remaining)) {
1281 panic("Corrupted USB list at 0x%p", (void *)head);
1282 /*NOTREACHED*/
1285 mutex_exit(&element->list_mutex);
1286 mutex_exit(&head->list_mutex);
1288 return (rval);
1293 usba_list_entry_leaks(usba_list_entry_t *head, char *what)
1295 int count = 0;
1296 int remaining;
1297 usba_list_entry_t *next;
1299 mutex_enter(&head->list_mutex);
1300 remaining = head->count;
1301 for (next = head->next; next != NULL; next = next->next) {
1302 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1303 "leaking %s 0x%p", what, (void *)next->private);
1304 count++;
1306 remaining--;
1308 /* Detect incorrect circ links or found unexpected elements. */
1309 if ((next->next && (remaining == 0)) ||
1310 ((next->next == NULL) && remaining)) {
1311 panic("Corrupted USB list at 0x%p", (void *)head);
1312 /*NOTREACHED*/
1315 ASSERT(count == head->count);
1316 mutex_exit(&head->list_mutex);
1318 if (count) {
1319 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1320 "usba_list_entry_count: leaking %d", count);
1323 return (count);
1328 usba_list_entry_count(usba_list_entry_t *head)
1330 int count;
1332 mutex_enter(&head->list_mutex);
1333 count = head->count;
1334 mutex_exit(&head->list_mutex);
1336 return (count);
1339 /* add a new root hub to the usba_root_hubs list */
1341 void
1342 usba_add_root_hub(dev_info_t *dip)
1344 usba_root_hub_ent_t *hub;
1346 hub = (usba_root_hub_ent_t *)
1347 kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
1349 mutex_enter(&usba_hub_mutex);
1350 hub->dip = dip;
1351 hub->next = usba_root_hubs;
1352 usba_root_hubs = hub;
1353 mutex_exit(&usba_hub_mutex);
1356 /* remove a root hub from the usba_root_hubs list */
1358 void
1359 usba_rem_root_hub(dev_info_t *dip)
1361 usba_root_hub_ent_t **hubp, *hub;
1363 mutex_enter(&usba_hub_mutex);
1364 hubp = &usba_root_hubs;
1365 while (*hubp) {
1366 if ((*hubp)->dip == dip) {
1367 hub = *hubp;
1368 *hubp = hub->next;
1369 kmem_free(hub, sizeof (struct usba_root_hub_ent));
1370 mutex_exit(&usba_hub_mutex);
1372 return;
1374 hubp = &(*hubp)->next;
1376 mutex_exit(&usba_hub_mutex);
1380 * check whether this dip is the root hub. Any root hub known by
1381 * usba is recorded in the linked list pointed to by usba_root_hubs
1384 usba_is_root_hub(dev_info_t *dip)
1386 usba_root_hub_ent_t *hub;
1388 mutex_enter(&usba_hub_mutex);
1389 hub = usba_root_hubs;
1390 while (hub) {
1391 if (hub->dip == dip) {
1392 mutex_exit(&usba_hub_mutex);
1394 return (1);
1396 hub = hub->next;
1398 mutex_exit(&usba_hub_mutex);
1400 return (0);
1404 * get and store usba_device pointer in the devi
1406 usba_device_t *
1407 usba_get_usba_device(dev_info_t *dip)
1410 * we cannot use parent_data in the usb node because its
1411 * bus parent (eg. PCI nexus driver) uses this data
1413 * we cannot use driver data in the other usb nodes since
1414 * usb drivers may need to use this
1416 if (usba_is_root_hub(dip)) {
1417 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1419 return (hcdi->hcdi_usba_device);
1420 } else {
1422 return (ddi_get_parent_data(dip));
1428 * Retrieve the usba_device pointer from the dev without checking for
1429 * the root hub first. This function is only used in polled mode.
1431 usba_device_t *
1432 usba_polled_get_usba_device(dev_info_t *dip)
1435 * Don't call usba_is_root_hub() to find out if this is
1436 * the root hub usba_is_root_hub() calls into the DDI
1437 * where there are locking issues. The dip sent in during
1438 * polled mode will never be the root hub, so just get
1439 * the usba_device pointer from the dip.
1441 return (ddi_get_parent_data(dip));
1445 void
1446 usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
1448 if (usba_is_root_hub(dip)) {
1449 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1450 /* no locking is needed here */
1451 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1452 hcdi->hcdi_usba_device = usba_device;
1453 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1454 } else {
1455 ddi_set_parent_data(dip, usba_device);
1461 * usba_set_node_name() according to class, subclass, and protocol
1462 * following the 1275 USB binding tables.
1465 /* device node table, refer to section 3.2.2.1 of 1275 binding */
1466 static node_name_entry_t device_node_name_table[] = {
1467 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1468 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1469 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1470 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1471 { DONTCARE, DONTCARE, DONTCARE, "device" }
1474 /* interface-association node table */
1475 static node_name_entry_t ia_node_name_table[] = {
1476 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "audio" },
1477 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1478 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
1479 "device-wire-adaptor" },
1480 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless-controller" },
1481 { DONTCARE, DONTCARE, DONTCARE, "interface-association" }
1484 /* interface node table, refer to section 3.3.2.1 */
1485 static node_name_entry_t if_node_name_table[] = {
1486 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1487 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1488 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1489 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1491 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1492 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1493 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1494 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1495 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1496 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1497 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1498 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1500 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1501 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1502 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1504 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1506 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1508 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1510 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1512 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1514 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1516 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1518 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1519 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1520 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1522 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1523 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1524 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1526 { USB_CLASS_MISC, USB_SUBCLS_CBAF, USB_PROTO_CBAF, "wusb_ca"},
1527 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
1528 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
1529 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
1530 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
1531 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
1533 { DONTCARE, DONTCARE, DONTCARE, "interface" },
1537 /* combined node table, refer to section 3.4.2.1 */
1538 static node_name_entry_t combined_node_name_table[] = {
1539 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1540 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1541 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1542 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1544 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1545 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1546 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1547 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1548 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1549 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1550 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1551 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1553 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1554 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1555 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1557 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1559 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1561 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1563 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10, DONTCARE, "storage" },
1564 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I, DONTCARE, "cdrom" },
1565 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157, DONTCARE, "tape" },
1566 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI, DONTCARE, "floppy" },
1567 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I, DONTCARE, "storage" },
1568 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI, DONTCARE, "storage" },
1569 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1571 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1573 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1575 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1576 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1577 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1579 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1580 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1581 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1583 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1584 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1585 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1586 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1587 { DONTCARE, DONTCARE, DONTCARE, "device" }
1590 static size_t device_node_name_table_size =
1591 sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1592 static size_t ia_node_name_table_size =
1593 sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
1594 static size_t if_node_name_table_size =
1595 sizeof (if_node_name_table)/sizeof (struct node_name_entry);
1596 static size_t combined_node_name_table_size =
1597 sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
1600 static void
1601 usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
1602 uint8_t protocol, uint_t flag)
1604 int i;
1605 size_t size;
1606 node_name_entry_t *node_name_table;
1608 switch (flag) {
1609 /* interface share node names with interface-association */
1610 case FLAG_INTERFACE_ASSOCIATION_NODE:
1611 node_name_table = ia_node_name_table;
1612 size = ia_node_name_table_size;
1613 break;
1614 case FLAG_INTERFACE_NODE:
1615 node_name_table = if_node_name_table;
1616 size = if_node_name_table_size;
1617 break;
1618 case FLAG_DEVICE_NODE:
1619 node_name_table = device_node_name_table;
1620 size = device_node_name_table_size;
1621 break;
1622 case FLAG_COMBINED_NODE:
1623 node_name_table = combined_node_name_table;
1624 size = combined_node_name_table_size;
1625 break;
1626 default:
1628 return;
1631 for (i = 0; i < size; i++) {
1632 int16_t c = node_name_table[i].class;
1633 int16_t s = node_name_table[i].subclass;
1634 int16_t p = node_name_table[i].protocol;
1636 if (((c == DONTCARE) || (c == class)) &&
1637 ((s == DONTCARE) || (s == subclass)) &&
1638 ((p == DONTCARE) || (p == protocol))) {
1639 char *name = node_name_table[i].name;
1641 (void) ndi_devi_set_nodename(dip, name, 0);
1642 break;
1648 #ifdef DEBUG
1650 * walk the children of the parent of this devi and compare the
1651 * name and reg property of each child. If there is a match
1652 * return this node
1654 static dev_info_t *
1655 usba_find_existing_node(dev_info_t *odip)
1657 dev_info_t *ndip, *child, *pdip;
1658 int *odata, *ndata;
1659 uint_t n_odata, n_ndata;
1660 int circular;
1662 pdip = ddi_get_parent(odip);
1663 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1664 odip, DDI_PROP_DONTPASS, "reg",
1665 &odata, &n_odata) != DDI_SUCCESS) {
1666 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1667 "usba_find_existing_node: "
1668 "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
1670 return (NULL);
1673 ndi_devi_enter(pdip, &circular);
1674 ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
1675 while ((child = ndip) != NULL) {
1677 ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
1679 if (child == odip) {
1680 continue;
1683 if (strcmp(DEVI(child)->devi_node_name,
1684 DEVI(odip)->devi_node_name)) {
1685 continue;
1688 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1689 child, DDI_PROP_DONTPASS, "reg",
1690 &ndata, &n_ndata) != DDI_SUCCESS) {
1692 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1693 "usba_find_existing_node: "
1694 "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
1696 } else if (n_ndata && n_odata && (bcmp(odata, ndata,
1697 max(n_odata, n_ndata) * sizeof (int)) == 0)) {
1699 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1700 "usba_find_existing_node: found %s%d (%p)",
1701 ddi_driver_name(child),
1702 ddi_get_instance(child), (void *)child);
1704 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1705 "usba_find_existing_node: "
1706 "reg: %x %x %x - %x %x %x",
1707 n_odata, odata[0], odata[1],
1708 n_ndata, ndata[0], ndata[1]);
1710 ddi_prop_free(ndata);
1711 break;
1713 } else {
1714 ddi_prop_free(ndata);
1718 ndi_devi_exit(pdip, circular);
1720 ddi_prop_free(odata);
1722 return (child);
1724 #endif
1726 /* change all unprintable characters to spaces */
1727 static void
1728 usba_filter_string(char *instr, char *outstr)
1730 while (*instr) {
1731 if ((*instr >= ' ') && (*instr <= '~')) {
1732 *outstr = *instr;
1733 } else {
1734 *outstr = ' ';
1736 outstr++;
1737 instr++;
1739 *outstr = '\0';
1744 * lookup ugen binding specified in property in
1745 * hcd.conf files
1748 usba_get_ugen_binding(dev_info_t *dip)
1750 usba_device_t *usba_device = usba_get_usba_device(dip);
1751 usba_hcdi_t *hcdi =
1752 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
1754 return (hcdi->hcdi_ugen_default_binding);
1759 * driver binding support at device level
1761 dev_info_t *
1762 usba_ready_device_node(dev_info_t *child_dip)
1764 int rval, i;
1765 int n = 0;
1766 usba_device_t *usba_device = usba_get_usba_device(child_dip);
1767 usb_dev_descr_t *usb_dev_descr;
1768 uint_t n_cfgs; /* number of configs */
1769 uint_t n_ifs; /* number of interfaces */
1770 uint_t port, bus_num;
1771 size_t usb_config_length;
1772 uchar_t *usb_config;
1773 int reg[1];
1774 usb_addr_t address = usb_get_addr(child_dip);
1775 usb_if_descr_t if_descr;
1776 size_t size;
1777 int combined_node = 0;
1778 int is_hub;
1779 char *devprop_str;
1780 char *force_bind = NULL;
1781 char *usba_name_buf = NULL;
1782 char *usba_name[USBA_MAX_COMPAT_NAMES];
1784 usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
1786 mutex_enter(&usba_device->usb_mutex);
1787 mutex_enter(&usba_mutex);
1789 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1790 "usba_ready_device_node: child=0x%p", (void *)child_dip);
1792 port = usba_device->usb_port;
1793 usb_dev_descr = usba_device->usb_dev_descr;
1794 n_cfgs = usba_device->usb_n_cfgs;
1795 n_ifs = usba_device->usb_n_ifs;
1796 bus_num = usba_device->usb_addr;
1798 if (address != ROOT_HUB_ADDR) {
1799 size = usb_parse_if_descr(
1800 usb_config,
1801 usb_config_length,
1802 0, /* interface index */
1803 0, /* alt interface index */
1804 &if_descr,
1805 USB_IF_DESCR_SIZE);
1807 if (size != USB_IF_DESCR_SIZE) {
1808 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1809 "parsing interface: "
1810 "size (%lu) != USB_IF_DESCR_SIZE (%d)",
1811 size, USB_IF_DESCR_SIZE);
1813 mutex_exit(&usba_mutex);
1814 mutex_exit(&usba_device->usb_mutex);
1816 return (child_dip);
1818 } else {
1819 /* fake an interface descriptor for the root hub */
1820 bzero(&if_descr, sizeof (if_descr));
1822 if_descr.bInterfaceClass = USB_CLASS_HUB;
1825 reg[0] = port;
1827 mutex_exit(&usba_mutex);
1828 mutex_exit(&usba_device->usb_mutex);
1830 rval = ndi_prop_update_int_array(
1831 DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
1833 if (rval != DDI_PROP_SUCCESS) {
1834 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1835 "usba_ready_device_node: property update failed");
1837 return (child_dip);
1840 combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
1841 ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
1842 (usb_dev_descr->bDeviceClass == 0)));
1844 is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
1845 (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
1847 /* set node name */
1848 if (combined_node) {
1849 usba_set_node_name(child_dip,
1850 if_descr.bInterfaceClass,
1851 if_descr.bInterfaceSubClass,
1852 if_descr.bInterfaceProtocol,
1853 FLAG_COMBINED_NODE);
1854 } else {
1855 usba_set_node_name(child_dip,
1856 usb_dev_descr->bDeviceClass,
1857 usb_dev_descr->bDeviceSubClass,
1858 usb_dev_descr->bDeviceProtocol,
1859 FLAG_DEVICE_NODE);
1863 * check force binding rules
1865 if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
1866 (address != usba_ddivs_usbc_xaddress) &&
1867 (!(usba_ddivs_usbc_xhubs && is_hub))) {
1868 force_bind = "ddivs_usbc";
1869 (void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
1871 } else if (usba_device->usb_preferred_driver) {
1872 force_bind = usba_device->usb_preferred_driver;
1874 } else if ((address != ROOT_HUB_ADDR) &&
1875 ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
1876 ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
1877 combined_node)) && (!is_hub)) {
1878 force_bind = "ugen";
1881 #ifdef DEBUG
1883 * check whether there is another dip with this name and address
1884 * If the dip contains usba_device, it is held by the previous
1885 * round of configuration.
1887 ASSERT(usba_find_existing_node(child_dip) == NULL);
1888 #endif
1890 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
1891 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
1893 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
1894 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
1897 if (force_bind) {
1898 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
1899 (void) strncpy(usba_name[n++], force_bind,
1900 USBA_MAX_COMPAT_NAME_LEN);
1904 * If the callback function of specified driver is registered,
1905 * it will be called here to check whether to take over the device.
1907 if (usb_cap.usba_dev_driver_cb != NULL) {
1908 char *dev_drv = NULL;
1909 usb_dev_str_t dev_str;
1910 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1912 dev_str.usb_mfg = usba_device->usb_mfg_str;
1913 dev_str.usb_product = usba_device->usb_product_str;
1914 dev_str.usb_serialno = usba_device->usb_serialno_str;
1916 (void) ddi_pathname(child_dip, pathname);
1918 if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1919 pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1920 (dev_drv != NULL)) {
1921 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1922 "usba_ready_device_node: dev_driver=%s, port =%d,"
1923 "bus =%d, path=%s\n\t",
1924 dev_drv, port, bus_num, pathname);
1926 (void) strncpy(usba_name[n++], dev_drv,
1927 USBA_MAX_COMPAT_NAME_LEN);
1929 kmem_free(pathname, MAXPATHLEN);
1932 /* create compatible names */
1933 if (combined_node) {
1935 /* 1. usbVID,PID.REV */
1936 (void) sprintf(usba_name[n++],
1937 "usb%x,%x.%x",
1938 usb_dev_descr->idVendor,
1939 usb_dev_descr->idProduct,
1940 usb_dev_descr->bcdDevice);
1942 /* 2. usbVID,PID */
1943 (void) sprintf(usba_name[n++],
1944 "usb%x,%x",
1945 usb_dev_descr->idVendor,
1946 usb_dev_descr->idProduct);
1948 if (usb_dev_descr->bDeviceClass != 0) {
1949 /* 3. usbVID,classDC.DSC.DPROTO */
1950 (void) sprintf(usba_name[n++],
1951 "usb%x,class%x.%x.%x",
1952 usb_dev_descr->idVendor,
1953 usb_dev_descr->bDeviceClass,
1954 usb_dev_descr->bDeviceSubClass,
1955 usb_dev_descr->bDeviceProtocol);
1957 /* 4. usbVID,classDC.DSC */
1958 (void) sprintf(usba_name[n++],
1959 "usb%x,class%x.%x",
1960 usb_dev_descr->idVendor,
1961 usb_dev_descr->bDeviceClass,
1962 usb_dev_descr->bDeviceSubClass);
1964 /* 5. usbVID,classDC */
1965 (void) sprintf(usba_name[n++],
1966 "usb%x,class%x",
1967 usb_dev_descr->idVendor,
1968 usb_dev_descr->bDeviceClass);
1970 /* 6. usb,classDC.DSC.DPROTO */
1971 (void) sprintf(usba_name[n++],
1972 "usb,class%x.%x.%x",
1973 usb_dev_descr->bDeviceClass,
1974 usb_dev_descr->bDeviceSubClass,
1975 usb_dev_descr->bDeviceProtocol);
1977 /* 7. usb,classDC.DSC */
1978 (void) sprintf(usba_name[n++],
1979 "usb,class%x.%x",
1980 usb_dev_descr->bDeviceClass,
1981 usb_dev_descr->bDeviceSubClass);
1983 /* 8. usb,classDC */
1984 (void) sprintf(usba_name[n++],
1985 "usb,class%x",
1986 usb_dev_descr->bDeviceClass);
1989 if (if_descr.bInterfaceClass != 0) {
1990 /* 9. usbifVID,classIC.ISC.IPROTO */
1991 (void) sprintf(usba_name[n++],
1992 "usbif%x,class%x.%x.%x",
1993 usb_dev_descr->idVendor,
1994 if_descr.bInterfaceClass,
1995 if_descr.bInterfaceSubClass,
1996 if_descr.bInterfaceProtocol);
1998 /* 10. usbifVID,classIC.ISC */
1999 (void) sprintf(usba_name[n++],
2000 "usbif%x,class%x.%x",
2001 usb_dev_descr->idVendor,
2002 if_descr.bInterfaceClass,
2003 if_descr.bInterfaceSubClass);
2005 /* 11. usbifVID,classIC */
2006 (void) sprintf(usba_name[n++],
2007 "usbif%x,class%x",
2008 usb_dev_descr->idVendor,
2009 if_descr.bInterfaceClass);
2011 /* 12. usbif,classIC.ISC.IPROTO */
2012 (void) sprintf(usba_name[n++],
2013 "usbif,class%x.%x.%x",
2014 if_descr.bInterfaceClass,
2015 if_descr.bInterfaceSubClass,
2016 if_descr.bInterfaceProtocol);
2018 /* 13. usbif,classIC.ISC */
2019 (void) sprintf(usba_name[n++],
2020 "usbif,class%x.%x",
2021 if_descr.bInterfaceClass,
2022 if_descr.bInterfaceSubClass);
2024 /* 14. usbif,classIC */
2025 (void) sprintf(usba_name[n++],
2026 "usbif,class%x",
2027 if_descr.bInterfaceClass);
2030 /* 15. ugen or usb_mid */
2031 if (usba_get_ugen_binding(child_dip) ==
2032 USBA_UGEN_DEVICE_BINDING) {
2033 (void) sprintf(usba_name[n++], "ugen");
2034 } else {
2035 (void) sprintf(usba_name[n++], "usb,device");
2038 } else {
2039 if (n_cfgs > 1) {
2040 /* 1. usbVID,PID.REV.configCN */
2041 (void) sprintf(usba_name[n++],
2042 "usb%x,%x.%x.config%x",
2043 usb_dev_descr->idVendor,
2044 usb_dev_descr->idProduct,
2045 usb_dev_descr->bcdDevice,
2046 usba_device->usb_cfg_value);
2049 /* 2. usbVID,PID.REV */
2050 (void) sprintf(usba_name[n++],
2051 "usb%x,%x.%x",
2052 usb_dev_descr->idVendor,
2053 usb_dev_descr->idProduct,
2054 usb_dev_descr->bcdDevice);
2056 /* 3. usbVID,PID.configCN */
2057 if (n_cfgs > 1) {
2058 (void) sprintf(usba_name[n++],
2059 "usb%x,%x.%x",
2060 usb_dev_descr->idVendor,
2061 usb_dev_descr->idProduct,
2062 usba_device->usb_cfg_value);
2065 /* 4. usbVID,PID */
2066 (void) sprintf(usba_name[n++],
2067 "usb%x,%x",
2068 usb_dev_descr->idVendor,
2069 usb_dev_descr->idProduct);
2071 if (usb_dev_descr->bDeviceClass != 0) {
2072 /* 5. usbVID,classDC.DSC.DPROTO */
2073 (void) sprintf(usba_name[n++],
2074 "usb%x,class%x.%x.%x",
2075 usb_dev_descr->idVendor,
2076 usb_dev_descr->bDeviceClass,
2077 usb_dev_descr->bDeviceSubClass,
2078 usb_dev_descr->bDeviceProtocol);
2080 /* 6. usbVID,classDC.DSC */
2081 (void) sprintf(usba_name[n++],
2082 "usb%x.class%x.%x",
2083 usb_dev_descr->idVendor,
2084 usb_dev_descr->bDeviceClass,
2085 usb_dev_descr->bDeviceSubClass);
2087 /* 7. usbVID,classDC */
2088 (void) sprintf(usba_name[n++],
2089 "usb%x.class%x",
2090 usb_dev_descr->idVendor,
2091 usb_dev_descr->bDeviceClass);
2093 /* 8. usb,classDC.DSC.DPROTO */
2094 (void) sprintf(usba_name[n++],
2095 "usb,class%x.%x.%x",
2096 usb_dev_descr->bDeviceClass,
2097 usb_dev_descr->bDeviceSubClass,
2098 usb_dev_descr->bDeviceProtocol);
2100 /* 9. usb,classDC.DSC */
2101 (void) sprintf(usba_name[n++],
2102 "usb,class%x.%x",
2103 usb_dev_descr->bDeviceClass,
2104 usb_dev_descr->bDeviceSubClass);
2106 /* 10. usb,classDC */
2107 (void) sprintf(usba_name[n++],
2108 "usb,class%x",
2109 usb_dev_descr->bDeviceClass);
2112 if (usba_get_ugen_binding(child_dip) ==
2113 USBA_UGEN_DEVICE_BINDING) {
2114 /* 11. ugen */
2115 (void) sprintf(usba_name[n++], "ugen");
2116 } else {
2117 /* 11. usb,device */
2118 (void) sprintf(usba_name[n++], "usb,device");
2122 for (i = 0; i < n; i += 2) {
2123 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2124 "compatible name:\t%s\t%s", usba_name[i],
2125 (((i+1) < n)? usba_name[i+1] : ""));
2128 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2129 "compatible", (char **)usba_name, n);
2131 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2132 USBA_MAX_COMPAT_NAME_LEN);
2134 if (rval != DDI_PROP_SUCCESS) {
2136 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2137 "usba_ready_device_node: property update failed");
2139 return (child_dip);
2142 /* update the address property */
2143 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2144 "assigned-address", usba_device->usb_addr);
2145 if (rval != DDI_PROP_SUCCESS) {
2146 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2147 "usba_ready_device_node: address update failed");
2150 /* update the usb device properties (PSARC/2000/454) */
2151 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2152 "usb-vendor-id", usb_dev_descr->idVendor);
2153 if (rval != DDI_PROP_SUCCESS) {
2154 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2155 "usba_ready_device_node: usb-vendor-id update failed");
2158 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2159 "usb-product-id", usb_dev_descr->idProduct);
2160 if (rval != DDI_PROP_SUCCESS) {
2161 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2162 "usba_ready_device_node: usb-product-id update failed");
2165 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2166 "usb-revision-id", usb_dev_descr->bcdDevice);
2167 if (rval != DDI_PROP_SUCCESS) {
2168 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2169 "usba_ready_device_node: usb-revision-id update failed");
2172 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2173 "usb-num-configs", usb_dev_descr->bNumConfigurations);
2174 if (rval != DDI_PROP_SUCCESS) {
2175 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2176 "usba_ready_device_node: usb-num-configs update failed");
2179 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2180 "usb-release", usb_dev_descr->bcdUSB);
2181 if (rval != DDI_PROP_SUCCESS) {
2182 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2183 "usba_ready_device_node: usb-release update failed");
2186 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2187 "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
2188 sizeof (usb_dev_descr_t));
2189 if (rval != DDI_PROP_SUCCESS) {
2190 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2191 "usba_ready_device_node: usb-descriptor update failed");
2194 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2195 "usb-raw-cfg-descriptors", usb_config, usb_config_length);
2196 if (rval != DDI_PROP_SUCCESS) {
2197 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2198 "usba_ready_device_node: usb-raw-cfg-descriptors update "
2199 "failed");
2202 devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2204 if (usba_device->usb_serialno_str) {
2205 usba_filter_string(usba_device->usb_serialno_str, devprop_str);
2206 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2207 "usb-serialno", devprop_str);
2208 if (rval != DDI_PROP_SUCCESS) {
2209 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2210 "usba_ready_device_node: "
2211 "usb-serialno update failed");
2215 if (usba_device->usb_mfg_str) {
2216 usba_filter_string(usba_device->usb_mfg_str, devprop_str);
2217 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2218 "usb-vendor-name", devprop_str);
2219 if (rval != DDI_PROP_SUCCESS) {
2220 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2221 "usba_ready_device_node: "
2222 "usb-vendor-name update failed");
2226 if (usba_device->usb_product_str) {
2227 usba_filter_string(usba_device->usb_product_str, devprop_str);
2228 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2229 "usb-product-name", devprop_str);
2230 if (rval != DDI_PROP_SUCCESS) {
2231 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2232 "usba_ready_device_node: "
2233 "usb-product-name update failed");
2237 kmem_free(devprop_str, USB_MAXSTRINGLEN);
2239 if (!combined_node) {
2240 /* update the configuration property */
2241 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2242 "configuration#", usba_device->usb_cfg_value);
2243 if (rval != DDI_PROP_SUCCESS) {
2244 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2245 "usba_ready_device_node: "
2246 "config prop update failed");
2250 if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
2251 /* create boolean property */
2252 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2253 "low-speed");
2254 if (rval != DDI_PROP_SUCCESS) {
2255 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2256 "usba_ready_device_node: "
2257 "low speed prop update failed");
2261 if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
2262 /* create boolean property */
2263 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2264 "high-speed");
2265 if (rval != DDI_PROP_SUCCESS) {
2266 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2267 "usba_ready_device_node: "
2268 "high speed prop update failed");
2272 if (usba_device->usb_port_status == USBA_SUPER_SPEED_DEV) {
2273 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2274 "super-speed");
2275 if (rval != DDI_PROP_SUCCESS) {
2276 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2277 "usba_ready_device_node: "
2278 "super speed prop update failed");
2282 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2283 "%s%d at port %d: %s, dip=0x%p",
2284 ddi_node_name(ddi_get_parent(child_dip)),
2285 ddi_get_instance(ddi_get_parent(child_dip)),
2286 port, ddi_node_name(child_dip), (void *)child_dip);
2288 usba_set_usba_device(child_dip, usba_device);
2290 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2292 return (child_dip);
2297 * driver binding at interface association level. the first arg is the parent
2298 * dip. if_count returns amount of interfaces which are associated within
2299 * this interface-association that starts from first_if.
2301 /*ARGSUSED*/
2302 dev_info_t *
2303 usba_ready_interface_association_node(dev_info_t *dip,
2304 uint_t first_if,
2305 uint_t *if_count)
2307 dev_info_t *child_dip = NULL;
2308 usba_device_t *child_ud = usba_get_usba_device(dip);
2309 usb_dev_descr_t *usb_dev_descr;
2310 size_t usb_cfg_length;
2311 uchar_t *usb_cfg;
2312 usb_ia_descr_t ia_descr;
2313 int i, n, rval;
2314 int reg[2];
2315 size_t size;
2316 usb_port_status_t port_status;
2317 char *force_bind = NULL;
2318 char *usba_name_buf = NULL;
2319 char *usba_name[USBA_MAX_COMPAT_NAMES];
2321 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2323 mutex_enter(&child_ud->usb_mutex);
2325 usb_dev_descr = child_ud->usb_dev_descr;
2328 * for each interface association, determine all compatible names
2330 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2331 "usba_ready_ia_node: "
2332 "port %d, interface = %d, port_status = %x",
2333 child_ud->usb_port, first_if, child_ud->usb_port_status);
2335 /* Parse the interface descriptor */
2336 size = usb_parse_ia_descr(
2337 usb_cfg,
2338 usb_cfg_length,
2339 first_if, /* interface index */
2340 &ia_descr,
2341 USB_IA_DESCR_SIZE);
2343 *if_count = 1;
2344 if (size != USB_IA_DESCR_SIZE) {
2345 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2346 "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2347 size, USB_IA_DESCR_SIZE);
2348 mutex_exit(&child_ud->usb_mutex);
2350 return (NULL);
2353 port_status = child_ud->usb_port_status;
2355 /* create reg property */
2356 reg[0] = first_if;
2357 reg[1] = child_ud->usb_cfg_value;
2359 mutex_exit(&child_ud->usb_mutex);
2361 /* clone this dip */
2362 rval = usba_create_child_devi(dip,
2363 "interface-association",
2364 NULL, /* usba_hcdi ops */
2365 NULL, /* root hub dip */
2366 port_status, /* port status */
2367 child_ud, /* share this usba_device */
2368 &child_dip);
2370 if (rval != USB_SUCCESS) {
2372 goto fail;
2375 rval = ndi_prop_update_int_array(
2376 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2378 if (rval != DDI_PROP_SUCCESS) {
2380 goto fail;
2383 usba_set_node_name(child_dip, ia_descr.bFunctionClass,
2384 ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
2385 FLAG_INTERFACE_ASSOCIATION_NODE);
2387 /* check force binding */
2388 if (usba_ugen_force_binding ==
2389 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2390 force_bind = "ugen";
2394 * check whether there is another dip with this name and address
2396 ASSERT(usba_find_existing_node(child_dip) == NULL);
2398 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2399 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2401 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2402 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2405 n = 0;
2407 if (force_bind) {
2408 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2409 (void) strncpy(usba_name[n++], force_bind,
2410 USBA_MAX_COMPAT_NAME_LEN);
2413 /* 1) usbiaVID,PID.REV.configCN.FN */
2414 (void) sprintf(usba_name[n++],
2415 "usbia%x,%x.%x.config%x.%x",
2416 usb_dev_descr->idVendor,
2417 usb_dev_descr->idProduct,
2418 usb_dev_descr->bcdDevice,
2419 child_ud->usb_cfg_value,
2420 first_if);
2422 /* 2) usbiaVID,PID.configCN.FN */
2423 (void) sprintf(usba_name[n++],
2424 "usbia%x,%x.config%x.%x",
2425 usb_dev_descr->idVendor,
2426 usb_dev_descr->idProduct,
2427 child_ud->usb_cfg_value,
2428 first_if);
2431 if (ia_descr.bFunctionClass) {
2432 /* 3) usbiaVID,classFC.FSC.FPROTO */
2433 (void) sprintf(usba_name[n++],
2434 "usbia%x,class%x.%x.%x",
2435 usb_dev_descr->idVendor,
2436 ia_descr.bFunctionClass,
2437 ia_descr.bFunctionSubClass,
2438 ia_descr.bFunctionProtocol);
2440 /* 4) usbiaVID,classFC.FSC */
2441 (void) sprintf(usba_name[n++],
2442 "usbia%x,class%x.%x",
2443 usb_dev_descr->idVendor,
2444 ia_descr.bFunctionClass,
2445 ia_descr.bFunctionSubClass);
2447 /* 5) usbiaVID,classFC */
2448 (void) sprintf(usba_name[n++],
2449 "usbia%x,class%x",
2450 usb_dev_descr->idVendor,
2451 ia_descr.bFunctionClass);
2453 /* 6) usbia,classFC.FSC.FPROTO */
2454 (void) sprintf(usba_name[n++],
2455 "usbia,class%x.%x.%x",
2456 ia_descr.bFunctionClass,
2457 ia_descr.bFunctionSubClass,
2458 ia_descr.bFunctionProtocol);
2460 /* 7) usbia,classFC.FSC */
2461 (void) sprintf(usba_name[n++],
2462 "usbia,class%x.%x",
2463 ia_descr.bFunctionClass,
2464 ia_descr.bFunctionSubClass);
2466 /* 8) usbia,classFC */
2467 (void) sprintf(usba_name[n++],
2468 "usbia,class%x",
2469 ia_descr.bFunctionClass);
2472 if (usba_get_ugen_binding(child_dip) ==
2473 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2474 /* 9) ugen */
2475 (void) sprintf(usba_name[n++], "ugen");
2476 } else {
2478 (void) sprintf(usba_name[n++], "usb,ia");
2481 for (i = 0; i < n; i += 2) {
2482 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2483 "compatible name:\t%s\t%s", usba_name[i],
2484 (((i+1) < n)? usba_name[i+1] : ""));
2487 /* create compatible property */
2488 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2489 "compatible", (char **)usba_name, n);
2491 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2492 USBA_MAX_COMPAT_NAME_LEN);
2494 if (rval != DDI_PROP_SUCCESS) {
2496 goto fail;
2499 /* update the address property */
2500 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2501 "assigned-address", child_ud->usb_addr);
2502 if (rval != DDI_PROP_SUCCESS) {
2503 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2504 "usba_ready_interface_node: address update failed");
2507 /* create property with first interface number */
2508 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2509 "interface", ia_descr.bFirstInterface);
2511 if (rval != DDI_PROP_SUCCESS) {
2513 goto fail;
2516 /* create property with the count of interfaces in this ia */
2517 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2518 "interface-count", ia_descr.bInterfaceCount);
2520 if (rval != DDI_PROP_SUCCESS) {
2522 goto fail;
2525 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2526 "%s%d port %d: %s, dip = 0x%p",
2527 ddi_node_name(ddi_get_parent(dip)),
2528 ddi_get_instance(ddi_get_parent(dip)),
2529 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2531 *if_count = ia_descr.bInterfaceCount;
2532 usba_set_usba_device(child_dip, child_ud);
2533 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2535 return (child_dip);
2537 fail:
2538 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2540 return (NULL);
2545 * driver binding at interface level, the first arg will be the
2546 * the parent dip
2548 /*ARGSUSED*/
2549 dev_info_t *
2550 usba_ready_interface_node(dev_info_t *dip, uint_t intf)
2552 dev_info_t *child_dip = NULL;
2553 usba_device_t *child_ud = usba_get_usba_device(dip);
2554 usb_dev_descr_t *usb_dev_descr;
2555 size_t usb_cfg_length;
2556 uchar_t *usb_cfg;
2557 usb_if_descr_t if_descr;
2558 int i, n, rval;
2559 int reg[2];
2560 size_t size;
2561 usb_port_status_t port_status;
2562 char *force_bind = NULL;
2563 char *usba_name_buf = NULL;
2564 char *usba_name[USBA_MAX_COMPAT_NAMES];
2566 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2568 mutex_enter(&child_ud->usb_mutex);
2570 usb_dev_descr = child_ud->usb_dev_descr;
2573 * for each interface, determine all compatible names
2575 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2576 "usba_ready_interface_node: "
2577 "port %d, interface = %d port status = %x",
2578 child_ud->usb_port, intf, child_ud->usb_port_status);
2580 /* Parse the interface descriptor */
2581 size = usb_parse_if_descr(
2582 usb_cfg,
2583 usb_cfg_length,
2584 intf, /* interface index */
2585 0, /* alt interface index */
2586 &if_descr,
2587 USB_IF_DESCR_SIZE);
2589 if (size != USB_IF_DESCR_SIZE) {
2590 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2591 "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
2592 size, USB_IF_DESCR_SIZE);
2593 mutex_exit(&child_ud->usb_mutex);
2595 return (NULL);
2598 port_status = child_ud->usb_port_status;
2600 /* create reg property */
2601 reg[0] = intf;
2602 reg[1] = child_ud->usb_cfg_value;
2604 mutex_exit(&child_ud->usb_mutex);
2606 /* clone this dip */
2607 rval = usba_create_child_devi(dip,
2608 "interface",
2609 NULL, /* usba_hcdi ops */
2610 NULL, /* root hub dip */
2611 port_status, /* port status */
2612 child_ud, /* share this usba_device */
2613 &child_dip);
2615 if (rval != USB_SUCCESS) {
2617 goto fail;
2620 rval = ndi_prop_update_int_array(
2621 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2623 if (rval != DDI_PROP_SUCCESS) {
2625 goto fail;
2628 usba_set_node_name(child_dip, if_descr.bInterfaceClass,
2629 if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
2630 FLAG_INTERFACE_NODE);
2632 /* check force binding */
2633 if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
2634 force_bind = "ugen";
2638 * check whether there is another dip with this name and address
2640 ASSERT(usba_find_existing_node(child_dip) == NULL);
2642 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2643 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2645 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2646 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2649 n = 0;
2651 if (force_bind) {
2652 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2653 (void) strncpy(usba_name[n++], force_bind,
2654 USBA_MAX_COMPAT_NAME_LEN);
2657 /* 1) usbifVID,PID.REV.configCN.IN */
2658 (void) sprintf(usba_name[n++],
2659 "usbif%x,%x.%x.config%x.%x",
2660 usb_dev_descr->idVendor,
2661 usb_dev_descr->idProduct,
2662 usb_dev_descr->bcdDevice,
2663 child_ud->usb_cfg_value,
2664 intf);
2666 /* 2) usbifVID,PID.configCN.IN */
2667 (void) sprintf(usba_name[n++],
2668 "usbif%x,%x.config%x.%x",
2669 usb_dev_descr->idVendor,
2670 usb_dev_descr->idProduct,
2671 child_ud->usb_cfg_value,
2672 intf);
2675 if (if_descr.bInterfaceClass) {
2676 /* 3) usbifVID,classIC.ISC.IPROTO */
2677 (void) sprintf(usba_name[n++],
2678 "usbif%x,class%x.%x.%x",
2679 usb_dev_descr->idVendor,
2680 if_descr.bInterfaceClass,
2681 if_descr.bInterfaceSubClass,
2682 if_descr.bInterfaceProtocol);
2684 /* 4) usbifVID,classIC.ISC */
2685 (void) sprintf(usba_name[n++],
2686 "usbif%x,class%x.%x",
2687 usb_dev_descr->idVendor,
2688 if_descr.bInterfaceClass,
2689 if_descr.bInterfaceSubClass);
2691 /* 5) usbifVID,classIC */
2692 (void) sprintf(usba_name[n++],
2693 "usbif%x,class%x",
2694 usb_dev_descr->idVendor,
2695 if_descr.bInterfaceClass);
2697 /* 6) usbif,classIC.ISC.IPROTO */
2698 (void) sprintf(usba_name[n++],
2699 "usbif,class%x.%x.%x",
2700 if_descr.bInterfaceClass,
2701 if_descr.bInterfaceSubClass,
2702 if_descr.bInterfaceProtocol);
2704 /* 7) usbif,classIC.ISC */
2705 (void) sprintf(usba_name[n++],
2706 "usbif,class%x.%x",
2707 if_descr.bInterfaceClass,
2708 if_descr.bInterfaceSubClass);
2710 /* 8) usbif,classIC */
2711 (void) sprintf(usba_name[n++],
2712 "usbif,class%x",
2713 if_descr.bInterfaceClass);
2716 if (usba_get_ugen_binding(child_dip) ==
2717 USBA_UGEN_INTERFACE_BINDING) {
2718 /* 9) ugen */
2719 (void) sprintf(usba_name[n++], "ugen");
2722 for (i = 0; i < n; i += 2) {
2723 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2724 "compatible name:\t%s\t%s", usba_name[i],
2725 (((i+1) < n)? usba_name[i+1] : ""));
2728 /* create compatible property */
2729 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2730 "compatible", (char **)usba_name, n);
2732 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2733 USBA_MAX_COMPAT_NAME_LEN);
2735 if (rval != DDI_PROP_SUCCESS) {
2737 goto fail;
2740 /* update the address property */
2741 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2742 "assigned-address", child_ud->usb_addr);
2743 if (rval != DDI_PROP_SUCCESS) {
2744 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2745 "usba_ready_interface_node: address update failed");
2748 /* create property with if number */
2749 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2750 "interface", intf);
2752 if (rval != DDI_PROP_SUCCESS) {
2754 goto fail;
2757 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2758 "%s%d port %d: %s, dip = 0x%p",
2759 ddi_node_name(ddi_get_parent(dip)),
2760 ddi_get_instance(ddi_get_parent(dip)),
2761 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2763 usba_set_usba_device(child_dip, child_ud);
2764 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2766 return (child_dip);
2768 fail:
2769 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2771 return (NULL);
2776 * retrieve string descriptors for manufacturer, vendor and serial
2777 * number
2779 void
2780 usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
2782 char *tmpbuf, *str;
2783 int l;
2784 usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
2787 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2788 "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
2789 usb_dev_descr->iManufacturer,
2790 usb_dev_descr->iProduct,
2791 usb_dev_descr->iSerialNumber);
2793 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2795 /* fetch manufacturer string */
2796 if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
2797 (usb_get_string_descr(dip, USB_LANG_ID,
2798 usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
2799 USB_SUCCESS)) {
2801 l = strlen(tmpbuf);
2802 if (l > 0) {
2803 str = kmem_zalloc(l + 1, KM_SLEEP);
2804 mutex_enter(&ud->usb_mutex);
2805 ud->usb_mfg_str = str;
2806 (void) strcpy(ud->usb_mfg_str, tmpbuf);
2807 mutex_exit(&ud->usb_mutex);
2811 /* fetch product string */
2812 if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
2813 (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
2814 tmpbuf, USB_MAXSTRINGLEN) ==
2815 USB_SUCCESS)) {
2817 l = strlen(tmpbuf);
2818 if (l > 0) {
2819 str = kmem_zalloc(l + 1, KM_SLEEP);
2820 mutex_enter(&ud->usb_mutex);
2821 ud->usb_product_str = str;
2822 (void) strcpy(ud->usb_product_str, tmpbuf);
2823 mutex_exit(&ud->usb_mutex);
2827 /* fetch device serial number string */
2828 if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
2829 (usb_get_string_descr(dip, USB_LANG_ID,
2830 usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
2831 USB_SUCCESS)) {
2833 l = strlen(tmpbuf);
2834 if (l > 0) {
2835 str = kmem_zalloc(l + 1, KM_SLEEP);
2836 mutex_enter(&ud->usb_mutex);
2837 ud->usb_serialno_str = str;
2838 (void) strcpy(ud->usb_serialno_str, tmpbuf);
2839 mutex_exit(&ud->usb_mutex);
2843 kmem_free(tmpbuf, USB_MAXSTRINGLEN);
2848 * usba_get_mfg_prod_sn_str:
2849 * Return a string containing mfg, product, serial number strings.
2850 * Remove duplicates if some strings are the same.
2852 * Arguments:
2853 * dip - pointer to dev info
2854 * buffer - Where string is returned
2855 * buflen - Length of buffer
2857 * Returns:
2858 * Same as second arg.
2860 char *
2861 usba_get_mfg_prod_sn_str(
2862 dev_info_t *dip,
2863 char *buffer,
2864 int buflen)
2866 usba_device_t *usba_device = usba_get_usba_device(dip);
2867 int return_len = 0;
2868 int len = 0;
2870 buffer[0] = '\0';
2871 buffer[buflen-1] = '\0';
2873 /* Manufacturer string exists. */
2874 if ((usba_device->usb_mfg_str) &&
2875 ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
2876 (void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
2877 return_len = min(buflen - 1, len);
2880 /* Product string exists to append. */
2881 if ((usba_device->usb_product_str) &&
2882 ((len = strlen(usba_device->usb_product_str)) != 0)) {
2883 if (return_len > 0) {
2884 buffer[return_len++] = ' ';
2886 (void) strncpy(&buffer[return_len],
2887 usba_device->usb_product_str, buflen - return_len - 1);
2888 return_len = min(buflen - 1, return_len + len);
2891 /* Serial number string exists to append. */
2892 if ((usba_device->usb_serialno_str) &&
2893 ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
2894 if (return_len > 0) {
2895 buffer[return_len++] = ' ';
2897 (void) strncpy(&buffer[return_len],
2898 usba_device->usb_serialno_str,
2899 buflen - return_len - 1);
2902 return (buffer);
2907 * USB enumeration statistic functions
2911 * Increments the hotplug statistics based on flags.
2913 void
2914 usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
2916 usba_device_t *usba_device = usba_get_usba_device(dip);
2917 usba_hcdi_t *hcdi =
2918 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2920 mutex_enter(&hcdi->hcdi_mutex);
2921 if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
2922 hcdi->hcdi_total_hotplug_success++;
2923 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2924 hcdi_hotplug_total_success.value.ui64++;
2926 if (flags & USBA_HOTPLUG_SUCCESS) {
2927 hcdi->hcdi_hotplug_success++;
2928 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2929 hcdi_hotplug_success.value.ui64++;
2931 if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
2932 hcdi->hcdi_total_hotplug_failure++;
2933 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2934 hcdi_hotplug_total_failure.value.ui64++;
2936 if (flags & USBA_HOTPLUG_FAILURE) {
2937 hcdi->hcdi_hotplug_failure++;
2938 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2939 hcdi_hotplug_failure.value.ui64++;
2941 mutex_exit(&hcdi->hcdi_mutex);
2946 * Retrieve the current enumeration statistics
2948 void
2949 usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
2950 ulong_t *success, ulong_t *total_failure, ulong_t *failure,
2951 uchar_t *device_count)
2953 usba_device_t *usba_device = usba_get_usba_device(dip);
2954 usba_hcdi_t *hcdi =
2955 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2957 mutex_enter(&hcdi->hcdi_mutex);
2958 *total_success = hcdi->hcdi_total_hotplug_success;
2959 *success = hcdi->hcdi_hotplug_success;
2960 *total_failure = hcdi->hcdi_total_hotplug_failure;
2961 *failure = hcdi->hcdi_hotplug_failure;
2962 *device_count = hcdi->hcdi_device_count;
2963 mutex_exit(&hcdi->hcdi_mutex);
2968 * Reset the resetable hotplug stats
2970 void
2971 usba_reset_hotplug_stats(dev_info_t *dip)
2973 usba_device_t *usba_device = usba_get_usba_device(dip);
2974 usba_hcdi_t *hcdi =
2975 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2976 hcdi_hotplug_stats_t *hsp;
2978 mutex_enter(&hcdi->hcdi_mutex);
2979 hcdi->hcdi_hotplug_success = 0;
2980 hcdi->hcdi_hotplug_failure = 0;
2982 hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
2983 hsp->hcdi_hotplug_success.value.ui64 = 0;
2984 hsp->hcdi_hotplug_failure.value.ui64 = 0;
2985 mutex_exit(&hcdi->hcdi_mutex);
2990 * usba_bind_driver():
2991 * This function calls ndi_devi_bind_driver() which tries to
2992 * bind a driver to the device. If the driver binding fails
2993 * we get an rval of NDI_UNBOUD and report an error to the
2994 * syslog that the driver failed binding.
2995 * If rval is something other than NDI_UNBOUND we report an
2996 * error to the console.
2998 * This function returns USB_SUCCESS if no errors were
2999 * encountered while binding.
3002 usba_bind_driver(dev_info_t *dip)
3004 int rval;
3005 char *name;
3006 uint8_t if_num = usba_get_ifno(dip);
3008 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3009 "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
3011 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
3013 /* bind device to the driver */
3014 if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
3015 /* if we fail to bind report an error */
3016 (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
3017 if (name[0] != '\0') {
3018 if (!usb_owns_device(dip)) {
3019 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3020 usba_log_handle,
3021 "no driver found for "
3022 "interface %d (nodename: '%s') of %s",
3023 if_num, ddi_node_name(dip), name);
3024 } else {
3025 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3026 usba_log_handle,
3027 "no driver found for device %s", name);
3029 } else {
3030 (void) ddi_pathname(dip, name);
3031 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3032 usba_log_handle,
3033 "no driver found for device %s", name);
3036 kmem_free(name, MAXNAMELEN);
3038 return (USB_FAILURE);
3040 kmem_free(name, MAXNAMELEN);
3042 return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
3047 * usba_get_hc_dma_attr:
3048 * function returning dma attributes of the HCD
3050 * Arguments:
3051 * dip - pointer to devinfo of the client
3053 * Return Values:
3054 * hcdi_dma_attr
3056 ddi_dma_attr_t *
3057 usba_get_hc_dma_attr(dev_info_t *dip)
3059 usba_device_t *usba_device = usba_get_usba_device(dip);
3060 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
3062 return (hcdi->hcdi_dma_attr);
3067 * usba_check_for_leaks:
3068 * check usba_device structure for leaks
3070 * Arguments:
3071 * usba_device - usba_device structure pointer
3073 void
3074 usba_check_for_leaks(usba_device_t *usba_device)
3076 int i, ph_open_cnt, req_wrp_leaks, iface;
3077 int leaks = 0;
3079 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3080 "usba_check_for_leaks: %s%d usba_device=0x%p",
3081 ddi_driver_name(usba_device->usb_dip),
3082 ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
3085 * default pipe is still open
3086 * all other pipes should be closed
3088 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
3089 usba_ph_impl_t *ph_impl =
3090 &usba_device->usb_ph_list[i];
3091 if (ph_impl->usba_ph_data) {
3092 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3093 usba_log_handle,
3094 "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
3095 ddi_driver_name(ph_impl->usba_ph_data->p_dip),
3096 ddi_get_instance(ph_impl->usba_ph_data->p_dip),
3097 (void *)ph_impl,
3098 (void *)ph_impl->usba_ph_data,
3099 ph_impl->usba_ph_ep.bEndpointAddress);
3100 ph_open_cnt++;
3101 leaks++;
3102 #ifndef DEBUG
3103 usb_pipe_close(ph_impl->usba_ph_data->p_dip,
3104 (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
3105 (void (*)())NULL, NULL);
3106 #endif
3109 req_wrp_leaks = usba_list_entry_leaks(&usba_device->
3110 usb_allocated, "request wrappers");
3112 ASSERT(ph_open_cnt == 0);
3113 ASSERT(req_wrp_leaks == 0);
3115 if (req_wrp_leaks) {
3116 usba_list_entry_t *entry;
3118 while ((entry = usba_rm_first_from_list(
3119 &usba_device->usb_allocated)) != NULL) {
3120 usba_req_wrapper_t *wrp;
3122 mutex_enter(&entry->list_mutex);
3123 wrp = (usba_req_wrapper_t *)entry->private;
3124 mutex_exit(&entry->list_mutex);
3125 leaks++;
3127 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3128 usba_log_handle,
3129 "%s%d: leaking request 0x%p",
3130 ddi_driver_name(wrp->wr_dip),
3131 ddi_get_instance(wrp->wr_dip),
3132 (void *)wrp->wr_req);
3135 * put it back, usba_req_wrapper_free
3136 * expects it on the list
3138 usba_add_to_list(&usba_device->usb_allocated,
3139 &wrp->wr_allocated_list);
3141 usba_req_wrapper_free(wrp);
3145 mutex_enter(&usba_device->usb_mutex);
3146 for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
3147 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
3148 "usba_check_for_leaks: if=%d client_flags=0x%x",
3149 iface, usba_device->usb_client_flags[iface]);
3151 if (usba_device->usb_client_flags[iface] &
3152 USBA_CLIENT_FLAG_DEV_DATA) {
3153 usb_client_dev_data_list_t *entry =
3154 usba_device->usb_client_dev_data_list.cddl_next;
3155 usb_client_dev_data_list_t *next;
3156 usb_client_dev_data_t *dev_data;
3158 while (entry) {
3159 dev_info_t *dip = entry->cddl_dip;
3160 next = entry->cddl_next;
3161 dev_data = entry->cddl_dev_data;
3164 if (!i_ddi_devi_attached(dip)) {
3165 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3166 usba_log_handle,
3167 "%s%d: leaking dev_data 0x%p",
3168 ddi_driver_name(dip),
3169 ddi_get_instance(dip),
3170 (void *)dev_data);
3172 leaks++;
3174 mutex_exit(&usba_device->usb_mutex);
3175 usb_free_dev_data(dip, dev_data);
3176 mutex_enter(&usba_device->usb_mutex);
3179 entry = next;
3182 if (usba_device->usb_client_flags[iface] &
3183 USBA_CLIENT_FLAG_ATTACH) {
3184 dev_info_t *dip = usba_device->
3185 usb_client_attach_list[iface].dip;
3187 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3188 usba_log_handle,
3189 "%s%d: did no usb_client_detach",
3190 ddi_driver_name(dip), ddi_get_instance(dip));
3191 leaks++;
3193 mutex_exit(&usba_device->usb_mutex);
3194 usb_client_detach(dip, NULL);
3195 mutex_enter(&usba_device->usb_mutex);
3197 usba_device->
3198 usb_client_attach_list[iface].dip = NULL;
3200 usba_device->usb_client_flags[iface] &=
3201 ~USBA_CLIENT_FLAG_ATTACH;
3204 if (usba_device->usb_client_flags[iface] &
3205 USBA_CLIENT_FLAG_EV_CBS) {
3206 dev_info_t *dip =
3207 usba_device->usb_client_ev_cb_list[iface].
3208 dip;
3209 usb_event_t *ev_data =
3210 usba_device->usb_client_ev_cb_list[iface].
3211 ev_data;
3213 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3214 usba_log_handle,
3215 "%s%d: did no usb_unregister_event_cbs",
3216 ddi_driver_name(dip), ddi_get_instance(dip));
3217 leaks++;
3219 mutex_exit(&usba_device->usb_mutex);
3220 usb_unregister_event_cbs(dip, ev_data);
3221 mutex_enter(&usba_device->usb_mutex);
3223 usba_device->usb_client_ev_cb_list[iface].
3224 dip = NULL;
3225 usba_device->usb_client_ev_cb_list[iface].
3226 ev_data = NULL;
3227 usba_device->usb_client_flags[iface] &=
3228 ~USBA_CLIENT_FLAG_EV_CBS;
3231 mutex_exit(&usba_device->usb_mutex);
3233 if (leaks) {
3234 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
3235 "all %d leaks fixed", leaks);