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