Archivo por meses: agosto 2013

Galletitas

Parece que ha empezado la trasposición de la ley europea de cookies, y ahora es obligatorio que cualquier página web que haga uso de cookies lo avise claramente. Por eso a partir de ahora aparecerá un pequeño aviso en la parte inferior de mi página (aunque una vez eliminado, no volverá a aparecer).

Desde luego quiero dejar claro que YO (el autor del blog) no almaceno ni utilizo ninguna información personal de los usuarios que visitan esta página. No tengo Google Analytics ni ninguna otra herramienta de seguimiento ni publicidad, y hasta donde yo se, no se debería estar almacenando ningún tipo de información privada sin consentimiento expreso del usuario.

Actualización: tras hacer algunas pruebas, veo que el mero hecho de tener un vídeo de Youtube insertado hace que aparezcan sendas cookies, una de Youtube, y otra de Google. Por otro lado, el pulsar en los botones Me gusta de Facebook, o +1 de Google+ hace que se inserten cookies de estos dos sitios, como cabe suponer.

Actualización 2: la mera visita de mi blog hace que se almacene una simple cookie, que indica que ya se visitó esta página en alguna ocasión. Esta cookie permite, por ejemplo, evitar mostrar constantemente el aviso de que se almacenan cookies y demás.

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.

 

Pantalla tactil

Por fin he conseguido acceder a la pantalla táctil. Esta tablet lleva un controlador GSL1680, para el cual no hay casi documentación. Sin embargo, pude encontrar un presunto driver, y de él sacar mucha información.

Después de muchas pruebas fui capaz de leer las coordenadas, pero sólo si arrancaba Linux en caliente (o sea, si arrancaba primero Android y luego reiniciaba). Si apagaba a machete la tablet y encendía directamente en Linux, no funcionaba.

Tras investigar, descubrí que el motivo es que el chip necesita que le envíen el firmware para funcionar. Si arrancaba Android, éste le metía dicho firmware, y al reiniciar todo seguía funcionando. Pero si apagaba la tablet, al quedarse sin corriente, el firmware se borraba, y es necesario volver a cargarlo.

Encima, parece que el firmware es específico para cada modelo. Afortunadamente, en el caso de mi tablet éste estaba disponible en un fichero de texto, en /system/etc.

Los detalles específicos de programación los he escrito en la página sobre el GSL1680 en linux-sunxi, y como no me apetece repetirlo todo, me limitaré a poner un enlace.

Gestion de energia

Nuevos cambios en la configuración del núcleo. Para que la gestión de energía funcione y la tablet se apague realmente al utilizar shutdown -h now o halt, y que apm -v devuelva el nivel actual de batería, es necesario activar las siguientes opciones:

    Power management options --->
        Run-time PM core functionality=Y
        Advanced Power Management Emulation=y
    Device Drivers --->
        Power supply class support=Y --->
            AXP Power drivers=Y --->
                AXP PMU type=AXP20 driver
                AXP initial charging environment set=Y
                AXP charging current set when suspendresumeshutdown=Y
            APM emulation for class batteries=Y
        Voltage and Current Regulator Support=Y --->

La última es necesaria para que aparezcan las de AXP Power drivers.

Teclados Logitech

Para trabajar con más comodidad con la tablet decidí utilizar un teclado con touchpad integrado. En casa tenía un modelo Logitech, así que lo conecté; sin embargo, no funcionó. Lo curioso es que desde Android sí funcionaba, así como en mi PC, así que decidí hacer algunas pruebas extra. Al final descubrí que para que estos dispositivos, que utilizan el Logitech Unifying Receiver, funcionen, es necesario activar no sólo el soporte HID completo en el núcleo, sino también las opciones siguientes opciones:

    Device Drivers --->
        HID devices=Y --->
            Generic HID support=Y
                /dev/hidraw raw HID device support=Y
            USB Human Interface Device (full HID) support=Y
            /dev/hiddev raw HID device support=Y

Wifi, sonido y mas

Actualizado. Después de mucho pelearme con mi tablet, finalmente he conseguido que funcionen casi todos los dispositivos. También he pulido el proceso de instalación de Linux; de hecho hay bastantes cosas que cambiar del artículo anterior, así que vamos allá.

El fichero SCRIPT.BIN

En primer lugar quería disponer del fichero script.bin original de mi tablet, y no de uno creado para otro dispositivo, porque obviamente podía haber algún parámetro (velocidad de memoria, puertos de dispositivos, etc) que tuviese un valor diferente, evitando que funcionase algún dispositivo. De hecho, una vez que conseguí utilizarlo, el sonido funcionó automáticamente (antes no detectaba ninguna tarjeta de sonido).

El proceso para obtener dicho fichero bin no fue sencillo: dicho fichero está en la flash interna de la tablet, pero por desgracia no tenía acceso a ella desde Linux (no detecta dicho dispositivo) ni desde Android (lo detecta, obviamente, pero no tengo permisos de acceso por no tener la tablet rooteada. Además, al ser la partición de arranque, no se monta una vez lanzado Android, por lo que tampoco está disponible desde éste). Tras muchos intentos encontré la solución: utilizar el ADB (Android Debug Bridge). Esto permite acceder a un dispositivo Android desde un PC. Para ello, una vez instalado el kit de desarrollo de Android, basta conectar la tablet al PC a través de un puerto USB, ir al directorio sdk/platform-tools y ejecutar:

    sudo ./adb start-server
    ./adb shell
    cat /dev/block/mmcblk0p1 > punto_de_montaje_de_tarjeta_SD/particion1.img
    exit
    sudo ./adb kill-server

El primer comando lanzará como root el servidor ADB, que se conectará a nuestro dispositivo, y el segundo lanzará una shell como root en él. El tercero, ejecutado ya desde la shell del dispositivo, volcará la primera partición de la flash en el fichero particion1.img de la tarjeta SD. Por último, salimos de la shell y desactivamos el servidor ADB.

En ocasiones adb no encuentra nuestro dispositivo. Si tecleando ./adb devices no aparece ningún dispositivo detectado, es posible que adb no tenga a nuestro fabricante en su lista. Para añadirlo manualmente hacemos un lsusb, y vemos el identificador de nuestra tablet. Digamos que es AAAA:BBBB (dos números en hexadecimal de cuatro cifras cada uno). Sólo tenemos que editar ~/.android/adb_usb.ini y añadir en él 0xAAAA, reiniciar el servidor adb, y listo.

Ahora sólo tenemos que llevar el fichero particion1.img a un PC con linux y montar dicha partición, por ejemplo en /mnt:

    sudo mount -o loop particion1.img /mnt

Ahí encontraremos el fichero script.bin, que podremos convertir en un fichero .fex mediante la utilidad bin2fex, que encontraremos en el repositorio sunxi-tools. De hecho es necesario hacerlo para poder hacer un par de modificaciones, sin las que nuestro Linux no arrancaría desde la tarjeta SD. En concreto éstos son los cambios:

@@ -12,7 +12,7 @@
 pll4_freq = 960
 pll6_freq = 720
 power_start = 0
-storage_type = 2
+storage_type = 1

 [pm_para]
 standby_mode = 0
@@ -445,7 +445,7 @@
 sdc_wp =

 [mmc2_para]
-sdc_used = 1
+sdc_used = 0
 sdc_detmode = 3
 bus_width = 8
 sdc_cmd = port:PC06<3><1><3><default>
@@ -510,7 +510,7 @@
 usb_id_gpio =
 usb_det_vbus_gpio =
 usb_drv_vbus_gpio = port:power203<1><0><default><0>
-usb_host_init_state = 0
+usb_host_init_state = 1

 [port_pm]
 restrict_1a = 0

El primero cambia el tipo de almacenamiento de Flash a SD. El segundo especifica que no se active la memoria Flash interna (si se activa, no arranca el sistema). Por último, el tercero activa desde el principio el segundo USB, necesario para que funcione la red WiFi.

Existe una lista con todas las opciones de un fichero FEX, útil si se quieren hacer más cambios manuales.

Una vez hechos estos cambios ya podemos generar el fichero script.bin final, siguiendo el método indicado en el artículo anterior.

El kernel

En el núcleo también hay que hacer algunos cambios. Para empezar, hay que utilizar la versión 3.4, en lugar de la 3.0, porque es la que tiene soporte para la tarjeta de red:

    git clone -b sunxi-3.4 https://github.com/linux-sunxi/linux-sunxi linux-3.4-sunxi
    cd linux-3.4-sunxi

De todas formas, el chip que lleva esta tablet es el Realtek RTL8188etv. Aunque en teoría es compatible con el driver para la familia RTL8188, en la práctica hay que añadir una línea para que reconozca el identificador USB de este chip concreto. Aunque ya envié el parche a la lista de correo, lo añado aquí porque no se cuanto tardarán en añadirlo:

diff --git a/drivers/net/wireless/rtl8188eu/os_dep/linux/usb_intf.c b/drivers/net/wireless/rtl8188eu/os_dep/linux/usb_intf.c
index 5f4390a..df9d488 100644
--- a/drivers/net/wireless/rtl8188eu/os_dep/linux/usb_intf.c
+++ b/drivers/net/wireless/rtl8188eu/os_dep/linux/usb_intf.c
@@ -185,7 +185,8 @@ static struct usb_device_id rtw_usb_id_tbl[] ={
 #endif
 #ifdef CONFIG_RTL8188E
        /*=== Realtek demoboard ===*/           
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)},//Default ID        
+       {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)},//rtl8188etv ID (szenio 1207 tablet)
 #endif
        {}      /* Terminating entry */
 };

Una vez aplicado este cambio de una única línea, podemos ya proceder a configurar el núcleo. Para ello partimos de la configuración genérica para el A13:

    make ARCH=arm a13_defconfig
    make ARCH=arm menuconfig

Estas son las opciones que he modificado:

    General Setup
        POSIX message queues=Y
    Device Drivers
        Network Device Support
            Ethernet (10 or 100Mbit)=N
            Wireless LAN
                Realtek 8188E USB WiFi=M
        Character Devices
            Non-standard serial port support=N
            Serial drivers
                8250/16550 and compatible serial support=N
        Graphics support
            Console Display driver support
                Map the console to the primary display device=Y
            Bootup logo=Y
    Security Options
        Enable the securityfs filesystem=N

Una vez hecho, podemos ya proceder a compilarlo, pero con el compilador que utilice la gnueabihf (que utiliza coma flotante por hardware, en lugar de la gnueabi, como hacía en el artículo anterior). Para ello primero necesitamos instalar esta versión del compilador:

    sudo apt-get install gcc-4.7-arm-linux-gnueabihf gcc-arm-linux-gnueabihf

y ya podemos compilar el núcleo en sí:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=out modules
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=out modules_install

Los ficheros boot.cmd y boot.scr

El último cambio respecto al artículo anterior está en el fichero boot.cmd (y su fichero hijo boot.scr). Este fichero contiene los parámetros de arranque del núcleo, y es básicamente un script para U-Boot. En nuestro caso, crearemos el fichero boot.cmd en la partición VFAT de nuestra tarjeta SD con este contenido:

    setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait panic=10 ${extra}
    fatload mmc 0 0x43000000 script.bin
    fatload mmc 0 0x48000000 uImage
    bootm 0x48000000

y lo compilaremos con:

    mkimage -C none -A arm -T script -d boot.cmd boot.scr

Y listo. Si en algún momento queremos cambiar las opciones de arranque de nuestro núcleo, sólo tendremos que editar el fichero boot.cmd, añadirlas en la primera línea y recompilarlo. Existe una página con todas las opciones del núcleo específicas de sunXi.

Encender y apagar el sistema

De momento no está activa la gestión de energía, por lo que si se hace un halt o un shutdown -h now, el sistema parecerá apagarse, pero en realidad seguirá encendido. En estos casos, para apagarlo «de verdad» es necesario mantener pulsado el botón de encendido durante seis o más segundos.

Arrancando Linux en la tablet

Actualizado: Hoy me puse a intentar meter Linux en la tablet de la que hablé en la anterior entrada. Y lo he conseguido, he aquí la prueba:

tablet_linux

Dado que esta tablet está equipada con un Allwinner A13, necesitamos un kernel y un cargador adecuados. Lo interesante de este chip es que no hace falta tocar la flash interna, sino que basta con ponerlos en una tarjeta SD, y arrancará desde ésta directamente. Y si luego queremos volver al sistema original, basta con retirar la tarjeta y reiniciar.

El núcleo y el cargador los podemos obtener del repositorio GIT linux-sunxi, orientado precisamente hacia este tipo de SoCs. Las instrucciones básicas para compilar y generar todo las saqué de la página de Olimex, y las he adaptado a este modelo.

Supondré que tienes una distribución basada en Debian. Lo primero que hay que hacer es instalar los paquetes de compilación cruzada y otras bibliotecas necesarias:

    sudo apt-get install gcc-4.7-arm-linux-gnueabi gcc-4.7-arm-linux-gnueabi-base gcc-arm-linux-gnueabi libncurses5-dev uboot-mkimage build-essential git libusb-dev libusb-1.0-0-dev

Ahora bajamos el u-boot modificado con:

    git clone -b sunxi https://github.com/linux-sunxi/u-boot-sunxi

Entramos en el directorio u-boot-sunxi y compilamos el código:

    cd u-boot-sunxi
    make CROSS_COMPILE=arm-linux-gnueabi- a13-olinuxino
    ls -l u-boot.bin spl/sunxi-spl.bin
    cd ..

Ahora que tenemos compilado el cargador, vamos con el núcleo. Nos lo bajamos desde el repositorio, preparamos una configuración base y entramos en modo configuración:

    git clone -b sunxi-3.0 https://github.com/linux-sunxi/linux-sunxi
    cd linux-sunxi
    make ARCH=arm a13_defconfig
    make ARCH=arm menuconfig

tablet_config

Entre las opciones que he tocado están las siguientes:

  • General Setup
    • POSIX message queues -> Y
  • System Type
    • Emulate SWP/SWPB instructions -> N
  • Device Drivers
    • Network Device Support
      • Ethernet (10 or 100Mbit) -> N
    • Character Devices
      • Non-standard serial port support -> N
      • Serial drivers
        • 8250/16550 and compatible serial support -> N
    • Console Display driver support
      • Map the console to the primary display device -> Y
    • Bootup logo -> Y
  • Security Options
    • Enable the securityfs filesystem -> N

 

Una vez configurado, procedemos a compilar el núcleo:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=out modules
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=out modules_install

Ahora llega el momento de generar la tarjeta SD con el sistema básico. Para ello, primero necesitamos dividirla en, al menos, dos particiones, una en formato VFAT (donde irá el núcleo) y otra en formato EXT2/3/4 con el sistema en sí. Así que arrancamos fdisk y empezamos. Es importante que la primera partición empiece, al menos, en el sector 2048, para dejar sitio para el arranque.

Una vez formateadas ambas particiones, descargamos un sistema Debian base, lo descomprimimos en la partición EXT2/3/4 (que supondremos que está montada en /media/particion2) y copiamos los módulos (asumiendo, también, que la versión de núcleo que tenemos es la 3.0.76):

    wget http://rcn-ee.net/deb/rootfs/wheezy/debian-7.1-console-armhf-2013-07-22.tar.xz
    tar xvf debian-7.1-console-armhf-2013-07-22.tar.xz
    sudo tar -C /media/particion2 -xvf debian-7.1-console-armhf-2013-07-22/armhf-rootfs-debian-wheezy.tar
    cd ../linux-sunxi
    sudo cp -a linux-allwinner/out/lib/modules/3.0.76/ /media/particion2/lib/modules/

Es importante descomprimirlo como root para que conserve los nombres de usuario correctos.

Ahora bajamos los ficheros de definición de placas y las utilidades, y las compilamos:

    git clone https://github.com/linux-sunxi/sunxi-boards
    git clone https://github.com/linux-sunxi/sunxi-tools
    cd sunxi-tools
    make

Ahora vamos a generar el fichero script.bin, necesario para configurar el núcleo durante el arranque. Para ello utilizaremos las utilidades que acabamos de compilar y el fichero de configuración a13_mid.fex, situado en el repo sunxi-boards, por ser el más parecido a nuestra tablet:

    ./fex2bin ../sunxi-boards/sys_config/a13/a13_mid.fex script.bin

El siguiente paso consiste en copiar el fichero uImage y script.bin en la partición VFAT de nuestra tarjeta SD:

    cp script.bin /media/particion1
    cd ../linux-sunxi
    cp arch/arm/boot/uImage /media/particion1

Por último sólo queda instalar u-Boot en la tarjeta, para lo cual hacemos (asumiendo que la tarjeta está en /dev/sdX):

    cd ../u-boot-sunxi
    sudo dd if=spl/sunxi-spl.bin of=/dev/sdX bs=1024 seek=8
    sudo dd if=u-boot.bin of=/dev/sdX bs=1024 seek=32

Y con esto ya está. Sólo queda meter la tarjeta SD en la tablet, encenderla, y conectar un teclado USB.

El próximo paso será intentar activar la WiFi, algo que me está dando bastantes quebraderos de cabeza.

Amplificando mi tablet

Recientemente me compré una pequeña tablet Szenio 1207 que estaba de oferta en unos grandes almacenes. Se trata de un cacharro bastante limitado y que no recomiendo para uso habitual: su procesador no tiene suficiente potencia para mover de manera fluida Android 4.0, por lo que la interfaz se atasca constantemente al intentar utilizarla para navegar o leer el correo (una de las cosas que quiero hacer más adelante es intentar meterle un linux con Debian o Gentoo a ver si mejora).

Sin embargo, para mí es perfecta porque sólo la quiero para ver algún que otro capítulo de series mientras pedaleo en la bicicleta estática del gimnasio (aunque éstas tienen una televisión, estoy harto de ver una y otra vez los mismos capítulos de Rex, el perro policía, y me niego a tragarme a Ana Rosa y similares). En este caso funciona bien porque no hay interacción con el usuario.

Por desgracia el gimnasio es un entorno bastante ruidoso: entre las máquinas y el hilo musical, el volumen que da la tablet a través de los cascos es insuficiente. Por este motivo decidí añadirle un pequeño amplificador de sonido. Casualmente, rebuscando entre la cacharrada que tengo en el taller encontré el viejo amplificador de sonido que construí para mi viejo Spectrum (y que, posteriormente, había reutilizado en un DAC de sonido para mi primer PC), así que decidí aprovecharlo en lugar de ensamblar uno nuevo.

El diseño está basado en el chip LM386, un amplificador de sonido que permite construir equipos con muy pocos componentes y especialmente orientado para su uso con baterías. Este es el esquema (sí, aunque no lo parezca es correcto: no necesita realimentación porque su ganancia interna, por defecto, es de 20. En el datasheet aparece exactamente igual, y garantizo que funciona con la ganancia indicada):

amplificador_tablet2

Como se ve, el amplificador no es estéreo, por lo que tuve que cortocircuitar los canales derecho e izquierdo. Una vez conectado el circuito, lo monté en una pequeña caja con una pila de 9 voltios y demás:

amp1amp2

amp3

Una vez montado quedaba la cuestión de cómo fijarlo a la tablet para no andar con él colgando por ahí. La solución que se me ocurrió fue utilizar velcro para sujetarlo por detrás. De esa manera hace también la función de atril, inclinando el tablet hasta una posición más cómoda, y permite montarlo y desmontarlo las veces que se desee. Además, como mejor se ve la pantalla en el gimnasio es con la tablet «boca abajo», así que decidí poner velcro en todas las esquinas para así poder orientarla en cualquiera de las cuatro posiciones posibles. Para pegar el velcro a la tablet y a la caja del amplificador utilicé cinta adhesiva de doble cara:

amp4amp5

amp6

¡Y ya está!

amp7

Un detalle importante es que ahora es necesario ajustar el volumen de la tablet casi al mínimo. Cuando hice la primera prueba casi me quedo sordo por culpa de la potencia que saca.