This source file includes following definitions.
- uhidev_match
- uhidev_attach
- uhidev_maxrepid
- uhidevprint
- uhidevsubmatch
- uhidev_activate
- uhidev_detach
- uhidev_intr
- uhidev_get_report_desc
- uhidev_open
- uhidev_close
- uhidev_set_report
- uhidev_set_report_async
- uhidev_get_report
- uhidev_write
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
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
119
120
121
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
201
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
210 descptr = NULL;
211 if (uaa->vendor == USB_VENDOR_WACOM) {
212 static uByte reportbuf[] = {2, 2, 2};
213
214
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
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;
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 ;
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
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;
511 }
512
513
514
515
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
550 usbd_close_pipe(sc->sc_opipe);
551 out2:
552
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
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
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 }