WarmGrayMatteInkMistClaySage
RELIEF · DEMO

One touch, glass to app一次触摸,从玻璃到应用

Every other demo in this repo renders the same marketing page in a different voice. This one cannot: relief's subject is technical diagrams, so the honest demo is a real thing explained. Below, one finger press is followed from the glass to the application, and each hop is drawn with whichever diagram shape actually fits it.这个仓里别的 demo 都是同一份营销页换一种声音。这个不行:relief 的主题是技术框图,所以诚实的 demo 是真讲一件事。下面跟着一次按压从玻璃走到应用,每一跳用真正合适它的那种图来画。

1 · The whole way, once1 · 先把整条路走一遍

Seven hops from a finger to an application. Everything after this page zooms into one of them — and every figure here is built from the same two words: raised is a thing that exists, sunken is somewhere you cannot go or a channel something travels down.从手指到应用,七跳。这一页往后的每一节都是放大其中一跳 —— 而这里每一张图都只用两个词搭出来:凸起是一个存在的东西,凹陷是去不了的地方、或者一条东西从里面走过的通道。

ONE TOUCH · GLASS TO APP一次触摸 · 从玻璃到应用the two dark blocks are where data rests; everything between them only transforms it两头深色的是数据待着的地方,中间全是加工它的
Glass玻璃a finger changes the capacitance手指改变了电容
TP chipTP 芯片scans the electrode grid扫描电极阵列
INT pin中断脚pulled low拉低
GICGIChwirq 42hwirq 42
irq thread中断线程reads 16 bytes over i2c走 i2c 读 16 字节
input coreinput 子系统input_report_abs()input_report_abs()
/dev/input/dev/inputthe app wakes up应用醒过来

2 · Where it is allowed to sleep2 · 哪一段允许睡眠

The chip needs an i2c read to hand over the coordinates, and i2c sleeps. The interrupt handler cannot. So the work is split across two contexts, and the band a function sits in decides what it may call — the ringed band is the one where a single i2c_transfer() would deadlock the machine.要拿到坐标得走一次 i2c 读,而 i2c 会睡眠,中断处理函数不能睡。所以活被劈成两段,一个函数在哪条带里,决定了它能调什么 —— 描圈那条带里,一次 i2c_transfer() 就能把机器锁死。

WHY THE HANDLER IS SPLIT IN TWO中断为什么要劈成两半this is not a style preference — the top band physically cannot wait for a bus这不是写法偏好 —— 上面那条带在物理上就等不了总线
Hard IRQ — the first 3 microseconds硬中断 —— 最初的 3 微秒cannot sleep, so it cannot touch i2c不能睡眠,所以碰不了 i2c
tp_irq_handler()returns IRQ_WAKE_THREAD and nothing else只做一件事:返回 IRQ_WAKE_THREAD
Process context — everything after进程上下文 —— 之后的一切may sleep, so i2c is finally legal here可以睡眠,所以到这里 i2c 才合法
tp_irq_thread()i2c read, parse, reporti2c 读取、解析、上报
input_event()
read() syscallthe app collecting it应用来取

3 · What the chip actually hands over3 · 芯片到底交出来什么

The first register read is 16 bits and it decides everything that follows. Reserved bits are drawn sunken, so you know which ones you may not write without reading the access column. The write-1-to-clear bit carries the accent because it is the one people get wrong — it always reads back 0, and that does not mean your write missed.第一次寄存器读是 16 位,后面所有事都由它决定。保留位画成凹陷,不用读属性列就知道哪些不能写。写 1 清除的那位给强调色,因为它是最容易出错的一个 —— 它读回来永远是 0,而这不代表你那次写没生效。

STATUS REGISTER · 16 bits状态寄存器 · 16 位a driver that polls RDY by reading CLR will hang forever, and the register is not broken靠读 CLR 来轮询 RDY 的驱动会永远卡住,而寄存器没坏
15 ········· 0
RSVD
TOUCH_CNT0..10
GESTURE_ID0 = none0 = 无
CLR
RDY
read this first — it says how many points follow先读它 —— 它说后面跟几个点 CLR is write-1-to-clear · reading it always gives 0CLR 写 1 清除 · 读回恒为 0

4 · When it goes wrong4 · 出事的时候

A backtrace read top to bottom goes from where it died back to where it started, while the stack pointer runs the other way — the address gutter is there to say so. The accent frame is the innermost one, which is the line the reader came for.栈回溯从上往下读是从出事的地方回到起点,而栈指针是反着走的 —— 左边那列地址就是说这个的。强调色标的是最里面那一帧,也就是读者来找的那一行。

BACKTRACE栈回溯the note on the top frame is the actual bug: it died holding a mutex最上面那帧右边的注解才是真正的 bug:它是握着锁死的
0xffffffc0_11e8
tp_irq_thread()tp_core.c:508
still holding the i2c mutex还握着 i2c 的锁
0xffffffc0_1240
irq_thread_fn()kernel/irq/manage.c
0xffffffc0_1298
irq_thread()kernel/irq/manage.c
0xffffffc0_12f0
kthread()kernel/kthread.c
bottom of stack栈底
THE FULL SET完整图集

Fifty diagram shapes across eight canonical pages. This demo used five of them.八张范本页,五十种框图。这个 demo 用掉了其中五种。