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