1 /* $OpenBSD: uhidpp.c,v 1.14 2021/05/11 16:40:57 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 dev->d_connected = 1; 609 610 sens = &dev->d_battery.b_sens[0]; 611 strlcpy(sens->desc, "battery level", sizeof(sens->desc)); 612 sens->type = SENSOR_PERCENT; 613 sens->flags = SENSOR_FUNKNOWN; 614 sensor_attach(&sc->sc_sensdev, sens); 615 616 sens = &dev->d_battery.b_sens[1]; 617 strlcpy(sens->desc, "battery levels", sizeof(sens->desc)); 618 sens->type = SENSOR_INTEGER; 619 sens->value = dev->d_battery.b_nlevels; 620 sensor_attach(&sc->sc_sensdev, sens); 621 622 if (sc->sc_senstsk == NULL) { 623 /* 624 * The mutex must be temporarily released while calling 625 * sensor_task_register() as it might end up sleeping. 626 */ 627 mtx_leave(&sc->sc_mtx); 628 sc->sc_senstsk = sensor_task_register(sc, uhidpp_refresh, 30); 629 mtx_enter(&sc->sc_mtx); 630 } 631 632 uhidpp_device_refresh(sc, dev); 633 } 634 635 void 636 uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev) 637 { 638 int error; 639 640 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 641 642 if (dev->d_major >= 2) { 643 error = hidpp20_battery_get_level_status(sc, dev->d_id, 644 dev->d_battery.b_feature_idx, 645 &dev->d_battery.b_level, &dev->d_battery.b_next_level, 646 &dev->d_battery.b_status); 647 if (error) { 648 DPRINTF("%s: battery status failure: device_id=%d, " 649 "error=%d\n", 650 __func__, dev->d_id, error); 651 return; 652 } 653 654 dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000; 655 dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN; 656 if (dev->d_battery.b_nlevels < 10) { 657 /* 658 * According to the HID++ 2.0 specification, less than 659 * 10 levels should be mapped to the following 4 levels: 660 * 661 * [0, 10] critical 662 * [11, 30] low 663 * [31, 80] good 664 * [81, 100] full 665 * 666 * Since sensors are limited to 3 valid statuses, clamp 667 * it even further. 668 */ 669 if (dev->d_battery.b_level <= 10) 670 dev->d_battery.b_sens[0].status = SENSOR_S_CRIT; 671 else if (dev->d_battery.b_level <= 30) 672 dev->d_battery.b_sens[0].status = SENSOR_S_WARN; 673 else 674 dev->d_battery.b_sens[0].status = SENSOR_S_OK; 675 } else { 676 /* 677 * XXX the device supports battery mileage. The current 678 * level must be checked against resp.fap.params[3] 679 * given by hidpp20_battery_get_capability(). 680 */ 681 dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN; 682 } 683 } 684 } 685 686 /* 687 * Enumerate all supported HID++ 2.0 features for the given device. 688 */ 689 int 690 uhidpp_device_features(struct uhidpp_softc *sc, struct uhidpp_device *dev) 691 { 692 int error; 693 uint8_t count, feature_idx, feature_type, i; 694 695 /* All devices support the root feature. */ 696 dev->d_features |= UHIDPP_DEVICE_FEATURE_ROOT; 697 698 error = hidpp20_root_get_feature(sc, dev->d_id, 699 HIDPP20_FEAT_FEATURE_ID, 700 &feature_idx, &feature_type); 701 if (error) { 702 DPRINTF("%s: feature index failure: device_id=%d, error=%d\n", 703 __func__, dev->d_id, error); 704 return error; 705 } 706 707 error = hidpp20_feature_get_count(sc, dev->d_id, feature_idx, &count); 708 if (error) { 709 DPRINTF("%s: feature count failure: device_id=%d, error=%d\n", 710 __func__, dev->d_id, error); 711 return error; 712 } 713 714 for (i = 1; i <= count; i++) { 715 uint16_t id; 716 uint8_t type; 717 718 error = hidpp20_feature_get_id(sc, dev->d_id, feature_idx, i, 719 &id, &type); 720 if (error) 721 continue; 722 723 if (id == HIDPP20_FEAT_BATTERY_ID) 724 dev->d_features |= UHIDPP_DEVICE_FEATURE_BATTERY; 725 726 DPRINTF("%s: idx=%d, id=%x, type=%x device_id=%d\n", 727 __func__, i, id, type, dev->d_id); 728 } 729 DPRINTF("%s: device_id=%d, count=%d, features=%x\n", 730 __func__, dev->d_id, count, dev->d_features); 731 732 if ((dev->d_features & UHIDPP_DEVICE_FEATURE_BATTERY) == 0) 733 return -ENODEV; 734 return 0; 735 } 736 737 /* 738 * Returns the next available notification slot, if available. 739 */ 740 struct uhidpp_notification * 741 uhidpp_claim_notification(struct uhidpp_softc *sc) 742 { 743 struct uhidpp_notification *ntf = NULL; 744 int nclaimed = 0; 745 int i; 746 747 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 748 749 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 750 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 751 752 if (tmp->n_id > 0) 753 nclaimed++; 754 else if (ntf == NULL) 755 ntf = tmp; 756 } 757 758 if (ntf == NULL) 759 return NULL; 760 ntf->n_id = nclaimed + 1; 761 return ntf; 762 } 763 764 /* 765 * Consume the first unhandled notification, if present. 766 */ 767 int 768 uhidpp_consume_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 769 { 770 struct uhidpp_notification *ntf = NULL; 771 int i; 772 773 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 774 775 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 776 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 777 778 if (tmp->n_id > 0 && (ntf == NULL || tmp->n_id < ntf->n_id)) 779 ntf = tmp; 780 } 781 if (ntf == NULL) 782 return 1; 783 784 memcpy(rep, &ntf->n_rep, sizeof(*rep)); 785 ntf->n_id = 0; 786 return 0; 787 } 788 789 790 /* 791 * Returns non-zero if the given report is a notification. Otherwise, it must be 792 * a response. 793 */ 794 int 795 uhidpp_is_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 796 { 797 /* Not waiting for a response. */ 798 if (sc->sc_req == NULL) 799 return 1; 800 801 /* Everything except the parameters must be repeated in a response. */ 802 if (sc->sc_req->device_id == rep->device_id && 803 sc->sc_req->rap.sub_id == rep->rap.sub_id && 804 sc->sc_req->rap.reg_address == rep->rap.reg_address) 805 return 0; 806 807 /* An error must always be a response. */ 808 if ((rep->rap.sub_id == HIDPP_ERROR || 809 rep->fap.feature_idx == HIDPP20_ERROR) && 810 rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx && 811 rep->fap.params[0] == sc->sc_req->fap.funcidx_swid) 812 return 0; 813 814 return 1; 815 } 816 817 int 818 hidpp_get_protocol_version(struct uhidpp_softc *sc, uint8_t device_id, 819 uint8_t *major, uint8_t *minor) 820 { 821 struct uhidpp_report resp; 822 uint8_t params[3] = { 0, 0, HIDPP_FEAT_ROOT_PING_DATA }; 823 int error; 824 825 error = hidpp_send_fap_report(sc, 826 HIDPP_REPORT_ID_SHORT, 827 device_id, 828 HIDPP_FEAT_ROOT_IDX, 829 HIDPP_FEAT_ROOT_PING_FUNC, 830 params, sizeof(params), &resp); 831 if (error == HIDPP_ERROR_INVALID_SUBID) { 832 *major = 1; 833 *minor = 0; 834 return 0; 835 } 836 if (error) 837 return error; 838 if (resp.rap.params[2] != HIDPP_FEAT_ROOT_PING_DATA) 839 return -EPROTO; 840 841 *major = resp.fap.params[0]; 842 *minor = resp.fap.params[1]; 843 return 0; 844 } 845 846 int 847 hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id, 848 char *buf, size_t bufsiz) 849 { 850 struct uhidpp_report resp; 851 int error; 852 uint8_t params[1] = { 0x40 + (device_id - 1) }; 853 uint8_t len; 854 855 error = hidpp_send_rap_report(sc, 856 HIDPP_REPORT_ID_SHORT, 857 HIDPP_DEVICE_ID_RECEIVER, 858 HIDPP_GET_LONG_REGISTER, 859 HIDPP_REG_PAIRING_INFORMATION, 860 params, sizeof(params), &resp); 861 if (error) 862 return error; 863 864 len = resp.rap.params[1]; 865 if (len + 2 > sizeof(resp.rap.params)) 866 return -ENAMETOOLONG; 867 if (len > bufsiz - 1) 868 len = bufsiz - 1; 869 memcpy(buf, &resp.rap.params[2], len); 870 buf[len] = '\0'; 871 return 0; 872 } 873 874 int 875 hidpp10_get_serial(struct uhidpp_softc *sc, uint8_t device_id, 876 uint8_t *buf, size_t bufsiz) 877 { 878 struct uhidpp_report resp; 879 int error; 880 uint8_t params[1] = { 0x30 + (device_id - 1) }; 881 uint8_t len; 882 883 error = hidpp_send_rap_report(sc, 884 HIDPP_REPORT_ID_SHORT, 885 HIDPP_DEVICE_ID_RECEIVER, 886 HIDPP_GET_LONG_REGISTER, 887 HIDPP_REG_PAIRING_INFORMATION, 888 params, sizeof(params), &resp); 889 if (error) 890 return error; 891 892 len = 4; 893 if (bufsiz < len) 894 len = bufsiz; 895 memcpy(buf, &resp.rap.params[1], len); 896 return 0; 897 } 898 899 int 900 hidpp10_get_type(struct uhidpp_softc *sc, uint8_t device_id, const char **type) 901 { 902 struct uhidpp_report resp; 903 int error; 904 uint8_t params[1] = { 0x20 + (device_id - 1) }; 905 906 error = hidpp_send_rap_report(sc, 907 HIDPP_REPORT_ID_SHORT, 908 HIDPP_DEVICE_ID_RECEIVER, 909 HIDPP_GET_LONG_REGISTER, 910 HIDPP_REG_PAIRING_INFORMATION, 911 params, sizeof(params), &resp); 912 if (error) 913 return error; 914 915 switch (resp.rap.params[7]) { 916 case 0x00: 917 *type = "unknown"; 918 return 0; 919 case 0x01: 920 *type = "keyboard"; 921 return 0; 922 case 0x02: 923 *type = "mouse"; 924 return 0; 925 case 0x03: 926 *type = "numpad"; 927 return 0; 928 case 0x04: 929 *type = "presenter"; 930 return 0; 931 case 0x08: 932 *type = "trackball"; 933 return 0; 934 case 0x09: 935 *type = "touchpad"; 936 return 0; 937 } 938 return -ENOENT; 939 } 940 941 int 942 hidpp10_enable_notifications(struct uhidpp_softc *sc, uint8_t device_id) 943 { 944 struct uhidpp_report resp; 945 uint8_t params[3]; 946 947 /* Device reporting flags. */ 948 params[0] = HIDPP_NOTIF_DEVICE_BATTERY_STATUS; 949 /* Receiver reporting flags. */ 950 params[1] = HIDPP_NOTIF_RECEIVER_WIRELESS | 951 HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT; 952 /* Device reporting flags (continued). */ 953 params[2] = 0; 954 955 return hidpp_send_rap_report(sc, 956 HIDPP_REPORT_ID_SHORT, 957 device_id, 958 HIDPP_SET_REGISTER, 959 HIDPP_REG_ENABLE_REPORTS, 960 params, sizeof(params), &resp); 961 } 962 963 int 964 hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id, 965 uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type) 966 { 967 struct uhidpp_report resp; 968 uint8_t params[2] = { feature >> 8, feature & 0xff }; 969 int error; 970 971 error = hidpp_send_fap_report(sc, 972 HIDPP_REPORT_ID_LONG, 973 device_id, 974 HIDPP20_FEAT_ROOT_ID, 975 HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC, 976 params, sizeof(params), &resp); 977 if (error) 978 return error; 979 980 if (resp.fap.params[0] == 0) 981 return -ENOENT; 982 983 *feature_idx = resp.fap.params[0]; 984 *feature_type = resp.fap.params[1]; 985 return 0; 986 } 987 988 int 989 hidpp20_feature_get_count(struct uhidpp_softc *sc, uint8_t device_id, 990 uint8_t feature_idx, uint8_t *count) 991 { 992 struct uhidpp_report resp; 993 int error; 994 995 error = hidpp_send_fap_report(sc, 996 HIDPP_REPORT_ID_LONG, 997 device_id, 998 feature_idx, 999 HIDPP20_FEAT_FEATURE_COUNT_FUNC, 1000 NULL, 0, &resp); 1001 if (error) 1002 return error; 1003 1004 *count = resp.fap.params[0]; 1005 return 0; 1006 } 1007 1008 int 1009 hidpp20_feature_get_id(struct uhidpp_softc *sc, uint8_t device_id, 1010 uint8_t feature_idx, uint8_t idx, uint16_t *id, uint8_t *type) 1011 { 1012 struct uhidpp_report resp; 1013 uint8_t params[1] = { idx }; 1014 int error; 1015 1016 error = hidpp_send_fap_report(sc, 1017 HIDPP_REPORT_ID_LONG, 1018 device_id, 1019 feature_idx, 1020 HIDPP20_FEAT_FEATURE_ID_FUNC, 1021 params, sizeof(params), &resp); 1022 if (error) 1023 return error; 1024 1025 *id = bemtoh16(resp.fap.params); 1026 *type = resp.fap.params[2]; 1027 return 0; 1028 } 1029 1030 int 1031 hidpp20_battery_get_level_status(struct uhidpp_softc *sc, uint8_t device_id, 1032 uint8_t feature_idx, uint8_t *level, uint8_t *next_level, uint8_t *status) 1033 { 1034 struct uhidpp_report resp; 1035 int error; 1036 1037 error = hidpp_send_fap_report(sc, 1038 HIDPP_REPORT_ID_LONG, 1039 device_id, 1040 feature_idx, 1041 HIDPP20_FEAT_BATTERY_LEVEL_FUNC, 1042 NULL, 0, &resp); 1043 if (error) 1044 return error; 1045 1046 *level = resp.fap.params[0]; 1047 *next_level = resp.fap.params[1]; 1048 *status = resp.fap.params[2]; 1049 return 0; 1050 } 1051 1052 int 1053 hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id, 1054 uint8_t feature_idx, uint8_t *nlevels) 1055 { 1056 struct uhidpp_report resp; 1057 int error; 1058 1059 error = hidpp_send_fap_report(sc, 1060 HIDPP_REPORT_ID_LONG, 1061 device_id, 1062 feature_idx, 1063 HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC, 1064 NULL, 0, &resp); 1065 if (error) 1066 return error; 1067 *nlevels = resp.fap.params[0]; 1068 return 0; 1069 } 1070 1071 int 1072 hidpp_send_validate(uint8_t report_id, int nparams) 1073 { 1074 if (report_id == HIDPP_REPORT_ID_SHORT) { 1075 if (nparams > HIDPP_REPORT_SHORT_PARAMS_MAX) 1076 return -EMSGSIZE; 1077 } else if (report_id == HIDPP_REPORT_ID_LONG) { 1078 if (nparams > HIDPP_REPORT_LONG_PARAMS_MAX) 1079 return -EMSGSIZE; 1080 } else { 1081 return -EINVAL; 1082 } 1083 return 0; 1084 } 1085 1086 int 1087 hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id, 1088 uint8_t device_id, uint8_t feature_idx, uint8_t funcidx_swid, 1089 uint8_t *params, int nparams, struct uhidpp_report *resp) 1090 { 1091 struct uhidpp_report req; 1092 int error; 1093 1094 error = hidpp_send_validate(report_id, nparams); 1095 if (error) 1096 return error; 1097 1098 memset(&req, 0, sizeof(req)); 1099 req.device_id = device_id; 1100 req.fap.feature_idx = feature_idx; 1101 req.fap.funcidx_swid = 1102 (funcidx_swid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID; 1103 memcpy(req.fap.params, params, nparams); 1104 return hidpp_send_report(sc, report_id, &req, resp); 1105 } 1106 1107 int 1108 hidpp_send_rap_report(struct uhidpp_softc *sc, uint8_t report_id, 1109 uint8_t device_id, uint8_t sub_id, uint8_t reg_address, 1110 uint8_t *params, int nparams, struct uhidpp_report *resp) 1111 { 1112 struct uhidpp_report req; 1113 int error; 1114 1115 error = hidpp_send_validate(report_id, nparams); 1116 if (error) 1117 return error; 1118 1119 memset(&req, 0, sizeof(req)); 1120 req.device_id = device_id; 1121 req.rap.sub_id = sub_id; 1122 req.rap.reg_address = reg_address; 1123 memcpy(req.rap.params, params, nparams); 1124 return hidpp_send_report(sc, report_id, &req, resp); 1125 } 1126 1127 int 1128 hidpp_send_report(struct uhidpp_softc *sc, uint8_t report_id, 1129 struct uhidpp_report *req, struct uhidpp_report *resp) 1130 { 1131 int error, len, n; 1132 1133 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 1134 1135 if (report_id == HIDPP_REPORT_ID_SHORT) 1136 len = HIDPP_REPORT_SHORT_LENGTH; 1137 else if (report_id == HIDPP_REPORT_ID_LONG) 1138 len = HIDPP_REPORT_LONG_LENGTH; 1139 else 1140 return -EINVAL; 1141 1142 DREPORT(__func__, report_id, (const unsigned char *)req, len); 1143 1144 /* Wait until any ongoing command has completed. */ 1145 while (sc->sc_resp_state != UHIDPP_RESP_NONE) 1146 uhidpp_sleep(sc, INFSLP); 1147 sc->sc_req = req; 1148 sc->sc_resp = resp; 1149 sc->sc_resp_state = UHIDPP_RESP_WAIT; 1150 /* 1151 * The mutex must be temporarily released while calling 1152 * uhidev_set_report() as it might end up sleeping. 1153 */ 1154 mtx_leave(&sc->sc_mtx); 1155 1156 n = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 1157 report_id, req, len); 1158 1159 mtx_enter(&sc->sc_mtx); 1160 if (len != n) { 1161 error = -EBUSY; 1162 goto out; 1163 } 1164 /* 1165 * The interrupt could already have been received while the mutex was 1166 * released. Otherwise, wait for it. 1167 */ 1168 if (sc->sc_resp_state == UHIDPP_RESP_WAIT) { 1169 /* Timeout taken from the hid-logitech-hidpp Linux driver. */ 1170 error = uhidpp_sleep(sc, SEC_TO_NSEC(5)); 1171 if (error) { 1172 error = -error; 1173 goto out; 1174 } 1175 } 1176 1177 if (sc->sc_resp_state == UHIDPP_RESP_ERROR) 1178 error = -EIO; 1179 else if (sc->sc_resp_state == HIDPP_REPORT_ID_SHORT && 1180 resp->rap.sub_id == HIDPP_ERROR) 1181 error = resp->rap.params[1]; 1182 else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG && 1183 resp->fap.feature_idx == HIDPP20_ERROR) 1184 error = resp->fap.params[1]; 1185 1186 out: 1187 sc->sc_req = NULL; 1188 sc->sc_resp = NULL; 1189 sc->sc_resp_state = UHIDPP_RESP_NONE; 1190 wakeup(sc); 1191 return error; 1192 } 1193 1194 #ifdef UHIDPP_DEBUG 1195 1196 void 1197 uhidd_dump_report(const char *prefix, uint8_t repid, const unsigned char *buf, 1198 u_int buflen) 1199 { 1200 u_int i; 1201 1202 printf("%s: %02x ", prefix, repid); 1203 for (i = 0; i < buflen; i++) { 1204 printf("%02x%s", buf[i], 1205 i == 2 ? " [" : (i + 1 < buflen ? " " : "")); 1206 } 1207 printf("]\n"); 1208 } 1209 1210 #endif 1211