// SPDX-License-Identifier: GPL-2.0-or-later // // Laptop touchpads: HID over I2C, on the SoC's DesignWare I2C controller. // // A laptop's touchpad is not on PS/2 any more and not on USB either. It hangs // off an I2C bus inside the chipset, and the only place that says so is ACPI: // a device whose _HID or _CID is PNP0C50, with an I2cSerialBus resource // naming the controller and the touchpad's address, a GpioInt naming the pin // it pulls when it has something to say, and a _DSM giving the one register // number the protocol needs to bootstrap itself. Without this the touchpad of // every recent laptop -- the ASUS TUF A15's included -- does nothing at all. // // Three layers, all here because each is small: // // The controller. Every x86 chipset since Haswell, AMD's included, uses the // same Synopsys DesignWare I2C block (AMDI0010 on Ryzen, INT33C3, INT3433 // and the PCI LPSS functions on Intel). Driven by polling: a touchpad report // is about 30 bytes, a millisecond on the bus. // // HID over I2C (Microsoft's specification, version 1.0). Read the HID // descriptor from the register _DSM names; power the device on and reset // it; read the report descriptor; then every input report is a read of the // input register, two bytes of length and the report. // // The interrupt line. It is level-triggered and stays asserted for as long // as a report is waiting, so instead of routing it through the GPIO // controller's interrupt the pin's *level* is read, every tick: low means // read a report. That is exact -- no report is read twice and none is // missed -- and needs nothing from the GPIO controller but its registers. // On AMD those are one 32-bit word per pin. Elsewhere there is no pin to // watch, and the input register is simply read every tick; devices answer // a read with nothing waiting with a zero length. // // The reports themselves go through the USB HID driver's parser and pointer // path (include/dev/hid.h). A Windows Precision Touchpad starts in mouse mode // after a reset -- relative motion, a button for a click and for a tap -- and // that is the report taken: it is what makes it a mouse on /dev/input/event1, // for the console and for X. Multi-finger reports (two-finger scroll) need the // device switched to touchpad mode and a gesture layer; not yet. #include "core/types.h" #include "core/defs.h" #include "core/param.h" #include "core/spinlock.h" #include "arch/mmu.h" #include "dev/hid.h" #include "dev/acpi.h" #include #include #include #include #include "gmmos/gmmos.h" // Each step said before it is taken, in a verbose boot: a machine that stops // here stops with the step it was on as the last line on the screen. #define STEP(...) do { if(boot_verbose) cprintf(__VA_ARGS__); } while(0) // --------------------------------------------------------------------------- // DesignWare I2C // --------------------------------------------------------------------------- #define IC_CON 0x00 #define IC_TAR 0x04 #define IC_DATA_CMD 0x10 #define IC_SS_SCL_HCNT 0x14 #define IC_SS_SCL_LCNT 0x18 #define IC_FS_SCL_HCNT 0x1C #define IC_FS_SCL_LCNT 0x20 #define IC_INTR_MASK 0x30 #define IC_RAW_INTR_STAT 0x34 #define IC_RX_TL 0x38 #define IC_TX_TL 0x3C #define IC_CLR_INTR 0x40 #define IC_CLR_TX_ABRT 0x54 #define IC_CLR_STOP_DET 0x60 #define IC_ENABLE 0x6C #define IC_STATUS 0x70 #define IC_TXFLR 0x74 #define IC_RXFLR 0x78 #define IC_SDA_HOLD 0x7C #define IC_TX_ABRT_SOURCE 0x80 #define IC_ENABLE_STATUS 0x9C #define IC_COMP_PARAM_1 0xF4 #define IC_COMP_TYPE 0xFC #define DW_COMP_TYPE 0x44570140 #define CON_MASTER (1 << 0) #define CON_SPEED_STD (1 << 1) #define CON_SPEED_FAST (2 << 1) #define CON_RESTART_EN (1 << 5) #define CON_SLAVE_DISABLE (1 << 6) #define CMD_READ (1 << 8) #define CMD_STOP (1 << 9) #define CMD_RESTART (1 << 10) #define INTR_TX_ABRT (1 << 6) #define INTR_STOP_DET (1 << 9) #define NCTL 4 struct dwi2c { uint64 phys; volatile uint32 *regs; int txdepth, rxdepth; int fast; }; static struct dwi2c ctls[NCTL]; static int nctl; static uint32 rd(struct dwi2c *c, int reg) { return c->regs[reg / 4]; } static void wr(struct dwi2c *c, int reg, uint32 v) { c->regs[reg / 4] = v; } static int dw_enable(struct dwi2c *c, int on) { int i; for(i = 0; i < 1000; i++){ wr(c, IC_ENABLE, on); if((rd(c, IC_ENABLE_STATUS) & 1) == (uint32)on) return 0; microdelay(25); } return -1; } // SCL high and low periods, in controller clocks, from the firmware's own // numbers when it gives them: SSCN and FMCN are packages of (HCNT, LCNT, // SDA hold) for exactly this controller's clock. static int acpi_counts(uacpi_namespace_node *node, const char *name, uint32 *hcnt, uint32 *lcnt, uint32 *hold) { uacpi_object *o = 0; uacpi_object_array a; uacpi_u64 v[3]; int i; if(uacpi_eval_package(node, name, 0, &o) != UACPI_STATUS_OK) return -1; if(uacpi_object_get_package(o, &a) != UACPI_STATUS_OK || a.count < 2){ uacpi_object_unref(o); return -1; } v[2] = 0; for(i = 0; i < 3 && i < (int)a.count; i++) if(uacpi_object_get_integer(a.objects[i], &v[i]) != UACPI_STATUS_OK){ uacpi_object_unref(o); return -1; } uacpi_object_unref(o); *hcnt = v[0]; *lcnt = v[1]; *hold = v[2]; return 0; } static int dw_init(struct dwi2c *c, uacpi_namespace_node *node, uint32 speed) { uint32 type, param, hcnt, lcnt, hold = 0; c->regs = ioremap(c->phys, 0x1000); if(c->regs == 0) return -1; STEP("i2c: controller registers at 0x%p\n", c->phys); type = rd(c, IC_COMP_TYPE); if(type != DW_COMP_TYPE){ cprintf("i2c: controller at 0x%p is not DesignWare (0x%x)\n", c->phys, type); return -1; } param = rd(c, IC_COMP_PARAM_1); c->txdepth = param ? ((param >> 16) & 0xFF) + 1 : 8; c->rxdepth = param ? ((param >> 8) & 0xFF) + 1 : 8; c->fast = speed >= 400000; if(dw_enable(c, 0) < 0) return -1; wr(c, IC_CON, CON_MASTER | CON_SLAVE_DISABLE | CON_RESTART_EN | (c->fast ? CON_SPEED_FAST : CON_SPEED_STD)); // Without the firmware's numbers, periods long enough for a 150 MHz clock, // the fastest any of these runs at: on a slower clock the bus is merely // slower than it could be, never out of specification. if(c->fast){ if(acpi_counts(node, "FMCN", &hcnt, &lcnt, &hold) < 0){ hcnt = 135; // 0.6 us high, 1.3 us low, plus rise and fall lcnt = 240; } wr(c, IC_FS_SCL_HCNT, hcnt); wr(c, IC_FS_SCL_LCNT, lcnt); } else { if(acpi_counts(node, "SSCN", &hcnt, &lcnt, &hold) < 0){ hcnt = 645; // 4.0 us high, 4.7 us low, plus the same lcnt = 750; } wr(c, IC_SS_SCL_HCNT, hcnt); wr(c, IC_SS_SCL_LCNT, lcnt); } if(hold) wr(c, IC_SDA_HOLD, hold); wr(c, IC_INTR_MASK, 0); wr(c, IC_RX_TL, 0); wr(c, IC_TX_TL, 0); rd(c, IC_CLR_INTR); return 0; } // Write `wn` bytes to `addr`, then read `rn` bytes back after a repeated // start, all as one transaction. 0, or -1 if the device did not answer. // // The command FIFO holds reads as well as writes, and each read becomes a // byte in the receive FIFO, so reads are queued no faster than they are // drained: a full receive FIFO stalls the bus. static int dw_xfer(struct dwi2c *c, int addr, const uchar *w, int wn, uchar *r, int rn) { int total = wn + rn, sent = 0, got = 0, spin; uint32 raw; if(dw_enable(c, 0) < 0) return -1; wr(c, IC_TAR, addr); rd(c, IC_CLR_INTR); if(dw_enable(c, 1) < 0) return -1; for(spin = 0; got < rn || sent < total; spin++){ raw = rd(c, IC_RAW_INTR_STAT); if(raw & INTR_TX_ABRT) goto abort; while(got < rn && rd(c, IC_RXFLR) > 0) r[got++] = rd(c, IC_DATA_CMD); while(sent < total && (int)rd(c, IC_TXFLR) < c->txdepth){ uint32 cmd; if(sent >= wn && (sent - wn) - got >= c->rxdepth) break; if(sent < wn) cmd = w[sent]; else cmd = CMD_READ | (sent == wn && wn > 0 ? CMD_RESTART : 0); if(sent == total - 1) cmd |= CMD_STOP; wr(c, IC_DATA_CMD, cmd); sent++; } if(spin > 20000) // 200 ms: no transfer of ours takes that long goto abort; microdelay(10); } for(spin = 0; !(rd(c, IC_RAW_INTR_STAT) & INTR_STOP_DET); spin++){ if(rd(c, IC_RAW_INTR_STAT) & INTR_TX_ABRT) goto abort; if(spin > 2000) goto abort; microdelay(10); } rd(c, IC_CLR_STOP_DET); dw_enable(c, 0); return 0; abort: rd(c, IC_TX_ABRT_SOURCE); rd(c, IC_CLR_TX_ABRT); rd(c, IC_CLR_INTR); dw_enable(c, 0); return -1; } // --------------------------------------------------------------------------- // ACPI // --------------------------------------------------------------------------- struct found { uint64 mem; // the first memory range int i2c, addr; uint32 speed; char bus[64]; // the controller's namespace path int gpio, pin, active_low; char gpioctl[64]; }; static void copy_source(char *dst, const uacpi_resource_source *s) { int n = s->string && s->length ? s->length : 0; if(n > 63) n = 63; if(n) memmove(dst, s->string, n); dst[n] = 0; } static uacpi_iteration_decision take_resource(void *user, uacpi_resource *r) { struct found *f = user; switch(r->type){ case UACPI_RESOURCE_TYPE_FIXED_MEMORY32: if(!f->mem) f->mem = r->fixed_memory32.address; break; case UACPI_RESOURCE_TYPE_MEMORY32: if(!f->mem) f->mem = r->memory32.minimum; break; case UACPI_RESOURCE_TYPE_ADDRESS32: if(!f->mem && r->address32.common.type == UACPI_RANGE_MEMORY) f->mem = r->address32.minimum; break; case UACPI_RESOURCE_TYPE_ADDRESS64: if(!f->mem && r->address64.common.type == UACPI_RANGE_MEMORY) f->mem = r->address64.minimum; break; case UACPI_RESOURCE_TYPE_SERIAL_I2C_CONNECTION: if(!f->i2c){ f->i2c = 1; f->addr = r->i2c_connection.slave_address; f->speed = r->i2c_connection.connection_speed; copy_source(f->bus, &r->i2c_connection.common.source); } break; case UACPI_RESOURCE_TYPE_GPIO_CONNECTION: if(!f->gpio && r->gpio_connection.type == UACPI_GPIO_CONNECTION_INTERRUPT && r->gpio_connection.pin_table_length > 0){ f->gpio = 1; f->pin = r->gpio_connection.pin_table[0]; f->active_low = r->gpio_connection.intr.polarity != UACPI_POLARITY_ACTIVE_HIGH; copy_source(f->gpioctl, &r->gpio_connection.source); } break; } return UACPI_ITERATION_DECISION_CONTINUE; } static int resources(uacpi_namespace_node *node, struct found *f) { memset(f, 0, sizeof(*f)); return uacpi_for_each_device_resource(node, "_CRS", take_resource, f) == UACPI_STATUS_OK ? 0 : -1; } // The I2C-HID _DSM, function 1: the HID descriptor's register. static int hid_desc_register(uacpi_namespace_node *node, uint32 *reg) { static const uchar uuid[16] = { // 3CDFF6F7-4267-4555-AD05-B30A3D8938DE 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, }; uacpi_data_view view = { .const_bytes = uuid, .length = sizeof(uuid) }; uacpi_object_array none = { 0, 0 }; uacpi_object *args[4], *ret = 0; uacpi_object_array a = { args, 4 }; uacpi_u64 v = 0; int rc = -1, i; args[0] = uacpi_object_create_buffer(view); args[1] = uacpi_object_create_integer(1); // revision args[2] = uacpi_object_create_integer(1); // function args[3] = uacpi_object_create_package(none); if(args[0] && args[1] && args[2] && args[3] && uacpi_eval(node, "_DSM", &a, &ret) == UACPI_STATUS_OK && ret && uacpi_object_get_integer(ret, &v) == UACPI_STATUS_OK){ *reg = v; rc = 0; } if(ret) uacpi_object_unref(ret); for(i = 0; i < 4; i++) if(args[i]) uacpi_object_unref(args[i]); return rc; } static uacpi_namespace_node * node_at(const char *path) { uacpi_namespace_node *n = 0; if(path[0] == 0 || uacpi_namespace_node_find(0, path, &n) != UACPI_STATUS_OK) return 0; return n; } static struct dwi2c * controller(const char *path, uint32 speed) { uacpi_namespace_node *node = node_at(path); struct found f; struct dwi2c *c; int i; if(node == 0 || resources(node, &f) < 0 || f.mem == 0){ cprintf("i2c: no registers for controller %s\n", path); return 0; } for(i = 0; i < nctl; i++) if(ctls[i].phys == f.mem) return &ctls[i]; if(nctl == NCTL) return 0; uacpi_execute(node, "_PS0", 0); c = &ctls[nctl]; memset(c, 0, sizeof(*c)); c->phys = f.mem; if(dw_init(c, node, speed) < 0) return 0; nctl++; cprintf("i2c: %s at 0x%p, %s mode, FIFOs %d/%d\n", path, c->phys, c->fast ? "fast" : "standard", c->txdepth, c->rxdepth); return c; } // --------------------------------------------------------------------------- // HID over I2C // --------------------------------------------------------------------------- #define NI2CHID 4 struct i2chid { struct dwi2c *c; int addr; uint32 cmdreg, inreg, maxin; volatile uint32 *pin; // the interrupt pin's register, or 0 int active_low; void *hid; uchar *buf; // one page, for input reports char name[8]; }; static struct i2chid devs[NI2CHID]; static int ndev; static int reg_write(struct i2chid *d, const uchar *w, int n) { return dw_xfer(d->c, d->addr, w, n, 0, 0); } static int reg_read(struct i2chid *d, uint32 reg, uchar *r, int n) { uchar w[2] = { reg & 0xFF, reg >> 8 }; return dw_xfer(d->c, d->addr, w, 2, r, n); } // SET_POWER and RESET, the two commands needed: written to the command // register as (register, opcode byte, power state / report byte). static int command(struct i2chid *d, int opcode, int arg) { uchar w[4] = { d->cmdreg & 0xFF, d->cmdreg >> 8, arg, opcode }; return reg_write(d, w, 4); } #define OP_RESET 0x01 #define OP_SET_POWER 0x08 static void wait_ticks(uint n) { acquire(&tickslock); uint start = ticks; while(ticks - start < n) sleep(&ticks, &tickslock); release(&tickslock); } // AMD's GPIO controller: one 32-bit register per pin, its level in bit 16. #define AMD_PIN_STS (1u << 16) static int asserted(struct i2chid *d) { int high = (*d->pin & AMD_PIN_STS) != 0; return d->active_low ? !high : high; } static volatile uint32 * interrupt_pin(const struct found *f) { static const char *const amd[] = { "AMDI0030", "AMD0030", 0 }; uacpi_namespace_node *node = node_at(f->gpioctl); struct found g; if(!f->gpio || node == 0 || !uacpi_device_matches_pnp_id(node, amd)) return 0; if(resources(node, &g) < 0 || g.mem == 0) return 0; return (volatile uint32 *)((char *)ioremap(g.mem, 0x1000) + f->pin * 4); } // One input report: two bytes of length, length included, then the report. // A length of 0 is the device saying it has nothing, or acknowledging a // reset. static int read_input(struct i2chid *d) { int len; if(dw_xfer(d->c, d->addr, 0, 0, d->buf, d->maxin) < 0) return -1; len = d->buf[0] | (d->buf[1] << 8); if(len <= 2 || len > (int)d->maxin) return 0; hid_attached_input(d->hid, d->buf + 2, len - 2); return 1; } static uacpi_iteration_decision probe(void *user, uacpi_namespace_node *node, uacpi_u32 depth) { struct i2chid *d; struct found f; uchar desc[30], *rdesc; uint32 descreg, rlen, rreg; int i; (void)user; (void)depth; if(ndev == NI2CHID) return UACPI_ITERATION_DECISION_BREAK; d = &devs[ndev]; memset(d, 0, sizeof(*d)); memmove(d->name, uacpi_namespace_node_name(node).text, 4); STEP("i2c-hid: %s: reading its resources\n", d->name); if(resources(node, &f) < 0 || !f.i2c){ cprintf("i2c-hid: %s has no I2C connection\n", d->name); return UACPI_ITERATION_DECISION_CONTINUE; } STEP("i2c-hid: %s: _DSM\n", d->name); if(hid_desc_register(node, &descreg) < 0){ cprintf("i2c-hid: %s: _DSM gave no descriptor register\n", d->name); return UACPI_ITERATION_DECISION_CONTINUE; } STEP("i2c-hid: %s: controller %s, address 0x%x\n", d->name, f.bus, f.addr); if((d->c = controller(f.bus, f.speed)) == 0) return UACPI_ITERATION_DECISION_CONTINUE; d->addr = f.addr; STEP("i2c-hid: %s: _PS0\n", d->name); uacpi_execute(node, "_PS0", 0); STEP("i2c-hid: %s: HID descriptor at register 0x%x\n", d->name, descreg); if(reg_read(d, descreg, desc, sizeof(desc)) < 0 || (desc[0] | desc[1] << 8) != 30){ cprintf("i2c-hid: %s at 0x%x does not answer\n", d->name, d->addr); return UACPI_ITERATION_DECISION_CONTINUE; } rlen = desc[4] | desc[5] << 8; rreg = desc[6] | desc[7] << 8; d->inreg = desc[8] | desc[9] << 8; d->maxin = desc[10] | desc[11] << 8; d->cmdreg = desc[16] | desc[17] << 8; if(d->maxin < 3 || d->maxin > PGSIZE || rlen == 0 || rlen > PGSIZE){ cprintf("i2c-hid: %s: unusable descriptor\n", d->name); return UACPI_ITERATION_DECISION_CONTINUE; } d->pin = interrupt_pin(&f); d->active_low = f.active_low; STEP("i2c-hid: %s: power on and reset, pin %s\n", d->name, d->pin ? "watched" : "none"); command(d, OP_SET_POWER, 0); // 0 = on wait_ticks(2); command(d, OP_RESET, 0); wait_ticks(10); d->buf = (uchar *)kalloc(); rdesc = (uchar *)kalloc(); if(d->buf == 0 || rdesc == 0) return UACPI_ITERATION_DECISION_BREAK; // The reset is acknowledged with an empty report. Read it, and anything // else already waiting, so the first real report is not behind it. for(i = 0; i < 4 && (d->pin == 0 || asserted(d)); i++) if(dw_xfer(d->c, d->addr, 0, 0, d->buf, d->maxin) < 0) break; STEP("i2c-hid: %s: report descriptor, %d bytes\n", d->name, rlen); if(reg_read(d, rreg, rdesc, rlen) < 0){ cprintf("i2c-hid: %s: report descriptor unreadable\n", d->name); kfree((char *)rdesc); return UACPI_ITERATION_DECISION_CONTINUE; } char what[24] = "i2c-hid "; memmove(what + 8, d->name, 4); d->hid = hid_attach(rdesc, rlen, what); kfree((char *)rdesc); if(d->hid == 0){ cprintf("i2c-hid: %s is neither a keyboard nor a pointer\n", d->name); return UACPI_ITERATION_DECISION_CONTINUE; } cprintf("i2c-hid: %s: %x:%x at 0x%x, %s\n", d->name, desc[20] | desc[21] << 8, desc[22] | desc[23] << 8, d->addr, d->pin ? "interrupt pin watched" : "polled"); ndev++; return UACPI_ITERATION_DECISION_CONTINUE; } // **The thread runs on a stack of its own, 64 KB.** A kernel thread's stack // is 8 KB, and this one runs the firmware's AML -- _DSM, _PS0, _CRS, and // whatever those call -- through uACPI's interpreter, built at -O0. On the // ASUS TUF A15 that ran off the end: kernel stacks are one array, so it ran // into the next thread's, and the machine died a moment later in whatever // that thread was doing, with a crash report about the wrong code. // call_on_stack() is SCFF's (kernel/scff/scff.c). Sleeping here is fine: // the context is saved on this stack, and only this thread ever uses it. static unsigned char i2c_stack[64 * 1024] __attribute__((aligned(16))); long call_on_stack(long (*fn)(void *), void *arg, void *top); static long i2c_hid_main(void *arg) { static const char *const ids[] = { "PNP0C50", "ACPI0C50", 0 }; int i, n; (void)arg; STEP("i2c-hid: looking for touchpads\n"); uacpi_find_devices_at(uacpi_namespace_root(), ids, probe, 0); STEP("i2c-hid: %d found\n", ndev); if(ndev == 0) for(;;) wait_ticks(1000000); for(;;){ wait_ticks(1); for(i = 0; i < ndev; i++){ struct i2chid *d = &devs[i]; if(d->pin == 0){ read_input(d); continue; } // Everything waiting, up to a bound so that a stuck line cannot keep // the other devices from their turn. for(n = 0; n < 16 && asserted(d); n++) if(read_input(d) < 0) break; } } } // For GMMOS. Read without a lock: `ndev` only ever grows, and only before the // polling loop starts, so a panic sees a list that was finished or not begun. int i2c_hid_keyboards(struct gmmos_i2c_kbd *out, int max) { int i, n = 0; for(i = 0; i < ndev && n < max; i++){ struct i2chid *d = &devs[i]; if(!hid_is_keyboard(d->hid)) continue; out[n].regs = d->c->regs; out[n].txdepth = d->c->txdepth; out[n].rxdepth = d->c->rxdepth; out[n].addr = d->addr; out[n].maxin = d->maxin; out[n].pin = d->pin; out[n].active_low = d->active_low; out[n].hid = d->hid; n++; } return n; } static void i2c_hid_thread(void) { call_on_stack(i2c_hid_main, 0, i2c_stack + sizeof(i2c_stack)); } void i2c_hid_start(void) { if(acpi_rsdp_phys() == 0) return; if(kthread_create(i2c_hid_thread, "i2chid") < 0) cprintf("i2c-hid: no thread; touchpads will not work\n"); }