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