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 error = copyin(ugd->ugd_data, &id, 1); 363 if (error == 0) 364 error = uhid_get_report(sc, ugd->ugd_report_type, id, 365 NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); 366 break; 367 368 case USB_SET_REPORT: 369 if (!(fflags & FWRITE)) { 370 error = EPERM; 371 break; 372 } 373 switch (ugd->ugd_report_type) { 374 case UHID_INPUT_REPORT: 375 size = sc->sc_isize; 376 id = sc->sc_iid; 377 break; 378 case UHID_OUTPUT_REPORT: 379 size = sc->sc_osize; 380 id = sc->sc_oid; 381 break; 382 case UHID_FEATURE_REPORT: 383 size = sc->sc_fsize; 384 id = sc->sc_fid; 385 break; 386 default: 387 return (EINVAL); 388 } 389 if (id != 0) 390 error = copyin(ugd->ugd_data, &id, 1); 391 if (error == 0) 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