1 /* $OpenBSD: uhidpp.c,v 1.13 2021/03/18 09:21:53 anton Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/kernel.h> 22 #include <sys/device.h> 23 #include <sys/mutex.h> 24 #include <sys/sensors.h> 25 26 #include <dev/usb/usb.h> 27 #include <dev/usb/usbhid.h> 28 #include <dev/usb/usbdi.h> 29 #include <dev/usb/usbdevs.h> 30 #include <dev/usb/uhidev.h> 31 32 /* #define UHIDPP_DEBUG */ 33 #ifdef UHIDPP_DEBUG 34 35 #define DPRINTF(x...) do { \ 36 if (uhidpp_debug) \ 37 printf(x); \ 38 } while (0) 39 40 #define DREPORT(prefix, repid, buf, len) do { \ 41 if (uhidpp_debug) \ 42 uhidd_dump_report((prefix), (repid), (buf), (len)); \ 43 } while (0) 44 45 void uhidd_dump_report(const char *, uint8_t, const unsigned char *, u_int); 46 47 int uhidpp_debug = 1; 48 49 #else 50 51 #define DPRINTF(x...) 52 #define DREPORT(prefix, repid, buf, len) 53 54 #endif 55 56 #define HIDPP_LINK_STATUS(x) ((x) & (1 << 7)) 57 58 #define HIDPP_REPORT_ID_SHORT 0x10 59 #define HIDPP_REPORT_ID_LONG 0x11 60 61 /* 62 * Length of reports. Note that the effective length is always +1 as 63 * uhidev_set_report() prepends the report ID. 64 */ 65 #define HIDPP_REPORT_SHORT_LENGTH (7 - 1) 66 #define HIDPP_REPORT_LONG_LENGTH (20 - 1) 67 68 /* 69 * Maximum number of allowed parameters for reports. Note, the parameters always 70 * starts at offset 3 for both RAP and FAP reports. 71 */ 72 #define HIDPP_REPORT_SHORT_PARAMS_MAX (HIDPP_REPORT_SHORT_LENGTH - 3) 73 #define HIDPP_REPORT_LONG_PARAMS_MAX (HIDPP_REPORT_LONG_LENGTH - 3) 74 75 #define HIDPP_DEVICE_ID_RECEIVER 0xff 76 77 #define HIDPP_FEAT_ROOT_IDX 0x00 78 #define HIDPP_FEAT_ROOT_PING_FUNC 0x01 79 #define HIDPP_FEAT_ROOT_PING_DATA 0x5a 80 81 #define HIDPP_SET_REGISTER 0x80 82 #define HIDPP_GET_REGISTER 0x81 83 #define HIDPP_SET_LONG_REGISTER 0x82 84 #define HIDPP_GET_LONG_REGISTER 0x83 85 86 #define HIDPP_REG_ENABLE_REPORTS 0x00 87 #define HIDPP_REG_PAIRING_INFORMATION 0xb5 88 89 #define HIDPP_NOTIF_DEVICE_BATTERY_STATUS (1 << 4) 90 #define HIDPP_NOTIF_RECEIVER_WIRELESS (1 << 0) 91 #define HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT (1 << 3) 92 93 /* HID++ 1.0 error codes. */ 94 #define HIDPP_ERROR 0x8f 95 #define HIDPP_ERROR_SUCCESS 0x00 96 #define HIDPP_ERROR_INVALID_SUBID 0x01 97 #define HIDPP_ERROR_INVALID_ADRESS 0x02 98 #define HIDPP_ERROR_INVALID_VALUE 0x03 99 #define HIDPP_ERROR_CONNECT_FAIL 0x04 100 #define HIDPP_ERROR_TOO_MANY_DEVICES 0x05 101 #define HIDPP_ERROR_ALREADY_EXISTS 0x06 102 #define HIDPP_ERROR_BUSY 0x07 103 #define HIDPP_ERROR_UNKNOWN_DEVICE 0x08 104 #define HIDPP_ERROR_RESOURCE_ERROR 0x09 105 #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a 106 #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b 107 #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c 108 109 /* 110 * The software ID is added to feature access reports (FAP) and used to 111 * distinguish responses from notifications. Note, the software ID must be 112 * greater than zero which is reserved for notifications. 113 */ 114 #define HIDPP_SOFTWARE_ID 0x01 115 #define HIDPP_SOFTWARE_ID_LEN 4 116 117 #define HIDPP20_FEAT_ROOT_ID 0x0000 118 #define HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC 0x0000 119 120 #define HIDPP20_FEAT_FEATURE_ID 0x0001 121 #define HIDPP20_FEAT_FEATURE_COUNT_FUNC 0x0000 122 #define HIDPP20_FEAT_FEATURE_ID_FUNC 0x0001 123 124 #define HIDPP20_FEAT_BATTERY_ID 0x1000 125 #define HIDPP20_FEAT_BATTERY_LEVEL_FUNC 0x0000 126 #define HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC 0x0001 127 128 /* HID++ 2.0 error codes. */ 129 #define HIDPP20_ERROR 0xff 130 #define HIDPP20_ERROR_NO_ERROR 0x00 131 #define HIDPP20_ERROR_UNKNOWN 0x01 132 #define HIDPP20_ERROR_INVALID_ARGUMENT 0x02 133 #define HIDPP20_ERROR_OUT_OF_RANGE 0x03 134 #define HIDPP20_ERROR_HARDWARE_ERROR 0x04 135 #define HIDPP20_ERROR_LOGITECH_INTERNAL 0x05 136 #define HIDPP20_ERROR_INVALID_FEATURE_INDEX 0x06 137 #define HIDPP20_ERROR_INVALID_FUNCTION_ID 0x07 138 #define HIDPP20_ERROR_BUSY 0x08 139 #define HIDPP20_ERROR_UNSUPPORTED 0x09 140 141 /* 142 * Sentinels used for interrupt response synchronization. The values must be 143 * disjoint from existing report IDs. 144 */ 145 #define UHIDPP_RESP_NONE 0 146 #define UHIDPP_RESP_WAIT 1 147 #define UHIDPP_RESP_ERROR 2 148 149 /* Maximum number of devices associated with a single receiver. */ 150 #define UHIDPP_NDEVICES 6 151 152 /* Maximum number of pending notifications. */ 153 #define UHIDPP_NNOTIFICATIONS 4 154 155 /* Number of sensors per paired device. */ 156 #define UHIDPP_NSENSORS 2 157 158 /* Feature access report used by the HID++ 2.0 (and greater) protocol. */ 159 struct fap { 160 uint8_t feature_idx; 161 uint8_t funcidx_swid; 162 uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX]; 163 }; 164 165 /* 166 * Register access report used by the HID++ 1.0 protocol. Receivers always uses 167 * this type of report. 168 */ 169 struct rap { 170 uint8_t sub_id; 171 uint8_t reg_address; 172 uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX]; 173 }; 174 175 struct uhidpp_report { 176 uint8_t device_id; 177 union { 178 struct fap fap; 179 struct rap rap; 180 }; 181 } __packed; 182 183 struct uhidpp_notification { 184 struct uhidpp_report n_rep; 185 unsigned int n_id; 186 }; 187 188 struct uhidpp_device { 189 uint8_t d_id; 190 uint8_t d_connected; 191 uint8_t d_major; 192 uint8_t d_minor; 193 uint8_t d_features; 194 #define UHIDPP_DEVICE_FEATURE_ROOT 0x01 195 #define UHIDPP_DEVICE_FEATURE_BATTERY 0x02 196 197 struct { 198 struct ksensor b_sens[UHIDPP_NSENSORS]; 199 uint8_t b_feature_idx; 200 uint8_t b_level; 201 uint8_t b_next_level; 202 uint8_t b_status; 203 uint8_t b_nlevels; 204 } d_battery; 205 }; 206 207 /* 208 * Locking: 209 * [m] sc_mtx 210 */ 211 struct uhidpp_softc { 212 struct uhidev sc_hdev; 213 struct usbd_device *sc_udev; 214 215 struct mutex sc_mtx; 216 217 struct uhidpp_device sc_devices[UHIDPP_NDEVICES]; 218 /* [m] connected devices */ 219 220 struct uhidpp_notification sc_notifications[UHIDPP_NNOTIFICATIONS]; 221 /* [m] pending notifications */ 222 223 struct usb_task sc_task; /* [m] notification task */ 224 225 struct ksensordev sc_sensdev; /* [m] */ 226 struct sensor_task *sc_senstsk; /* [m] */ 227 228 struct uhidpp_report *sc_req; /* [m] synchronous request buffer */ 229 struct uhidpp_report *sc_resp; /* [m] synchronous response buffer */ 230 u_int sc_resp_state; /* [m] synchronous response state */ 231 232 }; 233 234 int uhidpp_match(struct device *, void *, void *); 235 void uhidpp_attach(struct device *, struct device *, void *); 236 int uhidpp_detach(struct device *, int flags); 237 void uhidpp_intr(struct uhidev *addr, void *ibuf, u_int len); 238 void uhidpp_refresh(void *); 239 void uhidpp_task(void *); 240 int uhidpp_sleep(struct uhidpp_softc *, uint64_t); 241 242 void uhidpp_device_connect(struct uhidpp_softc *, struct uhidpp_device *); 243 void uhidpp_device_refresh(struct uhidpp_softc *, struct uhidpp_device *); 244 int uhidpp_device_features(struct uhidpp_softc *, struct uhidpp_device *); 245 246 struct uhidpp_notification *uhidpp_claim_notification(struct uhidpp_softc *); 247 int uhidpp_consume_notification(struct uhidpp_softc *, struct uhidpp_report *); 248 int uhidpp_is_notification(struct uhidpp_softc *, struct uhidpp_report *); 249 250 int hidpp_get_protocol_version(struct uhidpp_softc *, uint8_t, uint8_t *, 251 uint8_t *); 252 253 int hidpp10_get_name(struct uhidpp_softc *, uint8_t, char *, size_t); 254 int hidpp10_get_serial(struct uhidpp_softc *, uint8_t, uint8_t *, size_t); 255 int hidpp10_get_type(struct uhidpp_softc *, uint8_t, const char **); 256 int hidpp10_enable_notifications(struct uhidpp_softc *, uint8_t); 257 258 int hidpp20_root_get_feature(struct uhidpp_softc *, uint8_t, uint16_t, 259 uint8_t *, uint8_t *); 260 int hidpp20_feature_get_count(struct uhidpp_softc *, uint8_t, uint8_t, 261 uint8_t *); 262 int hidpp20_feature_get_id(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t, 263 uint16_t *, uint8_t *); 264 int hidpp20_battery_get_level_status(struct uhidpp_softc *, uint8_t, uint8_t, 265 uint8_t *, uint8_t *, uint8_t *); 266 int hidpp20_battery_get_capability(struct uhidpp_softc *, uint8_t, uint8_t, 267 uint8_t *); 268 269 int hidpp_send_validate(uint8_t, int); 270 int hidpp_send_rap_report(struct uhidpp_softc *, uint8_t, uint8_t, 271 uint8_t, uint8_t, uint8_t *, int, struct uhidpp_report *); 272 int hidpp_send_fap_report(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t, 273 uint8_t, uint8_t *, int, struct uhidpp_report *); 274 int hidpp_send_report(struct uhidpp_softc *, uint8_t, struct uhidpp_report *, 275 struct uhidpp_report *); 276 277 struct cfdriver uhidpp_cd = { 278 NULL, "uhidpp", DV_DULL 279 }; 280 281 const struct cfattach uhidpp_ca = { 282 sizeof(struct uhidpp_softc), 283 uhidpp_match, 284 uhidpp_attach, 285 uhidpp_detach, 286 }; 287 288 static const struct usb_devno uhidpp_devs[] = { 289 { USB_VENDOR_LOGITECH, USB_PRODUCT_ANY }, 290 }; 291 292 int 293 uhidpp_match(struct device *parent, void *match, void *aux) 294 { 295 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 296 void *desc; 297 int descsiz, siz; 298 299 if (uha->reportid != HIDPP_REPORT_ID_SHORT && 300 uha->reportid != HIDPP_REPORT_ID_LONG) 301 return UMATCH_NONE; 302 303 if (usb_lookup(uhidpp_devs, 304 uha->uaa->vendor, uha->uaa->product) == NULL) 305 return UMATCH_NONE; 306 307 uhidev_get_report_desc(uha->parent, &desc, &descsiz); 308 siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_SHORT); 309 if (siz != HIDPP_REPORT_SHORT_LENGTH) 310 return UMATCH_NONE; 311 siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_LONG); 312 if (siz != HIDPP_REPORT_LONG_LENGTH) 313 return UMATCH_NONE; 314 315 return UMATCH_VENDOR_PRODUCT; 316 } 317 318 void 319 uhidpp_attach(struct device *parent, struct device *self, void *aux) 320 { 321 struct uhidpp_softc *sc = (struct uhidpp_softc *)self; 322 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 323 struct usb_attach_arg *uaa = uha->uaa; 324 int error, i; 325 int npaired = 0; 326 327 sc->sc_hdev.sc_intr = uhidpp_intr; 328 sc->sc_hdev.sc_udev = uaa->device; 329 sc->sc_hdev.sc_parent = uha->parent; 330 sc->sc_hdev.sc_report_id = uha->reportid; 331 /* The largest supported report dictates the sizes. */ 332 sc->sc_hdev.sc_isize = HIDPP_REPORT_LONG_LENGTH; 333 sc->sc_hdev.sc_osize = HIDPP_REPORT_LONG_LENGTH; 334 335 sc->sc_udev = uaa->device; 336 337 mtx_init(&sc->sc_mtx, IPL_USB); 338 339 sc->sc_resp = NULL; 340 sc->sc_resp_state = UHIDPP_RESP_NONE; 341 342 error = uhidev_open(&sc->sc_hdev); 343 if (error) { 344 printf(" open error %d\n", error); 345 return; 346 } 347 348 usb_init_task(&sc->sc_task, uhidpp_task, sc, USB_TASK_TYPE_GENERIC); 349 350 mtx_enter(&sc->sc_mtx); 351 352 /* 353 * Wire up report device handlers before issuing commands to the device 354 * in order to receive responses. Necessary as uhidev by default 355 * performs the wiring after the attach routine has returned. 356 */ 357 error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev, 358 HIDPP_REPORT_ID_SHORT); 359 if (error) { 360 printf(" short report error %d\n", error); 361 return; 362 } 363 error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev, 364 HIDPP_REPORT_ID_LONG); 365 if (error) { 366 printf(" long report error %d\n", error); 367 return; 368 } 369 370 /* Probe paired devices. */ 371 for (i = 0; i < UHIDPP_NDEVICES; i++) { 372 char name[16]; 373 uint8_t serial[4]; 374 struct uhidpp_device *dev = &sc->sc_devices[i]; 375 const char *type; 376 uint8_t device_id = i + 1; 377 378 dev->d_id = device_id; 379 380 if (hidpp10_get_serial(sc, device_id, serial, sizeof(serial)) || 381 hidpp10_get_type(sc, device_id, &type) || 382 hidpp10_get_name(sc, device_id, name, sizeof(name))) 383 continue; 384 385 if (npaired > 0) 386 printf(","); 387 printf(" device %d", device_id); 388 printf(" %s", type); 389 printf(" \"%s\"", name); 390 printf(" serial %02x-%02x-%02x-%02x", 391 serial[0], serial[1], serial[2], serial[3]); 392 npaired++; 393 } 394 if (npaired == 0) 395 goto out; 396 397 /* Enable notifications for the receiver. */ 398 error = hidpp10_enable_notifications(sc, HIDPP_DEVICE_ID_RECEIVER); 399 if (error) 400 printf(" error %d", error); 401 402 strlcpy(sc->sc_sensdev.xname, sc->sc_hdev.sc_dev.dv_xname, 403 sizeof(sc->sc_sensdev.xname)); 404 sensordev_install(&sc->sc_sensdev); 405 406 out: 407 mtx_leave(&sc->sc_mtx); 408 printf("\n"); 409 } 410 411 int 412 uhidpp_detach(struct device *self, int flags) 413 { 414 struct uhidpp_softc *sc = (struct uhidpp_softc *)self; 415 int i, j; 416 417 usb_rem_wait_task(sc->sc_udev, &sc->sc_task); 418 419 if (sc->sc_senstsk != NULL) 420 sensor_task_unregister(sc->sc_senstsk); 421 422 KASSERT(sc->sc_resp_state == UHIDPP_RESP_NONE); 423 424 if (sc->sc_sensdev.xname[0] != '\0') 425 sensordev_deinstall(&sc->sc_sensdev); 426 427 for (i = 0; i < UHIDPP_NDEVICES; i++) { 428 struct uhidpp_device *dev = &sc->sc_devices[i]; 429 430 if (!dev->d_connected) 431 continue; 432 433 for (j = 0; j < UHIDPP_NSENSORS; j++) 434 sensor_detach(&sc->sc_sensdev, &dev->d_battery.b_sens[j]); 435 } 436 437 uhidev_close(&sc->sc_hdev); 438 439 return 0; 440 } 441 442 void 443 uhidpp_intr(struct uhidev *addr, void *buf, u_int len) 444 { 445 struct uhidpp_softc *sc = (struct uhidpp_softc *)addr; 446 struct uhidpp_report *rep = buf; 447 int dowake = 0; 448 uint8_t repid; 449 450 /* 451 * Ugliness ahead as the report ID is stripped of by uhidev_intr() but 452 * needed to determine if an error occurred. 453 * Note that an error response is always a short report even if the 454 * command that caused the error is a long report. 455 */ 456 repid = ((uint8_t *)buf)[-1]; 457 458 DREPORT(__func__, repid, buf, len); 459 460 mtx_enter(&sc->sc_mtx); 461 if (uhidpp_is_notification(sc, rep)) { 462 struct uhidpp_notification *ntf; 463 464 ntf = uhidpp_claim_notification(sc); 465 if (ntf != NULL) { 466 memcpy(&ntf->n_rep, buf, len); 467 usb_add_task(sc->sc_udev, &sc->sc_task); 468 } else { 469 DPRINTF("%s: too many notifications", __func__); 470 } 471 } else { 472 KASSERT(sc->sc_resp_state == UHIDPP_RESP_WAIT); 473 dowake = 1; 474 sc->sc_resp_state = repid; 475 memcpy(sc->sc_resp, buf, len); 476 } 477 mtx_leave(&sc->sc_mtx); 478 if (dowake) 479 wakeup(sc); 480 } 481 482 void 483 uhidpp_refresh(void *arg) 484 { 485 struct uhidpp_softc *sc = arg; 486 int i; 487 488 mtx_enter(&sc->sc_mtx); 489 for (i = 0; i < UHIDPP_NDEVICES; i++) { 490 struct uhidpp_device *dev = &sc->sc_devices[i]; 491 492 if (dev->d_connected) 493 uhidpp_device_refresh(sc, dev); 494 } 495 mtx_leave(&sc->sc_mtx); 496 } 497 498 void 499 uhidpp_task(void *arg) 500 { 501 struct uhidpp_softc *sc = arg; 502 503 mtx_enter(&sc->sc_mtx); 504 for (;;) { 505 struct uhidpp_report rep; 506 struct uhidpp_device *dev; 507 508 if (uhidpp_consume_notification(sc, &rep)) 509 break; 510 511 DPRINTF("%s: device_id=%d, sub_id=%02x\n", 512 __func__, rep.device_id, rep.rap.sub_id); 513 514 if (rep.device_id == 0 || rep.device_id > UHIDPP_NDEVICES) { 515 DPRINTF("%s: invalid device\n", __func__); 516 continue; 517 } 518 dev = &sc->sc_devices[rep.device_id - 1]; 519 520 switch (rep.rap.sub_id) { 521 case 0x0e: /* leds */ 522 case 0x40: /* disconnect */ 523 case 0x4b: /* pairing accepted */ 524 break; 525 case 0x41: /* connect */ 526 /* 527 * Do nothing if the link is reported to be out of 528 * range. This happens when a device has been idle for a 529 * while. 530 */ 531 if (HIDPP_LINK_STATUS(rep.rap.params[0])) 532 uhidpp_device_connect(sc, dev); 533 break; 534 } 535 } 536 mtx_leave(&sc->sc_mtx); 537 } 538 539 int 540 uhidpp_sleep(struct uhidpp_softc *sc, uint64_t nsecs) 541 { 542 return msleep_nsec(sc, &sc->sc_mtx, PZERO, "uhidpp", nsecs); 543 } 544 545 void 546 uhidpp_device_connect(struct uhidpp_softc *sc, struct uhidpp_device *dev) 547 { 548 struct ksensor *sens; 549 int error; 550 uint8_t feature_type; 551 552 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 553 554 /* A connected device will continously send connect events. */ 555 if (dev->d_connected) 556 return; 557 558 /* 559 * If features are already present, it must be a device lacking battery 560 * support. 561 */ 562 if (dev->d_features) 563 return; 564 565 error = hidpp_get_protocol_version(sc, dev->d_id, 566 &dev->d_major, &dev->d_minor); 567 if (error) { 568 DPRINTF("%s: protocol version failure: device_id=%d, " 569 "error=%d\n", 570 __func__, dev->d_id, error); 571 return; 572 } 573 574 DPRINTF("%s: device_id=%d, version=%d.%d\n", 575 __func__, dev->d_id, dev->d_major, dev->d_minor); 576 577 if (dev->d_major >= 2) { 578 error = uhidpp_device_features(sc, dev); 579 if (error) { 580 DPRINTF("%s: features failure: device_id=%d, " 581 "error=%d\n", 582 __func__, dev->d_id, error); 583 return; 584 } 585 586 error = hidpp20_root_get_feature(sc, dev->d_id, 587 HIDPP20_FEAT_BATTERY_ID, 588 &dev->d_battery.b_feature_idx, &feature_type); 589 if (error) { 590 DPRINTF("%s: battery feature index failure: " 591 "device_id=%d, error=%d\n", 592 __func__, dev->d_id, error); 593 return; 594 } 595 596 error = hidpp20_battery_get_capability(sc, dev->d_id, 597 dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels); 598 if (error) { 599 DPRINTF("%s: battery capability failure: device_id=%d, " 600 "error=%d\n", __func__, dev->d_id, error); 601 return; 602 } 603 604 } else { 605 return; 606 } 607 608 sens = &dev->d_battery.b_sens[0]; 609 strlcpy(sens->desc, "battery level", sizeof(sens->desc)); 610 sens->type = SENSOR_PERCENT; 611 sens->flags = SENSOR_FUNKNOWN; 612 sensor_attach(&sc->sc_sensdev, sens); 613 614 sens = &dev->d_battery.b_sens[1]; 615 strlcpy(sens->desc, "battery levels", sizeof(sens->desc)); 616 sens->type = SENSOR_INTEGER; 617 sens->value = dev->d_battery.b_nlevels; 618 sensor_attach(&sc->sc_sensdev, sens); 619 620 if (sc->sc_senstsk == NULL) 621 sc->sc_senstsk = sensor_task_register(sc, uhidpp_refresh, 30); 622 623 dev->d_connected = 1; 624 uhidpp_device_refresh(sc, dev); 625 } 626 627 void 628 uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev) 629 { 630 int error; 631 632 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 633 634 if (dev->d_major >= 2) { 635 error = hidpp20_battery_get_level_status(sc, dev->d_id, 636 dev->d_battery.b_feature_idx, 637 &dev->d_battery.b_level, &dev->d_battery.b_next_level, 638 &dev->d_battery.b_status); 639 if (error) { 640 DPRINTF("%s: battery status failure: device_id=%d, " 641 "error=%d\n", 642 __func__, dev->d_id, error); 643 return; 644 } 645 646 dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000; 647 dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN; 648 if (dev->d_battery.b_nlevels < 10) { 649 /* 650 * According to the HID++ 2.0 specification, less than 651 * 10 levels should be mapped to the following 4 levels: 652 * 653 * [0, 10] critical 654 * [11, 30] low 655 * [31, 80] good 656 * [81, 100] full 657 * 658 * Since sensors are limited to 3 valid statuses, clamp 659 * it even further. 660 */ 661 if (dev->d_battery.b_level <= 10) 662 dev->d_battery.b_sens[0].status = SENSOR_S_CRIT; 663 else if (dev->d_battery.b_level <= 30) 664 dev->d_battery.b_sens[0].status = SENSOR_S_WARN; 665 else 666 dev->d_battery.b_sens[0].status = SENSOR_S_OK; 667 } else { 668 /* 669 * XXX the device supports battery mileage. The current 670 * level must be checked against resp.fap.params[3] 671 * given by hidpp20_battery_get_capability(). 672 */ 673 dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN; 674 } 675 } 676 } 677 678 /* 679 * Enumerate all supported HID++ 2.0 features for the given device. 680 */ 681 int 682 uhidpp_device_features(struct uhidpp_softc *sc, struct uhidpp_device *dev) 683 { 684 int error; 685 uint8_t count, feature_idx, feature_type, i; 686 687 /* All devices support the root feature. */ 688 dev->d_features |= UHIDPP_DEVICE_FEATURE_ROOT; 689 690 error = hidpp20_root_get_feature(sc, dev->d_id, 691 HIDPP20_FEAT_FEATURE_ID, 692 &feature_idx, &feature_type); 693 if (error) { 694 DPRINTF("%s: feature index failure: device_id=%d, error=%d\n", 695 __func__, dev->d_id, error); 696 return error; 697 } 698 699 error = hidpp20_feature_get_count(sc, dev->d_id, feature_idx, &count); 700 if (error) { 701 DPRINTF("%s: feature count failure: device_id=%d, error=%d\n", 702 __func__, dev->d_id, error); 703 return error; 704 } 705 706 for (i = 1; i <= count; i++) { 707 uint16_t id; 708 uint8_t type; 709 710 error = hidpp20_feature_get_id(sc, dev->d_id, feature_idx, i, 711 &id, &type); 712 if (error) 713 continue; 714 715 if (id == HIDPP20_FEAT_BATTERY_ID) 716 dev->d_features |= UHIDPP_DEVICE_FEATURE_BATTERY; 717 718 DPRINTF("%s: idx=%d, id=%x, type=%x device_id=%d\n", 719 __func__, i, id, type, dev->d_id); 720 } 721 DPRINTF("%s: device_id=%d, count=%d, features=%x\n", 722 __func__, dev->d_id, count, dev->d_features); 723 724 if ((dev->d_features & UHIDPP_DEVICE_FEATURE_BATTERY) == 0) 725 return -ENODEV; 726 return 0; 727 } 728 729 /* 730 * Returns the next available notification slot, if available. 731 */ 732 struct uhidpp_notification * 733 uhidpp_claim_notification(struct uhidpp_softc *sc) 734 { 735 struct uhidpp_notification *ntf = NULL; 736 int nclaimed = 0; 737 int i; 738 739 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 740 741 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 742 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 743 744 if (tmp->n_id > 0) 745 nclaimed++; 746 else if (ntf == NULL) 747 ntf = tmp; 748 } 749 750 if (ntf == NULL) 751 return NULL; 752 ntf->n_id = nclaimed + 1; 753 return ntf; 754 } 755 756 /* 757 * Consume the first unhandled notification, if present. 758 */ 759 int 760 uhidpp_consume_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 761 { 762 struct uhidpp_notification *ntf = NULL; 763 int i; 764 765 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 766 767 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 768 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 769 770 if (tmp->n_id > 0 && (ntf == NULL || tmp->n_id < ntf->n_id)) 771 ntf = tmp; 772 } 773 if (ntf == NULL) 774 return 1; 775 776 memcpy(rep, &ntf->n_rep, sizeof(*rep)); 777 ntf->n_id = 0; 778 return 0; 779 } 780 781 782 /* 783 * Returns non-zero if the given report is a notification. Otherwise, it must be 784 * a response. 785 */ 786 int 787 uhidpp_is_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 788 { 789 /* Not waiting for a response. */ 790 if (sc->sc_req == NULL) 791 return 1; 792 793 /* Everything except the parameters must be repeated in a response. */ 794 if (sc->sc_req->device_id == rep->device_id && 795 sc->sc_req->rap.sub_id == rep->rap.sub_id && 796 sc->sc_req->rap.reg_address == rep->rap.reg_address) 797 return 0; 798 799 /* An error must always be a response. */ 800 if ((rep->rap.sub_id == HIDPP_ERROR || 801 rep->fap.feature_idx == HIDPP20_ERROR) && 802 rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx && 803 rep->fap.params[0] == sc->sc_req->fap.funcidx_swid) 804 return 0; 805 806 return 1; 807 } 808 809 int 810 hidpp_get_protocol_version(struct uhidpp_softc *sc, uint8_t device_id, 811 uint8_t *major, uint8_t *minor) 812 { 813 struct uhidpp_report resp; 814 uint8_t params[3] = { 0, 0, HIDPP_FEAT_ROOT_PING_DATA }; 815 int error; 816 817 error = hidpp_send_fap_report(sc, 818 HIDPP_REPORT_ID_SHORT, 819 device_id, 820 HIDPP_FEAT_ROOT_IDX, 821 HIDPP_FEAT_ROOT_PING_FUNC, 822 params, sizeof(params), &resp); 823 if (error == HIDPP_ERROR_INVALID_SUBID) { 824 *major = 1; 825 *minor = 0; 826 return 0; 827 } 828 if (error) 829 return error; 830 if (resp.rap.params[2] != HIDPP_FEAT_ROOT_PING_DATA) 831 return -EPROTO; 832 833 *major = resp.fap.params[0]; 834 *minor = resp.fap.params[1]; 835 return 0; 836 } 837 838 int 839 hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id, 840 char *buf, size_t bufsiz) 841 { 842 struct uhidpp_report resp; 843 int error; 844 uint8_t params[1] = { 0x40 + (device_id - 1) }; 845 uint8_t len; 846 847 error = hidpp_send_rap_report(sc, 848 HIDPP_REPORT_ID_SHORT, 849 HIDPP_DEVICE_ID_RECEIVER, 850 HIDPP_GET_LONG_REGISTER, 851 HIDPP_REG_PAIRING_INFORMATION, 852 params, sizeof(params), &resp); 853 if (error) 854 return error; 855 856 len = resp.rap.params[1]; 857 if (len + 2 > sizeof(resp.rap.params)) 858 return -ENAMETOOLONG; 859 if (len > bufsiz - 1) 860 len = bufsiz - 1; 861 memcpy(buf, &resp.rap.params[2], len); 862 buf[len] = '\0'; 863 return 0; 864 } 865 866 int 867 hidpp10_get_serial(struct uhidpp_softc *sc, uint8_t device_id, 868 uint8_t *buf, size_t bufsiz) 869 { 870 struct uhidpp_report resp; 871 int error; 872 uint8_t params[1] = { 0x30 + (device_id - 1) }; 873 uint8_t len; 874 875 error = hidpp_send_rap_report(sc, 876 HIDPP_REPORT_ID_SHORT, 877 HIDPP_DEVICE_ID_RECEIVER, 878 HIDPP_GET_LONG_REGISTER, 879 HIDPP_REG_PAIRING_INFORMATION, 880 params, sizeof(params), &resp); 881 if (error) 882 return error; 883 884 len = 4; 885 if (bufsiz < len) 886 len = bufsiz; 887 memcpy(buf, &resp.rap.params[1], len); 888 return 0; 889 } 890 891 int 892 hidpp10_get_type(struct uhidpp_softc *sc, uint8_t device_id, const char **type) 893 { 894 struct uhidpp_report resp; 895 int error; 896 uint8_t params[1] = { 0x20 + (device_id - 1) }; 897 898 error = hidpp_send_rap_report(sc, 899 HIDPP_REPORT_ID_SHORT, 900 HIDPP_DEVICE_ID_RECEIVER, 901 HIDPP_GET_LONG_REGISTER, 902 HIDPP_REG_PAIRING_INFORMATION, 903 params, sizeof(params), &resp); 904 if (error) 905 return error; 906 907 switch (resp.rap.params[7]) { 908 case 0x00: 909 *type = "unknown"; 910 return 0; 911 case 0x01: 912 *type = "keyboard"; 913 return 0; 914 case 0x02: 915 *type = "mouse"; 916 return 0; 917 case 0x03: 918 *type = "numpad"; 919 return 0; 920 case 0x04: 921 *type = "presenter"; 922 return 0; 923 case 0x08: 924 *type = "trackball"; 925 return 0; 926 case 0x09: 927 *type = "touchpad"; 928 return 0; 929 } 930 return -ENOENT; 931 } 932 933 int 934 hidpp10_enable_notifications(struct uhidpp_softc *sc, uint8_t device_id) 935 { 936 struct uhidpp_report resp; 937 uint8_t params[3]; 938 939 /* Device reporting flags. */ 940 params[0] = HIDPP_NOTIF_DEVICE_BATTERY_STATUS; 941 /* Receiver reporting flags. */ 942 params[1] = HIDPP_NOTIF_RECEIVER_WIRELESS | 943 HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT; 944 /* Device reporting flags (continued). */ 945 params[2] = 0; 946 947 return hidpp_send_rap_report(sc, 948 HIDPP_REPORT_ID_SHORT, 949 device_id, 950 HIDPP_SET_REGISTER, 951 HIDPP_REG_ENABLE_REPORTS, 952 params, sizeof(params), &resp); 953 } 954 955 int 956 hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id, 957 uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type) 958 { 959 struct uhidpp_report resp; 960 uint8_t params[2] = { feature >> 8, feature & 0xff }; 961 int error; 962 963 error = hidpp_send_fap_report(sc, 964 HIDPP_REPORT_ID_LONG, 965 device_id, 966 HIDPP20_FEAT_ROOT_ID, 967 HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC, 968 params, sizeof(params), &resp); 969 if (error) 970 return error; 971 972 if (resp.fap.params[0] == 0) 973 return -ENOENT; 974 975 *feature_idx = resp.fap.params[0]; 976 *feature_type = resp.fap.params[1]; 977 return 0; 978 } 979 980 int 981 hidpp20_feature_get_count(struct uhidpp_softc *sc, uint8_t device_id, 982 uint8_t feature_idx, uint8_t *count) 983 { 984 struct uhidpp_report resp; 985 int error; 986 987 error = hidpp_send_fap_report(sc, 988 HIDPP_REPORT_ID_LONG, 989 device_id, 990 feature_idx, 991 HIDPP20_FEAT_FEATURE_COUNT_FUNC, 992 NULL, 0, &resp); 993 if (error) 994 return error; 995 996 *count = resp.fap.params[0]; 997 return 0; 998 } 999 1000 int 1001 hidpp20_feature_get_id(struct uhidpp_softc *sc, uint8_t device_id, 1002 uint8_t feature_idx, uint8_t idx, uint16_t *id, uint8_t *type) 1003 { 1004 struct uhidpp_report resp; 1005 uint8_t params[1] = { idx }; 1006 int error; 1007 1008 error = hidpp_send_fap_report(sc, 1009 HIDPP_REPORT_ID_LONG, 1010 device_id, 1011 feature_idx, 1012 HIDPP20_FEAT_FEATURE_ID_FUNC, 1013 params, sizeof(params), &resp); 1014 if (error) 1015 return error; 1016 1017 *id = bemtoh16(resp.fap.params); 1018 *type = resp.fap.params[2]; 1019 return 0; 1020 } 1021 1022 int 1023 hidpp20_battery_get_level_status(struct uhidpp_softc *sc, uint8_t device_id, 1024 uint8_t feature_idx, uint8_t *level, uint8_t *next_level, uint8_t *status) 1025 { 1026 struct uhidpp_report resp; 1027 int error; 1028 1029 error = hidpp_send_fap_report(sc, 1030 HIDPP_REPORT_ID_LONG, 1031 device_id, 1032 feature_idx, 1033 HIDPP20_FEAT_BATTERY_LEVEL_FUNC, 1034 NULL, 0, &resp); 1035 if (error) 1036 return error; 1037 1038 *level = resp.fap.params[0]; 1039 *next_level = resp.fap.params[1]; 1040 *status = resp.fap.params[2]; 1041 return 0; 1042 } 1043 1044 int 1045 hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id, 1046 uint8_t feature_idx, uint8_t *nlevels) 1047 { 1048 struct uhidpp_report resp; 1049 int error; 1050 1051 error = hidpp_send_fap_report(sc, 1052 HIDPP_REPORT_ID_LONG, 1053 device_id, 1054 feature_idx, 1055 HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC, 1056 NULL, 0, &resp); 1057 if (error) 1058 return error; 1059 *nlevels = resp.fap.params[0]; 1060 return 0; 1061 } 1062 1063 int 1064 hidpp_send_validate(uint8_t report_id, int nparams) 1065 { 1066 if (report_id == HIDPP_REPORT_ID_SHORT) { 1067 if (nparams > HIDPP_REPORT_SHORT_PARAMS_MAX) 1068 return -EMSGSIZE; 1069 } else if (report_id == HIDPP_REPORT_ID_LONG) { 1070 if (nparams > HIDPP_REPORT_LONG_PARAMS_MAX) 1071 return -EMSGSIZE; 1072 } else { 1073 return -EINVAL; 1074 } 1075 return 0; 1076 } 1077 1078 int 1079 hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id, 1080 uint8_t device_id, uint8_t feature_idx, uint8_t funcidx_swid, 1081 uint8_t *params, int nparams, struct uhidpp_report *resp) 1082 { 1083 struct uhidpp_report req; 1084 int error; 1085 1086 error = hidpp_send_validate(report_id, nparams); 1087 if (error) 1088 return error; 1089 1090 memset(&req, 0, sizeof(req)); 1091 req.device_id = device_id; 1092 req.fap.feature_idx = feature_idx; 1093 req.fap.funcidx_swid = 1094 (funcidx_swid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID; 1095 memcpy(req.fap.params, params, nparams); 1096 return hidpp_send_report(sc, report_id, &req, resp); 1097 } 1098 1099 int 1100 hidpp_send_rap_report(struct uhidpp_softc *sc, uint8_t report_id, 1101 uint8_t device_id, uint8_t sub_id, uint8_t reg_address, 1102 uint8_t *params, int nparams, struct uhidpp_report *resp) 1103 { 1104 struct uhidpp_report req; 1105 int error; 1106 1107 error = hidpp_send_validate(report_id, nparams); 1108 if (error) 1109 return error; 1110 1111 memset(&req, 0, sizeof(req)); 1112 req.device_id = device_id; 1113 req.rap.sub_id = sub_id; 1114 req.rap.reg_address = reg_address; 1115 memcpy(req.rap.params, params, nparams); 1116 return hidpp_send_report(sc, report_id, &req, resp); 1117 } 1118 1119 int 1120 hidpp_send_report(struct uhidpp_softc *sc, uint8_t report_id, 1121 struct uhidpp_report *req, struct uhidpp_report *resp) 1122 { 1123 int error, len, n; 1124 1125 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 1126 1127 if (report_id == HIDPP_REPORT_ID_SHORT) 1128 len = HIDPP_REPORT_SHORT_LENGTH; 1129 else if (report_id == HIDPP_REPORT_ID_LONG) 1130 len = HIDPP_REPORT_LONG_LENGTH; 1131 else 1132 return -EINVAL; 1133 1134 DREPORT(__func__, report_id, (const unsigned char *)req, len); 1135 1136 /* Wait until any ongoing command has completed. */ 1137 while (sc->sc_resp_state != UHIDPP_RESP_NONE) 1138 uhidpp_sleep(sc, INFSLP); 1139 sc->sc_req = req; 1140 sc->sc_resp = resp; 1141 sc->sc_resp_state = UHIDPP_RESP_WAIT; 1142 /* 1143 * The mutex must be temporarily released while calling 1144 * uhidev_set_report() as it might end up sleeping. 1145 */ 1146 mtx_leave(&sc->sc_mtx); 1147 1148 n = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 1149 report_id, req, len); 1150 1151 mtx_enter(&sc->sc_mtx); 1152 if (len != n) { 1153 error = -EBUSY; 1154 goto out; 1155 } 1156 /* 1157 * The interrupt could already have been received while the mutex was 1158 * released. Otherwise, wait for it. 1159 */ 1160 if (sc->sc_resp_state == UHIDPP_RESP_WAIT) { 1161 /* Timeout taken from the hid-logitech-hidpp Linux driver. */ 1162 error = uhidpp_sleep(sc, SEC_TO_NSEC(5)); 1163 if (error) { 1164 error = -error; 1165 goto out; 1166 } 1167 } 1168 1169 if (sc->sc_resp_state == UHIDPP_RESP_ERROR) 1170 error = -EIO; 1171 else if (sc->sc_resp_state == HIDPP_REPORT_ID_SHORT && 1172 resp->rap.sub_id == HIDPP_ERROR) 1173 error = resp->rap.params[1]; 1174 else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG && 1175 resp->fap.feature_idx == HIDPP20_ERROR) 1176 error = resp->fap.params[1]; 1177 1178 out: 1179 sc->sc_req = NULL; 1180 sc->sc_resp = NULL; 1181 sc->sc_resp_state = UHIDPP_RESP_NONE; 1182 wakeup(sc); 1183 return error; 1184 } 1185 1186 #ifdef UHIDPP_DEBUG 1187 1188 void 1189 uhidd_dump_report(const char *prefix, uint8_t repid, const unsigned char *buf, 1190 u_int buflen) 1191 { 1192 u_int i; 1193 1194 printf("%s: %02x ", prefix, repid); 1195 for (i = 0; i < buflen; i++) { 1196 printf("%02x%s", buf[i], 1197 i == 2 ? " [" : (i + 1 < buflen ? " " : "")); 1198 } 1199 printf("]\n"); 1200 } 1201 1202 #endif 1203