viernes, 20 de julio de 2007

Uso de readline y history

Para mejorar el interfaz de usuario de la aplicación de control del maestro se han usado las librerías libreadline y libhistory para poder editar fácilmente los comandos y tener una historia de los comandos introducidos anteriormente.

Lo primero que hemos hecho es instalar el paquete de desarrollo de las librerías:

sudo apt-get install libreadline5-dev

El paquete anterior incluye ambas liberías.

El siguiente paso es adaptar nuestro programa para usar ambas liberías. Para ello hay que tener en cuenta lo siguiente:

Para leer una línea de entrada, en lugar de gets o fgets se usará readline. El prototipo de esta función es:

char *readline (const char *prompt);

La función recibe como argumento una cadena que se usará como prompt, aunque si no se necesita se puede usar NULL. readline permitirá que el usuario introduzca su comando facilitando la edición de éste. Cuando el usuario pulse enter, la función devuelve un puntero a una cadena con el comando introducido, pero sin el \n. La función asigna memoria dinámicamente para la cadena, por lo que cuando terminemos de usarla tendremos que liberarla con un free().

Para almacenar un comando en el histórico se usa la función:

void add_history (const char *string);

Esta función almacena la cadena string en el histórico.

El proceso a seguir es por tanto leer la cadena con el comando, almacenarla en el histórico, usarla (interpretándola y ejecutando el comando correspondiente) y luego liberar la memoria asignada. Lo más apropiado en este caso es hacer una función que se encarge de realizar todo el proceso anterior salvo la interpretación del comando. Esta función será un sustituto de gets. El código de esta función es el siguiente:

/* Lee una línea usando libreadline y libhistory para permitir
editar la línea y tener una historia de los comandos tecleados
*/

char *rl_gets(void)
{
static char *plinea=(char *)NULL; /* Para guardar la línea devuelta por
readline */
if(plinea!=NULL){/* En la llamada anterior se devolvió una línea válida.
Como ya no la necesitamos liberamos la memoria.*/
free(plinea);
plinea = (char *)NULL;
}

plinea = readline("Comando > ");
if(plinea != NULL && plinea[0] != '\0'){
/* Se ha introducido una línea válida*/
add_history(plinea);
}

return plinea;
}

El modo de llamar a esta función es el siguiente:

#include
#include

main()
{
char *pcomando;

do{
pcomando = rl_gets();
InterpretaComando(pcomando);
}while(strcmp(pcomando, "quit")!=0);
}

Por ello rl_gets lo primero que hace es liberar la memoria de la cadena de la ejecución anterior de rl_gets, salvo que sea la primera ejecución o que haya devuelto NULL (devuelve un NULL si sólo lee como entrada un EOF). Luego lee la siguiente línea y si se ha leído correctamente (no es NULL) y contiene algún carácter (plinea[0] no es el caracter nulo) se almacena dicha línea en el histórico.

Por último, para compilar el programa no hay que olvidar de decirle al linker que incluya las librerías:

gcc -o prog prog.c -lreadline -lhistory

Más información


La información mostrada aquí está obtenida de la siguiente página:
Programming with GNU Readline

También tiene más información en las páginas del manual.

  • man readline

  • man history

lunes, 16 de julio de 2007

Instalando ddd

La última herramienta que falta para poder desarrollar en condiciones es un debugger. Aunque ya hemos instalado gdb, el interfaz en modo texto es un poco incómodo. Un buen interfaz gráfico para gdb es el ddd (Data Display Debugger), pero éste no está en los repositiorios de Ubuntu. Para poder instalarlo es necesario habilitar el repositiorio "universe". Para ello basta con editar /etc/apt/sources.list y descomentar las líneas:

deb http://es.archive.ubuntu.com/ubuntu/ dapper universe
deb-src http://es.archive.ubuntu.com/ubuntu/ dapper universe

deb http://security.ubuntu.com/ubuntu dapper-security universe
deb-src http://security.ubuntu.com/ubuntu dapper-security universe

Las dos primeras están por la mitad del archivo y las dos últimas al final.

Una vez habilitado el repositiorio "universe" basta con actualizar la lista de paquetes:

sudo apt-get update

Y luego instalar el paquete ddd:

sudo apt-get install ddd ddd-doc

viernes, 13 de julio de 2007

Accediendo al bus ISA en la MOPSlcdLX (2ª parte)

Hoy hemos conseguido por fín acceder a la tarjeta. Para ello nos hemos hecho un programa de prueba que busca por toda la memoria un registro especial de la tarjeta que tiene la particularidad que cuando se escribe un 0x9a después se lee un 0x65. Además dicho registro está mapeado en la posición 0xF80004 del mapa de memoria de 16 MB del bus ISA. Por tanto la tarea es fácil: buscar en cada bloque de 16 MB de la tarjeta si existe dicho registro "mágico".

Acceder a la memoria en Linux desde un programa de usuario no es algo inmediato, pero tampoco es nada complicado una vez que te lo explican.

En primer lugar es necesario abrir el "fichero" /dev/mem que es una "copia" de la memoria física del ordenador. Ojo, para ello es necesario ser root, por lo que el programa tendrá que ejecutarse teniendo esto en cuenta. La manera de abrirlo es:


fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd<0) {
perror("open(\"/dev/mem\")");
exit(1);
}
}


Una vez abierto el fichero se mapea una página de la memoria a un puntero para poder acceder a la memoria. Para ello se usa la función mmap:


#define MAP_SIZE 4096
#define MAP_MASK ( MAP_SIZE - 1 )
....
map = mmap(0,
MAP_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
addr & ~MAP_MASK
);
if (map == (void*)-1 ) {
perror("mmap()");
exit(1);
}

regaddr = map + (addr & MAP_MASK);

val = *(uint16*) regaddr;
munmap(0,MAP_SIZE);

El primer parámetro de mmap se suele dejar siempre a 0, el segundo indica el tamaño del bloque (que en este caso es una página de 4 kB). El tercero indica que queremos leer y escribir en la memoria. El cuarto indica que este mapeo puede compartirse con otros procesos que soliciten acceder a la misma página física y que la escritura en el bloque mapeado se realiza también en el "fichero" (y por tanto en la memoria física en este caso). El quinto indica el fichero que se mapea y por último se indica el desplazamiento dentro del fichero. Nótese que en dicho desplazamiento se han puesto a cero los bits menos significativos correspondientes a la dirección dentro de la página, pues lo que se quiere mapear es la página que contiene la dirección (addr) a la que queremos acceder.

La siguiente línea calcula la dirección dentro del bloque mapeado en la que se encuentra la dirección física que buscábamos. En la siguiente accedemos a dicha dirección y por último antes de terminar liberamos mapeo pues el número de éstos disponibles es limitado.

Este código se ha obtenido del programa pxaregs.c, disponible como casi todo en google ;)

Dicho programa encapsula todo el proceso de lectura/escritura en memoria física en dos funciones:


static uint16 getmem(uint32 addr);
static void putmem(uint32 addr, uint16 val);


Usando estas funciones hemos creado un programa que barre la memoria de la tarjeta buscando en cada bloque de 16 MB un registro mágico situado en la dirección 0x??F80004. Esto se consigue con este bucle:


for(n=0; n<256; n++){
dir_mag = (n<<24) | TCNMAGIC;
putmem(dir_mag, 0x9A);
valor = getmem(dir_mag);
printf("Dir: %x, valor: %x\n", dir_mag, valor);
}


Al ejecutar el programa resulta que el registro mágico aparece en todos los sitios excepto en donde ya existía memoria; es decir, que la tarjeta en cuanto se intenta acceder a una dirección que no está dada de alta como memoria RAM o como espacio de direcciones del PCI, la envía al bus isa. la ejecución del programa resulta en:


Dir: f80004, valor: 9a
Dir: 1f80004, valor: 9a
...
Dir: 1bf80004, valor: 9a
Dir: 1cf80004, valor: 65
...
Dir: eff80004, valor: 65
Dir: f0f80004, valor: 3568
...
Dir: fef80004, valor: 3568
Dir: fff80004, valor: 3568

Si se hace un cat de /proc/iomem nos sale:

00000000-0009efff : System RAM
000a0000-000bffff : Video RAM area
000c0000-000c7fff : Video ROM
000f0000-000fffff : System ROM
00100000-1bfbffff : System RAM
00100000-002ee668 : Kernel code
002ee669-00385c03 : Kernel data
20000000-2000ffff : 0000:00:09.0
e0000000-e7ffffff : 0000:00:01.1
effa0000-effbffff : 0000:00:09.0
effa0000-effbffff : e100
effe8000-effebfff : 0000:00:01.1
effec000-effeffff : 0000:00:01.1
efff0000-efff3fff : 0000:00:01.1
efff4000-efff7fff : 0000:00:01.2
efff8000-efffbfff : 0000:00:01.1
efffd000-efffdfff : 0000:00:0f.5
efffd000-efffdfff : ehci_hcd
efffe000-efffefff : 0000:00:0f.4
efffe000-efffefff : ohci_hcd
effff000-efffffff : 0000:00:09.0
effff000-efffffff : e100
fffe8000-ffffffff : reserved

jueves, 12 de julio de 2007

Accediendo al bus ISA en la MOPSlcdLX

Después de unos días de baja, por culpa de una infección de garganta, no por los malos ratos que me está dando esta tarjeta; volvemos al trabajo.

Visto que con las X no hay manera y que tenemos que terminar el proyecto en curso, nos conformaremos con la Xubuntu 6.06LTS que funciona perfectamente salvo que en modo VESA, por lo que el ratón va a saltos, pero al menos el sistema es usable con un poco de paciencia.

Lo que tenemos que hacer ahora es conseguir acceder desde un programa de usuario a una tarjeta colocada en el bus PC/104, la cual dispone de un espacio de memoria de 1MB a la que es necesario leer para configurar la tarjeta y poder trabajar con ella. El problema es. ¿Dónde demonios está situado ese MB de memoria? Si se ejecuta un lspci, la salida es:
> lspci
0000:00:01.0 Host bridge: Advanced Micro Devices [AMD]: Unknown device 2080 (rev 30)
0000:00:01.1 VGA compatible controller: Advanced Micro Devices [AMD]: Unknown device 2081
0000:00:01.2 Entertainment encryption device: Advanced Micro Devices [AMD]: Unknown device 2082
0000:00:09.0 Ethernet controller: Intel Corporation 8255xER/82551IT Fast Ethernet Controller (rev 10)
0000:00:0f.0 ISA bridge: Advanced Micro Devices [AMD]: Unknown device 2090 (rev 03)
0000:00:0f.2 IDE interface: Advanced Micro Devices [AMD]: Unknown device 209a (rev 01)
0000:00:0f.4 USB Controller: Advanced Micro Devices [AMD]: Unknown device 2094 (rev 02)
0000:00:0f.5 USB Controller: Advanced Micro Devices [AMD]: Unknown device 2095 (rev 02)


Como podemos ver existe un ISA bridge en el bus 0, slot F, función 0 (0:f.0). Si obtenemos más información acerca del bridge obtenemos:


>lspci -v -s 0:f.0
0000:00:0f.0 ISA bridge: Advanced Micro Devices [AMD]: Unknown device 2090 (rev 03)
Subsystem: Advanced Micro Devices [AMD]: Unknown device 2090
Flags: 66MHz, medium devsel
I/O ports at 6000 [size=8]
I/O ports at 6100 [size=256]
I/O ports at 6200 [size=64]
I/O ports at 1000 [size=32]
I/O ports at 9d00 [size=128]
I/O ports at 9c00 [size=64]


Que como vemos dispone de muchos huecos para puertos de entradas/salida (supongo que serán los de periféricos como el ratón, teclado, etc.) pero no aparece nada de memoria RAM de dispositivos del bus ISA. Por tanto, para poder ver la memoria de la tarjeta desde la CPU habrá que hacer un poco de magia negra.

Lo primero que hemos hecho es buscar en la BIOS alguna opción que permita una configuración manual del bus ISA, pero no hemos encontrado nada.

Lo que sí hemos encontrado en la BIOS es una opción denominada algo parecido a:

PS/2 mouse DISABELED
Arghhhh. La m.... que p.... a los de Kontron. Por defecto ponen el ratón inhabilitado en la BIOS y no indican semejante cosa con luces de neón en sus manuales. ¡Vamos hombre! Pa matarlos.

Resulta que el ratón iba mal porque al inhabilitarlo en la BIOS las interrupciones del ratón no llegaban a la CPU y las pobres X debían de estar haciendo polling. Ahora el ratón ya va como la seda. Si pudiera les pedía indemnización a los de Kontron ;)

Volviendo al tema de la tarjeta, como vamos a tener que acceder al HW, necesitamos instalar los includes del kernel, y de paso aprovechamos también para instalar nuestro editor favorito: emacs y las páginas de manual para desarrollo (llamadas al sistema y a las librerias). Los paquetes elegidos son:
linux-headers-2.6.15-26 emacs21 manpages-dev glibc-doc

Con esto ya podemos empezar ha hacer pruebas con la dichosa tarjetita, pero eso será en el siguiente "post".

viernes, 6 de julio de 2007

Y seguimos reinstalando

Esto ya parece una pesadilla. Hemos verificado el CD y está grabado perfectamente. Para verificarlo hemos calculado el "checksum" del disco:

> umount /media/cdrom
> md5sum /dev/cdrom

La MD5 que nos dió era idéntica a la de la ISO de xubuntu. Por tanto, lo más probable es que el CD del PC104 estuviera ayer un poco vago.

Hemos probado a instalarlo de nuevo y ahora nos da problemas en otros ficheros. Tenemos por tanto dos alternativas: o volver a grabar el CD con la xubuntu o probar con una debian "netinstall" que lee todos los paquetes de la red. Como parece que el CD del PC104 no quiere trabajar mucho, vamos a probar con la segunda opción a ver si ya de una puñetera vez arranca esto.

La Debian elegida es la 4.0r etch (testing). Hemos descargado una de las imágenes generadas a diario, que contienen lo último de lo último. Está en la página:

http://cdimage.debian.org/cdimage/daily-builds/daily/arch-latest/i386/iso-cd/


y el archivo descargado ha sido: debian-testing-i386-netinst.iso

Una vez instalado, no sin dar un poco de guerra el CD de nuevo, resulta que las X no arrancan.

Antes de tirarnos por un barranco decidimos compilar el driver del dichoso lx800. Repetimos los pasos de la primera entrada y luego nos acordamos de la m... que p... al que ha escrito el driver, pues las instrucciones de instalación no dicen nada de nada.

Al final suponemos que se instala como la mayoría de estos chismes:
> ./autogen.sh
> make
> make install

Esto coloca los drivers en el directorio /usr/local/lib/xorg/modules/drivers/

Pero la debian los tiene en /usr/lib/xorg/modules/drivers

Por tanto basta con copiar el driver del amd_lx800 a su sitio y modificar el archivo /etc/X11/xorg.conf para que use el nuevo driver.

Tras cruzar los dedos mientras arranca el sistema, resulta que ahora se queda frito el ordenador entero (antes sólo la pantalla) y no podemos entrar ni desde fuera por ssh.

Moraleja: el driver del lx800 no tira muy bien que digamos. Creo que optaremos por usar la Xubuntu 6.06 aunque tenga las X sin aceleración hardware.

Mañana más.

jueves, 5 de julio de 2007

Reinstalando

Como compilar las X es un marrón y el driver del lx800 está desarrollado para la última versión de x.org (7.2), hemos decidido actualizar la Xubuntu a la última versión (7.04), que tras mucho mirar en la web de Ubuntu parece que trae esta versión de X por defecto.

Esta versión arranca bien en modo gráfico, pero por más que se mueva el ratón, el cursor de la pantalla ni se entera. Si conoce las recientes versiones de Ubuntu sabrá que para instalar el operativo es necesario hacer doble click en el icono de Instalar, tarea arduo difícil si el ratón no funciona. La opción ahora es descargar un nuevo CD con la versión de instalación en modo texto y rezar para que al actualizar la versión el ratón funcione o intentarlo con la versión 7.10. Esta versión es de pruebas, pero como somos gente valiente no nos vamos a asustar por semejante tontería.

Bueno, pues después de pasar un buen rato descargando la versión 7.10, 5 minutillos grabando el CD y otro buen rato esperando a que arranque, ahora resulta que ni siquiera funcionan las X. Vamos, que caminamos como los cangrejos: para atrás. ¡Tres hurras vicevérsicos para Xubuntu!

Siguiente intento, y van ya unos cuantos. Probamos con Xubuntu 7.04 alternate, que permite la instalación en modo texto, con la esperanza que una vez instalado y actualizado funcionen las X y el ratón. Nuevamente se repite el proceso de descarga, grabado de CD, instalación y ... ¡Cha Chaaaan! el CD se ha grabado mal. ¡Otros tres hurras vicevérsicos para la grabadora de CD y el CD regrabable!

Resumen: un día perdido entre unas cosas y otras. Mañana más y mejor.

miércoles, 4 de julio de 2007

Instalando Instalando

Antes de hacer nada, lo que hemos hecho ha sido actualizar el sistema. Para ello basta con usar el gestor de actualizaciones. Está en el menú de sistema.

La distribución Xubuntu viene pensada de serie para usuarios normales. Los usuarios "anormales" que se dedican a programar o a compilarse sus propios drivers necesitan algunas herramientas más interesantes. Los paquetes que nos hemos instalado han sido:

Para poder obtener los drivers se necesita un sistema de control de versiones denominado git, que es el mismísimo usado en el kernel de Linux. Los paquetes son:

git-core git-doc gitk

El tercero es un interfaz gráfico para manejar el repositiorio.

Después se necesita el compilador y sus amiguetes, como librerías de desarrollo, depurador, make, etc. Los paquetes son:

autoconf automake1.9 gcc make libtool flex bison gdb libc6-dev

También hace falta el paquete para desarrollo de Xorg:

xserver-xorg-dev xorg-dev

Después de bajar tanto paquete podemos aprovechar para poner el cacharro en hora. Para ello en el menú del sistema se selecciona "Hora y fecha". En la ventanita que aparece se seleciona que use NTP para no tener que meter la hora a mano cada vez que se arranque el chisme este, ya que no tiene batería. Como no se instala el NTP por defecto lo instala automáticamente en este momento. ¡Tres hurras por Xubuntu!

Una vez instalado todo el software necesario, hay que bajarse el driver. Para ello usamos el siguiente comando:

> git clone git://git.freedesktop.org/git/xorg/driver/xf86-video-amd lx800Driver

Esto nos descargará el driver en el directorio lx800Driver. Para compilar el driver basta con entrar en el directorio lx800Driver y teclear:

> ./autogen.sh
> make

Si has seguido estos pasos te dará el mismo error que a mí:

In file included from amd_dcon.c:37:
/usr/include/unistd.h:189: error: conflicting types for 'xf86ssize_t'
/usr/include/xorg/xf86_libc.h:86: error: previous declaration of 'xf86ssize_t' was here

Tiene toda la pinta que el driver está pensado para otra versión de xorg...

Mañana más.

Ya tenemos tarjeta nueva

Acabamos de conseguir un nuevo juguetito: una placa PC/104 de Kontron basada en el procesador AMD LX800 (Geode). El modelo concreto es MOPSlcdLX.

Obviamente lo primero que hemos hecho es instalarle Linux. La distribución elegida es la Xubuntu, pesada para equipos de pocas prestaciones, como es el caso.

La instalación por defecto no da ningún problema, pero al tener un controlador de VGA un poco raro (integrado en el LX800) solo funciona en modo VESA sin acceleración, por lo que va a pedales. Existe un driver proporcionado por AMD, pero en forma de código fuente, por lo que toca recompilar las X.org.

En sucesivas entradas detallaremos el proceso de instalación.