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 #define SNES_DEV(v,p,i) { USB_VPI(v,p,i) }
73
74 static const STRUCT_USB_HOST_ID snes_devs[] = {
75 SNES_DEV(0x0810, 0xe501, 0), /* GeeekPi K-0161 */
76 SNES_DEV(0x0079, 0x0011, 0) /* Dragonrise */
77 };
78
79 enum {
80 UHID_SNES_INTR_DT_RD,
81 UHID_SNES_STATUS_DT_RD,
82 UHID_SNES_N_TRANSFER
83 };
84
85 struct uhid_snes_softc {
86 device_t sc_dev;
87 struct usb_device *sc_usb_device;
88 struct mtx sc_mutex;
89 struct usb_callout sc_watchdog;
90 uint8_t sc_iface_num;
91 struct usb_xfer *sc_transfer[UHID_SNES_N_TRANSFER];
92 struct usb_fifo_sc sc_fifo;
93 struct usb_fifo_sc sc_fifo_no_reset;
94 int sc_fflags;
95 struct usb_fifo *sc_fifo_open[2];
96 uint8_t sc_zero_length_packets;
97 uint8_t sc_iid;
98 uint8_t sc_oid;
99 uint8_t sc_fid;
100 uint8_t sc_iface_index;
101
102 uint32_t sc_isize;
103 uint32_t sc_osize;
104 uint32_t sc_fsize;
105
106 void *sc_repdesc_ptr;
107
108 uint16_t sc_repdesc_size;
109
110 struct usb_device *sc_udev;
111 #define UHID_FLAG_IMMED 0x01 /* set if read should be immediate */
112
113 };
114
115 static device_probe_t uhid_snes_probe;
116 static device_attach_t uhid_snes_attach;
117 static device_detach_t uhid_snes_detach;
118
119 static usb_fifo_open_t uhid_snes_open;
120 static usb_fifo_close_t uhid_snes_close;
121 static usb_fifo_ioctl_t uhid_snes_ioctl;
122 static usb_fifo_cmd_t uhid_snes_start_read;
123 static usb_fifo_cmd_t uhid_snes_stop_read;
124
125 static void uhid_snes_reset(struct uhid_snes_softc *);
126 static void uhid_snes_watchdog(void *);
127
128 static usb_callback_t uhid_snes_read_callback;
129 static usb_callback_t uhid_snes_status_callback;
130
131 static struct usb_fifo_methods uhid_snes_fifo_methods = {
132 .f_open = &uhid_snes_open,
133 .f_close = &uhid_snes_close,
134 .f_ioctl = &uhid_snes_ioctl,
135 .f_start_read = &uhid_snes_start_read,
136 .f_stop_read = &uhid_snes_stop_read,
137 .basename[0] = "uhid_snes"
138 };
139
140 static const struct usb_config uhid_snes_config[UHID_SNES_N_TRANSFER] = {
141 [UHID_SNES_INTR_DT_RD] = {
142 .callback = &uhid_snes_read_callback,
143 .bufsize = sizeof(struct usb_device_request) +1,
144 .flags = {.short_xfer_ok = 1, .short_frames_ok = 1,
145 .pipe_bof =1, .proxy_buffer =1},
146 .type = UE_INTERRUPT,
147 .endpoint = 0x81,
148 .direction = UE_DIR_IN
149 },
150 [UHID_SNES_STATUS_DT_RD] = {
151 .callback = &uhid_snes_status_callback,
152 .bufsize = sizeof(struct usb_device_request) + 1,
153 .timeout = 1000,
154 .type = UE_CONTROL,
155 .endpoint = 0x00,
156 .direction = UE_DIR_ANY
157 }
158 };
159
160 static int
161 uhid_get_report(struct uhid_snes_softc *sc, uint8_t type,
162 uint8_t id, void *kern_data, void *user_data, uint16_t len)
163 {
164 int err;
165 uint8_t free_data = 0;
166
167 if (kern_data == NULL) {
168 kern_data = malloc(len, M_USBDEV, M_WAITOK);
169 free_data = 1;
170 }
171 err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
172 len, sc->sc_iface_index, type, id);
173 if (err) {
174 err = ENXIO;
175 goto done;
176 }
177 if (user_data) {
178 /* dummy buffer */
179 err = copyout(kern_data, user_data, len);
180 if (err) {
181 goto done;
182 }
183 }
184 done:
185 if (free_data) {
186 free(kern_data, M_USBDEV);
187 }
188 return (err);
189 }
190
191 static int
192 uhid_set_report(struct uhid_snes_softc *sc, uint8_t type,
193 uint8_t id, void *kern_data, void *user_data, uint16_t len)
194 {
195 int err;
196 uint8_t free_data = 0;
197
198 if (kern_data == NULL) {
199 kern_data = malloc(len, M_USBDEV, M_WAITOK);
200 free_data = 1;
201 err = copyin(user_data, kern_data, len);
202 if (err) {
203 goto done;
204 }
205 }
206 err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
207 len, sc->sc_iface_index, type, id);
208 if (err) {
209 err = ENXIO;
210 goto done;
211 }
212 done:
213 if (free_data) {
214 free(kern_data, M_USBDEV);
215 }
216 return (err);
217 }
218
219 static int
220 uhid_snes_open(struct usb_fifo *fifo, int fflags)
221 {
222 struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
223 int error;
224
225 if (sc->sc_fflags & fflags) {
226 uhid_snes_reset(sc);
227 return (EBUSY);
228 }
229
230 mtx_lock(&sc->sc_mutex);
231 usbd_xfer_set_stall(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
232 mtx_unlock(&sc->sc_mutex);
233
234 error = usb_fifo_alloc_buffer(fifo,
235 usbd_xfer_max_len(sc->sc_transfer[UHID_SNES_INTR_DT_RD]),
236 UHID_SNES_IFQ_MAX_LEN);
237 if (error)
238 return (ENOMEM);
239
240 sc->sc_fifo_open[USB_FIFO_RX] = fifo;
241
242 return (0);
243 }
244
245 static void
246 uhid_snes_reset(struct uhid_snes_softc *sc)
247 {
248 struct usb_device_request req;
249 int error;
250
251 req.bRequest = UREQ_SOFT_RESET;
252 USETW(req.wValue, 0);
253 USETW(req.wIndex, sc->sc_iface_num);
254 USETW(req.wLength, 0);
255
256 mtx_lock(&sc->sc_mutex);
257
258 error = usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
259 &req, NULL, 0, NULL, 2 * USB_MS_HZ);
260
261 if (error) {
262 usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
263 &req, NULL, 0, NULL, 2 * USB_MS_HZ);
264 }
265
266 mtx_unlock(&sc->sc_mutex);
267 }
268
269 static void
270 uhid_snes_close(struct usb_fifo *fifo, int fflags)
271 {
272 struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
273
274 sc->sc_fflags &= ~(fflags & FREAD);
275 usb_fifo_free_buffer(fifo);
276 }
277
278 static int
279 uhid_snes_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, int fflags)
280 {
281 struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
282 struct usb_gen_descriptor *ugd;
283 #ifdef COMPAT_FREEBSD32
284 struct usb_gen_descriptor local_ugd;
285 struct usb_gen_descriptor32 *ugd32 = NULL;
286 #endif
287 uint32_t size;
288 int error = 0;
289 uint8_t id;
290
291 ugd = data;
292 #ifdef COMPAT_FREEBSD32
293 switch (cmd) {
294 case USB_GET_REPORT_DESC32:
295 case USB_GET_REPORT32:
296 case USB_SET_REPORT32:
297 ugd32 = data;
298 ugd = &local_ugd;
299 usb_gen_descriptor_from32(ugd, ugd32);
300 cmd = _IOC_NEWTYPE(cmd, struct usb_gen_descriptor);
301 break;
302 }
303 #endif
304
305 switch (cmd) {
306 case USB_GET_REPORT_DESC:
307 if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
308 size = ugd->ugd_maxlen;
309 } else {
310 size = sc->sc_repdesc_size;
311 }
312
313 ugd->ugd_actlen = size;
314 if (ugd->ugd_data == NULL)
315 break; /* descriptor length only*/
316 error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
317 break;
318
319 case USB_SET_IMMED:
320 if (!(fflags & FREAD)) {
321 error = EPERM;
322 break;
323 }
324
325 if (*(int *)data) {
326 /* do a test read */
327 error = uhid_get_report(sc, UHID_INPUT_REPORT,
328 sc->sc_iid, NULL, NULL, sc->sc_isize);
329 if (error) {
330 break;
331 }
332 mtx_lock(&sc->sc_mutex);
333 sc->sc_fflags |= UHID_FLAG_IMMED;
334 mtx_unlock(&sc->sc_mutex);
335 } else {
336 mtx_lock(&sc->sc_mutex);
337 sc->sc_fflags &= ~UHID_FLAG_IMMED;
338 mtx_unlock(&sc->sc_mutex);
339 }
340 break;
341
342 case USB_GET_REPORT:
343 if (!(fflags & FREAD)) {
344 error = EPERM;
345 break;
346 }
347 switch (ugd->ugd_report_type) {
348 case UHID_INPUT_REPORT:
349 size = sc->sc_isize;
350 id = sc->sc_iid;
351 break;
352 case UHID_OUTPUT_REPORT:
353 size = sc->sc_osize;
354 id = sc->sc_oid;
355 break;
356 case UHID_FEATURE_REPORT:
357 size = sc->sc_fsize;
358 id = sc->sc_fid;
359 break;
360 default:
361 return (EINVAL);
362 }
363 if (id != 0)
364 copyin(ugd->ugd_data, &id, 1);
365 error = uhid_get_report(sc, ugd->ugd_report_type, id,
366 NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
367 break;
368
369 case USB_SET_REPORT:
370 if (!(fflags & FWRITE)) {
371 error = EPERM;
372 break;
373 }
374 switch (ugd->ugd_report_type) {
375 case UHID_INPUT_REPORT:
376 size = sc->sc_isize;
377 id = sc->sc_iid;
378 break;
379 case UHID_OUTPUT_REPORT:
380 size = sc->sc_osize;
381 id = sc->sc_oid;
382 break;
383 case UHID_FEATURE_REPORT:
384 size = sc->sc_fsize;
385 id = sc->sc_fid;
386 break;
387 default:
388 return (EINVAL);
389 }
390 if (id != 0)
391 copyin(ugd->ugd_data, &id, 1);
392 error = uhid_set_report(sc, ugd->ugd_report_type, id,
393 NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
394 break;
395
396 case USB_GET_REPORT_ID:
397 /* XXX: we only support reportid 0? */
398 *(int *)data = 0;
399 break;
400
401 default:
402 error = EINVAL;
403 break;
404 }
405
406 #ifdef COMPAT_FREEBSD32
407 if (ugd32 != NULL)
408 update_usb_gen_descriptor32(ugd32, ugd);
409 #endif
410 return (error);
411 }
412
413 static void
414 uhid_snes_watchdog(void *arg)
415 {
416 struct uhid_snes_softc *sc = arg;
417
418 mtx_assert(&sc->sc_mutex, MA_OWNED);
419
420 if (sc->sc_fflags == 0)
421 usbd_transfer_start(sc->sc_transfer[UHID_SNES_STATUS_DT_RD]);
422
423 usb_callout_reset(&sc->sc_watchdog, hz, &uhid_snes_watchdog, sc);
424 }
425
426 static void
427 uhid_snes_start_read(struct usb_fifo *fifo)
428 {
429 struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
430
431 usbd_transfer_start(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
432 }
433
434 static void
435 uhid_snes_stop_read(struct usb_fifo *fifo)
436 {
437 struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
438
439 usbd_transfer_stop(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
440 }
441
442 static void
443 uhid_snes_read_callback(struct usb_xfer *transfer, usb_error_t error)
444 {
445 struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
446 struct usb_fifo *fifo = sc->sc_fifo_open[USB_FIFO_RX];
447 struct usb_page_cache *pc;
448 int actual, max;
449
450 usbd_xfer_status(transfer, &actual, NULL, NULL, NULL);
451 if (fifo == NULL)
452 return;
453
454 switch (USB_GET_STATE(transfer)) {
455 case USB_ST_TRANSFERRED:
456 if (actual == 0) {
457 if (sc->sc_zero_length_packets == 4)
458 /* Throttle transfers. */
459 usbd_xfer_set_interval(transfer, 500);
460 else
461 sc->sc_zero_length_packets++;
462
463 } else {
464 /* disable throttling. */
465 usbd_xfer_set_interval(transfer, 0);
466 sc->sc_zero_length_packets = 0;
467 }
468 pc = usbd_xfer_get_frame(transfer, 0);
469 usb_fifo_put_data(fifo, pc, 0, actual, 1);
470 /* Fall through */
471 setup:
472 case USB_ST_SETUP:
473 if (usb_fifo_put_bytes_max(fifo) != 0) {
474 max = usbd_xfer_max_len(transfer);
475 usbd_xfer_set_frame_len(transfer, 0, max);
476 usbd_transfer_submit(transfer);
477 }
478 break;
479
480 default:
481 /*disable throttling. */
482 usbd_xfer_set_interval(transfer, 0);
483 sc->sc_zero_length_packets = 0;
484
485 if (error != USB_ERR_CANCELLED) {
486 /* Issue a clear-stall request. */
487 usbd_xfer_set_stall(transfer);
488 goto setup;
489 }
490 break;
491 }
492 }
493
494 static void
495 uhid_snes_status_callback(struct usb_xfer *transfer, usb_error_t error)
496 {
497 struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
498 struct usb_device_request req;
499 struct usb_page_cache *pc;
500
501 switch (USB_GET_STATE(transfer)) {
502 case USB_ST_SETUP:
503 req.bmRequestType = UT_READ_CLASS_INTERFACE;
504 req.bRequest = UREQ_GET_PORT_STATUS;
505 USETW(req.wValue, 0);
506 req.wIndex[0] = sc->sc_iface_num;
507 req.wIndex[1] = 0;
508 USETW(req.wLength, 1);
509
510 pc = usbd_xfer_get_frame(transfer, 0);
511 usbd_copy_in(pc, 0, &req, sizeof(req));
512 usbd_xfer_set_frame_len(transfer, 0, sizeof(req));
513 usbd_xfer_set_frame_len(transfer, 1, 1);
514 usbd_xfer_set_frames(transfer, 2);
515 usbd_transfer_submit(transfer);
516 break;
517
518 default:
519 break;
520 }
521
522 }
523
524 static int
525 uhid_snes_probe(device_t dev)
526 {
527 struct usb_attach_arg *uaa = device_get_ivars(dev);
528
529 if (uaa->usb_mode != USB_MODE_HOST)
530 return (ENXIO);
531
532 return (usbd_lookup_id_by_uaa(snes_devs, sizeof(snes_devs), uaa));
533 }
534
535 static int
536 uhid_snes_attach(device_t dev)
537 {
538 struct usb_attach_arg *uaa = device_get_ivars(dev);
539 struct uhid_snes_softc *sc = device_get_softc(dev);
540 struct usb_interface_descriptor *idesc;
541 struct usb_config_descriptor *cdesc;
542 uint8_t alt_index, iface_index = uaa->info.bIfaceIndex;
543 int error,unit = device_get_unit(dev);
544
545 sc->sc_dev = dev;
546 sc->sc_usb_device = uaa->device;
547 device_set_usb_desc(dev);
548 mtx_init(&sc->sc_mutex, "uhid_snes", NULL, MTX_DEF | MTX_RECURSE);
549 usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mutex, 0);
550
551 idesc = usbd_get_interface_descriptor(uaa->iface);
552 alt_index = -1;
553 for(;;) {
554 if (idesc == NULL)
555 break;
556
557 if ((idesc->bDescriptorType == UDESC_INTERFACE) &&
558 (idesc->bLength >= sizeof(*idesc))) {
559 if (idesc->bInterfaceNumber != uaa->info.bIfaceNum) {
560 break;
561 } else {
562 alt_index++;
563 if (idesc->bInterfaceClass == UICLASS_HID)
564 goto found;
565 }
566 }
567
568 cdesc = usbd_get_config_descriptor(uaa->device);
569 idesc = (void *)usb_desc_foreach(cdesc, (void *)idesc);
570 goto found;
571 }
572 goto detach;
573
574 found:
575 if (alt_index) {
576 error = usbd_set_alt_interface_index(uaa->device, iface_index, alt_index);
577 if (error)
578 goto detach;
579 }
580
581 sc->sc_iface_num = idesc->bInterfaceNumber;
582
583 error = usbd_transfer_setup(uaa->device, &iface_index,
584 sc->sc_transfer, uhid_snes_config, UHID_SNES_N_TRANSFER, sc,
585 &sc->sc_mutex);
586
587 if (error)
588 goto detach;
589
590 error = usb_fifo_attach(uaa->device, sc, &sc->sc_mutex,
591 &uhid_snes_fifo_methods, &sc->sc_fifo, unit, -1,
592 iface_index, UID_ROOT, GID_OPERATOR, 0644);
593 sc->sc_repdesc_size = sizeof(uhid_snes_report_descr);
594 sc->sc_repdesc_ptr = __DECONST(void*, &uhid_snes_report_descr);
595
596 if (error)
597 goto detach;
598
599 mtx_lock(&sc->sc_mutex);
600 uhid_snes_watchdog(sc);
601 mtx_unlock(&sc->sc_mutex);
602 return (0);
603
604 detach:
605 uhid_snes_detach(dev);
606 return (ENOMEM);
607 }
608
609 static int
610 uhid_snes_detach(device_t dev)
611 {
612 struct uhid_snes_softc *sc = device_get_softc(dev);
613
614 usb_fifo_detach(&sc->sc_fifo);
615 usb_fifo_detach(&sc->sc_fifo_no_reset);
616
617 mtx_lock(&sc->sc_mutex);
618 usb_callout_stop(&sc->sc_watchdog);
619 mtx_unlock(&sc->sc_mutex);
620
621 usbd_transfer_unsetup(sc->sc_transfer, UHID_SNES_N_TRANSFER);
622 usb_callout_drain(&sc->sc_watchdog);
623 mtx_destroy(&sc->sc_mutex);
624
625 return (0);
626 }
627
628 static device_method_t uhid_snes_methods[] = {
629 DEVMETHOD(device_probe, uhid_snes_probe),
630 DEVMETHOD(device_attach, uhid_snes_attach),
631 DEVMETHOD(device_detach, uhid_snes_detach),
632 DEVMETHOD_END
633 };
634
635 static driver_t uhid_snes_driver = {
636 "uhid_snes",
637 uhid_snes_methods,
638 sizeof(struct uhid_snes_softc)
639 };
640
641 DRIVER_MODULE(uhid_snes, uhub, uhid_snes_driver, NULL, NULL);
642 MODULE_DEPEND(uhid_snes, usb, 1, 1, 1);
643 USB_PNP_HOST_INFO(snes_devs);
Cache object: 6a602802bedbdc7f50a33c9210c1392b
|