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