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