]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hid/hidbus.c
hid: Import usbhid - USB transport backend for HID subsystem.
[FreeBSD/FreeBSD.git] / sys / dev / hid / hidbus.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/ck.h>
34 #include <sys/epoch.h>
35 #include <sys/kdb.h>
36 #include <sys/kernel.h>
37 #include <sys/libkern.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/proc.h>
43 #include <sys/systm.h>
44 #include <sys/sx.h>
45
46 #define HID_DEBUG_VAR   hid_debug
47 #include <dev/hid/hid.h>
48 #include <dev/hid/hidbus.h>
49 #include <dev/hid/hidquirk.h>
50
51 #include "hid_if.h"
52
53 #define INPUT_EPOCH     global_epoch_preempt
54 #define HID_RSIZE_MAX   1024
55
56 static hid_intr_t       hidbus_intr;
57
58 static device_probe_t   hidbus_probe;
59 static device_attach_t  hidbus_attach;
60 static device_detach_t  hidbus_detach;
61
62 struct hidbus_ivars {
63         int32_t                         usage;
64         uint8_t                         index;
65         uint32_t                        flags;
66         uintptr_t                       driver_info;    /* for internal use */
67         struct mtx                      *mtx;           /* child intr mtx */
68         hid_intr_t                      *intr_handler;  /* executed under mtx*/
69         void                            *intr_ctx;
70         unsigned int                    refcnt;         /* protected by mtx */
71         struct epoch_context            epoch_ctx;
72         CK_STAILQ_ENTRY(hidbus_ivars)   link;
73 };
74
75 struct hidbus_softc {
76         device_t                        dev;
77         struct sx                       sx;
78         struct mtx                      mtx;
79
80         bool                            nowrite;
81
82         struct hid_rdesc_info           rdesc;
83         bool                            overloaded;
84         int                             nest;   /* Child attach nesting lvl */
85         int                             nauto;  /* Number of autochildren */
86
87         CK_STAILQ_HEAD(, hidbus_ivars)  tlcs;
88 };
89
90 static int
91 hidbus_fill_rdesc_info(struct hid_rdesc_info *hri, const void *data,
92     hid_size_t len)
93 {
94         int error = 0;
95
96         hri->data = __DECONST(void *, data);
97         hri->len = len;
98
99         /*
100          * If report descriptor is not available yet, set maximal
101          * report sizes high enough to allow hidraw to work.
102          */
103         hri->isize = len == 0 ? HID_RSIZE_MAX :
104             hid_report_size_max(data, len, hid_input, &hri->iid);
105         hri->osize = len == 0 ? HID_RSIZE_MAX :
106             hid_report_size_max(data, len, hid_output, &hri->oid);
107         hri->fsize = len == 0 ? HID_RSIZE_MAX :
108             hid_report_size_max(data, len, hid_feature, &hri->fid);
109
110         if (hri->isize > HID_RSIZE_MAX) {
111                 DPRINTF("input size is too large, %u bytes (truncating)\n",
112                     hri->isize);
113                 hri->isize = HID_RSIZE_MAX;
114                 error = EOVERFLOW;
115         }
116         if (hri->osize > HID_RSIZE_MAX) {
117                 DPRINTF("output size is too large, %u bytes (truncating)\n",
118                     hri->osize);
119                 hri->osize = HID_RSIZE_MAX;
120                 error = EOVERFLOW;
121         }
122         if (hri->fsize > HID_RSIZE_MAX) {
123                 DPRINTF("feature size is too large, %u bytes (truncating)\n",
124                     hri->fsize);
125                 hri->fsize = HID_RSIZE_MAX;
126                 error = EOVERFLOW;
127         }
128
129         return (error);
130 }
131
132 int
133 hidbus_locate(const void *desc, hid_size_t size, int32_t u, enum hid_kind k,
134     uint8_t tlc_index, uint8_t index, struct hid_location *loc,
135     uint32_t *flags, uint8_t *id, struct hid_absinfo *ai)
136 {
137         struct hid_data *d;
138         struct hid_item h;
139         int i;
140
141         d = hid_start_parse(desc, size, 1 << k);
142         HIDBUS_FOREACH_ITEM(d, &h, tlc_index) {
143                 for (i = 0; i < h.nusages; i++) {
144                         if (h.kind == k && h.usages[i] == u) {
145                                 if (index--)
146                                         break;
147                                 if (loc != NULL)
148                                         *loc = h.loc;
149                                 if (flags != NULL)
150                                         *flags = h.flags;
151                                 if (id != NULL)
152                                         *id = h.report_ID;
153                                 if (ai != NULL && (h.flags&HIO_RELATIVE) == 0)
154                                         *ai = (struct hid_absinfo) {
155                                             .max = h.logical_maximum,
156                                             .min = h.logical_minimum,
157                                             .res = hid_item_resolution(&h),
158                                         };
159                                 hid_end_parse(d);
160                                 return (1);
161                         }
162                 }
163         }
164         if (loc != NULL)
165                 loc->size = 0;
166         if (flags != NULL)
167                 *flags = 0;
168         if (id != NULL)
169                 *id = 0;
170         hid_end_parse(d);
171         return (0);
172 }
173
174 static device_t
175 hidbus_add_child(device_t dev, u_int order, const char *name, int unit)
176 {
177         struct hidbus_softc *sc = device_get_softc(dev);
178         struct hidbus_ivars *tlc;
179         device_t child;
180
181         child = device_add_child_ordered(dev, order, name, unit);
182         if (child == NULL)
183                         return (child);
184
185         tlc = malloc(sizeof(struct hidbus_ivars), M_DEVBUF, M_WAITOK | M_ZERO);
186         tlc->mtx = &sc->mtx;
187         device_set_ivars(child, tlc);
188         sx_xlock(&sc->sx);
189         CK_STAILQ_INSERT_TAIL(&sc->tlcs, tlc, link);
190         sx_unlock(&sc->sx);
191
192         return (child);
193 }
194
195 static int
196 hidbus_enumerate_children(device_t dev, const void* data, hid_size_t len)
197 {
198         struct hidbus_softc *sc = device_get_softc(dev);
199         struct hid_data *hd;
200         struct hid_item hi;
201         device_t child;
202         uint8_t index = 0;
203
204         if (data == NULL || len == 0)
205                 return (ENXIO);
206
207         /* Add a child for each top level collection */
208         hd = hid_start_parse(data, len, 1 << hid_input);
209         while (hid_get_item(hd, &hi)) {
210                 if (hi.kind != hid_collection || hi.collevel != 1)
211                         continue;
212                 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
213                 if (child == NULL) {
214                         device_printf(dev, "Could not add HID device\n");
215                         continue;
216                 }
217                 hidbus_set_index(child, index);
218                 hidbus_set_usage(child, hi.usage);
219                 hidbus_set_flags(child, HIDBUS_FLAG_AUTOCHILD);
220                 index++;
221                 DPRINTF("Add child TLC: 0x%04x:0x%04x\n",
222                     HID_GET_USAGE_PAGE(hi.usage), HID_GET_USAGE(hi.usage));
223         }
224         hid_end_parse(hd);
225
226         if (index == 0)
227                 return (ENXIO);
228
229         sc->nauto = index;
230
231         return (0);
232 }
233
234 static int
235 hidbus_attach_children(device_t dev)
236 {
237         struct hidbus_softc *sc = device_get_softc(dev);
238         int error;
239
240         HID_INTR_SETUP(device_get_parent(dev), hidbus_intr, sc, &sc->rdesc);
241
242         error = hidbus_enumerate_children(dev, sc->rdesc.data, sc->rdesc.len);
243         if (error != 0)
244                 DPRINTF("failed to enumerate children: error %d\n", error);
245
246         /*
247          * hidbus_attach_children() can recurse through device_identify->
248          * hid_set_report_descr() call sequence. Do not perform children
249          * attach twice in that case.
250          */
251         sc->nest++;
252         bus_generic_probe(dev);
253         sc->nest--;
254         if (sc->nest != 0)
255                 return (0);
256
257         if (hid_is_keyboard(sc->rdesc.data, sc->rdesc.len) != 0)
258                 error = bus_generic_attach(dev);
259         else
260                 error = bus_delayed_attach_children(dev);
261         if (error != 0)
262                 device_printf(dev, "failed to attach child: error %d\n", error);
263
264         return (error);
265 }
266
267 static int
268 hidbus_detach_children(device_t dev)
269 {
270         device_t *children, bus;
271         bool is_bus;
272         int i, error;
273
274         error = 0;
275
276         is_bus = device_get_devclass(dev) == hidbus_devclass;
277         bus = is_bus ? dev : device_get_parent(dev);
278
279         KASSERT(device_get_devclass(bus) == hidbus_devclass,
280             ("Device is not hidbus or it's child"));
281
282         if (is_bus) {
283                 /* If hidbus is passed, delete all children. */
284                 bus_generic_detach(bus);
285                 device_delete_children(bus);
286         } else {
287                 /*
288                  * If hidbus child is passed, delete all hidbus children
289                  * except caller. Deleting the caller may result in deadlock.
290                  */
291                 error = device_get_children(bus, &children, &i);
292                 if (error != 0)
293                         return (error);
294                 while (i-- > 0) {
295                         if (children[i] == dev)
296                                 continue;
297                         DPRINTF("Delete child. index=%d (%s)\n",
298                             hidbus_get_index(children[i]),
299                             device_get_nameunit(children[i]));
300                         error = device_delete_child(bus, children[i]);
301                         if (error) {
302                                 DPRINTF("Failed deleting %s\n",
303                                     device_get_nameunit(children[i]));
304                                 break;
305                         }
306                 }
307                 free(children, M_TEMP);
308         }
309
310         HID_INTR_UNSETUP(device_get_parent(bus));
311
312         return (error);
313 }
314
315 static int
316 hidbus_probe(device_t dev)
317 {
318
319         device_set_desc(dev, "HID bus");
320
321         /* Allow other subclasses to override this driver. */
322         return (BUS_PROBE_GENERIC);
323 }
324
325 static int
326 hidbus_attach(device_t dev)
327 {
328         struct hidbus_softc *sc = device_get_softc(dev);
329         struct hid_device_info *devinfo = device_get_ivars(dev);
330         void *d_ptr = NULL;
331         hid_size_t d_len;
332         int error;
333
334         sc->dev = dev;
335         CK_STAILQ_INIT(&sc->tlcs);
336         mtx_init(&sc->mtx, "hidbus ivar lock", NULL, MTX_DEF);
337         sx_init(&sc->sx, "hidbus ivar list lock");
338
339         /*
340          * Ignore error. It is possible for non-HID device e.g. XBox360 gamepad
341          * to emulate HID through overloading of report descriptor.
342          */
343         d_len = devinfo->rdescsize;
344         if (d_len != 0) {
345                 d_ptr = malloc(d_len, M_DEVBUF, M_ZERO | M_WAITOK);
346                 error = hid_get_rdesc(dev, d_ptr, d_len);
347                 if (error != 0) {
348                         free(d_ptr, M_DEVBUF);
349                         d_len = 0;
350                         d_ptr = NULL;
351                 }
352         }
353
354         hidbus_fill_rdesc_info(&sc->rdesc, d_ptr, d_len);
355
356         sc->nowrite = hid_test_quirk(devinfo, HQ_NOWRITE);
357
358         error = hidbus_attach_children(dev);
359         if (error != 0) {
360                 hidbus_detach(dev);
361                 return (ENXIO);
362         }
363
364         return (0);
365 }
366
367 static int
368 hidbus_detach(device_t dev)
369 {
370         struct hidbus_softc *sc = device_get_softc(dev);
371
372         hidbus_detach_children(dev);
373         sx_destroy(&sc->sx);
374         mtx_destroy(&sc->mtx);
375         free(sc->rdesc.data, M_DEVBUF);
376
377         return (0);
378 }
379
380 static void
381 hidbus_child_detached(device_t bus, device_t child)
382 {
383         struct hidbus_softc *sc = device_get_softc(bus);
384         struct hidbus_ivars *tlc = device_get_ivars(child);
385
386         KASSERT(tlc->refcnt == 0, ("Child device is running"));
387         tlc->mtx = &sc->mtx;
388         tlc->intr_handler = NULL;
389         tlc->flags &= ~HIDBUS_FLAG_CAN_POLL;
390 }
391
392 /*
393  * Epoch callback indicating tlc is safe to destroy
394  */
395 static void
396 hidbus_ivar_dtor(epoch_context_t ctx)
397 {
398         struct hidbus_ivars *tlc;
399
400         tlc = __containerof(ctx, struct hidbus_ivars, epoch_ctx);
401         free(tlc, M_DEVBUF);
402 }
403
404 static void
405 hidbus_child_deleted(device_t bus, device_t child)
406 {
407         struct hidbus_softc *sc = device_get_softc(bus);
408         struct hidbus_ivars *tlc = device_get_ivars(child);
409
410         sx_xlock(&sc->sx);
411         KASSERT(tlc->refcnt == 0, ("Child device is running"));
412         CK_STAILQ_REMOVE(&sc->tlcs, tlc, hidbus_ivars, link);
413         sx_unlock(&sc->sx);
414         epoch_call(INPUT_EPOCH, hidbus_ivar_dtor, &tlc->epoch_ctx);
415 }
416
417 static int
418 hidbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
419 {
420         struct hidbus_softc *sc = device_get_softc(bus);
421         struct hidbus_ivars *tlc = device_get_ivars(child);
422
423         switch (which) {
424         case HIDBUS_IVAR_INDEX:
425                 *result = tlc->index;
426                 break;
427         case HIDBUS_IVAR_USAGE:
428                 *result = tlc->usage;
429                 break;
430         case HIDBUS_IVAR_FLAGS:
431                 *result = tlc->flags;
432                 break;
433         case HIDBUS_IVAR_DRIVER_INFO:
434                 *result = tlc->driver_info;
435                 break;
436         case HIDBUS_IVAR_LOCK:
437                 *result = (uintptr_t)(tlc->mtx == &sc->mtx ? NULL : tlc->mtx);
438                 break;
439         default:
440                 return (EINVAL);
441         }
442         return (0);
443 }
444
445 static int
446 hidbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
447 {
448         struct hidbus_softc *sc = device_get_softc(bus);
449         struct hidbus_ivars *tlc = device_get_ivars(child);
450
451         switch (which) {
452         case HIDBUS_IVAR_INDEX:
453                 tlc->index = value;
454                 break;
455         case HIDBUS_IVAR_USAGE:
456                 tlc->usage = value;
457                 break;
458         case HIDBUS_IVAR_FLAGS:
459                 tlc->flags = value;
460                 break;
461         case HIDBUS_IVAR_DRIVER_INFO:
462                 tlc->driver_info = value;
463                 break;
464         case HIDBUS_IVAR_LOCK:
465                 tlc->mtx = (struct mtx *)value == NULL ?
466                     &sc->mtx : (struct mtx *)value;
467                 break;
468         default:
469                 return (EINVAL);
470         }
471         return (0);
472 }
473
474 /* Location hint for devctl(8) */
475 static int
476 hidbus_child_location_str(device_t bus, device_t child, char *buf,
477     size_t buflen)
478 {
479         struct hidbus_ivars *tlc = device_get_ivars(child);
480
481         snprintf(buf, buflen, "index=%hhu", tlc->index);
482         return (0);
483 }
484
485 /* PnP information for devctl(8) */
486 static int
487 hidbus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
488     size_t buflen)
489 {
490         struct hidbus_ivars *tlc = device_get_ivars(child);
491         struct hid_device_info *devinfo = device_get_ivars(bus);
492
493         snprintf(buf, buflen, "page=0x%04x usage=0x%04x bus=0x%02hx "
494             "vendor=0x%04hx product=0x%04hx version=0x%04hx%s%s",
495             HID_GET_USAGE_PAGE(tlc->usage), HID_GET_USAGE(tlc->usage),
496             devinfo->idBus, devinfo->idVendor, devinfo->idProduct,
497             devinfo->idVersion, devinfo->idPnP[0] == '\0' ? "" : " _HID=",
498             devinfo->idPnP[0] == '\0' ? "" : devinfo->idPnP);
499         return (0);
500 }
501
502 void
503 hidbus_set_desc(device_t child, const char *suffix)
504 {
505         device_t bus = device_get_parent(child);
506         struct hidbus_softc *sc = device_get_softc(bus);
507         struct hid_device_info *devinfo = device_get_ivars(bus);
508         struct hidbus_ivars *tlc = device_get_ivars(child);
509         char buf[80];
510
511         /* Do not add NULL suffix or if device name already contains it. */
512         if (suffix != NULL && strcasestr(devinfo->name, suffix) == NULL &&
513             (sc->nauto > 1 || (tlc->flags & HIDBUS_FLAG_AUTOCHILD) == 0)) {
514                 snprintf(buf, sizeof(buf), "%s %s", devinfo->name, suffix);
515                 device_set_desc_copy(child, buf);
516         } else
517                 device_set_desc(child, devinfo->name);
518 }
519
520 device_t
521 hidbus_find_child(device_t bus, int32_t usage)
522 {
523         device_t *children, child;
524         int ccount, i;
525
526         GIANT_REQUIRED;
527
528         /* Get a list of all hidbus children */
529         if (device_get_children(bus, &children, &ccount) != 0)
530                 return (NULL);
531
532         /* Scan through to find required TLC */
533         for (i = 0, child = NULL; i < ccount; i++) {
534                 if (hidbus_get_usage(children[i]) == usage) {
535                         child = children[i];
536                         break;
537                 }
538         }
539         free(children, M_TEMP);
540
541         return (child);
542 }
543
544 void
545 hidbus_intr(void *context, void *buf, hid_size_t len)
546 {
547         struct hidbus_softc *sc = context;
548         struct hidbus_ivars *tlc;
549         struct epoch_tracker et;
550
551         /*
552          * Broadcast input report to all subscribers.
553          * TODO: Add check for input report ID.
554          *
555          * Relock mutex on every TLC item as we can't hold any locks over whole
556          * TLC list here due to LOR with open()/close() handlers.
557          */
558         if (!HID_IN_POLLING_MODE())
559                 epoch_enter_preempt(INPUT_EPOCH, &et);
560         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
561                 if (tlc->refcnt == 0 || tlc->intr_handler == NULL)
562                         continue;
563                 if (HID_IN_POLLING_MODE()) {
564                         if ((tlc->flags & HIDBUS_FLAG_CAN_POLL) != 0)
565                                 tlc->intr_handler(tlc->intr_ctx, buf, len);
566                 } else {
567                         mtx_lock(tlc->mtx);
568                         tlc->intr_handler(tlc->intr_ctx, buf, len);
569                         mtx_unlock(tlc->mtx);
570                 }
571         }
572         if (!HID_IN_POLLING_MODE())
573                 epoch_exit_preempt(INPUT_EPOCH, &et);
574 }
575
576 void
577 hidbus_set_intr(device_t child, hid_intr_t *handler, void *context)
578 {
579         struct hidbus_ivars *tlc = device_get_ivars(child);
580
581         tlc->intr_handler = handler;
582         tlc->intr_ctx = context;
583 }
584
585 int
586 hidbus_intr_start(device_t child)
587 {
588         device_t bus = device_get_parent(child);
589         struct hidbus_softc *sc = device_get_softc(bus);
590         struct hidbus_ivars *ivar = device_get_ivars(child);
591         struct hidbus_ivars *tlc;
592         int refcnt = 0;
593         int error;
594
595         if (sx_xlock_sig(&sc->sx) != 0)
596                 return (EINTR);
597         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
598                 refcnt += tlc->refcnt;
599                 if (tlc == ivar) {
600                         mtx_lock(tlc->mtx);
601                         ++tlc->refcnt;
602                         mtx_unlock(tlc->mtx);
603                 }
604         }
605         error = refcnt != 0 ? 0 : HID_INTR_START(device_get_parent(bus));
606         sx_unlock(&sc->sx);
607
608         return (error);
609 }
610
611 int
612 hidbus_intr_stop(device_t child)
613 {
614         device_t bus = device_get_parent(child);
615         struct hidbus_softc *sc = device_get_softc(bus);
616         struct hidbus_ivars *ivar = device_get_ivars(child);
617         struct hidbus_ivars *tlc;
618         bool refcnt = 0;
619         int error;
620
621         if (sx_xlock_sig(&sc->sx) != 0)
622                 return (EINTR);
623         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
624                 if (tlc == ivar) {
625                         mtx_lock(tlc->mtx);
626                         MPASS(tlc->refcnt != 0);
627                         --tlc->refcnt;
628                         mtx_unlock(tlc->mtx);
629                 }
630                 refcnt += tlc->refcnt;
631         }
632         error = refcnt != 0 ? 0 : HID_INTR_STOP(device_get_parent(bus));
633         sx_unlock(&sc->sx);
634
635         return (error);
636 }
637
638 void
639 hidbus_intr_poll(device_t child)
640 {
641         device_t bus = device_get_parent(child);
642
643         HID_INTR_POLL(device_get_parent(bus));
644 }
645
646 struct hid_rdesc_info *
647 hidbus_get_rdesc_info(device_t child)
648 {
649         device_t bus = device_get_parent(child);
650         struct hidbus_softc *sc = device_get_softc(bus);
651
652         return (&sc->rdesc);
653 }
654
655 /*
656  * HID interface.
657  *
658  * Hidbus as well as any hidbus child can be passed as first arg.
659  */
660
661 /* Read cached report descriptor */
662 int
663 hid_get_report_descr(device_t dev, void **data, hid_size_t *len)
664 {
665         device_t bus;
666         struct hidbus_softc *sc;
667
668         bus = device_get_devclass(dev) == hidbus_devclass ?
669             dev : device_get_parent(dev);
670         sc = device_get_softc(bus);
671
672         /*
673          * Do not send request to a transport backend.
674          * Use cached report descriptor instead of it.
675          */
676         if (sc->rdesc.data == NULL || sc->rdesc.len == 0)
677                 return (ENXIO);
678
679         if (data != NULL)
680                 *data = sc->rdesc.data;
681         if (len != NULL)
682                 *len = sc->rdesc.len;
683
684         return (0);
685 }
686
687 /*
688  * Replace cached report descriptor with top level driver provided one.
689  *
690  * It deletes all hidbus children except caller and enumerates them again after
691  * new descriptor has been registered. Currently it can not be called from
692  * autoenumerated (by report's TLC) child device context as it results in child
693  * duplication. To overcome this limitation hid_set_report_descr() should be
694  * called from device_identify driver's handler with hidbus itself passed as
695  * 'device_t dev' parameter.
696  */
697 int
698 hid_set_report_descr(device_t dev, const void *data, hid_size_t len)
699 {
700         struct hid_rdesc_info rdesc;
701         device_t bus;
702         struct hidbus_softc *sc;
703         bool is_bus;
704         int error;
705
706         GIANT_REQUIRED;
707
708         is_bus = device_get_devclass(dev) == hidbus_devclass;
709         bus = is_bus ? dev : device_get_parent(dev);
710         sc = device_get_softc(bus);
711
712         /*
713          * Do not overload already overloaded report descriptor in
714          * device_identify handler. It causes infinite recursion loop.
715          */
716         if (is_bus && sc->overloaded)
717                 return(0);
718
719         DPRINTFN(5, "len=%d\n", len);
720         DPRINTFN(5, "data = %*D\n", len, data, " ");
721
722         error = hidbus_fill_rdesc_info(&rdesc, data, len);
723         if (error != 0)
724                 return (error);
725
726         error = hidbus_detach_children(dev);
727         if (error != 0)
728                 return(error);
729
730         /* Make private copy to handle a case of dynamicaly allocated data. */
731         rdesc.data = malloc(len, M_DEVBUF, M_ZERO | M_WAITOK);
732         bcopy(data, rdesc.data, len);
733         sc->overloaded = true;
734         free(sc->rdesc.data, M_DEVBUF);
735         bcopy(&rdesc, &sc->rdesc, sizeof(struct hid_rdesc_info));
736
737         error = hidbus_attach_children(bus);
738
739         return (error);
740 }
741
742 static int
743 hidbus_write(device_t dev, const void *data, hid_size_t len)
744 {
745         struct hidbus_softc *sc;
746         uint8_t id;
747
748         sc = device_get_softc(dev);
749         /*
750          * Output interrupt endpoint is often optional. If HID device
751          * does not provide it, send reports via control pipe.
752          */
753         if (sc->nowrite) {
754                 /* try to extract the ID byte */
755                 id = (sc->rdesc.oid & (len > 0)) ? *(const uint8_t*)data : 0;
756                 return (hid_set_report(dev, data, len, HID_OUTPUT_REPORT, id));
757         }
758
759         return (hid_write(dev, data, len));
760 }
761
762 /*------------------------------------------------------------------------*
763  *      hidbus_lookup_id
764  *
765  * This functions takes an array of "struct hid_device_id" and tries
766  * to match the entries with the information in "struct hid_device_info".
767  *
768  * Return values:
769  * NULL: No match found.
770  * Else: Pointer to matching entry.
771  *------------------------------------------------------------------------*/
772 const struct hid_device_id *
773 hidbus_lookup_id(device_t dev, const struct hid_device_id *id, int nitems_id)
774 {
775         const struct hid_device_id *id_end;
776         const struct hid_device_info *info;
777         int32_t usage;
778         bool is_child;
779
780         if (id == NULL) {
781                 goto done;
782         }
783
784         id_end = id + nitems_id;
785         info = hid_get_device_info(dev);
786         is_child = device_get_devclass(dev) != hidbus_devclass;
787         if (is_child)
788                 usage = hidbus_get_usage(dev);
789
790         /*
791          * Keep on matching array entries until we find a match or
792          * until we reach the end of the matching array:
793          */
794         for (; id != id_end; id++) {
795
796                 if (is_child && (id->match_flag_page) &&
797                     (id->page != HID_GET_USAGE_PAGE(usage))) {
798                         continue;
799                 }
800                 if (is_child && (id->match_flag_usage) &&
801                     (id->usage != HID_GET_USAGE(usage))) {
802                         continue;
803                 }
804                 if ((id->match_flag_bus) &&
805                     (id->idBus != info->idBus)) {
806                         continue;
807                 }
808                 if ((id->match_flag_vendor) &&
809                     (id->idVendor != info->idVendor)) {
810                         continue;
811                 }
812                 if ((id->match_flag_product) &&
813                     (id->idProduct != info->idProduct)) {
814                         continue;
815                 }
816                 if ((id->match_flag_ver_lo) &&
817                     (id->idVersion_lo > info->idVersion)) {
818                         continue;
819                 }
820                 if ((id->match_flag_ver_hi) &&
821                     (id->idVersion_hi < info->idVersion)) {
822                         continue;
823                 }
824                 if (id->match_flag_pnp &&
825                     strncmp(id->idPnP, info->idPnP, HID_PNP_ID_SIZE) != 0) {
826                         continue;
827                 }
828                 /* We found a match! */
829                 return (id);
830         }
831
832 done:
833         return (NULL);
834 }
835
836 /*------------------------------------------------------------------------*
837  *      hidbus_lookup_driver_info - factored out code
838  *
839  * Return values:
840  *    0: Success
841  * Else: Failure
842  *------------------------------------------------------------------------*/
843 int
844 hidbus_lookup_driver_info(device_t child, const struct hid_device_id *id,
845     int nitems_id)
846 {
847
848         id = hidbus_lookup_id(child, id, nitems_id);
849         if (id) {
850                 /* copy driver info */
851                 hidbus_set_driver_info(child, id->driver_info);
852                 return (0);
853         }
854         return (ENXIO);
855 }
856
857 const struct hid_device_info *
858 hid_get_device_info(device_t dev)
859 {
860         device_t bus;
861
862         bus = device_get_devclass(dev) == hidbus_devclass ?
863             dev : device_get_parent(dev);
864
865         return (device_get_ivars(bus));
866 }
867
868 static device_method_t hidbus_methods[] = {
869         /* device interface */
870         DEVMETHOD(device_probe,         hidbus_probe),
871         DEVMETHOD(device_attach,        hidbus_attach),
872         DEVMETHOD(device_detach,        hidbus_detach),
873         DEVMETHOD(device_suspend,       bus_generic_suspend),
874         DEVMETHOD(device_resume,        bus_generic_resume),
875
876         /* bus interface */
877         DEVMETHOD(bus_add_child,        hidbus_add_child),
878         DEVMETHOD(bus_child_detached,   hidbus_child_detached),
879         DEVMETHOD(bus_child_deleted,    hidbus_child_deleted),
880         DEVMETHOD(bus_read_ivar,        hidbus_read_ivar),
881         DEVMETHOD(bus_write_ivar,       hidbus_write_ivar),
882         DEVMETHOD(bus_child_pnpinfo_str,hidbus_child_pnpinfo_str),
883         DEVMETHOD(bus_child_location_str,hidbus_child_location_str),
884
885         /* hid interface */
886         DEVMETHOD(hid_get_rdesc,        hid_get_rdesc),
887         DEVMETHOD(hid_read,             hid_read),
888         DEVMETHOD(hid_write,            hidbus_write),
889         DEVMETHOD(hid_get_report,       hid_get_report),
890         DEVMETHOD(hid_set_report,       hid_set_report),
891         DEVMETHOD(hid_set_idle,         hid_set_idle),
892         DEVMETHOD(hid_set_protocol,     hid_set_protocol),
893
894         DEVMETHOD_END
895 };
896
897 devclass_t hidbus_devclass;
898 driver_t hidbus_driver = {
899         "hidbus",
900         hidbus_methods,
901         sizeof(struct hidbus_softc),
902 };
903
904 MODULE_DEPEND(hidbus, hid, 1, 1, 1);
905 MODULE_VERSION(hidbus, 1);
906 DRIVER_MODULE(hidbus, iichid, hidbus_driver, hidbus_devclass, 0, 0);
907 DRIVER_MODULE(hidbus, usbhid, hidbus_driver, hidbus_devclass, 0, 0);