1 /* $OpenBSD: usbdi_util.c,v 1.25 2008/06/26 05:42:19 ray Exp $ */ 2 /* $NetBSD: usbdi_util.c,v 1.40 2002/07/11 21:14:36 augustss Exp $ */ 3 /* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */ 4 5 /* 6 * Copyright (c) 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Lennart Augustsson (lennart@augustsson.net) at 11 * Carlstedt Research & Technology. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/proc.h> 40 #include <sys/device.h> 41 42 #include <dev/usb/usb.h> 43 #include <dev/usb/usbhid.h> 44 45 #include <dev/usb/usbdi.h> 46 #include <dev/usb/usbdi_util.h> 47 48 #ifdef USB_DEBUG 49 #define DPRINTF(x) do { if (usbdebug) printf x; } while (0) 50 #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0) 51 extern int usbdebug; 52 #else 53 #define DPRINTF(x) 54 #define DPRINTFN(n,x) 55 #endif 56 57 usbd_status 58 usbd_get_desc(usbd_device_handle dev, int type, int index, int len, void *desc) 59 { 60 usb_device_request_t req; 61 62 DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n", type, index, 63 len)); 64 65 req.bmRequestType = UT_READ_DEVICE; 66 req.bRequest = UR_GET_DESCRIPTOR; 67 USETW2(req.wValue, type, index); 68 USETW(req.wIndex, 0); 69 USETW(req.wLength, len); 70 return (usbd_do_request(dev, &req, desc)); 71 } 72 73 usbd_status 74 usbd_get_config_desc(usbd_device_handle dev, int confidx, 75 usb_config_descriptor_t *d) 76 { 77 usbd_status err; 78 79 DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx)); 80 err = usbd_get_desc(dev, UDESC_CONFIG, confidx, 81 USB_CONFIG_DESCRIPTOR_SIZE, d); 82 if (err) 83 return (err); 84 if (d->bDescriptorType != UDESC_CONFIG) { 85 DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc " 86 "len=%d type=%d\n", confidx, d->bLength, 87 d->bDescriptorType)); 88 return (USBD_INVAL); 89 } 90 return (USBD_NORMAL_COMPLETION); 91 } 92 93 usbd_status 94 usbd_get_config_desc_full(usbd_device_handle dev, int conf, void *d, int size) 95 { 96 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf)); 97 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d)); 98 } 99 100 usbd_status 101 usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d) 102 { 103 DPRINTFN(3,("usbd_get_device_desc:\n")); 104 return (usbd_get_desc(dev, UDESC_DEVICE, 0, USB_DEVICE_DESCRIPTOR_SIZE, 105 d)); 106 } 107 108 usbd_status 109 usbd_get_device_status(usbd_device_handle dev, usb_status_t *st) 110 { 111 usb_device_request_t req; 112 113 req.bmRequestType = UT_READ_DEVICE; 114 req.bRequest = UR_GET_STATUS; 115 USETW(req.wValue, 0); 116 USETW(req.wIndex, 0); 117 USETW(req.wLength, sizeof(usb_status_t)); 118 return (usbd_do_request(dev, &req, st)); 119 } 120 121 usbd_status 122 usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st) 123 { 124 usb_device_request_t req; 125 126 req.bmRequestType = UT_READ_CLASS_DEVICE; 127 req.bRequest = UR_GET_STATUS; 128 USETW(req.wValue, 0); 129 USETW(req.wIndex, 0); 130 USETW(req.wLength, sizeof(usb_hub_status_t)); 131 return (usbd_do_request(dev, &req, st)); 132 } 133 134 usbd_status 135 usbd_set_address(usbd_device_handle dev, int addr) 136 { 137 usb_device_request_t req; 138 139 req.bmRequestType = UT_WRITE_DEVICE; 140 req.bRequest = UR_SET_ADDRESS; 141 USETW(req.wValue, addr); 142 USETW(req.wIndex, 0); 143 USETW(req.wLength, 0); 144 return usbd_do_request(dev, &req, 0); 145 } 146 147 usbd_status 148 usbd_get_port_status(usbd_device_handle dev, int port, usb_port_status_t *ps) 149 { 150 usb_device_request_t req; 151 152 req.bmRequestType = UT_READ_CLASS_OTHER; 153 req.bRequest = UR_GET_STATUS; 154 USETW(req.wValue, 0); 155 USETW(req.wIndex, port); 156 USETW(req.wLength, sizeof *ps); 157 return (usbd_do_request(dev, &req, ps)); 158 } 159 160 usbd_status 161 usbd_clear_hub_feature(usbd_device_handle dev, int sel) 162 { 163 usb_device_request_t req; 164 165 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 166 req.bRequest = UR_CLEAR_FEATURE; 167 USETW(req.wValue, sel); 168 USETW(req.wIndex, 0); 169 USETW(req.wLength, 0); 170 return (usbd_do_request(dev, &req, 0)); 171 } 172 173 usbd_status 174 usbd_set_hub_feature(usbd_device_handle dev, int sel) 175 { 176 usb_device_request_t req; 177 178 req.bmRequestType = UT_WRITE_CLASS_DEVICE; 179 req.bRequest = UR_SET_FEATURE; 180 USETW(req.wValue, sel); 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_clear_port_feature(usbd_device_handle dev, int port, int sel) 188 { 189 usb_device_request_t req; 190 191 req.bmRequestType = UT_WRITE_CLASS_OTHER; 192 req.bRequest = UR_CLEAR_FEATURE; 193 USETW(req.wValue, sel); 194 USETW(req.wIndex, port); 195 USETW(req.wLength, 0); 196 return (usbd_do_request(dev, &req, 0)); 197 } 198 199 usbd_status 200 usbd_set_port_feature(usbd_device_handle dev, int port, int sel) 201 { 202 usb_device_request_t req; 203 204 req.bmRequestType = UT_WRITE_CLASS_OTHER; 205 req.bRequest = UR_SET_FEATURE; 206 USETW(req.wValue, sel); 207 USETW(req.wIndex, port); 208 USETW(req.wLength, 0); 209 return (usbd_do_request(dev, &req, 0)); 210 } 211 212 usbd_status 213 usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report) 214 { 215 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 216 usbd_device_handle dev; 217 usb_device_request_t req; 218 219 DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n", iface, 220 id->bInterfaceNumber)); 221 if (id == NULL) 222 return (USBD_IOERROR); 223 usbd_interface2device_handle(iface, &dev); 224 req.bmRequestType = UT_READ_CLASS_INTERFACE; 225 req.bRequest = UR_GET_PROTOCOL; 226 USETW(req.wValue, 0); 227 USETW(req.wIndex, id->bInterfaceNumber); 228 USETW(req.wLength, 1); 229 return (usbd_do_request(dev, &req, report)); 230 } 231 232 usbd_status 233 usbd_set_protocol(usbd_interface_handle iface, int report) 234 { 235 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); 236 usbd_device_handle dev; 237 usb_device_request_t req; 238 239 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n", 240 iface, report, id->bInterfaceNumber)); 241 if (id == NULL) 242 return (USBD_IOERROR); 243 usbd_interface2device_handle(iface, &dev); 244 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 245 req.bRequest = UR_SET_PROTOCOL; 246 USETW(req.wValue, report); 247 USETW(req.wIndex, id->bInterfaceNumber); 248 USETW(req.wLength, 0); 249 return (usbd_do_request(dev, &req, 0)); 250 } 251 252 usbd_status 253 usbd_set_report(usbd_interface_handle iface, int type, int id, void *data, 254 int len) 255 { 256 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 257 usbd_device_handle dev; 258 usb_device_request_t req; 259 260 DPRINTFN(4, ("usbd_set_report: len=%d\n", len)); 261 if (ifd == NULL) 262 return (USBD_IOERROR); 263 usbd_interface2device_handle(iface, &dev); 264 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 265 req.bRequest = UR_SET_REPORT; 266 USETW2(req.wValue, type, id); 267 USETW(req.wIndex, ifd->bInterfaceNumber); 268 USETW(req.wLength, len); 269 return (usbd_do_request(dev, &req, data)); 270 } 271 272 usbd_status 273 usbd_set_report_async(usbd_interface_handle iface, int type, int id, 274 void *data, int len) 275 { 276 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 277 usbd_device_handle dev; 278 usb_device_request_t req; 279 280 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len)); 281 if (ifd == NULL) 282 return (USBD_IOERROR); 283 usbd_interface2device_handle(iface, &dev); 284 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 285 req.bRequest = UR_SET_REPORT; 286 USETW2(req.wValue, type, id); 287 USETW(req.wIndex, ifd->bInterfaceNumber); 288 USETW(req.wLength, len); 289 return (usbd_do_request_async(dev, &req, data)); 290 } 291 292 usbd_status 293 usbd_get_report(usbd_interface_handle iface, int type, int id, void *data, 294 int len) 295 { 296 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 297 usbd_device_handle dev; 298 usb_device_request_t req; 299 300 DPRINTFN(4, ("usbd_get_report: len=%d\n", len)); 301 if (ifd == NULL) 302 return (USBD_IOERROR); 303 usbd_interface2device_handle(iface, &dev); 304 req.bmRequestType = UT_READ_CLASS_INTERFACE; 305 req.bRequest = UR_GET_REPORT; 306 USETW2(req.wValue, type, id); 307 USETW(req.wIndex, ifd->bInterfaceNumber); 308 USETW(req.wLength, len); 309 return (usbd_do_request(dev, &req, data)); 310 } 311 312 usbd_status 313 usbd_set_idle(usbd_interface_handle iface, int duration, int id) 314 { 315 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); 316 usbd_device_handle dev; 317 usb_device_request_t req; 318 319 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id)); 320 if (ifd == NULL) 321 return (USBD_IOERROR); 322 usbd_interface2device_handle(iface, &dev); 323 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 324 req.bRequest = UR_SET_IDLE; 325 USETW2(req.wValue, duration, id); 326 USETW(req.wIndex, ifd->bInterfaceNumber); 327 USETW(req.wLength, 0); 328 return (usbd_do_request(dev, &req, 0)); 329 } 330 331 usbd_status 332 usbd_get_report_descriptor(usbd_device_handle dev, int ifcno, int size, 333 void *d) 334 { 335 usb_device_request_t req; 336 337 req.bmRequestType = UT_READ_INTERFACE; 338 req.bRequest = UR_GET_DESCRIPTOR; 339 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 340 USETW(req.wIndex, ifcno); 341 USETW(req.wLength, size); 342 return (usbd_do_request(dev, &req, d)); 343 } 344 345 usb_hid_descriptor_t * 346 usbd_get_hid_descriptor(usbd_interface_handle ifc) 347 { 348 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc); 349 usbd_device_handle dev; 350 usb_config_descriptor_t *cdesc; 351 usb_hid_descriptor_t *hd; 352 char *p, *end; 353 354 if (idesc == NULL) 355 return (0); 356 usbd_interface2device_handle(ifc, &dev); 357 cdesc = usbd_get_config_descriptor(dev); 358 359 p = (char *)idesc + idesc->bLength; 360 end = (char *)cdesc + UGETW(cdesc->wTotalLength); 361 362 for (; p < end; p += hd->bLength) { 363 hd = (usb_hid_descriptor_t *)p; 364 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID) 365 return (hd); 366 if (hd->bDescriptorType == UDESC_INTERFACE) 367 break; 368 } 369 return (0); 370 } 371 372 usbd_status 373 usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep, 374 int mem) 375 { 376 usb_interface_descriptor_t *id; 377 usb_hid_descriptor_t *hid; 378 usbd_device_handle dev; 379 usbd_status err; 380 381 usbd_interface2device_handle(ifc, &dev); 382 id = usbd_get_interface_descriptor(ifc); 383 if (id == NULL) 384 return (USBD_INVAL); 385 hid = usbd_get_hid_descriptor(ifc); 386 if (hid == NULL) 387 return (USBD_IOERROR); 388 *sizep = UGETW(hid->descrs[0].wDescriptorLength); 389 *descp = malloc(*sizep, mem, M_NOWAIT); 390 if (*descp == NULL) 391 return (USBD_NOMEM); 392 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, *sizep, 393 *descp); 394 if (err) { 395 free(*descp, mem); 396 *descp = NULL; 397 return (err); 398 } 399 return (USBD_NORMAL_COMPLETION); 400 } 401 402 usbd_status 403 usbd_get_config(usbd_device_handle dev, u_int8_t *conf) 404 { 405 usb_device_request_t req; 406 407 req.bmRequestType = UT_READ_DEVICE; 408 req.bRequest = UR_GET_CONFIG; 409 USETW(req.wValue, 0); 410 USETW(req.wIndex, 0); 411 USETW(req.wLength, 1); 412 return (usbd_do_request(dev, &req, conf)); 413 } 414 415 void usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, 416 usbd_status status); 417 void 418 usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, 419 usbd_status status) 420 { 421 wakeup(xfer); 422 } 423 424 usbd_status 425 usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, 426 u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl) 427 { 428 usbd_status err; 429 int s, error; 430 431 usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, 432 usbd_bulk_transfer_cb); 433 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size)); 434 s = splusb(); /* don't want callback until tsleep() */ 435 err = usbd_transfer(xfer); 436 if (err != USBD_IN_PROGRESS) { 437 splx(s); 438 return (err); 439 } 440 error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0); 441 splx(s); 442 if (error) { 443 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error)); 444 usbd_abort_pipe(pipe); 445 return (USBD_INTERRUPTED); 446 } 447 usbd_get_xfer_status(xfer, NULL, NULL, size, &err); 448 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size)); 449 if (err) { 450 DPRINTF(("usbd_bulk_transfer: error=%d\n", err)); 451 usbd_clear_endpoint_stall(pipe); 452 } 453 return (err); 454 } 455 456 void usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, 457 usbd_status status); 458 void 459 usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, 460 usbd_status status) 461 { 462 wakeup(xfer); 463 } 464 465 usbd_status 466 usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, 467 u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl) 468 { 469 usbd_status err; 470 int s, error; 471 472 usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, 473 usbd_intr_transfer_cb); 474 DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size)); 475 s = splusb(); /* don't want callback until tsleep() */ 476 err = usbd_transfer(xfer); 477 if (err != USBD_IN_PROGRESS) { 478 splx(s); 479 return (err); 480 } 481 error = tsleep(xfer, PZERO | PCATCH, lbl, 0); 482 splx(s); 483 if (error) { 484 DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error)); 485 usbd_abort_pipe(pipe); 486 return (USBD_INTERRUPTED); 487 } 488 usbd_get_xfer_status(xfer, NULL, NULL, size, &err); 489 DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size)); 490 if (err) { 491 DPRINTF(("usbd_intr_transfer: error=%d\n", err)); 492 usbd_clear_endpoint_stall(pipe); 493 } 494 return (err); 495 } 496 497 void 498 usb_detach_wait(struct device *dv) 499 { 500 DPRINTF(("usb_detach_wait: waiting for %s\n", dv->dv_xname)); 501 if (tsleep(dv, PZERO, "usbdet", hz * 60)) 502 printf("usb_detach_wait: %s didn't detach\n", dv->dv_xname); 503 DPRINTF(("usb_detach_wait: %s done\n", dv->dv_xname)); 504 } 505 506 void 507 usb_detach_wakeup(struct device *dv) 508 { 509 DPRINTF(("usb_detach_wakeup: for %s\n", dv->dv_xname)); 510 wakeup(dv); 511 } 512 513 usb_descriptor_t * 514 usb_find_desc(usbd_device_handle dev, int type) 515 { 516 usb_descriptor_t *desc; 517 usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); 518 uByte *p = (uByte *)cd; 519 uByte *end = p + UGETW(cd->wTotalLength); 520 521 while (p < end) { 522 desc = (usb_descriptor_t *)p; 523 if (desc->bDescriptorType == type) 524 return (desc); 525 p += desc->bLength; 526 } 527 528 return (NULL); 529 } 530