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