1 /* $OpenBSD: uhidpp.c,v 1.7 2021/02/11 11:03: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_IDX 0x00 118 #define HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC 0x00 119 120 #define HIDPP20_FEAT_BATTERY_IDX 0x1000 121 #define HIDPP20_FEAT_BATTERY_LEVEL_FUNC 0x0000 122 #define HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC 0x0001 123 124 /* HID++ 2.0 error codes. */ 125 #define HIDPP20_ERROR 0xff 126 #define HIDPP20_ERROR_NO_ERROR 0x00 127 #define HIDPP20_ERROR_UNKNOWN 0x01 128 #define HIDPP20_ERROR_INVALID_ARGUMENT 0x02 129 #define HIDPP20_ERROR_OUT_OF_RANGE 0x03 130 #define HIDPP20_ERROR_HARDWARE_ERROR 0x04 131 #define HIDPP20_ERROR_LOGITECH_INTERNAL 0x05 132 #define HIDPP20_ERROR_INVALID_FEATURE_INDEX 0x06 133 #define HIDPP20_ERROR_INVALID_FUNCTION_ID 0x07 134 #define HIDPP20_ERROR_BUSY 0x08 135 #define HIDPP20_ERROR_UNSUPPORTED 0x09 136 137 /* 138 * Sentinels used for interrupt response synchronization. The values must be 139 * disjoint from existing report IDs. 140 */ 141 #define UHIDPP_RESP_NONE 0 142 #define UHIDPP_RESP_WAIT 1 143 #define UHIDPP_RESP_ERROR 2 144 145 /* Maximum number of devices associated with a single receiver. */ 146 #define UHIDPP_NDEVICES 6 147 148 /* Maximum number of pending notifications. */ 149 #define UHIDPP_NNOTIFICATIONS 4 150 151 /* Number of sensors per paired device. */ 152 #define UHIDPP_NSENSORS 2 153 154 /* Feature access report used by the HID++ 2.0 (and greater) protocol. */ 155 struct fap { 156 uint8_t feature_idx; 157 uint8_t funcidx_swid; 158 uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX]; 159 }; 160 161 /* 162 * Register access report used by the HID++ 1.0 protocol. Receivers always uses 163 * this type of report. 164 */ 165 struct rap { 166 uint8_t sub_id; 167 uint8_t reg_address; 168 uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX]; 169 }; 170 171 struct uhidpp_report { 172 uint8_t device_id; 173 union { 174 struct fap fap; 175 struct rap rap; 176 }; 177 } __packed; 178 179 struct uhidpp_notification { 180 struct uhidpp_report n_rep; 181 unsigned int n_id; 182 }; 183 184 struct uhidpp_device { 185 uint8_t d_id; 186 uint8_t d_connected; 187 uint8_t d_major; 188 uint8_t d_minor; 189 struct { 190 struct ksensor b_sens[UHIDPP_NSENSORS]; 191 uint8_t b_feature_idx; 192 uint8_t b_level; 193 uint8_t b_next_level; 194 uint8_t b_status; 195 uint8_t b_nlevels; 196 } d_battery; 197 }; 198 199 /* 200 * Locking: 201 * [m] sc_mtx 202 */ 203 struct uhidpp_softc { 204 struct uhidev sc_hdev; 205 struct usbd_device *sc_udev; 206 207 struct mutex sc_mtx; 208 209 struct uhidpp_device sc_devices[UHIDPP_NDEVICES]; 210 /* [m] connected devices */ 211 212 struct uhidpp_notification sc_notifications[UHIDPP_NNOTIFICATIONS]; 213 /* [m] pending notifications */ 214 215 struct usb_task sc_task; /* [m] notification task */ 216 217 struct ksensordev sc_sensdev; /* [m] */ 218 struct sensor_task *sc_senstsk; /* [m] */ 219 220 struct uhidpp_report *sc_req; /* [m] synchronous request buffer */ 221 struct uhidpp_report *sc_resp; /* [m] synchronous response buffer */ 222 u_int sc_resp_state; /* [m] synchronous response state */ 223 224 }; 225 226 int uhidpp_match(struct device *, void *, void *); 227 void uhidpp_attach(struct device *, struct device *, void *); 228 int uhidpp_detach(struct device *, int flags); 229 void uhidpp_intr(struct uhidev *addr, void *ibuf, u_int len); 230 void uhidpp_refresh(void *); 231 void uhidpp_task(void *); 232 int uhidpp_sleep(struct uhidpp_softc *, uint64_t); 233 234 void uhidpp_device_connect(struct uhidpp_softc *, struct uhidpp_device *); 235 void uhidpp_device_refresh(struct uhidpp_softc *, struct uhidpp_device *); 236 237 struct uhidpp_notification *uhidpp_claim_notification(struct uhidpp_softc *); 238 int uhidpp_consume_notification(struct uhidpp_softc *, struct uhidpp_report *); 239 int uhidpp_is_notification(struct uhidpp_softc *, struct uhidpp_report *); 240 241 int hidpp_get_protocol_version(struct uhidpp_softc *, uint8_t, uint8_t *, 242 uint8_t *); 243 244 int hidpp10_get_name(struct uhidpp_softc *, uint8_t, char *, size_t); 245 int hidpp10_get_serial(struct uhidpp_softc *, uint8_t, uint8_t *, size_t); 246 int hidpp10_get_type(struct uhidpp_softc *, uint8_t, const char **); 247 int hidpp10_enable_notifications(struct uhidpp_softc *, uint8_t); 248 249 int hidpp20_root_get_feature(struct uhidpp_softc *, uint8_t, uint16_t, 250 uint8_t *, uint8_t *); 251 int hidpp20_battery_get_level_status(struct uhidpp_softc *, uint8_t, uint8_t, 252 uint8_t *, uint8_t *, uint8_t *); 253 int hidpp20_battery_get_capability(struct uhidpp_softc *, uint8_t, uint8_t, 254 uint8_t *); 255 256 int hidpp_send_validate(uint8_t, int); 257 int hidpp_send_rap_report(struct uhidpp_softc *, uint8_t, uint8_t, 258 uint8_t, uint8_t, uint8_t *, int, struct uhidpp_report *); 259 int hidpp_send_fap_report(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t, 260 uint8_t, uint8_t *, int, struct uhidpp_report *); 261 int hidpp_send_report(struct uhidpp_softc *, uint8_t, struct uhidpp_report *, 262 struct uhidpp_report *); 263 264 struct cfdriver uhidpp_cd = { 265 NULL, "uhidpp", DV_DULL 266 }; 267 268 const struct cfattach uhidpp_ca = { 269 sizeof(struct uhidpp_softc), 270 uhidpp_match, 271 uhidpp_attach, 272 uhidpp_detach, 273 }; 274 275 static const struct usb_devno uhidpp_devs[] = { 276 { USB_VENDOR_LOGITECH, USB_PRODUCT_ANY }, 277 }; 278 279 int 280 uhidpp_match(struct device *parent, void *match, void *aux) 281 { 282 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 283 void *desc; 284 int descsiz, siz; 285 286 if (uha->reportid != HIDPP_REPORT_ID_SHORT && 287 uha->reportid != HIDPP_REPORT_ID_LONG) 288 return UMATCH_NONE; 289 290 if (usb_lookup(uhidpp_devs, 291 uha->uaa->vendor, uha->uaa->product) == NULL) 292 return UMATCH_NONE; 293 294 uhidev_get_report_desc(uha->parent, &desc, &descsiz); 295 siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_SHORT); 296 if (siz != HIDPP_REPORT_SHORT_LENGTH) 297 return UMATCH_NONE; 298 siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_LONG); 299 if (siz != HIDPP_REPORT_LONG_LENGTH) 300 return UMATCH_NONE; 301 302 return UMATCH_VENDOR_PRODUCT; 303 } 304 305 void 306 uhidpp_attach(struct device *parent, struct device *self, void *aux) 307 { 308 struct uhidpp_softc *sc = (struct uhidpp_softc *)self; 309 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 310 struct usb_attach_arg *uaa = uha->uaa; 311 int error, i; 312 int npaired = 0; 313 314 sc->sc_hdev.sc_intr = uhidpp_intr; 315 sc->sc_hdev.sc_udev = uaa->device; 316 sc->sc_hdev.sc_parent = uha->parent; 317 sc->sc_hdev.sc_report_id = uha->reportid; 318 /* The largest supported report dictates the sizes. */ 319 sc->sc_hdev.sc_isize = HIDPP_REPORT_LONG_LENGTH; 320 sc->sc_hdev.sc_osize = HIDPP_REPORT_LONG_LENGTH; 321 322 sc->sc_udev = uaa->device; 323 324 mtx_init(&sc->sc_mtx, IPL_USB); 325 326 sc->sc_resp = NULL; 327 sc->sc_resp_state = UHIDPP_RESP_NONE; 328 329 error = uhidev_open(&sc->sc_hdev); 330 if (error) { 331 printf(" open error %d\n", error); 332 return; 333 } 334 335 usb_init_task(&sc->sc_task, uhidpp_task, sc, USB_TASK_TYPE_GENERIC); 336 337 mtx_enter(&sc->sc_mtx); 338 339 /* 340 * Wire up report device handlers before issuing commands to the device 341 * in order to receive responses. Necessary as uhidev by default 342 * performs the wiring after the attach routine has returned. 343 */ 344 error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev, 345 HIDPP_REPORT_ID_SHORT); 346 if (error) { 347 printf(" short report error %d\n", error); 348 return; 349 } 350 error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev, 351 HIDPP_REPORT_ID_LONG); 352 if (error) { 353 printf(" long report error %d\n", error); 354 return; 355 } 356 357 /* Probe paired devices. */ 358 for (i = 0; i < UHIDPP_NDEVICES; i++) { 359 char name[16]; 360 uint8_t serial[4]; 361 struct uhidpp_device *dev = &sc->sc_devices[i]; 362 const char *type; 363 uint8_t device_id = i + 1; 364 365 dev->d_id = device_id; 366 367 if (hidpp10_get_serial(sc, device_id, serial, sizeof(serial)) || 368 hidpp10_get_type(sc, device_id, &type) || 369 hidpp10_get_name(sc, device_id, name, sizeof(name))) 370 continue; 371 372 if (npaired > 0) 373 printf(","); 374 printf(" device %d", device_id); 375 printf(" %s", type); 376 printf(" \"%s\"", name); 377 printf(" serial %02x-%02x-%02x-%02x", 378 serial[0], serial[1], serial[2], serial[3]); 379 npaired++; 380 } 381 382 /* Enable notifications for the receiver. */ 383 error = hidpp10_enable_notifications(sc, HIDPP_DEVICE_ID_RECEIVER); 384 if (error) 385 printf(" error %d", error); 386 387 printf("\n"); 388 389 strlcpy(sc->sc_sensdev.xname, sc->sc_hdev.sc_dev.dv_xname, 390 sizeof(sc->sc_sensdev.xname)); 391 sensordev_install(&sc->sc_sensdev); 392 sc->sc_senstsk = sensor_task_register(sc, uhidpp_refresh, 6); 393 394 mtx_leave(&sc->sc_mtx); 395 } 396 397 int 398 uhidpp_detach(struct device *self, int flags) 399 { 400 struct uhidpp_softc *sc = (struct uhidpp_softc *)self; 401 int i, j; 402 403 usb_rem_wait_task(sc->sc_udev, &sc->sc_task); 404 405 if (sc->sc_senstsk != NULL) 406 sensor_task_unregister(sc->sc_senstsk); 407 408 KASSERT(sc->sc_resp_state == UHIDPP_RESP_NONE); 409 410 sensordev_deinstall(&sc->sc_sensdev); 411 412 for (i = 0; i < UHIDPP_NDEVICES; i++) { 413 struct uhidpp_device *dev = &sc->sc_devices[i]; 414 415 if (!dev->d_connected) 416 continue; 417 418 for (j = 0; j < UHIDPP_NSENSORS; j++) 419 sensor_detach(&sc->sc_sensdev, &dev->d_battery.b_sens[j]); 420 } 421 422 /* 423 * Since this driver has multiple device handlers attached, remove all 424 * of them preventing the uhidev parent from calling this detach routine 425 * more than once. 426 */ 427 uhidev_unset_report_dev(sc->sc_hdev.sc_parent, HIDPP_REPORT_ID_SHORT); 428 uhidev_unset_report_dev(sc->sc_hdev.sc_parent, HIDPP_REPORT_ID_LONG); 429 430 uhidev_close(&sc->sc_hdev); 431 432 return 0; 433 } 434 435 void 436 uhidpp_intr(struct uhidev *addr, void *buf, u_int len) 437 { 438 struct uhidpp_softc *sc = (struct uhidpp_softc *)addr; 439 struct uhidpp_report *rep = buf; 440 int dowake = 0; 441 uint8_t repid; 442 443 /* 444 * Ugliness ahead as the report ID is stripped of by uhidev_intr() but 445 * needed to determine if an error occurred. 446 * Note that an error response is always a short report even if the 447 * command that caused the error is a long report. 448 */ 449 repid = ((uint8_t *)buf)[-1]; 450 451 DREPORT(__func__, repid, buf, len); 452 453 mtx_enter(&sc->sc_mtx); 454 if (uhidpp_is_notification(sc, rep)) { 455 struct uhidpp_notification *ntf; 456 457 ntf = uhidpp_claim_notification(sc); 458 if (ntf != NULL) { 459 memcpy(&ntf->n_rep, buf, len); 460 usb_add_task(sc->sc_udev, &sc->sc_task); 461 } else { 462 DPRINTF("%s: too many notifications", __func__); 463 } 464 } else { 465 KASSERT(sc->sc_resp_state == UHIDPP_RESP_WAIT); 466 dowake = 1; 467 sc->sc_resp_state = repid; 468 memcpy(sc->sc_resp, buf, len); 469 } 470 mtx_leave(&sc->sc_mtx); 471 if (dowake) 472 wakeup(sc); 473 } 474 475 void 476 uhidpp_refresh(void *arg) 477 { 478 struct uhidpp_softc *sc = arg; 479 int i; 480 481 mtx_enter(&sc->sc_mtx); 482 for (i = 0; i < UHIDPP_NDEVICES; i++) { 483 struct uhidpp_device *dev = &sc->sc_devices[i]; 484 485 if (dev->d_connected) 486 uhidpp_device_refresh(sc, dev); 487 } 488 mtx_leave(&sc->sc_mtx); 489 } 490 491 void 492 uhidpp_task(void *arg) 493 { 494 struct uhidpp_softc *sc = arg; 495 496 mtx_enter(&sc->sc_mtx); 497 for (;;) { 498 struct uhidpp_report rep; 499 struct uhidpp_device *dev; 500 501 if (uhidpp_consume_notification(sc, &rep)) 502 break; 503 504 DPRINTF("%s: device_id=%d, sub_id=%02x\n", 505 __func__, rep.device_id, rep.rap.sub_id); 506 507 if (rep.device_id == 0 || rep.device_id > UHIDPP_NDEVICES) { 508 DPRINTF("%s: invalid device\n", __func__); 509 continue; 510 } 511 dev = &sc->sc_devices[rep.device_id - 1]; 512 513 switch (rep.rap.sub_id) { 514 case 0x0e: /* leds */ 515 case 0x40: /* disconnect */ 516 case 0x4b: /* pairing accepted */ 517 break; 518 case 0x41: /* connect */ 519 /* 520 * Do nothing if the link is reported to be out of 521 * range. This happens when a device has been idle for a 522 * while. 523 */ 524 if (HIDPP_LINK_STATUS(rep.rap.params[0])) 525 uhidpp_device_connect(sc, dev); 526 break; 527 } 528 } 529 mtx_leave(&sc->sc_mtx); 530 } 531 532 int 533 uhidpp_sleep(struct uhidpp_softc *sc, uint64_t nsecs) 534 { 535 return msleep_nsec(sc, &sc->sc_mtx, PZERO, "uhidpp", nsecs); 536 } 537 538 void 539 uhidpp_device_connect(struct uhidpp_softc *sc, struct uhidpp_device *dev) 540 { 541 struct ksensor *sens; 542 int error; 543 uint8_t feature_type; 544 545 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 546 547 /* A connected device will continously send connect events. */ 548 if (dev->d_connected) 549 return; 550 551 error = hidpp_get_protocol_version(sc, dev->d_id, 552 &dev->d_major, &dev->d_minor); 553 if (error) { 554 DPRINTF("%s: protocol version failure: device_id=%d, " 555 "error=%d\n", 556 __func__, dev->d_id, error); 557 return; 558 } 559 560 DPRINTF("%s: device_id=%d, version=%d.%d\n", 561 __func__, dev->d_id, dev->d_major, dev->d_minor); 562 563 if (dev->d_major >= 2) { 564 error = hidpp20_root_get_feature(sc, dev->d_id, 565 HIDPP20_FEAT_BATTERY_IDX, 566 &dev->d_battery.b_feature_idx, &feature_type); 567 if (error) { 568 DPRINTF("%s: battery feature index failure: " 569 "device_id=%d, error=%d\n", 570 __func__, dev->d_id, error); 571 return; 572 } 573 574 error = hidpp20_battery_get_capability(sc, dev->d_id, 575 dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels); 576 if (error) { 577 DPRINTF("%s: battery capability failure: device_id=%d, " 578 "error=%d\n", __func__, dev->d_id, error); 579 return; 580 } 581 582 } else { 583 return; 584 } 585 586 sens = &dev->d_battery.b_sens[0]; 587 strlcpy(sens->desc, "battery level", sizeof(sens->desc)); 588 sens->type = SENSOR_PERCENT; 589 sens->flags = SENSOR_FUNKNOWN; 590 sensor_attach(&sc->sc_sensdev, sens); 591 592 sens = &dev->d_battery.b_sens[1]; 593 strlcpy(sens->desc, "battery levels", sizeof(sens->desc)); 594 sens->type = SENSOR_INTEGER; 595 sens->value = dev->d_battery.b_nlevels; 596 sensor_attach(&sc->sc_sensdev, sens); 597 598 dev->d_connected = 1; 599 uhidpp_device_refresh(sc, dev); 600 } 601 602 void 603 uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev) 604 { 605 int error; 606 607 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 608 609 if (dev->d_major >= 2) { 610 error = hidpp20_battery_get_level_status(sc, dev->d_id, 611 dev->d_battery.b_feature_idx, 612 &dev->d_battery.b_level, &dev->d_battery.b_next_level, 613 &dev->d_battery.b_status); 614 if (error) { 615 DPRINTF("%s: battery status failure: device_id=%d, " 616 "error=%d\n", 617 __func__, dev->d_id, error); 618 return; 619 } 620 621 dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000; 622 dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN; 623 if (dev->d_battery.b_nlevels < 10) { 624 /* 625 * According to the HID++ 2.0 specification, less than 626 * 10 levels should be mapped to the following 4 levels: 627 * 628 * [0, 10] critical 629 * [11, 30] low 630 * [31, 80] good 631 * [81, 100] full 632 * 633 * Since sensors are limited to 3 valid statuses, clamp 634 * it even further. 635 */ 636 if (dev->d_battery.b_level <= 10) 637 dev->d_battery.b_sens[0].status = SENSOR_S_CRIT; 638 else if (dev->d_battery.b_level <= 30) 639 dev->d_battery.b_sens[0].status = SENSOR_S_WARN; 640 else 641 dev->d_battery.b_sens[0].status = SENSOR_S_OK; 642 } else { 643 /* 644 * XXX the device supports battery mileage. The current 645 * level must be checked against resp.fap.params[3] 646 * given by hidpp20_battery_get_capability(). 647 */ 648 dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN; 649 } 650 } 651 } 652 653 /* 654 * Returns the next available notification slot, if available. 655 */ 656 struct uhidpp_notification * 657 uhidpp_claim_notification(struct uhidpp_softc *sc) 658 { 659 struct uhidpp_notification *ntf = NULL; 660 int nclaimed = 0; 661 int i; 662 663 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 664 665 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 666 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 667 668 if (tmp->n_id > 0) 669 nclaimed++; 670 else if (ntf == NULL) 671 ntf = tmp; 672 } 673 674 if (ntf == NULL) 675 return NULL; 676 ntf->n_id = nclaimed + 1; 677 return ntf; 678 } 679 680 /* 681 * Consume the first unhandled notification, if present. 682 */ 683 int 684 uhidpp_consume_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 685 { 686 struct uhidpp_notification *ntf = NULL; 687 int i; 688 689 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 690 691 for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) { 692 struct uhidpp_notification *tmp = &sc->sc_notifications[i]; 693 694 if (tmp->n_id > 0 && (ntf == NULL || tmp->n_id < ntf->n_id)) 695 ntf = tmp; 696 } 697 if (ntf == NULL) 698 return 1; 699 700 memcpy(rep, &ntf->n_rep, sizeof(*rep)); 701 ntf->n_id = 0; 702 return 0; 703 } 704 705 706 /* 707 * Returns non-zero if the given report is a notification. Otherwise, it must be 708 * a response. 709 */ 710 int 711 uhidpp_is_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep) 712 { 713 /* Not waiting for a response. */ 714 if (sc->sc_req == NULL) 715 return 1; 716 717 /* Everything except the parameters must be repeated in a response. */ 718 if (sc->sc_req->device_id == rep->device_id && 719 sc->sc_req->rap.sub_id == rep->rap.sub_id && 720 sc->sc_req->rap.reg_address == rep->rap.reg_address) 721 return 0; 722 723 /* An error must always be a response. */ 724 if ((rep->rap.sub_id == HIDPP_ERROR || 725 rep->fap.feature_idx == HIDPP20_ERROR) && 726 rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx && 727 rep->fap.params[0] == sc->sc_req->fap.funcidx_swid) 728 return 0; 729 730 return 1; 731 } 732 733 int 734 hidpp_get_protocol_version(struct uhidpp_softc *sc, uint8_t device_id, 735 uint8_t *major, uint8_t *minor) 736 { 737 struct uhidpp_report resp; 738 uint8_t params[3] = { 0, 0, HIDPP_FEAT_ROOT_PING_DATA }; 739 int error; 740 741 error = hidpp_send_fap_report(sc, 742 HIDPP_REPORT_ID_SHORT, 743 device_id, 744 HIDPP_FEAT_ROOT_IDX, 745 HIDPP_FEAT_ROOT_PING_FUNC, 746 params, sizeof(params), &resp); 747 if (error == HIDPP_ERROR_INVALID_SUBID) { 748 *major = 1; 749 *minor = 0; 750 return 0; 751 } 752 if (error) 753 return error; 754 if (resp.rap.params[2] != HIDPP_FEAT_ROOT_PING_DATA) 755 return -EPROTO; 756 757 *major = resp.fap.params[0]; 758 *minor = resp.fap.params[1]; 759 return 0; 760 } 761 762 int 763 hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id, 764 char *buf, size_t bufsiz) 765 { 766 struct uhidpp_report resp; 767 int error; 768 uint8_t params[1] = { 0x40 + (device_id - 1) }; 769 uint8_t len; 770 771 error = hidpp_send_rap_report(sc, 772 HIDPP_REPORT_ID_SHORT, 773 HIDPP_DEVICE_ID_RECEIVER, 774 HIDPP_GET_LONG_REGISTER, 775 HIDPP_REG_PAIRING_INFORMATION, 776 params, sizeof(params), &resp); 777 if (error) 778 return error; 779 780 len = resp.rap.params[1]; 781 if (len + 2 > sizeof(resp.rap.params)) 782 return -ENAMETOOLONG; 783 if (len > bufsiz - 1) 784 len = bufsiz - 1; 785 memcpy(buf, &resp.rap.params[2], len); 786 buf[len] = '\0'; 787 return 0; 788 } 789 790 int 791 hidpp10_get_serial(struct uhidpp_softc *sc, uint8_t device_id, 792 uint8_t *buf, size_t bufsiz) 793 { 794 struct uhidpp_report resp; 795 int error; 796 uint8_t params[1] = { 0x30 + (device_id - 1) }; 797 uint8_t len; 798 799 error = hidpp_send_rap_report(sc, 800 HIDPP_REPORT_ID_SHORT, 801 HIDPP_DEVICE_ID_RECEIVER, 802 HIDPP_GET_LONG_REGISTER, 803 HIDPP_REG_PAIRING_INFORMATION, 804 params, sizeof(params), &resp); 805 if (error) 806 return error; 807 808 len = 4; 809 if (bufsiz < len) 810 len = bufsiz; 811 memcpy(buf, &resp.rap.params[1], len); 812 return 0; 813 } 814 815 int 816 hidpp10_get_type(struct uhidpp_softc *sc, uint8_t device_id, const char **type) 817 { 818 struct uhidpp_report resp; 819 int error; 820 uint8_t params[1] = { 0x20 + (device_id - 1) }; 821 822 error = hidpp_send_rap_report(sc, 823 HIDPP_REPORT_ID_SHORT, 824 HIDPP_DEVICE_ID_RECEIVER, 825 HIDPP_GET_LONG_REGISTER, 826 HIDPP_REG_PAIRING_INFORMATION, 827 params, sizeof(params), &resp); 828 if (error) 829 return error; 830 831 switch (resp.rap.params[7]) { 832 case 0x00: 833 *type = "unknown"; 834 return 0; 835 case 0x01: 836 *type = "keyboard"; 837 return 0; 838 case 0x02: 839 *type = "mouse"; 840 return 0; 841 case 0x03: 842 *type = "numpad"; 843 return 0; 844 case 0x04: 845 *type = "presenter"; 846 return 0; 847 case 0x08: 848 *type = "trackball"; 849 return 0; 850 case 0x09: 851 *type = "touchpad"; 852 return 0; 853 } 854 return -ENOENT; 855 } 856 857 int 858 hidpp10_enable_notifications(struct uhidpp_softc *sc, uint8_t device_id) 859 { 860 struct uhidpp_report resp; 861 uint8_t params[3]; 862 863 /* Device reporting flags. */ 864 params[0] = HIDPP_NOTIF_DEVICE_BATTERY_STATUS; 865 /* Receiver reporting flags. */ 866 params[1] = HIDPP_NOTIF_RECEIVER_WIRELESS | 867 HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT; 868 /* Device reporting flags (continued). */ 869 params[2] = 0; 870 871 return hidpp_send_rap_report(sc, 872 HIDPP_REPORT_ID_SHORT, 873 device_id, 874 HIDPP_SET_REGISTER, 875 HIDPP_REG_ENABLE_REPORTS, 876 params, sizeof(params), &resp); 877 } 878 879 int 880 hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id, 881 uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type) 882 { 883 struct uhidpp_report resp; 884 uint8_t params[2] = { feature >> 8, feature & 0xff }; 885 int error; 886 887 error = hidpp_send_fap_report(sc, 888 HIDPP_REPORT_ID_LONG, 889 device_id, 890 HIDPP20_FEAT_ROOT_IDX, 891 HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC, 892 params, sizeof(params), &resp); 893 if (error) 894 return error; 895 896 if (resp.fap.params[0] == 0) 897 return -ENOENT; 898 899 *feature_idx = resp.fap.params[0]; 900 *feature_type = resp.fap.params[1]; 901 return 0; 902 } 903 904 int 905 hidpp20_battery_get_level_status(struct uhidpp_softc *sc, uint8_t device_id, 906 uint8_t feature_idx, uint8_t *level, uint8_t *next_level, uint8_t *status) 907 { 908 struct uhidpp_report resp; 909 int error; 910 911 error = hidpp_send_fap_report(sc, 912 HIDPP_REPORT_ID_LONG, 913 device_id, 914 feature_idx, 915 HIDPP20_FEAT_BATTERY_LEVEL_FUNC, 916 NULL, 0, &resp); 917 if (error) 918 return error; 919 920 *level = resp.fap.params[0]; 921 *next_level = resp.fap.params[1]; 922 *status = resp.fap.params[2]; 923 return 0; 924 } 925 926 int 927 hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id, 928 uint8_t feature_idx, uint8_t *nlevels) 929 { 930 struct uhidpp_report resp; 931 int error; 932 933 error = hidpp_send_fap_report(sc, 934 HIDPP_REPORT_ID_LONG, 935 device_id, 936 feature_idx, 937 HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC, 938 NULL, 0, &resp); 939 if (error) 940 return error; 941 *nlevels = resp.fap.params[0]; 942 return 0; 943 } 944 945 int 946 hidpp_send_validate(uint8_t report_id, int nparams) 947 { 948 if (report_id == HIDPP_REPORT_ID_SHORT) { 949 if (nparams > HIDPP_REPORT_SHORT_PARAMS_MAX) 950 return -EMSGSIZE; 951 } else if (report_id == HIDPP_REPORT_ID_LONG) { 952 if (nparams > HIDPP_REPORT_LONG_PARAMS_MAX) 953 return -EMSGSIZE; 954 } else { 955 return -EINVAL; 956 } 957 return 0; 958 } 959 960 int 961 hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id, 962 uint8_t device_id, uint8_t feature_idx, uint8_t funcidx_swid, 963 uint8_t *params, int nparams, struct uhidpp_report *resp) 964 { 965 struct uhidpp_report req; 966 int error; 967 968 error = hidpp_send_validate(report_id, nparams); 969 if (error) 970 return error; 971 972 memset(&req, 0, sizeof(req)); 973 req.device_id = device_id; 974 req.fap.feature_idx = feature_idx; 975 req.fap.funcidx_swid = 976 (funcidx_swid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID; 977 memcpy(req.fap.params, params, nparams); 978 return hidpp_send_report(sc, report_id, &req, resp); 979 } 980 981 int 982 hidpp_send_rap_report(struct uhidpp_softc *sc, uint8_t report_id, 983 uint8_t device_id, uint8_t sub_id, uint8_t reg_address, 984 uint8_t *params, int nparams, struct uhidpp_report *resp) 985 { 986 struct uhidpp_report req; 987 int error; 988 989 error = hidpp_send_validate(report_id, nparams); 990 if (error) 991 return error; 992 993 memset(&req, 0, sizeof(req)); 994 req.device_id = device_id; 995 req.rap.sub_id = sub_id; 996 req.rap.reg_address = reg_address; 997 memcpy(req.rap.params, params, nparams); 998 return hidpp_send_report(sc, report_id, &req, resp); 999 } 1000 1001 int 1002 hidpp_send_report(struct uhidpp_softc *sc, uint8_t report_id, 1003 struct uhidpp_report *req, struct uhidpp_report *resp) 1004 { 1005 int error, len, n; 1006 1007 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 1008 1009 if (report_id == HIDPP_REPORT_ID_SHORT) 1010 len = HIDPP_REPORT_SHORT_LENGTH; 1011 else if (report_id == HIDPP_REPORT_ID_LONG) 1012 len = HIDPP_REPORT_LONG_LENGTH; 1013 else 1014 return -EINVAL; 1015 1016 DREPORT(__func__, report_id, (const unsigned char *)req, len); 1017 1018 /* Wait until any ongoing command has completed. */ 1019 while (sc->sc_resp_state != UHIDPP_RESP_NONE) 1020 uhidpp_sleep(sc, INFSLP); 1021 sc->sc_req = req; 1022 sc->sc_resp = resp; 1023 sc->sc_resp_state = UHIDPP_RESP_WAIT; 1024 /* 1025 * The mutex must be temporarily released while calling 1026 * uhidev_set_report() as it might end up sleeping. 1027 */ 1028 mtx_leave(&sc->sc_mtx); 1029 1030 n = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 1031 report_id, req, len); 1032 1033 mtx_enter(&sc->sc_mtx); 1034 if (len != n) { 1035 error = -EBUSY; 1036 goto out; 1037 } 1038 /* 1039 * The interrupt could already have been received while the mutex was 1040 * released. Otherwise, wait for it. 1041 */ 1042 if (sc->sc_resp_state == UHIDPP_RESP_WAIT) { 1043 /* Timeout taken from the hid-logitech-hidpp Linux driver. */ 1044 error = uhidpp_sleep(sc, SEC_TO_NSEC(5)); 1045 if (error) { 1046 error = -error; 1047 goto out; 1048 } 1049 } 1050 1051 if (sc->sc_resp_state == UHIDPP_RESP_ERROR) 1052 error = -EIO; 1053 else if (sc->sc_resp_state == HIDPP_REPORT_ID_SHORT && 1054 resp->rap.sub_id == HIDPP_ERROR) 1055 error = resp->rap.params[1]; 1056 else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG && 1057 resp->fap.feature_idx == HIDPP20_ERROR) 1058 error = resp->fap.params[1]; 1059 1060 out: 1061 sc->sc_req = NULL; 1062 sc->sc_resp = NULL; 1063 sc->sc_resp_state = UHIDPP_RESP_NONE; 1064 wakeup(sc); 1065 return error; 1066 } 1067 1068 #ifdef UHIDPP_DEBUG 1069 1070 void 1071 uhidd_dump_report(const char *prefix, uint8_t repid, const unsigned char *buf, 1072 u_int buflen) 1073 { 1074 u_int i; 1075 1076 printf("%s: %02x ", prefix, repid); 1077 for (i = 0; i < buflen; i++) { 1078 printf("%02x%s", buf[i], 1079 i == 2 ? " [" : (i + 1 < buflen ? " " : "")); 1080 } 1081 printf("]\n"); 1082 } 1083 1084 #endif 1085