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