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