Driver tactil

Acabo de terminar la segunda versión completamente funcional del driver para el chip táctil GSL1680 que incorpora mi tablet. Entre las ventajas que tiene están que, además de procesar pulsaciones normales, permite también emular la rueda de desplazamiento del ratón para hacer scroll de una ventana, así como emular zoom-in y zoom-out con el gesto pinch-to-zoom. Por último, también permite hacer click derecho de manera puramente táctil.

El scroll se hace con dos dedos, moviéndolos de manera simultanea. Cuando el driver lo detecta emite eventos wheel y hwheel, que todas las aplicaciones interpretan como scroll. Por otro lado, al detectar un pinch-to-zoom, emite un evento wheel más la tecla CTRL. Esto se interpreta, en general, como zoom (al menos en Firefox, GIMP e InkScape).

El click derecho es el menos intuitivo, pero dado que no es algo se se utilice demasiado, no es tan problemático. Para hacerlo hay que:

  • tocar con un dedo en la pantalla, y mantenerlo.
  • tocar y soltar con otro dedo sin quitar el primer dedo de la pantalla. Esto hace entrar al driver en el modo click derecho
  • mover el primer dedo al punto donde queremos hacer click derecho (lo normal es que ya esté ahí, pero…)
  • tocar y soltar con otro dedo sin quitar el primer dedo de la pantalla.
  • mientras no despeguemos el primer dedo de la pantalla, podemos hacer tantos clicks derechos como queramos en cualquier parte de la pantalla.

Como es algo lioso, sugiero ver este vídeo de demostración del driver. El click derecho se hace en el segundo 5:

Para programar el driver decidí no meterme en fregados, y lo implementé como un driver en espacio de usuario mediante uinput. La principal ventaja es que resulta mucho más sencillo de depurar que un módulo para el kernel, además de permitir hacer cosas más avanzadas, como cargar el firmware directamente, sin necesidad de meter a udev por medio. A nivel técnico, comentar que, en realidad, se crean dos dispositivos, uno de tipo absoluto (pantalla táctil, touchpad…) y otro de tipo relativo (ratón). El motivo es que un mismo dispositivo no puede enviar eventos relativos y absolutos a la vez, pero para el cursor necesitaba eventos absolutos, mientras que para el scroll y el zoom necesitaba relativos.

De momento el código del driver está disponible únicamente en github.

 

CC BY-SA 4.0 Driver tactil por A cuadros está licenciado bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

26 comentarios en “Driver tactil

  1. Es una tablet sin marca y la caja dice Android Tablet PC solamente (en Android dice que es un TY-Q88 y con casi nada de documentación) pero me acabo de dar cuenta que la touchscreen es una ft5x_ts y por eso mismo no carga el driver obviamente (aunque el resto del hardware lo compartimos). Según este post https://www.miniand.com/forums/forums/development/topics/how-do-i-get-the-lcd-display-and-touch-screen-working-on-an-a10-tablet#post-1225 hay que comentar una línea del driver al compilar al kernel para desactivar el multitouch (y para que así evdev lo tome), pero sin embargo no funciona en xorg. Estoy ocupando el kernel 3.4.61+ y gracias a tu documentación logré echar a andar el WiFi 🙂

  2. Yo no me fiaría mucho de dmesg, porque a fin de cuentas i2c es un bus sin PnP, por lo que el sistema operativo no puede «preguntar» qué es lo que hay.

    Prueba a escanear el bus I2C a ver qué encuentras. Para ello haz como root

    i2cdetect X

    con X números desde 0 hasta el número de buses I2C que tenga tu tablet. El chip debería aparecer en la dirección 0x40. Si en ninguno de los buses aparece algún dispositivo en esa dirección, entonces no tienes un GSL1680.

    Otro motivo de fallo puede ser el formato del firmware, que no esté de la forma que lo espera el driver, pero eso lo veremos luego.

  3. Con i2cdetect me lanza que efectivamente se encuentra en la dirección 0x40 en el bus i2c-1.

    Para conseguir el firmware, lo extraje con las herramientas que están aquí: https://gitorious.org/gslx680-for-sunxi/gslx680-for-sunxi

    Probé con el mismo driver de ahí, e inicia completamente, sin embargo sigue sin funcionar el táctil (y con evtest no obtengo ningún valor).

    Dejé mi firmware aquí en caso de cualquier cosa: http://marcianisto.cl/gslx680.fw

    Saludos!

  4. Vale, ese firmware está en formato binario, no en formato texto plano como requiere mi driver… Pero ya veo como va codificado. Voy a preparar una versión que soporte ese formato y lo subo al git. Dame unos minutos.

  5. Ya cargó el firmware ! la salida es esta:

    root@arm:~/gsl1680# ./driver /dev/i2c-1 gslx680.fw
    Connecting to device /dev/i2c-1, firmware gslx680.fw
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent
    =============gsl_load_fw start==============
    =============gsl_load_fw end==============
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent
    sh: 1: cannot create /sys/devices/virtual/misc/sun4i-gpio/pin/pb3: Directory nonexistent

    Pero se queda colgado ahí, y no anda el touchscreen aún… ¿Alguna dependencia?

  6. La otra posibildad es que sea otro hardware, como apunta el script.bin…

    ctp_used = 1
    ctp_name = «ft5x_ts»
    ctp_twi_id = 1
    ctp_twi_addr = 0x3f

    Pero me ocurre esto al cargarlo con el driver ft5x:

    [ 9.627344] ===========================ft5x_ts_init=====================
    [ 9.674587] ctp_fetch_sysconfig_para.
    [ 9.684274] ctp_fetch_sysconfig_para: after: ctp_twi_addr is 0x3f, dirty_addr_buf: 0x3f. dirty_addr_buf[1]: 0xfffe
    [ 9.694755] ctp_fetch_sysconfig_para: ctp_twi_id is 1.
    [ 9.699981] ctp_fetch_sysconfig_para: screen_max_x = 800.
    [ 9.704440] ctp_fetch_sysconfig_para: screen_max_y = 480.
    [ 9.708930] ctp_fetch_sysconfig_para: revert_x_flag = 1.
    [ 9.713282] ctp_fetch_sysconfig_para: revert_y_flag = 0.
    [ 9.717983] ctp_fetch_sysconfig_para: exchange_x_y_flag = 0.
    [ 9.725734] ft5x_ts_init: after fetch_sysconfig_para: normal_i2c: 0x3f. normal_i2c[1]: 0xfffe
    [ 9.731032] ctp_init_platform_resource: tp_reset request gpio fail!
    [ 9.736511] ctp_init_platform_resource: No power port feature present.
    [ 9.738083] ctp_wakeup.
    [ 9.790416] ctp_detect: Detected chip ft5x_ts at adapter 1, address 0x3f
    [ 9.795671] ====ft5x_ts_probe begin=====.
    [ 9.808791] input: ft5x_ts as /devices/platform/sunxi-i2c.1/i2c-1/1-003f/input/input3
    [ 9.814179] ctp_set_irq_mode: config gpio to int mode.
    [ 9.820114] ctp_set_irq_mode, 225: gpio_int_info, port = 7, port_num = 11.
    [ 9.822200] INTERRUPT CONFIG
    [ 9.828957] ==ft5x_ts_probe over =

  7. El problema probablemente se deba a que no tienes configurado correctamente el acceso al GPIO que activa y desactiva el chip, y por eso la inicialización falla. Acabo de subir otra versión a github que permite especificar la ruta al GPIO, pero también necesitas activar el módulo GPIO_UGLY en el kernel, y añadir una entrada con el GPIO correspondiente en el fichero FEX. He añadido los pasos necesarios en la documentación del driver.

    También puede ser que el firmware sea incorrecto, eso sí, o que tenga algún bug en la carga del firmware en modo binario… pero primero asegúrate de probar a acceder al GPIO correctamente.

  8. Por cierto: respecto al FT5x, fíjate que dice lo mismo: no puede acceder al GPIO… sospecho que te falta añadir soporte de GPIO al núcleo (en este caso supongo que tendrá que ser el soporte interno, no el UGLY, que es para acceder desde espacio de usuario).

  9. Ahora sí se puede acceder al GPIO correctamente, pero aún no hay respuesta del touchscreen. Según i2cdetect (aunque cambie los valores del FEX) es un gsl1680 (0x40). Trataré de probar con algún otro firmware a ver si se trata de eso.

  10. Algo interesante, es que Android parece probar varios drivers hasta llegar al correcto, ignorando los datos del script.bin:

    [ 12.360823] szg ko name=/system/vendor/modules/ft5x_ts.ko,addr=3f reg=9 vaule=0
    [ 12.360897] init: szg set bus mode fail!
    [ 12.361114] [i2c1] incomplete xfer (0x20)
    [ 12.361520] init: szg i2c write fail reg=9!
    [ 12.361614] init: szg open /dev/i2c-1 success !
    [ 12.361673] readtp: resetstatus= 0
    [ 12.853066] szg ko name=/system/vendor/modules/goodix811.ko,addr=5d reg=0 vaule=0
    [ 12.853141] init: szg set bus mode fail!
    [ 12.860107] [i2c1] incomplete xfer (0x20)
    [ 12.860159] init: szg i2c write fail reg=0!
    [ 12.860285] init: szg open /dev/i2c-1 success !
    [ 12.860342] readtp: resetstatus= 0
    [ 13.353410] szg ko name=/system/vendor/modules/ssd253x-ts.ko,addr=48 reg=0 vaule=0
    [ 13.353486] init: szg set bus mode fail!
    [ 13.360133] [i2c1] incomplete xfer (0x20)
    [ 13.360195] init: szg i2c write fail reg=0!
    [ 13.360309] init: szg open /dev/i2c-1 success !
    [ 13.360370] readtp: resetstatus= 0
    [ 13.849786] szg ko name=/system/vendor/modules/ct360_ts.ko,addr=1 reg=0 vaule=0
    [ 13.849866] init: szg set bus mode fail!
    [ 13.870140] [i2c1] incomplete xfer (0x20)
    [ 13.870210] init: szg i2c write fail reg=0!
    [ 13.870333] init: szg open /dev/i2c-1 success !
    [ 13.870394] readtp: resetstatus= 0
    [ 14.357224] szg ko name=/system/vendor/modules/elan_ts.ko,addr=15 reg=0 vaule=0
    [ 14.357303] init: szg set bus mode fail!
    [ 14.357516] [i2c1] incomplete xfer (0x20)
    [ 14.357541] init: szg i2c write fail reg=0!
    [ 14.357647] init: szg open /dev/i2c-1 success !
    [ 14.357707] readtp: resetstatus= 0
    [ 14.844434] szg ko name=/system/vendor/modules/gslx680.ko,addr=40 reg=0 vaule=0
    [ 14.844511] init: szg set bus mode fail!
    [ 14.856389] init: szg get ko name/system/vendor/modules/gslx680.ko
    [ 14.900592] ==gsl_ts_init==
    [ 14.900622] ctp_fetch_sysconfig_para.
    [ 14.900644] ctp_fetch_sysconfig_para: after: ctp_twi_addr is 0x40, dirty_addr_buf: 0x40. dirty_addr_buf[1]: 0xfffe
    [ 14.900661] ctp_fetch_sysconfig_para: ctp_twi_id is 1.
    [ 14.900671] ctp_fetch_sysconfig_para: screen_max_x = 800.
    [ 14.900681] ctp_fetch_sysconfig_para: screen_max_y = 480.
    [ 14.900690] ctp_fetch_sysconfig_para: revert_x_flag = 1.
    [ 14.900700] ctp_fetch_sysconfig_para: revert_y_flag = 0.
    [ 14.900710] ctp_fetch_sysconfig_para: exchange_x_y_flag = 0.
    [ 14.900719] gsl_ts_init: after fetch_sysconfig_para: normal_i2c: 0x40. normal_i2c[1]: 0xfffe
    [ 14.900855] script parser fetch err.
    [ 14.900868] ctp_init_platform_resource: tp_reset request gpio fail!
    [ 14.901300] ctp_detect: Detected chip gslx680 at adapter 1, address 0x40
    [ 14.901636] GSLX680 Enter gsl_ts_probe
    [ 14.901648] ==kzalloc success=
    [ 14.901655] [GSLX680] Enter gsl_ts_init_ts
    [ 14.911104] input: gslx680 as /devices/virtual/input/input3
    [ 14.911970] ctp_set_irq_mode: config gpio to int mode.
    [ 14.911984] ctp_set_irq_mode: config gpio to int mode.
    [ 14.912020] ctp_set_irq_mode, 323: gpio_int_info, port = 7, port_num = 11.
    [ 14.912028] INTERRUPT CONFIG
    [ 15.160038] ++++++++++++judge_chip_version+++++++++++
    [ 15.220535] =============gsl_load_fw_new start==============
    [ 15.915211] =============gsl_load_fw_new end==============
    [ 16.050696] [i2c1] incomplete xfer (0x48)
    [ 16.051212] gsl_probe: 0
    [ 16.051246] [GSLX680] End gsl_ts_probe

    ¿Es posible que puedas subir tu firmware para ver si es compatible?

  11. Corrijo, funciona aunque bootee desde 0 con Linux.

    El tema del eje invertido cambiando la siguiente línea:

    ev.value = y;

    por:

    ev.value = SCREEN_MAX_Y-y;

    Sin embargo la pantalla está descalibrada, y en los extremos no me detecta los toques, pero bueno, son detalles.

    Gracias por el driver estimado, cualquier avance que obtenga por estos lados, comento 🙂
    (Probaré pronto TabletWM a ver cómo me va)

  12. Pues añadiré la opción de invertir los ejes X e Y.

    Respecto a lo de los extremos… ¿qué resolución tiene la pantalla? Por defecto, el driver asume 800×480, pero puedes pasarle el parámetro -res XxY con la resolución real.

    Creo que podría usar la API de fbdev para saber en el arranque la resolución real…

  13. La resolución también es de 800×480 en este caso, mi tablet es bastante similar (solo que tiene dos cámaras). Ocupé un programa llamado xinput_calibrator que mejora un poco las cosas, pero siguen existiendo algunos problemas con los extremos.

  14. De hecho, es un solo extremo (el izquierdo que no me toma los toques) Quizás tiene que ver con el firmware (aunque lo dudo)… ¿Habría que convertir el binario a texto plano acaso?

  15. Bueno, acabo de subir una versión del driver que permite invertir los ejes si se desea.

    Respecto a lo de convertir el firmware a texto plano, no, no es necesario. El driver, tal y como está ahora, es capaz de diferenciar uno de otro y entiende ambos perfectamente. De todas formas, a lo mejor ese firmware no es el correcto, y tienes que buscar en otra parte de la flash de android…

  16. Estimado,

    Durante los meses que pasaron, la tablet estuvo en total tranquilidad en su cajón. Aprendí a modificar la BIOS de mi laptop, y por consecuencia a leer mejor los archivos binarios con un editor hexadecimal.

    El firmware lo había intentado extraer con el script subido acá ==> https://gitorious.org/gslx680-for-sunxi/gslx680-for-sunxi/source/fw_extractor

    Este script, detectó perfectamente el principio del archivo, pero lamentablemente no el final y me extrajo todos los datos hasta el final del módulo que viene en la tablet.

    Mirando un poco los firmwares que tenía a mano (los que funcionan en mi tablet, pero no en la resolución correcta) me di cuenta que la clave está en el registro de cada página que sigue una secuencia obvia (0x03, 0x04, 0x05…….0xb3) luego de 0xb3 en el firmware tuyo hay 2 bloques más (0xe0 y 0xe1) los cuales en otros firmwares de texto no están.

    En fin, recorté el archivo binario hasta el último valor de la página 0xb3, lo subí a la tablet, y eché a correr el driver. Funciona, me detecta los sectores del táctil que no me detectaba, sin embargo en ciertos puntos no me actúa bien, y quizás es por los dos bloques faltantes.

    Saludos, y espero que sea útil esta información.

  17. Miento. No es el algoritmo correcto. En tu firmware va en el 0x09 y pasa al 0x00 hasta el 0x02 y vuelve a la secuencia.
    En otro firmware SI va en orden, aparecen las páginas del 0x00 al 0xb3, luego hay 3 bloques más y vuelve a empezar desde el 0.

    En fin, me di por vencido extrayendo el firmware y topé con estos códigos fuentes:
    http://dl.linux-sunxi.org/SDK/A23-v1.0/unpacked/A23/lichee/linux-3.4/drivers/input/touchscreen/gslx680/

    Al final el que dice 1688_a70 me sirvió.

    Saludos

Responder a Henry López del Pino Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *