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