1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26 * Copyright 2016 James S. Blachly, MD <james.blachly@gmail.com>
27 */
28
29
30 /*
31 * USBA: Solaris USB Architecture support
32 */
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>
38
39 /*
40 * USBA private variables and tunables
41 */
42 static kmutex_t usba_mutex;
43
44 /* mutex to protect usba_root_hubs */
45 static kmutex_t usba_hub_mutex;
46
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;
51
52 static usba_root_hub_ent_t *usba_root_hubs = NULL;
53
54 /*
55 * ddivs forced binding:
56 *
57 * usbc usbc_xhubs usbc_xaddress node name
58 *
59 * 0 x x class name or "device"
60 *
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
67 */
68 uint_t usba_ddivs_usbc;
69 uint_t usba_ddivs_usbc_xhubs;
70 uint_t usba_ddivs_usbc_xaddress;
71
72 uint_t usba_ugen_force_binding;
73
74 /*
75 * compatible name handling
76 */
77 /*
78 * allowing for 15 compat names, plus one force bind name and
79 * one possible specified client driver name
80 */
81 #define USBA_MAX_COMPAT_NAMES 17
82 #define USBA_MAX_COMPAT_NAME_LEN 64
83
84 /* double linked list for usba_devices */
85 usba_list_entry_t usba_device_list;
86
87 _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
88
89 /*
90 * modload support
91 */
92
93 static struct modlmisc modlmisc = {
94 &mod_miscops, /* Type of module */
95 "USBA: USB Architecture 2.0 1.66"
96 };
97
98 static struct modlinkage modlinkage = {
99 MODREV_1, (void *)&modlmisc, NULL
100 };
101
102
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;
106
107 extern usb_log_handle_t hubdi_log_handle;
108
109 int
110 _init(void)
111 {
112 int rval;
113
114 /*
115 * usbai providing log support needs to be init'ed first
116 * and destroyed last
117 */
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();
124
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();
132 }
133
134 return (rval);
135 }
136
137 int
138 _fini()
139 {
140 int rval;
141
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();
149 }
150
151 return (rval);
152 }
153
154 int
155 _info(struct modinfo *modinfop)
156 {
157 return (mod_info(&modlinkage, modinfop));
158 }
159
160 boolean_t
161 usba_owns_ia(dev_info_t *dip)
162 {
163 int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
164 "interface-count", 0);
165
166 return ((if_count) ? B_TRUE : B_FALSE);
167 }
168
169 /*
170 * common bus ctl for hcd, usb_mid, and hubd
171 */
172 int
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)
178 {
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;
183
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);
188
189 switch (op) {
190
191 case DDI_CTLOPS_REPORTDEV:
192 {
193 char *name, compat_name[64], *speed;
194 usba_device_t *hub_usba_device;
195 dev_info_t *hubdip;
196
197 usba_device = usba_get_usba_device(rdip);
198
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);
204 }
205
206 hub_usba_device = usba_get_usba_device(hubdip);
207
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));
231 }
232 switch (usba_device->usb_port_status) {
233 case USBA_HIGH_SPEED_DEV:
234 speed = "hi speed (USB 2.x)";
235
236 break;
237 case USBA_LOW_SPEED_DEV:
238 speed = "low speed (USB 1.x)";
239
240 break;
241 case USBA_FULL_SPEED_DEV:
242 default:
243 speed = "full speed (USB 1.x)";
244
245 break;
246 }
247
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);
265
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);
270 }
271 kmem_free(name, MAXNAMELEN);
272
273 } else { /* harden USBA against this case; if it happens */
274
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));
279 }
280
281 return (DDI_SUCCESS);
282 }
283
284 case DDI_CTLOPS_INITCHILD:
285 {
286 int usb_addr;
287 uint_t n;
288 char name[32];
289 int *data;
290 int rval;
291 int len = sizeof (usb_addr);
292
293 usba_hcdi = usba_hcdi_get_hcdi(dip);
294 usba_hcdi_ops = usba_hcdi->hcdi_ops;
295 ASSERT(usba_hcdi_ops != NULL);
296
297 /*
298 * as long as the dip exists, it should have
299 * usba_device structure associated with it
300 */
301 usba_device = usba_get_usba_device(child_dip);
302 if (usba_device == NULL) {
303
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);
307
308 return (DDI_NOT_WELL_FORMED);
309 }
310
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) {
315
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);
322
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);
326
327 return (DDI_NOT_WELL_FORMED);
328 }
329
330 if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
331 DDI_PROP_DONTPASS, "reg",
332 &data, &n)) != DDI_SUCCESS) {
333
334 USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
335 "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
336
337 return (DDI_NOT_WELL_FORMED);
338 }
339
340
341 /*
342 * if the configuration is 1, the unit address is
343 * just the interface number
344 */
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]);
349 }
350
351 USB_DPRINTF_L3(DPRINT_MASK_USBA,
352 hubdi_log_handle, "usba_bus_ctl: name = %s", name);
353
354 ddi_prop_free(data);
355 ddi_set_name_addr(child_dip, name);
356
357 /*
358 * increment the reference count for each child using this
359 * usba_device structure
360 */
361 mutex_enter(&usba_device->usb_mutex);
362 usba_device->usb_ref_count++;
363
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);
367
368 mutex_exit(&usba_device->usb_mutex);
369
370 return (DDI_SUCCESS);
371 }
372
373 case DDI_CTLOPS_UNINITCHILD:
374 {
375 usba_device = usba_get_usba_device(child_dip);
376
377 if (usba_device != NULL) {
378 /*
379 * decrement the reference count for each child
380 * using this usba_device structure
381 */
382 mutex_enter(&usba_device->usb_mutex);
383 usba_device->usb_ref_count--;
384
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);
389
390 mutex_exit(&usba_device->usb_mutex);
391 }
392 ddi_set_name_addr(child_dip, NULL);
393
394 return (DDI_SUCCESS);
395 }
396
397 case DDI_CTLOPS_IOMIN:
398 /* Do nothing */
399 return (DDI_SUCCESS);
400
401 /*
402 * These ops correspond to functions that "shouldn't" be called
403 * by a USB client driver. So we whine when we're called.
404 */
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);
418
419 /*
420 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
421 */
422 default:
423 return (ddi_ctlops(dip, rdip, op, arg, result));
424 }
425 }
426
427
428 /*
429 * initialize and destroy USBA module
430 */
431 void
432 usba_usba_initialization()
433 {
434 usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
435 &usba_errmask, NULL, 0);
436
437 USB_DPRINTF_L4(DPRINT_MASK_USBA,
438 usba_log_handle, "usba_usba_initialization");
439
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);
443 }
444
445
446 void
447 usba_usba_destroy()
448 {
449 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
450
451 mutex_destroy(&usba_hub_mutex);
452 mutex_destroy(&usba_mutex);
453 usba_destroy_list(&usba_device_list);
454
455 usb_free_log_hdl(usba_log_handle);
456 }
457
458
459 /*
460 * usba_set_usb_address:
461 * set usb address in usba_device structure
462 */
463 int
464 usba_set_usb_address(usba_device_t *usba_device)
465 {
466 usb_addr_t address;
467 uchar_t s = 8;
468 usba_hcdi_t *hcdi;
469 char *usb_address_in_use;
470
471 mutex_enter(&usba_device->usb_mutex);
472
473 hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
474
475 mutex_enter(&hcdi->hcdi_mutex);
476 usb_address_in_use = hcdi->hcdi_usb_address_in_use;
477
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;
482 }
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);
487
488 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
489 "usba_set_usb_address: %d", address);
490
491 usba_device->usb_addr = address;
492
493 mutex_exit(&usba_device->usb_mutex);
494
495 return (USB_SUCCESS);
496 }
497
498 usba_device->usb_addr = 0;
499
500 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
501 "no usb address available");
502
503 mutex_exit(&hcdi->hcdi_mutex);
504 mutex_exit(&usba_device->usb_mutex);
505
506 return (USB_FAILURE);
507 }
508
509
510 /*
511 * usba_unset_usb_address:
512 * unset usb_address in usba_device structure
513 */
514 void
515 usba_unset_usb_address(usba_device_t *usba_device)
516 {
517 usb_addr_t address;
518 usba_hcdi_t *hcdi;
519 uchar_t s = 8;
520 char *usb_address_in_use;
521
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);
525
526 if (address > ROOT_HUB_ADDR) {
527 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
528 "usba_unset_usb_address: address=%d", address);
529
530 mutex_enter(&hcdi->hcdi_mutex);
531 usb_address_in_use = hcdi->hcdi_usb_address_in_use;
532
533 ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
534
535 usb_address_in_use[address/s] &= ~(1 << (address % s));
536
537 hcdi->hcdi_device_count--;
538 HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
539
540 mutex_exit(&hcdi->hcdi_mutex);
541
542 usba_device->usb_addr = 0;
543 }
544 mutex_exit(&usba_device->usb_mutex);
545 }
546
547
548 struct usba_evdata *
549 usba_get_evdata(dev_info_t *dip)
550 {
551 usba_evdata_t *evdata;
552 usba_device_t *usba_device = usba_get_usba_device(dip);
553
554 /* called when dip attaches */
555 ASSERT(usba_device != NULL);
556
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);
562
563 return (evdata);
564 }
565 evdata = evdata->ev_next;
566 }
567
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);
573
574 return (evdata);
575 }
576
577
578 /*
579 * allocate a usb device structure and link it in the list
580 */
581 usba_device_t *
582 usba_alloc_usba_device(dev_info_t *root_hub_dip)
583 {
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;
588
589 /*
590 * create a new usba_device structure
591 */
592 usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
593
594 /*
595 * initialize usba_device
596 */
597 mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
598 iblock_cookie);
599
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;
606
607 /*
608 * add to list of usba_devices
609 */
610 usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
611
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);
616 }
617
618 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
619 "allocated usba_device 0x%p", (void *)usba_device);
620
621 mutex_exit(&usba_device->usb_mutex);
622
623 return (usba_device);
624 }
625
626
627 /* free NDI event data associated with usba_device */
628 void
629 usba_free_evdata(usba_evdata_t *evdata)
630 {
631 usba_evdata_t *next;
632
633 while (evdata) {
634 next = evdata->ev_next;
635 kmem_free(evdata, sizeof (usba_evdata_t));
636 evdata = next;
637 }
638 }
639
640
641 /*
642 * free usb device structure
643 */
644 void
645 usba_free_usba_device(usba_device_t *usba_device)
646 {
647 int i, ep_idx;
648 usb_pipe_handle_t def_ph;
649
650 if (usba_device == NULL) {
651
652 return;
653 }
654
655 mutex_enter(&usba_device->usb_mutex);
656 if (usba_device->usb_ref_count) {
657 mutex_exit(&usba_device->usb_mutex);
658
659 return;
660 }
661
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);
666
667 usba_free_evdata(usba_device->usb_evdata);
668 mutex_exit(&usba_device->usb_mutex);
669
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);
673
674 if (ph_data) {
675 usb_pipe_close(ph_data->p_dip, def_ph,
676 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
677 NULL, NULL);
678 }
679 }
680
681 mutex_enter(&usba_mutex);
682
683 /* destroy mutex in each usba_ph_impl structure */
684 for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
685 mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
686 }
687
688 (void) usba_rm_from_list(&usba_device_list,
689 &usba_device->usb_device_list);
690
691 mutex_exit(&usba_mutex);
692
693 usba_destroy_list(&usba_device->usb_device_list);
694 usba_destroy_list(&usba_device->usb_allocated);
695
696 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
697 "deallocating usba_device = 0x%p, address = 0x%x",
698 (void *)usba_device, usba_device->usb_addr);
699
700 /*
701 * ohci allocates descriptors for root hub so we can't
702 * deallocate these here
703 */
704
705 if (usba_device->usb_addr != ROOT_HUB_ADDR) {
706 if (usba_device->usb_cfg_array) {
707 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
708 "deallocating usb_config_array: 0x%p",
709 (void *)usba_device->usb_cfg_array);
710 mutex_enter(&usba_device->usb_mutex);
711 for (i = 0;
712 i < usba_device->usb_dev_descr->bNumConfigurations;
713 i++) {
714 if (usba_device->usb_cfg_array[i]) {
715 kmem_free(
716 usba_device->usb_cfg_array[i],
717 usba_device->usb_cfg_array_len[i]);
718 }
719 }
720
721 /* free the array pointers */
722 kmem_free(usba_device->usb_cfg_array,
723 usba_device->usb_cfg_array_length);
724 kmem_free(usba_device->usb_cfg_array_len,
725 usba_device->usb_cfg_array_len_length);
726
727 mutex_exit(&usba_device->usb_mutex);
728 }
729
730 if (usba_device->usb_cfg_str_descr) {
731 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
732 "deallocating usb_cfg_str_descr: 0x%p",
733 (void *)usba_device->usb_cfg_str_descr);
734 for (i = 0;
735 i < usba_device->usb_dev_descr->bNumConfigurations;
736 i++) {
737 if (usba_device->usb_cfg_str_descr[i]) {
738 kmem_free(
739 usba_device->usb_cfg_str_descr[i],
740 strlen(usba_device->
741 usb_cfg_str_descr[i]) + 1);
742 }
743 }
744 /* free the array pointers */
745 kmem_free(usba_device->usb_cfg_str_descr,
746 sizeof (uchar_t *) * usba_device->usb_n_cfgs);
747 }
748
749 if (usba_device->usb_dev_descr) {
750 kmem_free(usba_device->usb_dev_descr,
751 sizeof (usb_dev_descr_t));
752 }
753
754 if (usba_device->usb_mfg_str) {
755 kmem_free(usba_device->usb_mfg_str,
756 strlen(usba_device->usb_mfg_str) + 1);
757 }
758
759 if (usba_device->usb_product_str) {
760 kmem_free(usba_device->usb_product_str,
761 strlen(usba_device->usb_product_str) + 1);
762 }
763
764 if (usba_device->usb_serialno_str) {
765 kmem_free(usba_device->usb_serialno_str,
766 strlen(usba_device->usb_serialno_str) + 1);
767 }
768
769 usba_unset_usb_address(usba_device);
770 }
771
772 #ifndef __lock_lint
773 ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
774 #endif
775
776 if (usba_device->usb_client_flags) {
777 #ifndef __lock_lint
778 int i;
779
780 for (i = 0; i < usba_device->usb_n_ifs; i++) {
781 ASSERT(usba_device->usb_client_flags[i] == 0);
782 }
783 #endif
784 kmem_free(usba_device->usb_client_flags,
785 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
786 }
787
788
789 if (usba_device->usb_client_attach_list) {
790 kmem_free(usba_device->usb_client_attach_list,
791 usba_device->usb_n_ifs *
792 sizeof (*usba_device->usb_client_attach_list));
793 }
794 if (usba_device->usb_client_ev_cb_list) {
795 kmem_free(usba_device->usb_client_ev_cb_list,
796 usba_device->usb_n_ifs *
797 sizeof (*usba_device->usb_client_ev_cb_list));
798 }
799
800 /*
801 * finally ready to destroy the structure
802 */
803 mutex_destroy(&usba_device->usb_mutex);
804
805 kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
806 }
807
808
809 /* clear the data toggle for all endpoints on this device */
810 void
811 usba_clear_data_toggle(usba_device_t *usba_device)
812 {
813 int i;
814
815 if (usba_device != NULL) {
816 mutex_enter(&usba_device->usb_mutex);
817 for (i = 0; i < USBA_N_ENDPOINTS; i++) {
818 usba_device->usb_ph_list[i].usba_ph_flags &=
819 ~USBA_PH_DATA_TOGGLE;
820 }
821 mutex_exit(&usba_device->usb_mutex);
822 }
823 }
824
825
826 /*
827 * usba_create_child_devi():
828 * create a child devinfo node, usba_device, attach properties.
829 * the usba_device structure is shared between all interfaces
830 */
831 int
832 usba_create_child_devi(dev_info_t *dip,
833 char *node_name,
834 usba_hcdi_ops_t *usba_hcdi_ops,
835 dev_info_t *usb_root_hub_dip,
836 usb_port_status_t port_status,
837 usba_device_t *usba_device,
838 dev_info_t **child_dip)
839 {
840 int rval = USB_FAILURE;
841 int usba_device_allocated = 0;
842 usb_addr_t address;
843
844 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
845 "usba_create_child_devi: %s usba_device=0x%p "
846 "port status=0x%x", node_name,
847 (void *)usba_device, port_status);
848
849 ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
850 child_dip);
851
852 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
853 "child dip=0x%p", (void *)*child_dip);
854
855 if (usba_device == NULL) {
856
857 usba_device = usba_alloc_usba_device(usb_root_hub_dip);
858
859 /* grab the mutex to keep warlock happy */
860 mutex_enter(&usba_device->usb_mutex);
861 usba_device->usb_hcdi_ops = usba_hcdi_ops;
862 usba_device->usb_port_status = port_status;
863 mutex_exit(&usba_device->usb_mutex);
864
865 usba_device_allocated++;
866 } else {
867 mutex_enter(&usba_device->usb_mutex);
868 if (usba_hcdi_ops) {
869 ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
870 }
871 if (usb_root_hub_dip) {
872 ASSERT(usba_device->usb_root_hub_dip ==
873 usb_root_hub_dip);
874 }
875
876 usba_device->usb_port_status = port_status;
877
878 mutex_exit(&usba_device->usb_mutex);
879 }
880
881 if (usba_device->usb_addr == 0) {
882 if (usba_set_usb_address(usba_device) == USB_FAILURE) {
883 address = 0;
884
885 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
886 "cannot set usb address for dip=0x%p",
887 (void *)*child_dip);
888
889 goto fail;
890 }
891 }
892 address = usba_device->usb_addr;
893
894 /* attach properties */
895 rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
896 "assigned-address", address);
897 if (rval != DDI_PROP_SUCCESS) {
898 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
899 "cannot set usb address property for dip=0x%p",
900 (void *)*child_dip);
901 rval = USB_FAILURE;
902
903 goto fail;
904 }
905
906 /*
907 * store the usba_device point in the dip
908 */
909 usba_set_usba_device(*child_dip, usba_device);
910
911 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
912 "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
913 (void *)*child_dip, ddi_driver_name(*child_dip),
914 (void *)usba_device);
915
916 return (USB_SUCCESS);
917
918 fail:
919 if (*child_dip) {
920 int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
921 ASSERT(rval == USB_SUCCESS);
922 *child_dip = NULL;
923 }
924
925 if (usba_device_allocated) {
926 usba_free_usba_device(usba_device);
927 } else if (address && usba_device) {
928 usba_unset_usb_address(usba_device);
929 }
930
931 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
932 "usba_create_child_devi failed: rval=%d", rval);
933
934 return (rval);
935 }
936
937
938 int
939 usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
940 {
941 usba_device_t *usba_device;
942 int rval = NDI_SUCCESS;
943
944 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
945 "usba_destroy_child_devi: %s%d (0x%p)",
946 ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip);
947
948 usba_device = usba_get_usba_device(dip);
949
950 /*
951 * if the child hasn't been bound yet, we can just
952 * free the dip
953 */
954 if (i_ddi_node_state(dip) < DS_INITIALIZED) {
955 /*
956 * do not call ndi_devi_free() since it might
957 * deadlock
958 */
959 rval = ddi_remove_child(dip, 0);
960
961 } else {
962 char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
963 dev_info_t *pdip = ddi_get_parent(dip);
964
965 (void) ddi_deviname(dip, devnm);
966
967 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
968 "usba_destroy_child_devi:\n\t"
969 "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
970 (void *)usba_device, devnm);
971
972 (void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
973 rval = ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
974 flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
975 if (rval != NDI_SUCCESS) {
976 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
977 " ndi_devi_unconfig_one %s%d failed (%d)",
978 ddi_driver_name(dip), ddi_get_instance(dip),
979 rval);
980 }
981 kmem_free(devnm, MAXNAMELEN + 1);
982 }
983
984 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
985 "usba_destroy_child_devi: rval=%d", rval);
986
987 return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
988 }
989
990
991 /*
992 * list management
993 */
994 void
995 usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
996 ddi_iblock_cookie_t iblock_cookie)
997 {
998 mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
999 iblock_cookie);
1000 mutex_enter(&element->list_mutex);
1001 element->private = private;
1002 mutex_exit(&element->list_mutex);
1003 }
1004
1005
1006 void
1007 usba_destroy_list(usba_list_entry_t *head)
1008 {
1009 mutex_enter(&head->list_mutex);
1010 ASSERT(head->next == NULL);
1011 ASSERT(head->prev == NULL);
1012 mutex_exit(&head->list_mutex);
1013
1014 mutex_destroy(&head->list_mutex);
1015 }
1016
1017
1018 void
1019 usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
1020 {
1021 usba_list_entry_t *next;
1022 int remaining;
1023
1024 mutex_enter(&head->list_mutex);
1025 mutex_enter(&element->list_mutex);
1026
1027 remaining = head->count;
1028
1029 /* check if it is not in another list */
1030 ASSERT(element->next == NULL);
1031 ASSERT(element->prev == NULL);
1032
1033 #ifdef DEBUG
1034 /*
1035 * only verify the list when not in interrupt context, we
1036 * have to trust the HCD
1037 */
1038 if (!servicing_interrupt()) {
1039
1040 /* check if not already in this list */
1041 for (next = head->next; (next != NULL);
1042 next = next->next) {
1043 if (next == element) {
1044 USB_DPRINTF_L0(DPRINT_MASK_USBA,
1045 usba_log_handle,
1046 "Attempt to corrupt USB list at 0x%p",
1047 (void *)head);
1048 ASSERT(next == element);
1049
1050 goto done;
1051 }
1052 remaining--;
1053
1054 /*
1055 * Detect incorrect circ links or found
1056 * unexpected elements.
1057 */
1058 if ((next->next && (remaining == 0)) ||
1059 ((next->next == NULL) && remaining)) {
1060 panic("Corrupted USB list at 0x%p",
1061 (void *)head);
1062 /*NOTREACHED*/
1063 }
1064 }
1065 }
1066 #endif
1067
1068 if (head->next == NULL) {
1069 head->prev = head->next = element;
1070 } else {
1071 /* add to tail */
1072 head->prev->next = element;
1073 element->prev = head->prev;
1074 head->prev = element;
1075 }
1076
1077 head->count++;
1078
1079 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1080 "usba_add_to_list: head=0x%p element=0x%p count=%d",
1081 (void *)head, (void *)element, head->count);
1082
1083 done:
1084 mutex_exit(&head->list_mutex);
1085 mutex_exit(&element->list_mutex);
1086 }
1087
1088
1089 int
1090 usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
1091 {
1092 usba_list_entry_t *e;
1093 int found = 0;
1094 int remaining;
1095
1096 /* find the element in the list first */
1097 mutex_enter(&head->list_mutex);
1098
1099 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1100 "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1101 (void *)head, (void *)element, head->count);
1102
1103 remaining = head->count;
1104 e = head->next;
1105
1106 while (e) {
1107 if (e == element) {
1108 found++;
1109 break;
1110 }
1111 e = e->next;
1112
1113 remaining--;
1114
1115 /* Detect incorrect circ links or found unexpected elements. */
1116 if ((e && (remaining == 0)) ||
1117 ((e == NULL) && (remaining))) {
1118 panic("Corrupted USB list at 0x%p", (void *)head);
1119 /*NOTREACHED*/
1120 }
1121 }
1122
1123 if (!found) {
1124 mutex_exit(&head->list_mutex);
1125
1126 return (USB_FAILURE);
1127 }
1128
1129 /* now remove the element */
1130 mutex_enter(&element->list_mutex);
1131
1132 if (element->next) {
1133 element->next->prev = element->prev;
1134 }
1135 if (element->prev) {
1136 element->prev->next = element->next;
1137 }
1138 if (head->next == element) {
1139 head->next = element->next;
1140 }
1141 if (head->prev == element) {
1142 head->prev = element->prev;
1143 }
1144
1145 element->prev = element->next = NULL;
1146 if (head->next == NULL) {
1147 ASSERT(head->prev == NULL);
1148 } else {
1149 ASSERT(head->next->prev == NULL);
1150 }
1151 if (head->prev == NULL) {
1152 ASSERT(head->next == NULL);
1153 } else {
1154 ASSERT(head->prev->next == NULL);
1155 }
1156
1157 head->count--;
1158
1159 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1160 "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1161 (void *)head, (void *)element, head->count);
1162
1163 mutex_exit(&element->list_mutex);
1164 mutex_exit(&head->list_mutex);
1165
1166 return (USB_SUCCESS);
1167 }
1168
1169
1170 usba_list_entry_t *
1171 usba_rm_first_from_list(usba_list_entry_t *head)
1172 {
1173 usba_list_entry_t *element = NULL;
1174
1175 if (head) {
1176 mutex_enter(&head->list_mutex);
1177 element = head->next;
1178 if (element) {
1179 /* now remove the element */
1180 mutex_enter(&element->list_mutex);
1181 head->next = element->next;
1182 if (head->next) {
1183 head->next->prev = NULL;
1184 }
1185 if (head->prev == element) {
1186 head->prev = element->next;
1187 }
1188 element->prev = element->next = NULL;
1189 mutex_exit(&element->list_mutex);
1190 head->count--;
1191 }
1192 if (head->next == NULL) {
1193 ASSERT(head->prev == NULL);
1194 } else {
1195 ASSERT(head->next->prev == NULL);
1196 }
1197 if (head->prev == NULL) {
1198 ASSERT(head->next == NULL);
1199 } else {
1200 ASSERT(head->prev->next == NULL);
1201 }
1202 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1203 "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1204 (void *)head, (void *)element, head->count);
1205
1206 mutex_exit(&head->list_mutex);
1207 }
1208
1209 return (element);
1210 }
1211
1212
1213 usb_opaque_t
1214 usba_rm_first_pvt_from_list(usba_list_entry_t *head)
1215 {
1216 usba_list_entry_t *element = usba_rm_first_from_list(head);
1217 usb_opaque_t private = NULL;
1218
1219 if (element) {
1220 mutex_enter(&element->list_mutex);
1221 private = element->private;
1222 mutex_exit(&element->list_mutex);
1223 }
1224
1225 return (private);
1226 }
1227
1228
1229 /*
1230 * move list to new list and zero original list
1231 */
1232 void
1233 usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
1234 ddi_iblock_cookie_t iblock_cookie)
1235 {
1236 usba_init_list(new, NULL, iblock_cookie);
1237 mutex_enter(&head->list_mutex);
1238 mutex_enter(&new->list_mutex);
1239
1240 new->next = head->next;
1241 new->prev = head->prev;
1242 new->count = head->count;
1243 new->private = head->private;
1244
1245 head->next = NULL;
1246 head->prev = NULL;
1247 head->count = 0;
1248 head->private = NULL;
1249 mutex_exit(&head->list_mutex);
1250 mutex_exit(&new->list_mutex);
1251 }
1252
1253
1254 int
1255 usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
1256 {
1257 int rval = USB_FAILURE;
1258 int remaining;
1259 usba_list_entry_t *next;
1260
1261 mutex_enter(&head->list_mutex);
1262 remaining = head->count;
1263
1264 mutex_enter(&element->list_mutex);
1265 for (next = head->next; next != NULL; next = next->next) {
1266 if (next == element) {
1267 rval = USB_SUCCESS;
1268 break;
1269 }
1270 remaining--;
1271
1272 /* Detect incorrect circ links or found unexpected elements. */
1273 if ((next->next && (remaining == 0)) ||
1274 ((next->next == NULL) && remaining)) {
1275 panic("Corrupted USB list at 0x%p", (void *)head);
1276 /*NOTREACHED*/
1277 }
1278 }
1279 mutex_exit(&element->list_mutex);
1280 mutex_exit(&head->list_mutex);
1281
1282 return (rval);
1283 }
1284
1285
1286 int
1287 usba_list_entry_leaks(usba_list_entry_t *head, char *what)
1288 {
1289 int count = 0;
1290 int remaining;
1291 usba_list_entry_t *next;
1292
1293 mutex_enter(&head->list_mutex);
1294 remaining = head->count;
1295 for (next = head->next; next != NULL; next = next->next) {
1296 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1297 "leaking %s 0x%p", what, (void *)next->private);
1298 count++;
1299
1300 remaining--;
1301
1302 /* Detect incorrect circ links or found unexpected elements. */
1303 if ((next->next && (remaining == 0)) ||
1304 ((next->next == NULL) && remaining)) {
1305 panic("Corrupted USB list at 0x%p", (void *)head);
1306 /*NOTREACHED*/
1307 }
1308 }
1309 ASSERT(count == head->count);
1310 mutex_exit(&head->list_mutex);
1311
1312 if (count) {
1313 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1314 "usba_list_entry_count: leaking %d", count);
1315 }
1316
1317 return (count);
1318 }
1319
1320
1321 int
1322 usba_list_entry_count(usba_list_entry_t *head)
1323 {
1324 int count;
1325
1326 mutex_enter(&head->list_mutex);
1327 count = head->count;
1328 mutex_exit(&head->list_mutex);
1329
1330 return (count);
1331 }
1332
1333 /* add a new root hub to the usba_root_hubs list */
1334
1335 void
1336 usba_add_root_hub(dev_info_t *dip)
1337 {
1338 usba_root_hub_ent_t *hub;
1339
1340 hub = (usba_root_hub_ent_t *)
1341 kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
1342
1343 mutex_enter(&usba_hub_mutex);
1344 hub->dip = dip;
1345 hub->next = usba_root_hubs;
1346 usba_root_hubs = hub;
1347 mutex_exit(&usba_hub_mutex);
1348 }
1349
1350 /* remove a root hub from the usba_root_hubs list */
1351
1352 void
1353 usba_rem_root_hub(dev_info_t *dip)
1354 {
1355 usba_root_hub_ent_t **hubp, *hub;
1356
1357 mutex_enter(&usba_hub_mutex);
1358 hubp = &usba_root_hubs;
1359 while (*hubp) {
1360 if ((*hubp)->dip == dip) {
1361 hub = *hubp;
1362 *hubp = hub->next;
1363 kmem_free(hub, sizeof (struct usba_root_hub_ent));
1364 mutex_exit(&usba_hub_mutex);
1365
1366 return;
1367 }
1368 hubp = &(*hubp)->next;
1369 }
1370 mutex_exit(&usba_hub_mutex);
1371 }
1372
1373 /*
1374 * check whether this dip is the root hub. Any root hub known by
1375 * usba is recorded in the linked list pointed to by usba_root_hubs
1376 */
1377 int
1378 usba_is_root_hub(dev_info_t *dip)
1379 {
1380 usba_root_hub_ent_t *hub;
1381
1382 mutex_enter(&usba_hub_mutex);
1383 hub = usba_root_hubs;
1384 while (hub) {
1385 if (hub->dip == dip) {
1386 mutex_exit(&usba_hub_mutex);
1387
1388 return (1);
1389 }
1390 hub = hub->next;
1391 }
1392 mutex_exit(&usba_hub_mutex);
1393
1394 return (0);
1395 }
1396
1397 /*
1398 * get and store usba_device pointer in the devi
1399 */
1400 usba_device_t *
1401 usba_get_usba_device(dev_info_t *dip)
1402 {
1403 /*
1404 * we cannot use parent_data in the usb node because its
1405 * bus parent (eg. PCI nexus driver) uses this data
1406 *
1407 * we cannot use driver data in the other usb nodes since
1408 * usb drivers may need to use this
1409 */
1410 if (usba_is_root_hub(dip)) {
1411 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1412
1413 return (hcdi->hcdi_usba_device);
1414 } else {
1415
1416 return (ddi_get_parent_data(dip));
1417 }
1418 }
1419
1420
1421 /*
1422 * Retrieve the usba_device pointer from the dev without checking for
1423 * the root hub first. This function is only used in polled mode.
1424 */
1425 usba_device_t *
1426 usba_polled_get_usba_device(dev_info_t *dip)
1427 {
1428 /*
1429 * Don't call usba_is_root_hub() to find out if this is
1430 * the root hub usba_is_root_hub() calls into the DDI
1431 * where there are locking issues. The dip sent in during
1432 * polled mode will never be the root hub, so just get
1433 * the usba_device pointer from the dip.
1434 */
1435 return (ddi_get_parent_data(dip));
1436 }
1437
1438
1439 void
1440 usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
1441 {
1442 if (usba_is_root_hub(dip)) {
1443 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1444 /* no locking is needed here */
1445 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1446 hcdi->hcdi_usba_device = usba_device;
1447 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1448 } else {
1449 ddi_set_parent_data(dip, usba_device);
1450 }
1451 }
1452
1453
1454 /*
1455 * usba_set_node_name() according to class, subclass, and protocol
1456 * following the 1275 USB binding tables.
1457 */
1458
1459 /* device node table, refer to section 3.2.2.1 of 1275 binding */
1460 static node_name_entry_t device_node_name_table[] = {
1461 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1462 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1463 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1464 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1465 { DONTCARE, DONTCARE, DONTCARE, "device" }
1466 };
1467
1468 /* interface-association node table */
1469 static node_name_entry_t ia_node_name_table[] = {
1470 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "audio" },
1471 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1472 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
1473 "device-wire-adaptor" },
1474 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless-controller" },
1475 { DONTCARE, DONTCARE, DONTCARE, "interface-association" }
1476 };
1477
1478 /* interface node table, refer to section 3.3.2.1 */
1479 static node_name_entry_t if_node_name_table[] = {
1480 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1481 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1482 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1483 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1484
1485 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1486 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1487 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1488 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1489 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1490 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1491 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1492 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1493
1494 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1495 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1496 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1497
1498 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1499
1500 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1501
1502 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1503
1504 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1505
1506 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1507
1508 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1509
1510 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1511
1512 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1513 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1514 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1515
1516 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1517 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1518 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1519
1520 { USB_CLASS_MISC, USB_SUBCLS_CBAF, USB_PROTO_CBAF, "wusb_ca"},
1521 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
1522 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
1523 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
1524 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
1525 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
1526
1527 { DONTCARE, DONTCARE, DONTCARE, "interface" },
1528
1529 };
1530
1531 /* combined node table, refer to section 3.4.2.1 */
1532 static node_name_entry_t combined_node_name_table[] = {
1533 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1534 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1535 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1536 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1537
1538 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1539 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1540 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1541 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1542 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1543 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1544 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1545 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1546
1547 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1548 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1549 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1550
1551 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1552
1553 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1554
1555 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1556
1557 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10, DONTCARE, "storage" },
1558 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I, DONTCARE, "cdrom" },
1559 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157, DONTCARE, "tape" },
1560 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI, DONTCARE, "floppy" },
1561 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I, DONTCARE, "storage" },
1562 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI, DONTCARE, "storage" },
1563 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1564
1565 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1566
1567 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1568
1569 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1570 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1571 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1572
1573 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1574 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1575 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1576
1577 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1578 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1579 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1580 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1581 { DONTCARE, DONTCARE, DONTCARE, "device" }
1582 };
1583
1584 static size_t device_node_name_table_size =
1585 sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1586 static size_t ia_node_name_table_size =
1587 sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
1588 static size_t if_node_name_table_size =
1589 sizeof (if_node_name_table)/sizeof (struct node_name_entry);
1590 static size_t combined_node_name_table_size =
1591 sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
1592
1593
1594 static void
1595 usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
1596 uint8_t protocol, uint_t flag)
1597 {
1598 int i;
1599 size_t size;
1600 node_name_entry_t *node_name_table;
1601
1602 switch (flag) {
1603 /* interface share node names with interface-association */
1604 case FLAG_INTERFACE_ASSOCIATION_NODE:
1605 node_name_table = ia_node_name_table;
1606 size = ia_node_name_table_size;
1607 break;
1608 case FLAG_INTERFACE_NODE:
1609 node_name_table = if_node_name_table;
1610 size = if_node_name_table_size;
1611 break;
1612 case FLAG_DEVICE_NODE:
1613 node_name_table = device_node_name_table;
1614 size = device_node_name_table_size;
1615 break;
1616 case FLAG_COMBINED_NODE:
1617 node_name_table = combined_node_name_table;
1618 size = combined_node_name_table_size;
1619 break;
1620 default:
1621
1622 return;
1623 }
1624
1625 for (i = 0; i < size; i++) {
1626 int16_t c = node_name_table[i].class;
1627 int16_t s = node_name_table[i].subclass;
1628 int16_t p = node_name_table[i].protocol;
1629
1630 if (((c == DONTCARE) || (c == class)) &&
1631 ((s == DONTCARE) || (s == subclass)) &&
1632 ((p == DONTCARE) || (p == protocol))) {
1633 char *name = node_name_table[i].name;
1634
1635 (void) ndi_devi_set_nodename(dip, name, 0);
1636 break;
1637 }
1638 }
1639 }
1640
1641
1642 #ifdef DEBUG
1643 /*
1644 * walk the children of the parent of this devi and compare the
1645 * name and reg property of each child. If there is a match
1646 * return this node
1647 */
1648 static dev_info_t *
1649 usba_find_existing_node(dev_info_t *odip)
1650 {
1651 dev_info_t *ndip, *child, *pdip;
1652 int *odata, *ndata;
1653 uint_t n_odata, n_ndata;
1654 int circular;
1655
1656 pdip = ddi_get_parent(odip);
1657 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1658 odip, DDI_PROP_DONTPASS, "reg",
1659 &odata, &n_odata) != DDI_SUCCESS) {
1660 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1661 "usba_find_existing_node: "
1662 "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
1663
1664 return (NULL);
1665 }
1666
1667 ndi_devi_enter(pdip, &circular);
1668 ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
1669 while ((child = ndip) != NULL) {
1670
1671 ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
1672
1673 if (child == odip) {
1674 continue;
1675 }
1676
1677 if (strcmp(DEVI(child)->devi_node_name,
1678 DEVI(odip)->devi_node_name)) {
1679 continue;
1680 }
1681
1682 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1683 child, DDI_PROP_DONTPASS, "reg",
1684 &ndata, &n_ndata) != DDI_SUCCESS) {
1685
1686 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1687 "usba_find_existing_node: "
1688 "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
1689
1690 } else if (n_ndata && n_odata && (bcmp(odata, ndata,
1691 max(n_odata, n_ndata) * sizeof (int)) == 0)) {
1692
1693 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1694 "usba_find_existing_node: found %s%d (%p)",
1695 ddi_driver_name(child),
1696 ddi_get_instance(child), (void *)child);
1697
1698 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1699 "usba_find_existing_node: "
1700 "reg: %x %x %x - %x %x %x",
1701 n_odata, odata[0], odata[1],
1702 n_ndata, ndata[0], ndata[1]);
1703
1704 ddi_prop_free(ndata);
1705 break;
1706
1707 } else {
1708 ddi_prop_free(ndata);
1709 }
1710 }
1711
1712 ndi_devi_exit(pdip, circular);
1713
1714 ddi_prop_free(odata);
1715
1716 return (child);
1717 }
1718 #endif
1719
1720 /* change all unprintable characters to spaces */
1721 static void
1722 usba_filter_string(char *instr, char *outstr)
1723 {
1724 while (*instr) {
1725 if ((*instr >= ' ') && (*instr <= '~')) {
1726 *outstr = *instr;
1727 } else {
1728 *outstr = ' ';
1729 }
1730 outstr++;
1731 instr++;
1732 }
1733 *outstr = '\0';
1734 }
1735
1736
1737 /*
1738 * lookup ugen binding specified in property in
1739 * hcd.conf files
1740 */
1741 int
1742 usba_get_ugen_binding(dev_info_t *dip)
1743 {
1744 usba_device_t *usba_device = usba_get_usba_device(dip);
1745 usba_hcdi_t *hcdi =
1746 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
1747
1748 return (hcdi->hcdi_ugen_default_binding);
1749 }
1750
1751
1752 /*
1753 * driver binding support at device level
1754 */
1755 dev_info_t *
1756 usba_ready_device_node(dev_info_t *child_dip)
1757 {
1758 int rval, i;
1759 int n = 0;
1760 usba_device_t *usba_device = usba_get_usba_device(child_dip);
1761 usb_dev_descr_t *usb_dev_descr;
1762 uint_t n_cfgs; /* number of configs */
1763 uint_t n_ifs; /* number of interfaces */
1764 uint_t port, bus_num;
1765 size_t usb_config_length;
1766 uchar_t *usb_config;
1767 int reg[1];
1768 usb_addr_t address = usb_get_addr(child_dip);
1769 usb_if_descr_t if_descr;
1770 size_t size;
1771 int combined_node = 0;
1772 int is_hub;
1773 char *devprop_str;
1774 char *force_bind = NULL;
1775 char *usba_name_buf = NULL;
1776 char *usba_name[USBA_MAX_COMPAT_NAMES];
1777
1778 usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
1779
1780 mutex_enter(&usba_device->usb_mutex);
1781 mutex_enter(&usba_mutex);
1782
1783 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1784 "usba_ready_device_node: child=0x%p", (void *)child_dip);
1785
1786 port = usba_device->usb_port;
1787 usb_dev_descr = usba_device->usb_dev_descr;
1788 n_cfgs = usba_device->usb_n_cfgs;
1789 n_ifs = usba_device->usb_n_ifs;
1790 bus_num = usba_device->usb_addr;
1791
1792 if (address != ROOT_HUB_ADDR) {
1793 size = usb_parse_if_descr(
1794 usb_config,
1795 usb_config_length,
1796 0, /* interface index */
1797 0, /* alt interface index */
1798 &if_descr,
1799 USB_IF_DESCR_SIZE);
1800
1801 if (size != USB_IF_DESCR_SIZE) {
1802 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1803 "parsing interface: "
1804 "size (%lu) != USB_IF_DESCR_SIZE (%d)",
1805 size, USB_IF_DESCR_SIZE);
1806
1807 mutex_exit(&usba_mutex);
1808 mutex_exit(&usba_device->usb_mutex);
1809
1810 return (child_dip);
1811 }
1812 } else {
1813 /* fake an interface descriptor for the root hub */
1814 bzero(&if_descr, sizeof (if_descr));
1815
1816 if_descr.bInterfaceClass = USB_CLASS_HUB;
1817 }
1818
1819 reg[0] = port;
1820
1821 mutex_exit(&usba_mutex);
1822 mutex_exit(&usba_device->usb_mutex);
1823
1824 rval = ndi_prop_update_int_array(
1825 DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
1826
1827 if (rval != DDI_PROP_SUCCESS) {
1828 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1829 "usba_ready_device_node: property update failed");
1830
1831 return (child_dip);
1832 }
1833
1834 combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
1835 ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
1836 (usb_dev_descr->bDeviceClass == 0)));
1837
1838 is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
1839 (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
1840
1841 /* set node name */
1842 if (combined_node) {
1843 usba_set_node_name(child_dip,
1844 if_descr.bInterfaceClass,
1845 if_descr.bInterfaceSubClass,
1846 if_descr.bInterfaceProtocol,
1847 FLAG_COMBINED_NODE);
1848 } else {
1849 usba_set_node_name(child_dip,
1850 usb_dev_descr->bDeviceClass,
1851 usb_dev_descr->bDeviceSubClass,
1852 usb_dev_descr->bDeviceProtocol,
1853 FLAG_DEVICE_NODE);
1854 }
1855
1856 /*
1857 * check force binding rules
1858 */
1859 if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
1860 (address != usba_ddivs_usbc_xaddress) &&
1861 (!(usba_ddivs_usbc_xhubs && is_hub))) {
1862 force_bind = "ddivs_usbc";
1863 (void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
1864
1865 } else if (usba_device->usb_preferred_driver) {
1866 force_bind = usba_device->usb_preferred_driver;
1867
1868 } else if ((address != ROOT_HUB_ADDR) &&
1869 ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
1870 ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
1871 combined_node)) && (!is_hub)) {
1872 force_bind = "ugen";
1873 }
1874
1875 #ifdef DEBUG
1876 /*
1877 * check whether there is another dip with this name and address
1878 * If the dip contains usba_device, it is held by the previous
1879 * round of configuration.
1880 */
1881 ASSERT(usba_find_existing_node(child_dip) == NULL);
1882 #endif
1883
1884 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
1885 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
1886
1887 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
1888 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
1889 }
1890
1891 if (force_bind) {
1892 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
1893 (void) strncpy(usba_name[n++], force_bind,
1894 USBA_MAX_COMPAT_NAME_LEN);
1895 }
1896
1897 /*
1898 * If the callback function of specified driver is registered,
1899 * it will be called here to check whether to take over the device.
1900 */
1901 if (usb_cap.usba_dev_driver_cb != NULL) {
1902 char *dev_drv = NULL;
1903 usb_dev_str_t dev_str;
1904 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1905
1906 dev_str.usb_mfg = usba_device->usb_mfg_str;
1907 dev_str.usb_product = usba_device->usb_product_str;
1908 dev_str.usb_serialno = usba_device->usb_serialno_str;
1909
1910 (void) ddi_pathname(child_dip, pathname);
1911
1912 if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1913 pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1914 (dev_drv != NULL)) {
1915 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1916 "usba_ready_device_node: dev_driver=%s, port =%d,"
1917 "bus =%d, path=%s\n\t",
1918 dev_drv, port, bus_num, pathname);
1919
1920 (void) strncpy(usba_name[n++], dev_drv,
1921 USBA_MAX_COMPAT_NAME_LEN);
1922 }
1923 kmem_free(pathname, MAXPATHLEN);
1924 }
1925
1926 /* create compatible names */
1927 if (combined_node) {
1928
1929 /* 1. usbVID,PID.REV */
1930 (void) sprintf(usba_name[n++],
1931 "usb%x,%x.%x",
1932 usb_dev_descr->idVendor,
1933 usb_dev_descr->idProduct,
1934 usb_dev_descr->bcdDevice);
1935
1936 /* 2. usbVID,PID */
1937 (void) sprintf(usba_name[n++],
1938 "usb%x,%x",
1939 usb_dev_descr->idVendor,
1940 usb_dev_descr->idProduct);
1941
1942 if (usb_dev_descr->bDeviceClass != 0) {
1943 /* 3. usbVID,classDC.DSC.DPROTO */
1944 (void) sprintf(usba_name[n++],
1945 "usb%x,class%x.%x.%x",
1946 usb_dev_descr->idVendor,
1947 usb_dev_descr->bDeviceClass,
1948 usb_dev_descr->bDeviceSubClass,
1949 usb_dev_descr->bDeviceProtocol);
1950
1951 /* 4. usbVID,classDC.DSC */
1952 (void) sprintf(usba_name[n++],
1953 "usb%x,class%x.%x",
1954 usb_dev_descr->idVendor,
1955 usb_dev_descr->bDeviceClass,
1956 usb_dev_descr->bDeviceSubClass);
1957
1958 /* 5. usbVID,classDC */
1959 (void) sprintf(usba_name[n++],
1960 "usb%x,class%x",
1961 usb_dev_descr->idVendor,
1962 usb_dev_descr->bDeviceClass);
1963
1964 /* 6. usb,classDC.DSC.DPROTO */
1965 (void) sprintf(usba_name[n++],
1966 "usb,class%x.%x.%x",
1967 usb_dev_descr->bDeviceClass,
1968 usb_dev_descr->bDeviceSubClass,
1969 usb_dev_descr->bDeviceProtocol);
1970
1971 /* 7. usb,classDC.DSC */
1972 (void) sprintf(usba_name[n++],
1973 "usb,class%x.%x",
1974 usb_dev_descr->bDeviceClass,
1975 usb_dev_descr->bDeviceSubClass);
1976
1977 /* 8. usb,classDC */
1978 (void) sprintf(usba_name[n++],
1979 "usb,class%x",
1980 usb_dev_descr->bDeviceClass);
1981 }
1982
1983 if (if_descr.bInterfaceClass != 0) {
1984 /* 9. usbifVID,classIC.ISC.IPROTO */
1985 (void) sprintf(usba_name[n++],
1986 "usbif%x,class%x.%x.%x",
1987 usb_dev_descr->idVendor,
1988 if_descr.bInterfaceClass,
1989 if_descr.bInterfaceSubClass,
1990 if_descr.bInterfaceProtocol);
1991
1992 /* 10. usbifVID,classIC.ISC */
1993 (void) sprintf(usba_name[n++],
1994 "usbif%x,class%x.%x",
1995 usb_dev_descr->idVendor,
1996 if_descr.bInterfaceClass,
1997 if_descr.bInterfaceSubClass);
1998
1999 /* 11. usbifVID,classIC */
2000 (void) sprintf(usba_name[n++],
2001 "usbif%x,class%x",
2002 usb_dev_descr->idVendor,
2003 if_descr.bInterfaceClass);
2004
2005 /* 12. usbif,classIC.ISC.IPROTO */
2006 (void) sprintf(usba_name[n++],
2007 "usbif,class%x.%x.%x",
2008 if_descr.bInterfaceClass,
2009 if_descr.bInterfaceSubClass,
2010 if_descr.bInterfaceProtocol);
2011
2012 /* 13. usbif,classIC.ISC */
2013 (void) sprintf(usba_name[n++],
2014 "usbif,class%x.%x",
2015 if_descr.bInterfaceClass,
2016 if_descr.bInterfaceSubClass);
2017
2018 /* 14. usbif,classIC */
2019 (void) sprintf(usba_name[n++],
2020 "usbif,class%x",
2021 if_descr.bInterfaceClass);
2022 }
2023
2024 /* 15. ugen or usb_mid */
2025 if (usba_get_ugen_binding(child_dip) ==
2026 USBA_UGEN_DEVICE_BINDING) {
2027 (void) sprintf(usba_name[n++], "ugen");
2028 } else {
2029 (void) sprintf(usba_name[n++], "usb,device");
2030 }
2031
2032 } else {
2033 if (n_cfgs > 1) {
2034 /* 1. usbVID,PID.REV.configCN */
2035 (void) sprintf(usba_name[n++],
2036 "usb%x,%x.%x.config%x",
2037 usb_dev_descr->idVendor,
2038 usb_dev_descr->idProduct,
2039 usb_dev_descr->bcdDevice,
2040 usba_device->usb_cfg_value);
2041 }
2042
2043 /* 2. usbVID,PID.REV */
2044 (void) sprintf(usba_name[n++],
2045 "usb%x,%x.%x",
2046 usb_dev_descr->idVendor,
2047 usb_dev_descr->idProduct,
2048 usb_dev_descr->bcdDevice);
2049
2050 /* 3. usbVID,PID.configCN */
2051 if (n_cfgs > 1) {
2052 (void) sprintf(usba_name[n++],
2053 "usb%x,%x.%x",
2054 usb_dev_descr->idVendor,
2055 usb_dev_descr->idProduct,
2056 usba_device->usb_cfg_value);
2057 }
2058
2059 /* 4. usbVID,PID */
2060 (void) sprintf(usba_name[n++],
2061 "usb%x,%x",
2062 usb_dev_descr->idVendor,
2063 usb_dev_descr->idProduct);
2064
2065 if (usb_dev_descr->bDeviceClass != 0) {
2066 /* 5. usbVID,classDC.DSC.DPROTO */
2067 (void) sprintf(usba_name[n++],
2068 "usb%x,class%x.%x.%x",
2069 usb_dev_descr->idVendor,
2070 usb_dev_descr->bDeviceClass,
2071 usb_dev_descr->bDeviceSubClass,
2072 usb_dev_descr->bDeviceProtocol);
2073
2074 /* 6. usbVID,classDC.DSC */
2075 (void) sprintf(usba_name[n++],
2076 "usb%x.class%x.%x",
2077 usb_dev_descr->idVendor,
2078 usb_dev_descr->bDeviceClass,
2079 usb_dev_descr->bDeviceSubClass);
2080
2081 /* 7. usbVID,classDC */
2082 (void) sprintf(usba_name[n++],
2083 "usb%x.class%x",
2084 usb_dev_descr->idVendor,
2085 usb_dev_descr->bDeviceClass);
2086
2087 /* 8. usb,classDC.DSC.DPROTO */
2088 (void) sprintf(usba_name[n++],
2089 "usb,class%x.%x.%x",
2090 usb_dev_descr->bDeviceClass,
2091 usb_dev_descr->bDeviceSubClass,
2092 usb_dev_descr->bDeviceProtocol);
2093
2094 /* 9. usb,classDC.DSC */
2095 (void) sprintf(usba_name[n++],
2096 "usb,class%x.%x",
2097 usb_dev_descr->bDeviceClass,
2098 usb_dev_descr->bDeviceSubClass);
2099
2100 /* 10. usb,classDC */
2101 (void) sprintf(usba_name[n++],
2102 "usb,class%x",
2103 usb_dev_descr->bDeviceClass);
2104 }
2105
2106 if (usba_get_ugen_binding(child_dip) ==
2107 USBA_UGEN_DEVICE_BINDING) {
2108 /* 11. ugen */
2109 (void) sprintf(usba_name[n++], "ugen");
2110 } else {
2111 /* 11. usb,device */
2112 (void) sprintf(usba_name[n++], "usb,device");
2113 }
2114 }
2115
2116 for (i = 0; i < n; i += 2) {
2117 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2118 "compatible name:\t%s\t%s", usba_name[i],
2119 (((i+1) < n)? usba_name[i+1] : ""));
2120 }
2121
2122 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2123 "compatible", (char **)usba_name, n);
2124
2125 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2126 USBA_MAX_COMPAT_NAME_LEN);
2127
2128 if (rval != DDI_PROP_SUCCESS) {
2129
2130 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2131 "usba_ready_device_node: property update failed");
2132
2133 return (child_dip);
2134 }
2135
2136 /* update the address property */
2137 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2138 "assigned-address", usba_device->usb_addr);
2139 if (rval != DDI_PROP_SUCCESS) {
2140 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2141 "usba_ready_device_node: address update failed");
2142 }
2143
2144 /* update the usb device properties (PSARC/2000/454) */
2145 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2146 "usb-vendor-id", usb_dev_descr->idVendor);
2147 if (rval != DDI_PROP_SUCCESS) {
2148 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2149 "usba_ready_device_node: usb-vendor-id update failed");
2150 }
2151
2152 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2153 "usb-product-id", usb_dev_descr->idProduct);
2154 if (rval != DDI_PROP_SUCCESS) {
2155 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2156 "usba_ready_device_node: usb-product-id update failed");
2157 }
2158
2159 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2160 "usb-revision-id", usb_dev_descr->bcdDevice);
2161 if (rval != DDI_PROP_SUCCESS) {
2162 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2163 "usba_ready_device_node: usb-revision-id update failed");
2164 }
2165
2166 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2167 "usb-num-configs", usb_dev_descr->bNumConfigurations);
2168 if (rval != DDI_PROP_SUCCESS) {
2169 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2170 "usba_ready_device_node: usb-num-configs update failed");
2171 }
2172
2173 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2174 "usb-release", usb_dev_descr->bcdUSB);
2175 if (rval != DDI_PROP_SUCCESS) {
2176 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2177 "usba_ready_device_node: usb-release update failed");
2178 }
2179
2180 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2181 "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
2182 sizeof (usb_dev_descr_t));
2183 if (rval != DDI_PROP_SUCCESS) {
2184 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2185 "usba_ready_device_node: usb-descriptor update failed");
2186 }
2187
2188 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2189 "usb-raw-cfg-descriptors", usb_config, usb_config_length);
2190 if (rval != DDI_PROP_SUCCESS) {
2191 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2192 "usba_ready_device_node: usb-raw-cfg-descriptors update "
2193 "failed");
2194 }
2195
2196 devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2197
2198 if (usba_device->usb_serialno_str) {
2199 usba_filter_string(usba_device->usb_serialno_str, devprop_str);
2200 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2201 "usb-serialno", devprop_str);
2202 if (rval != DDI_PROP_SUCCESS) {
2203 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2204 "usba_ready_device_node: "
2205 "usb-serialno update failed");
2206 }
2207 }
2208
2209 if (usba_device->usb_mfg_str) {
2210 usba_filter_string(usba_device->usb_mfg_str, devprop_str);
2211 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2212 "usb-vendor-name", devprop_str);
2213 if (rval != DDI_PROP_SUCCESS) {
2214 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2215 "usba_ready_device_node: "
2216 "usb-vendor-name update failed");
2217 }
2218 }
2219
2220 if (usba_device->usb_product_str) {
2221 usba_filter_string(usba_device->usb_product_str, devprop_str);
2222 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2223 "usb-product-name", devprop_str);
2224 if (rval != DDI_PROP_SUCCESS) {
2225 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2226 "usba_ready_device_node: "
2227 "usb-product-name update failed");
2228 }
2229 }
2230
2231 kmem_free(devprop_str, USB_MAXSTRINGLEN);
2232
2233 if (!combined_node) {
2234 /* update the configuration property */
2235 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2236 "configuration#", usba_device->usb_cfg_value);
2237 if (rval != DDI_PROP_SUCCESS) {
2238 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2239 "usba_ready_device_node: "
2240 "config prop update failed");
2241 }
2242 }
2243
2244 if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
2245 /* create boolean property */
2246 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2247 "low-speed");
2248 if (rval != DDI_PROP_SUCCESS) {
2249 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2250 "usba_ready_device_node: "
2251 "low speed prop update failed");
2252 }
2253 }
2254
2255 if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
2256 /* create boolean property */
2257 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2258 "high-speed");
2259 if (rval != DDI_PROP_SUCCESS) {
2260 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2261 "usba_ready_device_node: "
2262 "high speed prop update failed");
2263 }
2264 }
2265
2266 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2267 "%s%d at port %d: %s, dip=0x%p",
2268 ddi_node_name(ddi_get_parent(child_dip)),
2269 ddi_get_instance(ddi_get_parent(child_dip)),
2270 port, ddi_node_name(child_dip), (void *)child_dip);
2271
2272 usba_set_usba_device(child_dip, usba_device);
2273
2274 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2275
2276 return (child_dip);
2277 }
2278
2279
2280 /*
2281 * driver binding at interface association level. the first arg is the parent
2282 * dip. if_count returns amount of interfaces which are associated within
2283 * this interface-association that starts from first_if.
2284 */
2285 /*ARGSUSED*/
2286 dev_info_t *
2287 usba_ready_interface_association_node(dev_info_t *dip,
2288 uint_t first_if,
2289 uint_t *if_count)
2290 {
2291 dev_info_t *child_dip = NULL;
2292 usba_device_t *child_ud = usba_get_usba_device(dip);
2293 usb_dev_descr_t *usb_dev_descr;
2294 size_t usb_cfg_length;
2295 uchar_t *usb_cfg;
2296 usb_ia_descr_t ia_descr;
2297 int i, n, rval;
2298 int reg[2];
2299 size_t size;
2300 usb_port_status_t port_status;
2301 char *force_bind = NULL;
2302 char *usba_name_buf = NULL;
2303 char *usba_name[USBA_MAX_COMPAT_NAMES];
2304
2305 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2306
2307 mutex_enter(&child_ud->usb_mutex);
2308
2309 usb_dev_descr = child_ud->usb_dev_descr;
2310
2311 /*
2312 * for each interface association, determine all compatible names
2313 */
2314 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2315 "usba_ready_ia_node: "
2316 "port %d, interface = %d, port_status = %x",
2317 child_ud->usb_port, first_if, child_ud->usb_port_status);
2318
2319 /* Parse the interface descriptor */
2320 size = usb_parse_ia_descr(
2321 usb_cfg,
2322 usb_cfg_length,
2323 first_if, /* interface index */
2324 &ia_descr,
2325 USB_IA_DESCR_SIZE);
2326
2327 *if_count = 1;
2328 if (size != USB_IA_DESCR_SIZE) {
2329 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2330 "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2331 size, USB_IA_DESCR_SIZE);
2332 mutex_exit(&child_ud->usb_mutex);
2333
2334 return (NULL);
2335 }
2336
2337 port_status = child_ud->usb_port_status;
2338
2339 /* create reg property */
2340 reg[0] = first_if;
2341 reg[1] = child_ud->usb_cfg_value;
2342
2343 mutex_exit(&child_ud->usb_mutex);
2344
2345 /* clone this dip */
2346 rval = usba_create_child_devi(dip,
2347 "interface-association",
2348 NULL, /* usba_hcdi ops */
2349 NULL, /* root hub dip */
2350 port_status, /* port status */
2351 child_ud, /* share this usba_device */
2352 &child_dip);
2353
2354 if (rval != USB_SUCCESS) {
2355
2356 goto fail;
2357 }
2358
2359 rval = ndi_prop_update_int_array(
2360 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2361
2362 if (rval != DDI_PROP_SUCCESS) {
2363
2364 goto fail;
2365 }
2366
2367 usba_set_node_name(child_dip, ia_descr.bFunctionClass,
2368 ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
2369 FLAG_INTERFACE_ASSOCIATION_NODE);
2370
2371 /* check force binding */
2372 if (usba_ugen_force_binding ==
2373 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2374 force_bind = "ugen";
2375 }
2376
2377 /*
2378 * check whether there is another dip with this name and address
2379 */
2380 ASSERT(usba_find_existing_node(child_dip) == NULL);
2381
2382 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2383 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2384
2385 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2386 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2387 }
2388
2389 n = 0;
2390
2391 if (force_bind) {
2392 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2393 (void) strncpy(usba_name[n++], force_bind,
2394 USBA_MAX_COMPAT_NAME_LEN);
2395 }
2396
2397 /* 1) usbiaVID,PID.REV.configCN.FN */
2398 (void) sprintf(usba_name[n++],
2399 "usbia%x,%x.%x.config%x.%x",
2400 usb_dev_descr->idVendor,
2401 usb_dev_descr->idProduct,
2402 usb_dev_descr->bcdDevice,
2403 child_ud->usb_cfg_value,
2404 first_if);
2405
2406 /* 2) usbiaVID,PID.configCN.FN */
2407 (void) sprintf(usba_name[n++],
2408 "usbia%x,%x.config%x.%x",
2409 usb_dev_descr->idVendor,
2410 usb_dev_descr->idProduct,
2411 child_ud->usb_cfg_value,
2412 first_if);
2413
2414
2415 if (ia_descr.bFunctionClass) {
2416 /* 3) usbiaVID,classFC.FSC.FPROTO */
2417 (void) sprintf(usba_name[n++],
2418 "usbia%x,class%x.%x.%x",
2419 usb_dev_descr->idVendor,
2420 ia_descr.bFunctionClass,
2421 ia_descr.bFunctionSubClass,
2422 ia_descr.bFunctionProtocol);
2423
2424 /* 4) usbiaVID,classFC.FSC */
2425 (void) sprintf(usba_name[n++],
2426 "usbia%x,class%x.%x",
2427 usb_dev_descr->idVendor,
2428 ia_descr.bFunctionClass,
2429 ia_descr.bFunctionSubClass);
2430
2431 /* 5) usbiaVID,classFC */
2432 (void) sprintf(usba_name[n++],
2433 "usbia%x,class%x",
2434 usb_dev_descr->idVendor,
2435 ia_descr.bFunctionClass);
2436
2437 /* 6) usbia,classFC.FSC.FPROTO */
2438 (void) sprintf(usba_name[n++],
2439 "usbia,class%x.%x.%x",
2440 ia_descr.bFunctionClass,
2441 ia_descr.bFunctionSubClass,
2442 ia_descr.bFunctionProtocol);
2443
2444 /* 7) usbia,classFC.FSC */
2445 (void) sprintf(usba_name[n++],
2446 "usbia,class%x.%x",
2447 ia_descr.bFunctionClass,
2448 ia_descr.bFunctionSubClass);
2449
2450 /* 8) usbia,classFC */
2451 (void) sprintf(usba_name[n++],
2452 "usbia,class%x",
2453 ia_descr.bFunctionClass);
2454 }
2455
2456 if (usba_get_ugen_binding(child_dip) ==
2457 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2458 /* 9) ugen */
2459 (void) sprintf(usba_name[n++], "ugen");
2460 } else {
2461
2462 (void) sprintf(usba_name[n++], "usb,ia");
2463 }
2464
2465 for (i = 0; i < n; i += 2) {
2466 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2467 "compatible name:\t%s\t%s", usba_name[i],
2468 (((i+1) < n)? usba_name[i+1] : ""));
2469 }
2470
2471 /* create compatible property */
2472 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2473 "compatible", (char **)usba_name, n);
2474
2475 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2476 USBA_MAX_COMPAT_NAME_LEN);
2477
2478 if (rval != DDI_PROP_SUCCESS) {
2479
2480 goto fail;
2481 }
2482
2483 /* update the address property */
2484 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2485 "assigned-address", child_ud->usb_addr);
2486 if (rval != DDI_PROP_SUCCESS) {
2487 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2488 "usba_ready_interface_node: address update failed");
2489 }
2490
2491 /* create property with first interface number */
2492 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2493 "interface", ia_descr.bFirstInterface);
2494
2495 if (rval != DDI_PROP_SUCCESS) {
2496
2497 goto fail;
2498 }
2499
2500 /* create property with the count of interfaces in this ia */
2501 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2502 "interface-count", ia_descr.bInterfaceCount);
2503
2504 if (rval != DDI_PROP_SUCCESS) {
2505
2506 goto fail;
2507 }
2508
2509 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2510 "%s%d port %d: %s, dip = 0x%p",
2511 ddi_node_name(ddi_get_parent(dip)),
2512 ddi_get_instance(ddi_get_parent(dip)),
2513 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2514
2515 *if_count = ia_descr.bInterfaceCount;
2516 usba_set_usba_device(child_dip, child_ud);
2517 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2518
2519 return (child_dip);
2520
2521 fail:
2522 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2523
2524 return (NULL);
2525 }
2526
2527
2528 /*
2529 * driver binding at interface level, the first arg will be the
2530 * the parent dip
2531 */
2532 /*ARGSUSED*/
2533 dev_info_t *
2534 usba_ready_interface_node(dev_info_t *dip, uint_t intf)
2535 {
2536 dev_info_t *child_dip = NULL;
2537 usba_device_t *child_ud = usba_get_usba_device(dip);
2538 usb_dev_descr_t *usb_dev_descr;
2539 size_t usb_cfg_length;
2540 uchar_t *usb_cfg;
2541 usb_if_descr_t if_descr;
2542 int i, n, rval;
2543 int reg[2];
2544 size_t size;
2545 usb_port_status_t port_status;
2546 char *force_bind = NULL;
2547 char *usba_name_buf = NULL;
2548 char *usba_name[USBA_MAX_COMPAT_NAMES];
2549
2550 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2551
2552 mutex_enter(&child_ud->usb_mutex);
2553
2554 usb_dev_descr = child_ud->usb_dev_descr;
2555
2556 /*
2557 * for each interface, determine all compatible names
2558 */
2559 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2560 "usba_ready_interface_node: "
2561 "port %d, interface = %d port status = %x",
2562 child_ud->usb_port, intf, child_ud->usb_port_status);
2563
2564 /* Parse the interface descriptor */
2565 size = usb_parse_if_descr(
2566 usb_cfg,
2567 usb_cfg_length,
2568 intf, /* interface index */
2569 0, /* alt interface index */
2570 &if_descr,
2571 USB_IF_DESCR_SIZE);
2572
2573 if (size != USB_IF_DESCR_SIZE) {
2574 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2575 "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
2576 size, USB_IF_DESCR_SIZE);
2577 mutex_exit(&child_ud->usb_mutex);
2578
2579 return (NULL);
2580 }
2581
2582 port_status = child_ud->usb_port_status;
2583
2584 /* create reg property */
2585 reg[0] = intf;
2586 reg[1] = child_ud->usb_cfg_value;
2587
2588 mutex_exit(&child_ud->usb_mutex);
2589
2590 /* clone this dip */
2591 rval = usba_create_child_devi(dip,
2592 "interface",
2593 NULL, /* usba_hcdi ops */
2594 NULL, /* root hub dip */
2595 port_status, /* port status */
2596 child_ud, /* share this usba_device */
2597 &child_dip);
2598
2599 if (rval != USB_SUCCESS) {
2600
2601 goto fail;
2602 }
2603
2604 rval = ndi_prop_update_int_array(
2605 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2606
2607 if (rval != DDI_PROP_SUCCESS) {
2608
2609 goto fail;
2610 }
2611
2612 usba_set_node_name(child_dip, if_descr.bInterfaceClass,
2613 if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
2614 FLAG_INTERFACE_NODE);
2615
2616 /* check force binding */
2617 if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
2618 force_bind = "ugen";
2619 }
2620
2621 /*
2622 * check whether there is another dip with this name and address
2623 */
2624 ASSERT(usba_find_existing_node(child_dip) == NULL);
2625
2626 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2627 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2628
2629 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2630 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2631 }
2632
2633 n = 0;
2634
2635 if (force_bind) {
2636 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2637 (void) strncpy(usba_name[n++], force_bind,
2638 USBA_MAX_COMPAT_NAME_LEN);
2639 }
2640
2641 /* 1) usbifVID,PID.REV.configCN.IN */
2642 (void) sprintf(usba_name[n++],
2643 "usbif%x,%x.%x.config%x.%x",
2644 usb_dev_descr->idVendor,
2645 usb_dev_descr->idProduct,
2646 usb_dev_descr->bcdDevice,
2647 child_ud->usb_cfg_value,
2648 intf);
2649
2650 /* 2) usbifVID,PID.configCN.IN */
2651 (void) sprintf(usba_name[n++],
2652 "usbif%x,%x.config%x.%x",
2653 usb_dev_descr->idVendor,
2654 usb_dev_descr->idProduct,
2655 child_ud->usb_cfg_value,
2656 intf);
2657
2658
2659 if (if_descr.bInterfaceClass) {
2660 /* 3) usbifVID,classIC.ISC.IPROTO */
2661 (void) sprintf(usba_name[n++],
2662 "usbif%x,class%x.%x.%x",
2663 usb_dev_descr->idVendor,
2664 if_descr.bInterfaceClass,
2665 if_descr.bInterfaceSubClass,
2666 if_descr.bInterfaceProtocol);
2667
2668 /* 4) usbifVID,classIC.ISC */
2669 (void) sprintf(usba_name[n++],
2670 "usbif%x,class%x.%x",
2671 usb_dev_descr->idVendor,
2672 if_descr.bInterfaceClass,
2673 if_descr.bInterfaceSubClass);
2674
2675 /* 5) usbifVID,classIC */
2676 (void) sprintf(usba_name[n++],
2677 "usbif%x,class%x",
2678 usb_dev_descr->idVendor,
2679 if_descr.bInterfaceClass);
2680
2681 /* 6) usbif,classIC.ISC.IPROTO */
2682 (void) sprintf(usba_name[n++],
2683 "usbif,class%x.%x.%x",
2684 if_descr.bInterfaceClass,
2685 if_descr.bInterfaceSubClass,
2686 if_descr.bInterfaceProtocol);
2687
2688 /* 7) usbif,classIC.ISC */
2689 (void) sprintf(usba_name[n++],
2690 "usbif,class%x.%x",
2691 if_descr.bInterfaceClass,
2692 if_descr.bInterfaceSubClass);
2693
2694 /* 8) usbif,classIC */
2695 (void) sprintf(usba_name[n++],
2696 "usbif,class%x",
2697 if_descr.bInterfaceClass);
2698 }
2699
2700 if (usba_get_ugen_binding(child_dip) ==
2701 USBA_UGEN_INTERFACE_BINDING) {
2702 /* 9) ugen */
2703 (void) sprintf(usba_name[n++], "ugen");
2704 }
2705
2706 for (i = 0; i < n; i += 2) {
2707 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2708 "compatible name:\t%s\t%s", usba_name[i],
2709 (((i+1) < n)? usba_name[i+1] : ""));
2710 }
2711
2712 /* create compatible property */
2713 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2714 "compatible", (char **)usba_name, n);
2715
2716 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2717 USBA_MAX_COMPAT_NAME_LEN);
2718
2719 if (rval != DDI_PROP_SUCCESS) {
2720
2721 goto fail;
2722 }
2723
2724 /* update the address property */
2725 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2726 "assigned-address", child_ud->usb_addr);
2727 if (rval != DDI_PROP_SUCCESS) {
2728 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2729 "usba_ready_interface_node: address update failed");
2730 }
2731
2732 /* create property with if number */
2733 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2734 "interface", intf);
2735
2736 if (rval != DDI_PROP_SUCCESS) {
2737
2738 goto fail;
2739 }
2740
2741 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2742 "%s%d port %d: %s, dip = 0x%p",
2743 ddi_node_name(ddi_get_parent(dip)),
2744 ddi_get_instance(ddi_get_parent(dip)),
2745 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2746
2747 usba_set_usba_device(child_dip, child_ud);
2748 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2749
2750 return (child_dip);
2751
2752 fail:
2753 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2754
2755 return (NULL);
2756 }
2757
2758
2759 /*
2760 * retrieve string descriptors for manufacturer, vendor and serial
2761 * number
2762 */
2763 void
2764 usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
2765 {
2766 char *tmpbuf, *str;
2767 int l;
2768 usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
2769
2770
2771 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2772 "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
2773 usb_dev_descr->iManufacturer,
2774 usb_dev_descr->iProduct,
2775 usb_dev_descr->iSerialNumber);
2776
2777 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2778
2779 /* fetch manufacturer string */
2780 if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
2781 (usb_get_string_descr(dip, USB_LANG_ID,
2782 usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
2783 USB_SUCCESS)) {
2784
2785 l = strlen(tmpbuf);
2786 if (l > 0) {
2787 str = kmem_zalloc(l + 1, KM_SLEEP);
2788 mutex_enter(&ud->usb_mutex);
2789 ud->usb_mfg_str = str;
2790 (void) strcpy(ud->usb_mfg_str, tmpbuf);
2791 mutex_exit(&ud->usb_mutex);
2792 }
2793 }
2794
2795 /* fetch product string */
2796 if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
2797 (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
2798 tmpbuf, USB_MAXSTRINGLEN) ==
2799 USB_SUCCESS)) {
2800
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_product_str = str;
2806 (void) strcpy(ud->usb_product_str, tmpbuf);
2807 mutex_exit(&ud->usb_mutex);
2808 }
2809 }
2810
2811 /* fetch device serial number string */
2812 if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
2813 (usb_get_string_descr(dip, USB_LANG_ID,
2814 usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
2815 USB_SUCCESS)) {
2816
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_serialno_str = str;
2822 (void) strcpy(ud->usb_serialno_str, tmpbuf);
2823 mutex_exit(&ud->usb_mutex);
2824 }
2825 }
2826
2827 kmem_free(tmpbuf, USB_MAXSTRINGLEN);
2828 }
2829
2830
2831 /*
2832 * usba_get_mfg_prod_sn_str:
2833 * Return a string containing mfg, product, serial number strings.
2834 * Remove duplicates if some strings are the same.
2835 *
2836 * Arguments:
2837 * dip - pointer to dev info
2838 * buffer - Where string is returned
2839 * buflen - Length of buffer
2840 *
2841 * Returns:
2842 * Same as second arg.
2843 */
2844 char *
2845 usba_get_mfg_prod_sn_str(
2846 dev_info_t *dip,
2847 char *buffer,
2848 int buflen)
2849 {
2850 usba_device_t *usba_device = usba_get_usba_device(dip);
2851 int return_len = 0;
2852 int len = 0;
2853
2854 buffer[0] = '\0';
2855 buffer[buflen-1] = '\0';
2856
2857 /* Manufacturer string exists. */
2858 if ((usba_device->usb_mfg_str) &&
2859 ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
2860 (void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
2861 return_len = min(buflen - 1, len);
2862 }
2863
2864 /* Product string exists to append. */
2865 if ((usba_device->usb_product_str) &&
2866 ((len = strlen(usba_device->usb_product_str)) != 0)) {
2867 if (return_len > 0) {
2868 buffer[return_len++] = ' ';
2869 }
2870 (void) strncpy(&buffer[return_len],
2871 usba_device->usb_product_str, buflen - return_len - 1);
2872 return_len = min(buflen - 1, return_len + len);
2873 }
2874
2875 /* Serial number string exists to append. */
2876 if ((usba_device->usb_serialno_str) &&
2877 ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
2878 if (return_len > 0) {
2879 buffer[return_len++] = ' ';
2880 }
2881 (void) strncpy(&buffer[return_len],
2882 usba_device->usb_serialno_str,
2883 buflen - return_len - 1);
2884 }
2885
2886 return (buffer);
2887 }
2888
2889
2890 /*
2891 * USB enumeration statistic functions
2892 */
2893
2894 /*
2895 * Increments the hotplug statistics based on flags.
2896 */
2897 void
2898 usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
2899 {
2900 usba_device_t *usba_device = usba_get_usba_device(dip);
2901 usba_hcdi_t *hcdi =
2902 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2903
2904 mutex_enter(&hcdi->hcdi_mutex);
2905 if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
2906 hcdi->hcdi_total_hotplug_success++;
2907 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2908 hcdi_hotplug_total_success.value.ui64++;
2909 }
2910 if (flags & USBA_HOTPLUG_SUCCESS) {
2911 hcdi->hcdi_hotplug_success++;
2912 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2913 hcdi_hotplug_success.value.ui64++;
2914 }
2915 if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
2916 hcdi->hcdi_total_hotplug_failure++;
2917 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2918 hcdi_hotplug_total_failure.value.ui64++;
2919 }
2920 if (flags & USBA_HOTPLUG_FAILURE) {
2921 hcdi->hcdi_hotplug_failure++;
2922 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2923 hcdi_hotplug_failure.value.ui64++;
2924 }
2925 mutex_exit(&hcdi->hcdi_mutex);
2926 }
2927
2928
2929 /*
2930 * Retrieve the current enumeration statistics
2931 */
2932 void
2933 usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
2934 ulong_t *success, ulong_t *total_failure, ulong_t *failure,
2935 uchar_t *device_count)
2936 {
2937 usba_device_t *usba_device = usba_get_usba_device(dip);
2938 usba_hcdi_t *hcdi =
2939 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2940
2941 mutex_enter(&hcdi->hcdi_mutex);
2942 *total_success = hcdi->hcdi_total_hotplug_success;
2943 *success = hcdi->hcdi_hotplug_success;
2944 *total_failure = hcdi->hcdi_total_hotplug_failure;
2945 *failure = hcdi->hcdi_hotplug_failure;
2946 *device_count = hcdi->hcdi_device_count;
2947 mutex_exit(&hcdi->hcdi_mutex);
2948 }
2949
2950
2951 /*
2952 * Reset the resetable hotplug stats
2953 */
2954 void
2955 usba_reset_hotplug_stats(dev_info_t *dip)
2956 {
2957 usba_device_t *usba_device = usba_get_usba_device(dip);
2958 usba_hcdi_t *hcdi =
2959 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2960 hcdi_hotplug_stats_t *hsp;
2961
2962 mutex_enter(&hcdi->hcdi_mutex);
2963 hcdi->hcdi_hotplug_success = 0;
2964 hcdi->hcdi_hotplug_failure = 0;
2965
2966 hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
2967 hsp->hcdi_hotplug_success.value.ui64 = 0;
2968 hsp->hcdi_hotplug_failure.value.ui64 = 0;
2969 mutex_exit(&hcdi->hcdi_mutex);
2970 }
2971
2972
2973 /*
2974 * usba_bind_driver():
2975 * This function calls ndi_devi_bind_driver() which tries to
2976 * bind a driver to the device. If the driver binding fails
2977 * we get an rval of NDI_UNBOUD and report an error to the
2978 * syslog that the driver failed binding.
2979 * If rval is something other than NDI_UNBOUND we report an
2980 * error to the console.
2981 *
2982 * This function returns USB_SUCCESS if no errors were
2983 * encountered while binding.
2984 */
2985 int
2986 usba_bind_driver(dev_info_t *dip)
2987 {
2988 int rval;
2989 char *name;
2990 uint8_t if_num = usba_get_ifno(dip);
2991
2992 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2993 "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
2994
2995 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2996
2997 /* bind device to the driver */
2998 if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
2999 /* if we fail to bind report an error */
3000 (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
3001 if (name[0] != '\0') {
3002 if (!usb_owns_device(dip)) {
3003 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3004 usba_log_handle,
3005 "no driver found for "
3006 "interface %d (nodename: '%s') of %s",
3007 if_num, ddi_node_name(dip), name);
3008 } else {
3009 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3010 usba_log_handle,
3011 "no driver found for device %s", name);
3012 }
3013 } else {
3014 (void) ddi_pathname(dip, name);
3015 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3016 usba_log_handle,
3017 "no driver found for device %s", name);
3018 }
3019
3020 kmem_free(name, MAXNAMELEN);
3021
3022 return (USB_FAILURE);
3023 }
3024 kmem_free(name, MAXNAMELEN);
3025
3026 return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
3027 }
3028
3029
3030 /*
3031 * usba_get_hc_dma_attr:
3032 * function returning dma attributes of the HCD
3033 *
3034 * Arguments:
3035 * dip - pointer to devinfo of the client
3036 *
3037 * Return Values:
3038 * hcdi_dma_attr
3039 */
3040 ddi_dma_attr_t *
3041 usba_get_hc_dma_attr(dev_info_t *dip)
3042 {
3043 usba_device_t *usba_device = usba_get_usba_device(dip);
3044 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
3045
3046 return (hcdi->hcdi_dma_attr);
3047 }
3048
3049
3050 /*
3051 * usba_check_for_leaks:
3052 * check usba_device structure for leaks
3053 *
3054 * Arguments:
3055 * usba_device - usba_device structure pointer
3056 */
3057 void
3058 usba_check_for_leaks(usba_device_t *usba_device)
3059 {
3060 int i, ph_open_cnt, req_wrp_leaks, iface;
3061 int leaks = 0;
3062
3063 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3064 "usba_check_for_leaks: %s%d usba_device=0x%p",
3065 ddi_driver_name(usba_device->usb_dip),
3066 ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
3067
3068 /*
3069 * default pipe is still open
3070 * all other pipes should be closed
3071 */
3072 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
3073 usba_ph_impl_t *ph_impl =
3074 &usba_device->usb_ph_list[i];
3075 if (ph_impl->usba_ph_data) {
3076 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3077 usba_log_handle,
3078 "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
3079 ddi_driver_name(ph_impl->usba_ph_data->p_dip),
3080 ddi_get_instance(ph_impl->usba_ph_data->p_dip),
3081 (void *)ph_impl,
3082 (void *)ph_impl->usba_ph_data,
3083 ph_impl->usba_ph_ep.bEndpointAddress);
3084 ph_open_cnt++;
3085 leaks++;
3086 #ifndef DEBUG
3087 usb_pipe_close(ph_impl->usba_ph_data->p_dip,
3088 (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
3089 NULL, NULL);
3090 #endif
3091 }
3092 }
3093 req_wrp_leaks = usba_list_entry_leaks(&usba_device->
3094 usb_allocated, "request wrappers");
3095
3096 ASSERT(ph_open_cnt == 0);
3097 ASSERT(req_wrp_leaks == 0);
3098
3099 if (req_wrp_leaks) {
3100 usba_list_entry_t *entry;
3101
3102 while ((entry = usba_rm_first_from_list(
3103 &usba_device->usb_allocated)) != NULL) {
3104 usba_req_wrapper_t *wrp;
3105
3106 mutex_enter(&entry->list_mutex);
3107 wrp = (usba_req_wrapper_t *)entry->private;
3108 mutex_exit(&entry->list_mutex);
3109 leaks++;
3110
3111 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3112 usba_log_handle,
3113 "%s%d: leaking request 0x%p",
3114 ddi_driver_name(wrp->wr_dip),
3115 ddi_get_instance(wrp->wr_dip),
3116 (void *)wrp->wr_req);
3117
3118 /*
3119 * put it back, usba_req_wrapper_free
3120 * expects it on the list
3121 */
3122 usba_add_to_list(&usba_device->usb_allocated,
3123 &wrp->wr_allocated_list);
3124
3125 usba_req_wrapper_free(wrp);
3126 }
3127 }
3128
3129 mutex_enter(&usba_device->usb_mutex);
3130 for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
3131 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
3132 "usba_check_for_leaks: if=%d client_flags=0x%x",
3133 iface, usba_device->usb_client_flags[iface]);
3134
3135 if (usba_device->usb_client_flags[iface] &
3136 USBA_CLIENT_FLAG_DEV_DATA) {
3137 usb_client_dev_data_list_t *entry =
3138 usba_device->usb_client_dev_data_list.cddl_next;
3139 usb_client_dev_data_list_t *next;
3140 usb_client_dev_data_t *dev_data;
3141
3142 while (entry) {
3143 dev_info_t *dip = entry->cddl_dip;
3144 next = entry->cddl_next;
3145 dev_data = entry->cddl_dev_data;
3146
3147
3148 if (!i_ddi_devi_attached(dip)) {
3149 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3150 usba_log_handle,
3151 "%s%d: leaking dev_data 0x%p",
3152 ddi_driver_name(dip),
3153 ddi_get_instance(dip),
3154 (void *)dev_data);
3155
3156 leaks++;
3157
3158 mutex_exit(&usba_device->usb_mutex);
3159 usb_free_dev_data(dip, dev_data);
3160 mutex_enter(&usba_device->usb_mutex);
3161 }
3162
3163 entry = next;
3164 }
3165 }
3166 if (usba_device->usb_client_flags[iface] &
3167 USBA_CLIENT_FLAG_ATTACH) {
3168 dev_info_t *dip = usba_device->
3169 usb_client_attach_list[iface].dip;
3170
3171 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3172 usba_log_handle,
3173 "%s%d: did no usb_client_detach",
3174 ddi_driver_name(dip), ddi_get_instance(dip));
3175 leaks++;
3176
3177 mutex_exit(&usba_device->usb_mutex);
3178 usb_client_detach(dip, NULL);
3179 mutex_enter(&usba_device->usb_mutex);
3180
3181 usba_device->
3182 usb_client_attach_list[iface].dip = NULL;
3183
3184 usba_device->usb_client_flags[iface] &=
3185 ~USBA_CLIENT_FLAG_ATTACH;
3186
3187 }
3188 if (usba_device->usb_client_flags[iface] &
3189 USBA_CLIENT_FLAG_EV_CBS) {
3190 dev_info_t *dip =
3191 usba_device->usb_client_ev_cb_list[iface].
3192 dip;
3193 usb_event_t *ev_data =
3194 usba_device->usb_client_ev_cb_list[iface].
3195 ev_data;
3196
3197 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3198 usba_log_handle,
3199 "%s%d: did no usb_unregister_event_cbs",
3200 ddi_driver_name(dip), ddi_get_instance(dip));
3201 leaks++;
3202
3203 mutex_exit(&usba_device->usb_mutex);
3204 usb_unregister_event_cbs(dip, ev_data);
3205 mutex_enter(&usba_device->usb_mutex);
3206
3207 usba_device->usb_client_ev_cb_list[iface].
3208 dip = NULL;
3209 usba_device->usb_client_ev_cb_list[iface].
3210 ev_data = NULL;
3211 usba_device->usb_client_flags[iface] &=
3212 ~USBA_CLIENT_FLAG_EV_CBS;
3213 }
3214 }
3215 mutex_exit(&usba_device->usb_mutex);
3216
3217 if (leaks) {
3218 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
3219 "all %d leaks fixed", leaks);
3220 }
3221 }