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