Annotation of src/sys/dev/usb/uhidev.c, Revision 1.52.2.1
1.52.2.1! yamt 1: /* $NetBSD: uhidev.c,v 1.52 2011/10/25 16:12:02 aymeric Exp $ */
1.1 augustss 2:
3: /*
4: * Copyright (c) 2001 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 (lennart@augustsson.net) 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: *
20: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
32:
33: /*
1.14 augustss 34: * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
1.1 augustss 35: */
1.15 lukem 36:
37: #include <sys/cdefs.h>
1.52.2.1! yamt 38: __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.52 2011/10/25 16:12:02 aymeric Exp $");
1.1 augustss 39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/kernel.h>
43: #include <sys/malloc.h>
44: #include <sys/signalvar.h>
45: #include <sys/device.h>
46: #include <sys/ioctl.h>
47: #include <sys/conf.h>
48:
49: #include <dev/usb/usb.h>
50: #include <dev/usb/usbhid.h>
51:
52: #include <dev/usb/usbdevs.h>
53: #include <dev/usb/usbdi.h>
54: #include <dev/usb/usbdi_util.h>
55: #include <dev/usb/hid.h>
56: #include <dev/usb/usb_quirks.h>
57:
58: #include <dev/usb/uhidev.h>
59:
60: /* Report descriptor for broken Wacom Graphire */
61: #include <dev/usb/ugraphire_rdesc.h>
1.51 jmcneill 62: /* Report descriptor for game controllers in "XInput" mode */
63: #include <dev/usb/xinput_rdesc.h>
1.1 augustss 64:
1.22 drochner 65: #include "locators.h"
66:
1.1 augustss 67: #ifdef UHIDEV_DEBUG
1.48 dyoung 68: #define DPRINTF(x) if (uhidevdebug) printf x
69: #define DPRINTFN(n,x) if (uhidevdebug>(n)) printf x
1.1 augustss 70: int uhidevdebug = 0;
71: #else
72: #define DPRINTF(x)
73: #define DPRINTFN(n,x)
74: #endif
75:
76: Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
77:
1.29 drochner 78: Static int uhidev_maxrepid(void *, int);
79: Static int uhidevprint(void *, const char *);
1.1 augustss 80:
1.41 cube 81: int uhidev_match(device_t, cfdata_t, void *);
1.39 dyoung 82: void uhidev_attach(device_t, device_t, void *);
83: void uhidev_childdet(device_t, device_t);
84: int uhidev_detach(device_t, int);
85: int uhidev_activate(device_t, enum devact);
86: extern struct cfdriver uhidev_cd;
1.41 cube 87: CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match,
1.39 dyoung 88: uhidev_attach, uhidev_detach, uhidev_activate, NULL, uhidev_childdet);
1.1 augustss 89:
1.48 dyoung 90: int
91: uhidev_match(device_t parent, cfdata_t match, void *aux)
1.1 augustss 92: {
1.48 dyoung 93: struct usbif_attach_arg *uaa = aux;
1.6 augustss 94:
1.51 jmcneill 95: /* Game controllers in "XInput" mode */
96: if (USBIF_IS_XINPUT(uaa))
97: return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO;
1.34 drochner 98: if (uaa->class != UICLASS_HID)
1.1 augustss 99: return (UMATCH_NONE);
1.36 veego 100: if (usbd_get_quirks(uaa->device)->uq_flags & UQ_HID_IGNORE)
101: return (UMATCH_NONE);
1.1 augustss 102: return (UMATCH_IFACECLASS_GENERIC);
103: }
104:
1.48 dyoung 105: void
106: uhidev_attach(device_t parent, device_t self, void *aux)
1.1 augustss 107: {
1.48 dyoung 108: struct uhidev_softc *sc = device_private(self);
109: struct usbif_attach_arg *uaa = aux;
1.1 augustss 110: usbd_interface_handle iface = uaa->iface;
111: usb_interface_descriptor_t *id;
112: usb_endpoint_descriptor_t *ed;
113: struct uhidev_attach_arg uha;
1.42 drochner 114: device_t dev;
115: struct uhidev *csc;
1.44 rafal 116: int maxinpktsize, size, nrepid, repid, repsz;
1.32 christos 117: int *repsizes;
1.25 skrll 118: int i;
1.19 jdolecek 119: void *desc;
1.20 augustss 120: const void *descptr;
1.1 augustss 121: usbd_status err;
1.26 augustss 122: char *devinfop;
1.28 drochner 123: int locs[UHIDBUSCF_NLOCS];
1.6 augustss 124:
1.41 cube 125: sc->sc_dev = self;
1.1 augustss 126: sc->sc_udev = uaa->device;
127: sc->sc_iface = iface;
1.43 plunky 128:
129: aprint_naive("\n");
130: aprint_normal("\n");
131:
1.1 augustss 132: id = usbd_get_interface_descriptor(iface);
1.26 augustss 133:
134: devinfop = usbd_devinfo_alloc(uaa->device, 0);
1.41 cube 135: aprint_normal_dev(self, "%s, iclass %d/%d\n",
1.26 augustss 136: devinfop, id->bInterfaceClass, id->bInterfaceSubClass);
137: usbd_devinfo_free(devinfop);
1.1 augustss 138:
1.38 jmcneill 139: if (!pmf_device_register(self, NULL, NULL))
140: aprint_error_dev(self, "couldn't establish power handler\n");
141:
1.1 augustss 142: (void)usbd_set_idle(iface, 0, 0);
143: #if 0
144:
145: qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
146: if ((qflags & UQ_NO_SET_PROTO) == 0 &&
147: id->bInterfaceSubClass != UISUBCLASS_BOOT)
148: (void)usbd_set_protocol(iface, 1);
149: #endif
150:
1.44 rafal 151: maxinpktsize = 0;
1.25 skrll 152: sc->sc_iep_addr = sc->sc_oep_addr = -1;
153: for (i = 0; i < id->bNumEndpoints; i++) {
154: ed = usbd_interface2endpoint_descriptor(iface, i);
155: if (ed == NULL) {
1.41 cube 156: aprint_error_dev(self,
157: "could not read endpoint descriptor\n");
1.25 skrll 158: sc->sc_dying = 1;
1.48 dyoung 159: return;
1.25 skrll 160: }
161:
162: DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
163: "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
164: " bInterval=%d\n",
165: ed->bLength, ed->bDescriptorType,
166: ed->bEndpointAddress & UE_ADDR,
167: UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
168: ed->bmAttributes & UE_XFERTYPE,
169: UGETW(ed->wMaxPacketSize), ed->bInterval));
170:
171: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
172: (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
1.44 rafal 173: maxinpktsize = UGETW(ed->wMaxPacketSize);
1.25 skrll 174: sc->sc_iep_addr = ed->bEndpointAddress;
175: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
176: (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
177: sc->sc_oep_addr = ed->bEndpointAddress;
178: } else {
1.41 cube 179: aprint_verbose_dev(self, "endpoint %d: ignored\n", i);
1.25 skrll 180: }
1.1 augustss 181: }
182:
1.25 skrll 183: /*
184: * Check that we found an input interrupt endpoint. The output interrupt
185: * endpoint is optional
186: */
187: if (sc->sc_iep_addr == -1) {
1.41 cube 188: aprint_error_dev(self, "no input interrupt endpoint\n");
1.1 augustss 189: sc->sc_dying = 1;
1.48 dyoung 190: return;
1.1 augustss 191: }
192:
193: /* XXX need to extend this */
1.20 augustss 194: descptr = NULL;
195: if (uaa->vendor == USB_VENDOR_WACOM) {
196: static uByte reportbuf[] = {2, 2, 2};
1.17 augustss 197:
1.1 augustss 198: /* The report descriptor for the Wacom Graphire is broken. */
1.17 augustss 199: switch (uaa->product) {
200: case USB_PRODUCT_WACOM_GRAPHIRE:
1.49 tsutsui 201: case USB_PRODUCT_WACOM_GRAPHIRE2:
1.33 ghen 202: case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
203: case USB_PRODUCT_WACOM_GRAPHIRE3_6X8:
204: case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: /* The 6x8 too? */
1.17 augustss 205: /*
206: * The Graphire3 needs 0x0202 to be written to
207: * feature report ID 2 before it'll start
208: * returning digitizer data.
209: */
210: usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
1.20 augustss 211: &reportbuf, sizeof reportbuf);
1.17 augustss 212:
213: size = sizeof uhid_graphire3_4x5_report_descr;
214: descptr = uhid_graphire3_4x5_report_descr;
215: break;
1.20 augustss 216: default:
217: /* Keep descriptor */
218: break;
1.17 augustss 219: }
220: }
1.51 jmcneill 221: if (USBIF_IS_XINPUT(uaa)) {
222: size = sizeof uhid_xinput_report_descr;
223: descptr = uhid_xinput_report_descr;
224: }
1.17 augustss 225:
226: if (descptr) {
1.1 augustss 227: desc = malloc(size, M_USBDEV, M_NOWAIT);
228: if (desc == NULL)
229: err = USBD_NOMEM;
230: else {
231: err = USBD_NORMAL_COMPLETION;
1.17 augustss 232: memcpy(desc, descptr, size);
1.1 augustss 233: }
234: } else {
235: desc = NULL;
1.17 augustss 236: err = usbd_read_report_desc(uaa->iface, &desc, &size,
237: M_USBDEV);
1.1 augustss 238: }
239: if (err) {
1.41 cube 240: aprint_error_dev(self, "no report descriptor\n");
1.1 augustss 241: sc->sc_dying = 1;
1.48 dyoung 242: return;
1.1 augustss 243: }
1.6 augustss 244:
1.27 augustss 245: if (uaa->vendor == USB_VENDOR_HOSIDEN &&
246: uaa->product == USB_PRODUCT_HOSIDEN_PPP) {
247: static uByte reportbuf[] = { 1 };
248: /*
249: * This device was sold by Konami with its ParaParaParadise
250: * game for PlayStation2. It needs to be "turned on"
251: * before it will send any reports.
252: */
253:
254: usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 0,
255: &reportbuf, sizeof reportbuf);
256: }
257:
1.47 jakllsch 258: if (uaa->vendor == USB_VENDOR_LOGITECH &&
259: uaa->product == USB_PRODUCT_LOGITECH_CBT44 && size == 0xb1) {
260: uint8_t *data = desc;
261: /*
262: * This device has a odd USAGE_MINIMUM value that would
263: * cause the multimedia keys to have their usage number
264: * shifted up one usage. Adjust so the usages are sane.
265: */
266:
267: if (data[0x56] == 0x19 && data[0x57] == 0x01 &&
268: data[0x58] == 0x2a && data[0x59] == 0x8c)
269: data[0x57] = 0x00;
270: }
271:
1.52 aymeric 272: /*
273: * Enable the Six Axis and DualShock 3 controllers.
274: * See http://ps3.jim.sh/sixaxis/usb/
275: */
276: if (uaa->vendor == USB_VENDOR_SONY &&
277: uaa->product == USB_PRODUCT_SONY_PS3CONTROLLER) {
278: usb_device_request_t req;
279: char data[17];
280: int actlen;
281:
282: req.bmRequestType = UT_READ_CLASS_INTERFACE;
283: req.bRequest = 1;
284: USETW(req.wValue, 0x3f2);
285: USETW(req.wIndex, 0);
286: USETW(req.wLength, sizeof data);
287:
288: usbd_do_request_flags(sc->sc_udev, &req, data,
289: USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
290: }
291:
1.1 augustss 292: sc->sc_repdesc = desc;
293: sc->sc_repdesc_size = size;
294:
295: uha.uaa = uaa;
296: nrepid = uhidev_maxrepid(desc, size);
297: if (nrepid < 0)
1.48 dyoung 298: return;
1.1 augustss 299: if (nrepid > 0)
1.41 cube 300: aprint_normal_dev(self, "%d report ids\n", nrepid);
1.1 augustss 301: nrepid++;
1.32 christos 302: repsizes = malloc(nrepid * sizeof(*repsizes), M_TEMP, M_NOWAIT);
303: if (repsizes == NULL)
304: goto nomem;
1.39 dyoung 305: sc->sc_subdevs = malloc(nrepid * sizeof(device_t),
1.5 augustss 306: M_USBDEV, M_NOWAIT | M_ZERO);
1.1 augustss 307: if (sc->sc_subdevs == NULL) {
1.32 christos 308: free(repsizes, M_TEMP);
309: nomem:
1.41 cube 310: aprint_error_dev(self, "no memory\n");
1.48 dyoung 311: return;
1.1 augustss 312: }
1.44 rafal 313:
314: /* Just request max packet size for the interrupt pipe */
315: sc->sc_isize = maxinpktsize;
1.1 augustss 316: sc->sc_nrepid = nrepid;
317:
318: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
1.48 dyoung 319: sc->sc_dev);
1.1 augustss 320:
321: for (repid = 0; repid < nrepid; repid++) {
322: repsz = hid_report_size(desc, size, hid_input, repid);
323: DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
1.2 augustss 324: repsizes[repid] = repsz;
1.1 augustss 325: }
1.44 rafal 326:
1.1 augustss 327: DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
328:
329: uha.parent = sc;
330: for (repid = 0; repid < nrepid; repid++) {
331: DPRINTF(("uhidev_match: try repid=%d\n", repid));
332: if (hid_report_size(desc, size, hid_input, repid) == 0 &&
333: hid_report_size(desc, size, hid_output, repid) == 0 &&
334: hid_report_size(desc, size, hid_feature, repid) == 0) {
1.5 augustss 335: ; /* already NULL in sc->sc_subdevs[repid] */
1.1 augustss 336: } else {
337: uha.reportid = repid;
1.28 drochner 338: locs[UHIDBUSCF_REPORTID] = repid;
1.22 drochner 339:
1.42 drochner 340: dev = config_found_sm_loc(self,
1.28 drochner 341: "uhidbus", locs, &uha,
1.42 drochner 342: uhidevprint, config_stdsubmatch);
1.1 augustss 343: sc->sc_subdevs[repid] = dev;
1.4 augustss 344: if (dev != NULL) {
1.42 drochner 345: csc = device_private(dev);
346: csc->sc_in_rep_size = repsizes[repid];
1.1 augustss 347: #ifdef DIAGNOSTIC
348: DPRINTF(("uhidev_match: repid=%d dev=%p\n",
349: repid, dev));
1.42 drochner 350: if (csc->sc_intr == NULL) {
1.32 christos 351: free(repsizes, M_TEMP);
1.41 cube 352: aprint_error_dev(self,
353: "sc_intr == NULL\n");
1.48 dyoung 354: return;
1.1 augustss 355: }
1.4 augustss 356: #endif
1.42 drochner 357: rnd_attach_source(&csc->rnd_source,
1.48 dyoung 358: device_xname(dev),
1.9 dan 359: RND_TYPE_TTY, 0);
1.1 augustss 360: }
361: }
362: }
1.32 christos 363: free(repsizes, M_TEMP);
1.1 augustss 364:
1.48 dyoung 365: return;
1.1 augustss 366: }
367:
368: int
369: uhidev_maxrepid(void *buf, int len)
370: {
371: struct hid_data *d;
372: struct hid_item h;
373: int maxid;
374:
375: maxid = -1;
376: h.report_ID = 0;
377: for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
378: if (h.report_ID > maxid)
379: maxid = h.report_ID;
380: hid_end_parse(d);
381: return (maxid);
382: }
383:
384: int
385: uhidevprint(void *aux, const char *pnp)
386: {
387: struct uhidev_attach_arg *uha = aux;
388:
389: if (pnp)
1.12 thorpej 390: aprint_normal("uhid at %s", pnp);
1.1 augustss 391: if (uha->reportid != 0)
1.12 thorpej 392: aprint_normal(" reportid %d", uha->reportid);
1.1 augustss 393: return (UNCONF);
394: }
395:
396: int
1.39 dyoung 397: uhidev_activate(device_t self, enum devact act)
1.1 augustss 398: {
1.39 dyoung 399: struct uhidev_softc *sc = device_private(self);
1.1 augustss 400:
401: switch (act) {
402: case DVACT_DEACTIVATE:
403: sc->sc_dying = 1;
1.45 dyoung 404: return 0;
1.16 christos 405: default:
1.45 dyoung 406: return EOPNOTSUPP;
1.1 augustss 407: }
408: }
409:
1.39 dyoung 410: void
411: uhidev_childdet(device_t self, device_t child)
412: {
413: int i;
414: struct uhidev_softc *sc = device_private(self);
415:
416: for (i = 0; i < sc->sc_nrepid; i++) {
1.42 drochner 417: if (sc->sc_subdevs[i] == child)
1.39 dyoung 418: break;
419: }
420: KASSERT(i < sc->sc_nrepid);
421: sc->sc_subdevs[i] = NULL;
422: }
423:
1.48 dyoung 424: int
425: uhidev_detach(device_t self, int flags)
1.1 augustss 426: {
1.48 dyoung 427: struct uhidev_softc *sc = device_private(self);
1.1 augustss 428: int i, rv;
1.42 drochner 429: struct uhidev *csc;
1.1 augustss 430:
431: DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
432:
433: sc->sc_dying = 1;
1.25 skrll 434: if (sc->sc_ipipe != NULL)
435: usbd_abort_pipe(sc->sc_ipipe);
1.1 augustss 436:
437: if (sc->sc_repdesc != NULL)
438: free(sc->sc_repdesc, M_USBDEV);
439:
440: rv = 0;
441: for (i = 0; i < sc->sc_nrepid; i++) {
442: if (sc->sc_subdevs[i] != NULL) {
1.42 drochner 443: csc = device_private(sc->sc_subdevs[i]);
444: rnd_detach_source(&csc->rnd_source);
445: rv |= config_detach(sc->sc_subdevs[i], flags);
1.1 augustss 446: }
447: }
448:
449: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
1.48 dyoung 450: sc->sc_dev);
1.1 augustss 451:
1.38 jmcneill 452: pmf_device_deregister(self);
453:
1.1 augustss 454: return (rv);
455: }
456:
457: void
458: uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
459: {
460: struct uhidev_softc *sc = addr;
1.42 drochner 461: device_t cdev;
1.1 augustss 462: struct uhidev *scd;
463: u_char *p;
464: u_int rep;
465: u_int32_t cc;
466:
467: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
468:
469: #ifdef UHIDEV_DEBUG
470: if (uhidevdebug > 5) {
471: u_int32_t i;
1.6 augustss 472:
1.1 augustss 473: DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc));
474: DPRINTF(("uhidev_intr: data ="));
475: for (i = 0; i < cc; i++)
476: DPRINTF((" %02x", sc->sc_ibuf[i]));
477: DPRINTF(("\n"));
478: }
479: #endif
480:
481: if (status == USBD_CANCELLED)
482: return;
483:
484: if (status != USBD_NORMAL_COMPLETION) {
1.48 dyoung 485: DPRINTF(("%s: interrupt status=%d\n", device_xname(sc->sc_dev),
1.3 augustss 486: status));
1.25 skrll 487: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.1 augustss 488: return;
489: }
490:
491: p = sc->sc_ibuf;
492: if (sc->sc_nrepid != 1)
493: rep = *p++, cc--;
494: else
495: rep = 0;
496: if (rep >= sc->sc_nrepid) {
497: printf("uhidev_intr: bad repid %d\n", rep);
498: return;
499: }
1.42 drochner 500: cdev = sc->sc_subdevs[rep];
501: if (!cdev)
502: return;
503: scd = device_private(cdev);
1.1 augustss 504: DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n",
505: rep, scd, scd ? scd->sc_state : 0));
1.42 drochner 506: if (!(scd->sc_state & UHIDEV_OPEN))
1.1 augustss 507: return;
1.46 jakllsch 508: #ifdef UHIDEV_DEBUG
509: if (scd->sc_in_rep_size != cc) {
510: DPRINTF(("%s: expected %d bytes, got %d\n",
1.48 dyoung 511: device_xname(sc->sc_dev), scd->sc_in_rep_size, cc));
1.46 jakllsch 512: }
513: #endif
514: if (cc == 0) {
515: DPRINTF(("%s: 0-length input ignored\n",
1.48 dyoung 516: device_xname(sc->sc_dev)));
1.23 augustss 517: return;
518: }
1.10 fair 519: rnd_add_uint32(&scd->rnd_source, (uintptr_t)(sc->sc_ibuf));
1.1 augustss 520: scd->sc_intr(scd, p, cc);
521: }
522:
523: void
524: uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size)
525: {
526: *desc = sc->sc_repdesc;
527: *size = sc->sc_repdesc_size;
528: }
529:
530: int
531: uhidev_open(struct uhidev *scd)
532: {
533: struct uhidev_softc *sc = scd->sc_parent;
534: usbd_status err;
1.25 skrll 535: int error;
1.1 augustss 536:
537: DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
538: scd->sc_state, sc->sc_refcnt));
539:
540: if (scd->sc_state & UHIDEV_OPEN)
541: return (EBUSY);
542: scd->sc_state |= UHIDEV_OPEN;
543: if (sc->sc_refcnt++)
544: return (0);
545:
546: if (sc->sc_isize == 0)
547: return (0);
548:
549: sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
550:
1.25 skrll 551: /* Set up input interrupt pipe. */
1.1 augustss 552: DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
1.25 skrll 553: sc->sc_iep_addr));
554:
555: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
556: USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
1.1 augustss 557: sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
1.25 skrll 558: if (err != USBD_NORMAL_COMPLETION) {
1.1 augustss 559: DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
1.25 skrll 560: "error=%d\n", err));
561: error = EIO;
562: goto out1;
563: }
564:
565: /*
566: * Set up output interrupt pipe if an output interrupt endpoint
567: * exists.
568: */
569: if (sc->sc_oep_addr != -1) {
570: DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
571:
572: err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
573: 0, &sc->sc_opipe);
574:
575: if (err != USBD_NORMAL_COMPLETION) {
576: DPRINTF(("uhidev_open: usbd_open_pipe failed, "
577: "error=%d\n", err));
578: error = EIO;
579: goto out2;
580: }
581: DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
582:
583: sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
584: if (sc->sc_oxfer == NULL) {
585: DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
586: error = ENOMEM;
587: goto out3;
588: }
1.1 augustss 589: }
1.25 skrll 590:
1.1 augustss 591: return (0);
1.25 skrll 592: out3:
593: /* Abort output pipe */
594: usbd_close_pipe(sc->sc_opipe);
595: out2:
596: /* Abort input pipe */
597: usbd_close_pipe(sc->sc_ipipe);
598: out1:
599: DPRINTF(("uhidev_open: failed in someway"));
600: free(sc->sc_ibuf, M_USBDEV);
601: scd->sc_state &= ~UHIDEV_OPEN;
602: sc->sc_refcnt = 0;
603: sc->sc_ipipe = NULL;
604: sc->sc_opipe = NULL;
605: sc->sc_oxfer = NULL;
606: return error;
1.1 augustss 607: }
608:
609: void
610: uhidev_close(struct uhidev *scd)
611: {
612: struct uhidev_softc *sc = scd->sc_parent;
613:
614: if (!(scd->sc_state & UHIDEV_OPEN))
615: return;
616: scd->sc_state &= ~UHIDEV_OPEN;
617: if (--sc->sc_refcnt)
618: return;
619: DPRINTF(("uhidev_close: close pipe\n"));
620:
1.25 skrll 621: if (sc->sc_oxfer != NULL)
622: usbd_free_xfer(sc->sc_oxfer);
623:
1.1 augustss 624: /* Disable interrupts. */
1.25 skrll 625: if (sc->sc_opipe != NULL) {
626: usbd_abort_pipe(sc->sc_opipe);
627: usbd_close_pipe(sc->sc_opipe);
628: sc->sc_opipe = NULL;
629: }
630:
631: if (sc->sc_ipipe != NULL) {
632: usbd_abort_pipe(sc->sc_ipipe);
633: usbd_close_pipe(sc->sc_ipipe);
634: sc->sc_ipipe = NULL;
1.1 augustss 635: }
636:
637: if (sc->sc_ibuf != NULL) {
638: free(sc->sc_ibuf, M_USBDEV);
639: sc->sc_ibuf = NULL;
640: }
641: }
642:
643: usbd_status
644: uhidev_set_report(struct uhidev *scd, int type, void *data, int len)
645: {
1.13 dsainty 646: char *buf;
647: usbd_status retstat;
648:
649: if (scd->sc_report_id == 0)
650: return usbd_set_report(scd->sc_parent->sc_iface, type,
651: scd->sc_report_id, data, len);
652:
653: buf = malloc(len + 1, M_TEMP, M_WAITOK);
654: buf[0] = scd->sc_report_id;
655: memcpy(buf+1, data, len);
656:
657: retstat = usbd_set_report(scd->sc_parent->sc_iface, type,
1.18 dsainty 658: scd->sc_report_id, buf, len + 1);
1.13 dsainty 659:
660: free(buf, M_TEMP);
1.1 augustss 661:
1.13 dsainty 662: return retstat;
1.1 augustss 663: }
664:
665: void
666: uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len)
667: {
668: /* XXX */
669: char buf[100];
670: if (scd->sc_report_id) {
671: buf[0] = scd->sc_report_id;
672: memcpy(buf+1, data, len);
673: len++;
674: data = buf;
675: }
676:
1.6 augustss 677: usbd_set_report_async(scd->sc_parent->sc_iface, type,
1.1 augustss 678: scd->sc_report_id, data, len);
679: }
680:
681: usbd_status
682: uhidev_get_report(struct uhidev *scd, int type, void *data, int len)
683: {
1.6 augustss 684: return usbd_get_report(scd->sc_parent->sc_iface, type,
1.1 augustss 685: scd->sc_report_id, data, len);
686: }
1.25 skrll 687:
688: usbd_status
689: uhidev_write(struct uhidev_softc *sc, void *data, int len)
690: {
691:
692: DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
693:
694: if (sc->sc_opipe == NULL)
695: return USBD_INVAL;
696:
697: #ifdef UHIDEV_DEBUG
698: if (uhidevdebug > 50) {
699:
700: u_int32_t i;
701: u_int8_t *d = data;
702:
703: DPRINTF(("uhidev_write: data ="));
704: for (i = 0; i < len; i++)
705: DPRINTF((" %02x", d[i]));
706: DPRINTF(("\n"));
707: }
708: #endif
709: return usbd_intr_transfer(sc->sc_oxfer, sc->sc_opipe, 0,
710: USBD_NO_TIMEOUT, data, &len, "uhidevwi");
711: }
CVSweb <webmaster@jp.NetBSD.org>