1 /* $NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $ */ 2 3 /* Also already merged from NetBSD: 4 * $NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $ 5 */ 6 7 #include <sys/cdefs.h> 8 __FBSDID("$FreeBSD: releng/12.2/sys/dev/usb/input/uhid.c 363664 2020-07-29 14:30:42Z markj $"); 9 10 /*- 11 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 12 * 13 * Copyright (c) 1998 The NetBSD Foundation, Inc. 14 * All rights reserved. 15 * 16 * This code is derived from software contributed to The NetBSD Foundation 17 * by Lennart Augustsson (lennart@augustsson.net) at 18 * Carlstedt Research & Technology. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 * POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42 /* 43 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 44 */ 45 46 #include "implementation/global_implementation.h" 47 #include "input/usb_rdesc.h" 48 #include "implementation/usbdevs.h" 49 #include "event_hub.h" 50 51 #undef USB_DEBUG_VAR 52 #define USB_DEBUG_VAR uhid_debug 53 54 #ifdef LOSCFG_USB_DEBUG 55 static int uhid_debug = 0; 56 #endif 57 58 #define UHID_BSIZE 1024 /* bytes, buffer size */ 59 #define UHID_FRAME_NUM 50 /* bytes, frame number */ 60 61 #define MOUSE_DATA_LEN 4 62 #define BTN_LEFT_VALUE(v) ((v) & 0x01) 63 #define BTN_RIGHT_VALUE(v) (((v) & 0x02)>>1) 64 #define BTN_MIDDLE_VALUE(v) (((v) & 0x04)>>2) 65 66 enum { 67 UHID_INTR_DT_WR, 68 UHID_INTR_DT_RD, 69 UHID_CTRL_DT_WR, 70 UHID_CTRL_DT_RD, 71 UHID_N_TRANSFER, 72 }; 73 74 struct uhid_softc { 75 struct usb_fifo_sc sc_fifo; 76 struct mtx sc_mtx; 77 78 struct usb_xfer *sc_xfer[UHID_N_TRANSFER]; 79 struct usb_device *sc_udev; 80 void *sc_repdesc_ptr; 81 82 uint32_t sc_isize; 83 uint32_t sc_osize; 84 uint32_t sc_fsize; 85 86 InputDevice *input_dev; 87 88 uint16_t sc_repdesc_size; 89 90 uint8_t sc_iface_no; 91 uint8_t sc_iface_index; 92 uint8_t sc_iid; 93 uint8_t sc_oid; 94 uint8_t sc_fid; 95 uint8_t sc_flags; 96 #define UHID_FLAG_IMMED 0x01 /* set if read should be immediate */ 97 #define UHID_FLAG_STATIC_DESC 0x04 /* set if report descriptors are 98 * static */ 99 }; 100 101 static const uint8_t uhid_xb360gp_report_descr[] = {UHID_XB360GP_REPORT_DESCR()}; 102 static const uint8_t uhid_graphire_report_descr[] = {UHID_GRAPHIRE_REPORT_DESCR()}; 103 static const uint8_t uhid_graphire3_4x5_report_descr[] = {UHID_GRAPHIRE3_4X5_REPORT_DESCR()}; 104 105 /* prototypes */ 106 107 static device_probe_t uhid_probe; 108 static device_attach_t uhid_attach; 109 static device_detach_t uhid_detach; 110 111 static usb_callback_t uhid_intr_write_callback; 112 static usb_callback_t uhid_intr_read_callback; 113 static usb_callback_t uhid_write_callback; 114 static usb_callback_t uhid_read_callback; 115 116 static usb_fifo_cmd_t uhid_start_read; 117 static usb_fifo_cmd_t uhid_stop_read; 118 static usb_fifo_cmd_t uhid_start_write; 119 static usb_fifo_cmd_t uhid_stop_write; 120 static usb_fifo_open_t uhid_open; 121 static usb_fifo_close_t uhid_close; 122 static usb_fifo_ioctl_t uhid_ioctl; 123 124 static struct usb_fifo_methods uhid_fifo_methods = { 125 .f_open = &uhid_open, 126 .f_close = &uhid_close, 127 .f_ioctl = &uhid_ioctl, 128 .f_start_read = &uhid_start_read, 129 .f_stop_read = &uhid_stop_read, 130 .f_start_write = &uhid_start_write, 131 .f_stop_write = &uhid_stop_write, 132 .basename[0] = "uhid", 133 }; 134 135 static void 136 uhid_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) 137 { 138 struct uhid_softc *sc = usbd_xfer_softc(xfer); 139 struct usb_page_cache *pc; 140 usb_frlength_t actlen; 141 142 switch (USB_GET_STATE(xfer)) { 143 case USB_ST_TRANSFERRED: 144 case USB_ST_SETUP: 145 tr_setup: 146 pc = usbd_xfer_get_frame(xfer, 0); 147 if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc, 148 0, usbd_xfer_max_len(xfer), &actlen, 0)) { 149 usbd_xfer_set_frame_len(xfer, 0, actlen); 150 usbd_transfer_submit(xfer); 151 } 152 return; 153 154 default: /* Error */ 155 if (error != USB_ERR_CANCELLED) { 156 /* try to clear stall first */ 157 usbd_xfer_set_stall(xfer); 158 goto tr_setup; 159 } 160 return; 161 } 162 } 163 164 void report_event(InputDevice *input_dev, uint32_t type, uint32_t code, int32_t value) 165 { 166 DPRINTF("%s type = %u, code = %u, value = %d\n", input_dev->devName, type, code, value); 167 if (type == EV_SYN || type == EV_KEY) { 168 PushOnePackage(input_dev, type, code, value); 169 } else if (value) { 170 PushOnePackage(input_dev, type, code, value); 171 } 172 } 173 174 void mouse_report_events(InputDevice *input_dev, void *buffer, int len) 175 { 176 if (len != MOUSE_DATA_LEN) { 177 DPRINTF("%s: invalid data len = %d\n", __func__, len); 178 return; 179 } 180 181 const char *buf = buffer; 182 report_event(input_dev, EV_KEY, BTN_LEFT, BTN_LEFT_VALUE((unsigned char)buf[0])); 183 report_event(input_dev, EV_KEY, BTN_RIGHT, BTN_RIGHT_VALUE((unsigned char)buf[0])); 184 report_event(input_dev, EV_KEY, BTN_MIDDLE, BTN_MIDDLE_VALUE((unsigned char)buf[0])); 185 report_event(input_dev, EV_REL, REL_X, buf[1]); 186 report_event(input_dev, EV_REL, REL_Y, buf[2]); 187 report_event(input_dev, EV_REL, REL_WHEEL, buf[3]); 188 report_event(input_dev, EV_SYN, SYN_REPORT, 0); 189 } 190 191 static void 192 uhid_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) 193 { 194 struct uhid_softc *sc = usbd_xfer_softc(xfer); 195 struct usb_page_cache *pc; 196 int actlen; 197 198 DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer)); 199 200 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 201 202 switch (USB_GET_STATE(xfer)) { 203 case USB_ST_TRANSFERRED: 204 pc = usbd_xfer_get_frame(xfer, 0); 205 if (sc->input_dev && sc->input_dev->devType == INDEV_TYPE_MOUSE) { 206 mouse_report_events(sc->input_dev, pc->buffer, actlen); 207 } 208 209 case USB_ST_SETUP: 210 usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize); 211 usbd_transfer_submit(xfer); 212 return; 213 214 default: 215 if (error != USB_ERR_CANCELLED) { 216 usbd_xfer_set_stall(xfer); 217 usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize); 218 usbd_transfer_submit(xfer); 219 } 220 return; 221 } 222 } 223 224 static void 225 uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no, 226 uint8_t type, uint8_t id, uint16_t size) 227 { 228 req->bmRequestType = UT_WRITE_CLASS_INTERFACE; 229 req->bRequest = UR_SET_REPORT; 230 USETW2(req->wValue, type, id); 231 req->wIndex[0] = iface_no; 232 req->wIndex[1] = 0; 233 USETW(req->wLength, size); 234 } 235 236 static void 237 uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no, 238 uint8_t type, uint8_t id, uint16_t size) 239 { 240 req->bmRequestType = UT_READ_CLASS_INTERFACE; 241 req->bRequest = UR_GET_REPORT; 242 USETW2(req->wValue, type, id); 243 req->wIndex[0] = iface_no; 244 req->wIndex[1] = 0; 245 USETW(req->wLength, size); 246 } 247 248 static void 249 uhid_write_callback(struct usb_xfer *xfer, usb_error_t error) 250 { 251 struct uhid_softc *sc = usbd_xfer_softc(xfer); 252 struct usb_device_request req; 253 struct usb_page_cache *pc; 254 uint32_t size = sc->sc_osize; 255 uint32_t actlen; 256 uint8_t id; 257 258 switch (USB_GET_STATE(xfer)) { 259 case USB_ST_TRANSFERRED: 260 case USB_ST_SETUP: 261 /* try to extract the ID byte */ 262 if (sc->sc_oid) { 263 pc = usbd_xfer_get_frame(xfer, 0); 264 if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc, 265 0, 1, &actlen, 0)) { 266 if (actlen != 1) { 267 goto tr_error; 268 } 269 usbd_copy_out(pc, 0, &id, 1); 270 271 } else { 272 return; 273 } 274 if (size) { 275 size--; 276 } 277 } else { 278 id = 0; 279 } 280 281 pc = usbd_xfer_get_frame(xfer, 1); 282 if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc, 283 0, UHID_BSIZE, &actlen, 1)) { 284 if (actlen != size) { 285 goto tr_error; 286 } 287 uhid_fill_set_report 288 (&req, sc->sc_iface_no, 289 UHID_OUTPUT_REPORT, id, size); 290 291 pc = usbd_xfer_get_frame(xfer, 0); 292 usbd_copy_in(pc, 0, &req, sizeof(req)); 293 294 usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 295 usbd_xfer_set_frame_len(xfer, 1, size); 296 usbd_xfer_set_frames(xfer, size ? 2 : 1); 297 usbd_transfer_submit(xfer); 298 } 299 return; 300 301 default: 302 tr_error: 303 /* bomb out */ 304 usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]); 305 return; 306 } 307 } 308 309 static void 310 uhid_read_callback(struct usb_xfer *xfer, usb_error_t error) 311 { 312 struct uhid_softc *sc = usbd_xfer_softc(xfer); 313 struct usb_device_request req; 314 struct usb_page_cache *pc; 315 316 DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer)); 317 318 pc = usbd_xfer_get_frame(xfer, 0); 319 320 switch (USB_GET_STATE(xfer)) { 321 case USB_ST_TRANSFERRED: 322 usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req), 323 sc->sc_isize, 1); 324 return; 325 326 case USB_ST_SETUP: 327 328 if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) { 329 330 uhid_fill_get_report 331 (&req, sc->sc_iface_no, UHID_INPUT_REPORT, 332 sc->sc_iid, sc->sc_isize); 333 334 usbd_copy_in(pc, 0, &req, sizeof(req)); 335 336 usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 337 usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize); 338 usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1); 339 usbd_transfer_submit(xfer); 340 } 341 return; 342 343 default: /* Error */ 344 /* bomb out */ 345 usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]); 346 return; 347 } 348 } 349 350 static const struct usb_config uhid_config[UHID_N_TRANSFER] = { 351 352 [UHID_INTR_DT_WR] = { 353 .type = UE_INTERRUPT, 354 .endpoint = UE_ADDR_ANY, 355 .direction = UE_DIR_OUT, 356 .flags = {.pipe_bof = 1,.no_pipe_ok = 1, }, 357 .bufsize = UHID_BSIZE, 358 .callback = &uhid_intr_write_callback, 359 }, 360 361 [UHID_INTR_DT_RD] = { 362 .type = UE_INTERRUPT, 363 .endpoint = UE_ADDR_ANY, 364 .direction = UE_DIR_IN, 365 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 366 .bufsize = UHID_BSIZE, 367 .callback = &uhid_intr_read_callback, 368 }, 369 370 [UHID_CTRL_DT_WR] = { 371 .type = UE_CONTROL, 372 .endpoint = 0x00, /* Control pipe */ 373 .direction = UE_DIR_ANY, 374 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE, 375 .callback = &uhid_write_callback, 376 .timeout = 1000, /* 1 second */ 377 }, 378 379 [UHID_CTRL_DT_RD] = { 380 .type = UE_CONTROL, 381 .endpoint = 0x00, /* Control pipe */ 382 .direction = UE_DIR_ANY, 383 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE, 384 .callback = &uhid_read_callback, 385 .timeout = 1000, /* 1 second */ 386 }, 387 }; 388 389 static void 390 uhid_start_read(struct usb_fifo *fifo) 391 { 392 struct uhid_softc *sc = usb_fifo_softc(fifo); 393 394 if (sc->sc_flags & UHID_FLAG_IMMED) { 395 usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_RD]); 396 } else { 397 usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]); 398 } 399 } 400 401 static void 402 uhid_stop_read(struct usb_fifo *fifo) 403 { 404 struct uhid_softc *sc = usb_fifo_softc(fifo); 405 406 usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_RD]); 407 usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]); 408 } 409 410 static void 411 uhid_start_write(struct usb_fifo *fifo) 412 { 413 struct uhid_softc *sc = usb_fifo_softc(fifo); 414 415 if ((sc->sc_flags & UHID_FLAG_IMMED) || 416 sc->sc_xfer[UHID_INTR_DT_WR] == NULL) { 417 usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_WR]); 418 } else { 419 usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_WR]); 420 } 421 } 422 423 static void 424 uhid_stop_write(struct usb_fifo *fifo) 425 { 426 struct uhid_softc *sc = usb_fifo_softc(fifo); 427 428 usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_WR]); 429 usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_WR]); 430 } 431 432 static int 433 uhid_get_report(struct uhid_softc *sc, uint8_t type, 434 uint8_t id, void *kern_data, void *user_data, 435 uint16_t len) 436 { 437 int err; 438 uint8_t free_data = 0; 439 440 if (kern_data == NULL) { 441 if (len == 0) { 442 err = EPERM; 443 goto done; 444 } 445 446 kern_data = malloc(len); 447 if (kern_data == NULL) { 448 err = ENOMEM; 449 goto done; 450 } 451 free_data = 1; 452 } 453 err = usbd_req_get_report(sc->sc_udev, NULL, kern_data, 454 len, sc->sc_iface_index, type, id); 455 if (err) { 456 err = ENXIO; 457 goto done; 458 } 459 if (user_data) { 460 /* dummy buffer */ 461 err = copyout(kern_data, user_data, len); 462 if (err) { 463 goto done; 464 } 465 } 466 done: 467 if (free_data) { 468 free(kern_data); 469 } 470 return (err); 471 } 472 473 static int 474 uhid_set_report(struct uhid_softc *sc, uint8_t type, 475 uint8_t id, void *kern_data, const void *user_data, 476 uint16_t len) 477 { 478 int err; 479 uint8_t free_data = 0; 480 481 if (kern_data == NULL) { 482 if (len == 0) { 483 err = EPERM; 484 goto done; 485 } 486 487 kern_data = malloc(len); 488 if (kern_data == NULL) { 489 err = ENOMEM; 490 goto done; 491 } 492 free_data = 1; 493 err = copyin(user_data, kern_data, len); 494 if (err) { 495 goto done; 496 } 497 } 498 err = usbd_req_set_report(sc->sc_udev, NULL, kern_data, 499 len, sc->sc_iface_index, type, id); 500 if (err) { 501 err = ENXIO; 502 goto done; 503 } 504 done: 505 if (free_data) { 506 free(kern_data); 507 } 508 return (err); 509 } 510 511 static int 512 uhid_open(struct usb_fifo *fifo, int fflags) 513 { 514 struct uhid_softc *sc = usb_fifo_softc(fifo); 515 516 /* 517 * The buffers are one byte larger than maximum so that one 518 * can detect too large read/writes and short transfers: 519 */ 520 if ((unsigned int)fflags & FREAD) { 521 /* reset flags */ 522 mtx_lock(&sc->sc_mtx); 523 sc->sc_flags &= ~UHID_FLAG_IMMED; 524 mtx_unlock(&sc->sc_mtx); 525 526 if (usb_fifo_alloc_buffer(fifo, 527 sc->sc_isize + 1, UHID_FRAME_NUM)) { 528 return (ENOMEM); 529 } 530 } 531 if ((unsigned int)fflags & FWRITE) { 532 if (usb_fifo_alloc_buffer(fifo, 533 sc->sc_osize + 1, UHID_FRAME_NUM)) { 534 return (ENOMEM); 535 } 536 } 537 538 return (0); 539 } 540 541 static void 542 uhid_close(struct usb_fifo *fifo, int fflags) 543 { 544 if ((unsigned int)fflags & (FREAD | FWRITE)) { 545 usb_fifo_free_buffer(fifo); 546 } 547 } 548 549 static int 550 uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, 551 int fflags) 552 { 553 struct uhid_softc *sc = usb_fifo_softc(fifo); 554 struct usb_gen_descriptor ugd; 555 uint32_t size; 556 int error = 0; 557 uint8_t id; 558 559 switch (cmd) { 560 case USB_GET_REPORT_DESC: 561 error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor)); 562 if (error != ENOERR) { 563 break; 564 } 565 if (sc->sc_repdesc_size > ugd.ugd_maxlen) { 566 size = ugd.ugd_maxlen; 567 } else { 568 size = sc->sc_repdesc_size; 569 } 570 ugd.ugd_actlen = size; 571 if (ugd.ugd_data == NULL) 572 break; /* descriptor length only */ 573 error = copyout(sc->sc_repdesc_ptr, ugd.ugd_data, size); 574 if (error == ENOERR) { 575 error = copyout((const void *)&ugd, addr, sizeof(struct usb_gen_descriptor)); 576 } 577 break; 578 579 case USB_SET_IMMED: { 580 int data; 581 if (!((unsigned int)fflags & FREAD)) { 582 error = EPERM; 583 break; 584 } 585 error = copyin((const void *)addr, &data, sizeof(data)); 586 if (error != ENOERR) { 587 break; 588 } 589 if (data) { 590 /* do a test read */ 591 592 error = uhid_get_report(sc, UHID_INPUT_REPORT, 593 sc->sc_iid, NULL, NULL, sc->sc_isize); 594 if (error) { 595 break; 596 } 597 mtx_lock(&sc->sc_mtx); 598 sc->sc_flags |= UHID_FLAG_IMMED; 599 mtx_unlock(&sc->sc_mtx); 600 } else { 601 mtx_lock(&sc->sc_mtx); 602 sc->sc_flags &= ~UHID_FLAG_IMMED; 603 mtx_unlock(&sc->sc_mtx); 604 } 605 break; 606 } 607 608 case USB_GET_REPORT: 609 if (!((unsigned int)fflags & FREAD)) { 610 error = EPERM; 611 break; 612 } 613 error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor)); 614 if (error != ENOERR) { 615 break; 616 } 617 switch (ugd.ugd_report_type) { 618 case UHID_INPUT_REPORT: 619 size = sc->sc_isize; 620 id = sc->sc_iid; 621 break; 622 case UHID_OUTPUT_REPORT: 623 size = sc->sc_osize; 624 id = sc->sc_oid; 625 break; 626 case UHID_FEATURE_REPORT: 627 size = sc->sc_fsize; 628 id = sc->sc_fid; 629 break; 630 default: 631 return (EINVAL); 632 } 633 if (id != 0) 634 copyin(ugd.ugd_data, &id, 1); 635 error = uhid_get_report(sc, ugd.ugd_report_type, id, 636 NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size)); 637 break; 638 639 case USB_SET_REPORT: 640 if (!((unsigned int)fflags & FWRITE)) { 641 error = EPERM; 642 break; 643 } 644 error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor)); 645 if (error != ENOERR) { 646 break; 647 } 648 switch (ugd.ugd_report_type) { 649 case UHID_INPUT_REPORT: 650 size = sc->sc_isize; 651 id = sc->sc_iid; 652 break; 653 case UHID_OUTPUT_REPORT: 654 size = sc->sc_osize; 655 id = sc->sc_oid; 656 break; 657 case UHID_FEATURE_REPORT: 658 size = sc->sc_fsize; 659 id = sc->sc_fid; 660 break; 661 default: 662 return (EINVAL); 663 } 664 if (id != 0) 665 copyin(ugd.ugd_data, &id, 1); 666 error = uhid_set_report(sc, ugd.ugd_report_type, id, 667 NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size)); 668 break; 669 670 case USB_GET_REPORT_ID: { 671 int data = 0; 672 error = copyout((const void *)&data, addr, sizeof(data)); /* XXX: we only support reportid 0? */ 673 break; 674 } 675 676 default: 677 error = EINVAL; 678 break; 679 } 680 681 return (error); 682 } 683 684 static const STRUCT_USB_HOST_ID uhid_devs[] = { 685 /* generic HID class */ 686 {USB_IFACE_CLASS(UICLASS_HID),}, 687 /* the Xbox 360 gamepad doesn't use the HID class */ 688 {USB_IFACE_CLASS(UICLASS_VENDOR), 689 USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER), 690 USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),}, 691 }; 692 693 static int 694 uhid_probe(device_t dev) 695 { 696 struct usb_attach_arg *uaa = device_get_ivars(dev); 697 int error; 698 699 DPRINTFN(11, "\n"); 700 701 if (uaa->usb_mode != USB_MODE_HOST) 702 return (ENXIO); 703 704 error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa); 705 if (error) 706 return (error); 707 708 if (usb_test_quirk(uaa, UQ_HID_IGNORE)) 709 return (ENXIO); 710 711 return (0); 712 } 713 714 static int 715 uhid_attach(device_t dev) 716 { 717 struct usb_attach_arg *uaa = device_get_ivars(dev); 718 struct uhid_softc *sc = device_get_softc(dev); 719 int unit = device_get_unit(dev); 720 int error = 0; 721 int32_t ret; 722 723 DPRINTFN(10, "sc=%p\n", sc); 724 725 device_set_usb_desc(dev); 726 727 mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE); 728 729 sc->sc_udev = uaa->device; 730 731 sc->sc_iface_no = uaa->info.bIfaceNum; 732 sc->sc_iface_index = uaa->info.bIfaceIndex; 733 734 error = usbd_transfer_setup(uaa->device, 735 &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config, 736 UHID_N_TRANSFER, sc, &sc->sc_mtx); 737 738 if (error) { 739 DPRINTF("error=%s\n", usbd_errstr(error)); 740 goto detach; 741 } 742 if (uaa->info.idVendor == USB_VENDOR_WACOM) { 743 744 /* the report descriptor for the Wacom Graphire is broken */ 745 746 if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) { 747 748 sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr); 749 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire_report_descr); 750 sc->sc_flags |= UHID_FLAG_STATIC_DESC; 751 752 } else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) { 753 754 static uint8_t reportbuf[] = {2, 2, 2}; 755 756 /* 757 * The Graphire3 needs 0x0202 to be written to 758 * feature report ID 2 before it'll start 759 * returning digitizer data. 760 */ 761 error = usbd_req_set_report(uaa->device, NULL, 762 reportbuf, sizeof(reportbuf), 763 uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2); 764 765 if (error) { 766 DPRINTF("set report failed, error=%s (ignored)\n", 767 usbd_errstr(error)); 768 } 769 sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr); 770 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire3_4x5_report_descr); 771 sc->sc_flags |= UHID_FLAG_STATIC_DESC; 772 } 773 } else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) && 774 (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) && 775 (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) { 776 static const uint8_t reportbuf[3] = {1, 3, 0}; 777 /* 778 * Turn off the four LEDs on the gamepad which 779 * are blinking by default: 780 */ 781 error = usbd_req_set_report(uaa->device, NULL, 782 __DECONST(void *, reportbuf), sizeof(reportbuf), 783 uaa->info.bIfaceIndex, UHID_OUTPUT_REPORT, 0); 784 if (error) { 785 DPRINTF("set output report failed, error=%s (ignored)\n", 786 usbd_errstr(error)); 787 } 788 /* the Xbox 360 gamepad has no report descriptor */ 789 sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr); 790 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_xb360gp_report_descr); 791 sc->sc_flags |= UHID_FLAG_STATIC_DESC; 792 } 793 794 if (sc->sc_repdesc_ptr == NULL) { 795 796 error = usbd_req_get_hid_desc(uaa->device, NULL, 797 &sc->sc_repdesc_ptr, &sc->sc_repdesc_size, 798 M_USBDEV, uaa->info.bIfaceIndex); 799 800 if (error) { 801 device_printf(dev, "no report descriptor\n"); 802 goto detach; 803 } 804 } 805 806 error = usbd_req_set_idle(uaa->device, NULL, 807 uaa->info.bIfaceIndex, 0, 0); 808 809 if (error) { 810 DPRINTF("set idle failed, error=%s (ignored)\n", 811 usbd_errstr(error)); 812 } 813 814 sc->sc_isize = hid_report_size 815 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid); 816 817 sc->sc_osize = hid_report_size 818 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid); 819 820 sc->sc_fsize = hid_report_size 821 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid); 822 823 if (sc->sc_isize > UHID_BSIZE) { 824 DPRINTF("input size is too large, " 825 "%d bytes (truncating)\n", 826 sc->sc_isize); 827 sc->sc_isize = UHID_BSIZE; 828 } 829 if (sc->sc_osize > UHID_BSIZE) { 830 DPRINTF("output size is too large, " 831 "%d bytes (truncating)\n", 832 sc->sc_osize); 833 sc->sc_osize = UHID_BSIZE; 834 } 835 if (sc->sc_fsize > UHID_BSIZE) { 836 DPRINTF("feature size is too large, " 837 "%d bytes (truncating)\n", 838 sc->sc_fsize); 839 sc->sc_fsize = UHID_BSIZE; 840 } 841 842 error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, 843 &uhid_fifo_methods, &sc->sc_fifo, 844 unit, -1, uaa->info.bIfaceIndex, 845 UID_ROOT, GID_OPERATOR, 0644); 846 if (error) { 847 goto detach; 848 } 849 850 sc->input_dev = (InputDevice*)zalloc(sizeof(InputDevice)); 851 if (sc->input_dev) { 852 if (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) { 853 sc->input_dev->devType = INDEV_TYPE_MOUSE; 854 sc->input_dev->devName = "mouse"; 855 } else { 856 sc->input_dev->devType = INDEV_TYPE_UNKNOWN; 857 sc->input_dev->devName = "other"; 858 } 859 860 ret = RegisterInputDevice(sc->input_dev); 861 if (ret != HDF_SUCCESS) { 862 DPRINTF("%s register failed, ret = %d!\n", sc->input_dev->devName, ret); 863 free(sc->input_dev); 864 sc->input_dev = NULL; 865 } else if (sc->input_dev->devType == INDEV_TYPE_MOUSE) { 866 DPRINTF("mouse register success!\n"); 867 mtx_lock(&sc->sc_mtx); 868 sc->sc_flags &= ~UHID_FLAG_IMMED; 869 usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]); 870 mtx_unlock(&sc->sc_mtx); 871 } 872 } 873 874 return (0); /* success */ 875 876 detach: 877 uhid_detach(dev); 878 return (ENOMEM); 879 } 880 881 static int 882 uhid_detach(device_t dev) 883 { 884 struct uhid_softc *sc = device_get_softc(dev); 885 886 DPRINTF("enter\n"); 887 888 if (sc->input_dev) { 889 if (sc->input_dev->devType == INDEV_TYPE_MOUSE) { 890 usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]); 891 } 892 893 UnregisterInputDevice(sc->input_dev); 894 free(sc->input_dev); 895 sc->input_dev = NULL; 896 } 897 898 usb_fifo_detach(&sc->sc_fifo); 899 900 usbd_transfer_unsetup(sc->sc_xfer, UHID_N_TRANSFER); 901 902 if (sc->sc_repdesc_ptr) { 903 if (!(sc->sc_flags & UHID_FLAG_STATIC_DESC)) { 904 free(sc->sc_repdesc_ptr); 905 } 906 } 907 mtx_destroy(&sc->sc_mtx); 908 909 return (0); 910 } 911 912 static devclass_t uhid_devclass; 913 914 static device_method_t uhid_methods[] = { 915 DEVMETHOD(device_probe, uhid_probe), 916 DEVMETHOD(device_attach, uhid_attach), 917 DEVMETHOD(device_detach, uhid_detach), 918 919 DEVMETHOD_END 920 }; 921 922 static driver_t uhid_driver = { 923 .name = "uhid", 924 .methods = uhid_methods, 925 .size = sizeof(struct uhid_softc), 926 }; 927 928 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0); 929