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