1 /* $NetBSD: usbdi_util.c,v 1.70 2017/10/28 00:37:13 pgoyette 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.70 2017/10/28 00:37:13 pgoyette 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/usbhist.h> 54 55 #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbdebug,1,FMT,A,B,C,D) 56 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbdebug,N,FMT,A,B,C,D) 57 58 usbd_status 59 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc) 60 { 61 usb_device_request_t req; 62 63 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 64 65 DPRINTFN(3,"type=%jd, index=%jd, len=%jd", type, index, len, 0); 66 67 req.bmRequestType = UT_READ_DEVICE; 68 req.bRequest = UR_GET_DESCRIPTOR; 69 USETW2(req.wValue, type, index); 70 USETW(req.wIndex, 0); 71 USETW(req.wLength, len); 72 return usbd_do_request(dev, &req, desc); 73 } 74 75 usbd_status 76 usbd_get_config_desc(struct usbd_device *dev, int confidx, 77 usb_config_descriptor_t *d) 78 { 79 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 80 usbd_status err; 81 82 DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0); 83 err = usbd_get_desc(dev, UDESC_CONFIG, confidx, 84 USB_CONFIG_DESCRIPTOR_SIZE, d); 85 if (err) 86 return err; 87 if (d->bDescriptorType != UDESC_CONFIG) { 88 DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d", 89 confidx, d->bLength, d->bDescriptorType, 0); 90 return USBD_INVAL; 91 } 92 return USBD_NORMAL_COMPLETION; 93 } 94 95 usbd_status 96 usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size) 97 { 98 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 99 100 DPRINTFN(3, "conf=%jd", conf, 0, 0, 0); 101 return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d); 102 } 103 104 usbd_status 105 usbd_get_bos_desc(struct usbd_device *dev, int confidx, 106 usb_bos_descriptor_t *d) 107 { 108 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 109 usbd_status err; 110 111 DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0); 112 err = usbd_get_desc(dev, UDESC_BOS, confidx, 113 USB_BOS_DESCRIPTOR_SIZE, d); 114 if (err) 115 return err; 116 if (d->bDescriptorType != UDESC_BOS) { 117 DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d", 118 confidx, d->bLength, d->bDescriptorType, 0); 119 return USBD_INVAL; 120 } 121 return USBD_NORMAL_COMPLETION; 122 } 123 124 usbd_status 125 usbd_get_bos_desc_full(struct usbd_device *dev, int conf, void *d, int size) 126 { 127 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 128 129 DPRINTFN(3, "conf=%jd", conf, 0, 0, 0); 130 return usbd_get_desc(dev, UDESC_BOS, conf, size, d); 131 } 132 133 usbd_status 134 usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d) 135 { 136 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 137 138 return usbd_get_desc(dev, UDESC_DEVICE, 139 0, USB_DEVICE_DESCRIPTOR_SIZE, d); 140 } 141 142 usbd_status 143 usbd_get_device_status(struct usbd_device *dev, usb_status_t *st) 144 { 145 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 146 usb_device_request_t req; 147 148 req.bmRequestType = UT_READ_DEVICE; 149 req.bRequest = UR_GET_STATUS; 150 USETW(req.wValue, 0); 151 USETW(req.wIndex, 0); 152 USETW(req.wLength, sizeof(usb_status_t)); 153 return usbd_do_request(dev, &req, st); 154 } 155 156 usbd_status 157 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st) 158 { 159 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 160 usb_device_request_t req; 161 162 DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0); 163 req.bmRequestType = UT_READ_CLASS_DEVICE; 164 req.bRequest = UR_GET_STATUS; 165 USETW(req.wValue, 0); 166 USETW(req.wIndex, 0); 167 USETW(req.wLength, sizeof(usb_hub_status_t)); 168 return usbd_do_request(dev, &req, st); 169 } 170 171 usbd_status 172 usbd_set_address(struct usbd_device *dev, int addr) 173 { 174 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 175 usb_device_request_t req; 176 177 DPRINTF("dev %#jx addr %jd", (uintptr_t)dev, addr, 0, 0); 178 req.bmRequestType = UT_WRITE_DEVICE; 179 req.bRequest = UR_SET_ADDRESS; 180 USETW(req.wValue, addr); 181 USETW(req.wIndex, 0); 182 USETW(req.wLength, 0); 183 return usbd_do_request(dev, &req, 0); 184 } 185 186 usbd_status 187 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps) 188 { 189 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 190 usb_device_request_t req; 191 192 DPRINTF("dev %#jx port %jd", (uintptr_t)dev, port, 0, 0); 193 req.bmRequestType = UT_READ_CLASS_OTHER; 194 req.bRequest = UR_GET_STATUS; 195 USETW(req.wValue, 0); 196 USETW(req.wIndex, port); 197 USETW(req.wLength, sizeof(*ps)); 198 return usbd_do_request(dev, &req, ps); 199 } 200 201 /* USB 3.1 10.16.2.6, 10.16.2.6.3 */ 202 usbd_status 203 usbd_get_port_status_ext(struct usbd_device *dev, int port, 204 usb_port_status_ext_t *pse) 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 USETW2(req.wValue, 0, UR_PST_EXT_PORT_STATUS); 213 USETW(req.wIndex, port); 214 USETW(req.wLength, sizeof(*pse)); 215 return usbd_do_request(dev, &req, pse); 216 } 217 218 usbd_status 219 usbd_clear_hub_feature(struct usbd_device *dev, int sel) 220 { 221 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 222 usb_device_request_t req; 223 224 DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0); 225 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 226 req.bRequest = UR_CLEAR_FEATURE; 227 USETW(req.wValue, sel); 228 USETW(req.wIndex, 0); 229 USETW(req.wLength, 0); 230 return usbd_do_request(dev, &req, 0); 231 } 232 233 usbd_status 234 usbd_set_hub_feature(struct usbd_device *dev, int sel) 235 { 236 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 237 usb_device_request_t req; 238 239 DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0); 240 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 241 req.bRequest = UR_SET_FEATURE; 242 USETW(req.wValue, sel); 243 USETW(req.wIndex, 0); 244 USETW(req.wLength, 0); 245 return usbd_do_request(dev, &req, 0); 246 } 247 248 usbd_status 249 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel) 250 { 251 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 252 usb_device_request_t req; 253 254 DPRINTF("dev %#jx port %jd sel %jd", (uintptr_t)dev, port, sel, 0); 255 req.bmRequestType = UT_WRITE_CLASS_OTHER; 256 req.bRequest = UR_CLEAR_FEATURE; 257 USETW(req.wValue, sel); 258 USETW(req.wIndex, port); 259 USETW(req.wLength, 0); 260 return usbd_do_request(dev, &req, 0); 261 } 262 263 usbd_status 264 usbd_set_port_feature(struct usbd_device *dev, int port, int sel) 265 { 266 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 267 usb_device_request_t req; 268 269 DPRINTF("dev %#jx port %jd sel %.d", (uintptr_t)dev, sel, 0, 0); 270 req.bmRequestType = UT_WRITE_CLASS_OTHER; 271 req.bRequest = UR_SET_FEATURE; 272 USETW(req.wValue, sel); 273 USETW(req.wIndex, port); 274 USETW(req.wLength, 0); 275 return usbd_do_request(dev, &req, 0); 276 } 277 278 usbd_status 279 usbd_set_port_u1_timeout(struct usbd_device *dev, int port, int timeout) 280 { 281 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 282 usb_device_request_t req; 283 284 DPRINTF("dev %#jx port %jd timeout %.d", (uintptr_t)dev, port, 285 timeout, 0); 286 req.bmRequestType = UT_WRITE_CLASS_OTHER; 287 req.bRequest = UR_SET_FEATURE; 288 USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 289 USETW2(req.wIndex, timeout, port); 290 USETW(req.wLength, 0); 291 return usbd_do_request(dev, &req, 0); 292 } 293 294 usbd_status 295 usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout) 296 { 297 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 298 usb_device_request_t req; 299 300 DPRINTF("dev %#jx port %jd timeout %jd", (uintptr_t)dev, port, 301 timeout, 0); 302 req.bmRequestType = UT_WRITE_CLASS_OTHER; 303 req.bRequest = UR_SET_FEATURE; 304 USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 305 USETW2(req.wIndex, timeout, port); 306 USETW(req.wLength, 0); 307 return usbd_do_request(dev, &req, 0); 308 } 309 310 usbd_status 311 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report) 312 { 313 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 314 struct usbd_device *dev; 315 usb_device_request_t req; 316 317 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 318 319 if (id == NULL) 320 return USBD_IOERROR; 321 DPRINTFN(4, "iface=%#jx, endpt=%jd", (uintptr_t)iface, 322 id->bInterfaceNumber, 0, 0); 323 324 usbd_interface2device_handle(iface, &dev); 325 req.bmRequestType = UT_READ_CLASS_INTERFACE; 326 req.bRequest = UR_GET_PROTOCOL; 327 USETW(req.wValue, 0); 328 USETW(req.wIndex, id->bInterfaceNumber); 329 USETW(req.wLength, 1); 330 return usbd_do_request(dev, &req, report); 331 } 332 333 usbd_status 334 usbd_set_protocol(struct usbd_interface *iface, int report) 335 { 336 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 337 struct usbd_device *dev; 338 usb_device_request_t req; 339 340 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 341 342 if (id == NULL) 343 return USBD_IOERROR; 344 DPRINTFN(4, "iface=%#jx, report=%jd, endpt=%jd", (uintptr_t)iface, 345 report, id->bInterfaceNumber, 0); 346 347 usbd_interface2device_handle(iface, &dev); 348 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 349 req.bRequest = UR_SET_PROTOCOL; 350 USETW(req.wValue, report); 351 USETW(req.wIndex, id->bInterfaceNumber); 352 USETW(req.wLength, 0); 353 return usbd_do_request(dev, &req, 0); 354 } 355 356 usbd_status 357 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data, 358 int len) 359 { 360 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 361 struct usbd_device *dev; 362 usb_device_request_t req; 363 364 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 365 366 DPRINTFN(4, "len=%jd", len, 0, 0, 0); 367 if (ifd == NULL) 368 return USBD_IOERROR; 369 usbd_interface2device_handle(iface, &dev); 370 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 371 req.bRequest = UR_SET_REPORT; 372 USETW2(req.wValue, type, id); 373 USETW(req.wIndex, ifd->bInterfaceNumber); 374 USETW(req.wLength, len); 375 return usbd_do_request(dev, &req, data); 376 } 377 378 usbd_status 379 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data, 380 int len) 381 { 382 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 383 struct usbd_device *dev; 384 usb_device_request_t req; 385 386 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 387 388 DPRINTFN(4, "len=%jd", len, 0, 0, 0); 389 if (ifd == NULL) 390 return USBD_IOERROR; 391 usbd_interface2device_handle(iface, &dev); 392 req.bmRequestType = UT_READ_CLASS_INTERFACE; 393 req.bRequest = UR_GET_REPORT; 394 USETW2(req.wValue, type, id); 395 USETW(req.wIndex, ifd->bInterfaceNumber); 396 USETW(req.wLength, len); 397 return usbd_do_request(dev, &req, data); 398 } 399 400 usbd_status 401 usbd_set_idle(struct usbd_interface *iface, int duration, int id) 402 { 403 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 404 struct usbd_device *dev; 405 usb_device_request_t req; 406 407 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 408 409 DPRINTFN(4, "duration %jd id %jd", duration, id, 0, 0); 410 if (ifd == NULL) 411 return USBD_IOERROR; 412 usbd_interface2device_handle(iface, &dev); 413 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 414 req.bRequest = UR_SET_IDLE; 415 USETW2(req.wValue, duration, id); 416 USETW(req.wIndex, ifd->bInterfaceNumber); 417 USETW(req.wLength, 0); 418 return usbd_do_request(dev, &req, 0); 419 } 420 421 usbd_status 422 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno, 423 int size, void *d) 424 { 425 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 426 usb_device_request_t req; 427 428 DPRINTF("dev %#jx ifcno %jd size %jd", (uintptr_t)dev, ifcno, size, 0); 429 req.bmRequestType = UT_READ_INTERFACE; 430 req.bRequest = UR_GET_DESCRIPTOR; 431 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 432 USETW(req.wIndex, ifcno); 433 USETW(req.wLength, size); 434 return usbd_do_request(dev, &req, d); 435 } 436 437 usb_hid_descriptor_t * 438 usbd_get_hid_descriptor(struct usbd_interface *ifc) 439 { 440 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc); 441 struct usbd_device *dev; 442 usb_config_descriptor_t *cdesc; 443 usb_hid_descriptor_t *hd; 444 char *p, *end; 445 446 if (idesc == NULL) 447 return NULL; 448 usbd_interface2device_handle(ifc, &dev); 449 cdesc = usbd_get_config_descriptor(dev); 450 451 p = (char *)idesc + idesc->bLength; 452 end = (char *)cdesc + UGETW(cdesc->wTotalLength); 453 454 for (; p < end; p += hd->bLength) { 455 hd = (usb_hid_descriptor_t *)p; 456 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID) 457 return hd; 458 if (hd->bDescriptorType == UDESC_INTERFACE) 459 break; 460 } 461 return NULL; 462 } 463 464 usbd_status 465 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep) 466 { 467 usb_interface_descriptor_t *id; 468 usb_hid_descriptor_t *hid; 469 struct usbd_device *dev; 470 usbd_status err; 471 472 usbd_interface2device_handle(ifc, &dev); 473 id = usbd_get_interface_descriptor(ifc); 474 if (id == NULL) 475 return USBD_INVAL; 476 hid = usbd_get_hid_descriptor(ifc); 477 if (hid == NULL) 478 return USBD_IOERROR; 479 *sizep = UGETW(hid->descrs[0].wDescriptorLength); 480 *descp = kmem_alloc(*sizep, KM_SLEEP); 481 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 482 *sizep, *descp); 483 if (err) { 484 kmem_free(*descp, *sizep); 485 *descp = NULL; 486 return err; 487 } 488 return USBD_NORMAL_COMPLETION; 489 } 490 491 usbd_status 492 usbd_get_config(struct usbd_device *dev, uint8_t *conf) 493 { 494 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 495 usb_device_request_t req; 496 497 DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0); 498 req.bmRequestType = UT_READ_DEVICE; 499 req.bRequest = UR_GET_CONFIG; 500 USETW(req.wValue, 0); 501 USETW(req.wIndex, 0); 502 USETW(req.wLength, 1); 503 return usbd_do_request(dev, &req, conf); 504 } 505 506 usbd_status 507 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 508 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 509 { 510 usbd_status err; 511 512 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 513 514 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 515 DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0); 516 err = usbd_sync_transfer_sig(xfer); 517 518 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 519 DPRINTFN(1, "transferred %jd", *size, 0, 0, 0); 520 if (err) { 521 usbd_clear_endpoint_stall(pipe); 522 } 523 USBHIST_LOG(usbdebug, "<- done xfer %#jx err %d", (uintptr_t)xfer, 524 err, 0, 0); 525 526 return err; 527 } 528 529 usbd_status 530 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 531 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 532 { 533 usbd_status err; 534 535 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 536 537 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 538 539 DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0); 540 err = usbd_sync_transfer_sig(xfer); 541 542 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 543 544 DPRINTFN(1, "transferred %jd", *size, 0, 0, 0); 545 if (err) { 546 usbd_clear_endpoint_stall(pipe); 547 } 548 USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer, 549 err, 0, 0); 550 551 return err; 552 } 553 554 void 555 usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock) 556 { 557 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 558 559 DPRINTFN(1, "waiting for dv %#jx", (uintptr_t)dv, 0, 0, 0); 560 if (cv_timedwait(cv, lock, hz * 60)) // dv, PZERO, "usbdet", hz * 60 561 printf("usb_detach_wait: %s didn't detach\n", 562 device_xname(dv)); 563 DPRINTFN(1, "done", 0, 0, 0, 0); 564 } 565 566 void 567 usb_detach_broadcast(device_t dv, kcondvar_t *cv) 568 { 569 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 570 571 DPRINTFN(1, "for dv %#jx", (uintptr_t)dv, 0, 0, 0); 572 cv_broadcast(cv); 573 } 574 575 void 576 usb_detach_waitold(device_t dv) 577 { 578 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 579 580 DPRINTFN(1, "waiting for dv %#jx", (uintptr_t)dv, 0, 0, 0); 581 if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */ 582 printf("usb_detach_waitold: %s didn't detach\n", 583 device_xname(dv)); 584 DPRINTFN(1, "done", 0, 0, 0, 0); 585 } 586 587 void 588 usb_detach_wakeupold(device_t dv) 589 { 590 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 591 592 DPRINTFN(1, "for dv %#jx", (uintptr_t)dv, 0, 0, 0); 593 wakeup(dv); /* XXXSMP ok */ 594 } 595 596 const usb_cdc_descriptor_t * 597 usb_find_desc(struct usbd_device *dev, int type, int subtype) 598 { 599 usbd_desc_iter_t iter; 600 const usb_cdc_descriptor_t *desc; 601 602 usb_desc_iter_init(dev, &iter); 603 for (;;) { 604 desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter); 605 if (!desc || (desc->bDescriptorType == type && 606 (subtype == USBD_CDCSUBTYPE_ANY || 607 subtype == desc->bDescriptorSubtype))) 608 break; 609 } 610 return desc; 611 } 612 613 /* same as usb_find_desc(), but searches only in the specified interface. */ 614 const usb_cdc_descriptor_t * 615 usb_find_desc_if(struct usbd_device *dev, int type, int subtype, 616 usb_interface_descriptor_t *id) 617 { 618 usbd_desc_iter_t iter; 619 const usb_cdc_descriptor_t *desc; 620 621 if (id == NULL) 622 return usb_find_desc(dev, type, subtype); 623 624 usb_desc_iter_init(dev, &iter); 625 626 iter.cur = (void *)id; /* start from the interface desc */ 627 usb_desc_iter_next(&iter); /* and skip it */ 628 629 while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter)) 630 != NULL) { 631 if (desc->bDescriptorType == UDESC_INTERFACE) { 632 /* we ran into the next interface --- not found */ 633 return NULL; 634 } 635 if (desc->bDescriptorType == type && 636 (subtype == USBD_CDCSUBTYPE_ANY || 637 subtype == desc->bDescriptorSubtype)) 638 break; 639 } 640 return desc; 641 } 642