GSL1680是一种芯片,旨在为LCD屏幕增加电容式、多触觉功能。用于多种设备。
该芯片有四个主引脚与CPU通信:
主线内核中有一个驱动程序。
目前,sunxi-3.4 中没有驱动程序,但驱动程序可从多个第三方位置获得:
最终,对此设备的支持在 A23 SDK 中显示为两个不同的驱动程序:
还有一个用户空间驱动程序(它使用 UFILE 系统链接到 INPUT 子系统)可在 https://github.com/rastersoft/gsl1680 上使用。由于它像真正的 INPUT 驱动程序一样工作,因此它与 Xorg 和与鼠标兼容的 Linux 中的任何其他程序完全兼容。该驱动程序的优点是在屏幕上移动两根手指时模拟鼠标滚轮,从而允许使用标准应用程序。它还在用三根手指触摸时模拟 Ctrl+MENU,从而可以与 TabletWM 集成。
芯片和 CPU 之间的通信使用 I2C 总线完成。GSL1680总是在地址0x40回答。这允许在 Linux 下使用命令来了解我们的设备是否具有GSL1680芯片
i2cdetect X
其中 X 是介于 0 和我们系统中 I2C 总线数量之间的数字。如果任何总线中的地址0x40处没有设备,则该设备没有GSL1680。
CPU 可以读取或写入多个 8 位寄存器,这些寄存器分配在GSL1680内。每次 I2C 传输开始时,第一个字节包含一个寄存器号,其他字节包含要存储在该寄存器和下一个寄存器中的数据。如果我们发送:
START(W) 0x10 0x00 0x01 0xF5 0x41 0xFF STOP
芯片将在寄存器0x10中存储一个0x00值;寄存器0x11中的0x01值;寄存器0x12中的0xF5值,依此类推。
要从芯片中读取,只需写入一个带有寄存器号的字节即可开始读取,然后执行与要读取的寄存器一样多的读取。
已知寄存器包括:
每组坐标的四个字节包含 X 和 Y 值,以及手指。
前两个字节以小端格式包含 12 个较低位的 X 坐标。另外两个字节以小端格式包含 12 个较低位的 Y 坐标。
Y 坐标中的 4 位上位包含进行触摸的手指标识符。
例:
假设用户用一根手指触摸屏幕。寄存器0x80将包含 1,寄存器0x84到 0x87 将包含 X 和 Y 坐标,手指标识符将为 1。
现在,用户无需移开第一根手指,而是用第二根手指触摸屏幕。寄存器0x80将包含 2。寄存器0x84到0x87将包含第一次触摸的 X 和 Y 坐标,其中的手指标识符将为 1。寄存器0x88到0x8B将包含第二次触摸的 X 和 Y 坐标,其中的手指标识符将为 2。
现在,用户移除第一根手指,保留第二根手指。寄存器0x80将包含 1。寄存器0x84 0x87将包含 X 和 Y 坐标,但手指标识符将为 2,因为这是保留在屏幕上的手指。
驱动程序显示了一个非常晦涩的初始化过程:
完成此过程后,芯片将开始读取触摸并发送事件。
要按照上一过程中的要求重置芯片,请按照以下步骤操作:
该芯片需要加载固件才能工作。此固件似乎特定于每个设备型号,因此必须在您的设备中找到它。在 Szenio 1207 平板电脑中,这些文件位于 /system/etc 中。
有时固件包含在驱动程序模块文件中,例如:/system/vendor/modules/gslx680.ko。
要提取固件,您可以使用fw_extractor或从寄存器序列中手动找到它并将其 dd 出来。
用户空间驱动程序支持固件的二进制格式或纯文本格式。在后一种情况下,它被划分为块,每个块的最大大小为 128 字节。每个区块必须存储在不同的页面中。下面是一个块的示例:
{0xf0,0x3},
{0x00,0xa5a5ffc0},
{0x04,0x00000000},
{0x08,0xe810c4e1},
{0x0c,0xd3dd7f4d},
{0x10,0xd7c56634},
{0x14,0xe3505a2a},
{0x18,0x514d494f},
{0x1c,0x5836e48b},
{0x20,0x00000000},
{0x24,0x00000000},
{0x28,0x00000000},
{0x2c,0x00000000},
{0x30,0x00001000},
{0x34,0x00000000},
{0x38,0x00000000},
{0x3c,0x00000000},
{0x40,0x00000001},
{0x44,0x00000000},
{0x48,0x00000000},
{0x4c,0x00000000},
{0x50,0x00000000},
{0x54,0x01020304},
{0x58,0x05060708},
{0x5c,0x090a0b0c},
{0x60,0x0d0e0e0f},
{0x64,0x10111213},
{0x68,0x14151617},
{0x6c,0x18191a1b},
{0x70,0x1b1c1e1f},
{0x74,0x00000000},
{0x78,0x00010000},
{0x7c,0x8c846af3},
每行包含一对元素。第一个是必须存储数据的寄存器编号;第二个是数据本身。
第一行有0xF0作为寄存器编号。这是PAGE寄存器。此行指定必须存储此块的页面。在此示例中,它是页码0x03。
其他 32 行包含固件本身,前面是每个 4 字节值的偏移量。在此示例中,我们的代码必须将0xC0写入寄存器0x00;0xFF进入登记册0x01;0xA5到寄存器0x02中,然后再次0x05到寄存器0x03中(请记住,ARM 中的值以 little endian 格式存储)。由于0x03存储在PAGE寄存器中,因此寄存器0x00映射到存储器中的位置0x180,寄存器0x01映射到位置0x181,依此类推。
由于发送多个字节将它们存储在相关寄存器中,因此理论上代码只需将0x00设置为目标寄存器,并在一次传输中发送该块的所有字节。不幸的是,I2C 传输的大小通常有限制,因此建议不要构建非常大的数据包,而是将每个块分成较小的部分发送。
