xref: /openbsd-src/sys/dev/usb/uhid.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: uhid.c,v 1.77 2020/02/20 16:56:52 visa Exp $ */
2 /*	$NetBSD: uhid.c,v 1.57 2003/03/11 16:44:00 augustss Exp $	*/
3 
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
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 "fido.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/signalvar.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/conf.h>
48 #include <sys/tty.h>
49 #include <sys/selinfo.h>
50 #include <sys/proc.h>
51 #include <sys/vnode.h>
52 #include <sys/poll.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 
61 #include <dev/usb/uhidev.h>
62 #include <dev/usb/uhid.h>
63 
64 #ifdef UHID_DEBUG
65 #define DPRINTF(x)	do { if (uhiddebug) printf x; } while (0)
66 #define DPRINTFN(n,x)	do { if (uhiddebug>(n)) printf x; } while (0)
67 int	uhiddebug = 0;
68 #else
69 #define DPRINTF(x)
70 #define DPRINTFN(n,x)
71 #endif
72 
73 int uhid_match(struct device *, void *, void *);
74 
75 struct cfdriver uhid_cd = {
76 	NULL, "uhid", DV_DULL
77 };
78 
79 const struct cfattach uhid_ca = {
80 	sizeof(struct uhid_softc),
81 	uhid_match,
82 	uhid_attach,
83 	uhid_detach,
84 };
85 
86 struct uhid_softc *
87 uhid_lookup(dev_t dev)
88 {
89 	struct uhid_softc *sc = NULL;
90 	struct cdevsw *cdev;
91 	struct cfdriver *cd;
92 
93 	cdev = &cdevsw[major(dev)];
94 	if (cdev->d_open == uhidopen)
95 		cd = &uhid_cd;
96 #if NFIDO > 0
97 	else if (cdev->d_open == fidoopen)
98 		cd = &fido_cd;
99 #endif
100 	else
101 		return (NULL);
102 	if (UHIDUNIT(dev) < cd->cd_ndevs)
103 		sc = cd->cd_devs[UHIDUNIT(dev)];
104 
105 	return (sc);
106 }
107 
108 int
109 uhid_match(struct device *parent, void *match, void *aux)
110 {
111 	struct uhidev_attach_arg *uha = aux;
112 
113 	if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
114 		return (UMATCH_NONE);
115 
116 	return (UMATCH_IFACECLASS_GENERIC);
117 }
118 
119 void
120 uhid_attach(struct device *parent, struct device *self, void *aux)
121 {
122 	struct uhid_softc *sc = (struct uhid_softc *)self;
123 	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
124 	int size, repid;
125 	void *desc;
126 
127 	sc->sc_hdev.sc_intr = uhid_intr;
128 	sc->sc_hdev.sc_parent = uha->parent;
129 	sc->sc_hdev.sc_udev = uha->uaa->device;
130 	sc->sc_hdev.sc_report_id = uha->reportid;
131 
132 	uhidev_get_report_desc(uha->parent, &desc, &size);
133 	repid = uha->reportid;
134 	sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
135 	sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
136 	sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
137 
138 	printf(": input=%d, output=%d, feature=%d\n",
139 	    sc->sc_hdev.sc_isize, sc->sc_hdev.sc_osize, sc->sc_hdev.sc_fsize);
140 }
141 
142 int
143 uhid_detach(struct device *self, int flags)
144 {
145 	struct uhid_softc *sc = (struct uhid_softc *)self;
146 	int s;
147 	int maj, mn;
148 
149 	DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
150 
151 	if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
152 		s = splusb();
153 		if (--sc->sc_refcnt >= 0) {
154 			/* Wake everyone */
155 			wakeup(&sc->sc_q);
156 			/* Wait for processes to go away. */
157 			usb_detach_wait(&sc->sc_hdev.sc_dev);
158 		}
159 		splx(s);
160 	}
161 
162 	/* locate the major number */
163 	for (maj = 0; maj < nchrdev; maj++)
164 		if (cdevsw[maj].d_open == uhidopen)
165 			break;
166 
167 	/* Nuke the vnodes for any open instances (calls close). */
168 	mn = self->dv_unit;
169 	vdevgone(maj, mn, mn, VCHR);
170 
171 	s = splusb();
172 	klist_invalidate(&sc->sc_rsel.si_note);
173 	splx(s);
174 
175 	return (0);
176 }
177 
178 void
179 uhid_intr(struct uhidev *addr, void *data, u_int len)
180 {
181 	struct uhid_softc *sc = (struct uhid_softc *)addr;
182 
183 #ifdef UHID_DEBUG
184 	if (uhiddebug > 5) {
185 		u_int32_t i;
186 
187 		DPRINTF(("uhid_intr: data ="));
188 		for (i = 0; i < len; i++)
189 			DPRINTF((" %02x", ((u_char *)data)[i]));
190 		DPRINTF(("\n"));
191 	}
192 #endif
193 
194 	(void)b_to_q(data, len, &sc->sc_q);
195 
196 	if (sc->sc_state & UHID_ASLP) {
197 		sc->sc_state &= ~UHID_ASLP;
198 		DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
199 		wakeup(&sc->sc_q);
200 	}
201 	selwakeup(&sc->sc_rsel);
202 }
203 
204 int
205 uhidopen(dev_t dev, int flag, int mode, struct proc *p)
206 {
207 	return (uhid_do_open(dev, flag, mode, p));
208 }
209 
210 int
211 uhid_do_open(dev_t dev, int flag, int mode, struct proc *p)
212 {
213 	struct uhid_softc *sc;
214 	int error;
215 
216 	if ((sc = uhid_lookup(dev)) == NULL)
217 		return (ENXIO);
218 
219 	DPRINTF(("uhidopen: sc=%p\n", sc));
220 
221 	if (usbd_is_dying(sc->sc_hdev.sc_udev))
222 		return (ENXIO);
223 
224 	error = uhidev_open(&sc->sc_hdev);
225 	if (error)
226 		return (error);
227 
228 	clalloc(&sc->sc_q, UHID_BSIZE, 0);
229 
230 	sc->sc_obuf = malloc(sc->sc_hdev.sc_osize, M_USBDEV, M_WAITOK);
231 
232 	return (0);
233 }
234 
235 int
236 uhidclose(dev_t dev, int flag, int mode, struct proc *p)
237 {
238 	struct uhid_softc *sc;
239 
240 	if ((sc = uhid_lookup(dev)) == NULL)
241 		return (ENXIO);
242 
243 	DPRINTF(("uhidclose: sc=%p\n", sc));
244 
245 	clfree(&sc->sc_q);
246 	free(sc->sc_obuf, M_USBDEV, sc->sc_hdev.sc_osize);
247 	uhidev_close(&sc->sc_hdev);
248 
249 	return (0);
250 }
251 
252 int
253 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
254 {
255 	int s;
256 	int error = 0;
257 	size_t length;
258 	u_char buffer[UHID_CHUNK];
259 
260 	DPRINTFN(1, ("uhidread\n"));
261 
262 	s = splusb();
263 	while (sc->sc_q.c_cc == 0) {
264 		if (flag & IO_NDELAY) {
265 			splx(s);
266 			return (EWOULDBLOCK);
267 		}
268 		sc->sc_state |= UHID_ASLP;
269 		DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
270 		error = tsleep_nsec(&sc->sc_q, PZERO|PCATCH, "uhidrea", INFSLP);
271 		DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
272 		if (usbd_is_dying(sc->sc_hdev.sc_udev))
273 			error = EIO;
274 		if (error) {
275 			sc->sc_state &= ~UHID_ASLP;
276 			break;
277 		}
278 	}
279 	splx(s);
280 
281 	/* Transfer as many chunks as possible. */
282 	while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
283 		length = ulmin(sc->sc_q.c_cc, uio->uio_resid);
284 		if (length > sizeof(buffer))
285 			length = sizeof(buffer);
286 
287 		/* Remove a small chunk from the input queue. */
288 		(void) q_to_b(&sc->sc_q, buffer, length);
289 		DPRINTFN(5, ("uhidread: got %zu chars\n", length));
290 
291 		/* Copy the data to the user process. */
292 		if ((error = uiomove(buffer, length, uio)) != 0)
293 			break;
294 	}
295 
296 	return (error);
297 }
298 
299 int
300 uhidread(dev_t dev, struct uio *uio, int flag)
301 {
302 	struct uhid_softc *sc;
303 	int error;
304 
305 	if ((sc = uhid_lookup(dev)) == NULL)
306 		return (ENXIO);
307 
308 	sc->sc_refcnt++;
309 	error = uhid_do_read(sc, uio, flag);
310 	if (--sc->sc_refcnt < 0)
311 		usb_detach_wakeup(&sc->sc_hdev.sc_dev);
312 	return (error);
313 }
314 
315 int
316 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
317 {
318 	int error;
319 	int size;
320 
321 	DPRINTFN(1, ("uhidwrite\n"));
322 
323 	if (usbd_is_dying(sc->sc_hdev.sc_udev))
324 		return (EIO);
325 
326 	size = sc->sc_hdev.sc_osize;
327 	error = 0;
328 	if (uio->uio_resid > size)
329 		return (EMSGSIZE);
330 	else if (uio->uio_resid < size) {
331 		/* don't leak kernel memory to the USB device */
332 		memset(sc->sc_obuf + uio->uio_resid, 0, size - uio->uio_resid);
333 	}
334 	error = uiomove(sc->sc_obuf, uio->uio_resid, uio);
335 	if (!error) {
336 		if (uhidev_set_report(sc->sc_hdev.sc_parent,
337 		    UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, sc->sc_obuf,
338 		    size) != size)
339 			error = EIO;
340 	}
341 
342 	return (error);
343 }
344 
345 int
346 uhidwrite(dev_t dev, struct uio *uio, int flag)
347 {
348 	struct uhid_softc *sc;
349 	int error;
350 
351 	if ((sc = uhid_lookup(dev)) == NULL)
352 		return (ENXIO);
353 
354 	sc->sc_refcnt++;
355 	error = uhid_do_write(sc, uio, flag);
356 	if (--sc->sc_refcnt < 0)
357 		usb_detach_wakeup(&sc->sc_hdev.sc_dev);
358 	return (error);
359 }
360 
361 int
362 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
363 	      int flag, struct proc *p)
364 {
365 	int rc;
366 
367 	DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
368 
369 	if (usbd_is_dying(sc->sc_hdev.sc_udev))
370 		return (EIO);
371 
372 	switch (cmd) {
373 	case FIONBIO:
374 	case FIOASYNC:
375 		/* All handled in the upper FS layer. */
376 		break;
377 
378 	case USB_GET_DEVICEINFO:
379 		usbd_fill_deviceinfo(sc->sc_hdev.sc_udev,
380 				     (struct usb_device_info *)addr);
381 		break;
382 
383 	case USB_GET_REPORT_DESC:
384 	case USB_GET_REPORT:
385 	case USB_SET_REPORT:
386 	case USB_GET_REPORT_ID:
387 	default:
388 		rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p);
389 		if (rc == -1)
390 			rc = EINVAL;
391 		return rc;
392 	}
393 	return (0);
394 }
395 
396 int
397 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
398 {
399 	struct uhid_softc *sc;
400 	int error;
401 
402 	if ((sc = uhid_lookup(dev)) == NULL)
403 		return (ENXIO);
404 
405 	sc->sc_refcnt++;
406 	error = uhid_do_ioctl(sc, cmd, addr, flag, p);
407 	if (--sc->sc_refcnt < 0)
408 		usb_detach_wakeup(&sc->sc_hdev.sc_dev);
409 	return (error);
410 }
411 
412 int
413 uhidpoll(dev_t dev, int events, struct proc *p)
414 {
415 	struct uhid_softc *sc;
416 	int revents = 0;
417 	int s;
418 
419 	if ((sc = uhid_lookup(dev)) == NULL)
420 		return (POLLERR);
421 
422 	if (usbd_is_dying(sc->sc_hdev.sc_udev))
423 		return (POLLHUP);
424 
425 	s = splusb();
426 	if (events & (POLLOUT | POLLWRNORM))
427 		revents |= events & (POLLOUT | POLLWRNORM);
428 	if (events & (POLLIN | POLLRDNORM)) {
429 		if (sc->sc_q.c_cc > 0)
430 			revents |= events & (POLLIN | POLLRDNORM);
431 		else
432 			selrecord(p, &sc->sc_rsel);
433 	}
434 
435 	splx(s);
436 	return (revents);
437 }
438 
439 void filt_uhidrdetach(struct knote *);
440 int filt_uhidread(struct knote *, long);
441 int uhidkqfilter(dev_t, struct knote *);
442 
443 void
444 filt_uhidrdetach(struct knote *kn)
445 {
446 	struct uhid_softc *sc = (void *)kn->kn_hook;
447 	int s;
448 
449 	s = splusb();
450 	SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext);
451 	splx(s);
452 }
453 
454 int
455 filt_uhidread(struct knote *kn, long hint)
456 {
457 	struct uhid_softc *sc = (void *)kn->kn_hook;
458 
459 	kn->kn_data = sc->sc_q.c_cc;
460 	return (kn->kn_data > 0);
461 }
462 
463 const struct filterops uhidread_filtops = {
464 	.f_flags	= FILTEROP_ISFD,
465 	.f_attach	= NULL,
466 	.f_detach	= filt_uhidrdetach,
467 	.f_event	= filt_uhidread,
468 };
469 
470 const struct filterops uhid_seltrue_filtops = {
471 	.f_flags	= FILTEROP_ISFD,
472 	.f_attach	= NULL,
473 	.f_detach	= filt_uhidrdetach,
474 	.f_event	= filt_seltrue,
475 };
476 
477 int
478 uhidkqfilter(dev_t dev, struct knote *kn)
479 {
480 	struct uhid_softc *sc;
481 	struct klist *klist;
482 	int s;
483 
484 	if ((sc = uhid_lookup(dev)) == NULL)
485 		return (ENXIO);
486 
487 	if (usbd_is_dying(sc->sc_hdev.sc_udev))
488 		return (EIO);
489 
490 	switch (kn->kn_filter) {
491 	case EVFILT_READ:
492 		klist = &sc->sc_rsel.si_note;
493 		kn->kn_fop = &uhidread_filtops;
494 		break;
495 
496 	case EVFILT_WRITE:
497 		klist = &sc->sc_rsel.si_note;
498 		kn->kn_fop = &uhid_seltrue_filtops;
499 		break;
500 
501 	default:
502 		return (EINVAL);
503 	}
504 
505 	kn->kn_hook = (void *)sc;
506 
507 	s = splusb();
508 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
509 	splx(s);
510 
511 	return (0);
512 }
513