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