Annotation of sys/dev/usb/uhidev.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uhidev.c,v 1.27 2007/06/14 10:11:16 mbalmer Exp $ */
2: /* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */
3:
4: /*
5: * Copyright (c) 2001 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (lennart@augustsson.net) at
10: * Carlstedt Research & Technology.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/malloc.h>
49: #include <sys/signalvar.h>
50: #include <sys/device.h>
51: #include <sys/ioctl.h>
52: #include <sys/conf.h>
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>
67:
68: #ifdef UHIDEV_DEBUG
69: #define DPRINTF(x) do { if (uhidevdebug) printf x; } while (0)
70: #define DPRINTFN(n,x) do { if (uhidevdebug>(n)) printf x; } while (0)
71: int uhidevdebug = 0;
72: #else
73: #define DPRINTF(x)
74: #define DPRINTFN(n,x)
75: #endif
76:
77: void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
78:
79: int uhidev_maxrepid(void *buf, int len);
80: int uhidevprint(void *aux, const char *pnp);
81: int uhidevsubmatch(struct device *parent, void *cf, void *aux);
82:
83: int uhidev_match(struct device *, void *, void *);
84: void uhidev_attach(struct device *, struct device *, void *);
85: int uhidev_detach(struct device *, int);
86: int uhidev_activate(struct device *, enum devact);
87:
88: struct cfdriver uhidev_cd = {
89: NULL, "uhidev", DV_DULL
90: };
91:
92: const struct cfattach uhidev_ca = {
93: sizeof(struct uhidev_softc),
94: uhidev_match,
95: uhidev_attach,
96: uhidev_detach,
97: uhidev_activate,
98: };
99:
100: int
101: uhidev_match(struct device *parent, void *match, void *aux)
102: {
103: struct usb_attach_arg *uaa = aux;
104: usb_interface_descriptor_t *id;
105:
106: if (uaa->iface == NULL)
107: return (UMATCH_NONE);
108: id = usbd_get_interface_descriptor(uaa->iface);
109: if (id == NULL || id->bInterfaceClass != UICLASS_HID)
110: return (UMATCH_NONE);
111: if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID)
112: return (UMATCH_NONE);
113: if (uaa->matchlvl)
114: return (uaa->matchlvl);
115:
116: #ifdef __macppc__
117: /*
118: * Some Apple laptops have USB phantom devices which match
119: * the ADB devices. We want to ignore them to avoid
120: * confusing users, as the real hardware underneath is adb
121: * and has already attached.
122: */
123: if (uaa->vendor == USB_VENDOR_APPLE &&
124: uaa->product == USB_PRODUCT_APPLE_ADB)
125: return (UMATCH_NONE);
126: #endif
127:
128: return (UMATCH_IFACECLASS_GENERIC);
129: }
130:
131: void
132: uhidev_attach(struct device *parent, struct device *self, void *aux)
133: {
134: struct uhidev_softc *sc = (struct uhidev_softc *)self;
135: struct usb_attach_arg *uaa = aux;
136: usbd_interface_handle iface = uaa->iface;
137: usb_interface_descriptor_t *id;
138: usb_endpoint_descriptor_t *ed;
139: struct uhidev_attach_arg uha;
140: struct uhidev *dev;
141: int size, nrepid, repid, repsz;
142: int repsizes[256];
143: int i;
144: void *desc;
145: const void *descptr;
146: usbd_status err;
147: char *devinfop;
148:
149: sc->sc_udev = uaa->device;
150: sc->sc_iface = iface;
151: id = usbd_get_interface_descriptor(iface);
152:
153: devinfop = usbd_devinfo_alloc(uaa->device, 0);
154: printf("\n%s: %s, iclass %d/%d\n", sc->sc_dev.dv_xname,
155: devinfop, id->bInterfaceClass, id->bInterfaceSubClass);
156: usbd_devinfo_free(devinfop);
157:
158: (void)usbd_set_idle(iface, 0, 0);
159: #if 0
160:
161: qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
162: if ((qflags & UQ_NO_SET_PROTO) == 0 &&
163: id->bInterfaceSubClass != UISUBCLASS_BOOT)
164: (void)usbd_set_protocol(iface, 1);
165: #endif
166:
167: sc->sc_iep_addr = sc->sc_oep_addr = -1;
168: for (i = 0; i < id->bNumEndpoints; i++) {
169: ed = usbd_interface2endpoint_descriptor(iface, i);
170: if (ed == NULL) {
171: printf("%s: could not read endpoint descriptor\n",
172: sc->sc_dev.dv_xname);
173: sc->sc_dying = 1;
174: return;
175: }
176:
177: DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
178: "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
179: " bInterval=%d\n",
180: ed->bLength, ed->bDescriptorType,
181: ed->bEndpointAddress & UE_ADDR,
182: UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
183: ed->bmAttributes & UE_XFERTYPE,
184: UGETW(ed->wMaxPacketSize), ed->bInterval));
185:
186: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
187: (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
188: sc->sc_iep_addr = ed->bEndpointAddress;
189: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
190: (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
191: sc->sc_oep_addr = ed->bEndpointAddress;
192: } else {
193: printf("%s: unexpected endpoint\n", sc->sc_dev.dv_xname);
194: sc->sc_dying = 1;
195: return;
196: }
197: }
198:
199: /*
200: * Check that we found an input interrupt endpoint. The output interrupt
201: * endpoint is optional
202: */
203: if (sc->sc_iep_addr == -1) {
204: printf("%s: no input interrupt endpoint\n", sc->sc_dev.dv_xname);
205: sc->sc_dying = 1;
206: return;
207: }
208:
209: /* XXX need to extend this */
210: descptr = NULL;
211: if (uaa->vendor == USB_VENDOR_WACOM) {
212: static uByte reportbuf[] = {2, 2, 2};
213:
214: /* The report descriptor for the Wacom Graphire is broken. */
215: switch (uaa->product) {
216: case USB_PRODUCT_WACOM_GRAPHIRE:
217: size = sizeof uhid_graphire_report_descr;
218: descptr = uhid_graphire_report_descr;
219: break;
220: case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
221: case USB_PRODUCT_WACOM_GRAPHIRE4_4X5:
222: usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
223: &reportbuf, sizeof reportbuf);
224: size = sizeof uhid_graphire3_4x5_report_descr;
225: descptr = uhid_graphire3_4x5_report_descr;
226: break;
227: default:
228: /* Keep descriptor */
229: break;
230: }
231: }
232:
233: if (descptr) {
234: desc = malloc(size, M_USBDEV, M_NOWAIT);
235: if (desc == NULL)
236: err = USBD_NOMEM;
237: else {
238: err = USBD_NORMAL_COMPLETION;
239: memcpy(desc, descptr, size);
240: }
241: } else {
242: desc = NULL;
243: err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV);
244: }
245: if (err) {
246: printf("%s: no report descriptor\n", sc->sc_dev.dv_xname);
247: sc->sc_dying = 1;
248: return;
249: }
250:
251: sc->sc_repdesc = desc;
252: sc->sc_repdesc_size = size;
253:
254: uha.uaa = uaa;
255: nrepid = uhidev_maxrepid(desc, size);
256: if (nrepid < 0)
257: return;
258: if (nrepid > 0)
259: printf("%s: %d report ids\n", sc->sc_dev.dv_xname, nrepid);
260: nrepid++;
261: sc->sc_subdevs = malloc(nrepid * sizeof(struct device *),
262: M_USBDEV, M_NOWAIT);
263: if (sc->sc_subdevs == NULL) {
264: printf("%s: no memory\n", sc->sc_dev.dv_xname);
265: return;
266: }
267: bzero(sc->sc_subdevs, nrepid * sizeof(struct device *));
268: sc->sc_nrepid = nrepid;
269: sc->sc_isize = 0;
270:
271: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
272: &sc->sc_dev);
273:
274: for (repid = 0; repid < nrepid; repid++) {
275: repsz = hid_report_size(desc, size, hid_input, repid);
276: DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
277: repsizes[repid] = repsz;
278: if (repsz > 0) {
279: if (repsz > sc->sc_isize)
280: sc->sc_isize = repsz;
281: }
282: }
283: sc->sc_isize += nrepid != 1; /* space for report ID */
284: DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
285:
286: uha.parent = sc;
287: for (repid = 0; repid < nrepid; repid++) {
288: DPRINTF(("uhidev_match: try repid=%d\n", repid));
289: if (hid_report_size(desc, size, hid_input, repid) == 0 &&
290: hid_report_size(desc, size, hid_output, repid) == 0 &&
291: hid_report_size(desc, size, hid_feature, repid) == 0) {
292: ; /* already NULL in sc->sc_subdevs[repid] */
293: } else {
294: uha.reportid = repid;
295: dev = (struct uhidev *)config_found_sm(self, &uha,
296: uhidevprint, uhidevsubmatch);
297: sc->sc_subdevs[repid] = dev;
298: if (dev != NULL) {
299: dev->sc_in_rep_size = repsizes[repid];
300: #ifdef DIAGNOSTIC
301: DPRINTF(("uhidev_match: repid=%d dev=%p\n",
302: repid, dev));
303: if (dev->sc_intr == NULL) {
304: printf("%s: sc_intr == NULL\n",
305: sc->sc_dev.dv_xname);
306: return;
307: }
308: #endif
309: }
310: }
311: }
312: }
313:
314: int
315: uhidev_maxrepid(void *buf, int len)
316: {
317: struct hid_data *d;
318: struct hid_item h;
319: int maxid;
320:
321: maxid = -1;
322: h.report_ID = 0;
323: for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
324: if (h.report_ID > maxid)
325: maxid = h.report_ID;
326: hid_end_parse(d);
327: return (maxid);
328: }
329:
330: int
331: uhidevprint(void *aux, const char *pnp)
332: {
333: struct uhidev_attach_arg *uha = aux;
334:
335: if (pnp)
336: printf("uhid at %s", pnp);
337: if (uha->reportid != 0)
338: printf(" reportid %d", uha->reportid);
339: return (UNCONF);
340: }
341:
342: int uhidevsubmatch(struct device *parent, void *match, void *aux)
343: {
344: struct uhidev_attach_arg *uha = aux;
345: struct cfdata *cf = match;
346:
347: if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID &&
348: cf->uhidevcf_reportid != uha->reportid)
349: return (0);
350: if (cf->uhidevcf_reportid == uha->reportid)
351: uha->matchlvl = UMATCH_VENDOR_PRODUCT;
352: else
353: uha->matchlvl = 0;
354: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
355: }
356:
357: int
358: uhidev_activate(struct device *self, enum devact act)
359: {
360: struct uhidev_softc *sc = (struct uhidev_softc *)self;
361: int i, rv = 0;
362:
363: switch (act) {
364: case DVACT_ACTIVATE:
365: break;
366:
367: case DVACT_DEACTIVATE:
368: for (i = 0; i < sc->sc_nrepid; i++)
369: if (sc->sc_subdevs[i] != NULL)
370: rv |= config_deactivate(
371: &sc->sc_subdevs[i]->sc_dev);
372: sc->sc_dying = 1;
373: break;
374: }
375: return (rv);
376: }
377:
378: int
379: uhidev_detach(struct device *self, int flags)
380: {
381: struct uhidev_softc *sc = (struct uhidev_softc *)self;
382: int i, rv;
383:
384: DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
385:
386: sc->sc_dying = 1;
387: if (sc->sc_ipipe != NULL)
388: usbd_abort_pipe(sc->sc_ipipe);
389:
390: if (sc->sc_repdesc != NULL)
391: free(sc->sc_repdesc, M_USBDEV);
392:
393: rv = 0;
394: for (i = 0; i < sc->sc_nrepid; i++) {
395: if (sc->sc_subdevs[i] != NULL) {
396: rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags);
397: sc->sc_subdevs[i] = NULL;
398: }
399: }
400:
401: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
402: &sc->sc_dev);
403:
404: return (rv);
405: }
406:
407: void
408: uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
409: {
410: struct uhidev_softc *sc = addr;
411: struct uhidev *scd;
412: u_char *p;
413: u_int rep;
414: u_int32_t cc;
415:
416: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
417:
418: #ifdef UHIDEV_DEBUG
419: if (uhidevdebug > 5) {
420: u_int32_t i;
421:
422: DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc));
423: DPRINTF(("uhidev_intr: data ="));
424: for (i = 0; i < cc; i++)
425: DPRINTF((" %02x", sc->sc_ibuf[i]));
426: DPRINTF(("\n"));
427: }
428: #endif
429:
430: if (status == USBD_CANCELLED)
431: return;
432:
433: if (status != USBD_NORMAL_COMPLETION) {
434: DPRINTF(("%s: interrupt status=%d\n", sc->sc_dev.dv_xname,
435: status));
436: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
437: return;
438: }
439:
440: p = sc->sc_ibuf;
441: if (sc->sc_nrepid != 1)
442: rep = *p++, cc--;
443: else
444: rep = 0;
445: if (rep >= sc->sc_nrepid) {
446: printf("uhidev_intr: bad repid %d\n", rep);
447: return;
448: }
449: scd = sc->sc_subdevs[rep];
450: DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n",
451: rep, scd, scd ? scd->sc_state : 0));
452: if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN))
453: return;
454: #ifdef UHIDEV_DEBUG
455: if (scd->sc_in_rep_size != cc)
456: printf("%s: bad input length %d != %d\n",sc->sc_dev.dv_xname,
457: scd->sc_in_rep_size, cc);
458: #endif
459: scd->sc_intr(scd, p, cc);
460: }
461:
462: void
463: uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size)
464: {
465: *desc = sc->sc_repdesc;
466: *size = sc->sc_repdesc_size;
467: }
468:
469: int
470: uhidev_open(struct uhidev *scd)
471: {
472: struct uhidev_softc *sc = scd->sc_parent;
473: usbd_status err;
474: int error;
475:
476: DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
477: scd->sc_state, sc->sc_refcnt));
478:
479: if (scd->sc_state & UHIDEV_OPEN)
480: return (EBUSY);
481: scd->sc_state |= UHIDEV_OPEN;
482: if (sc->sc_refcnt++)
483: return (0);
484:
485: if (sc->sc_isize == 0)
486: return (0);
487:
488: sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
489:
490: /* Set up input interrupt pipe. */
491: DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
492: sc->sc_iep_addr));
493:
494: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
495: USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
496: sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
497: if (err != USBD_NORMAL_COMPLETION) {
498: DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
499: "error=%d\n", err));
500: error = EIO;
501: goto out1;
502: }
503:
504: DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe));
505:
506: sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
507: if (sc->sc_ixfer == NULL) {
508: DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
509: error = ENOMEM;
510: goto out1; // xxxx
511: }
512:
513: /*
514: * Set up output interrupt pipe if an output interrupt endpoint
515: * exists.
516: */
517: if (sc->sc_oep_addr != -1) {
518: DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
519:
520: err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
521: 0, &sc->sc_opipe);
522:
523: if (err != USBD_NORMAL_COMPLETION) {
524: DPRINTF(("uhidev_open: usbd_open_pipe failed, "
525: "error=%d\n", err));
526: error = EIO;
527: goto out2;
528: }
529: DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
530:
531: sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
532: if (sc->sc_oxfer == NULL) {
533: DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
534: error = ENOMEM;
535: goto out3;
536: }
537:
538: sc->sc_owxfer = usbd_alloc_xfer(sc->sc_udev);
539: if (sc->sc_owxfer == NULL) {
540: DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
541: error = ENOMEM;
542: goto out3;
543: }
544: }
545:
546: return (0);
547:
548: out3:
549: /* Abort output pipe */
550: usbd_close_pipe(sc->sc_opipe);
551: out2:
552: /* Abort input pipe */
553: usbd_close_pipe(sc->sc_ipipe);
554: out1:
555: DPRINTF(("uhidev_open: failed in someway"));
556: free(sc->sc_ibuf, M_USBDEV);
557: scd->sc_state &= ~UHIDEV_OPEN;
558: sc->sc_refcnt = 0;
559: sc->sc_ipipe = NULL;
560: sc->sc_opipe = NULL;
561: if (sc->sc_oxfer != NULL) {
562: usbd_free_xfer(sc->sc_oxfer);
563: sc->sc_oxfer = NULL;
564: }
565: if (sc->sc_owxfer != NULL) {
566: usbd_free_xfer(sc->sc_owxfer);
567: sc->sc_owxfer = NULL;
568: }
569: return (error);
570: }
571:
572: void
573: uhidev_close(struct uhidev *scd)
574: {
575: struct uhidev_softc *sc = scd->sc_parent;
576:
577: if (!(scd->sc_state & UHIDEV_OPEN))
578: return;
579: scd->sc_state &= ~UHIDEV_OPEN;
580: if (--sc->sc_refcnt)
581: return;
582: DPRINTF(("uhidev_close: close pipe\n"));
583:
584: if (sc->sc_oxfer != NULL)
585: usbd_free_xfer(sc->sc_oxfer);
586:
587: if (sc->sc_owxfer != NULL)
588: usbd_free_xfer(sc->sc_owxfer);
589:
590: /* Disable interrupts. */
591: if (sc->sc_opipe != NULL) {
592: usbd_abort_pipe(sc->sc_opipe);
593: usbd_close_pipe(sc->sc_opipe);
594: sc->sc_opipe = NULL;
595: }
596:
597: if (sc->sc_ipipe != NULL) {
598: usbd_abort_pipe(sc->sc_ipipe);
599: usbd_close_pipe(sc->sc_ipipe);
600: sc->sc_ipipe = NULL;
601: }
602:
603: if (sc->sc_ibuf != NULL) {
604: free(sc->sc_ibuf, M_USBDEV);
605: sc->sc_ibuf = NULL;
606: }
607: }
608:
609: usbd_status
610: uhidev_set_report(struct uhidev *scd, int type, void *data, int len)
611: {
612: char *buf;
613: usbd_status retstat;
614:
615: if (scd->sc_report_id == 0)
616: return usbd_set_report(scd->sc_parent->sc_iface, type,
617: scd->sc_report_id, data, len);
618:
619: buf = malloc(len + 1, M_TEMP, M_WAITOK);
620: buf[0] = scd->sc_report_id;
621: memcpy(buf+1, data, len);
622:
623: retstat = usbd_set_report(scd->sc_parent->sc_iface, type,
624: scd->sc_report_id, data, len + 1);
625:
626: free(buf, M_TEMP);
627:
628: return retstat;
629: }
630:
631: void
632: uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len)
633: {
634: /* XXX */
635: char buf[100];
636: if (scd->sc_report_id) {
637: buf[0] = scd->sc_report_id;
638: memcpy(buf+1, data, len);
639: len++;
640: data = buf;
641: }
642:
643: usbd_set_report_async(scd->sc_parent->sc_iface, type,
644: scd->sc_report_id, data, len);
645: }
646:
647: usbd_status
648: uhidev_get_report(struct uhidev *scd, int type, void *data, int len)
649: {
650: return usbd_get_report(scd->sc_parent->sc_iface, type,
651: scd->sc_report_id, data, len);
652: }
653:
654: usbd_status
655: uhidev_write(struct uhidev_softc *sc, void *data, int len)
656: {
657:
658: DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
659:
660: if (sc->sc_opipe == NULL)
661: return USBD_INVAL;
662:
663: #ifdef UHIDEV_DEBUG
664: if (uhidevdebug > 50) {
665:
666: u_int32_t i;
667: u_int8_t *d = data;
668:
669: DPRINTF(("uhidev_write: data ="));
670: for (i = 0; i < len; i++)
671: DPRINTF((" %02x", d[i]));
672: DPRINTF(("\n"));
673: }
674: #endif
675: return usbd_intr_transfer(sc->sc_owxfer, sc->sc_opipe, 0,
676: USBD_NO_TIMEOUT, data, &len, "uhidevwi");
677: }
CVSweb