FreeBSD/Linux Kernel Cross Reference
sys/dev/hid/hidraw.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
3 *
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
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 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
36 */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include "opt_hid.h"
42
43 #include <sys/param.h>
44 #include <sys/bus.h>
45 #include <sys/conf.h>
46 #include <sys/fcntl.h>
47 #include <sys/filio.h>
48 #include <sys/ioccom.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/malloc.h>
52 #include <sys/module.h>
53 #include <sys/mutex.h>
54 #include <sys/poll.h>
55 #include <sys/priv.h>
56 #include <sys/proc.h>
57 #include <sys/selinfo.h>
58 #include <sys/sysctl.h>
59 #include <sys/systm.h>
60 #include <sys/tty.h>
61 #include <sys/uio.h>
62
63 #define HID_DEBUG_VAR hidraw_debug
64 #include <dev/hid/hid.h>
65 #include <dev/hid/hidbus.h>
66 #include <dev/hid/hidraw.h>
67
68 #ifdef HID_DEBUG
69 static int hidraw_debug = 0;
70 static SYSCTL_NODE(_hw_hid, OID_AUTO, hidraw, CTLFLAG_RW, 0,
71 "HID raw interface");
72 SYSCTL_INT(_hw_hid_hidraw, OID_AUTO, debug, CTLFLAG_RWTUN,
73 &hidraw_debug, 0, "Debug level");
74 #endif
75
76 #define HIDRAW_INDEX 0xFF /* Arbitrary high value */
77
78 #define HIDRAW_LOCAL_BUFSIZE 64 /* Size of on-stack buffer. */
79 #define HIDRAW_LOCAL_ALLOC(local_buf, size) \
80 (sizeof(local_buf) > (size) ? (local_buf) : \
81 malloc((size), M_DEVBUF, M_ZERO | M_WAITOK))
82 #define HIDRAW_LOCAL_FREE(local_buf, buf) \
83 if ((local_buf) != (buf)) { \
84 free((buf), M_DEVBUF); \
85 }
86
87 struct hidraw_softc {
88 device_t sc_dev; /* base device */
89
90 struct mtx sc_mtx; /* hidbus private mutex */
91
92 struct hid_rdesc_info *sc_rdesc;
93 const struct hid_device_info *sc_hw;
94
95 uint8_t *sc_q;
96 hid_size_t *sc_qlen;
97 int sc_head;
98 int sc_tail;
99 int sc_sleepcnt;
100
101 struct selinfo sc_rsel;
102 struct proc *sc_async; /* process that wants SIGIO */
103 struct { /* driver state */
104 bool open:1; /* device is open */
105 bool aslp:1; /* waiting for device data in read() */
106 bool sel:1; /* waiting for device data in poll() */
107 bool quiet:1; /* Ignore input data */
108 bool immed:1; /* return read data immediately */
109 bool uhid:1; /* driver switched in to uhid mode */
110 bool lock:1; /* input queue sleepable lock */
111 bool flush:1; /* do not wait for data in read() */
112 } sc_state;
113 int sc_fflags; /* access mode for open lifetime */
114
115 struct cdev *dev;
116 };
117
118 static d_open_t hidraw_open;
119 static d_read_t hidraw_read;
120 static d_write_t hidraw_write;
121 static d_ioctl_t hidraw_ioctl;
122 static d_poll_t hidraw_poll;
123 static d_kqfilter_t hidraw_kqfilter;
124
125 static d_priv_dtor_t hidraw_dtor;
126
127 static struct cdevsw hidraw_cdevsw = {
128 .d_version = D_VERSION,
129 .d_open = hidraw_open,
130 .d_read = hidraw_read,
131 .d_write = hidraw_write,
132 .d_ioctl = hidraw_ioctl,
133 .d_poll = hidraw_poll,
134 .d_kqfilter = hidraw_kqfilter,
135 .d_name = "hidraw",
136 };
137
138 static hid_intr_t hidraw_intr;
139
140 static device_identify_t hidraw_identify;
141 static device_probe_t hidraw_probe;
142 static device_attach_t hidraw_attach;
143 static device_detach_t hidraw_detach;
144
145 static int hidraw_kqread(struct knote *, long);
146 static void hidraw_kqdetach(struct knote *);
147 static void hidraw_notify(struct hidraw_softc *);
148
149 static struct filterops hidraw_filterops_read = {
150 .f_isfd = 1,
151 .f_detach = hidraw_kqdetach,
152 .f_event = hidraw_kqread,
153 };
154
155 static void
156 hidraw_identify(driver_t *driver, device_t parent)
157 {
158 device_t child;
159
160 if (device_find_child(parent, "hidraw", -1) == NULL) {
161 child = BUS_ADD_CHILD(parent, 0, "hidraw",
162 device_get_unit(parent));
163 if (child != NULL)
164 hidbus_set_index(child, HIDRAW_INDEX);
165 }
166 }
167
168 static int
169 hidraw_probe(device_t self)
170 {
171
172 if (hidbus_get_index(self) != HIDRAW_INDEX)
173 return (ENXIO);
174
175 hidbus_set_desc(self, "Raw HID Device");
176
177 return (BUS_PROBE_GENERIC);
178 }
179
180 static int
181 hidraw_attach(device_t self)
182 {
183 struct hidraw_softc *sc = device_get_softc(self);
184 struct make_dev_args mda;
185 int error;
186
187 sc->sc_dev = self;
188 sc->sc_rdesc = hidbus_get_rdesc_info(self);
189 sc->sc_hw = hid_get_device_info(self);
190
191 /* Hidraw mode does not require report descriptor to work */
192 if (sc->sc_rdesc->data == NULL || sc->sc_rdesc->len == 0)
193 device_printf(self, "no report descriptor\n");
194
195 mtx_init(&sc->sc_mtx, "hidraw lock", NULL, MTX_DEF);
196 knlist_init_mtx(&sc->sc_rsel.si_note, &sc->sc_mtx);
197
198 make_dev_args_init(&mda);
199 mda.mda_flags = MAKEDEV_WAITOK;
200 mda.mda_devsw = &hidraw_cdevsw;
201 mda.mda_uid = UID_ROOT;
202 mda.mda_gid = GID_OPERATOR;
203 mda.mda_mode = 0600;
204 mda.mda_si_drv1 = sc;
205
206 error = make_dev_s(&mda, &sc->dev, "hidraw%d", device_get_unit(self));
207 if (error) {
208 device_printf(self, "Can not create character device\n");
209 hidraw_detach(self);
210 return (error);
211 }
212 #ifdef HIDRAW_MAKE_UHID_ALIAS
213 (void)make_dev_alias(sc->dev, "uhid%d", device_get_unit(self));
214 #endif
215
216 hidbus_set_lock(self, &sc->sc_mtx);
217 hidbus_set_intr(self, hidraw_intr, sc);
218
219 return (0);
220 }
221
222 static int
223 hidraw_detach(device_t self)
224 {
225 struct hidraw_softc *sc = device_get_softc(self);
226
227 DPRINTF("sc=%p\n", sc);
228
229 if (sc->dev != NULL) {
230 mtx_lock(&sc->sc_mtx);
231 sc->dev->si_drv1 = NULL;
232 /* Wake everyone */
233 hidraw_notify(sc);
234 mtx_unlock(&sc->sc_mtx);
235 destroy_dev(sc->dev);
236 }
237
238 knlist_clear(&sc->sc_rsel.si_note, 0);
239 knlist_destroy(&sc->sc_rsel.si_note);
240 seldrain(&sc->sc_rsel);
241 mtx_destroy(&sc->sc_mtx);
242
243 return (0);
244 }
245
246 void
247 hidraw_intr(void *context, void *buf, hid_size_t len)
248 {
249 struct hidraw_softc *sc = context;
250 int next;
251
252 DPRINTFN(5, "len=%d\n", len);
253 DPRINTFN(5, "data = %*D\n", len, buf, " ");
254
255 next = (sc->sc_tail + 1) % HIDRAW_BUFFER_SIZE;
256 if (sc->sc_state.quiet || next == sc->sc_head)
257 return;
258
259 bcopy(buf, sc->sc_q + sc->sc_tail * sc->sc_rdesc->rdsize, len);
260
261 /* Make sure we don't process old data */
262 if (len < sc->sc_rdesc->rdsize)
263 bzero(sc->sc_q + sc->sc_tail * sc->sc_rdesc->rdsize + len,
264 sc->sc_rdesc->isize - len);
265
266 sc->sc_qlen[sc->sc_tail] = len;
267 sc->sc_tail = next;
268
269 hidraw_notify(sc);
270 }
271
272 static inline int
273 hidraw_lock_queue(struct hidraw_softc *sc, bool flush)
274 {
275 int error = 0;
276
277 mtx_assert(&sc->sc_mtx, MA_OWNED);
278
279 if (flush)
280 sc->sc_state.flush = true;
281 ++sc->sc_sleepcnt;
282 while (sc->sc_state.lock && error == 0) {
283 /* Flush is requested. Wakeup all readers and forbid sleeps */
284 if (flush && sc->sc_state.aslp) {
285 sc->sc_state.aslp = false;
286 DPRINTFN(5, "waking %p\n", &sc->sc_q);
287 wakeup(&sc->sc_q);
288 }
289 error = mtx_sleep(&sc->sc_sleepcnt, &sc->sc_mtx,
290 PZERO | PCATCH, "hidrawio", 0);
291 }
292 --sc->sc_sleepcnt;
293 if (flush)
294 sc->sc_state.flush = false;
295 if (error == 0)
296 sc->sc_state.lock = true;
297
298 return (error);
299 }
300
301 static inline void
302 hidraw_unlock_queue(struct hidraw_softc *sc)
303 {
304
305 mtx_assert(&sc->sc_mtx, MA_OWNED);
306 KASSERT(sc->sc_state.lock, ("input buffer is not locked"));
307
308 if (sc->sc_sleepcnt != 0)
309 wakeup_one(&sc->sc_sleepcnt);
310 sc->sc_state.lock = false;
311 }
312
313 static int
314 hidraw_open(struct cdev *dev, int flag, int mode, struct thread *td)
315 {
316 struct hidraw_softc *sc;
317 int error;
318
319 sc = dev->si_drv1;
320 if (sc == NULL)
321 return (ENXIO);
322
323 DPRINTF("sc=%p\n", sc);
324
325 mtx_lock(&sc->sc_mtx);
326 if (sc->sc_state.open) {
327 mtx_unlock(&sc->sc_mtx);
328 return (EBUSY);
329 }
330 sc->sc_state.open = true;
331 mtx_unlock(&sc->sc_mtx);
332
333 error = devfs_set_cdevpriv(sc, hidraw_dtor);
334 if (error != 0) {
335 mtx_lock(&sc->sc_mtx);
336 sc->sc_state.open = false;
337 mtx_unlock(&sc->sc_mtx);
338 return (error);
339 }
340
341 sc->sc_q = malloc(sc->sc_rdesc->rdsize * HIDRAW_BUFFER_SIZE, M_DEVBUF,
342 M_ZERO | M_WAITOK);
343 sc->sc_qlen = malloc(sizeof(hid_size_t) * HIDRAW_BUFFER_SIZE, M_DEVBUF,
344 M_ZERO | M_WAITOK);
345
346 /* Set up interrupt pipe. */
347 sc->sc_state.immed = false;
348 sc->sc_async = 0;
349 sc->sc_state.uhid = false; /* hidraw mode is default */
350 sc->sc_state.quiet = false;
351 sc->sc_head = sc->sc_tail = 0;
352 sc->sc_fflags = flag;
353
354 hidbus_intr_start(sc->sc_dev);
355
356 return (0);
357 }
358
359 static void
360 hidraw_dtor(void *data)
361 {
362 struct hidraw_softc *sc = data;
363
364 DPRINTF("sc=%p\n", sc);
365
366 /* Disable interrupts. */
367 hidbus_intr_stop(sc->sc_dev);
368
369 sc->sc_tail = sc->sc_head = 0;
370 sc->sc_async = 0;
371 free(sc->sc_q, M_DEVBUF);
372 free(sc->sc_qlen, M_DEVBUF);
373 sc->sc_q = NULL;
374
375 mtx_lock(&sc->sc_mtx);
376 sc->sc_state.open = false;
377 mtx_unlock(&sc->sc_mtx);
378 }
379
380 static int
381 hidraw_read(struct cdev *dev, struct uio *uio, int flag)
382 {
383 struct hidraw_softc *sc;
384 size_t length;
385 int error;
386
387 DPRINTFN(1, "\n");
388
389 sc = dev->si_drv1;
390 if (sc == NULL)
391 return (EIO);
392
393 mtx_lock(&sc->sc_mtx);
394 error = dev->si_drv1 == NULL ? EIO : hidraw_lock_queue(sc, false);
395 if (error != 0) {
396 mtx_unlock(&sc->sc_mtx);
397 return (error);
398 }
399
400 if (sc->sc_state.immed) {
401 mtx_unlock(&sc->sc_mtx);
402 DPRINTFN(1, "immed\n");
403
404 error = hid_get_report(sc->sc_dev, sc->sc_q,
405 sc->sc_rdesc->isize, NULL, HID_INPUT_REPORT,
406 sc->sc_rdesc->iid);
407 if (error == 0)
408 error = uiomove(sc->sc_q, sc->sc_rdesc->isize, uio);
409 mtx_lock(&sc->sc_mtx);
410 goto exit;
411 }
412
413 while (sc->sc_tail == sc->sc_head && !sc->sc_state.flush) {
414 if (flag & O_NONBLOCK) {
415 error = EWOULDBLOCK;
416 goto exit;
417 }
418 sc->sc_state.aslp = true;
419 DPRINTFN(5, "sleep on %p\n", &sc->sc_q);
420 error = mtx_sleep(&sc->sc_q, &sc->sc_mtx, PZERO | PCATCH,
421 "hidrawrd", 0);
422 DPRINTFN(5, "woke, error=%d\n", error);
423 if (dev->si_drv1 == NULL)
424 error = EIO;
425 if (error) {
426 sc->sc_state.aslp = false;
427 goto exit;
428 }
429 }
430
431 while (sc->sc_tail != sc->sc_head && uio->uio_resid > 0) {
432 length = min(uio->uio_resid, sc->sc_state.uhid ?
433 sc->sc_rdesc->isize : sc->sc_qlen[sc->sc_head]);
434 mtx_unlock(&sc->sc_mtx);
435
436 /* Copy the data to the user process. */
437 DPRINTFN(5, "got %lu chars\n", (u_long)length);
438 error = uiomove(sc->sc_q + sc->sc_head * sc->sc_rdesc->rdsize,
439 length, uio);
440
441 mtx_lock(&sc->sc_mtx);
442 if (error != 0)
443 goto exit;
444 /* Remove a small chunk from the input queue. */
445 sc->sc_head = (sc->sc_head + 1) % HIDRAW_BUFFER_SIZE;
446 /*
447 * In uhid mode transfer as many chunks as possible. Hidraw
448 * packets are transferred one by one due to different length.
449 */
450 if (!sc->sc_state.uhid)
451 goto exit;
452 }
453 exit:
454 hidraw_unlock_queue(sc);
455 mtx_unlock(&sc->sc_mtx);
456
457 return (error);
458 }
459
460 static int
461 hidraw_write(struct cdev *dev, struct uio *uio, int flag)
462 {
463 uint8_t local_buf[HIDRAW_LOCAL_BUFSIZE], *buf;
464 struct hidraw_softc *sc;
465 int error;
466 int size;
467 size_t buf_offset;
468 uint8_t id = 0;
469
470 DPRINTFN(1, "\n");
471
472 sc = dev->si_drv1;
473 if (sc == NULL)
474 return (EIO);
475
476 if (sc->sc_rdesc->osize == 0)
477 return (EOPNOTSUPP);
478
479 buf_offset = 0;
480 if (sc->sc_state.uhid) {
481 size = sc->sc_rdesc->osize;
482 if (uio->uio_resid != size)
483 return (EINVAL);
484 } else {
485 size = uio->uio_resid;
486 if (size < 2)
487 return (EINVAL);
488 /* Strip leading 0 if the device doesnt use numbered reports */
489 error = uiomove(&id, 1, uio);
490 if (error)
491 return (error);
492 if (id != 0)
493 buf_offset++;
494 else
495 size--;
496 /* Check if underlying driver could process this request */
497 if (size > sc->sc_rdesc->wrsize)
498 return (ENOBUFS);
499 }
500 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
501 buf[0] = id;
502 error = uiomove(buf + buf_offset, uio->uio_resid, uio);
503 if (error == 0)
504 error = hid_write(sc->sc_dev, buf, size);
505 HIDRAW_LOCAL_FREE(local_buf, buf);
506
507 return (error);
508 }
509
510 static int
511 hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
512 struct thread *td)
513 {
514 uint8_t local_buf[HIDRAW_LOCAL_BUFSIZE];
515 void *buf;
516 struct hidraw_softc *sc;
517 struct hidraw_gen_descriptor *hgd;
518 struct hidraw_report_descriptor *hrd;
519 struct hidraw_devinfo *hdi;
520 uint32_t size;
521 int id, len;
522 int error = 0;
523
524 DPRINTFN(2, "cmd=%lx\n", cmd);
525
526 sc = dev->si_drv1;
527 if (sc == NULL)
528 return (EIO);
529
530 /* fixed-length ioctls handling */
531 switch (cmd) {
532 case FIONBIO:
533 /* All handled in the upper FS layer. */
534 return (0);
535
536 case FIOASYNC:
537 mtx_lock(&sc->sc_mtx);
538 if (*(int *)addr) {
539 if (sc->sc_async == NULL) {
540 sc->sc_async = td->td_proc;
541 DPRINTF("FIOASYNC %p\n", sc->sc_async);
542 } else
543 error = EBUSY;
544 } else
545 sc->sc_async = NULL;
546 mtx_unlock(&sc->sc_mtx);
547 return (error);
548
549 /* XXX this is not the most general solution. */
550 case TIOCSPGRP:
551 mtx_lock(&sc->sc_mtx);
552 if (sc->sc_async == NULL)
553 error = EINVAL;
554 else if (*(int *)addr != sc->sc_async->p_pgid)
555 error = EPERM;
556 mtx_unlock(&sc->sc_mtx);
557 return (error);
558
559 case HIDRAW_GET_REPORT_DESC:
560 if (sc->sc_rdesc->data == NULL || sc->sc_rdesc->len == 0)
561 return (EOPNOTSUPP);
562 mtx_lock(&sc->sc_mtx);
563 sc->sc_state.uhid = true;
564 mtx_unlock(&sc->sc_mtx);
565 hgd = (struct hidraw_gen_descriptor *)addr;
566 if (sc->sc_rdesc->len > hgd->hgd_maxlen) {
567 size = hgd->hgd_maxlen;
568 } else {
569 size = sc->sc_rdesc->len;
570 }
571 hgd->hgd_actlen = size;
572 if (hgd->hgd_data == NULL)
573 return (0); /* descriptor length only */
574 return (copyout(sc->sc_rdesc->data, hgd->hgd_data, size));
575
576
577 case HIDRAW_SET_REPORT_DESC:
578 if (!(sc->sc_fflags & FWRITE))
579 return (EPERM);
580
581 /* check privileges */
582 error = priv_check(curthread, PRIV_DRIVER);
583 if (error)
584 return (error);
585
586 /* Stop interrupts and clear input report buffer */
587 mtx_lock(&sc->sc_mtx);
588 sc->sc_tail = sc->sc_head = 0;
589 error = hidraw_lock_queue(sc, true);
590 if (error == 0)
591 sc->sc_state.quiet = true;
592 mtx_unlock(&sc->sc_mtx);
593 if (error != 0)
594 return(error);
595
596 hgd = (struct hidraw_gen_descriptor *)addr;
597 buf = HIDRAW_LOCAL_ALLOC(local_buf, hgd->hgd_maxlen);
598 copyin(hgd->hgd_data, buf, hgd->hgd_maxlen);
599 /* Lock newbus around set_report_descr call */
600 mtx_lock(&Giant);
601 error = hid_set_report_descr(sc->sc_dev, buf, hgd->hgd_maxlen);
602 mtx_unlock(&Giant);
603 HIDRAW_LOCAL_FREE(local_buf, buf);
604
605 /* Realloc hidraw input queue */
606 if (error == 0)
607 sc->sc_q = realloc(sc->sc_q,
608 sc->sc_rdesc->rdsize * HIDRAW_BUFFER_SIZE,
609 M_DEVBUF, M_ZERO | M_WAITOK);
610
611 /* Start interrupts again */
612 mtx_lock(&sc->sc_mtx);
613 sc->sc_state.quiet = false;
614 hidraw_unlock_queue(sc);
615 mtx_unlock(&sc->sc_mtx);
616 return (error);
617 case HIDRAW_SET_IMMED:
618 if (!(sc->sc_fflags & FREAD))
619 return (EPERM);
620 if (*(int *)addr) {
621 /* XXX should read into ibuf, but does it matter? */
622 size = sc->sc_rdesc->isize;
623 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
624 error = hid_get_report(sc->sc_dev, buf, size, NULL,
625 HID_INPUT_REPORT, sc->sc_rdesc->iid);
626 HIDRAW_LOCAL_FREE(local_buf, buf);
627 if (error)
628 return (EOPNOTSUPP);
629
630 mtx_lock(&sc->sc_mtx);
631 sc->sc_state.immed = true;
632 mtx_unlock(&sc->sc_mtx);
633 } else {
634 mtx_lock(&sc->sc_mtx);
635 sc->sc_state.immed = false;
636 mtx_unlock(&sc->sc_mtx);
637 }
638 return (0);
639
640 case HIDRAW_GET_REPORT:
641 if (!(sc->sc_fflags & FREAD))
642 return (EPERM);
643 hgd = (struct hidraw_gen_descriptor *)addr;
644 switch (hgd->hgd_report_type) {
645 case HID_INPUT_REPORT:
646 size = sc->sc_rdesc->isize;
647 id = sc->sc_rdesc->iid;
648 break;
649 case HID_OUTPUT_REPORT:
650 size = sc->sc_rdesc->osize;
651 id = sc->sc_rdesc->oid;
652 break;
653 case HID_FEATURE_REPORT:
654 size = sc->sc_rdesc->fsize;
655 id = sc->sc_rdesc->fid;
656 break;
657 default:
658 return (EINVAL);
659 }
660 if (id != 0)
661 copyin(hgd->hgd_data, &id, 1);
662 size = MIN(hgd->hgd_maxlen, size);
663 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
664 error = hid_get_report(sc->sc_dev, buf, size, NULL,
665 hgd->hgd_report_type, id);
666 if (!error)
667 error = copyout(buf, hgd->hgd_data, size);
668 HIDRAW_LOCAL_FREE(local_buf, buf);
669 return (error);
670
671 case HIDRAW_SET_REPORT:
672 if (!(sc->sc_fflags & FWRITE))
673 return (EPERM);
674 hgd = (struct hidraw_gen_descriptor *)addr;
675 switch (hgd->hgd_report_type) {
676 case HID_INPUT_REPORT:
677 size = sc->sc_rdesc->isize;
678 id = sc->sc_rdesc->iid;
679 break;
680 case HID_OUTPUT_REPORT:
681 size = sc->sc_rdesc->osize;
682 id = sc->sc_rdesc->oid;
683 break;
684 case HID_FEATURE_REPORT:
685 size = sc->sc_rdesc->fsize;
686 id = sc->sc_rdesc->fid;
687 break;
688 default:
689 return (EINVAL);
690 }
691 size = MIN(hgd->hgd_maxlen, size);
692 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
693 copyin(hgd->hgd_data, buf, size);
694 if (id != 0)
695 id = *(uint8_t *)buf;
696 error = hid_set_report(sc->sc_dev, buf, size,
697 hgd->hgd_report_type, id);
698 HIDRAW_LOCAL_FREE(local_buf, buf);
699 return (error);
700
701 case HIDRAW_GET_REPORT_ID:
702 *(int *)addr = 0; /* XXX: we only support reportid 0? */
703 return (0);
704
705 case HIDIOCGRDESCSIZE:
706 *(int *)addr = sc->sc_hw->rdescsize;
707 return (0);
708
709 case HIDIOCGRDESC:
710 hrd = *(struct hidraw_report_descriptor **)addr;
711 error = copyin(&hrd->size, &size, sizeof(uint32_t));
712 if (error)
713 return (error);
714 /*
715 * HID_MAX_DESCRIPTOR_SIZE-1 is a limit of report descriptor
716 * size in current Linux implementation.
717 */
718 if (size >= HID_MAX_DESCRIPTOR_SIZE)
719 return (EINVAL);
720 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
721 error = hid_get_rdesc(sc->sc_dev, buf, size);
722 if (error == 0) {
723 size = MIN(size, sc->sc_rdesc->len);
724 error = copyout(buf, hrd->value, size);
725 }
726 HIDRAW_LOCAL_FREE(local_buf, buf);
727 return (error);
728
729 case HIDIOCGRAWINFO:
730 hdi = (struct hidraw_devinfo *)addr;
731 hdi->bustype = sc->sc_hw->idBus;
732 hdi->vendor = sc->sc_hw->idVendor;
733 hdi->product = sc->sc_hw->idProduct;
734 return (0);
735 }
736
737 /* variable-length ioctls handling */
738 len = IOCPARM_LEN(cmd);
739 switch (IOCBASECMD(cmd)) {
740 case HIDIOCGRAWNAME(0):
741 strlcpy(addr, sc->sc_hw->name, len);
742 return (0);
743
744 case HIDIOCGRAWPHYS(0):
745 strlcpy(addr, device_get_nameunit(sc->sc_dev), len);
746 return (0);
747
748 case HIDIOCSFEATURE(0):
749 if (!(sc->sc_fflags & FWRITE))
750 return (EPERM);
751 if (len < 2)
752 return (EINVAL);
753 id = *(uint8_t *)addr;
754 if (id == 0) {
755 addr = (uint8_t *)addr + 1;
756 len--;
757 }
758 return (hid_set_report(sc->sc_dev, addr, len,
759 HID_FEATURE_REPORT, id));
760
761 case HIDIOCGFEATURE(0):
762 if (!(sc->sc_fflags & FREAD))
763 return (EPERM);
764 if (len < 2)
765 return (EINVAL);
766 id = *(uint8_t *)addr;
767 if (id == 0) {
768 addr = (uint8_t *)addr + 1;
769 len--;
770 }
771 return (hid_get_report(sc->sc_dev, addr, len, NULL,
772 HID_FEATURE_REPORT, id));
773
774 case HIDIOCGRAWUNIQ(0):
775 strlcpy(addr, sc->sc_hw->serial, len);
776 return (0);
777 }
778
779 return (EINVAL);
780 }
781
782 static int
783 hidraw_poll(struct cdev *dev, int events, struct thread *td)
784 {
785 struct hidraw_softc *sc;
786 int revents = 0;
787
788 sc = dev->si_drv1;
789 if (sc == NULL)
790 return (POLLHUP);
791
792 if (events & (POLLOUT | POLLWRNORM) && (sc->sc_fflags & FWRITE))
793 revents |= events & (POLLOUT | POLLWRNORM);
794 if (events & (POLLIN | POLLRDNORM) && (sc->sc_fflags & FREAD)) {
795 mtx_lock(&sc->sc_mtx);
796 if (sc->sc_head != sc->sc_tail)
797 revents |= events & (POLLIN | POLLRDNORM);
798 else {
799 sc->sc_state.sel = true;
800 selrecord(td, &sc->sc_rsel);
801 }
802 mtx_unlock(&sc->sc_mtx);
803 }
804
805 return (revents);
806 }
807
808 static int
809 hidraw_kqfilter(struct cdev *dev, struct knote *kn)
810 {
811 struct hidraw_softc *sc;
812
813 sc = dev->si_drv1;
814 if (sc == NULL)
815 return (ENXIO);
816
817 switch(kn->kn_filter) {
818 case EVFILT_READ:
819 if (sc->sc_fflags & FREAD) {
820 kn->kn_fop = &hidraw_filterops_read;
821 break;
822 }
823 /* FALLTHROUGH */
824 default:
825 return(EINVAL);
826 }
827 kn->kn_hook = sc;
828
829 knlist_add(&sc->sc_rsel.si_note, kn, 0);
830 return (0);
831 }
832
833 static int
834 hidraw_kqread(struct knote *kn, long hint)
835 {
836 struct hidraw_softc *sc;
837 int ret;
838
839 sc = kn->kn_hook;
840
841 mtx_assert(&sc->sc_mtx, MA_OWNED);
842
843 if (sc->dev->si_drv1 == NULL) {
844 kn->kn_flags |= EV_EOF;
845 ret = 1;
846 } else
847 ret = (sc->sc_head != sc->sc_tail) ? 1 : 0;
848
849 return (ret);
850 }
851
852 static void
853 hidraw_kqdetach(struct knote *kn)
854 {
855 struct hidraw_softc *sc;
856
857 sc = kn->kn_hook;
858 knlist_remove(&sc->sc_rsel.si_note, kn, 0);
859 }
860
861 static void
862 hidraw_notify(struct hidraw_softc *sc)
863 {
864
865 mtx_assert(&sc->sc_mtx, MA_OWNED);
866
867 if (sc->sc_state.aslp) {
868 sc->sc_state.aslp = false;
869 DPRINTFN(5, "waking %p\n", &sc->sc_q);
870 wakeup(&sc->sc_q);
871 }
872 if (sc->sc_state.sel) {
873 sc->sc_state.sel = false;
874 selwakeuppri(&sc->sc_rsel, PZERO);
875 }
876 if (sc->sc_async != NULL) {
877 DPRINTFN(3, "sending SIGIO %p\n", sc->sc_async);
878 PROC_LOCK(sc->sc_async);
879 kern_psignal(sc->sc_async, SIGIO);
880 PROC_UNLOCK(sc->sc_async);
881 }
882 KNOTE_LOCKED(&sc->sc_rsel.si_note, 0);
883 }
884
885 static device_method_t hidraw_methods[] = {
886 /* Device interface */
887 DEVMETHOD(device_identify, hidraw_identify),
888 DEVMETHOD(device_probe, hidraw_probe),
889 DEVMETHOD(device_attach, hidraw_attach),
890 DEVMETHOD(device_detach, hidraw_detach),
891
892 DEVMETHOD_END
893 };
894
895 static driver_t hidraw_driver = {
896 "hidraw",
897 hidraw_methods,
898 sizeof(struct hidraw_softc)
899 };
900
901 #ifndef HIDRAW_MAKE_UHID_ALIAS
902 devclass_t hidraw_devclass;
903 #endif
904
905 DRIVER_MODULE(hidraw, hidbus, hidraw_driver, hidraw_devclass, NULL, 0);
906 MODULE_DEPEND(hidraw, hidbus, 1, 1, 1);
907 MODULE_DEPEND(hidraw, hid, 1, 1, 1);
908 MODULE_DEPEND(hidraw, usb, 1, 1, 1);
909 MODULE_VERSION(hidraw, 1);
Cache object: a0e577f7c28c0bb3664b1c6ef2e59160
|