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