G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!
Tarjetas sintonizadoras: Aprender mirando
Por Cherry George Mathew
Traducción al español por Pepa Suárez Poch
el día 15 de Julio 2003, para La Gaceta de Linux
 

Introducción:

Con suerte, este artículo ayudará a aquellos que estén pensando en programar un driver para tarjetas sintonizadoras y también a los que simplemente estén interesados en el funcionamiento de las tarjetas de televisión.

1 Acrobacias de un aficionado

Es increible el trabajo hoy en día. Uno tiene cientos de mensajes a los que responder, el informe de un análisis de calidad que entregar esta tarde, una presentación de negocios que preparar y un montón de códigos que estudiar para eliminar errores. Y no sólo eso, además echan en la televisión tu programa favorito, ese que no te perderías por nada del mundo. ¿Cómo solucionarlo? Encendiendo la tarjeta de TV, está claro, para así poder ver el programa en una ventana independiente en la parte superior izquierda de la pantalla del ordenador. ¡Es trabajo, no placer, por supuesto! Además, es possible minimizar la ventana de video si dejar rastro de ella siembre que al jefe le de por echar un vistazo por encima de tus hombros. Incluso podrías ejecutarla a pantalla completa y hacerle una señal para que viniese, si es que también es seguidor del programa. ;-) ¡Ah, las maravillas de la tecnología!

La plataforma Linux soporta un gran número de tarjetas sintonizadoras, así como cámaras web y una amplia gama de otros dispositivos multimedia. Además, al igual que ocurre con otros sistemas operativos, las áreas de los programas de aplicación y el kernel proper estan bien delimitados y diseñados con claridad. Video4Linux, o V4L, nombre que recibe la tecnología, sigue estando en proceso de desarrollo de la version 1, todavía un borrador, a la versión 2, mucho más robusta. Al mismo tiempo, se están creando una gran cantidad de drivers, en principio relacionados con el conjunto de chips, pero cada vez más en lo que se refiere a otro tipo de modelos. Los programas de aplicación se centran en desarrollar interfaces basadas en GUI sencillas para el usuario, tanto para ver televisión, como para grabar al disco, decodificar y leer el teletexto y demás. En lo que se refiere a la visualización de la televisión, el programador de aplicaciones tiene que realizar tareas tales como abrir una ventana del tamaño justo en la pantalla, ordenar al driver adecuado que proyecte la imagen dentro de dicha ventana (overlay), cambiar el tamaño del área de visualización y conseguir que el tamaño de la imagen se ajuste al mismo tiempo, así como sintonizar, a petición del usuario, un determinado canal o cambiar la entrada del sintonizador a modo AV, o simplemente desactivar el sonido. Por tanto, la aplicación se encuentra en el lado opuesto al driver de sintonización y pasa, a petición del usuario, al diver siguendo un procedimiento previaente establecido que recibe el nombre de Application Programer Interface (API).



API
			  figure



Esto se explicará en detalle más adelante.Por otro lado, los programadores de drivers de dispositivo se centran en traducir las peticiones del usuario, mencionadas con anterioridad, en intrucciones del hardware a la tarjeta sintonizadora. También se aseguran de que exista comunicación con las aplicaciones por medio de la API del V4L . Por lo tanto los drivers de dispositivo están situados entre el hardware y la aplicación, reciben órdentes de estos, las traducen y las envían al hardware subyacente, y todo esto en la jerga propia de las máquinas.

En las próximas páginas pondremos a prueba nuestra paciencia. Mostraremos, el uno al otro, entre otras cosas, cómo funcionan las tarjetas sintonizadoras de televisión, de qué están hechas, qué tipos existen, cómo hacerlas funcionar a través en Linux, etc. Utilizo la expresión «mostrar el uno al otro» ya que, al intentar redactar este artículo, tuve que realizar algunas investigaciones. ¡Y todo por ti, querido lector! Así que es mutuo. Por lo tanto, coge lapiz y papel, pónte cómodo y a leer.

Aviso: No dormirse en los laureles. Se realizará una prueba al final
Palabras clave: bus PCI , bus I2C , IF (Frecuencia Intermedia), Procesador de video, memoria intermedia, DMA y IRQ.

1

2 Tarjetas sintonizadoras al desnudo



API
			  figure



Muy bien, ahora veamos qué aspecto tiene una tarjeta sintonizadora de televisión. Lo más normal es que en ella localicemos al menos tres chips funcionales.

2.1 El módulo sintonizador

El «chip» sintonizador es en realidad un panel con todos los componentes de radio frecuencia, muy bien recubierto por una capa plateada, es decir, por una capa protectora. Echa un vistazo al diagrama. Los módulos de sintonización aparecen en paquetes distintos, los cuales presentan a menudo un aspecto muy similar. El cable de antena se conecta directamente en la ranura que se encuentra en un extremo del módulo de sintonización. La función del módulo de sintonización es realizar trucos con el mezclador de radio frecuencia, con el que se sintonizan los distintos programas de televisión. Sea cual sea la frecuencia que utilice el canal de televisión, esta se convierte en una frecuencia intermedia (IF) predeterminada. En verdad esta frecuencia «predeterminada» es desastrosa por motivos históricos (¿políticos?). Cada señal de televisión (por ejemplo PAL, SECAM, NTSC, etc) utiliza una IF propia. Sea cual sea ésta, el sintonizador tiene un sólo cometido: reconocer los miles de frecuencias de ondas de radio existentes en el universo y, a petición tuya, filtrar para ti sólo la cadena adecuada. En la «sección I2C»5, descubriremos como «a petición tuya» el módulo sintonizador encuentra tu canal deportivo favorito.

2.2 El procesador de video o decodificador de TV

La IF que llega del módulo sintonizador tiene que ser descodificada y transformada a un formato visionable. En esto consiste el trabajo del Procesador de Video. Los formatos visionables, por razones históricas, de nuevo, pueden presentar varias formas y tamaños. Cuentas con el antiguo formato plano de mapa de bits, formato VGA, paletizado y planarizado (sea cual sea su significado), formato RGB (siglas inglesas de Red Green Blue, rojo, verde y azul), formato YUV (y todas sus ligeras variantes) y, por supuesto, unos cuantos formatos registrados. Si tienes habilidad para leer entre líneas, tendrías que haver adivinado que la «transformación» a la que me refería antes incluye demodulación y conversión de señal análoga a digital, que, al fin y al cabo, es de lo que se tratan las tarjetas sintonizadoras. Cuando estás viendo la televisión en tu ordenador, lo que realmente estás presenciando es cómo el adaptador VGA muestra los datos de video digitalizados del procesador de video. Bien, ya podemos dividir el proceso en dos pasos:

  1. El Procesador de Video digitaliza los datos y los vuelca a la memoria intermedia.
  2. El adaptador VGA recopila datos de video de la memoria intermedia y los muestra en la pantalla.
Antes de detallar cómo se desarrolla este proceso, es necesario entender el significado de «memoria intermedia». La memoria intermedia, también conocida como buffer de video o frame RAM, normalmente se encuentra en la tarjeta VGA (pido a los expertos un poco de paciencia y que olviden por el momento el AGP).

API figure

Cualquier tipo de dato que se encuentre en la memoria intermedia es visualizada de forma inmediata en la pantalla. De esto se ocupa el controlador VGA. Si lo que quieres es mostrar algo en la pantalla, lo único que tienes que hacer es volcar los datos a la memoria intermedia y ¡voila! al momento aparecerán en la pantalla. En la mayoría de las plataformas, para copiar datos de la memoria sólo es necesario la memoria plana ya que la memoria intermedia, al igual que cualquier otra memoria RAM, viene mapeada en una dirección de memoria física. Sin embargo, en un sistema que utiliza algún tipo de protección de memoria, el acceso directo de las aplicaciones al sistema RAM no está permitido. En Linux, esto se controla por medio del sistema mmap() que opera junto con el nodo de dispositivo /dev/ram o el driver de la memoria intermedia. Para obtener más información a cerca de mmap(), echa un vistazo al manual. Está claro que, para conseguir que esto funcione de forma correcta, tienes que dejar bien claro al controlador qué es lo que quieres que aparezca en la pantalla, qué información has enviado a la memoria intermedia y dónde se encuentra. Esto se consigue «activando el modo VGA», con lo que cada bit de datos que se encuentre en la memoria intermedia pasa a ser reconocida por el controlador VGA. Por ejemplo, en el caso de que el modo VGA se configure a "640x480" y 8 bpp, el controlador VGA sabrá dos cosas a cerca de lo que va a ser mostrado:

  1. La pantalla estará dividida en 480 filas, cada una de ellas formada por 640 puntos horizontales (o píxels).
  2. A cada punto que aparece en la pantalla le corresponde un byte (8 bits) de la memoria intermedia. Así, las siglas 8bpp significan 8 bits por pixel.
Otra posibilidad es el formato del píxel. Cada píxel tiene dos propiedades asociadas que son el brillo y el color. Con el paso de los años han surgido diferentes formas de representar los píxels. De entre ellas, las más populares son el formato RGB y el YUV. La explicación de las mismas sobrepasaría los límites del tema que estamos tratando, sin embargo, los detalles son insignificantes y no nos impiden continuar. Una descripción completa de los adjustes del modo de video sería por tanto: resolución 640x480 en 8 bpp de profundidad, en formato RGB. Por lo tanto para poder representar una pantalla de dichas características será necesrio, por lo menos, una memoria intermedia de un tamaño 640 x 480 bytes.

API figure

Imaginemonos por un momento la típica tarjeta sintonizadora. Ésta ha sido programada para sintonizar un canal en concreto, capturar datos de video del mismo píxel a píxel en formato digital (por ejemplo bpp o YUV), para después volcarlos a la memoria RAM. Este procedimiento recibe el nombre de «captura de video». A continuación están enumeradas algunas de las posibilidades para capturar datos de video:

El módulo sintonizador se ocupa de demodular la frecuencia de radio en frecuencia intermedia. El procesador de video cuenta con un convertidor de modo análogo a digital que crea muestras de cada píxel, las cuales se unen formando conjuntos dentro de la memoria RAM, con la ayuda de las señales de control adecuadas por parte del procesador de video. En este artículo tomaremos como ejemplo un procesador de video de los más simples: el ITT VPX3224D.

2.3 El procesador de audio

Por lo general, las tarjetas sintonizadoras procesan el sonido de dos formas distintas. El primer método utiliza el procesador de audio para demodular el sonido en frecuencia intermedia (IF contiene tanto información de audio como de video). Las señales de audio obtenidas de esta foma tienen que ser dirigidas a un jack de audio externo, desde el cual sería necesario redirigirlas a la entrada de línea de una tarjeta de sonido independiente a través de un cable externo adecuado. Si no te puedes permitir el lujo de comprar una tarjeta de sonido, la entrada de línea de tu aparato de música valdrá :-).

Por otro lado, el procesador de audio tiene que demodular el sonido en frecuencia intermedia, convertirlo en muestras digitales para después utilizar técnicas como el DMA, de la que se hablará en el apartado sobre «buses PCI», para enviar dichas muestras a la tarjeta de sonido, a través del bus interno de sistema (por ejemplo el bus PCI). A continuación utilizará la tarjeta de sonido para volver a convertir las muestras digitales en señal de audio. Este proceso es más complejo pero más flexible, ya que los niveles de sonido de televisión se pueden controlar desde la propia tarjeta sintonizadora. Mediante el primer método, sólo nos podríamos permitir este lujo con el driver de sonido de una tarjeta de sonido independiente. Sea como sea, resumamos ahora lo que se nos exige y aquello que debemos exigir como buenos programadores de drivers de tarjetas sintonizadoras.

2.3.1 Lo que se nos exige:

En el apartado siguiente «¿qué quiere el driver?» veremos que una API independiente para un hardware normal ya viene definida para el kernel de Linux. Además, el kernel administra partes de la API y también una entrada del directorio /proc. Una entrada del directorio /proc aporta básicamente información volátil sobre drivers de dispositivos registrados de aplicaciones curiosas. Esto significa que, de alguna manera, nuestra responsabilidad como programadores de drivers de dispositivo se ve reducida y además no perdemos el tiempo almacenando manuales, lo que siempre es un rollo. ¿Le apetece a alguien explicarme lo que es sprintf()?:-) )

2.3.2 Lo que necesitamos :

Hmm.... esto nos lleva a una parte interesante en el diseño de un driver: rastrear en el kernel de Linux en busca de herramientas.

3 ¿Qué quiere el driver?

Alan Cox escribió un magnífico artículo sobre la API de Video4Linux para tarjetas de captura en Linux. Este artículo se encuentra, junto con la documentación sobre el kernel, en (Documentation/DocBook/videobook.tmpl)2 y abarca gran cantidad de temas relacionados con la API de Video4Linux. A lo que no hace referencia es a los detalles sobre los procesos de captura de las tarjetas sintonizadoras. Intentar referirse a los detalles sobre todos los tipos de dispositivos de captura de televisión en un mismo artículo resultaría imposible. Sin embargo una relación de las tarjetas sintonizadoras disponibles hoy en día (no me hago cargo de cámaras web u otros dispositivos que hay que enchufar en el puerto USB) se ajustaría a la información que se presenta aquí.

linux/videodev.h3 es la referencia autorizada para la API de V4L. Por lo tanto evitaremos realizar descripciones detalladas de la API de V4L. Cualquier tipo de detalle conceptual sobre el mismo se puede obtener en el artículo de Alan Cox al que nos hemos referido antes. Por otra parte la API de V4L está en proceso de desarrollo. Lo que es aplicable hoy, puede no serlo mañana.

3.1 Hablando con el driver

Antes de nada, echemos un vistazo al mecanismo se pone en marcha durante la comunicación entre una aplicación y el driver. Si ya conoces los dispositivos de carácter, esto te resultará repetitivo y podrás saltarte esta parte sin problema.

En todo sistema de Unix, el subdirectorio /dev contiene unos archivos especiales llamados nodos de dispositivo. Cada uno de ellos está asociado a un número específico de dispositivo registrado en el kernel. En Linux, al driver del Video4Linux le corresponde el número de dispositivo 81. Por convención, el nombre del nodo asociado con este número es /dev/video0. Para más detalles sobre numeración de nodos de dispositivo, ver Documentation/devices.txt. En el caso de que el nodo /dev/video0 no existiera, se podría crear con el comando mknod desde la estructura raíz tal y como se muestra a continuación:

root@maverick# mknod /dev/video0 c 81 0
De lo que se acaba de decir, se pueden obtener de forma inmediata tres maneras muy sencillas de acceder al driver desde el entorno del usuario4,: solicitudes de apertura, cierre y lectura al sistema. Si la captura de video es respaldada por el driver, el siguiente fragmento de código debería poder leer datos capturados y volcarlos al STDOUT. Si resulta que no tienes conocimientos de programación en C, antes de proseguir con la lectura de este artículo deberías hacerte con «The C Programming Language» de Kerningan y Richie mming Language.

------------- fragmento de código  ------------ 

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

main(){

int fd;

char *buffer;

/* Asignar un espacio de memoria lo más amplio posible. */

buffer = malloc(65535);

/* Abrir el nodo del dispositivo para su lectura. */

if((fd = open("/dev/video0", O_RDONLY))<0)

{

fprintf(stderr, "Sorry, error opening device /dev/video0\n");

exit(-1);

}

/* Leer hasta que el programa esté acabado o el dispositivo se quede sin datos (poco probable).*/

 

while( read(fd, buffer, 65535)) write(0, buffer, 65535);

free(buffer);

}

---------- Final del fragmento de código ----------
La conclusión que se pueden sacar del anterior fragmento es que los nodos de dispositivo son igualmente accesibles que cualquier otro archivo. Ésta es la única similitud. Además, las opciones de abrir(), leer(), escribir() y buscar() para los nodos de dispositivo tienen un sistema de solicitud especial, denominado ioctl(). Es precisamente este sistema ioctl el que lleva a cabo el milagro de «comunicarse con el driver»a través de la API de V4L.

¿Quieres abrir la ventana para ver la televisión?

ioctl(fd, VIDIOCCAPTURE, 1);
¿Quieres desactivar el sonido?

{
v.flags |= VIDEO_AUDIO_MUTE;

ioctl(fd, VIDIOCSAUDIO, &v);

}

debería descubrir el truco por el cual v aparece

struct video_audio v; 
Ten en cuenta que todas las constantes de VIDIOCXXXXX, la estructura de video_audio, etc. a la que nos referíamos antes aparecen definidas en linux/videodev.h, y son específicos de la API de V4L1. Por lo tanto, para que el código anterior tenga algún sentido, se tiene que añadir linux/videodev.h. Así que si yo fuera tú, lo siguiente que haría sería echar un vistazo el linux/videodev.h .

A continuación, algunas de las funciones posibles para los drivers de dispositivos:

int video_register_device(struct video_device *vfd, int type, int nr);

Descripción:
Registra un driver nuevo con un número menor 'nr' ya sea de VFL_TYPE_GRABBER, VFL_TYPE_VTX, VFL_TYPE_VBI o VFL_TYPE_RADIO. La estructura «video_device» aporta detalles como por ejemplo el nombre del driver. En cuanto el número menor está registrado, se bloquea, con lo cual no puede ser utilizado por otro driver sintonizador.


Esta función también crea una entrada en /proc/video/dev/

Esta entrada contiene información sobre el hardware de video.
Prueba:

cat /proc/video/dev/* 
para obtener un listado de entradas.

void video_unregister_device(struct video_device *vfd);
Descripción:
El número menor se desbloquea, el dispositivo aparece como no registrado y, por lo tanto, la entrada en /proc desaparece.

int video_exclusive_open(struct inode *inode, struct file *file);

int video_exclusive_release(struct inode *inode, struct file *file);

int video_usercopy(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int (*func)(struct inode *inode, struct file *file, unsigned int cmd, void *arg));

Descripción:
video_exclusive_open() es un bloqueo del kernel que impide más de una apertura a la vez. Esto evita que el driver tenga que ocuparse de situaciones como la que se daría si una aplicación utiliza el nodo de dispositivo para la captura de video, al tiempo que la superposición de video está activa. La función video_exclusive_release(), complementaria de video_exclusive_open(). video_user_copy(), se ocupa de copiar datos del entorno del usuario al entorno del kernel y viceversa. Se asegura que la parte de la memoria del kernel necesaria está disponible, ya sea del montón o a través del kmalloc(), el administrador de memoria del kernel.

4 Comunicándose con el hardware

Llegados a este punto, lo que podemos hacer es centrar todas nuestras energías a escribir el código para programar el hardware sintonizador para que realice funciones tales como comenzar captura, activar el sonido, copiar datos de un sitio a otro, etc. La mayoría de los ioctls del V4L se reducen a resolver este tipo de problemas. Finalmente, cuando todo está listo, podremos centrarnos en enlazar la última API de V4L con nuestro código subyacente. Esto es una práctica común en ingeniería.

--------------- Fragmento-------------------

General de brigada: «Teniente, quiero que al anochecer ese puente esté terminado.»

Ingeniero: «Vaya, creo que será imposible, señor. Es necesario tomar medidas en el terreno y pedir el material a los proveedores antes de poder pensar en comenzar a construir. Eso no llevará por lo menos un par de semanas, ¡señor!»

General de brigada: «Me está diciendo que no tienen puntales, tuercas o medidores de ángulos.¡Nada de nada con lo que puedan comenzar a trabajar inmediatamente!»

Ingeniero: «Pues, no, señor. No había pensado que necesitaríamos repuestos en un plazo de tiempo tan corto.»

Se escucha un disparo.

Fin de la primera toma.

--------------- Fin del fragmento ----------------
Comencemos a construir las partes.
La funcionalidad del driver que vamos a crear se podría clasificar en dos partes: adquisición de video y visualización de video.

4.0.1 Adquisición de video

Una de las funciones del driver tiene que ver con la adquisición de datos de video: asegurarse de que el módulo sintonizador está correctamente sintonizado, de que el procesador de video decodifica la señal correcta (ejemplo: PAL, NTSC, etc.), y de que las propiedades de la imagen, como brillo, tono, saturación y otras responsabilidad del hardware del procesador de video estén ajustadas, correctamente sintonizadas o establecidas en sus valores por defecto. La adquisición de audio puede ser también tarea del driver. Este aspecto está explicado en detalle en el apartado sobre I2C.

4.0.2 Visualización de video

La otra parte del driver se encarga de asegurarse de que los datos adquiridos aparecen en la pantalla de forma correcta. Esta parte del driver tiene que asegurarse del correcto funcionamiento del sistema en el caso de que el video se visualice en una ventana al tiempo que otras ventanas, correspondientes a otras aplicaciones, están abiertas. Aspectos relacionados con los parámetros que se ven afectados cuando la ventana de video es restaurada o arrastrada a otro lugar, tales como el área de visualización de la ventana, el número de líneas o píxels adquiridos, etc., son responsabilidad de esta parte del driver. Profundicemos un poco más en el problema de la superposición de ventanas. En un sistema basado en ventanas, como Xwindows, la visualización del video se lleva a cabo en una ventana. El problema de la superposición comienza cuando una esquina de la ventana de otra aplicación se superpone a la ventana de video.



API
			  figure



Existen dos posibilidades:

Presentación del Pixelview Combo TV plus

Lo que podemos hacer es comenzar programando rutinas que se ocupen de pequeñeces, tales como establecer el chroma key o el tamaño de la ventana de video, colocar la ventana correctamente, etc. La mejor forma de aprender este tipo de cosas es fijándose en un modelo. Centraremos nuestro estudio en algunos fragmentos de código de un driver no oficial que yo mismo estoy desarrollando para el Pixelview Combo TV plus. Esta es una tarjeta muy simple, tan simple como las tarjetas sintonizadoras pueden llegar a ser. El módulo sintonizador, el procesador de video y el controlador VGA se encuentran en la misma tarjeta. Ésta se conecta en la ranura PCI y funciona tanto de tarjeta sintonizadora como de tarjeta VGA.

Descripción de la tarjeta:

Ya que lo que nos interesa en estos momentos es la visualización de video, vamos a centrar nuestra atención en el controlador VGA Cirrus Logic GD-5446. El GD-5446 muestra una característica especial: es posible especificar la región de la memoria intermedia que va a contener los datos de video que más tarde serán mostrados en una ventana implementada por el hardware. Llamemos a esta memoria buffer de video.

API figure

El buffer de video puede estar situado en cualquier parte de la memoria intermedia, pero normalmente está al final de ésta. Esto previene que las muestras de datos de video capturados borren muestras de gráficos que ya estaban en la memoria intermedia y viceversa.

Pongamos un ejemplo:

Por lo tanto, podemos decir que el buffer de video arranca con unos recursos de unos 0,6 MB y no puede superar los 1,4 MB. El contenido del buffer de video no puede ser visualizado en la pantalla hasta que la ventana de video se active. Esta norma sólo tiene una excepción y es cuando se ha establecido que el buffer de video se superponga a aquellas partes de la memoria intermedia que se visualicen en forma de gráficos. Por ejemplo, si el buffer de video del ejemplo anterior arrancara con unos recursos de 0,5 MB, los datos de video capturados se situarían en la parte inferior de la pantalla, incluso si la ventana del hardware no está activa.

La ventana del hardware interpreta y muestra los datos que son de su competencia de una forma completamente distinta a como dicta el modo VGA. El tamaño y la situación de la ventana de video pueden ser modificados si se programan los registros VGA adecuados. El GD-5446 cuenta con tres grupos de registros llamados: registros de control, registros de gráficos y registros de secuencia. A cada uno de estos registros VGA se puede acceder por medio de múltiples lecturas y escrituras a los puertos del hardware, y por lo tanto están rodeados por funciones especializadas. Los he denominado gd_read_cr(), gd_write_cr()… Esto mejora la legibilidad del código a la vez que reduce las probabilidades de error. A continuación aparecen algunas de las rutinas del driver que estoy creando. Para ahorrar tiempo las he descompuesto en partes:

 

#define GD_SR_OFFSET 0x3c4

#define GD_GR_OFFSET 0x3ce

#define GD_CR_OFFSET 0x3d4

/* Adaptador - funciones de nivel bajo */

unsigned gd_read_cr(, unsigned reg){

unsigned value;

io_writeb(reg, gd_io_base + GD_CR_OFFSET);

value = io_readb(gd_io_base + GD_CR_OFFSET + 1);

return value;

}

Fíjate en que un acceso al registro VGA consiste en una escritura al puerto io del hardware,

io_writeb(reg, gd_io_base + GD_CR_OFFSET); 
seguida de la lectura de un puerto adyacente.

value = io_readb(gd_io_base + GD_CR_OFFSET + 1);
Funciones posteriores se crean a partir de variantes de gd_read_cr();

Éstas son algunas funciones de nivel más alto:

/* funciones de programación de video del hardware VGA.  */

void gd_enable_window();

Habilita la ventana de video del hardware.

void gd_disable_window();
Deshabilita la ventana de video del hardware.

 void gd_set_vbuf1(,);
Establece el lugar, dentro de la memoria intermedia, donde se recogerán los datos de video capturados.

void gd_set_vbuf2(,);
Hay dos opciones de esta memoria.

unsigned long gd_get_vbuf1();
Muestra la situación del buffer de captura actual dentro de la memoria intermedia. Esta función complementa gd_set_vbuf1();

unsigned long gd_get_vbuf2();
Ver arriba.

void gd_set_pitch(,); 
Establece el número de píxels de los que está formada una línea de datos de video capturados. Como el tamaño de la ventana de video puede ser modificado, el área de visualización tendrá que volver a ajustarse cada vez que el ancho de la ventana cambie.

unsigned long gd_get_pitch();
Muestra el valor del área de visualización actual.

/* funciones VGA de la ventana de video. */

static void gd_set_window(,,,);

Establece las coordenadas de la ventana del hardware con respecto a la pantalla principal. Las coordenadas se transmiten en indicadores de estructuras. Para más detalles, ver archivo (pvcl.h).

static void gd_get_window(,,);
Muestra las dimensiones actuales de la ventana de video del hardware. Esta información se toma de registros del hardware. Veamos ahora el contenido de una única rutina, para así avanzar un paso más en los detalles:

void gd_set_pitch(

struct clgd54xx_card * card_p, unsigned long offset)

{

unsigned long CR3C, CR3D;

CR3C = gd_read_cr(card_p, 0x3c);

CR3D = gd_read_cr(card_p, 0x3d);

/* CR3C[5] = offset[11], CR3D = offset[10:3]*/

gd_bit_copy(&CR3C, 5, &offset, 11, 11);

gd_bit_copy(&CR3D, 0, &offset, 3, 10);

gd_write_cr(card_p, CR3C, 0x3c);

gd_write_cr(card_p, CR3D, 0x3d);

}
Fíjate en las funciones gd_bit_copy() y gd_write_cr(). Se trata de funciones que marean un poco a los registros VGA. gd_bit_copy() altera unos bits concretos dentro de una variable concreta. Dicha variable se puede introducir más tarde en un registro VGA mediante una función que puede ser por ejemplo gd_write_cr(). Como cada uno de los bits de un registro VGA son de gran importancia y tienen que ser tratados con cuidado, he creído conveniente tratar aquellas funciones que se ocupen de los mismos.

gd_write_cr() se utiliza para escribir un valor en un registro VGA específico. Por ahora ignoraremos la variable card_p. Consiste en una estructura en la que se almacena información global sobre el estado del driver. card_p es utilizado por gd_write_cr únicamente con fines de contabilidad. gd_write_cr(card_p, CR3C, 0x3c) se ocupará de escribir el contenido de la variable CR3C dentro del registro de control 0x3c. (que no te confunda la designación CR3C, se trata de una variable).

En el caso general de una tarjeta sintonizadora, cuyo controlador VGA no ofrezca una ventana de video del hardware independiente, el procesador de video tendrá que volcar las imágenes justo en medio de los datos de gráficos. Este proceso se tendrá que llevar a cabo de tal manera que, cuando el controlador VGA muestre el contenido nuevo de la memoria intermedia, el video aparezca de forma correcta, sin distorsiones. Para ello es necesario que los datos de video se alineen de acuerdo con los límites de resolución (cada bate a 8bpp, uno de cada dos bytes a 16bpp, uno de cada cuatro bytes a 32bpp, etc.). Además de esto, la representación de los píxels dentro del procesador de video debe coincidir con la del modo actual del controlador VGA. El procesador de video no puede adquirir video a 32bpp y volcarlo a una memoria intermedia de 16bpp. Es más, los datos de video no se pueden presentar de una manera lineal continuada. Los recursos del buffer de cada línea deberán ser calculados como se indica en el gráfico que aparece a continuación:

API figure

Video Buffer Offset = Video Buffer Offset + Video Window Pitch x Line No.

Dicho de otra manera, todas las precauciones y cálculos que realiza el Xserver cuando dibuja una ventana de aplicación, tienen que ser tomadas por el procesador de video. En este caso, el procesador de datos modifica únicamente el buffer de gráficos y no realiza distinción alguna entre datos de video y de gráficos.

Sin embargo, en el caso del GD-5446, el procesador de video no escribe en el área de gráficos ni se preocupa de temas de alineación. De lo que se tienen que asegurar las rutinas de un procesador de video es de que el video sea capturado dentro del recurso correcto de la memoria intermedia, donde comienza el buffer de video. La rutina gd_set_vbuf1() se ocupa de eso por nosotros. Por lo tanto, el hardware GD-5446 se ocupa de lo relacionado con la actividad de las ventanas.

Para más detalles sobre la descripción de los registros GD5446 del hardware, echa un vistazo al manual de referencia técnica de GD-5446.

Un paseo por el IOCTL

Ha llegado el momento de realizar una visita guiada por el camino que recorre una llamada del IOCT. Partamos del instante en el que una aplicación del video4linux, como por ejemplo xawtv (ver: http://bytesex.org), conecta con el ioctl() para que active la ventana de televisión.



API
			  figure



Respuesta a la pregunta sobre el Chroma key:

La aplicación solicita información al driver de aplicación sobre los chroma keys disponibles y selecciona uno. Entonces pasa a rellenar el fondo de la ventan de video con un único color. Los elementos superpuestos ya pueden ser pintados sobre la ventana de aplicación, y la captura de video se active. Por supuesto, los datos de video aparecen sólo las zonas que no pueden ser superpuestas, las cuales se rellenan con el fondo del chroma key.


5 El bus I2C

En lo que se refiere a la captura sintonizadora, el GD-5446 tiene dos características interesantes: cuenta con una interfaz del bus I2C a través de dos clavijas y con una interfáz de puerto de video a través de 16 pines. La interfaz de puerto de video sigue el modelo del estándar ITU-656 para operaciones de intercambio de datos de video. No te eches atrás en este punto. ¿Te acuerdas que los píxels pueden estar formados por más de un byte? Ejemplo: 16 bpp es igual a dos bytes. Alguien tendría que decirles a los fabricantes de chips que, en el caso de múltiples bytes por píxel, las transmisiones entre chips tendrían que realizarse siguiendo un orden. En el caso de YUV, Y se refiere al brillo, U y V se refiere a los dos colores que componen un píxel. Que cada componente ocupe un byte no es muy factible en el mundo real del formato YUV 4:2:2 pero, que narices, podemos poner ejemplos hasta que nos cansemos. Un píxel, por lo tanto, necesita 3 bytes, es decir 24bits. Ahí va la propuesta: si eres un fabricante de chips y quieres alardear de una línea extra en el listado de características(para captar la atención de posibles clientes, por supuesto), ten en cuenta el sello ITU-656. Pero, ten cuidado, en cuanto esté sellado, el espíritu de la bestia residirá en tu chip. El video sólo se podrá transmitir a partir de una determinada orden: U-Y-V. Ahí va la parte Buena: ¡el VPX 3225D forma parte de la hermandad!, así que ahora as cosas ya están en su lugar. El controlador VGA y el procesador de video utilizan una vía clandestina de comunicación, algo con el nombre VPort. Todavía hay más buenas noticias: el VPX 3225D también cuenta con un bus I2C. ¡Sorpresa, sorpresa!
Bueno, serenémonos un poco y conozcamos lo que significa todo esto:



API
			  figure



  1. El controlador VGA GD-5446 tiene un bus I2C que se puede controlar directamente a través de uno de sus registros programables (en este caso, SR 8).
  2. El VPX-3225D se conecta al mismo bus y, por lo tanto, puede charlar con el GD-5446 en el lenguaje del I2C.
  3. Además, ambos están conectados a través de una línea de bus privada: la interfaz VPort; un bus de datos de alta velocidad para transmitir datos de video del procesador de video al controlador VGA, es decir, el VPX-3225D puede transmitir video capturado a través del bus Vport al GD-5446, y esta transferencia se puede controlar por medio del bus I2C.
    Date cuenta de que el procesador de video cuenta con un bus privado para escribir en la memoria intermedia del GD-5446. Este bus se encuentra en la propia tarjeta combo, y por lo rodea el bus del PCI e incluso el procesador de sistema. Todas las tareas de sincronización y los apretones de manos se llevan a cabo entre el GD-5446 u el VPX 3225D. La única forma de acceder a este bus desde el driver es haciéndolo de forma indirecta a través del GD-5446 SR8 (registro de secuencia número 8), por medio del bus I2C, a través del procesador de video. En cuanto la transferencia comienza, es decir; en cuanto comienza la captura de video, el procesador de vide comienza a escribir enérgicamente la memoria intermedia del GD-5446 a través del VPort, y recibiendo instrucciones del GD-5446 que llegan por medio del bus I2C. Sepamos más sobre el bus I2C antes de continuar.
El bus I2C tiene dos líneas: SDA y SCL. Aunque pueda haber más de dos chips conectados al mismo tiempo al bus I2C, sólo uno de ellos podrá hablar con el bus I2C de cada vez. Hasta aquí está claro. Los chips se dividen en dos tipos: Maestros y Esclavos. Los maestros pueden dirigirse a los esclavos siempre que quieran. Los esclavos no, a menos que se les pida que lo hagan. Parece lógico que no pueda haber más de un maestro conectado al mismo tiempo al bus I2C.

Otra tanda de preguntas:

Identifica el chip maestro en el bus I2C de la tarjeta sintonizadora Pixelview.

Echemos un vistazo a los dos pines: SDA y SCL:

TEl pin SDA es de datos. La SCL es la del reloj. La primera puede ser utilizada tanto or un maestro como por un esclavo, dependiendo de la dirección de la transferencia de datos. El pin SCL sólo es utilizado por un chip maestro.

API
			  figure



5.1 El subsistema I2C de Linux

Como programadores de drivers de dispositivo de Linux, somos afortunados. La mayoría de la información sobre el nivel inferior y el nivel de pines está almacenada para nosotros en el kernel. Lo que tenemos que hacer es conectar algunas rutinas helper al kernel. Estas permiten al kernel comunicarse con el bus I2C de nuestra tarjeta sintonizadora. Estas rutinas se podrían comparar con un conductor de rally: no sólo sabe cómo conducir bien, también conocen sus coches a la perfección. Si hay que cambiar el aceite, si el amortiguador pierde líquido o si el disco de embrague está a punto de hacerse trizas son pequeños altercados de los que el conductor se dará cuenta al instante. Por otro lado, el copiloto conoce el terreno y la ruta como la palma de su mano. Por e so, segundos antes de la próxima curva muy cerrada, gritará "¡curva cerrada a la izquierda!", con lo que el conductor reducirá, acariciará el pedal del freno, hará un movimiento de la dirección asistida y, ya está, una curva menos que tomar. Más o menos ocurre lo mismo con el kernel, que conoce el protocolo I2C y sabe cuándo hay que cambiar los pines SDA y SCL. El kernel espeta las órdenes a las funciones del helper, que son las que verdaderamente realizan el cambio. Con el fin de que el kernel hable con las funciones del helper, éstas tendrán que estar registradas en el kernel. El kernel tiene una función de registro para estos casos: i2c_bit_add_bus(). We pass it a structure defined so in linux/i2c-algo-bit.h :

struct i2c_algo_bit_data {
void *data;    /* datos privados de las rutinas de nivel bajo*/

void (*setsda) (void *data, int state);

void (*setscl) (void *data, int state);

int (*getsda) (void *data);

int (*getscl) (void *data);

/* configuración local */

int udelay;

int mdelay;

int timeout;

};
Has acertado. Las variables de indicador setsda, setscl, getsda y getscl son variables de indicador par alas funciones helper que nosotros aportamos. Así, cada vez que el SDA se establezca en un nivel superior o inferior, el kernel conecta con setsda(). Si setsda = gd54xx_setsda, entonces nuestra rutina, con las operaciones de lectura y escritura al registro VGA CL-GD5446 SR8, será llamada. Lo que tenemos que hacer es lo siguiente:

#include <linux/i2c-algo-bit.h>

struct i2c_algo_bit_data gd_bus;

gd_bus.setsda = gd54xx_setsda;

gd_bus.setscl = gd54xx_setscl;

gd_bus.getsda = gd54xx_getsda;

gd_bus.getscl = gd54xx_getscl;

udelay = 16;

mdelay = 10;

timeout = 200;

i2c_bus_add(&gd_bus);

Las variables udelay, mdelay y timeout son nuestro único contacto directo con los sincronizadores del bus I2C, cuando el kernel maneje los pines del I2C. No es necesario decir que el código anterior es un pseudo código y no funciona directamente. Algunos detalles han sido omitidos, pero saldrán a la luz en los próximos párrafos.


Dejad que os indique algunos documentos en el subdirectorio ('Documentation/i2c/') que contienen información exhaustiva sobre la puesta en práctica del I2C dentro del kernel. En concreto, ('Documentation/i2c/writing-clients') es una introducción agradable de leer a los drivers del I2C.


Respuestas a la tanda de preguntas:

El GD-5446.

El kernel proporciona acceso a algunos chips maestros del I2C así como una interfaz directa a los pines SDA y al SCL. Esta interfaz recibe el nombre de bang interfaz. En el caso de la tarjeta sintonizadora Pixelview Combo TV plus, conseguimos acceso directo a los pines SDA y SCL del bus I2C a través del registro SR8 del controlador VGA GD-5446. SR8 es accesible a través de los puertos del hardware 0x3c4 y 0x3c5. He creado estos accesos utilizando las rutinas gd_read_sr() y gd_write_sr(). Referirse a (pvcl.c). A continuación aparece una descripción del registro de control del I2C, SR 8, del GD5446:

I/O Port Address: 3C5h
Index: 08h
Bit Descripcion
7 I2C SDA Readback
6 I2C Configuration
5 Reserved
4 Reserved
3 Reserved
2 I2C SCL Readback
1 I2C Data (SDA) Out
0 I2C Clock (SCL) Out

Siempre que se produzca algún cambio en los bits del I2C bits dentro del registro SR8, éste se refleja en el bus I2C y todos los esclavos aprecian el cambio. Por ejemplo, si el bit 1 del SR8 pasa a 0, el GD-5446 coloca la línea SDA en un lugar inferior. Ocurre lo contrario si el bit 0 del SR8 pasa a 1. Es momento de que nos fijemos en el set_sda() y en el get_sda(). Como suele ocurrir, ambos pertenecen a pvcl.c, y han sido descompuestos para facilitar la lectura.

void gd54xx_setsda (int state)

{

/* Activar la interfaz I2C */

set_bit(6, &i2c_state);

/* Fijar/borrar un bit */

state ? set_bit(1, &i2c_state) : clear_bit(1, &i2c_state);

gd_write_sr(, i2c_state, 0x8);

}
set_bit(n, variable) activa el bit de variable nth, contando a partir del bit menos significante. Éste es proporcionado por el kernel. Ver (asm/bitops.h). clear_bit, de forma parecida, despeja el bit nth. i2c_state es una variable que contiene los características actuales del registro de VGA SR8.

Lo que ocurre, a grandes rasgos, es que el gd54xx_setsda (1) mueve una línea del SDA hacia arriba, mientras que el gd54xx_setsda (0), los hace hacia abajo.


set_scl() funciona de forma parecida, exceptuando el caso en el que el pin SCL se vea afectado.


Mediante la lectura del correspondiente bit de estado del SR8 se consigue conocer el estado actual del pin SDA. En este caso, se trata del bit 7. Si el pin SDA está en una posición alta, el bit 7 será igual a 1. Si su posición es baja, entonces será igual a 0. Esto se puede observar en una variable, como se muestra a continuación:

int gd54xx_getsda (i2c_state)

{

return (((i2c_state = gd_read_sr(, 0x8)) »7)&0x1);
}

Para poder tener una imagen general de lo que es el sistema I2C dentro del kernel, es necesario entender ciertos conceptos que se ponen en funcionamiento en el kernel.

El primer concepto es el de adaptador.

Según linux/i2c.h: " i2c_adapter es la estructura que se utiliza para identificar un bus físico i2c junto con los algoritmos de acceso necesarios para acceder al mismo."
En este caso, el bus I2C GD-5446 junto con el acceso del bit-bang forman el adaptador.

El segundo concepto es el de algoritmo:

Lo que el (linux/i2c.h) dice sobre los algoritmos es lo siguiente:

"(un algoritmo de acceso) ... es una interfaz para un tipo de solución de hardware, a la que se puede dirigir mediante los mismos algoritmos de bus, es decir, el bit-banging o el PCF8584, para nombrar dos de los más comunes."

Las funciones gd54xx_setsda(), gd54xx_getsda(), gd54xx_setscl() y gd54xx_getscl() , son funciones helper para el algoritmo de acceso bit-bang. Por lo tanto, nunca habrían existido si el bus I2C GD-5446 utilizara algún otro mecanismo, como por ejemplo la interfáz de I2C PCF 8584.

El tercer concepto tiene que ver con un cliente de I2C.

De nuevo (linux/i2c.h) es una referencia fiable:

"(Un cliente) ... identifica un dispositivo (es decir, un chip) que está conectado a un bus I2C."

En nuestro caso, tenemos dos únicos clientes: el VPX-3225D y el módulo sintonizador FM1216ME MK3 de Phillips. Mediante la asignación de ciertas direcciones a algunos chips, el protocolo I2C se asegura de que sólo de accede a un chip de cada vez. Por lo tanto, a cada cliente se le asocia un número de dirección. El VPX-3225D sólo responde a direcciones 0x86 and 0x87 o 0x8e and 0x8f, dependiendo del chip que esté configurado. El módulo sintonizador responde a la dirección 0xc6.

A cada transacción del I2C se le antepone la dirección de destino. De esto se tiene que encargar el maestro. Entonces, sólo los esclavos a los que se dirija el maestro podrán responder a sus peticiones. Este método también se puede utilizar para comprobar que el bus I2C es capaz de detectar algún chip. El kernel de Linux soporta este tipo de pruebas.

root@maverick# modprobe i2c-algo-bit bit_scan=1 
Esto hará que el módulo central del I2C del kernel escanee la gama completa de direcciones del adaptador bit_bang para detector los chips conectados. Cualquier descubrimiento es notificado a través de los logaritmos del kernel. De esta forma, un cliente contiene la siguiente información concerniente a los chips conectados:

  1. Nombre de identificación
  2. Dirección a la que responde.
  3. El adaptador al que está conectado.
  4. El driver de dispositivo encargado de programarlo.
Esto nos lleva al cuarto concepto relacionado con el subsistema del I2C: el driver del I2C. Veamos primero lo que tiene que decir el (linux/i2c.h) sobre este desconcertante concepto:

«Un driver es capaz de manejar más de un dispositivo físico presente en los adaptadores I2C. Esta información se utiliza para informar driver de los que sucede con el adaptador.»
Al principio, puede parecer increíble que estemos hablando de un driver de dispositivo dentro de otro driver. Pero, ocurre que puede haber más de un chip en un adaptador en concreto, y cada uno de ellos tiene que ser programado de forma individual. Podemos denominar driver a toda parte de código, que entiende el funcionamiento de un elemento del hardware y lo programa de acuerdo con el mismo. En este caso, el driver podría ser simplemente un par de rutinas dentro de un módulo y, en este sentido, resulta que puede que haya más de un driver dentro de un módulo del kernel.

Podría resultar útil tener en cuenta que puesto en práctica el driver del I2C para el VPX-3225D dentro de otro archivo denominado vpx322xd.c Con esto, el código se divide entre el driver principal del V4L y la parte del vpx de forma correcta. Ambos drivers se comunicarán entre ellos a través de un acuerdo interno parecido al de la llamada IOCTL en el entorno del usuario. Curiosamente, el driver del módulo sintonizador FM1216ME MK3 de Phillips ya está disponible dentro del kernel 2.4 y puede ser compilado en un módulo independiente. Esto sirve de ejemplo de lo bien que funcionan la fuente abierta. Yo he aportado el adaptador y las funciones para las operaciones con ventanas; otra persona ha creado un driver sintonizador que funciones con mi adaptador, al cual yo añado un módulo de procesador de video del que dispongo; y otra persona ha escrito cliente del entorno del usuario de V4L que entiende la API de V4L. No está mal, ¿eh ?

Para comprender cómo crear el código del driver del I2C para el procesador de video (en este caso, el VPX-3225D), hay que saber dos cosas: el contexto y en entorno en el que el código va a funcionar.

Realizar una IOCTL desde un driver I2C

Después de que todo esté dicho y hecho, la finalidad del driver VPX-3225D, es poner en práctica las instrucciones trasmitidas por las aplicaciones. Un driver I2C genérico, a la vez que se registra a sí mismo en el I2C de Linux, registra un elemento llamado función «comando». Una vez registrado, se puede conectar con esta función siguiéndole el rastro a través de una lista de adaptadores I2C disponibles. La lista de relaciones funciona de la siguiente manera: adapter-> clients[n]-> driver-> command, siendo n el cliente nth en un adaptador. Por lo tanto, adapter-> clients[n]-> driver-> command() se traduciría por«contactar con la función comando asociada al driver para el cliente "n" que se encuentra en el adaptador». Por supuesto, se puede acceder a la estructura del adaptador desde el driver principal del V4L, pvcl.c, que ha sido registrado por dicho adaptador en primer lugar. Por lo tanto, todos los clientes del adaptador y, por consiguiente, todos los driver de cliente y sus rutinas de «comando» rellamada, son accesibles a través del pvcl.c, con sólo atravesar la estructura del adaptador.

API figure

Marquemos ahora los pasos de una llamada ioctl() para activar la captura:

vpx_start_capture() y sus compañeros son pequeñas funciones que realizan operaciones triviales pero específicas. Éstas, al igual que las series de llamadas gd_xxxx_() en el pvcl.c file, hacen uso de funciones de nivel inferior para acceder al hardware. En este caso se recurre a las funciones vpx_read_byte()/vpx_write_byte(), en vez de gd_write_xr()/gd_read_xr(). Estas funciones dependen más de funciones de nivel inferior aportadas por el núcleo de I2C, tales como i2c_smbus_read_byte_data() . Estas funciones se ocupan de los detalles exactos del protocolo de intercambio del I2C utilizado para comunicarse con el chip VPX a través del bus I2C.

Así termina este apartado.

6 El bus PCI

El bus PCI es el que se utiliza con más frecuencia el los ordenadores actuales. (Para inocentes novatos: un bus es un pedazo de cable o conjunto de cables a los que se conecta uno o más periféricos al mismo tiempo y, por lo tanto cuenta con un recurso compartido.) Aparte de su velocidad (33MHz como mínimo), el PCI es un bus plug and play. Por su puesto, esto no tiene nada que ver con los cables, ya que son como los cables de una lámpara de mesa. La diferencia reside en que un dispositivo conectado al bus PCI tiene que actuar de acuerdo con una serie de normas llamadas especificaciones PCI. Entre otras cosas, los dispositivos PCI, es decir, los dispositivos conectados al bus PCI, tienen que aportar información al bus maestro, sobre el nombre, el tipo y el número de los chips funcionales, así como sobre sus líneas IRQ preferentes, su capacidad de DMA, etc. Esto contribuye a la correcta distribución de recursos por parte del bus maestro. El bus maestro, en este caso, es un Proxy del procesador de sistema, que normalmente será un "dispositivo conductor" o un "dispositivo puente". No entraremos en detalles en este punto, ya que lo que nos interesa, como programadores de drivers de dispositivo, son tres cosas:

Identificación del dispositivo, el DMA y la asignación de la línea IRQ.

6.1 Identificación del dispositivo

Linux cuenta con una serie de funciones para acceder ala información sobre los dispositivos PCI. Estas funciones, que ya han obtenido detalles sobre las tarjetas conectadas, se comunican con el hardware del PCI. Lo que nos interesa es la identificación del chip conectado a la tarjeta. pci_find_device() completa una estructura con el nombre de la tarjeta, la identificación del vendedor y identificación del chip de la tarjeta. Estos ID están disponibles en linux/pci_ids.h. Se encuentran allí porque los fabricantes de chips, de antemano, registraron sus dispositivos en una base de datos central pública.

En el caso de la tarjeta Pixelview, la operación de identificar el GD-5446 es muy sencilla. Busca el PCI_VENDOR_ID_CIRRUS y el PCI_DEVICE_ID_CIRRUS_5446. Si ambos campos están disponibles en la base de datos de la tarjeta, significa que ésta es controlada por CL-GD5446. Encuentra la función de sondeo en i2c_clgd54xx_find_card() en pvcl.c para obtener información sobré cómo ocurre eso.

6.2 DMA

Como ocurre con cualquier otro bus, el sistema del PCI permite la transferencia de datos sólo entre un maestro y un esclavo. El maestro inicia la conversación, y el esclavo responde con datos o peticiones. En el bus PCI, el maestro suele ser un Proxy del procesador de sistema. Este chip se comporta como el propio procesador de sistema, haciendo que los demás chips se sometan. De forma efectiva, los dispositivos del sistema reconocen al procesador en el Proxy y obedecen sus instrucciones. No obstante, el procesador es un chip muy ajetreado y no se puede dedicarse exclusivamente a transmitir datos entre los chips PCI sin dejar de lado otras funciones. Por eso, de vez en cuando, permite a otros chips esclavos actuar como maestros, bajo la responsabilidad del procesador de sistema. En tales casos, los nuevos maestros del bus tienen control sobre el bus PCI y pueden comenzar cualquier tipo de transferencia que deseen. Está claro que este nombramiento de maestro es temporal, y el procesador, en cuanto así lo quiera, puede revocar los poderes otorgados y devolver al chip a su situación inicial, con lo cual, el procesador asume de nuevo el control.

Tomemos el ejemplo de una tarjeta sintonizadora que decide transferir datos a la tarjeta VGA. El chip de la tarjeta sintonizadora informa de su intención de realizar esa operación enviando una petición DMA por una línea particular llamada DREQ, en el bus PCI. El chip del controlador del PCI, tras consultar con el procesador, a través líneas fuera del bus PCI, garantiza o deniega el cumplimiento de dicha petición. En cuanto la realización de dicha operación es garantizada, la tarjeta sintonizadora puede dirigirse al chip VGA, tal y como lo haría el procesador, y se puede iniciar la transmisión de datos a través del bus PCI, mientras el procesador de sistema puede ocuparse tranquilamente de otros asuntos. Si ocurriese que el procesador también necesitara acceder al chip VGA, sólo tendría que revocar los derechos del bus de la tarjeta sintonizadora y escribir al chip VGA, como hace siempre.

En buses más antiguos, un chip dedicado, llamado contralor DMA, se utilizaba para llevar el control de los buses delegados. La responsabilidad de asignar recursos al propio controlador DMA correspondía al kernel de sistema y, por ello, las ventajas del DMA estaban limitadas a un número reducido de dispositivos, en tales buses. En el caso del PCI, cualquier chip puede pasar a ser maestro de bus, y el controlador DMA puede ser situado en una tarjeta individual. Esto podría ocasionar disputas en la línea DREQ, el único punto que puede retrasar el proceso. Para aliviar el problema, varias líneas DREQ están disponibles en el bus PCI, con el controlador del bus PCI como árbitro entre DREQ simultaneas en múltiples líneas.

6.3 Líneas IRQ

Los dispositivos tienen que informar al procesador de aquellas situaciones que no pueden ser previstas de forma anticipada. Estas situaciones reciben el nombre de eventos asincrónicos y pueden ser: la llegada de un paquete de datos a una tarjeta de red; la apertura de la bandeja del CD-ROM; la finalización, por parte del procesador de video, del llenado de una serie de datos de video; etc.

Los dispositivos informan de los eventos asincrónicos a través de una línea en el bus PCI llamada línea IRQ Interrupt Request Queue (siglas inglesas para línea de petición de interrupción). Las líneas IRQ constituyen unos recursos escasos en un bus, y el bus PCI no es una excepción. No obstante, si existiera algún medio para distinguir entre las diversas partes que pueden compartir la misma línea, las líneas IRQ podrían ser compartidas por los distintos dispositivos. El código que se ocupa de las peticiones IRQ recibe el nombre de Interrupt Service Routine, ISR (rutina de interrupción de servicio). El procesador, si así se lo indica un algún chip a la IRQ, activa de forma inmediata la ISR. Entonces la ISR lee los registros de cada dispositivo sospechoso, hasta que da con el dispositivo en la línea compartida culpable de enviar una IRQ y actúa en consecuencia para atender dicha petición. Atender una petición puede incluir tareas como guardar el paquete que se acaba de recibir, vaciar los buffers del sistema, o resetear los indicadores en el procesador de video. Cada una de estas acciones es específica de un dispositivo y, por ello, el driver habrá de incluir la ISR registrada con el kernel de sistema, de manera que pueda ser llamado en el momento de la interrupción.

7 Programando tu propio driver

Nadie escribe un código partiendo de cero. Los pocos que lo hacen así tienen rezones concretas para ello, pero, incluso así, se basan en plantillas de código o en ideas prestadas de otros códigos, ya sean suyos o de otros. Por esto, si está naciendo en ti un programador de drivers, la mejor manera de empezar sería leer el código del driver que está disponible en el kernel de Linux. Tranquilo, nadie te va a denunciar por plagio, de hecho la licencia Gnu Public License (GPL), por la cual el kernel de Linux fue puesto al público, promueve la reutilización del código. Mientras no hagas copias al pie de la letra del código de otro y luego le cambies el nombre del autor, eres libre de utilizar el código del kernel. Puedes reclamar cualquier parte nueva del código existente, pero, no olvides, que cualquier código GPL alterado tiene que ser puesto al público siempre bajo los términos del GPL, aunque los derechos de los cambios te pertenezcan a ti.

Apéndice A - código del driver del Pixelview Combo TV Plus (alpha)

Entra el los siguientes enlaces para ver el código fuente.

pvclnotes.txt

pvcard.h

pvproc.h

pvcl.h

pvcl.c

vpx322xd.c

Existe un parche no oficial de driver de Linux del autor para la tarjeta sintonizadora de televisión Pixelview Combo TV plus que se encuentra en http://cherry.freeshell.org/downloads/

Bibliography

1
Fuentes del kernel de Linux

2
Manual de referencia técnica del Cirrus Logic 5446

3
Manual de referencia técnica del VPX 3225D

4
archivos de e-mail de la lista de V4L: video4linux-list@redhat.com.

A cerca del artículo...

Tarjetas sintonizadoras: aprender mirando

Este documento se creó utilizando la versión 2K.1beta (1.48) del traductor LaTeX2HTML

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

Los argumentos de la línea de comando son:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir12763rVg3I/lyx_tmpbuf1276gZAXat/article.tuner.tex

La traducción fue comenzada por Cherry George Mathew el 20/05/2003


Pies de página

...P1
La expresión «kernel de Linux»se refiere a las versiones del kernel 2.4 y superiores.
...Documentation/DocBook/videobook.tmpl)2
Todas las rutas están relacionadas con la raíz de recursos de Linux. Por ejemplo si la raíz de Linux es /usr/src/linux entoncws Documentation/DocBook/videobook.tmpl estará en /usr/src/linux/Documentation/DocBook/videobook.tmpl
...3
Todas las rutas están relacionadas con el directorio por defecto de del fuentes de Linux.
... space4
En kernels monolíticos, como Linux, las aplicaciónes funcionan en el entorno del usuario. el kernel y su driver funcionan en el entorno del kernel.

 

[BIO] Cherry es licenciado en ingeniería electrónica. Vive en la ciudad de Bangalore, en la India. sus aficiones preferidas son leer novelas, tocar la guitarra y hackear código.


Copyright © 2003, Cherry George Mathew. Licencia de copia http://www.linuxgazette.com/copying.html
Publicado en el número 91 de Linux Gazette, Junio 2003