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