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 done:
1099 mutex_exit(&head->list_mutex);
1100 mutex_exit(&element->list_mutex);
1101 }
1102
1103
1104 int
usba_rm_from_list(usba_list_entry_t * head,usba_list_entry_t * element)1105 usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
1106 {
1107 usba_list_entry_t *e;
1108 int found = 0;
1109 int remaining;
1110
1111 /* find the element in the list first */
1112 mutex_enter(&head->list_mutex);
1113
1114 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1115 "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1116 (void *)head, (void *)element, head->count);
1117
1118 remaining = head->count;
1119 e = head->next;
1120
1121 while (e) {
1122 if (e == element) {
1123 found++;
1124 break;
1125 }
1126 e = e->next;
1127
1128 remaining--;
1129
1130 /* Detect incorrect circ links or found unexpected elements. */
1131 if ((e && (remaining == 0)) ||
1132 ((e == NULL) && (remaining))) {
1133 panic("Corrupted USB list at 0x%p", (void *)head);
1134 /*NOTREACHED*/
1135 }
1136 }
1137
1138 if (!found) {
1139 mutex_exit(&head->list_mutex);
1140
1141 return (USB_FAILURE);
1142 }
1143
1144 /* now remove the element */
1145 mutex_enter(&element->list_mutex);
1146
1147 if (element->next) {
1148 element->next->prev = element->prev;
1149 }
1150 if (element->prev) {
1151 element->prev->next = element->next;
1152 }
1153 if (head->next == element) {
1154 head->next = element->next;
1155 }
1156 if (head->prev == element) {
1157 head->prev = element->prev;
1158 }
1159
1160 element->prev = element->next = NULL;
1161 if (head->next == NULL) {
1162 ASSERT(head->prev == NULL);
1163 } else {
1164 ASSERT(head->next->prev == NULL);
1165 }
1166 if (head->prev == NULL) {
1167 ASSERT(head->next == NULL);
1168 } else {
1169 ASSERT(head->prev->next == NULL);
1170 }
1171
1172 head->count--;
1173
1174 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1175 "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1176 (void *)head, (void *)element, head->count);
1177
1178 mutex_exit(&element->list_mutex);
1179 mutex_exit(&head->list_mutex);
1180
1181 return (USB_SUCCESS);
1182 }
1183
1184
1185 usba_list_entry_t *
usba_rm_first_from_list(usba_list_entry_t * head)1186 usba_rm_first_from_list(usba_list_entry_t *head)
1187 {
1188 usba_list_entry_t *element = NULL;
1189
1190 if (head) {
1191 mutex_enter(&head->list_mutex);
1192 element = head->next;
1193 if (element) {
1194 /* now remove the element */
1195 mutex_enter(&element->list_mutex);
1196 head->next = element->next;
1197 if (head->next) {
1198 head->next->prev = NULL;
1199 }
1200 if (head->prev == element) {
1201 head->prev = element->next;
1202 }
1203 element->prev = element->next = NULL;
1204 mutex_exit(&element->list_mutex);
1205 head->count--;
1206 }
1207 if (head->next == NULL) {
1208 ASSERT(head->prev == NULL);
1209 } else {
1210 ASSERT(head->next->prev == NULL);
1211 }
1212 if (head->prev == NULL) {
1213 ASSERT(head->next == NULL);
1214 } else {
1215 ASSERT(head->prev->next == NULL);
1216 }
1217 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1218 "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1219 (void *)head, (void *)element, head->count);
1220
1221 mutex_exit(&head->list_mutex);
1222 }
1223
1224 return (element);
1225 }
1226
1227
1228 usb_opaque_t
usba_rm_first_pvt_from_list(usba_list_entry_t * head)1229 usba_rm_first_pvt_from_list(usba_list_entry_t *head)
1230 {
1231 usba_list_entry_t *element = usba_rm_first_from_list(head);
1232 usb_opaque_t private = NULL;
1233
1234 if (element) {
1235 mutex_enter(&element->list_mutex);
1236 private = element->private;
1237 mutex_exit(&element->list_mutex);
1238 }
1239
1240 return (private);
1241 }
1242
1243
1244 /*
1245 * move list to new list and zero original list
1246 */
1247 void
usba_move_list(usba_list_entry_t * head,usba_list_entry_t * new,ddi_iblock_cookie_t iblock_cookie)1248 usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
1249 ddi_iblock_cookie_t iblock_cookie)
1250 {
1251 usba_init_list(new, NULL, iblock_cookie);
1252 mutex_enter(&head->list_mutex);
1253 mutex_enter(&new->list_mutex);
1254
1255 new->next = head->next;
1256 new->prev = head->prev;
1257 new->count = head->count;
1258 new->private = head->private;
1259
1260 head->next = NULL;
1261 head->prev = NULL;
1262 head->count = 0;
1263 head->private = NULL;
1264 mutex_exit(&head->list_mutex);
1265 mutex_exit(&new->list_mutex);
1266 }
1267
1268
1269 int
usba_check_in_list(usba_list_entry_t * head,usba_list_entry_t * element)1270 usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
1271 {
1272 int rval = USB_FAILURE;
1273 int remaining;
1274 usba_list_entry_t *next;
1275
1276 mutex_enter(&head->list_mutex);
1277 remaining = head->count;
1278
1279 mutex_enter(&element->list_mutex);
1280 for (next = head->next; next != NULL; next = next->next) {
1281 if (next == element) {
1282 rval = USB_SUCCESS;
1283 break;
1284 }
1285 remaining--;
1286
1287 /* Detect incorrect circ links or found unexpected elements. */
1288 if ((next->next && (remaining == 0)) ||
1289 ((next->next == NULL) && remaining)) {
1290 panic("Corrupted USB list at 0x%p", (void *)head);
1291 /*NOTREACHED*/
1292 }
1293 }
1294 mutex_exit(&element->list_mutex);
1295 mutex_exit(&head->list_mutex);
1296
1297 return (rval);
1298 }
1299
1300
1301 int
usba_list_entry_leaks(usba_list_entry_t * head,char * what)1302 usba_list_entry_leaks(usba_list_entry_t *head, char *what)
1303 {
1304 int count = 0;
1305 int remaining;
1306 usba_list_entry_t *next;
1307
1308 mutex_enter(&head->list_mutex);
1309 remaining = head->count;
1310 for (next = head->next; next != NULL; next = next->next) {
1311 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1312 "leaking %s 0x%p", what, (void *)next->private);
1313 count++;
1314
1315 remaining--;
1316
1317 /* Detect incorrect circ links or found unexpected elements. */
1318 if ((next->next && (remaining == 0)) ||
1319 ((next->next == NULL) && remaining)) {
1320 panic("Corrupted USB list at 0x%p", (void *)head);
1321 /*NOTREACHED*/
1322 }
1323 }
1324 ASSERT(count == head->count);
1325 mutex_exit(&head->list_mutex);
1326
1327 if (count) {
1328 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1329 "usba_list_entry_count: leaking %d", count);
1330 }
1331
1332 return (count);
1333 }
1334
1335
1336 int
usba_list_entry_count(usba_list_entry_t * head)1337 usba_list_entry_count(usba_list_entry_t *head)
1338 {
1339 int count;
1340
1341 mutex_enter(&head->list_mutex);
1342 count = head->count;
1343 mutex_exit(&head->list_mutex);
1344
1345 return (count);
1346 }
1347
1348 /* add a new root hub to the usba_root_hubs list */
1349
1350 void
usba_add_root_hub(dev_info_t * dip)1351 usba_add_root_hub(dev_info_t *dip)
1352 {
1353 usba_root_hub_ent_t *hub;
1354
1355 hub = (usba_root_hub_ent_t *)
1356 kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
1357
1358 mutex_enter(&usba_hub_mutex);
1359 hub->dip = dip;
1360 hub->next = usba_root_hubs;
1361 usba_root_hubs = hub;
1362 mutex_exit(&usba_hub_mutex);
1363 }
1364
1365 /* remove a root hub from the usba_root_hubs list */
1366
1367 void
usba_rem_root_hub(dev_info_t * dip)1368 usba_rem_root_hub(dev_info_t *dip)
1369 {
1370 usba_root_hub_ent_t **hubp, *hub;
1371
1372 mutex_enter(&usba_hub_mutex);
1373 hubp = &usba_root_hubs;
1374 while (*hubp) {
1375 if ((*hubp)->dip == dip) {
1376 hub = *hubp;
1377 *hubp = hub->next;
1378 kmem_free(hub, sizeof (struct usba_root_hub_ent));
1379 mutex_exit(&usba_hub_mutex);
1380
1381 return;
1382 }
1383 hubp = &(*hubp)->next;
1384 }
1385 mutex_exit(&usba_hub_mutex);
1386 }
1387
1388 /*
1389 * check whether this dip is the root hub. Any root hub known by
1390 * usba is recorded in the linked list pointed to by usba_root_hubs
1391 */
1392 int
usba_is_root_hub(dev_info_t * dip)1393 usba_is_root_hub(dev_info_t *dip)
1394 {
1395 usba_root_hub_ent_t *hub;
1396
1397 mutex_enter(&usba_hub_mutex);
1398 hub = usba_root_hubs;
1399 while (hub) {
1400 if (hub->dip == dip) {
1401 mutex_exit(&usba_hub_mutex);
1402
1403 return (1);
1404 }
1405 hub = hub->next;
1406 }
1407 mutex_exit(&usba_hub_mutex);
1408
1409 return (0);
1410 }
1411
1412 /*
1413 * get and store usba_device pointer in the devi
1414 */
1415 usba_device_t *
usba_get_usba_device(dev_info_t * dip)1416 usba_get_usba_device(dev_info_t *dip)
1417 {
1418 /*
1419 * we cannot use parent_data in the usb node because its
1420 * bus parent (eg. PCI nexus driver) uses this data
1421 *
1422 * we cannot use driver data in the other usb nodes since
1423 * usb drivers may need to use this
1424 */
1425 if (usba_is_root_hub(dip)) {
1426 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1427
1428 return (hcdi->hcdi_usba_device);
1429 } else {
1430
1431 return (ddi_get_parent_data(dip));
1432 }
1433 }
1434
1435
1436 /*
1437 * Retrieve the usba_device pointer from the dev without checking for
1438 * the root hub first. This function is only used in polled mode.
1439 */
1440 usba_device_t *
usba_polled_get_usba_device(dev_info_t * dip)1441 usba_polled_get_usba_device(dev_info_t *dip)
1442 {
1443 /*
1444 * Don't call usba_is_root_hub() to find out if this is
1445 * the root hub usba_is_root_hub() calls into the DDI
1446 * where there are locking issues. The dip sent in during
1447 * polled mode will never be the root hub, so just get
1448 * the usba_device pointer from the dip.
1449 */
1450 return (ddi_get_parent_data(dip));
1451 }
1452
1453
1454 void
usba_set_usba_device(dev_info_t * dip,usba_device_t * usba_device)1455 usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
1456 {
1457 if (usba_is_root_hub(dip)) {
1458 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1459 /* no locking is needed here */
1460 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1461 hcdi->hcdi_usba_device = usba_device;
1462 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1463 } else {
1464 ddi_set_parent_data(dip, usba_device);
1465 }
1466 }
1467
1468
1469 /*
1470 * usba_set_node_name() according to class, subclass, and protocol
1471 * following the 1275 USB binding tables.
1472 */
1473
1474 /* device node table, refer to section 3.2.2.1 of 1275 binding */
1475 static node_name_entry_t device_node_name_table[] = {
1476 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1477 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1478 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1479 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1480 { DONTCARE, DONTCARE, DONTCARE, "device" }
1481 };
1482
1483 /* interface-association node table */
1484 static node_name_entry_t ia_node_name_table[] = {
1485 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "audio" },
1486 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1487 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
1488 "device-wire-adaptor" },
1489 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless-controller" },
1490 { DONTCARE, DONTCARE, DONTCARE, "interface-association" }
1491 };
1492
1493 /* interface node table, refer to section 3.3.2.1 */
1494 static node_name_entry_t if_node_name_table[] = {
1495 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1496 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1497 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1498 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1499
1500 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1501 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1502 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1503 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1504 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1505 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1506 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1507 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1508
1509 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1510 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1511 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1512
1513 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1514
1515 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1516
1517 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1518
1519 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1520
1521 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1522
1523 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1524
1525 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1526
1527 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1528 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1529 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1530
1531 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1532 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1533 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1534
1535 { USB_CLASS_MISC, USB_SUBCLS_CBAF, USB_PROTO_CBAF, "wusb_ca"},
1536 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
1537 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
1538 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
1539 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
1540 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
1541
1542 { DONTCARE, DONTCARE, DONTCARE, "interface" },
1543
1544 };
1545
1546 /* combined node table, refer to section 3.4.2.1 */
1547 static node_name_entry_t combined_node_name_table[] = {
1548 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
1549 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1550 { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1551 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
1552
1553 { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
1554 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
1555 { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1556 { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1557 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
1558 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
1559 { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1560 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1561
1562 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1563 { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
1564 { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
1565
1566 { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
1567
1568 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1569
1570 { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
1571
1572 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10, DONTCARE, "storage" },
1573 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I, DONTCARE, "cdrom" },
1574 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157, DONTCARE, "tape" },
1575 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI, DONTCARE, "floppy" },
1576 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I, DONTCARE, "storage" },
1577 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI, DONTCARE, "storage" },
1578 { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
1579
1580 { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
1581
1582 { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
1583
1584 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1585 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1586 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1587
1588 { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1589 { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
1590 { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
1591
1592 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1593 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1594 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1595 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1596 { DONTCARE, DONTCARE, DONTCARE, "device" }
1597 };
1598
1599 static size_t device_node_name_table_size =
1600 sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1601 static size_t ia_node_name_table_size =
1602 sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
1603 static size_t if_node_name_table_size =
1604 sizeof (if_node_name_table)/sizeof (struct node_name_entry);
1605 static size_t combined_node_name_table_size =
1606 sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
1607
1608
1609 static void
usba_set_node_name(dev_info_t * dip,uint8_t class,uint8_t subclass,uint8_t protocol,uint_t flag)1610 usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
1611 uint8_t protocol, uint_t flag)
1612 {
1613 int i;
1614 size_t size;
1615 node_name_entry_t *node_name_table;
1616
1617 switch (flag) {
1618 /* interface share node names with interface-association */
1619 case FLAG_INTERFACE_ASSOCIATION_NODE:
1620 node_name_table = ia_node_name_table;
1621 size = ia_node_name_table_size;
1622 break;
1623 case FLAG_INTERFACE_NODE:
1624 node_name_table = if_node_name_table;
1625 size = if_node_name_table_size;
1626 break;
1627 case FLAG_DEVICE_NODE:
1628 node_name_table = device_node_name_table;
1629 size = device_node_name_table_size;
1630 break;
1631 case FLAG_COMBINED_NODE:
1632 node_name_table = combined_node_name_table;
1633 size = combined_node_name_table_size;
1634 break;
1635 default:
1636
1637 return;
1638 }
1639
1640 for (i = 0; i < size; i++) {
1641 int16_t c = node_name_table[i].class;
1642 int16_t s = node_name_table[i].subclass;
1643 int16_t p = node_name_table[i].protocol;
1644
1645 if (((c == DONTCARE) || (c == class)) &&
1646 ((s == DONTCARE) || (s == subclass)) &&
1647 ((p == DONTCARE) || (p == protocol))) {
1648 char *name = node_name_table[i].name;
1649
1650 (void) ndi_devi_set_nodename(dip, name, 0);
1651 break;
1652 }
1653 }
1654 }
1655
1656
1657 #ifdef DEBUG
1658 /*
1659 * walk the children of the parent of this devi and compare the
1660 * name and reg property of each child. If there is a match
1661 * return this node
1662 */
1663 static dev_info_t *
usba_find_existing_node(dev_info_t * odip)1664 usba_find_existing_node(dev_info_t *odip)
1665 {
1666 dev_info_t *ndip, *child, *pdip;
1667 int *odata, *ndata;
1668 uint_t n_odata, n_ndata;
1669
1670 pdip = ddi_get_parent(odip);
1671 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1672 odip, DDI_PROP_DONTPASS, "reg",
1673 &odata, &n_odata) != DDI_SUCCESS) {
1674 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1675 "usba_find_existing_node: "
1676 "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
1677
1678 return (NULL);
1679 }
1680
1681 ndi_devi_enter(pdip);
1682 ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
1683 while ((child = ndip) != NULL) {
1684
1685 ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
1686
1687 if (child == odip) {
1688 continue;
1689 }
1690
1691 if (strcmp(DEVI(child)->devi_node_name,
1692 DEVI(odip)->devi_node_name)) {
1693 continue;
1694 }
1695
1696 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1697 child, DDI_PROP_DONTPASS, "reg",
1698 &ndata, &n_ndata) != DDI_SUCCESS) {
1699
1700 USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1701 "usba_find_existing_node: "
1702 "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
1703
1704 } else if (n_ndata && n_odata && (bcmp(odata, ndata,
1705 max(n_odata, n_ndata) * sizeof (int)) == 0)) {
1706
1707 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1708 "usba_find_existing_node: found %s%d (%p)",
1709 ddi_driver_name(child),
1710 ddi_get_instance(child), (void *)child);
1711
1712 USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1713 "usba_find_existing_node: "
1714 "reg: %x %x %x - %x %x %x",
1715 n_odata, odata[0], odata[1],
1716 n_ndata, ndata[0], ndata[1]);
1717
1718 ddi_prop_free(ndata);
1719 break;
1720
1721 } else {
1722 ddi_prop_free(ndata);
1723 }
1724 }
1725
1726 ndi_devi_exit(pdip);
1727
1728 ddi_prop_free(odata);
1729
1730 return (child);
1731 }
1732 #endif
1733
1734 /* change all unprintable characters to spaces */
1735 static void
usba_filter_string(char * instr,char * outstr)1736 usba_filter_string(char *instr, char *outstr)
1737 {
1738 while (*instr) {
1739 if ((*instr >= ' ') && (*instr <= '~')) {
1740 *outstr = *instr;
1741 } else {
1742 *outstr = ' ';
1743 }
1744 outstr++;
1745 instr++;
1746 }
1747 *outstr = '\0';
1748 }
1749
1750
1751 /*
1752 * lookup ugen binding specified in property in
1753 * hcd.conf files
1754 */
1755 int
usba_get_ugen_binding(dev_info_t * dip)1756 usba_get_ugen_binding(dev_info_t *dip)
1757 {
1758 usba_device_t *usba_device = usba_get_usba_device(dip);
1759 usba_hcdi_t *hcdi =
1760 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
1761
1762 return (hcdi->hcdi_ugen_default_binding);
1763 }
1764
1765
1766 /*
1767 * driver binding support at device level
1768 */
1769 dev_info_t *
usba_ready_device_node(dev_info_t * child_dip)1770 usba_ready_device_node(dev_info_t *child_dip)
1771 {
1772 int rval, i;
1773 int n = 0;
1774 usba_device_t *usba_device = usba_get_usba_device(child_dip);
1775 usb_dev_descr_t *usb_dev_descr;
1776 uint_t n_cfgs; /* number of configs */
1777 uint_t n_ifs; /* number of interfaces */
1778 uint_t port, bus_num;
1779 size_t usb_config_length;
1780 uchar_t *usb_config;
1781 int reg[1];
1782 usb_addr_t address = usb_get_addr(child_dip);
1783 usb_if_descr_t if_descr;
1784 size_t size;
1785 int combined_node = 0;
1786 int is_hub;
1787 char *devprop_str;
1788 char *force_bind = NULL;
1789 char *usba_name_buf = NULL;
1790 char *usba_name[USBA_MAX_COMPAT_NAMES];
1791
1792 usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
1793
1794 mutex_enter(&usba_device->usb_mutex);
1795 mutex_enter(&usba_mutex);
1796
1797 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1798 "usba_ready_device_node: child=0x%p", (void *)child_dip);
1799
1800 port = usba_device->usb_port;
1801 usb_dev_descr = usba_device->usb_dev_descr;
1802 n_cfgs = usba_device->usb_n_cfgs;
1803 n_ifs = usba_device->usb_n_ifs;
1804 bus_num = usba_device->usb_addr;
1805
1806 if (address != ROOT_HUB_ADDR) {
1807 size = usb_parse_if_descr(
1808 usb_config,
1809 usb_config_length,
1810 0, /* interface index */
1811 0, /* alt interface index */
1812 &if_descr,
1813 USB_IF_DESCR_SIZE);
1814
1815 if (size != USB_IF_DESCR_SIZE) {
1816 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1817 "parsing interface: "
1818 "size (%lu) != USB_IF_DESCR_SIZE (%d)",
1819 size, USB_IF_DESCR_SIZE);
1820
1821 mutex_exit(&usba_mutex);
1822 mutex_exit(&usba_device->usb_mutex);
1823
1824 return (child_dip);
1825 }
1826 } else {
1827 /* fake an interface descriptor for the root hub */
1828 bzero(&if_descr, sizeof (if_descr));
1829
1830 if_descr.bInterfaceClass = USB_CLASS_HUB;
1831 }
1832
1833 reg[0] = port;
1834
1835 mutex_exit(&usba_mutex);
1836 mutex_exit(&usba_device->usb_mutex);
1837
1838 rval = ndi_prop_update_int_array(
1839 DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
1840
1841 if (rval != DDI_PROP_SUCCESS) {
1842 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
1843 "usba_ready_device_node: property update failed");
1844
1845 return (child_dip);
1846 }
1847
1848 combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
1849 ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
1850 (usb_dev_descr->bDeviceClass == 0)));
1851
1852 is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
1853 (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
1854
1855 /* set node name */
1856 if (combined_node) {
1857 usba_set_node_name(child_dip,
1858 if_descr.bInterfaceClass,
1859 if_descr.bInterfaceSubClass,
1860 if_descr.bInterfaceProtocol,
1861 FLAG_COMBINED_NODE);
1862 } else {
1863 usba_set_node_name(child_dip,
1864 usb_dev_descr->bDeviceClass,
1865 usb_dev_descr->bDeviceSubClass,
1866 usb_dev_descr->bDeviceProtocol,
1867 FLAG_DEVICE_NODE);
1868 }
1869
1870 /*
1871 * check force binding rules
1872 */
1873 if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
1874 (address != usba_ddivs_usbc_xaddress) &&
1875 (!(usba_ddivs_usbc_xhubs && is_hub))) {
1876 force_bind = "ddivs_usbc";
1877 (void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
1878
1879 } else if (usba_device->usb_preferred_driver) {
1880 force_bind = usba_device->usb_preferred_driver;
1881
1882 } else if ((address != ROOT_HUB_ADDR) &&
1883 ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
1884 ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
1885 combined_node)) && (!is_hub)) {
1886 force_bind = "ugen";
1887 }
1888
1889 #ifdef DEBUG
1890 /*
1891 * check whether there is another dip with this name and address
1892 * If the dip contains usba_device, it is held by the previous
1893 * round of configuration.
1894 */
1895 ASSERT(usba_find_existing_node(child_dip) == NULL);
1896 #endif
1897
1898 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
1899 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
1900
1901 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
1902 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
1903 }
1904
1905 if (force_bind) {
1906 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
1907 (void) strncpy(usba_name[n++], force_bind,
1908 USBA_MAX_COMPAT_NAME_LEN);
1909 }
1910
1911 /*
1912 * If the callback function of specified driver is registered,
1913 * it will be called here to check whether to take over the device.
1914 */
1915 if (usb_cap.usba_dev_driver_cb != NULL) {
1916 char *dev_drv = NULL;
1917 usb_dev_str_t dev_str;
1918 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1919
1920 dev_str.usb_mfg = usba_device->usb_mfg_str;
1921 dev_str.usb_product = usba_device->usb_product_str;
1922 dev_str.usb_serialno = usba_device->usb_serialno_str;
1923
1924 (void) ddi_pathname(child_dip, pathname);
1925
1926 if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1927 pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1928 (dev_drv != NULL)) {
1929 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1930 "usba_ready_device_node: dev_driver=%s, port =%d,"
1931 "bus =%d, path=%s\n\t",
1932 dev_drv, port, bus_num, pathname);
1933
1934 (void) strncpy(usba_name[n++], dev_drv,
1935 USBA_MAX_COMPAT_NAME_LEN);
1936 }
1937 kmem_free(pathname, MAXPATHLEN);
1938 }
1939
1940 /* create compatible names */
1941 if (combined_node) {
1942
1943 /* 1. usbVID,PID.REV */
1944 (void) sprintf(usba_name[n++],
1945 "usb%x,%x.%x",
1946 usb_dev_descr->idVendor,
1947 usb_dev_descr->idProduct,
1948 usb_dev_descr->bcdDevice);
1949
1950 /* 2. usbVID,PID */
1951 (void) sprintf(usba_name[n++],
1952 "usb%x,%x",
1953 usb_dev_descr->idVendor,
1954 usb_dev_descr->idProduct);
1955
1956 if (usb_dev_descr->bDeviceClass != 0) {
1957 /* 3. usbVID,classDC.DSC.DPROTO */
1958 (void) sprintf(usba_name[n++],
1959 "usb%x,class%x.%x.%x",
1960 usb_dev_descr->idVendor,
1961 usb_dev_descr->bDeviceClass,
1962 usb_dev_descr->bDeviceSubClass,
1963 usb_dev_descr->bDeviceProtocol);
1964
1965 /* 4. usbVID,classDC.DSC */
1966 (void) sprintf(usba_name[n++],
1967 "usb%x,class%x.%x",
1968 usb_dev_descr->idVendor,
1969 usb_dev_descr->bDeviceClass,
1970 usb_dev_descr->bDeviceSubClass);
1971
1972 /* 5. usbVID,classDC */
1973 (void) sprintf(usba_name[n++],
1974 "usb%x,class%x",
1975 usb_dev_descr->idVendor,
1976 usb_dev_descr->bDeviceClass);
1977
1978 /* 6. usb,classDC.DSC.DPROTO */
1979 (void) sprintf(usba_name[n++],
1980 "usb,class%x.%x.%x",
1981 usb_dev_descr->bDeviceClass,
1982 usb_dev_descr->bDeviceSubClass,
1983 usb_dev_descr->bDeviceProtocol);
1984
1985 /* 7. usb,classDC.DSC */
1986 (void) sprintf(usba_name[n++],
1987 "usb,class%x.%x",
1988 usb_dev_descr->bDeviceClass,
1989 usb_dev_descr->bDeviceSubClass);
1990
1991 /* 8. usb,classDC */
1992 (void) sprintf(usba_name[n++],
1993 "usb,class%x",
1994 usb_dev_descr->bDeviceClass);
1995 }
1996
1997 if (if_descr.bInterfaceClass != 0) {
1998 /* 9. usbifVID,classIC.ISC.IPROTO */
1999 (void) sprintf(usba_name[n++],
2000 "usbif%x,class%x.%x.%x",
2001 usb_dev_descr->idVendor,
2002 if_descr.bInterfaceClass,
2003 if_descr.bInterfaceSubClass,
2004 if_descr.bInterfaceProtocol);
2005
2006 /* 10. usbifVID,classIC.ISC */
2007 (void) sprintf(usba_name[n++],
2008 "usbif%x,class%x.%x",
2009 usb_dev_descr->idVendor,
2010 if_descr.bInterfaceClass,
2011 if_descr.bInterfaceSubClass);
2012
2013 /* 11. usbifVID,classIC */
2014 (void) sprintf(usba_name[n++],
2015 "usbif%x,class%x",
2016 usb_dev_descr->idVendor,
2017 if_descr.bInterfaceClass);
2018
2019 /* 12. usbif,classIC.ISC.IPROTO */
2020 (void) sprintf(usba_name[n++],
2021 "usbif,class%x.%x.%x",
2022 if_descr.bInterfaceClass,
2023 if_descr.bInterfaceSubClass,
2024 if_descr.bInterfaceProtocol);
2025
2026 /* 13. usbif,classIC.ISC */
2027 (void) sprintf(usba_name[n++],
2028 "usbif,class%x.%x",
2029 if_descr.bInterfaceClass,
2030 if_descr.bInterfaceSubClass);
2031
2032 /* 14. usbif,classIC */
2033 (void) sprintf(usba_name[n++],
2034 "usbif,class%x",
2035 if_descr.bInterfaceClass);
2036 }
2037
2038 /* 15. ugen or usb_mid */
2039 if (usba_get_ugen_binding(child_dip) ==
2040 USBA_UGEN_DEVICE_BINDING) {
2041 (void) sprintf(usba_name[n++], "ugen");
2042 } else {
2043 (void) sprintf(usba_name[n++], "usb,device");
2044 }
2045
2046 } else {
2047 if (n_cfgs > 1) {
2048 /* 1. usbVID,PID.REV.configCN */
2049 (void) sprintf(usba_name[n++],
2050 "usb%x,%x.%x.config%x",
2051 usb_dev_descr->idVendor,
2052 usb_dev_descr->idProduct,
2053 usb_dev_descr->bcdDevice,
2054 usba_device->usb_cfg_value);
2055 }
2056
2057 /* 2. usbVID,PID.REV */
2058 (void) sprintf(usba_name[n++],
2059 "usb%x,%x.%x",
2060 usb_dev_descr->idVendor,
2061 usb_dev_descr->idProduct,
2062 usb_dev_descr->bcdDevice);
2063
2064 /* 3. usbVID,PID.configCN */
2065 if (n_cfgs > 1) {
2066 (void) sprintf(usba_name[n++],
2067 "usb%x,%x.%x",
2068 usb_dev_descr->idVendor,
2069 usb_dev_descr->idProduct,
2070 usba_device->usb_cfg_value);
2071 }
2072
2073 /* 4. usbVID,PID */
2074 (void) sprintf(usba_name[n++],
2075 "usb%x,%x",
2076 usb_dev_descr->idVendor,
2077 usb_dev_descr->idProduct);
2078
2079 if (usb_dev_descr->bDeviceClass != 0) {
2080 /* 5. usbVID,classDC.DSC.DPROTO */
2081 (void) sprintf(usba_name[n++],
2082 "usb%x,class%x.%x.%x",
2083 usb_dev_descr->idVendor,
2084 usb_dev_descr->bDeviceClass,
2085 usb_dev_descr->bDeviceSubClass,
2086 usb_dev_descr->bDeviceProtocol);
2087
2088 /* 6. usbVID,classDC.DSC */
2089 (void) sprintf(usba_name[n++],
2090 "usb%x.class%x.%x",
2091 usb_dev_descr->idVendor,
2092 usb_dev_descr->bDeviceClass,
2093 usb_dev_descr->bDeviceSubClass);
2094
2095 /* 7. usbVID,classDC */
2096 (void) sprintf(usba_name[n++],
2097 "usb%x.class%x",
2098 usb_dev_descr->idVendor,
2099 usb_dev_descr->bDeviceClass);
2100
2101 /* 8. usb,classDC.DSC.DPROTO */
2102 (void) sprintf(usba_name[n++],
2103 "usb,class%x.%x.%x",
2104 usb_dev_descr->bDeviceClass,
2105 usb_dev_descr->bDeviceSubClass,
2106 usb_dev_descr->bDeviceProtocol);
2107
2108 /* 9. usb,classDC.DSC */
2109 (void) sprintf(usba_name[n++],
2110 "usb,class%x.%x",
2111 usb_dev_descr->bDeviceClass,
2112 usb_dev_descr->bDeviceSubClass);
2113
2114 /* 10. usb,classDC */
2115 (void) sprintf(usba_name[n++],
2116 "usb,class%x",
2117 usb_dev_descr->bDeviceClass);
2118 }
2119
2120 if (usba_get_ugen_binding(child_dip) ==
2121 USBA_UGEN_DEVICE_BINDING) {
2122 /* 11. ugen */
2123 (void) sprintf(usba_name[n++], "ugen");
2124 } else {
2125 /* 11. usb,device */
2126 (void) sprintf(usba_name[n++], "usb,device");
2127 }
2128 }
2129
2130 for (i = 0; i < n; i += 2) {
2131 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2132 "compatible name:\t%s\t%s", usba_name[i],
2133 (((i+1) < n)? usba_name[i+1] : ""));
2134 }
2135
2136 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2137 "compatible", (char **)usba_name, n);
2138
2139 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2140 USBA_MAX_COMPAT_NAME_LEN);
2141
2142 if (rval != DDI_PROP_SUCCESS) {
2143
2144 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2145 "usba_ready_device_node: property update failed");
2146
2147 return (child_dip);
2148 }
2149
2150 /* update the address property */
2151 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2152 "assigned-address", usba_device->usb_addr);
2153 if (rval != DDI_PROP_SUCCESS) {
2154 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2155 "usba_ready_device_node: address update failed");
2156 }
2157
2158 /* update the usb device properties (PSARC/2000/454) */
2159 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2160 "usb-vendor-id", usb_dev_descr->idVendor);
2161 if (rval != DDI_PROP_SUCCESS) {
2162 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2163 "usba_ready_device_node: usb-vendor-id update failed");
2164 }
2165
2166 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2167 "usb-product-id", usb_dev_descr->idProduct);
2168 if (rval != DDI_PROP_SUCCESS) {
2169 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2170 "usba_ready_device_node: usb-product-id update failed");
2171 }
2172
2173 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2174 "usb-revision-id", usb_dev_descr->bcdDevice);
2175 if (rval != DDI_PROP_SUCCESS) {
2176 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2177 "usba_ready_device_node: usb-revision-id update failed");
2178 }
2179
2180 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2181 "usb-num-configs", usb_dev_descr->bNumConfigurations);
2182 if (rval != DDI_PROP_SUCCESS) {
2183 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2184 "usba_ready_device_node: usb-num-configs update failed");
2185 }
2186
2187 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2188 "usb-release", usb_dev_descr->bcdUSB);
2189 if (rval != DDI_PROP_SUCCESS) {
2190 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2191 "usba_ready_device_node: usb-release update failed");
2192 }
2193
2194 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2195 "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
2196 sizeof (usb_dev_descr_t));
2197 if (rval != DDI_PROP_SUCCESS) {
2198 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2199 "usba_ready_device_node: usb-descriptor update failed");
2200 }
2201
2202 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2203 "usb-raw-cfg-descriptors", usb_config, usb_config_length);
2204 if (rval != DDI_PROP_SUCCESS) {
2205 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2206 "usba_ready_device_node: usb-raw-cfg-descriptors update "
2207 "failed");
2208 }
2209
2210 devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2211
2212 if (usba_device->usb_serialno_str) {
2213 usba_filter_string(usba_device->usb_serialno_str, devprop_str);
2214 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2215 "usb-serialno", devprop_str);
2216 if (rval != DDI_PROP_SUCCESS) {
2217 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2218 "usba_ready_device_node: "
2219 "usb-serialno update failed");
2220 }
2221 }
2222
2223 if (usba_device->usb_mfg_str) {
2224 usba_filter_string(usba_device->usb_mfg_str, devprop_str);
2225 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2226 "usb-vendor-name", devprop_str);
2227 if (rval != DDI_PROP_SUCCESS) {
2228 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2229 "usba_ready_device_node: "
2230 "usb-vendor-name update failed");
2231 }
2232 }
2233
2234 if (usba_device->usb_product_str) {
2235 usba_filter_string(usba_device->usb_product_str, devprop_str);
2236 rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2237 "usb-product-name", devprop_str);
2238 if (rval != DDI_PROP_SUCCESS) {
2239 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2240 "usba_ready_device_node: "
2241 "usb-product-name update failed");
2242 }
2243 }
2244
2245 kmem_free(devprop_str, USB_MAXSTRINGLEN);
2246
2247 if (!combined_node) {
2248 /* update the configuration property */
2249 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2250 "configuration#", usba_device->usb_cfg_value);
2251 if (rval != DDI_PROP_SUCCESS) {
2252 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2253 "usba_ready_device_node: "
2254 "config prop update failed");
2255 }
2256 }
2257
2258 if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
2259 /* create boolean property */
2260 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2261 "low-speed");
2262 if (rval != DDI_PROP_SUCCESS) {
2263 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2264 "usba_ready_device_node: "
2265 "low speed prop update failed");
2266 }
2267 }
2268
2269 if (usba_device->usb_port_status == USBA_FULL_SPEED_DEV) {
2270 /* create boolean property */
2271 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2272 "full-speed");
2273 if (rval != DDI_PROP_SUCCESS) {
2274 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2275 "usba_ready_device_node: "
2276 "full speed prop update failed");
2277 }
2278 }
2279
2280 if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
2281 /* create boolean property */
2282 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2283 "high-speed");
2284 if (rval != DDI_PROP_SUCCESS) {
2285 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2286 "usba_ready_device_node: "
2287 "high speed prop update failed");
2288 }
2289 }
2290
2291 if (usba_device->usb_port_status == USBA_SUPER_SPEED_DEV) {
2292 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2293 "super-speed");
2294 if (rval != DDI_PROP_SUCCESS) {
2295 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2296 "usba_ready_device_node: "
2297 "super speed prop update failed");
2298 }
2299 }
2300
2301 usba_add_binary_object_store_props(child_dip, usba_device);
2302
2303 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2304 "%s%d at port %d: %s, dip=0x%p",
2305 ddi_node_name(ddi_get_parent(child_dip)),
2306 ddi_get_instance(ddi_get_parent(child_dip)),
2307 port, ddi_node_name(child_dip), (void *)child_dip);
2308
2309 usba_set_usba_device(child_dip, usba_device);
2310
2311 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2312
2313 return (child_dip);
2314 }
2315
2316
2317 /*
2318 * driver binding at interface association level. the first arg is the parent
2319 * dip. if_count returns amount of interfaces which are associated within
2320 * this interface-association that starts from first_if.
2321 */
2322 /*ARGSUSED*/
2323 dev_info_t *
usba_ready_interface_association_node(dev_info_t * dip,uint_t first_if,uint_t * if_count)2324 usba_ready_interface_association_node(
2325 dev_info_t *dip,
2326 uint_t first_if,
2327 uint_t *if_count)
2328 {
2329 dev_info_t *child_dip = NULL;
2330 usba_device_t *child_ud = usba_get_usba_device(dip);
2331 usb_dev_descr_t *usb_dev_descr;
2332 size_t usb_cfg_length;
2333 uchar_t *usb_cfg;
2334 usb_ia_descr_t ia_descr;
2335 int i, n, rval;
2336 int reg[2];
2337 size_t size;
2338 usb_port_status_t port_status;
2339 char *force_bind = NULL;
2340 char *usba_name_buf = NULL;
2341 char *usba_name[USBA_MAX_COMPAT_NAMES];
2342
2343 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2344
2345 mutex_enter(&child_ud->usb_mutex);
2346
2347 usb_dev_descr = child_ud->usb_dev_descr;
2348
2349 /*
2350 * for each interface association, determine all compatible names
2351 */
2352 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2353 "usba_ready_ia_node: "
2354 "port %d, interface = %d, port_status = %x",
2355 child_ud->usb_port, first_if, child_ud->usb_port_status);
2356
2357 /* Parse the interface descriptor */
2358 size = usb_parse_ia_descr(
2359 usb_cfg,
2360 usb_cfg_length,
2361 first_if, /* interface index */
2362 &ia_descr,
2363 USB_IA_DESCR_SIZE);
2364
2365 *if_count = 1;
2366 if (size != USB_IA_DESCR_SIZE) {
2367 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2368 "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2369 size, USB_IA_DESCR_SIZE);
2370 mutex_exit(&child_ud->usb_mutex);
2371
2372 return (NULL);
2373 }
2374
2375 port_status = child_ud->usb_port_status;
2376
2377 /* create reg property */
2378 reg[0] = first_if;
2379 reg[1] = child_ud->usb_cfg_value;
2380
2381 mutex_exit(&child_ud->usb_mutex);
2382
2383 /* clone this dip */
2384 rval = usba_create_child_devi(dip,
2385 "interface-association",
2386 NULL, /* usba_hcdi ops */
2387 NULL, /* root hub dip */
2388 port_status, /* port status */
2389 child_ud, /* share this usba_device */
2390 &child_dip);
2391
2392 if (rval != USB_SUCCESS) {
2393
2394 goto fail;
2395 }
2396
2397 rval = ndi_prop_update_int_array(
2398 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2399
2400 if (rval != DDI_PROP_SUCCESS) {
2401
2402 goto fail;
2403 }
2404
2405 usba_set_node_name(child_dip, ia_descr.bFunctionClass,
2406 ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
2407 FLAG_INTERFACE_ASSOCIATION_NODE);
2408
2409 /* check force binding */
2410 if (usba_ugen_force_binding ==
2411 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2412 force_bind = "ugen";
2413 }
2414
2415 /*
2416 * check whether there is another dip with this name and address
2417 */
2418 ASSERT(usba_find_existing_node(child_dip) == NULL);
2419
2420 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2421 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2422
2423 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2424 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2425 }
2426
2427 n = 0;
2428
2429 if (force_bind) {
2430 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2431 (void) strncpy(usba_name[n++], force_bind,
2432 USBA_MAX_COMPAT_NAME_LEN);
2433 }
2434
2435 /* 1) usbiaVID,PID.REV.configCN.FN */
2436 (void) sprintf(usba_name[n++],
2437 "usbia%x,%x.%x.config%x.%x",
2438 usb_dev_descr->idVendor,
2439 usb_dev_descr->idProduct,
2440 usb_dev_descr->bcdDevice,
2441 child_ud->usb_cfg_value,
2442 first_if);
2443
2444 /* 2) usbiaVID,PID.configCN.FN */
2445 (void) sprintf(usba_name[n++],
2446 "usbia%x,%x.config%x.%x",
2447 usb_dev_descr->idVendor,
2448 usb_dev_descr->idProduct,
2449 child_ud->usb_cfg_value,
2450 first_if);
2451
2452
2453 if (ia_descr.bFunctionClass) {
2454 /* 3) usbiaVID,classFC.FSC.FPROTO */
2455 (void) sprintf(usba_name[n++],
2456 "usbia%x,class%x.%x.%x",
2457 usb_dev_descr->idVendor,
2458 ia_descr.bFunctionClass,
2459 ia_descr.bFunctionSubClass,
2460 ia_descr.bFunctionProtocol);
2461
2462 /* 4) usbiaVID,classFC.FSC */
2463 (void) sprintf(usba_name[n++],
2464 "usbia%x,class%x.%x",
2465 usb_dev_descr->idVendor,
2466 ia_descr.bFunctionClass,
2467 ia_descr.bFunctionSubClass);
2468
2469 /* 5) usbiaVID,classFC */
2470 (void) sprintf(usba_name[n++],
2471 "usbia%x,class%x",
2472 usb_dev_descr->idVendor,
2473 ia_descr.bFunctionClass);
2474
2475 /* 6) usbia,classFC.FSC.FPROTO */
2476 (void) sprintf(usba_name[n++],
2477 "usbia,class%x.%x.%x",
2478 ia_descr.bFunctionClass,
2479 ia_descr.bFunctionSubClass,
2480 ia_descr.bFunctionProtocol);
2481
2482 /* 7) usbia,classFC.FSC */
2483 (void) sprintf(usba_name[n++],
2484 "usbia,class%x.%x",
2485 ia_descr.bFunctionClass,
2486 ia_descr.bFunctionSubClass);
2487
2488 /* 8) usbia,classFC */
2489 (void) sprintf(usba_name[n++],
2490 "usbia,class%x",
2491 ia_descr.bFunctionClass);
2492 }
2493
2494 if (usba_get_ugen_binding(child_dip) ==
2495 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2496 /* 9) ugen */
2497 (void) sprintf(usba_name[n++], "ugen");
2498 } else {
2499
2500 (void) sprintf(usba_name[n++], "usb,ia");
2501 }
2502
2503 for (i = 0; i < n; i += 2) {
2504 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2505 "compatible name:\t%s\t%s", usba_name[i],
2506 (((i+1) < n)? usba_name[i+1] : ""));
2507 }
2508
2509 /* create compatible property */
2510 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2511 "compatible", (char **)usba_name, n);
2512
2513 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2514 USBA_MAX_COMPAT_NAME_LEN);
2515
2516 if (rval != DDI_PROP_SUCCESS) {
2517
2518 goto fail;
2519 }
2520
2521 /* update the address property */
2522 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2523 "assigned-address", child_ud->usb_addr);
2524 if (rval != DDI_PROP_SUCCESS) {
2525 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2526 "usba_ready_interface_node: address update failed");
2527 }
2528
2529 /* create property with first interface number */
2530 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2531 "interface", ia_descr.bFirstInterface);
2532
2533 if (rval != DDI_PROP_SUCCESS) {
2534
2535 goto fail;
2536 }
2537
2538 /* create property with the count of interfaces in this ia */
2539 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2540 "interface-count", ia_descr.bInterfaceCount);
2541
2542 if (rval != DDI_PROP_SUCCESS) {
2543
2544 goto fail;
2545 }
2546
2547 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2548 "%s%d port %d: %s, dip = 0x%p",
2549 ddi_node_name(ddi_get_parent(dip)),
2550 ddi_get_instance(ddi_get_parent(dip)),
2551 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2552
2553 *if_count = ia_descr.bInterfaceCount;
2554 usba_set_usba_device(child_dip, child_ud);
2555 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2556
2557 return (child_dip);
2558
2559 fail:
2560 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2561
2562 return (NULL);
2563 }
2564
2565
2566 /*
2567 * driver binding at interface level, the first arg will be the
2568 * the parent dip
2569 */
2570 /*ARGSUSED*/
2571 dev_info_t *
usba_ready_interface_node(dev_info_t * dip,uint_t intf)2572 usba_ready_interface_node(dev_info_t *dip, uint_t intf)
2573 {
2574 dev_info_t *child_dip = NULL;
2575 usba_device_t *child_ud = usba_get_usba_device(dip);
2576 usb_dev_descr_t *usb_dev_descr;
2577 size_t usb_cfg_length;
2578 uchar_t *usb_cfg;
2579 usb_if_descr_t if_descr;
2580 int i, n, rval;
2581 int reg[2];
2582 size_t size;
2583 usb_port_status_t port_status;
2584 char *force_bind = NULL;
2585 char *usba_name_buf = NULL;
2586 char *usba_name[USBA_MAX_COMPAT_NAMES];
2587
2588 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2589
2590 mutex_enter(&child_ud->usb_mutex);
2591
2592 usb_dev_descr = child_ud->usb_dev_descr;
2593
2594 /*
2595 * for each interface, determine all compatible names
2596 */
2597 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2598 "usba_ready_interface_node: "
2599 "port %d, interface = %d port status = %x",
2600 child_ud->usb_port, intf, child_ud->usb_port_status);
2601
2602 /* Parse the interface descriptor */
2603 size = usb_parse_if_descr(
2604 usb_cfg,
2605 usb_cfg_length,
2606 intf, /* interface index */
2607 0, /* alt interface index */
2608 &if_descr,
2609 USB_IF_DESCR_SIZE);
2610
2611 if (size != USB_IF_DESCR_SIZE) {
2612 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2613 "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
2614 size, USB_IF_DESCR_SIZE);
2615 mutex_exit(&child_ud->usb_mutex);
2616
2617 return (NULL);
2618 }
2619
2620 port_status = child_ud->usb_port_status;
2621
2622 /* create reg property */
2623 reg[0] = intf;
2624 reg[1] = child_ud->usb_cfg_value;
2625
2626 mutex_exit(&child_ud->usb_mutex);
2627
2628 /* clone this dip */
2629 rval = usba_create_child_devi(dip,
2630 "interface",
2631 NULL, /* usba_hcdi ops */
2632 NULL, /* root hub dip */
2633 port_status, /* port status */
2634 child_ud, /* share this usba_device */
2635 &child_dip);
2636
2637 if (rval != USB_SUCCESS) {
2638
2639 goto fail;
2640 }
2641
2642 rval = ndi_prop_update_int_array(
2643 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2644
2645 if (rval != DDI_PROP_SUCCESS) {
2646
2647 goto fail;
2648 }
2649
2650 usba_set_node_name(child_dip, if_descr.bInterfaceClass,
2651 if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
2652 FLAG_INTERFACE_NODE);
2653
2654 /* check force binding */
2655 if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
2656 force_bind = "ugen";
2657 }
2658
2659 /*
2660 * check whether there is another dip with this name and address
2661 */
2662 ASSERT(usba_find_existing_node(child_dip) == NULL);
2663
2664 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
2665 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
2666
2667 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
2668 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
2669 }
2670
2671 n = 0;
2672
2673 if (force_bind) {
2674 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2675 (void) strncpy(usba_name[n++], force_bind,
2676 USBA_MAX_COMPAT_NAME_LEN);
2677 }
2678
2679 /* 1) usbifVID,PID.REV.configCN.IN */
2680 (void) sprintf(usba_name[n++],
2681 "usbif%x,%x.%x.config%x.%x",
2682 usb_dev_descr->idVendor,
2683 usb_dev_descr->idProduct,
2684 usb_dev_descr->bcdDevice,
2685 child_ud->usb_cfg_value,
2686 intf);
2687
2688 /* 2) usbifVID,PID.configCN.IN */
2689 (void) sprintf(usba_name[n++],
2690 "usbif%x,%x.config%x.%x",
2691 usb_dev_descr->idVendor,
2692 usb_dev_descr->idProduct,
2693 child_ud->usb_cfg_value,
2694 intf);
2695
2696
2697 if (if_descr.bInterfaceClass) {
2698 /* 3) usbifVID,classIC.ISC.IPROTO */
2699 (void) sprintf(usba_name[n++],
2700 "usbif%x,class%x.%x.%x",
2701 usb_dev_descr->idVendor,
2702 if_descr.bInterfaceClass,
2703 if_descr.bInterfaceSubClass,
2704 if_descr.bInterfaceProtocol);
2705
2706 /* 4) usbifVID,classIC.ISC */
2707 (void) sprintf(usba_name[n++],
2708 "usbif%x,class%x.%x",
2709 usb_dev_descr->idVendor,
2710 if_descr.bInterfaceClass,
2711 if_descr.bInterfaceSubClass);
2712
2713 /* 5) usbifVID,classIC */
2714 (void) sprintf(usba_name[n++],
2715 "usbif%x,class%x",
2716 usb_dev_descr->idVendor,
2717 if_descr.bInterfaceClass);
2718
2719 /* 6) usbif,classIC.ISC.IPROTO */
2720 (void) sprintf(usba_name[n++],
2721 "usbif,class%x.%x.%x",
2722 if_descr.bInterfaceClass,
2723 if_descr.bInterfaceSubClass,
2724 if_descr.bInterfaceProtocol);
2725
2726 /* 7) usbif,classIC.ISC */
2727 (void) sprintf(usba_name[n++],
2728 "usbif,class%x.%x",
2729 if_descr.bInterfaceClass,
2730 if_descr.bInterfaceSubClass);
2731
2732 /* 8) usbif,classIC */
2733 (void) sprintf(usba_name[n++],
2734 "usbif,class%x",
2735 if_descr.bInterfaceClass);
2736 }
2737
2738 if (usba_get_ugen_binding(child_dip) ==
2739 USBA_UGEN_INTERFACE_BINDING) {
2740 /* 9) ugen */
2741 (void) sprintf(usba_name[n++], "ugen");
2742 }
2743
2744 for (i = 0; i < n; i += 2) {
2745 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2746 "compatible name:\t%s\t%s", usba_name[i],
2747 (((i+1) < n)? usba_name[i+1] : ""));
2748 }
2749
2750 /* create compatible property */
2751 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
2752 "compatible", (char **)usba_name, n);
2753
2754 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
2755 USBA_MAX_COMPAT_NAME_LEN);
2756
2757 if (rval != DDI_PROP_SUCCESS) {
2758
2759 goto fail;
2760 }
2761
2762 /* update the address property */
2763 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2764 "assigned-address", child_ud->usb_addr);
2765 if (rval != DDI_PROP_SUCCESS) {
2766 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2767 "usba_ready_interface_node: address update failed");
2768 }
2769
2770 /* create property with if number */
2771 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2772 "interface", intf);
2773
2774 if (rval != DDI_PROP_SUCCESS) {
2775
2776 goto fail;
2777 }
2778
2779 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2780 "%s%d port %d: %s, dip = 0x%p",
2781 ddi_node_name(ddi_get_parent(dip)),
2782 ddi_get_instance(ddi_get_parent(dip)),
2783 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2784
2785 usba_set_usba_device(child_dip, child_ud);
2786 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2787
2788 return (child_dip);
2789
2790 fail:
2791 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2792
2793 return (NULL);
2794 }
2795
2796
2797 /*
2798 * retrieve string descriptors for manufacturer, vendor and serial
2799 * number
2800 */
2801 void
usba_get_dev_string_descrs(dev_info_t * dip,usba_device_t * ud)2802 usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
2803 {
2804 char *tmpbuf, *str;
2805 int l;
2806 usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
2807
2808
2809 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2810 "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
2811 usb_dev_descr->iManufacturer,
2812 usb_dev_descr->iProduct,
2813 usb_dev_descr->iSerialNumber);
2814
2815 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2816
2817 /* fetch manufacturer string */
2818 if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
2819 (usb_get_string_descr(dip, USB_LANG_ID,
2820 usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
2821 USB_SUCCESS)) {
2822
2823 l = strlen(tmpbuf);
2824 if (l > 0) {
2825 str = kmem_zalloc(l + 1, KM_SLEEP);
2826 mutex_enter(&ud->usb_mutex);
2827 ud->usb_mfg_str = str;
2828 (void) strcpy(ud->usb_mfg_str, tmpbuf);
2829 mutex_exit(&ud->usb_mutex);
2830 }
2831 }
2832
2833 /* fetch product string */
2834 if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
2835 (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
2836 tmpbuf, USB_MAXSTRINGLEN) ==
2837 USB_SUCCESS)) {
2838
2839 l = strlen(tmpbuf);
2840 if (l > 0) {
2841 str = kmem_zalloc(l + 1, KM_SLEEP);
2842 mutex_enter(&ud->usb_mutex);
2843 ud->usb_product_str = str;
2844 (void) strcpy(ud->usb_product_str, tmpbuf);
2845 mutex_exit(&ud->usb_mutex);
2846 }
2847 }
2848
2849 /* fetch device serial number string */
2850 if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
2851 (usb_get_string_descr(dip, USB_LANG_ID,
2852 usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
2853 USB_SUCCESS)) {
2854
2855 l = strlen(tmpbuf);
2856 if (l > 0) {
2857 str = kmem_zalloc(l + 1, KM_SLEEP);
2858 mutex_enter(&ud->usb_mutex);
2859 ud->usb_serialno_str = str;
2860 (void) strcpy(ud->usb_serialno_str, tmpbuf);
2861 mutex_exit(&ud->usb_mutex);
2862 }
2863 }
2864
2865 kmem_free(tmpbuf, USB_MAXSTRINGLEN);
2866 }
2867
2868
2869 /*
2870 * usba_get_mfg_prod_sn_str:
2871 * Return a string containing mfg, product, serial number strings.
2872 * Remove duplicates if some strings are the same.
2873 *
2874 * Arguments:
2875 * dip - pointer to dev info
2876 * buffer - Where string is returned
2877 * buflen - Length of buffer
2878 *
2879 * Returns:
2880 * Same as second arg.
2881 */
2882 char *
usba_get_mfg_prod_sn_str(dev_info_t * dip,char * buffer,int buflen)2883 usba_get_mfg_prod_sn_str(
2884 dev_info_t *dip,
2885 char *buffer,
2886 int buflen)
2887 {
2888 usba_device_t *usba_device = usba_get_usba_device(dip);
2889 int return_len = 0;
2890 int len = 0;
2891
2892 buffer[0] = '\0';
2893 buffer[buflen-1] = '\0';
2894
2895 /* Manufacturer string exists. */
2896 if ((usba_device->usb_mfg_str) &&
2897 ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
2898 (void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
2899 return_len = min(buflen - 1, len);
2900 }
2901
2902 /* Product string exists to append. */
2903 if ((usba_device->usb_product_str) &&
2904 ((len = strlen(usba_device->usb_product_str)) != 0)) {
2905 if (return_len > 0) {
2906 buffer[return_len++] = ' ';
2907 }
2908 (void) strncpy(&buffer[return_len],
2909 usba_device->usb_product_str, buflen - return_len - 1);
2910 return_len = min(buflen - 1, return_len + len);
2911 }
2912
2913 /* Serial number string exists to append. */
2914 if ((usba_device->usb_serialno_str) &&
2915 ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
2916 if (return_len > 0) {
2917 buffer[return_len++] = ' ';
2918 }
2919 (void) strncpy(&buffer[return_len],
2920 usba_device->usb_serialno_str,
2921 buflen - return_len - 1);
2922 }
2923
2924 return (buffer);
2925 }
2926
2927 /*
2928 * USB enumeration statistic functions
2929 */
2930
2931 /*
2932 * Increments the hotplug statistics based on flags.
2933 */
2934 void
usba_update_hotplug_stats(dev_info_t * dip,usb_flags_t flags)2935 usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
2936 {
2937 usba_device_t *usba_device = usba_get_usba_device(dip);
2938 usba_hcdi_t *hcdi =
2939 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2940
2941 mutex_enter(&hcdi->hcdi_mutex);
2942 if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
2943 hcdi->hcdi_total_hotplug_success++;
2944 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2945 hcdi_hotplug_total_success.value.ui64++;
2946 }
2947 if (flags & USBA_HOTPLUG_SUCCESS) {
2948 hcdi->hcdi_hotplug_success++;
2949 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2950 hcdi_hotplug_success.value.ui64++;
2951 }
2952 if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
2953 hcdi->hcdi_total_hotplug_failure++;
2954 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2955 hcdi_hotplug_total_failure.value.ui64++;
2956 }
2957 if (flags & USBA_HOTPLUG_FAILURE) {
2958 hcdi->hcdi_hotplug_failure++;
2959 HCDI_HOTPLUG_STATS_DATA(hcdi)->
2960 hcdi_hotplug_failure.value.ui64++;
2961 }
2962 mutex_exit(&hcdi->hcdi_mutex);
2963 }
2964
2965
2966 /*
2967 * Retrieve the current enumeration statistics
2968 */
2969 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)2970 usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
2971 ulong_t *success, ulong_t *total_failure, ulong_t *failure,
2972 uchar_t *device_count)
2973 {
2974 usba_device_t *usba_device = usba_get_usba_device(dip);
2975 usba_hcdi_t *hcdi =
2976 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2977
2978 mutex_enter(&hcdi->hcdi_mutex);
2979 *total_success = hcdi->hcdi_total_hotplug_success;
2980 *success = hcdi->hcdi_hotplug_success;
2981 *total_failure = hcdi->hcdi_total_hotplug_failure;
2982 *failure = hcdi->hcdi_hotplug_failure;
2983 *device_count = hcdi->hcdi_device_count;
2984 mutex_exit(&hcdi->hcdi_mutex);
2985 }
2986
2987
2988 /*
2989 * Reset the resetable hotplug stats
2990 */
2991 void
usba_reset_hotplug_stats(dev_info_t * dip)2992 usba_reset_hotplug_stats(dev_info_t *dip)
2993 {
2994 usba_device_t *usba_device = usba_get_usba_device(dip);
2995 usba_hcdi_t *hcdi =
2996 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2997 hcdi_hotplug_stats_t *hsp;
2998
2999 mutex_enter(&hcdi->hcdi_mutex);
3000 hcdi->hcdi_hotplug_success = 0;
3001 hcdi->hcdi_hotplug_failure = 0;
3002
3003 hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
3004 hsp->hcdi_hotplug_success.value.ui64 = 0;
3005 hsp->hcdi_hotplug_failure.value.ui64 = 0;
3006 mutex_exit(&hcdi->hcdi_mutex);
3007 }
3008
3009
3010 /*
3011 * usba_bind_driver():
3012 * This function calls ndi_devi_bind_driver() which tries to
3013 * bind a driver to the device. If the driver binding fails
3014 * we get an rval of NDI_UNBOUD and report an error to the
3015 * syslog that the driver failed binding.
3016 * If rval is something other than NDI_UNBOUND we report an
3017 * error to the console.
3018 *
3019 * This function returns USB_SUCCESS if no errors were
3020 * encountered while binding.
3021 */
3022 int
usba_bind_driver(dev_info_t * dip)3023 usba_bind_driver(dev_info_t *dip)
3024 {
3025 int rval;
3026 char *name;
3027 uint8_t if_num = usba_get_ifno(dip);
3028
3029 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3030 "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
3031
3032 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
3033
3034 /* bind device to the driver */
3035 if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
3036 /* if we fail to bind report an error */
3037 (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
3038 if (name[0] != '\0') {
3039 if (!usb_owns_device(dip)) {
3040 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3041 usba_log_handle,
3042 "no driver found for "
3043 "interface %d (nodename: '%s') of %s",
3044 if_num, ddi_node_name(dip), name);
3045 } else {
3046 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3047 usba_log_handle,
3048 "no driver found for device %s", name);
3049 }
3050 } else {
3051 (void) ddi_pathname(dip, name);
3052 USB_DPRINTF_L1(DPRINT_MASK_USBA,
3053 usba_log_handle,
3054 "no driver found for device %s", name);
3055 }
3056
3057 kmem_free(name, MAXNAMELEN);
3058
3059 return (USB_FAILURE);
3060 }
3061 kmem_free(name, MAXNAMELEN);
3062
3063 return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
3064 }
3065
3066
3067 /*
3068 * usba_get_hc_dma_attr:
3069 * function returning dma attributes of the HCD
3070 *
3071 * Arguments:
3072 * dip - pointer to devinfo of the client
3073 *
3074 * Return Values:
3075 * hcdi_dma_attr
3076 */
3077 ddi_dma_attr_t *
usba_get_hc_dma_attr(dev_info_t * dip)3078 usba_get_hc_dma_attr(dev_info_t *dip)
3079 {
3080 usba_device_t *usba_device = usba_get_usba_device(dip);
3081 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
3082
3083 return (hcdi->hcdi_dma_attr);
3084 }
3085
3086
3087 /*
3088 * usba_check_for_leaks:
3089 * check usba_device structure for leaks
3090 *
3091 * Arguments:
3092 * usba_device - usba_device structure pointer
3093 */
3094 void
usba_check_for_leaks(usba_device_t * usba_device)3095 usba_check_for_leaks(usba_device_t *usba_device)
3096 {
3097 int i, ph_open_cnt, req_wrp_leaks, iface;
3098 int leaks = 0;
3099
3100 USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3101 "usba_check_for_leaks: %s%d usba_device=0x%p",
3102 ddi_driver_name(usba_device->usb_dip),
3103 ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
3104
3105 /*
3106 * default pipe is still open
3107 * all other pipes should be closed
3108 */
3109 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
3110 usba_ph_impl_t *ph_impl =
3111 &usba_device->usb_ph_list[i];
3112 if (ph_impl->usba_ph_data) {
3113 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3114 usba_log_handle,
3115 "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
3116 ddi_driver_name(ph_impl->usba_ph_data->p_dip),
3117 ddi_get_instance(ph_impl->usba_ph_data->p_dip),
3118 (void *)ph_impl,
3119 (void *)ph_impl->usba_ph_data,
3120 ph_impl->usba_ph_ep.bEndpointAddress);
3121 ph_open_cnt++;
3122 leaks++;
3123 #ifndef DEBUG
3124 usb_pipe_close(ph_impl->usba_ph_data->p_dip,
3125 (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
3126 NULL, NULL);
3127 #endif
3128 }
3129 }
3130 req_wrp_leaks = usba_list_entry_leaks(&usba_device->
3131 usb_allocated, "request wrappers");
3132
3133 ASSERT(ph_open_cnt == 0);
3134 ASSERT(req_wrp_leaks == 0);
3135
3136 if (req_wrp_leaks) {
3137 usba_list_entry_t *entry;
3138
3139 while ((entry = usba_rm_first_from_list(
3140 &usba_device->usb_allocated)) != NULL) {
3141 usba_req_wrapper_t *wrp;
3142
3143 mutex_enter(&entry->list_mutex);
3144 wrp = (usba_req_wrapper_t *)entry->private;
3145 mutex_exit(&entry->list_mutex);
3146 leaks++;
3147
3148 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3149 usba_log_handle,
3150 "%s%d: leaking request 0x%p",
3151 ddi_driver_name(wrp->wr_dip),
3152 ddi_get_instance(wrp->wr_dip),
3153 (void *)wrp->wr_req);
3154
3155 /*
3156 * put it back, usba_req_wrapper_free
3157 * expects it on the list
3158 */
3159 usba_add_to_list(&usba_device->usb_allocated,
3160 &wrp->wr_allocated_list);
3161
3162 usba_req_wrapper_free(wrp);
3163 }
3164 }
3165
3166 mutex_enter(&usba_device->usb_mutex);
3167 for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
3168 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
3169 "usba_check_for_leaks: if=%d client_flags=0x%x",
3170 iface, usba_device->usb_client_flags[iface]);
3171
3172 if (usba_device->usb_client_flags[iface] &
3173 USBA_CLIENT_FLAG_DEV_DATA) {
3174 usb_client_dev_data_list_t *entry =
3175 usba_device->usb_client_dev_data_list.cddl_next;
3176 usb_client_dev_data_list_t *next;
3177 usb_client_dev_data_t *dev_data;
3178
3179 while (entry) {
3180 dev_info_t *dip = entry->cddl_dip;
3181 next = entry->cddl_next;
3182 dev_data = entry->cddl_dev_data;
3183
3184
3185 if (!i_ddi_devi_attached(dip)) {
3186 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3187 usba_log_handle,
3188 "%s%d: leaking dev_data 0x%p",
3189 ddi_driver_name(dip),
3190 ddi_get_instance(dip),
3191 (void *)dev_data);
3192
3193 leaks++;
3194
3195 mutex_exit(&usba_device->usb_mutex);
3196 usb_free_dev_data(dip, dev_data);
3197 mutex_enter(&usba_device->usb_mutex);
3198 }
3199
3200 entry = next;
3201 }
3202 }
3203 if (usba_device->usb_client_flags[iface] &
3204 USBA_CLIENT_FLAG_ATTACH) {
3205 dev_info_t *dip = usba_device->
3206 usb_client_attach_list[iface].dip;
3207
3208 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3209 usba_log_handle,
3210 "%s%d: did no usb_client_detach",
3211 ddi_driver_name(dip), ddi_get_instance(dip));
3212 leaks++;
3213
3214 mutex_exit(&usba_device->usb_mutex);
3215 usb_client_detach(dip, NULL);
3216 mutex_enter(&usba_device->usb_mutex);
3217
3218 usba_device->
3219 usb_client_attach_list[iface].dip = NULL;
3220
3221 usba_device->usb_client_flags[iface] &=
3222 ~USBA_CLIENT_FLAG_ATTACH;
3223
3224 }
3225 if (usba_device->usb_client_flags[iface] &
3226 USBA_CLIENT_FLAG_EV_CBS) {
3227 dev_info_t *dip =
3228 usba_device->usb_client_ev_cb_list[iface].
3229 dip;
3230 usb_event_t *ev_data =
3231 usba_device->usb_client_ev_cb_list[iface].
3232 ev_data;
3233
3234 USB_DPRINTF_L2(DPRINT_MASK_USBA,
3235 usba_log_handle,
3236 "%s%d: did no usb_unregister_event_cbs",
3237 ddi_driver_name(dip), ddi_get_instance(dip));
3238 leaks++;
3239
3240 mutex_exit(&usba_device->usb_mutex);
3241 usb_unregister_event_cbs(dip, ev_data);
3242 mutex_enter(&usba_device->usb_mutex);
3243
3244 usba_device->usb_client_ev_cb_list[iface].
3245 dip = NULL;
3246 usba_device->usb_client_ev_cb_list[iface].
3247 ev_data = NULL;
3248 usba_device->usb_client_flags[iface] &=
3249 ~USBA_CLIENT_FLAG_EV_CBS;
3250 }
3251 }
3252 mutex_exit(&usba_device->usb_mutex);
3253
3254 if (leaks) {
3255 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
3256 "all %d leaks fixed", leaks);
3257 }
3258 }
3259