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); 644