Esto deja la caracter�stica perdida - E/S As�ncrona. Normalmente los
programas UNIX usan la llamada poll (o su
forma variante select) para esperar a que ocurra
un evento en uno de los m�ltiples dispositivos de entrada o salida. Este
modelo trabaja bien para la mayor�a de las tareas porque las esperas
poll y select para un evento
no son convenientes para tareas que est�n continuamente haciendo
trabajo computacional. Tales programas realmente quieren que el n�cleo
les golpee cuando pasa algo en vez de mirar por los eventos.
Poll es semejante a tener una fila de luces delante de t�. Puedes ver en
un instante cuales de ellas est�n encendidas. No puedes, de cualquier forma,
hacer nada �til mientras las est�s mirando. La E/S as�ncrona usa se�ales
que trabajan m�s bien como un timbre. Es vez de mirar, dice que algo
se ha manifestado.
La E/S as�ncrona env�a la se�al SIGIO al proceso de usuario cuando ocurre el
evento de E/S. En este caso esto significa cuando la gente
mueve el rat�n. La se�al SIGIO causa que el proceso de usuario salga
a su manejador de se�ales y ejecute el c�digo en ese manejador antes de
regresar a lo que estuviera haciendo previamente. Esta es la aplicaci�n
equivalente a un manejador de interrupciones.
La mayor parte del c�digo necesitado para esta operaci�n es com�n a todos
los usuarios. El n�cleo suministra un conjunto simple de funciones para
administrar la E/S as�ncrona.
Nuestro primer trabajo es permitir a los usuarioes establecer E/S
as�ncrona en el manejadores de archivos. Para hacer esto necesitamos a�adir
una nueva funci�nn a la tabla de operaciones de archivo para nuestro rat�n:
struct file_operations our_mouse_fops = {
owner: THIS_MODULE
read: read_mouse, /* Puedes leer un rat�n */
write: write_mouse, /* Esto no har� mucho */
poll: poll_mouse, /* Encuesta */
open: open_mouse, /* Llamado en open */
release: close_mouse, /* Llamado en close */
fasync: fasync_mouse, /* E/S as�ncrona */
};
Una vez que hemos instalado esta entrada, el n�cleo conoce que soportamos
E/S as�ncrona y permitir� todas las operaciones relevantes en el
dispositivo. Siempre que un usuario a�ade o quita la notificaci�n de
E/S as�ncrona de un manejador de archivos, llama a nuestra rutina
fasync_mouse que acabamos de a�adir. Esta rutina
usa las funciones de ayuda para mantener actualizada la cola de manejadores:
static struct fasync_struct *mouse_fasync = NULL;
static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval = fasync_helper(fd, filp, on, &mouse_fasync);
if (retval < 0)
return retval;
return 0;
}
La fasync helper a�ade y borra entradas administrando la lista
suministrada. Tambi�n necesitamos quitar entradas de esta lista
cuando es cerradi el archivo. Esto requiere a�adir una l�nea
a nuestra funci�n close:
static int close_mouse(struct inode *inode, struct file *file)
{
fasync_mouse(-1, file, 0)
if(--mouse_users)
return 0;
free_irq(OURMOUSE_IRQ, NULL);
MOD_DEC_USE_COUNT;
return 0;
}
Cuando cerramos el archivo podemos llamar a nuestro propio manejador
fasync como si el usuario pidiera que este archivo cesara de ser
usado para E/S as�ncrona. Esto aproximadamente limpia cualesquiera
finales perdidos. Seguramente no esperamos por la llegada de una
se�al para un archivo que no existir� m�s.
En este punto, el controlador del rat�n soporta todas las operaciones
de E/S as�ncrona, y las aplicaciones us�ndolas no fallar�n. Estas
de todas formas no trabajar�n todav�a. Necesitamos realmente
enviar las se�ales. Otra vez el n�cleo suministra una funci�n
para manejar esto.
Actualizamos un poco nuestro manejador de interrupciones:
static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
char delta_x;
char delta_y;
unsigned char new_buttons;
delta_x = inb(OURMOUSE_BASE);
delta_y = inb(OURMOUSE_BASE+1);
new_buttons = inb(OURMOUSE_BASE+2);
if(delta_x || delta_y || new_buttons != mouse_buttons)
{
/* Algo ha pasado */
spin_lock(&mouse_lock);
mouse_event = 1;
mouse_dx += delta_x;
mouse_dy += delta_y;
if(mouse_dx < -4096)
mouse_dx = -4096;
if(mouse_dx > 4096)
mouse_dx = 4096;
if(mouse_dy < -4096)
mouse_dy = -4096;
if(mouse_dy > 4096)
mouse_dy = 4096;
mouse_buttons = new_buttons;
spin_unlock(&mouse_lock);
/* Ahora hacemos E/S as�ncrona */
kill_fasync(&mouse_fasync, SIGIO);
wake_up_interruptible(&mouse_wait);
}
}
El nuevo c�digo simplemente llama a la rutina kill_fasync
suminstrada por el n�cleo si la cola no est� vac�a. Esto env�a la
se�al requerida (SIGIO en este caso) al proceso que cada manejador de
archivo dijo que quer�a ser informado sobre el excitante nuevo
movimiento del rat�n que acaba de ocurrir.
Con esto en su sitio y arreglados los fallos en la versi�n original,
tienes ahora un controlador de rat�n totalmente funcional usando el
protocolo del bus del rat�n. El trabajar� con X window
system, trabajar� con GPM
y deber�a de trabajar con todas las otras aplicaciones que necesites.
Doom es, por supuesto, la forma ideal
para probar que tu nuevo controlador de rat�n est� funcionando
de forma adecuada. Aseg�rate de probarlo de todas las formas posibles.