xref: /freebsd/sys/dev/usb/input/uhid_snes.c (revision 9e5787d2284e187abb5b654d924394a65772e004)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 2013, Michael Terrell <vashisnotatree@gmail.com>
5  * Copyright 2018, Johannes Lundberg <johalun0@gmail.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/module.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 
37 #include <sys/conf.h>
38 #include <sys/bus.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/syslog.h>
42 #include <sys/fcntl.h>
43 
44 #include <dev/usb/usb.h>
45 #include <dev/usb/usbdi.h>
46 #include <dev/usb/usbdi_util.h>
47 
48 #include <dev/usb/usbhid.h>
49 #include <dev/usb/usb_ioctl.h>
50 
51 #include "usb_rdesc.h"
52 
53 #define	UHID_SNES_IFQ_MAX_LEN 8
54 
55 #define	UREQ_GET_PORT_STATUS 0x01
56 #define	UREQ_SOFT_RESET      0x02
57 
58 #define	UP      0x7f00
59 #define	DOWN    0x7fff
60 #define	LEFT    0x00ff
61 #define	RIGHT   0xff7f
62 #define	X       0x1f
63 #define	Y       0x8f
64 #define	A       0x2f
65 #define	B       0x4f
66 #define	SELECT  0x10
67 #define	START   0x20
68 #define	LEFT_T  0x01
69 #define	RIGHT_T 0x02
70 
71 static const uint8_t uhid_snes_report_descr[] = { UHID_SNES_REPORT_DESCR() };
72 
73 #define	SNES_DEV(v,p,i) { USB_VPI(v,p,i) }
74 
75 static const STRUCT_USB_HOST_ID snes_devs[] = {
76 	SNES_DEV(0x0810, 0xe501, 0), /* GeeekPi K-0161 */
77 	SNES_DEV(0x0079, 0x0011, 0)  /* Dragonrise */
78 };
79 
80 enum {
81 	UHID_SNES_INTR_DT_RD,
82 	UHID_SNES_STATUS_DT_RD,
83 	UHID_SNES_N_TRANSFER
84 };
85 
86 struct uhid_snes_softc {
87 	device_t sc_dev;
88 	struct usb_device *sc_usb_device;
89 	struct mtx sc_mutex;
90 	struct usb_callout sc_watchdog;
91 	uint8_t sc_iface_num;
92 	struct usb_xfer *sc_transfer[UHID_SNES_N_TRANSFER];
93 	struct usb_fifo_sc sc_fifo;
94 	struct usb_fifo_sc sc_fifo_no_reset;
95 	int sc_fflags;
96 	struct usb_fifo *sc_fifo_open[2];
97 	uint8_t sc_zero_length_packets;
98 	uint8_t sc_previous_status;
99 	uint8_t sc_iid;
100 	uint8_t sc_oid;
101 	uint8_t sc_fid;
102 	uint8_t sc_iface_index;
103 
104 	uint32_t sc_isize;
105 	uint32_t sc_osize;
106 	uint32_t sc_fsize;
107 
108 	void *sc_repdesc_ptr;
109 
110 	uint16_t sc_repdesc_size;
111 
112 	struct usb_device *sc_udev;
113 #define	UHID_FLAG_IMMED        0x01	/* set if read should be immediate */
114 
115 };
116 
117 static device_probe_t uhid_snes_probe;
118 static device_attach_t uhid_snes_attach;
119 static device_detach_t uhid_snes_detach;
120 
121 static usb_fifo_open_t uhid_snes_open;
122 static usb_fifo_close_t uhid_snes_close;
123 static usb_fifo_ioctl_t uhid_snes_ioctl;
124 static usb_fifo_cmd_t uhid_snes_start_read;
125 static usb_fifo_cmd_t uhid_snes_stop_read;
126 
127 static void uhid_snes_reset(struct uhid_snes_softc *);
128 static void uhid_snes_watchdog(void *);
129 
130 static usb_callback_t uhid_snes_read_callback;
131 static usb_callback_t uhid_snes_status_callback;
132 
133 static struct usb_fifo_methods uhid_snes_fifo_methods = {
134 	.f_open = &uhid_snes_open,
135 	.f_close = &uhid_snes_close,
136 	.f_ioctl = &uhid_snes_ioctl,
137 	.f_start_read = &uhid_snes_start_read,
138 	.f_stop_read = &uhid_snes_stop_read,
139 	.basename[0] = "uhid_snes"
140 };
141 
142 static const struct usb_config uhid_snes_config[UHID_SNES_N_TRANSFER] = {
143 	[UHID_SNES_INTR_DT_RD] = {
144 		.callback = &uhid_snes_read_callback,
145 		.bufsize = sizeof(struct usb_device_request) +1,
146 		.flags = {.short_xfer_ok = 1, .short_frames_ok = 1,
147 			  .pipe_bof =1, .proxy_buffer =1},
148 		.type = UE_INTERRUPT,
149 		.endpoint = 0x81,
150 		.direction = UE_DIR_IN
151 	},
152 	[UHID_SNES_STATUS_DT_RD] = {
153 		.callback = &uhid_snes_status_callback,
154 		.bufsize = sizeof(struct usb_device_request) + 1,
155 		.timeout = 1000,
156 		.type = UE_CONTROL,
157 		.endpoint = 0x00,
158 		.direction = UE_DIR_ANY
159 	}
160 };
161 
162 static int
163 uhid_get_report(struct uhid_snes_softc *sc, uint8_t type,
164     uint8_t id, void *kern_data, void *user_data, uint16_t len)
165 {
166 	int err;
167 	uint8_t free_data = 0;
168 
169 	if (kern_data == NULL) {
170 		kern_data = malloc(len, M_USBDEV, M_WAITOK);
171 		free_data = 1;
172 	}
173 	err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
174 	    len, sc->sc_iface_index, type, id);
175 	if (err) {
176 		err = ENXIO;
177 		goto done;
178 	}
179 	if (user_data) {
180 		/* dummy buffer */
181 		err = copyout(kern_data, user_data, len);
182 		if (err) {
183 			goto done;
184 		}
185 	}
186 done:
187 	if (free_data) {
188 		free(kern_data, M_USBDEV);
189 	}
190 	return (err);
191 }
192 
193 static int
194 uhid_set_report(struct uhid_snes_softc *sc, uint8_t type,
195     uint8_t id, void *kern_data, void *user_data, uint16_t len)
196 {
197 	int err;
198 	uint8_t free_data = 0;
199 
200 	if (kern_data == NULL) {
201 		kern_data = malloc(len, M_USBDEV, M_WAITOK);
202 		free_data = 1;
203 		err = copyin(user_data, kern_data, len);
204 		if (err) {
205 			goto done;
206 		}
207 	}
208 	err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
209 	    len, sc->sc_iface_index, type, id);
210 	if (err) {
211 		err = ENXIO;
212 		goto done;
213 	}
214 done:
215 	if (free_data) {
216 		free(kern_data, M_USBDEV);
217 	}
218 	return (err);
219 }
220 
221 static int
222 uhid_snes_open(struct usb_fifo *fifo, int fflags)
223 {
224 	struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
225 	int error;
226 
227 	if (sc->sc_fflags & fflags) {
228 		uhid_snes_reset(sc);
229 		return (EBUSY);
230 	}
231 
232 	mtx_lock(&sc->sc_mutex);
233 	usbd_xfer_set_stall(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
234 	mtx_unlock(&sc->sc_mutex);
235 
236 	error = usb_fifo_alloc_buffer(fifo,
237 	    usbd_xfer_max_len(sc->sc_transfer[UHID_SNES_INTR_DT_RD]),
238 	    UHID_SNES_IFQ_MAX_LEN);
239 	if (error)
240 		return (ENOMEM);
241 
242 	sc->sc_fifo_open[USB_FIFO_RX] = fifo;
243 
244 	return (0);
245 }
246 
247 static void
248 uhid_snes_reset(struct uhid_snes_softc *sc)
249 {
250 	struct usb_device_request req;
251 	int error;
252 
253 	req.bRequest = UREQ_SOFT_RESET;
254 	USETW(req.wValue, 0);
255 	USETW(req.wIndex, sc->sc_iface_num);
256 	USETW(req.wLength, 0);
257 
258 	mtx_lock(&sc->sc_mutex);
259 
260 	error = usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
261 	    &req, NULL, 0, NULL, 2 * USB_MS_HZ);
262 
263 	if (error) {
264 		usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
265 		    &req, NULL, 0, NULL, 2 * USB_MS_HZ);
266 	}
267 
268 	mtx_unlock(&sc->sc_mutex);
269 }
270 
271 static void
272 uhid_snes_close(struct usb_fifo *fifo, int fflags)
273 {
274 	struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
275 
276 	sc->sc_fflags &= ~(fflags & FREAD);
277 	usb_fifo_free_buffer(fifo);
278 }
279 
280 static int
281 uhid_snes_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, int fflags)
282 {
283 	struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
284 	struct usb_gen_descriptor *ugd;
285 	uint32_t size;
286 	int error = 0;
287 	uint8_t id;
288 
289 	switch (cmd) {
290 	case USB_GET_REPORT_DESC:
291 		ugd = data;
292 		if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
293 			size = ugd->ugd_maxlen;
294 		} else {
295 			size = sc->sc_repdesc_size;
296 		}
297 
298 		ugd->ugd_actlen = size;
299 		if (ugd->ugd_data == NULL)
300 			break; /*desciptor length only*/
301 		error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
302 		break;
303 
304 	case USB_SET_IMMED:
305 		if (!(fflags & FREAD)) {
306 			error = EPERM;
307 			break;
308 		}
309 
310 		if (*(int *)data) {
311 			/* do a test read */
312 			error = uhid_get_report(sc, UHID_INPUT_REPORT,
313 			    sc->sc_iid, NULL, NULL, sc->sc_isize);
314 			if (error) {
315 				break;
316 			}
317 			mtx_lock(&sc->sc_mutex);
318 			sc->sc_fflags |= UHID_FLAG_IMMED;
319 			mtx_unlock(&sc->sc_mutex);
320 		} else {
321 			mtx_lock(&sc->sc_mutex);
322 			sc->sc_fflags &= ~UHID_FLAG_IMMED;
323 			mtx_unlock(&sc->sc_mutex);
324 		}
325 		break;
326 
327 	case USB_GET_REPORT:
328 		if (!(fflags & FREAD)) {
329 			error = EPERM;
330 			break;
331 		}
332 		ugd = data;
333 		switch (ugd->ugd_report_type) {
334 		case UHID_INPUT_REPORT:
335 			size = sc->sc_isize;
336 			id = sc->sc_iid;
337 			break;
338 		case UHID_OUTPUT_REPORT:
339 			size = sc->sc_osize;
340 			id = sc->sc_oid;
341 			break;
342 		case UHID_FEATURE_REPORT:
343 			size = sc->sc_fsize;
344 			id = sc->sc_fid;
345 			break;
346 		default:
347 			return (EINVAL);
348 		}
349 		if (id != 0)
350 			copyin(ugd->ugd_data, &id, 1);
351 		error = uhid_get_report(sc, ugd->ugd_report_type, id,
352 		    NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
353 		break;
354 
355 	case USB_SET_REPORT:
356 		if (!(fflags & FWRITE)) {
357 			error = EPERM;
358 			break;
359 		}
360 		ugd = data;
361 		switch (ugd->ugd_report_type) {
362 		case UHID_INPUT_REPORT:
363 			size = sc->sc_isize;
364 			id = sc->sc_iid;
365 			break;
366 		case UHID_OUTPUT_REPORT:
367 			size = sc->sc_osize;
368 			id = sc->sc_oid;
369 			break;
370 		case UHID_FEATURE_REPORT:
371 			size = sc->sc_fsize;
372 			id = sc->sc_fid;
373 			break;
374 		default:
375 			return (EINVAL);
376 		}
377 		if (id != 0)
378 			copyin(ugd->ugd_data, &id, 1);
379 		error = uhid_set_report(sc, ugd->ugd_report_type, id,
380 		    NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
381 		break;
382 
383 	case USB_GET_REPORT_ID:
384 		/* XXX: we only support reportid 0? */
385 		*(int *)data = 0;
386 		break;
387 
388 	default:
389 		error = EINVAL;
390 		break;
391 	}
392 	return (error);
393 }
394 
395 static void
396 uhid_snes_watchdog(void *arg)
397 {
398 	struct uhid_snes_softc *sc = arg;
399 
400 	mtx_assert(&sc->sc_mutex, MA_OWNED);
401 
402 	if (sc->sc_fflags == 0)
403 		usbd_transfer_start(sc->sc_transfer[UHID_SNES_STATUS_DT_RD]);
404 
405 	usb_callout_reset(&sc->sc_watchdog, hz, &uhid_snes_watchdog, sc);
406 }
407 
408 static void
409 uhid_snes_start_read(struct usb_fifo *fifo)
410 {
411 	struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
412 
413 	usbd_transfer_start(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
414 }
415 
416 static void
417 uhid_snes_stop_read(struct usb_fifo *fifo)
418 {
419 	struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
420 
421 	usbd_transfer_stop(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
422 }
423 
424 static void
425 uhid_snes_read_callback(struct usb_xfer *transfer, usb_error_t error)
426 {
427 	struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
428 	struct usb_fifo *fifo = sc->sc_fifo_open[USB_FIFO_RX];
429 	struct usb_page_cache *pc;
430 	int actual, max;
431 
432 	usbd_xfer_status(transfer, &actual, NULL, NULL, NULL);
433 	if (fifo == NULL)
434 		return;
435 
436 	switch (USB_GET_STATE(transfer)) {
437 	case USB_ST_TRANSFERRED:
438 		if (actual == 0) {
439 			if (sc->sc_zero_length_packets == 4)
440 				/* Throttle transfers. */
441 				usbd_xfer_set_interval(transfer, 500);
442 			else
443 				sc->sc_zero_length_packets++;
444 
445 		} else {
446 			/* disable throttling. */
447 			usbd_xfer_set_interval(transfer, 0);
448 			sc->sc_zero_length_packets = 0;
449 		}
450 		pc = usbd_xfer_get_frame(transfer, 0);
451 		usb_fifo_put_data(fifo, pc, 0, actual, 1);
452 		/* Fall through */
453 	setup:
454 	case USB_ST_SETUP:
455 		if (usb_fifo_put_bytes_max(fifo) != 0) {
456 			max = usbd_xfer_max_len(transfer);
457 			usbd_xfer_set_frame_len(transfer, 0, max);
458 			usbd_transfer_submit(transfer);
459 		}
460 		break;
461 
462 	default:
463 		/*disable throttling. */
464 		usbd_xfer_set_interval(transfer, 0);
465 		sc->sc_zero_length_packets = 0;
466 
467 		if (error != USB_ERR_CANCELLED) {
468 			/* Issue a clear-stall request. */
469 			usbd_xfer_set_stall(transfer);
470 			goto setup;
471 		}
472 		break;
473 	}
474 }
475 
476 static void
477 uhid_snes_status_callback(struct usb_xfer *transfer, usb_error_t error)
478 {
479 	struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
480 	struct usb_device_request req;
481 	struct usb_page_cache *pc;
482 	uint8_t current_status, new_status;
483 
484 	switch (USB_GET_STATE(transfer)) {
485 	case USB_ST_SETUP:
486 		req.bmRequestType = UT_READ_CLASS_INTERFACE;
487 		req.bRequest = UREQ_GET_PORT_STATUS;
488 		USETW(req.wValue, 0);
489 		req.wIndex[0] = sc->sc_iface_num;
490 		req.wIndex[1] = 0;
491 		USETW(req.wLength, 1);
492 
493 		pc = usbd_xfer_get_frame(transfer, 0);
494 		usbd_copy_in(pc, 0, &req, sizeof(req));
495 		usbd_xfer_set_frame_len(transfer, 0, sizeof(req));
496 		usbd_xfer_set_frame_len(transfer, 1, 1);
497 		usbd_xfer_set_frames(transfer, 2);
498 		usbd_transfer_submit(transfer);
499 		break;
500 
501 	case USB_ST_TRANSFERRED:
502 		pc = usbd_xfer_get_frame(transfer, 1);
503 		usbd_copy_out(pc, 0, &current_status, 1);
504 		new_status = current_status & ~sc->sc_previous_status;
505 		sc->sc_previous_status = current_status;
506 		break;
507 
508 	default:
509 		break;
510 	}
511 
512 }
513 
514 static int
515 uhid_snes_probe(device_t dev)
516 {
517 	struct usb_attach_arg *uaa = device_get_ivars(dev);
518 
519 	if (uaa->usb_mode != USB_MODE_HOST)
520 		return (ENXIO);
521 
522 	return (usbd_lookup_id_by_uaa(snes_devs, sizeof(snes_devs), uaa));
523 }
524 
525 static int
526 uhid_snes_attach(device_t dev)
527 {
528 	struct usb_attach_arg *uaa = device_get_ivars(dev);
529 	struct uhid_snes_softc *sc = device_get_softc(dev);
530 	struct usb_interface_descriptor *idesc;
531 	struct usb_config_descriptor *cdesc;
532 	uint8_t alt_index, iface_index = uaa->info.bIfaceIndex;
533 	int error,unit = device_get_unit(dev);
534 
535 	sc->sc_dev = dev;
536 	sc->sc_usb_device = uaa->device;
537 	device_set_usb_desc(dev);
538 	mtx_init(&sc->sc_mutex, "uhid_snes", NULL, MTX_DEF | MTX_RECURSE);
539 	usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mutex, 0);
540 
541 	idesc = usbd_get_interface_descriptor(uaa->iface);
542 	alt_index = -1;
543 	for(;;) {
544 		if (idesc == NULL)
545 			break;
546 
547 		if ((idesc->bDescriptorType == UDESC_INTERFACE) &&
548 		     (idesc->bLength >= sizeof(*idesc))) {
549 			if (idesc->bInterfaceNumber != uaa->info.bIfaceNum) {
550 				break;
551 			} else {
552 				alt_index++;
553 				if (idesc->bInterfaceClass == UICLASS_HID)
554 					goto found;
555 			}
556 		}
557 
558 		cdesc = usbd_get_config_descriptor(uaa->device);
559 		idesc = (void *)usb_desc_foreach(cdesc, (void *)idesc);
560 		goto found;
561 	}
562 	goto detach;
563 
564 found:
565 	if (alt_index) {
566 		error = usbd_set_alt_interface_index(uaa->device, iface_index, alt_index);
567 		if (error)
568 			goto detach;
569 	}
570 
571 	sc->sc_iface_num = idesc->bInterfaceNumber;
572 
573 	error = usbd_transfer_setup(uaa->device, &iface_index,
574 	    sc->sc_transfer, uhid_snes_config, UHID_SNES_N_TRANSFER, sc,
575 	    &sc->sc_mutex);
576 
577 	if (error)
578 		goto detach;
579 
580 	error = usb_fifo_attach(uaa->device, sc, &sc->sc_mutex,
581 	    &uhid_snes_fifo_methods, &sc->sc_fifo, unit, -1,
582 	    iface_index, UID_ROOT, GID_OPERATOR, 0644);
583 	sc->sc_repdesc_size = sizeof(uhid_snes_report_descr);
584 	sc->sc_repdesc_ptr = __DECONST(void*, &uhid_snes_report_descr);
585 
586 
587 	if (error)
588 		goto detach;
589 
590 	mtx_lock(&sc->sc_mutex);
591 	uhid_snes_watchdog(sc);
592 	mtx_unlock(&sc->sc_mutex);
593 	return (0);
594 
595 detach:
596 	uhid_snes_detach(dev);
597 	return (ENOMEM);
598 }
599 
600 static int
601 uhid_snes_detach(device_t dev)
602 {
603 	struct uhid_snes_softc *sc = device_get_softc(dev);
604 
605 	usb_fifo_detach(&sc->sc_fifo);
606 	usb_fifo_detach(&sc->sc_fifo_no_reset);
607 
608 	mtx_lock(&sc->sc_mutex);
609 	usb_callout_stop(&sc->sc_watchdog);
610 	mtx_unlock(&sc->sc_mutex);
611 
612 	usbd_transfer_unsetup(sc->sc_transfer, UHID_SNES_N_TRANSFER);
613 	usb_callout_drain(&sc->sc_watchdog);
614 	mtx_destroy(&sc->sc_mutex);
615 
616 	return (0);
617 }
618 
619 static device_method_t uhid_snes_methods[] = {
620 	DEVMETHOD(device_probe, uhid_snes_probe),
621 	DEVMETHOD(device_attach, uhid_snes_attach),
622 	DEVMETHOD(device_detach, uhid_snes_detach),
623 	DEVMETHOD_END
624 };
625 
626 static driver_t uhid_snes_driver = {
627 	"uhid_snes",
628 	uhid_snes_methods,
629 	sizeof(struct uhid_snes_softc)
630 };
631 
632 static devclass_t uhid_snes_devclass;
633 
634 DRIVER_MODULE(uhid_snes, uhub, uhid_snes_driver, uhid_snes_devclass, NULL, 0);
635 MODULE_DEPEND(uhid_snes, usb, 1, 1, 1);
636 USB_PNP_HOST_INFO(snes_devs);
637