usb_subr.c revision 1.72 1 /* $NetBSD: usb_subr.c,v 1.72 2000/04/14 14:13:56 augustss Exp $ */
2 /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
3
4 /*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss (at) carlstedt.se) at
10 * Carlstedt Research & Technology.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #if defined(__NetBSD__) || defined(__OpenBSD__)
46 #include <sys/device.h>
47 #include <sys/select.h>
48 #elif defined(__FreeBSD__)
49 #include <sys/module.h>
50 #include <sys/bus.h>
51 #endif
52 #include <sys/proc.h>
53
54 #include <machine/bus.h>
55
56 #include <dev/usb/usb.h>
57
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdi_util.h>
60 #include <dev/usb/usbdivar.h>
61 #include <dev/usb/usbdevs.h>
62 #include <dev/usb/usb_quirks.h>
63
64 #if defined(__FreeBSD__)
65 #include <machine/clock.h>
66 #define delay(d) DELAY(d)
67 #endif
68
69 #ifdef USB_DEBUG
70 #define DPRINTF(x) if (usbdebug) logprintf x
71 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
72 extern int usbdebug;
73 #else
74 #define DPRINTF(x)
75 #define DPRINTFN(n,x)
76 #endif
77
78 Static usbd_status usbd_set_config __P((usbd_device_handle, int));
79 Static char *usbd_get_string __P((usbd_device_handle, int, char *));
80 Static int usbd_getnewaddr __P((usbd_bus_handle bus));
81 #if defined(__NetBSD__)
82 Static int usbd_print __P((void *aux, const char *pnp));
83 Static int usbd_submatch __P((device_ptr_t, struct cfdata *cf, void *));
84 #elif defined(__OpenBSD__)
85 Static int usbd_print __P((void *aux, const char *pnp));
86 Static int usbd_submatch __P((device_ptr_t, void *, void *));
87 #endif
88 Static void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno));
89 Static void usbd_kill_pipe __P((usbd_pipe_handle));
90 Static usbd_status usbd_probe_and_attach
91 __P((device_ptr_t parent, usbd_device_handle dev, int port, int addr));
92
93 Static u_int32_t usb_cookie_no = 0;
94
95 #ifdef USBVERBOSE
96 typedef u_int16_t usb_vendor_id_t;
97 typedef u_int16_t usb_product_id_t;
98
99 /*
100 * Descriptions of of known vendors and devices ("products").
101 */
102 struct usb_knowndev {
103 usb_vendor_id_t vendor;
104 usb_product_id_t product;
105 int flags;
106 char *vendorname, *productname;
107 };
108 #define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
109
110 #include <dev/usb/usbdevs_data.h>
111 #endif /* USBVERBOSE */
112
113 Static const char *usbd_error_strs[] = {
114 "NORMAL_COMPLETION",
115 "IN_PROGRESS",
116 "PENDING_REQUESTS",
117 "NOT_STARTED",
118 "INVAL",
119 "NOMEM",
120 "CANCELLED",
121 "BAD_ADDRESS",
122 "IN_USE",
123 "NO_ADDR",
124 "SET_ADDR_FAILED",
125 "NO_POWER",
126 "TOO_DEEP",
127 "IOERROR",
128 "NOT_CONFIGURED",
129 "TIMEOUT",
130 "SHORT_XFER",
131 "STALLED",
132 "INTERRUPTED",
133 "XXX",
134 };
135
136 const char *
137 usbd_errstr(err)
138 usbd_status err;
139 {
140 static char buffer[5];
141
142 if (err < USBD_ERROR_MAX) {
143 return usbd_error_strs[err];
144 } else {
145 snprintf(buffer, sizeof buffer, "%d", err);
146 return buffer;
147 }
148 }
149
150 usbd_status
151 usbd_get_string_desc(dev, sindex, langid, sdesc)
152 usbd_device_handle dev;
153 int sindex;
154 int langid;
155 usb_string_descriptor_t *sdesc;
156 {
157 usb_device_request_t req;
158 usbd_status err;
159
160 req.bmRequestType = UT_READ_DEVICE;
161 req.bRequest = UR_GET_DESCRIPTOR;
162 USETW2(req.wValue, UDESC_STRING, sindex);
163 USETW(req.wIndex, langid);
164 USETW(req.wLength, 1); /* only size byte first */
165 err = usbd_do_request(dev, &req, sdesc);
166 if (err)
167 return (err);
168 USETW(req.wLength, sdesc->bLength); /* the whole string */
169 return (usbd_do_request(dev, &req, sdesc));
170 }
171
172 char *
173 usbd_get_string(dev, si, buf)
174 usbd_device_handle dev;
175 int si;
176 char *buf;
177 {
178 int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
179 usb_string_descriptor_t us;
180 char *s;
181 int i, n;
182 u_int16_t c;
183 usbd_status err;
184
185 if (si == 0)
186 return (0);
187 if (dev->quirks->uq_flags & UQ_NO_STRINGS)
188 return (0);
189 if (dev->langid == USBD_NOLANG) {
190 /* Set up default language */
191 err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
192 if (err || us.bLength < 4) {
193 dev->langid = 0; /* Well, just pick English then */
194 } else {
195 /* Pick the first language as the default. */
196 dev->langid = UGETW(us.bString[0]);
197 }
198 }
199 err = usbd_get_string_desc(dev, si, dev->langid, &us);
200 if (err)
201 return (0);
202 s = buf;
203 n = us.bLength / 2 - 1;
204 for (i = 0; i < n; i++) {
205 c = UGETW(us.bString[i]);
206 /* Convert from Unicode, handle buggy strings. */
207 if ((c & 0xff00) == 0)
208 *s++ = c;
209 else if ((c & 0x00ff) == 0 && swap)
210 *s++ = c >> 8;
211 else
212 *s++ = '?';
213 }
214 *s++ = 0;
215 return (buf);
216 }
217
218 void
219 usbd_devinfo_vp(dev, v, p)
220 usbd_device_handle dev;
221 char *v, *p;
222 {
223 usb_device_descriptor_t *udd = &dev->ddesc;
224 char *vendor = 0, *product = 0;
225 #ifdef USBVERBOSE
226 struct usb_knowndev *kdp;
227 #endif
228
229 if (dev == NULL) {
230 v[0] = p[0] = '\0';
231 return;
232 }
233
234 vendor = usbd_get_string(dev, udd->iManufacturer, v);
235 product = usbd_get_string(dev, udd->iProduct, p);
236 #ifdef USBVERBOSE
237 if (vendor == NULL || product == NULL) {
238 for(kdp = usb_knowndevs;
239 kdp->vendorname != NULL;
240 kdp++) {
241 if (kdp->vendor == UGETW(udd->idVendor) &&
242 (kdp->product == UGETW(udd->idProduct) ||
243 (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
244 break;
245 }
246 if (kdp->vendorname != NULL) {
247 if (!vendor)
248 vendor = kdp->vendorname;
249 if (!product)
250 product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?
251 kdp->productname : NULL;
252 }
253 }
254 #endif
255 if (vendor != NULL)
256 strcpy(v, vendor);
257 else
258 sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor));
259 if (product != NULL)
260 strcpy(p, product);
261 else
262 sprintf(p, "product 0x%04x", UGETW(udd->idProduct));
263 }
264
265 int
266 usbd_printBCD(cp, bcd)
267 char *cp;
268 int bcd;
269 {
270 return (sprintf(cp, "%x.%02x", bcd >> 8, bcd & 0xff));
271 }
272
273 void
274 usbd_devinfo(dev, showclass, cp)
275 usbd_device_handle dev;
276 int showclass;
277 char *cp;
278 {
279 usb_device_descriptor_t *udd = &dev->ddesc;
280 char vendor[USB_MAX_STRING_LEN];
281 char product[USB_MAX_STRING_LEN];
282 int bcdDevice, bcdUSB;
283
284 usbd_devinfo_vp(dev, vendor, product);
285 cp += sprintf(cp, "%s %s", vendor, product);
286 if (showclass)
287 cp += sprintf(cp, ", class %d/%d",
288 udd->bDeviceClass, udd->bDeviceSubClass);
289 bcdUSB = UGETW(udd->bcdUSB);
290 bcdDevice = UGETW(udd->bcdDevice);
291 cp += sprintf(cp, ", rev ");
292 cp += usbd_printBCD(cp, bcdUSB);
293 *cp++ = '/';
294 cp += usbd_printBCD(cp, bcdDevice);
295 cp += sprintf(cp, ", addr %d", dev->address);
296 *cp = 0;
297 }
298
299 /* Delay for a certain number of ms */
300 void
301 usb_delay_ms(bus, ms)
302 usbd_bus_handle bus;
303 u_int ms;
304 {
305 extern int cold;
306
307 /* Wait at least two clock ticks so we know the time has passed. */
308 if (bus->use_polling || cold)
309 delay((ms+1) * 1000);
310 else
311 tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1);
312 }
313
314 /* Delay given a device handle. */
315 void
316 usbd_delay_ms(dev, ms)
317 usbd_device_handle dev;
318 u_int ms;
319 {
320 usb_delay_ms(dev->bus, ms);
321 }
322
323 usbd_status
324 usbd_reset_port(dev, port, ps)
325 usbd_device_handle dev;
326 int port;
327 usb_port_status_t *ps;
328 {
329 usb_device_request_t req;
330 usbd_status err;
331 int n;
332
333 req.bmRequestType = UT_WRITE_CLASS_OTHER;
334 req.bRequest = UR_SET_FEATURE;
335 USETW(req.wValue, UHF_PORT_RESET);
336 USETW(req.wIndex, port);
337 USETW(req.wLength, 0);
338 err = usbd_do_request(dev, &req, 0);
339 DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
340 port, usbd_errstr(err)));
341 if (err)
342 return (err);
343 n = 10;
344 do {
345 /* Wait for device to recover from reset. */
346 usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
347 err = usbd_get_port_status(dev, port, ps);
348 if (err) {
349 DPRINTF(("usbd_reset_port: get status failed %d\n",
350 err));
351 return (err);
352 }
353 } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
354 if (n == 0) {
355 printf("usbd_reset_port: timeout\n");
356 return (USBD_IOERROR);
357 }
358 err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
359 #ifdef USB_DEBUG
360 if (err)
361 DPRINTF(("usbd_reset_port: clear port feature failed %d\n",
362 err));
363 #endif
364
365 /* Wait for the device to recover from reset. */
366 usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
367 return (err);
368 }
369
370 usb_interface_descriptor_t *
371 usbd_find_idesc(cd, ifaceidx, altidx)
372 usb_config_descriptor_t *cd;
373 int ifaceidx;
374 int altidx;
375 {
376 char *p = (char *)cd;
377 char *end = p + UGETW(cd->wTotalLength);
378 usb_interface_descriptor_t *d;
379 int curidx, lastidx, curaidx = 0;
380
381 for (curidx = lastidx = -1; p < end; ) {
382 d = (usb_interface_descriptor_t *)p;
383 DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d "
384 "type=%d\n",
385 ifaceidx, curidx, altidx, curaidx,
386 d->bLength, d->bDescriptorType));
387 if (d->bLength == 0) /* bad descriptor */
388 break;
389 p += d->bLength;
390 if (p <= end && d->bDescriptorType == UDESC_INTERFACE) {
391 if (d->bInterfaceNumber != lastidx) {
392 lastidx = d->bInterfaceNumber;
393 curidx++;
394 curaidx = 0;
395 } else
396 curaidx++;
397 if (ifaceidx == curidx && altidx == curaidx)
398 return (d);
399 }
400 }
401 return (NULL);
402 }
403
404 usb_endpoint_descriptor_t *
405 usbd_find_edesc(cd, ifaceidx, altidx, endptidx)
406 usb_config_descriptor_t *cd;
407 int ifaceidx;
408 int altidx;
409 int endptidx;
410 {
411 char *p = (char *)cd;
412 char *end = p + UGETW(cd->wTotalLength);
413 usb_interface_descriptor_t *d;
414 usb_endpoint_descriptor_t *e;
415 int curidx;
416
417 d = usbd_find_idesc(cd, ifaceidx, altidx);
418 if (d == NULL)
419 return (NULL);
420 if (endptidx >= d->bNumEndpoints) /* quick exit */
421 return (NULL);
422
423 curidx = -1;
424 for (p = (char *)d + d->bLength; p < end; ) {
425 e = (usb_endpoint_descriptor_t *)p;
426 if (e->bLength == 0) /* bad descriptor */
427 break;
428 p += e->bLength;
429 if (p <= end && e->bDescriptorType == UDESC_INTERFACE)
430 return (NULL);
431 if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) {
432 curidx++;
433 if (curidx == endptidx)
434 return (e);
435 }
436 }
437 return (NULL);
438 }
439
440 usbd_status
441 usbd_fill_iface_data(dev, ifaceidx, altidx)
442 usbd_device_handle dev;
443 int ifaceidx;
444 int altidx;
445 {
446 usbd_interface_handle ifc = &dev->ifaces[ifaceidx];
447 char *p, *end;
448 int endpt, nendpt;
449
450 DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n",
451 ifaceidx, altidx));
452 ifc->device = dev;
453 ifc->idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx);
454 if (ifc->idesc == 0)
455 return (USBD_INVAL);
456 ifc->index = ifaceidx;
457 ifc->altindex = altidx;
458 nendpt = ifc->idesc->bNumEndpoints;
459 DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt));
460 if (nendpt != 0) {
461 ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint),
462 M_USB, M_NOWAIT);
463 if (ifc->endpoints == NULL)
464 return (USBD_NOMEM);
465 } else
466 ifc->endpoints = NULL;
467 ifc->priv = NULL;
468 p = (char *)ifc->idesc + ifc->idesc->bLength;
469 end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength);
470 #define ed ((usb_endpoint_descriptor_t *)p)
471 for (endpt = 0; endpt < nendpt; endpt++) {
472 DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt));
473 for (; p < end; p += ed->bLength) {
474 ed = (usb_endpoint_descriptor_t *)p;
475 DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p "
476 "len=%d type=%d\n",
477 p, end, ed->bLength, ed->bDescriptorType));
478 if (p + ed->bLength <= end && ed->bLength != 0 &&
479 ed->bDescriptorType == UDESC_ENDPOINT)
480 goto found;
481 if (ed->bLength == 0 ||
482 ed->bDescriptorType == UDESC_INTERFACE)
483 break;
484 }
485 /* passed end, or bad desc */
486 DPRINTF(("usbd_fill_iface_data: bad descriptor(s): %s\n",
487 ed->bLength == 0 ? "0 length" :
488 ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":
489 "out of data"));
490 goto bad;
491 found:
492 ifc->endpoints[endpt].edesc = ed;
493 ifc->endpoints[endpt].refcnt = 0;
494 p += ed->bLength;
495 }
496 #undef ed
497 LIST_INIT(&ifc->pipes);
498 return (USBD_NORMAL_COMPLETION);
499
500 bad:
501 if (ifc->endpoints != NULL)
502 free(ifc->endpoints, M_USB);
503 return (USBD_INVAL);
504 }
505
506 void
507 usbd_free_iface_data(dev, ifcno)
508 usbd_device_handle dev;
509 int ifcno;
510 {
511 usbd_interface_handle ifc = &dev->ifaces[ifcno];
512 if (ifc->endpoints)
513 free(ifc->endpoints, M_USB);
514 }
515
516 Static usbd_status
517 usbd_set_config(dev, conf)
518 usbd_device_handle dev;
519 int conf;
520 {
521 usb_device_request_t req;
522
523 req.bmRequestType = UT_WRITE_DEVICE;
524 req.bRequest = UR_SET_CONFIG;
525 USETW(req.wValue, conf);
526 USETW(req.wIndex, 0);
527 USETW(req.wLength, 0);
528 return (usbd_do_request(dev, &req, 0));
529 }
530
531 usbd_status
532 usbd_set_config_no(dev, no, msg)
533 usbd_device_handle dev;
534 int no;
535 int msg;
536 {
537 int index;
538 usb_config_descriptor_t cd;
539 usbd_status err;
540
541 DPRINTFN(5,("usbd_set_config_no: %d\n", no));
542 /* Figure out what config index to use. */
543 for (index = 0; index < dev->ddesc.bNumConfigurations; index++) {
544 err = usbd_get_config_desc(dev, index, &cd);
545 if (err)
546 return (err);
547 if (cd.bConfigurationValue == no)
548 return (usbd_set_config_index(dev, index, msg));
549 }
550 return (USBD_INVAL);
551 }
552
553 usbd_status
554 usbd_set_config_index(dev, index, msg)
555 usbd_device_handle dev;
556 int index;
557 int msg;
558 {
559 usb_status_t ds;
560 usb_config_descriptor_t cd, *cdp;
561 usbd_status err;
562 int ifcidx, nifc, len, selfpowered, power;
563
564 DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));
565
566 /* XXX check that all interfaces are idle */
567 if (dev->config != 0) {
568 DPRINTF(("usbd_set_config_index: free old config\n"));
569 /* Free all configuration data structures. */
570 nifc = dev->cdesc->bNumInterface;
571 for (ifcidx = 0; ifcidx < nifc; ifcidx++)
572 usbd_free_iface_data(dev, ifcidx);
573 free(dev->ifaces, M_USB);
574 free(dev->cdesc, M_USB);
575 dev->ifaces = NULL;
576 dev->cdesc = NULL;
577 dev->config = 0;
578 }
579
580 /* Figure out what config number to use. */
581 err = usbd_get_config_desc(dev, index, &cd);
582 if (err)
583 return (err);
584 len = UGETW(cd.wTotalLength);
585 cdp = malloc(len, M_USB, M_NOWAIT);
586 if (cdp == NULL)
587 return (USBD_NOMEM);
588 err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
589 if (err)
590 goto bad;
591 if (cdp->bDescriptorType != UDESC_CONFIG) {
592 DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
593 cdp->bDescriptorType));
594 err = USBD_INVAL;
595 goto bad;
596 }
597 selfpowered = 0;
598 if (!(dev->quirks->uq_flags & UQ_BUS_POWERED) &&
599 cdp->bmAttributes & UC_SELF_POWERED) {
600 /* May be self powered. */
601 if (cdp->bmAttributes & UC_BUS_POWERED) {
602 /* Must ask device. */
603 err = usbd_get_device_status(dev, &ds);
604 if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED))
605 selfpowered = 1;
606 DPRINTF(("usbd_set_config_index: status=0x%04x, "
607 "error=%s\n",
608 UGETW(ds.wStatus), usbd_errstr(err)));
609 } else
610 selfpowered = 1;
611 }
612 DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, "
613 "selfpowered=%d, power=%d\n",
614 dev->address, cdp->bmAttributes,
615 selfpowered, cdp->bMaxPower * 2));
616 #ifdef USB_DEBUG
617 if (dev->powersrc == NULL) {
618 DPRINTF(("usbd_set_config_index: No power source?\n"));
619 return (USBD_IOERROR);
620 }
621 #endif
622 power = cdp->bMaxPower * 2;
623 if (power > dev->powersrc->power) {
624 /* XXX print nicer message. */
625 if (msg)
626 printf("%s: device addr %d (config %d) exceeds power "
627 "budget, %d mA > %d mA\n",
628 USBDEVNAME(dev->bus->bdev), dev->address,
629 cdp->bConfigurationValue,
630 power, dev->powersrc->power);
631 err = USBD_NO_POWER;
632 goto bad;
633 }
634 dev->power = power;
635 dev->self_powered = selfpowered;
636
637 DPRINTF(("usbd_set_config_index: set config %d\n",
638 cdp->bConfigurationValue));
639 err = usbd_set_config(dev, cdp->bConfigurationValue);
640 if (err) {
641 DPRINTF(("usbd_set_config_index: setting config=%d failed, "
642 "error=%s\n",
643 cdp->bConfigurationValue, usbd_errstr(err)));
644 goto bad;
645 }
646 DPRINTF(("usbd_set_config_index: setting new config %d\n",
647 cdp->bConfigurationValue));
648 nifc = cdp->bNumInterface;
649 dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
650 M_USB, M_NOWAIT);
651 if (dev->ifaces == NULL) {
652 err = USBD_NOMEM;
653 goto bad;
654 }
655 DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));
656 dev->cdesc = cdp;
657 dev->config = cdp->bConfigurationValue;
658 for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
659 err = usbd_fill_iface_data(dev, ifcidx, 0);
660 if (err) {
661 while (--ifcidx >= 0)
662 usbd_free_iface_data(dev, ifcidx);
663 goto bad;
664 }
665 }
666
667 return (USBD_NORMAL_COMPLETION);
668
669 bad:
670 free(cdp, M_USB);
671 return (err);
672 }
673
674 /* XXX add function for alternate settings */
675
676 usbd_status
677 usbd_setup_pipe(dev, iface, ep, ival, pipe)
678 usbd_device_handle dev;
679 usbd_interface_handle iface;
680 struct usbd_endpoint *ep;
681 int ival;
682 usbd_pipe_handle *pipe;
683 {
684 usbd_pipe_handle p;
685 usbd_status err;
686
687 DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",
688 dev, iface, ep, pipe));
689 p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
690 if (p == NULL)
691 return (USBD_NOMEM);
692 p->device = dev;
693 p->iface = iface;
694 p->endpoint = ep;
695 ep->refcnt++;
696 p->refcnt = 1;
697 p->intrxfer = 0;
698 p->running = 0;
699 p->aborting = 0;
700 p->repeat = 0;
701 p->interval = ival;
702 SIMPLEQ_INIT(&p->queue);
703 usb_callout_init(p->abort_handle);
704 err = dev->bus->methods->open_pipe(p);
705 if (err) {
706 DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
707 "%s\n",
708 ep->edesc->bEndpointAddress, usbd_errstr(err)));
709 free(p, M_USB);
710 return (err);
711 }
712 /* Clear any stall and make sure DATA0 toggle will be used next. */
713 if (UE_GET_ADDR(ep->edesc->bEndpointAddress) != USB_CONTROL_ENDPOINT)
714 usbd_clear_endpoint_stall(p);
715 *pipe = p;
716 return (USBD_NORMAL_COMPLETION);
717 }
718
719 /* Abort the device control pipe. */
720 void
721 usbd_kill_pipe(pipe)
722 usbd_pipe_handle pipe;
723 {
724 pipe->methods->close(pipe);
725 pipe->endpoint->refcnt--;
726 free(pipe, M_USB);
727 }
728
729 int
730 usbd_getnewaddr(bus)
731 usbd_bus_handle bus;
732 {
733 int addr;
734
735 for (addr = 1; addr < USB_MAX_DEVICES; addr++)
736 if (bus->devices[addr] == 0)
737 return (addr);
738 return (-1);
739 }
740
741
742 usbd_status
743 usbd_probe_and_attach(parent, dev, port, addr)
744 device_ptr_t parent;
745 usbd_device_handle dev;
746 int port;
747 int addr;
748 {
749 struct usb_attach_arg uaa;
750 usb_device_descriptor_t *dd = &dev->ddesc;
751 int found, i, confi, nifaces;
752 usbd_status err;
753 device_ptr_t dv;
754 usbd_interface_handle ifaces[256]; /* 256 is the absolute max */
755
756 #if defined(__FreeBSD__)
757 /*
758 * XXX uaa is a static var. Not a problem as it _should_ be used only
759 * during probe and attach. Should be changed however.
760 */
761 device_t bdev;
762 bdev = device_add_child(parent, NULL, -1, &uaa);
763 if (!bdev) {
764 printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));
765 return (USBD_INVAL);
766 }
767 device_quiet(bdev);
768 #endif
769
770 uaa.device = dev;
771 uaa.iface = NULL;
772 uaa.ifaces = NULL;
773 uaa.nifaces = 0;
774 uaa.usegeneric = 0;
775 uaa.port = port;
776 uaa.configno = UHUB_UNK_CONFIGURATION;
777 uaa.ifaceno = UHUB_UNK_INTERFACE;
778 uaa.vendor = UGETW(dd->idVendor);
779 uaa.product = UGETW(dd->idProduct);
780 uaa.release = UGETW(dd->bcdDevice);
781
782 /* First try with device specific drivers. */
783 DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));
784 dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
785 if (dv) {
786 dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
787 if (dev->subdevs == NULL)
788 return (USBD_NOMEM);
789 dev->subdevs[0] = dv;
790 dev->subdevs[1] = 0;
791 return (USBD_NORMAL_COMPLETION);
792 }
793
794 DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
795
796 DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n",
797 dd->bNumConfigurations));
798 /* Next try with interface drivers. */
799 for (confi = 0; confi < dd->bNumConfigurations; confi++) {
800 DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",
801 confi));
802 err = usbd_set_config_index(dev, confi, 1);
803 if (err) {
804 #ifdef USB_DEBUG
805 DPRINTF(("%s: port %d, set config at addr %d failed, "
806 "error=%s\n", USBDEVPTRNAME(parent), port,
807 addr, usbd_errstr(err)));
808 #else
809 printf("%s: port %d, set config at addr %d failed\n",
810 USBDEVPTRNAME(parent), port, addr);
811 #endif
812 #if defined(__FreeBSD__)
813 device_delete_child(parent, bdev);
814 #endif
815
816 return (err);
817 }
818 nifaces = dev->cdesc->bNumInterface;
819 uaa.configno = dev->cdesc->bConfigurationValue;
820 for (i = 0; i < nifaces; i++)
821 ifaces[i] = &dev->ifaces[i];
822 uaa.ifaces = ifaces;
823 uaa.nifaces = nifaces;
824 dev->subdevs = malloc((nifaces+1) * sizeof dv, M_USB,M_NOWAIT);
825 if (dev->subdevs == NULL) {
826 #if defined(__FreeBSD__)
827 device_delete_child(parent, bdev);
828 #endif
829 return (USBD_NOMEM);
830 }
831
832 found = 0;
833 for (i = 0; i < nifaces; i++) {
834 if (ifaces[i] == NULL)
835 continue; /* interface already claimed */
836 uaa.iface = ifaces[i];
837 uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
838 dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
839 usbd_submatch);
840 if (dv != NULL) {
841 dev->subdevs[found++] = dv;
842 dev->subdevs[found] = 0;
843 ifaces[i] = 0; /* consumed */
844
845 #if defined(__FreeBSD__)
846 /* create another child for the next iface */
847 bdev = device_add_child(parent, NULL, -1,&uaa);
848 if (!bdev) {
849 printf("%s: Device creation failed\n",
850 USBDEVNAME(dev->bus->bdev));
851 return (USBD_NORMAL_COMPLETION);
852 }
853 device_quiet(bdev);
854 #endif
855 }
856 }
857 if (found != 0) {
858 #if defined(__FreeBSD__)
859 /* remove the last created child again; it is unused */
860 device_delete_child(parent, bdev);
861 #endif
862 return (USBD_NORMAL_COMPLETION);
863 }
864 free(dev->subdevs, M_USB);
865 dev->subdevs = 0;
866 }
867 /* No interfaces were attached in any of the configurations. */
868
869 if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
870 usbd_set_config_index(dev, 0, 0);
871
872 DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
873
874 /* Finally try the generic driver. */
875 uaa.iface = NULL;
876 uaa.usegeneric = 1;
877 uaa.configno = UHUB_UNK_CONFIGURATION;
878 uaa.ifaceno = UHUB_UNK_INTERFACE;
879 dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
880 if (dv != NULL) {
881 dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
882 if (dev->subdevs == 0)
883 return (USBD_NOMEM);
884 dev->subdevs[0] = dv;
885 dev->subdevs[1] = 0;
886 return (USBD_NORMAL_COMPLETION);
887 }
888
889 /*
890 * The generic attach failed, but leave the device as it is.
891 * We just did not find any drivers, that's all. The device is
892 * fully operational and not harming anyone.
893 */
894 DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
895 #if defined(__FreeBSD__)
896 device_delete_child(parent, bdev);
897 #endif
898 return (USBD_NORMAL_COMPLETION);
899 }
900
901
902 /*
903 * Called when a new device has been put in the powered state,
904 * but not yet in the addressed state.
905 * Get initial descriptor, set the address, get full descriptor,
906 * and attach a driver.
907 */
908 usbd_status
909 usbd_new_device(parent, bus, depth, lowspeed, port, up)
910 device_ptr_t parent;
911 usbd_bus_handle bus;
912 int depth;
913 int lowspeed;
914 int port;
915 struct usbd_port *up;
916 {
917 usbd_device_handle dev;
918 usb_device_descriptor_t *dd;
919 usbd_status err;
920 int addr;
921 int i;
922
923 DPRINTF(("usbd_new_device bus=%p port=%d depth=%d lowspeed=%d\n",
924 bus, port, depth, lowspeed));
925 addr = usbd_getnewaddr(bus);
926 if (addr < 0) {
927 printf("%s: No free USB addresses, new device ignored.\n",
928 USBDEVNAME(bus->bdev));
929 return (USBD_NO_ADDR);
930 }
931
932 dev = malloc(sizeof *dev, M_USB, M_NOWAIT);
933 if (dev == NULL)
934 return (USBD_NOMEM);
935 memset(dev, 0, sizeof(*dev));
936
937 dev->bus = bus;
938
939 /* Set up default endpoint handle. */
940 dev->def_ep.edesc = &dev->def_ep_desc;
941
942 /* Set up default endpoint descriptor. */
943 dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
944 dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
945 dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
946 dev->def_ep_desc.bmAttributes = UE_CONTROL;
947 USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
948 dev->def_ep_desc.bInterval = 0;
949
950 dev->quirks = &usbd_no_quirk;
951 dev->address = USB_START_ADDR;
952 dev->ddesc.bMaxPacketSize = 0;
953 dev->lowspeed = lowspeed != 0;
954 dev->depth = depth;
955 dev->powersrc = up;
956 dev->langid = USBD_NOLANG;
957 dev->cookie.cookie = ++usb_cookie_no;
958
959 /* Establish the default pipe. */
960 err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
961 &dev->default_pipe);
962 if (err) {
963 usbd_remove_device(dev, up);
964 return (err);
965 }
966
967 up->device = dev;
968 dd = &dev->ddesc;
969 /* Try a few times in case the device is slow (i.e. outside specs.) */
970 for (i = 0; i < 3; i++) {
971 /* Get the first 8 bytes of the device descriptor. */
972 err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
973 if (!err)
974 break;
975 usbd_delay_ms(dev, 200);
976 }
977 if (err) {
978 DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
979 "failed\n", addr));
980 usbd_remove_device(dev, up);
981 return (err);
982 }
983
984 DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
985 "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n",
986 addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
987 dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
988 dev->lowspeed));
989
990 if (dd->bDescriptorType != UDESC_DEVICE) {
991 /* Illegal device descriptor */
992 DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",
993 dd->bDescriptorType));
994 usbd_remove_device(dev, up);
995 return (USBD_INVAL);
996 }
997
998 if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
999 DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength));
1000 usbd_remove_device(dev, up);
1001 return (USBD_INVAL);
1002 }
1003
1004 USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
1005
1006 err = usbd_reload_device_desc(dev);
1007 if (err) {
1008 DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "
1009 "failed\n", addr));
1010 usbd_remove_device(dev, up);
1011 return (err);
1012 }
1013
1014 /* Set the address */
1015 err = usbd_set_address(dev, addr);
1016 DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr));
1017 if (err) {
1018 DPRINTFN(-1,("usb_new_device: set address %d failed\n", addr));
1019 err = USBD_SET_ADDR_FAILED;
1020 usbd_remove_device(dev, up);
1021 return (err);
1022 }
1023 /* Allow device time to set new address */
1024 usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
1025
1026 dev->address = addr; /* New device address now */
1027 bus->devices[addr] = dev;
1028
1029 /* Assume 100mA bus powered for now. Changed when configured. */
1030 dev->power = USB_MIN_POWER;
1031 dev->self_powered = 0;
1032
1033 DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
1034 addr, dev, parent));
1035
1036 usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);
1037
1038 err = usbd_probe_and_attach(parent, dev, port, addr);
1039 if (err) {
1040 usbd_remove_device(dev, up);
1041 return (err);
1042 }
1043
1044 return (USBD_NORMAL_COMPLETION);
1045 }
1046
1047 usbd_status
1048 usbd_reload_device_desc(dev)
1049 usbd_device_handle dev;
1050 {
1051 usbd_status err;
1052
1053 /* Get the full device descriptor. */
1054 err = usbd_get_device_desc(dev, &dev->ddesc);
1055 if (err)
1056 return (err);
1057
1058 /* Figure out what's wrong with this device. */
1059 dev->quirks = usbd_find_quirk(&dev->ddesc);
1060
1061 return (USBD_NORMAL_COMPLETION);
1062 }
1063
1064 void
1065 usbd_remove_device(dev, up)
1066 usbd_device_handle dev;
1067 struct usbd_port *up;
1068 {
1069 DPRINTF(("usbd_remove_device: %p\n", dev));
1070
1071 if (dev->default_pipe != NULL)
1072 usbd_kill_pipe(dev->default_pipe);
1073 up->device = 0;
1074 dev->bus->devices[dev->address] = 0;
1075
1076 free(dev, M_USB);
1077 }
1078
1079 #if defined(__NetBSD__) || defined(__OpenBSD__)
1080 int
1081 usbd_print(aux, pnp)
1082 void *aux;
1083 const char *pnp;
1084 {
1085 struct usb_attach_arg *uaa = aux;
1086 char devinfo[1024];
1087
1088 DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device));
1089 if (pnp) {
1090 if (!uaa->usegeneric)
1091 return (QUIET);
1092 usbd_devinfo(uaa->device, 1, devinfo);
1093 printf("%s, %s", devinfo, pnp);
1094 }
1095 if (uaa->port != 0)
1096 printf(" port %d", uaa->port);
1097 if (uaa->configno != UHUB_UNK_CONFIGURATION)
1098 printf(" configuration %d", uaa->configno);
1099 if (uaa->ifaceno != UHUB_UNK_INTERFACE)
1100 printf(" interface %d", uaa->ifaceno);
1101 #if 0
1102 /*
1103 * It gets very crowded with these locators on the attach line.
1104 * They are not really needed since they are printed in the clear
1105 * by each driver.
1106 */
1107 if (uaa->vendor != UHUB_UNK_VENDOR)
1108 printf(" vendor 0x%04x", uaa->vendor);
1109 if (uaa->product != UHUB_UNK_PRODUCT)
1110 printf(" product 0x%04x", uaa->product);
1111 if (uaa->release != UHUB_UNK_RELEASE)
1112 printf(" release 0x%04x", uaa->release);
1113 #endif
1114 return (UNCONF);
1115 }
1116
1117 #if defined(__NetBSD__)
1118 int
1119 usbd_submatch(parent, cf, aux)
1120 struct device *parent;
1121 struct cfdata *cf;
1122 void *aux;
1123 {
1124 #elif defined(__OpenBSD__)
1125 int
1126 usbd_submatch(parent, match, aux)
1127 struct device *parent;
1128 void *match;
1129 void *aux;
1130 {
1131 struct cfdata *cf = match;
1132 #endif
1133 struct usb_attach_arg *uaa = aux;
1134
1135 DPRINTFN(5,("usbd_submatch port=%d,%d configno=%d,%d "
1136 "ifaceno=%d,%d vendor=%d,%d product=%d,%d release=%d,%d\n",
1137 uaa->port, cf->uhubcf_port,
1138 uaa->configno, cf->uhubcf_configuration,
1139 uaa->ifaceno, cf->uhubcf_interface,
1140 uaa->vendor, cf->uhubcf_vendor,
1141 uaa->product, cf->uhubcf_product,
1142 uaa->release, cf->uhubcf_release));
1143 if (uaa->port != 0 && /* root hub has port 0, it should match */
1144 ((uaa->port != 0 &&
1145 cf->uhubcf_port != UHUB_UNK_PORT &&
1146 cf->uhubcf_port != uaa->port) ||
1147 (uaa->configno != UHUB_UNK_CONFIGURATION &&
1148 cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION &&
1149 cf->uhubcf_configuration != uaa->configno) ||
1150 (uaa->ifaceno != UHUB_UNK_INTERFACE &&
1151 cf->uhubcf_interface != UHUB_UNK_INTERFACE &&
1152 cf->uhubcf_interface != uaa->ifaceno) ||
1153 (uaa->vendor != UHUB_UNK_VENDOR &&
1154 cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
1155 cf->uhubcf_vendor != uaa->vendor) ||
1156 (uaa->product != UHUB_UNK_PRODUCT &&
1157 cf->uhubcf_product != UHUB_UNK_PRODUCT &&
1158 cf->uhubcf_product != uaa->product) ||
1159 (uaa->release != UHUB_UNK_RELEASE &&
1160 cf->uhubcf_release != UHUB_UNK_RELEASE &&
1161 cf->uhubcf_release != uaa->release)
1162 )
1163 )
1164 return 0;
1165 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
1166 }
1167
1168 #endif
1169
1170 void
1171 usbd_fill_deviceinfo(dev, di)
1172 usbd_device_handle dev;
1173 struct usb_device_info *di;
1174 {
1175 struct usbd_port *p;
1176 int i, err, s;
1177
1178 di->bus = USBDEVUNIT(dev->bus->bdev);
1179 di->addr = dev->address;
1180 di->cookie = dev->cookie;
1181 usbd_devinfo_vp(dev, di->vendor, di->product);
1182 usbd_printBCD(di->release, UGETW(dev->ddesc.bcdDevice));
1183 di->vendorNo = UGETW(dev->ddesc.idVendor);
1184 di->productNo = UGETW(dev->ddesc.idProduct);
1185 di->releaseNo = UGETW(dev->ddesc.bcdDevice);
1186 di->class = dev->ddesc.bDeviceClass;
1187 di->subclass = dev->ddesc.bDeviceSubClass;
1188 di->protocol = dev->ddesc.bDeviceProtocol;
1189 di->config = dev->config;
1190 di->power = dev->self_powered ? 0 : dev->power;
1191 di->lowspeed = dev->lowspeed;
1192
1193 if (dev->subdevs != NULL) {
1194 for (i = 0; dev->subdevs[i] &&
1195 i < USB_MAX_DEVNAMES; i++) {
1196 strncpy(di->devnames[i], USBDEVPTRNAME(dev->subdevs[i]),
1197 USB_MAX_DEVNAMELEN);
1198 di->devnames[i][USB_MAX_DEVNAMELEN-1] = '\0';
1199 }
1200 } else {
1201 i = 0;
1202 }
1203 for (/*i is set */; i < USB_MAX_DEVNAMES; i++)
1204 di->devnames[i][0] = 0; /* empty */
1205
1206 if (dev->hub) {
1207 for (i = 0;
1208 i < sizeof(di->ports) / sizeof(di->ports[0]) &&
1209 i < dev->hub->hubdesc.bNbrPorts;
1210 i++) {
1211 p = &dev->hub->ports[i];
1212 if (p->device)
1213 err = p->device->address;
1214 else {
1215 s = UGETW(p->status.wPortStatus);
1216 if (s & UPS_PORT_ENABLED)
1217 err = USB_PORT_ENABLED;
1218 else if (s & UPS_SUSPEND)
1219 err = USB_PORT_SUSPENDED;
1220 else if (s & UPS_PORT_POWER)
1221 err = USB_PORT_POWERED;
1222 else
1223 err = USB_PORT_DISABLED;
1224 }
1225 di->ports[i] = err;
1226 }
1227 di->nports = dev->hub->hubdesc.bNbrPorts;
1228 } else
1229 di->nports = 0;
1230 }
1231
1232 void
1233 usb_free_device(dev)
1234 usbd_device_handle dev;
1235 {
1236 int ifcidx, nifc;
1237
1238 if (dev->default_pipe != NULL)
1239 usbd_kill_pipe(dev->default_pipe);
1240 if (dev->ifaces != NULL) {
1241 nifc = dev->cdesc->bNumInterface;
1242 for (ifcidx = 0; ifcidx < nifc; ifcidx++)
1243 usbd_free_iface_data(dev, ifcidx);
1244 free(dev->ifaces, M_USB);
1245 }
1246 if (dev->cdesc != NULL)
1247 free(dev->cdesc, M_USB);
1248 if (dev->subdevs != NULL)
1249 free(dev->subdevs, M_USB);
1250 free(dev, M_USB);
1251 }
1252
1253 /*
1254 * The general mechanism for detaching drivers works as follows: Each
1255 * driver is responsible for maintaining a reference count on the
1256 * number of outstanding references to its softc (e.g. from
1257 * processing hanging in a read or write). The detach method of the
1258 * driver decrements this counter and flags in the softc that the
1259 * driver is dying and then wakes any sleepers. It then sleeps on the
1260 * softc. Each place that can sleep must maintain the reference
1261 * count. When the reference count drops to -1 (0 is the normal value
1262 * of the reference count) the a wakeup on the softc is performed
1263 * signaling to the detach waiter that all references are gone.
1264 */
1265
1266 /*
1267 * Called from process context when we discover that a port has
1268 * been disconnected.
1269 */
1270 void
1271 usb_disconnect_port(up, parent)
1272 struct usbd_port *up;
1273 device_ptr_t parent;
1274 {
1275 usbd_device_handle dev = up->device;
1276 char *hubname = USBDEVPTRNAME(parent);
1277 int i;
1278
1279 DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
1280 up, dev, up->portno));
1281
1282 #ifdef DIAGNOSTIC
1283 if (dev == NULL) {
1284 printf("usb_disconnect_port: no device\n");
1285 return;
1286 }
1287 #endif
1288
1289 if (dev->subdevs != NULL) {
1290 DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
1291 for (i = 0; dev->subdevs[i]; i++) {
1292 printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]),
1293 hubname);
1294 if (up->portno != 0)
1295 printf(" port %d", up->portno);
1296 printf(" (addr %d) disconnected\n", dev->address);
1297 #if defined(__NetBSD__) || defined(__OpenBSD__)
1298 config_detach(dev->subdevs[i], DETACH_FORCE);
1299 #elif defined(__FreeBSD__)
1300 device_delete_child(device_get_parent(dev->subdevs[i]),
1301 dev->subdevs[i]);
1302 #endif
1303
1304 }
1305 }
1306
1307 usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
1308 dev->bus->devices[dev->address] = NULL;
1309 up->device = NULL;
1310 usb_free_device(dev);
1311 }
1312
1313 #ifdef __OpenBSD__
1314 void *usb_realloc(p, size, pool, flags)
1315 void *p;
1316 u_int size;
1317 int pool;
1318 int flags;
1319 {
1320 void *q;
1321
1322 q = malloc(size, pool, flags);
1323 if (q == NULL)
1324 return (NULL);
1325 bcopy(p, q, size);
1326 free(p, pool);
1327 return (q);
1328 }
1329 #endif
1330