Lines Matching +full:i2c +full:- +full:hid
1 /*-
2 * Copyright (c) 2018-2019 Marc Priggemeyer <marc.priggemeyer@gmail.com>
3 * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
28 * I2C HID transport backend.
56 #include <dev/hid/hid.h>
57 #include <dev/hid/hidquirk.h>
68 static SYSCTL_NODE(_hw, OID_AUTO, iichid, CTLFLAG_RW, 0, "I2C HID");
74 device_printf((sc)->dev, __VA_ARGS__); \
83 #define IICHID_SIZE_MAX (UINT16_MAX - 2)
116 /* 5.1.1 - HID Descriptor Format */
134 #define IICHID_REG_NONE -1
220 for (ids = iichid_ids; ids->id != NULL; ids++) { in acpi_is_iichid()
221 if (acpi_MatchHid(handle, ids->id)) { in acpi_is_iichid()
222 reg = ids->reg; in acpi_is_iichid()
226 if (ids->id == NULL) in acpi_is_iichid()
249 * the configuration register of the HID device. in iichid_get_config_reg()
251 /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */ in iichid_get_config_reg()
264 *config_reg = result->Integer.Value & 0xFFFF; in iichid_get_config_reg()
275 * 6.1.3 - Retrieval of Input Reports in iichid_cmd_read()
281 { sc->addr, IIC_M_RD, maxlen, buf }, in iichid_cmd_read()
285 error = iicbus_transfer(sc->dev, msgs, nitems(msgs)); in iichid_cmd_read()
294 if (!sc->reset_acked) { in iichid_cmd_read()
295 mtx_lock(&sc->mtx); in iichid_cmd_read()
296 sc->reset_acked = true; in iichid_cmd_read()
297 wakeup(&sc->reset_acked); in iichid_cmd_read()
298 mtx_unlock(&sc->mtx); in iichid_cmd_read()
315 /* 6.2.3 - Sending Output Reports. */ in iichid_cmd_write()
316 uint8_t *cmdreg = (uint8_t *)&sc->desc.wOutputRegister; in iichid_cmd_write()
320 {sc->addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd}, in iichid_cmd_write()
321 {sc->addr, IIC_M_WR | IIC_M_NOSTART, len, __DECONST(void *, buf)}, in iichid_cmd_write()
324 if (le16toh(sc->desc.wMaxOutputLength) == 0) in iichid_cmd_write()
329 DPRINTF(sc, "HID command I2C_HID_CMD_WRITE (len %d): " in iichid_cmd_write()
332 return (iicbus_transfer(sc->dev, msgs, nitems(msgs))); in iichid_cmd_write()
340 * 5.2.2 - HID Descriptor Retrieval in iichid_cmd_get_hid_desc()
345 { sc->addr, IIC_M_WR | IIC_M_NOSTOP, 2, (uint8_t *)&cmd }, in iichid_cmd_get_hid_desc()
346 { sc->addr, IIC_M_RD, sizeof(*hid_desc), (uint8_t *)hid_desc }, in iichid_cmd_get_hid_desc()
350 DPRINTF(sc, "HID command I2C_HID_CMD_DESCR at 0x%x\n", config_reg); in iichid_cmd_get_hid_desc()
352 error = iicbus_transfer(sc->dev, msgs, nitems(msgs)); in iichid_cmd_get_hid_desc()
356 DPRINTF(sc, "HID descriptor: %*D\n", in iichid_cmd_get_hid_desc()
365 uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister; in iichid_set_power()
368 { sc->addr, IIC_M_WR, sizeof(cmd), cmd }, in iichid_set_power()
371 DPRINTF(sc, "HID command I2C_HID_CMD_SET_POWER(%d)\n", param); in iichid_set_power()
373 return (iicbus_transfer(sc->dev, msgs, nitems(msgs))); in iichid_set_power()
379 uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister; in iichid_reset()
382 { sc->addr, IIC_M_WR, sizeof(cmd), cmd }, in iichid_reset()
385 DPRINTF(sc, "HID command I2C_HID_CMD_RESET\n"); in iichid_reset()
387 return (iicbus_transfer(sc->dev, msgs, nitems(msgs))); in iichid_reset()
394 uint16_t cmd = sc->desc.wReportDescRegister; in iichid_cmd_get_report_desc()
396 { sc->addr, IIC_M_WR | IIC_M_NOSTOP, 2, (uint8_t *)&cmd }, in iichid_cmd_get_report_desc()
397 { sc->addr, IIC_M_RD, len, buf }, in iichid_cmd_get_report_desc()
401 DPRINTF(sc, "HID command I2C_HID_REPORT_DESCR at 0x%x with size %d\n", in iichid_cmd_get_report_desc()
404 error = iicbus_transfer(sc->dev, msgs, nitems(msgs)); in iichid_cmd_get_report_desc()
408 DPRINTF(sc, "HID report descriptor: %*D\n", len, buf, " "); in iichid_cmd_get_report_desc()
418 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a in iichid_cmd_get_report()
423 uint8_t *dtareg = (uint8_t *)&sc->desc.wDataRegister; in iichid_cmd_get_report()
424 uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister; in iichid_cmd_get_report()
439 { sc->addr, IIC_M_WR | IIC_M_NOSTOP, cmdlen, cmd }, in iichid_cmd_get_report()
440 { sc->addr, IIC_M_RD | IIC_M_NOSTOP, 2, actbuf }, in iichid_cmd_get_report()
441 { sc->addr, IIC_M_RD | IIC_M_NOSTART, maxlen, buf }, in iichid_cmd_get_report()
447 DPRINTF(sc, "HID command I2C_HID_CMD_GET_REPORT %d " in iichid_cmd_get_report()
451 * 7.2.2.2 - Response will be a 2-byte length value, the report in iichid_cmd_get_report()
454 error = iicbus_transfer(sc->dev, msgs, nitems(msgs)); in iichid_cmd_get_report()
472 actlen -= 2; in iichid_cmd_get_report()
488 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a in iichid_cmd_set_report()
493 uint8_t *dtareg = (uint8_t *)&sc->desc.wDataRegister; in iichid_cmd_set_report()
494 uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister; in iichid_cmd_set_report()
509 {sc->addr, IIC_M_WR | IIC_M_NOSTOP, cmdlen, cmd}, in iichid_cmd_set_report()
510 {sc->addr, IIC_M_WR | IIC_M_NOSTART, len, __DECONST(void *, buf)}, in iichid_cmd_set_report()
513 DPRINTF(sc, "HID command I2C_HID_CMD_SET_REPORT %d (type %d, len %d): " in iichid_cmd_set_report()
516 return (iicbus_transfer(sc->dev, msgs, nitems(msgs))); in iichid_cmd_set_report()
530 parent = device_get_parent(sc->dev); in iichid_sampling_task()
533 if (iicbus_request_bus(parent, sc->dev, IIC_WAIT) != 0) in iichid_sampling_task()
537 if (!sc->power_on) in iichid_sampling_task()
540 error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual); in iichid_sampling_task()
543 sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, actual); in iichid_sampling_task()
544 sc->missing_samples = 0; in iichid_sampling_task()
545 if (sc->dup_size != actual || in iichid_sampling_task()
546 memcmp(sc->dup_buf, sc->intr_buf, actual) != 0) { in iichid_sampling_task()
547 sc->dup_size = actual; in iichid_sampling_task()
548 memcpy(sc->dup_buf, sc->intr_buf, actual); in iichid_sampling_task()
549 sc->dup_samples = 0; in iichid_sampling_task()
551 ++sc->dup_samples; in iichid_sampling_task()
553 if (++sc->missing_samples == 1) in iichid_sampling_task()
554 sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, 0); in iichid_sampling_task()
555 sc->dup_samples = 0; in iichid_sampling_task()
561 if (sc->callout_setup && sc->sampling_rate_slow > 0) { in iichid_sampling_task()
562 if (sc->missing_samples >= sc->sampling_hysteresis || in iichid_sampling_task()
563 sc->dup_samples >= sc->sampling_hysteresis) in iichid_sampling_task()
564 rate = sc->sampling_rate_slow; in iichid_sampling_task()
566 rate = sc->sampling_rate_fast; in iichid_sampling_task()
567 taskqueue_enqueue_timeout_sbt(sc->taskqueue, &sc->sampling_task, in iichid_sampling_task()
572 iicbus_release_bus(parent, sc->dev); in iichid_sampling_task()
585 parent = device_get_parent(sc->dev); in iichid_intr()
588 * Designware(IG4) driver-specific hack. in iichid_intr()
589 * Requesting of an I2C bus with IIC_DONTWAIT parameter enables polled in iichid_intr()
593 if (iicbus_request_bus(parent, sc->dev, IIC_DONTWAIT) != 0) in iichid_intr()
597 * Reading of input reports of I2C devices residing in SLEEP state is in iichid_intr()
604 error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual); in iichid_intr()
607 if (sc->power_on && sc->open) { in iichid_intr()
609 sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, in iichid_intr()
617 iicbus_release_bus(parent, sc->dev); in iichid_intr()
631 * Request iicbus early as sc->suspend and sc->power_on in iichid_set_power_state()
634 parent = device_get_parent(sc->dev); in iichid_set_power_state()
637 error = iicbus_request_bus(parent, sc->dev, how_request); in iichid_set_power_state()
643 sc->open = true; in iichid_set_power_state()
646 sc->open = false; in iichid_set_power_state()
655 sc->suspend = false; in iichid_set_power_state()
658 sc->suspend = true; in iichid_set_power_state()
665 power_on = sc->open & !sc->suspend; in iichid_set_power_state()
667 if (power_on != sc->power_on) { in iichid_set_power_state()
671 sc->power_on = power_on; in iichid_set_power_state()
673 if (sc->sampling_rate_slow >= 0 && sc->intr_handler != NULL) { in iichid_set_power_state()
683 iicbus_release_bus(parent, sc->dev); in iichid_set_power_state()
691 sc->irq_cookie = 0; in iichid_setup_interrupt()
693 int error = bus_setup_intr(sc->dev, sc->irq_res, in iichid_setup_interrupt()
694 INTR_TYPE_TTY|INTR_MPSAFE, NULL, iichid_intr, sc, &sc->irq_cookie); in iichid_setup_interrupt()
706 if (sc->irq_cookie) in iichid_teardown_interrupt()
707 bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_cookie); in iichid_teardown_interrupt()
709 sc->irq_cookie = 0; in iichid_teardown_interrupt()
717 if (sc->sampling_rate_slow < 0) { in iichid_setup_callout()
722 sc->callout_setup = true; in iichid_setup_callout()
731 if (sc->sampling_rate_slow <= 0) { in iichid_reset_callout()
737 if (!sc->callout_setup) in iichid_reset_callout()
741 sc->missing_samples = sc->sampling_hysteresis; in iichid_reset_callout()
742 sc->dup_samples = 0; in iichid_reset_callout()
743 sc->dup_size = 0; in iichid_reset_callout()
744 taskqueue_enqueue_timeout(sc->taskqueue, &sc->sampling_task, 0); in iichid_reset_callout()
753 sc->callout_setup = false; in iichid_teardown_callout()
754 taskqueue_cancel_timeout(sc->taskqueue, &sc->sampling_task, NULL); in iichid_teardown_callout()
767 value = sc->sampling_rate_slow; in iichid_sysctl_sampling_rate_handler()
770 if (error != 0 || req->newptr == NULL || in iichid_sysctl_sampling_rate_handler()
771 value == sc->sampling_rate_slow) in iichid_sysctl_sampling_rate_handler()
775 if (sc->irq_res == NULL && value < 0) in iichid_sysctl_sampling_rate_handler()
778 parent = device_get_parent(sc->dev); in iichid_sysctl_sampling_rate_handler()
779 error = iicbus_request_bus(parent, sc->dev, IIC_WAIT); in iichid_sysctl_sampling_rate_handler()
783 oldval = sc->sampling_rate_slow; in iichid_sysctl_sampling_rate_handler()
784 sc->sampling_rate_slow = value; in iichid_sysctl_sampling_rate_handler()
788 if (sc->power_on) in iichid_sysctl_sampling_rate_handler()
791 if (sc->power_on) in iichid_sysctl_sampling_rate_handler()
796 if (sc->power_on && value > 0) in iichid_sysctl_sampling_rate_handler()
799 iicbus_release_bus(parent, sc->dev); in iichid_sysctl_sampling_rate_handler()
823 rdesc->rdsize = 2 + in iichid_intr_setup()
824 MAX(rdesc->isize, le16toh(sc->desc.wMaxInputLength)); in iichid_intr_setup()
825 /* Write and get/set_report sizes are limited by I2C-HID protocol. */ in iichid_intr_setup()
826 rdesc->grsize = rdesc->srsize = IICHID_SIZE_MAX; in iichid_intr_setup()
827 rdesc->wrsize = IICHID_SIZE_MAX; in iichid_intr_setup()
829 parent = device_get_parent(sc->dev); in iichid_intr_setup()
830 iicbus_request_bus(parent, sc->dev, IIC_WAIT); in iichid_intr_setup()
832 sc->intr_handler = intr; in iichid_intr_setup()
833 sc->intr_ctx = context; in iichid_intr_setup()
834 sc->intr_bufsize = rdesc->rdsize; in iichid_intr_setup()
835 sc->intr_buf = realloc(sc->intr_buf, sc->intr_bufsize, in iichid_intr_setup()
838 sc->dup_buf = realloc(sc->dup_buf, sc->intr_bufsize, in iichid_intr_setup()
840 taskqueue_start_threads(&sc->taskqueue, 1, PI_TTY, in iichid_intr_setup()
841 "%s taskq", device_get_nameunit(sc->dev)); in iichid_intr_setup()
843 iicbus_release_bus(parent, sc->dev); in iichid_intr_setup()
853 taskqueue_drain_all(sc->taskqueue); in iichid_intr_unsetup()
877 * 8.2 - The HOST determines that there are no active applications in iichid_intr_stop()
878 * that are currently using the specific HID DEVICE. The HOST in iichid_intr_stop()
895 error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual); in iichid_intr_poll()
897 sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, actual); in iichid_intr_poll()
901 * HID interface
930 parent = device_get_parent(sc->dev); in iichid_read()
931 error = iicbus_request_bus(parent, sc->dev, IIC_WAIT); in iichid_read()
935 iicbus_release_bus(parent, sc->dev); in iichid_read()
1002 ((struct iic_rdwr_data *)data)->msgs, in iichid_ioctl()
1003 ((struct iic_rdwr_data *)data)->nmsgs)); in iichid_ioctl()
1018 hw->idBus = BUS_I2C; in iichid_fill_device_info()
1019 hw->idVendor = le16toh(desc->wVendorID); in iichid_fill_device_info()
1020 hw->idProduct = le16toh(desc->wProductID); in iichid_fill_device_info()
1021 hw->idVersion = le16toh(desc->wVersionID); in iichid_fill_device_info()
1023 /* get ACPI HID. It is a base part of the device name. */ in iichid_fill_device_info()
1027 if (device_info->Valid & ACPI_VALID_HID) in iichid_fill_device_info()
1028 strlcpy(hw->idPnP, device_info->HardwareId.String, in iichid_fill_device_info()
1030 snprintf(hw->name, sizeof(hw->name), "%s:%02lX %04X:%04X", in iichid_fill_device_info()
1031 (device_info->Valid & ACPI_VALID_HID) ? in iichid_fill_device_info()
1032 device_info->HardwareId.String : "Unknown", in iichid_fill_device_info()
1033 (device_info->Valid & ACPI_VALID_UID) ? in iichid_fill_device_info()
1034 strtoul(device_info->UniqueId.String, NULL, 10) : 0UL, in iichid_fill_device_info()
1035 le16toh(desc->wVendorID), le16toh(desc->wProductID)); in iichid_fill_device_info()
1039 strlcpy(hw->serial, "", sizeof(hw->serial)); in iichid_fill_device_info()
1040 hw->rdescsize = le16toh(desc->wReportDescLength); in iichid_fill_device_info()
1041 if (desc->wOutputRegister == 0 || desc->wMaxOutputLength == 0) in iichid_fill_device_info()
1056 sc->dev = dev; in iichid_probe()
1057 if (sc->probe_done) in iichid_probe()
1060 sc->probe_done = true; in iichid_probe()
1061 sc->probe_result = ENXIO; in iichid_probe()
1066 sc->addr = iicbus_get_addr(dev) << 1; in iichid_probe()
1067 if (sc->addr == 0) in iichid_probe()
1084 DPRINTF(sc, " IICbus addr : 0x%02X\n", sc->addr >> 1); in iichid_probe()
1085 DPRINTF(sc, " HID descriptor reg: 0x%02X\n", config_reg); in iichid_probe()
1087 error = iichid_cmd_get_hid_desc(sc, config_reg, &sc->desc); in iichid_probe()
1089 DPRINTF(sc, "could not retrieve HID descriptor from the " in iichid_probe()
1094 if (le16toh(sc->desc.wHIDDescLength) != 30 || in iichid_probe()
1095 le16toh(sc->desc.bcdVersion) != 0x100) { in iichid_probe()
1096 DPRINTF(sc, "HID descriptor is broken\n"); in iichid_probe()
1101 if (iichid_fill_device_info(&sc->desc, handle, &sc->hw) != 0) { in iichid_probe()
1106 if (hid_test_quirk(&sc->hw, HQ_HID_IGNORE)) in iichid_probe()
1109 sc->probe_result = BUS_PROBE_DEFAULT; in iichid_probe()
1111 if (sc->probe_result <= BUS_PROBE_SPECIFIC) in iichid_probe()
1112 device_set_descf(dev, "%s I2C HID device", sc->hw.name); in iichid_probe()
1113 return (sc->probe_result); in iichid_probe()
1129 sc->power_on = true; in iichid_attach()
1131 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); in iichid_attach()
1132 sc->intr_bufsize = le16toh(sc->desc.wMaxInputLength) - 2; in iichid_attach()
1133 sc->intr_buf = malloc(sc->intr_bufsize, M_DEVBUF, M_WAITOK | M_ZERO); in iichid_attach()
1134 TASK_INIT(&sc->suspend_task, 0, iichid_suspend_task, sc); in iichid_attach()
1136 sc->taskqueue = taskqueue_create_fast("iichid_tq", M_WAITOK | M_ZERO, in iichid_attach()
1137 taskqueue_thread_enqueue, &sc->taskqueue); in iichid_attach()
1138 TIMEOUT_TASK_INIT(sc->taskqueue, &sc->sampling_task, 0, in iichid_attach()
1141 sc->sampling_rate_slow = -1; in iichid_attach()
1142 sc->sampling_rate_fast = IICHID_SAMPLING_RATE_FAST; in iichid_attach()
1143 sc->sampling_hysteresis = IICHID_SAMPLING_HYSTERESIS; in iichid_attach()
1144 sc->dup_buf = malloc(sc->intr_bufsize, M_DEVBUF, M_WAITOK | M_ZERO); in iichid_attach()
1147 sc->irq_rid = 0; in iichid_attach()
1148 sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, in iichid_attach()
1149 &sc->irq_rid, RF_ACTIVE); in iichid_attach()
1151 if (sc->irq_res != NULL) { in iichid_attach()
1153 sc->irq_res, sc->irq_rid); in iichid_attach()
1157 if (sc->irq_res == NULL || error != 0) { in iichid_attach()
1159 device_printf(sc->dev, in iichid_attach()
1161 sc->sampling_rate_slow = IICHID_SAMPLING_RATE_SLOW; in iichid_attach()
1163 device_printf(sc->dev, "Interrupt setup failed\n"); in iichid_attach()
1164 if (sc->irq_res != NULL) in iichid_attach()
1165 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, in iichid_attach()
1166 sc->irq_res); in iichid_attach()
1174 SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), in iichid_attach()
1175 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), in iichid_attach()
1179 SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev), in iichid_attach()
1180 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), in iichid_attach()
1182 &sc->sampling_rate_fast, 0, in iichid_attach()
1184 SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev), in iichid_attach()
1185 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), in iichid_attach()
1187 &sc->sampling_hysteresis, 0, in iichid_attach()
1189 hid_add_dynamic_quirk(&sc->hw, HQ_IICHID_SAMPLING); in iichid_attach()
1208 if (sc->sampling_rate_slow >= 0) { in iichid_attach()
1210 (void)iichid_cmd_read(sc, sc->intr_buf, 0, NULL); in iichid_attach()
1214 mtx_lock(&sc->mtx); in iichid_attach()
1215 if (!sc->reset_acked && !cold) { in iichid_attach()
1216 error = mtx_sleep(&sc->reset_acked, &sc->mtx, 0, in iichid_attach()
1219 device_printf(sc->dev, in iichid_attach()
1222 mtx_unlock(&sc->mtx); in iichid_attach()
1227 device_printf(sc->dev, "Could not add I2C device\n"); in iichid_attach()
1233 device_set_ivars(child, &sc->hw); in iichid_attach()
1238 if (!sc->open) { in iichid_attach()
1240 sc->power_on = false; in iichid_attach()
1257 if (sc->irq_res != NULL) in iichid_detach()
1258 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, in iichid_detach()
1259 sc->irq_res); in iichid_detach()
1261 if (sc->taskqueue != NULL) in iichid_detach()
1262 taskqueue_free(sc->taskqueue); in iichid_detach()
1263 sc->taskqueue = NULL; in iichid_detach()
1264 free(sc->dup_buf, M_DEVBUF); in iichid_detach()
1266 free(sc->intr_buf, M_DEVBUF); in iichid_detach()
1267 mtx_destroy(&sc->mtx); in iichid_detach()
1288 * 8.2 - The HOST is going into a deep power optimized state and wishes in iichid_suspend()
1301 if (sc->sampling_rate_slow < 0) in iichid_suspend()
1310 #define suspend_thread sc->taskqueue in iichid_suspend()
1314 taskqueue_enqueue(suspend_thread, &sc->suspend_task); in iichid_suspend()
1315 taskqueue_drain(suspend_thread, &sc->suspend_task); in iichid_suspend()
1329 if (sc->sampling_rate_slow < 0) in iichid_resume()
1357 /* HID interface */
1379 MODULE_DEPEND(iichid, hid, 1, 1, 1);