usbdi_util.c revision 1.69
1/* $NetBSD: usbdi_util.c,v 1.69 2017/10/22 14:13:40 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.69 2017/10/22 14:13:40 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/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 58usbd_status 59usbd_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=%d, index=%d, len=%d", 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 75usbd_status 76usbd_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=%d", 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=%d, 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 95usbd_status 96usbd_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=%d", conf, 0, 0, 0); 101 return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d); 102} 103 104usbd_status 105usbd_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=%d", 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=%d, 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 124usbd_status 125usbd_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=%d", conf, 0, 0, 0); 130 return usbd_get_desc(dev, UDESC_BOS, conf, size, d); 131} 132 133usbd_status 134usbd_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 142usbd_status 143usbd_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 156usbd_status 157usbd_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 %p", 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 171usbd_status 172usbd_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 %p addr %d", 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 186usbd_status 187usbd_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 %p port %d", 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 */ 202usbd_status 203usbd_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 %p port %d", 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 218usbd_status 219usbd_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 %p sel %d", 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 233usbd_status 234usbd_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 %p sel %d", 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 248usbd_status 249usbd_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 %p port %d sel %d", 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 263usbd_status 264usbd_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 %p port %d sel %d", 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 278usbd_status 279usbd_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 %p port %d timeout %d", dev, port, timeout, 0); 285 req.bmRequestType = UT_WRITE_CLASS_OTHER; 286 req.bRequest = UR_SET_FEATURE; 287 USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 288 USETW2(req.wIndex, timeout, port); 289 USETW(req.wLength, 0); 290 return usbd_do_request(dev, &req, 0); 291} 292 293usbd_status 294usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout) 295{ 296 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 297 usb_device_request_t req; 298 299 DPRINTF("dev %p port %d timeout %d", dev, port, timeout, 0); 300 req.bmRequestType = UT_WRITE_CLASS_OTHER; 301 req.bRequest = UR_SET_FEATURE; 302 USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 303 USETW2(req.wIndex, timeout, port); 304 USETW(req.wLength, 0); 305 return usbd_do_request(dev, &req, 0); 306} 307 308usbd_status 309usbd_get_protocol(struct usbd_interface *iface, uint8_t *report) 310{ 311 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 312 struct usbd_device *dev; 313 usb_device_request_t req; 314 315 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 316 317 if (id == NULL) 318 return USBD_IOERROR; 319 DPRINTFN(4, "iface=%p, endpt=%d", iface, id->bInterfaceNumber, 0, 0); 320 321 usbd_interface2device_handle(iface, &dev); 322 req.bmRequestType = UT_READ_CLASS_INTERFACE; 323 req.bRequest = UR_GET_PROTOCOL; 324 USETW(req.wValue, 0); 325 USETW(req.wIndex, id->bInterfaceNumber); 326 USETW(req.wLength, 1); 327 return usbd_do_request(dev, &req, report); 328} 329 330usbd_status 331usbd_set_protocol(struct usbd_interface *iface, int report) 332{ 333 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 334 struct usbd_device *dev; 335 usb_device_request_t req; 336 337 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 338 339 if (id == NULL) 340 return USBD_IOERROR; 341 DPRINTFN(4, "iface=%p, report=%d, endpt=%d", iface, report, 342 id->bInterfaceNumber, 0); 343 344 usbd_interface2device_handle(iface, &dev); 345 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 346 req.bRequest = UR_SET_PROTOCOL; 347 USETW(req.wValue, report); 348 USETW(req.wIndex, id->bInterfaceNumber); 349 USETW(req.wLength, 0); 350 return usbd_do_request(dev, &req, 0); 351} 352 353usbd_status 354usbd_set_report(struct usbd_interface *iface, int type, int id, void *data, 355 int len) 356{ 357 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 358 struct usbd_device *dev; 359 usb_device_request_t req; 360 361 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 362 363 DPRINTFN(4, "len=%d", len, 0, 0, 0); 364 if (ifd == NULL) 365 return USBD_IOERROR; 366 usbd_interface2device_handle(iface, &dev); 367 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 368 req.bRequest = UR_SET_REPORT; 369 USETW2(req.wValue, type, id); 370 USETW(req.wIndex, ifd->bInterfaceNumber); 371 USETW(req.wLength, len); 372 return usbd_do_request(dev, &req, data); 373} 374 375usbd_status 376usbd_get_report(struct usbd_interface *iface, int type, int id, void *data, 377 int len) 378{ 379 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 380 struct usbd_device *dev; 381 usb_device_request_t req; 382 383 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 384 385 DPRINTFN(4, "len=%d", len, 0, 0, 0); 386 if (ifd == NULL) 387 return USBD_IOERROR; 388 usbd_interface2device_handle(iface, &dev); 389 req.bmRequestType = UT_READ_CLASS_INTERFACE; 390 req.bRequest = UR_GET_REPORT; 391 USETW2(req.wValue, type, id); 392 USETW(req.wIndex, ifd->bInterfaceNumber); 393 USETW(req.wLength, len); 394 return usbd_do_request(dev, &req, data); 395} 396 397usbd_status 398usbd_set_idle(struct usbd_interface *iface, int duration, int id) 399{ 400 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 401 struct usbd_device *dev; 402 usb_device_request_t req; 403 404 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 405 406 DPRINTFN(4, "duration %d id %d", duration, id, 0, 0); 407 if (ifd == NULL) 408 return USBD_IOERROR; 409 usbd_interface2device_handle(iface, &dev); 410 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 411 req.bRequest = UR_SET_IDLE; 412 USETW2(req.wValue, duration, id); 413 USETW(req.wIndex, ifd->bInterfaceNumber); 414 USETW(req.wLength, 0); 415 return usbd_do_request(dev, &req, 0); 416} 417 418usbd_status 419usbd_get_report_descriptor(struct usbd_device *dev, int ifcno, 420 int size, void *d) 421{ 422 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 423 usb_device_request_t req; 424 425 DPRINTF("dev %p ifcno %d size %d", dev, ifcno, size, 0); 426 req.bmRequestType = UT_READ_INTERFACE; 427 req.bRequest = UR_GET_DESCRIPTOR; 428 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 429 USETW(req.wIndex, ifcno); 430 USETW(req.wLength, size); 431 return usbd_do_request(dev, &req, d); 432} 433 434usb_hid_descriptor_t * 435usbd_get_hid_descriptor(struct usbd_interface *ifc) 436{ 437 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc); 438 struct usbd_device *dev; 439 usb_config_descriptor_t *cdesc; 440 usb_hid_descriptor_t *hd; 441 char *p, *end; 442 443 if (idesc == NULL) 444 return NULL; 445 usbd_interface2device_handle(ifc, &dev); 446 cdesc = usbd_get_config_descriptor(dev); 447 448 p = (char *)idesc + idesc->bLength; 449 end = (char *)cdesc + UGETW(cdesc->wTotalLength); 450 451 for (; p < end; p += hd->bLength) { 452 hd = (usb_hid_descriptor_t *)p; 453 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID) 454 return hd; 455 if (hd->bDescriptorType == UDESC_INTERFACE) 456 break; 457 } 458 return NULL; 459} 460 461usbd_status 462usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep) 463{ 464 usb_interface_descriptor_t *id; 465 usb_hid_descriptor_t *hid; 466 struct usbd_device *dev; 467 usbd_status err; 468 469 usbd_interface2device_handle(ifc, &dev); 470 id = usbd_get_interface_descriptor(ifc); 471 if (id == NULL) 472 return USBD_INVAL; 473 hid = usbd_get_hid_descriptor(ifc); 474 if (hid == NULL) 475 return USBD_IOERROR; 476 *sizep = UGETW(hid->descrs[0].wDescriptorLength); 477 *descp = kmem_alloc(*sizep, KM_SLEEP); 478 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 479 *sizep, *descp); 480 if (err) { 481 kmem_free(*descp, *sizep); 482 *descp = NULL; 483 return err; 484 } 485 return USBD_NORMAL_COMPLETION; 486} 487 488usbd_status 489usbd_get_config(struct usbd_device *dev, uint8_t *conf) 490{ 491 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 492 usb_device_request_t req; 493 494 DPRINTF("dev %p", dev, 0, 0, 0); 495 req.bmRequestType = UT_READ_DEVICE; 496 req.bRequest = UR_GET_CONFIG; 497 USETW(req.wValue, 0); 498 USETW(req.wIndex, 0); 499 USETW(req.wLength, 1); 500 return usbd_do_request(dev, &req, conf); 501} 502 503usbd_status 504usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 505 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 506{ 507 usbd_status err; 508 509 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 510 511 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 512 DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0); 513 err = usbd_sync_transfer_sig(xfer); 514 515 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 516 DPRINTFN(1, "transferred %d", *size, 0, 0, 0); 517 if (err) { 518 usbd_clear_endpoint_stall(pipe); 519 } 520 USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0); 521 522 return err; 523} 524 525usbd_status 526usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 527 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 528{ 529 usbd_status err; 530 531 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 532 533 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 534 535 DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0); 536 err = usbd_sync_transfer_sig(xfer); 537 538 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 539 540 DPRINTFN(1, "transferred %d", *size, 0, 0, 0); 541 if (err) { 542 usbd_clear_endpoint_stall(pipe); 543 } 544 USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0); 545 546 return err; 547} 548 549void 550usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock) 551{ 552 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 553 554 DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0); 555 if (cv_timedwait(cv, lock, hz * 60)) // dv, PZERO, "usbdet", hz * 60 556 printf("usb_detach_wait: %s didn't detach\n", 557 device_xname(dv)); 558 DPRINTFN(1, "done", 0, 0, 0, 0); 559} 560 561void 562usb_detach_broadcast(device_t dv, kcondvar_t *cv) 563{ 564 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 565 566 DPRINTFN(1, "for dv %p", dv, 0, 0, 0); 567 cv_broadcast(cv); 568} 569 570void 571usb_detach_waitold(device_t dv) 572{ 573 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 574 575 DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0); 576 if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */ 577 printf("usb_detach_waitold: %s didn't detach\n", 578 device_xname(dv)); 579 DPRINTFN(1, "done", 0, 0, 0, 0); 580} 581 582void 583usb_detach_wakeupold(device_t dv) 584{ 585 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 586 587 DPRINTFN(1, "for dv %p", dv, 0, 0, 0); 588 wakeup(dv); /* XXXSMP ok */ 589} 590 591const usb_cdc_descriptor_t * 592usb_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. */ 609const usb_cdc_descriptor_t * 610usb_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