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