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