1 /* $NetBSD: usbdi_util.c,v 1.73 2019/02/07 13:20:41 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net) at 9 * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.73 2019/02/07 13:20:41 skrll Exp $"); 35 36 #ifdef _KERNEL_OPT 37 #include "opt_usb.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/kmem.h> 44 #include <sys/proc.h> 45 #include <sys/device.h> 46 #include <sys/bus.h> 47 48 #include <dev/usb/usb.h> 49 #include <dev/usb/usbhid.h> 50 #include <dev/usb/usbdi.h> 51 #include <dev/usb/usbdivar.h> 52 #include <dev/usb/usbdi_util.h> 53 #include <dev/usb/usb_quirks.h> 54 #include <dev/usb/usbhist.h> 55 56 #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbdebug,1,FMT,A,B,C,D) 57 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbdebug,N,FMT,A,B,C,D) 58 59 usbd_status 60 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc) 61 { 62 usb_device_request_t req; 63 usbd_status err; 64 65 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 66 67 DPRINTFN(3,"type=%jd, index=%jd, len=%jd", type, index, len, 0); 68 69 /* 70 * Provide hard-coded configuration descriptors 71 * for devices that may corrupt it. This cannot 72 * be done for device descriptors which are used 73 * to identify the device. 74 */ 75 if (type != UDESC_DEVICE && 76 dev->ud_quirks->uq_flags & UQ_DESC_CORRUPT) { 77 err = usbd_get_desc_fake(dev, type, index, len, desc); 78 goto out; 79 } 80 81 req.bmRequestType = UT_READ_DEVICE; 82 req.bRequest = UR_GET_DESCRIPTOR; 83 USETW2(req.wValue, type, index); 84 USETW(req.wIndex, 0); 85 USETW(req.wLength, len); 86 err = usbd_do_request(dev, &req, desc); 87 88 out: 89 return err; 90 } 91 92 usbd_status 93 usbd_get_config_desc(struct usbd_device *dev, int confidx, 94 usb_config_descriptor_t *d) 95 { 96 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 97 usbd_status err; 98 99 DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0); 100 err = usbd_get_desc(dev, UDESC_CONFIG, confidx, 101 USB_CONFIG_DESCRIPTOR_SIZE, d); 102 if (err) 103 return err; 104 if (d->bDescriptorType != UDESC_CONFIG) { 105 DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d", 106 confidx, d->bLength, d->bDescriptorType, 0); 107 return USBD_INVAL; 108 } 109 return USBD_NORMAL_COMPLETION; 110 } 111 112 usbd_status 113 usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size) 114 { 115 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 116 117 DPRINTFN(3, "conf=%jd", conf, 0, 0, 0); 118 return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d); 119 } 120 121 usbd_status 122 usbd_get_bos_desc(struct usbd_device *dev, int confidx, 123 usb_bos_descriptor_t *d) 124 { 125 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 126 usbd_status err; 127 128 DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0); 129 err = usbd_get_desc(dev, UDESC_BOS, confidx, 130 USB_BOS_DESCRIPTOR_SIZE, d); 131 if (err) 132 return err; 133 if (d->bDescriptorType != UDESC_BOS) { 134 DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d", 135 confidx, d->bLength, d->bDescriptorType, 0); 136 return USBD_INVAL; 137 } 138 return USBD_NORMAL_COMPLETION; 139 } 140 141 usbd_status 142 usbd_get_bos_desc_full(struct usbd_device *dev, int conf, void *d, int size) 143 { 144 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 145 146 DPRINTFN(3, "conf=%jd", conf, 0, 0, 0); 147 return usbd_get_desc(dev, UDESC_BOS, conf, size, d); 148 } 149 150 usbd_status 151 usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d) 152 { 153 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 154 155 return usbd_get_desc(dev, UDESC_DEVICE, 156 0, USB_DEVICE_DESCRIPTOR_SIZE, d); 157 } 158 159 usbd_status 160 usbd_get_device_status(struct usbd_device *dev, usb_status_t *st) 161 { 162 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 163 usb_device_request_t req; 164 165 req.bmRequestType = UT_READ_DEVICE; 166 req.bRequest = UR_GET_STATUS; 167 USETW(req.wValue, 0); 168 USETW(req.wIndex, 0); 169 USETW(req.wLength, sizeof(usb_status_t)); 170 return usbd_do_request(dev, &req, st); 171 } 172 173 usbd_status 174 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st) 175 { 176 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 177 usb_device_request_t req; 178 179 DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0); 180 req.bmRequestType = UT_READ_CLASS_DEVICE; 181 req.bRequest = UR_GET_STATUS; 182 USETW(req.wValue, 0); 183 USETW(req.wIndex, 0); 184 USETW(req.wLength, sizeof(usb_hub_status_t)); 185 return usbd_do_request(dev, &req, st); 186 } 187 188 usbd_status 189 usbd_set_address(struct usbd_device *dev, int addr) 190 { 191 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 192 usb_device_request_t req; 193 194 DPRINTF("dev %#jx addr %jd", (uintptr_t)dev, addr, 0, 0); 195 req.bmRequestType = UT_WRITE_DEVICE; 196 req.bRequest = UR_SET_ADDRESS; 197 USETW(req.wValue, addr); 198 USETW(req.wIndex, 0); 199 USETW(req.wLength, 0); 200 return usbd_do_request(dev, &req, 0); 201 } 202 203 usbd_status 204 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps) 205 { 206 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 207 usb_device_request_t req; 208 209 DPRINTF("dev %#jx port %jd", (uintptr_t)dev, port, 0, 0); 210 req.bmRequestType = UT_READ_CLASS_OTHER; 211 req.bRequest = UR_GET_STATUS; 212 USETW(req.wValue, 0); 213 USETW(req.wIndex, port); 214 USETW(req.wLength, sizeof(*ps)); 215 return usbd_do_request(dev, &req, ps); 216 } 217 218 /* USB 3.1 10.16.2.6, 10.16.2.6.3 */ 219 usbd_status 220 usbd_get_port_status_ext(struct usbd_device *dev, int port, 221 usb_port_status_ext_t *pse) 222 { 223 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 224 usb_device_request_t req; 225 226 DPRINTF("dev %#jx port %jd", (uintptr_t)dev, port, 0, 0); 227 req.bmRequestType = UT_READ_CLASS_OTHER; 228 req.bRequest = UR_GET_STATUS; 229 USETW2(req.wValue, 0, UR_PST_EXT_PORT_STATUS); 230 USETW(req.wIndex, port); 231 USETW(req.wLength, sizeof(*pse)); 232 return usbd_do_request(dev, &req, pse); 233 } 234 235 usbd_status 236 usbd_clear_hub_feature(struct usbd_device *dev, int sel) 237 { 238 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 239 usb_device_request_t req; 240 241 DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0); 242 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 243 req.bRequest = UR_CLEAR_FEATURE; 244 USETW(req.wValue, sel); 245 USETW(req.wIndex, 0); 246 USETW(req.wLength, 0); 247 return usbd_do_request(dev, &req, 0); 248 } 249 250 usbd_status 251 usbd_set_hub_feature(struct usbd_device *dev, int sel) 252 { 253 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 254 usb_device_request_t req; 255 256 DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0); 257 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 258 req.bRequest = UR_SET_FEATURE; 259 USETW(req.wValue, sel); 260 USETW(req.wIndex, 0); 261 USETW(req.wLength, 0); 262 return usbd_do_request(dev, &req, 0); 263 } 264 265 usbd_status 266 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel) 267 { 268 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 269 usb_device_request_t req; 270 271 DPRINTF("dev %#jx port %jd sel %jd", (uintptr_t)dev, port, sel, 0); 272 req.bmRequestType = UT_WRITE_CLASS_OTHER; 273 req.bRequest = UR_CLEAR_FEATURE; 274 USETW(req.wValue, sel); 275 USETW(req.wIndex, port); 276 USETW(req.wLength, 0); 277 return usbd_do_request(dev, &req, 0); 278 } 279 280 usbd_status 281 usbd_set_port_feature(struct usbd_device *dev, int port, int sel) 282 { 283 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 284 usb_device_request_t req; 285 286 DPRINTF("dev %#jx port %jd sel %.d", (uintptr_t)dev, sel, 0, 0); 287 req.bmRequestType = UT_WRITE_CLASS_OTHER; 288 req.bRequest = UR_SET_FEATURE; 289 USETW(req.wValue, sel); 290 USETW(req.wIndex, port); 291 USETW(req.wLength, 0); 292 return usbd_do_request(dev, &req, 0); 293 } 294 295 usbd_status 296 usbd_set_port_u1_timeout(struct usbd_device *dev, int port, int timeout) 297 { 298 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 299 usb_device_request_t req; 300 301 DPRINTF("dev %#jx port %jd timeout %.d", (uintptr_t)dev, port, 302 timeout, 0); 303 req.bmRequestType = UT_WRITE_CLASS_OTHER; 304 req.bRequest = UR_SET_FEATURE; 305 USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 306 USETW2(req.wIndex, timeout, port); 307 USETW(req.wLength, 0); 308 return usbd_do_request(dev, &req, 0); 309 } 310 311 usbd_status 312 usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout) 313 { 314 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 315 usb_device_request_t req; 316 317 DPRINTF("dev %#jx port %jd timeout %jd", (uintptr_t)dev, port, 318 timeout, 0); 319 req.bmRequestType = UT_WRITE_CLASS_OTHER; 320 req.bRequest = UR_SET_FEATURE; 321 USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 322 USETW2(req.wIndex, timeout, port); 323 USETW(req.wLength, 0); 324 return usbd_do_request(dev, &req, 0); 325 } 326 327 usbd_status 328 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report) 329 { 330 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 331 struct usbd_device *dev; 332 usb_device_request_t req; 333 334 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 335 336 if (id == NULL) 337 return USBD_IOERROR; 338 DPRINTFN(4, "iface=%#jx, endpt=%jd", (uintptr_t)iface, 339 id->bInterfaceNumber, 0, 0); 340 341 usbd_interface2device_handle(iface, &dev); 342 req.bmRequestType = UT_READ_CLASS_INTERFACE; 343 req.bRequest = UR_GET_PROTOCOL; 344 USETW(req.wValue, 0); 345 USETW(req.wIndex, id->bInterfaceNumber); 346 USETW(req.wLength, 1); 347 return usbd_do_request(dev, &req, report); 348 } 349 350 usbd_status 351 usbd_set_protocol(struct usbd_interface *iface, int report) 352 { 353 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 354 struct usbd_device *dev; 355 usb_device_request_t req; 356 357 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 358 359 if (id == NULL) 360 return USBD_IOERROR; 361 DPRINTFN(4, "iface=%#jx, report=%jd, endpt=%jd", (uintptr_t)iface, 362 report, id->bInterfaceNumber, 0); 363 364 usbd_interface2device_handle(iface, &dev); 365 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 366 req.bRequest = UR_SET_PROTOCOL; 367 USETW(req.wValue, report); 368 USETW(req.wIndex, id->bInterfaceNumber); 369 USETW(req.wLength, 0); 370 return usbd_do_request(dev, &req, 0); 371 } 372 373 usbd_status 374 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data, 375 int len) 376 { 377 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 378 struct usbd_device *dev; 379 usb_device_request_t req; 380 381 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 382 383 DPRINTFN(4, "len=%jd", len, 0, 0, 0); 384 if (ifd == NULL) 385 return USBD_IOERROR; 386 usbd_interface2device_handle(iface, &dev); 387 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 388 req.bRequest = UR_SET_REPORT; 389 USETW2(req.wValue, type, id); 390 USETW(req.wIndex, ifd->bInterfaceNumber); 391 USETW(req.wLength, len); 392 return usbd_do_request(dev, &req, data); 393 } 394 395 usbd_status 396 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data, 397 int len) 398 { 399 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 400 struct usbd_device *dev; 401 usb_device_request_t req; 402 403 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 404 405 DPRINTFN(4, "len=%jd", len, 0, 0, 0); 406 if (ifd == NULL) 407 return USBD_IOERROR; 408 usbd_interface2device_handle(iface, &dev); 409 req.bmRequestType = UT_READ_CLASS_INTERFACE; 410 req.bRequest = UR_GET_REPORT; 411 USETW2(req.wValue, type, id); 412 USETW(req.wIndex, ifd->bInterfaceNumber); 413 USETW(req.wLength, len); 414 return usbd_do_request(dev, &req, data); 415 } 416 417 usbd_status 418 usbd_set_idle(struct usbd_interface *iface, int duration, int id) 419 { 420 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 421 struct usbd_device *dev; 422 usb_device_request_t req; 423 424 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 425 426 DPRINTFN(4, "duration %jd id %jd", duration, id, 0, 0); 427 if (ifd == NULL) 428 return USBD_IOERROR; 429 usbd_interface2device_handle(iface, &dev); 430 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 431 req.bRequest = UR_SET_IDLE; 432 USETW2(req.wValue, duration, id); 433 USETW(req.wIndex, ifd->bInterfaceNumber); 434 USETW(req.wLength, 0); 435 return usbd_do_request(dev, &req, 0); 436 } 437 438 usbd_status 439 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno, 440 int size, void *d) 441 { 442 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 443 usb_device_request_t req; 444 445 DPRINTF("dev %#jx ifcno %jd size %jd", (uintptr_t)dev, ifcno, size, 0); 446 req.bmRequestType = UT_READ_INTERFACE; 447 req.bRequest = UR_GET_DESCRIPTOR; 448 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 449 USETW(req.wIndex, ifcno); 450 USETW(req.wLength, size); 451 return usbd_do_request(dev, &req, d); 452 } 453 454 usb_hid_descriptor_t * 455 usbd_get_hid_descriptor(struct usbd_interface *ifc) 456 { 457 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc); 458 struct usbd_device *dev; 459 usb_config_descriptor_t *cdesc; 460 usb_hid_descriptor_t *hd; 461 char *p, *end; 462 463 if (idesc == NULL) 464 return NULL; 465 usbd_interface2device_handle(ifc, &dev); 466 cdesc = usbd_get_config_descriptor(dev); 467 468 p = (char *)idesc + idesc->bLength; 469 end = (char *)cdesc + UGETW(cdesc->wTotalLength); 470 471 for (; p < end; p += hd->bLength) { 472 hd = (usb_hid_descriptor_t *)p; 473 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID) 474 return hd; 475 if (hd->bDescriptorType == UDESC_INTERFACE) 476 break; 477 } 478 return NULL; 479 } 480 481 usbd_status 482 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep) 483 { 484 usb_interface_descriptor_t *id; 485 usb_hid_descriptor_t *hid; 486 struct usbd_device *dev; 487 usbd_status err; 488 489 usbd_interface2device_handle(ifc, &dev); 490 id = usbd_get_interface_descriptor(ifc); 491 if (id == NULL) 492 return USBD_INVAL; 493 hid = usbd_get_hid_descriptor(ifc); 494 if (hid == NULL) 495 return USBD_IOERROR; 496 *sizep = UGETW(hid->descrs[0].wDescriptorLength); 497 *descp = kmem_alloc(*sizep, KM_SLEEP); 498 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 499 *sizep, *descp); 500 if (err) { 501 kmem_free(*descp, *sizep); 502 *descp = NULL; 503 return err; 504 } 505 return USBD_NORMAL_COMPLETION; 506 } 507 508 usbd_status 509 usbd_get_config(struct usbd_device *dev, uint8_t *conf) 510 { 511 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 512 usb_device_request_t req; 513 514 DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0); 515 req.bmRequestType = UT_READ_DEVICE; 516 req.bRequest = UR_GET_CONFIG; 517 USETW(req.wValue, 0); 518 USETW(req.wIndex, 0); 519 USETW(req.wLength, 1); 520 return usbd_do_request(dev, &req, conf); 521 } 522 523 usbd_status 524 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 525 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 526 { 527 usbd_status err; 528 529 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 530 531 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 532 DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0); 533 err = usbd_sync_transfer_sig(xfer); 534 535 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 536 DPRINTFN(1, "transferred %jd", *size, 0, 0, 0); 537 if (err) { 538 usbd_clear_endpoint_stall(pipe); 539 } 540 USBHIST_LOG(usbdebug, "<- done xfer %#jx err %d", (uintptr_t)xfer, 541 err, 0, 0); 542 543 return err; 544 } 545 546 usbd_status 547 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 548 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 549 { 550 usbd_status err; 551 552 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 553 554 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 555 556 DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0); 557 err = usbd_sync_transfer_sig(xfer); 558 559 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 560 561 DPRINTFN(1, "transferred %jd", *size, 0, 0, 0); 562 if (err) { 563 usbd_clear_endpoint_stall(pipe); 564 } 565 USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer, 566 err, 0, 0); 567 568 return err; 569 } 570 571 void 572 usb_detach_waitold(device_t dv) 573 { 574 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 575 576 DPRINTFN(1, "waiting for dv %#jx", (uintptr_t)dv, 0, 0, 0); 577 if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */ 578 aprint_error_dev(dv, "usb_detach_waitold: didn't detach\n"); 579 DPRINTFN(1, "done", 0, 0, 0, 0); 580 } 581 582 void 583 usb_detach_wakeupold(device_t dv) 584 { 585 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 586 587 DPRINTFN(1, "for dv %#jx", (uintptr_t)dv, 0, 0, 0); 588 wakeup(dv); /* XXXSMP ok */ 589 } 590 591 const usb_cdc_descriptor_t * 592 usb_find_desc(struct usbd_device *dev, int type, int subtype) 593 { 594 usbd_desc_iter_t iter; 595 const usb_cdc_descriptor_t *desc; 596 597 usb_desc_iter_init(dev, &iter); 598 for (;;) { 599 desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter); 600 if (!desc || (desc->bDescriptorType == type && 601 (subtype == USBD_CDCSUBTYPE_ANY || 602 subtype == desc->bDescriptorSubtype))) 603 break; 604 } 605 return desc; 606 } 607 608 /* same as usb_find_desc(), but searches only in the specified interface. */ 609 const usb_cdc_descriptor_t * 610 usb_find_desc_if(struct usbd_device *dev, int type, int subtype, 611 usb_interface_descriptor_t *id) 612 { 613 usbd_desc_iter_t iter; 614 const usb_cdc_descriptor_t *desc; 615 616 if (id == NULL) 617 return usb_find_desc(dev, type, subtype); 618 619 usb_desc_iter_init(dev, &iter); 620 621 iter.cur = (void *)id; /* start from the interface desc */ 622 usb_desc_iter_next(&iter); /* and skip it */ 623 624 while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter)) 625 != NULL) { 626 if (desc->bDescriptorType == UDESC_INTERFACE) { 627 /* we ran into the next interface --- not found */ 628 return NULL; 629 } 630 if (desc->bDescriptorType == type && 631 (subtype == USBD_CDCSUBTYPE_ANY || 632 subtype == desc->bDescriptorSubtype)) 633 break; 634 } 635 return desc; 636 } 637