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