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, ¤t_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