Home | History | Annotate | Line # | Download | only in usb
usbdi_util.c revision 1.4
      1 /*	$NetBSD: usbdi_util.c,v 1.4 1998/08/02 22:30:53 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Author: Lennart Augustsson <augustss (at) carlstedt.se>
      8  *         Carlstedt Research & Technology
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/kernel.h>
     42 #include <sys/malloc.h>
     43 #include <sys/device.h>
     44 #include <sys/proc.h>
     45 #include <sys/select.h>
     46 
     47 #include <dev/usb/usb.h>
     48 #include <dev/usb/usbhid.h>
     49 
     50 #include <dev/usb/usbdi.h>
     51 #include <dev/usb/usbdi_util.h>
     52 
     53 #include "opt_usbverbose.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 	DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf));
     88 	return (usbd_get_desc(dev, UDESC_CONFIG,
     89 			      conf, USB_CONFIG_DESCRIPTOR_SIZE, d));
     90 }
     91 
     92 usbd_status
     93 usbd_get_config_desc_full(dev, conf, d, size)
     94 	usbd_device_handle dev;
     95 	int conf;
     96 	void *d;
     97 	int size;
     98 {
     99 	DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
    100 	return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
    101 }
    102 
    103 usbd_status
    104 usbd_get_device_desc(dev, d)
    105 	usbd_device_handle dev;
    106 	usb_device_descriptor_t *d;
    107 {
    108 	DPRINTFN(3,("usbd_get_device_desc:\n"));
    109 	return (usbd_get_desc(dev, UDESC_DEVICE,
    110 			     0, USB_DEVICE_DESCRIPTOR_SIZE, d));
    111 }
    112 
    113 usbd_status
    114 usbd_get_device_status(dev, st)
    115 	usbd_device_handle dev;
    116 	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(dev, st)
    130 	usbd_device_handle dev;
    131 	usb_hub_status_t *st;
    132 {
    133 	usb_device_request_t req;
    134 
    135 	req.bmRequestType = UT_READ_CLASS_DEVICE;
    136 	req.bRequest = UR_GET_STATUS;
    137 	USETW(req.wValue, 0);
    138 	USETW(req.wIndex, 0);
    139 	USETW(req.wLength, sizeof(usb_hub_status_t));
    140 	return (usbd_do_request(dev, &req, st));
    141 }
    142 
    143 usbd_status
    144 usbd_set_address(dev, addr)
    145 	usbd_device_handle dev;
    146 	int addr;
    147 {
    148 	usb_device_request_t req;
    149 
    150 	req.bmRequestType = UT_WRITE_DEVICE;
    151 	req.bRequest = UR_SET_ADDRESS;
    152 	USETW(req.wValue, addr);
    153 	USETW(req.wIndex, 0);
    154 	USETW(req.wLength, 0);
    155 	return usbd_do_request(dev, &req, 0);
    156 }
    157 
    158 usbd_status
    159 usbd_get_port_status(dev, port, ps)
    160 	usbd_device_handle dev;
    161 	int port;
    162 	usb_port_status_t *ps;
    163 {
    164 	usb_device_request_t req;
    165 
    166 	req.bmRequestType = UT_READ_CLASS_OTHER;
    167 	req.bRequest = UR_GET_STATUS;
    168 	USETW(req.wValue, 0);
    169 	USETW(req.wIndex, port);
    170 	USETW(req.wLength, sizeof *ps);
    171 	return (usbd_do_request(dev, &req, ps));
    172 }
    173 
    174 usbd_status
    175 usbd_clear_port_feature(dev, port, sel)
    176 	usbd_device_handle dev;
    177 	int port, sel;
    178 {
    179 	usb_device_request_t req;
    180 
    181 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
    182 	req.bRequest = UR_CLEAR_FEATURE;
    183 	USETW(req.wValue, sel);
    184 	USETW(req.wIndex, port);
    185 	USETW(req.wLength, 0);
    186 	return (usbd_do_request(dev, &req, 0));
    187 }
    188 
    189 usbd_status
    190 usbd_set_port_feature(dev, port, sel)
    191 	usbd_device_handle dev;
    192 	int port, sel;
    193 {
    194 	usb_device_request_t req;
    195 
    196 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
    197 	req.bRequest = UR_SET_FEATURE;
    198 	USETW(req.wValue, sel);
    199 	USETW(req.wIndex, port);
    200 	USETW(req.wLength, 0);
    201 	return (usbd_do_request(dev, &req, 0));
    202 }
    203 
    204 
    205 usbd_status
    206 usbd_set_protocol(iface, report)
    207 	usbd_interface_handle iface;
    208 	int report;
    209 {
    210 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
    211 	usbd_device_handle dev;
    212 	usb_device_request_t req;
    213 	usbd_status r;
    214 
    215 	DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
    216 		     iface, report, id->bInterfaceNumber));
    217 	r = usbd_interface2device_handle(iface, &dev);
    218 	if (r != USBD_NORMAL_COMPLETION)
    219 		return (r);
    220 	if (!id)
    221 		return (USBD_INVAL);
    222 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    223 	req.bRequest = UR_SET_PROTOCOL;
    224 	USETW(req.wValue, report);
    225 	USETW(req.wIndex, id->bInterfaceNumber);
    226 	USETW(req.wLength, 0);
    227 	return (usbd_do_request(dev, &req, 0));
    228 }
    229 
    230 usbd_status
    231 usbd_set_report(iface, type, id, data, len)
    232 	usbd_interface_handle iface;
    233 	int type;
    234 	int id;
    235 	void *data;
    236 	int len;
    237 {
    238 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
    239 	usbd_device_handle dev;
    240 	usb_device_request_t req;
    241 	usbd_status r;
    242 
    243 	DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
    244 	r = usbd_interface2device_handle(iface, &dev);
    245 	if (r != USBD_NORMAL_COMPLETION)
    246 		return (r);
    247 	if (!ifd)
    248 		return (USBD_INVAL);
    249 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    250 	req.bRequest = UR_SET_REPORT;
    251 	USETW2(req.wValue, type, id);
    252 	USETW(req.wIndex, ifd->bInterfaceNumber);
    253 	USETW(req.wLength, len);
    254 	return (usbd_do_request(dev, &req, data));
    255 }
    256 
    257 usbd_status
    258 usbd_set_report_async(iface, type, id, data, len)
    259 	usbd_interface_handle iface;
    260 	int type;
    261 	int id;
    262 	void *data;
    263 	int len;
    264 {
    265 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
    266 	usbd_device_handle dev;
    267 	usb_device_request_t req;
    268 	usbd_status r;
    269 
    270 	DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
    271 	r = usbd_interface2device_handle(iface, &dev);
    272 	if (r != USBD_NORMAL_COMPLETION)
    273 		return (r);
    274 	if (!ifd)
    275 		return (USBD_INVAL);
    276 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    277 	req.bRequest = UR_SET_REPORT;
    278 	USETW2(req.wValue, type, id);
    279 	USETW(req.wIndex, ifd->bInterfaceNumber);
    280 	USETW(req.wLength, len);
    281 	return (usbd_do_request_async(dev, &req, data));
    282 }
    283 
    284 usbd_status
    285 usbd_get_report(iface, type, id, data, len)
    286 	usbd_interface_handle iface;
    287 	int type;
    288 	int id;
    289 	void *data;
    290 	int len;
    291 {
    292 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
    293 	usbd_device_handle dev;
    294 	usb_device_request_t req;
    295 	usbd_status r;
    296 
    297 	DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
    298 	r = usbd_interface2device_handle(iface, &dev);
    299 	if (r != USBD_NORMAL_COMPLETION)
    300 		return (r);
    301 	if (!ifd)
    302 		return (USBD_INVAL);
    303 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
    304 	req.bRequest = UR_GET_REPORT;
    305 	USETW2(req.wValue, type, id);
    306 	USETW(req.wIndex, ifd->bInterfaceNumber);
    307 	USETW(req.wLength, len);
    308 	return (usbd_do_request(dev, &req, data));
    309 }
    310 
    311 usbd_status
    312 usbd_set_idle(iface, duration, id)
    313 	usbd_interface_handle iface;
    314 	int duration;
    315 	int id;
    316 {
    317 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
    318 	usbd_device_handle dev;
    319 	usb_device_request_t req;
    320 	usbd_status r;
    321 
    322 	DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
    323 	r = usbd_interface2device_handle(iface, &dev);
    324 	if (r != USBD_NORMAL_COMPLETION)
    325 		return (r);
    326 	if (!ifd)
    327 		return (USBD_INVAL);
    328 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    329 	req.bRequest = UR_SET_IDLE;
    330 	USETW2(req.wValue, duration, id);
    331 	USETW(req.wIndex, ifd->bInterfaceNumber);
    332 	USETW(req.wLength, 0);
    333 	return (usbd_do_request(dev, &req, 0));
    334 }
    335 
    336 usbd_status
    337 usbd_get_report_descriptor(dev, i, size, d)
    338 	usbd_device_handle dev;
    339 	int i;
    340 	int size;
    341 	void *d;
    342 {
    343 	usb_device_request_t req;
    344 
    345 	req.bmRequestType = UT_READ_INTERFACE;
    346 	req.bRequest = UR_GET_DESCRIPTOR;
    347 	USETW2(req.wValue, UDESC_REPORT, 0);
    348 	USETW(req.wIndex, i);
    349 	USETW(req.wLength, size);
    350 	return (usbd_do_request(dev, &req, d));
    351 }
    352 
    353 usb_hid_descriptor_t *
    354 usbd_get_hid_descriptor(ifc)
    355 	usbd_interface_handle ifc;
    356 {
    357 	usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
    358 	usbd_device_handle dev;
    359 	usb_config_descriptor_t *cdesc;
    360 	usb_hid_descriptor_t *hd;
    361 	char *p, *end;
    362 	usbd_status r;
    363 
    364 	r = usbd_interface2device_handle(ifc, &dev);
    365 	if (r != USBD_NORMAL_COMPLETION)
    366 		return (0);
    367 	cdesc = usbd_get_config_descriptor(dev);
    368 
    369 	p = (char *)idesc + idesc->bLength;
    370 	end = (char *)cdesc + UGETW(cdesc->wTotalLength);
    371 
    372 	for (; p < end; p += hd->bLength) {
    373 		hd = (usb_hid_descriptor_t *)p;
    374 		if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
    375 			return (hd);
    376 		if (hd->bDescriptorType == UDESC_INTERFACE)
    377 			break;
    378 	}
    379 	return (0);
    380 }
    381 
    382 usbd_status
    383 usbd_alloc_report_desc(ifc, descp, sizep, mem)
    384 	usbd_interface_handle ifc;
    385 	void **descp;
    386 	int *sizep;
    387 	int mem;
    388 {
    389 	usb_hid_descriptor_t *hid;
    390 	usbd_device_handle dev;
    391 	usbd_status r;
    392 
    393 	r = usbd_interface2device_handle(ifc, &dev);
    394 	if (r != USBD_NORMAL_COMPLETION)
    395 		return (r);
    396 	hid = usbd_get_hid_descriptor(ifc);
    397 	if (!hid)
    398 		return (USBD_IOERROR);
    399 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
    400 	*descp = malloc(*sizep, mem, M_NOWAIT);
    401 	if (!*descp)
    402 		return (USBD_NOMEM);
    403 	r = usbd_get_report_descriptor(dev, 0, *sizep, *descp);
    404 	if (r != USBD_NORMAL_COMPLETION) {
    405 		free(*descp, mem);
    406 		return (r);
    407 	}
    408 	return (USBD_NORMAL_COMPLETION);
    409 }
    410