Home | History | Annotate | Line # | Download | only in usb
usbdi_util.c revision 1.13
      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 (at) 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