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