![]() | Publicaci�n Anterior |
---|---|
Algunas partes de este documento aparecieron primero en Linux Magazine bajo una exclusividad de noventa dias. |
Table 1-1. Codificaci�n de Datos del Rat�n
Byte 0 | 0x80 + los botones actualmente pulsados. |
Byte 1 | Un valor con signo para el desplazamiento en la posici�n X |
Byte 2 | Un valor con signo para el desplazamiento en la posici�n Y |
Los valores de la posici�n son truncados si es que exceden del rango de los 8 bits (que es -127 <= delta <= 127). Como el valor -128 no encaja en un byte no es permitido.
Los
son numerados de izquierda a derecha como 0, 1, 2, 3.. y cada bot�n establece el bit relevante. Por lo tanto un usuario presionando los botonoes de la izquierda y de la derecha en un rat�n de tres botones establecer�n los bits 0 y 2.Todos los ratones est�n requeridos a soportar la operaci�n poll. Ser�a algo verdaderamente muy bonito si todos los usuarios de un controlador de un dispositivo usaran poll para esperar a que tuvieran lugar los eventos.
Finalmente el soporte as�ncrono de E/S de los ratonoes. Este es un t�pico que todav�a no hemos cubierto pero que explicar� m�s tarde, despu�s de mirar en un controlador simple de rat�n.
#define OURMOUSE_BASE 0x300 static struct miscdevice our_mouse = { OURMOUSE_MINOR, "ourmouse", &our_mouse_fops }; __init ourmouse_init(void) { if(check_region(OURMOUSE_BASE, 3)) return -ENODEV; request_region(OURMOUSE_BASE, 3, "ourmouse"); misc_register(&our_mouse); return 0; }
#ifdef MODULE int init_module(void) { if(ourmouse_init()<0) return -ENODEV: return 0; } void cleanup_module(void) { misc_deregister(&our_mouse); free_region(OURMOUSE_BASE, 3); } #endif
struct file_operations our_mouse_fops = { owner: THIS_MODULE, /* Autom�tica administraci�n de uso */ read: read_mouse, /* Puedes leer un rat�n */ write: write_mouse, /* Esto deber�a de hacer un mont�n */ poll: poll_mouse, /* Encuesta */ open: open_mouse, /* Llamado en open */ release: close_mouse, /* Llamado en close */ };
static int mouse_users = 0; /* Cuenta de Usuarios */ static int mouse_dx = 0; /* Cambios de Posici�n */ static int mouse_dy = 0; static int mouse_event = 0; /* El rat�n se movi� */ static int open_mouse(struct inode *inode, struct file *file) { if(mouse_users++) return 0; if(request_irq(mouse_intr, OURMOUSE_IRQ, 0, "ourmouse", NULL)) { mouse_users--; return -EBUSY; } mouse_dx = 0; mouse_dy = 0; mouse_event = 0; mouse_buttons = 0; return 0; }
La funci�n release (liberar) necesita desenrollar todas estas:
static int close_mouse(struct inode *inode, struct file *file) { if(--mouse_users) return 0; free_irq(OURMOUSE_IRQ, NULL); return 0; }
static ssize_t write_mouse(struct file *file, const char *buffer, size_t count, loff_t *ppos) { return -EINVAL; }
Esto es bastante auto-explicativo. Siempre que escribes dir�n que era una funci�n inv�lida.
static struct wait_queue *mouse_wait; static spinlock_t mouse_lock = SPIN_LOCK_UNLOCKED; 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; mouse_buttons = new_buttons; spin_unlock(&mouse_lock); wake_up_interruptible(&mouse_wait); } }
static unsigned int mouse_poll(struct file *file, poll_table *wait) { poll_wait(file, &mouse_wait, wait); if(mouse_event) return POLLIN | POLLRDNORM; return 0; }
static ssize_t mouse_read(struct file *file, char *buffer, size_t count, loff_t *pos) { int dx, dy; unsigned char button; unsigned long flags; int n; if(count<3) return -EINVAL; /* * Espera por un evento */ while(!mouse_event) { if(file->f_flags&O_NDELAY) return -EAGAIN; interruptible_sleep_on(&mouse_wait); if(signal_pending(current)) return -ERESTARTSYS; }
/* Coge el evento */ spinlock_irqsave(&mouse_lock, flags); dx = mouse_dx; dy = mouse_dy; button = mouse_buttons; if(dx<=-127) dx=-127; if(dx>=127) dx=127; if(dy<=-127) dy=-127; if(dy>=127) dy=127; mouse_dx -= dx; mouse_dy -= dy; if(mouse_dx == 0 && mouse_dy == 0) mouse_event = 0; spin_unlock_irqrestore(&mouse_lock, flags);
if(put_user(button|0x80, buffer)) return -EFAULT; if(put_user((char)dx, buffer+1)) return -EFAULT; if(put_user((char)dy, buffer+2)) return -EFAULT; for(n=3; n < count; n++) if(put_user(0x00, buffer+n)) return -EFAULT; return count; }
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); wake_up_interruptible(&mouse_wait); } }
A�adiendo estos chequeos limitamos el rango de movimiento acumulado a algo sensible.
while(!mouse_event) {
interruptible_sleep_on(&mouse_wait);
save_flags(flags); cli(); while(!mouse_event) { if(file->f_flags&O_NDELAY) { restore_flags(flags); return -EAGAIN; } interruptible_sleep_on(&mouse_wait); if(signal_pending(current)) { restore_flags(flags); return -ERESTARTSYS; } } restore_flags(flags);
struct wait_queue wait = { current, NULL }; add_wait_queue(&mouse_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); while(!mouse_event) { if(file->f_flags&O_NDELAY) { remove_wait_queue(&mouse_wait, &wait); set_current_state(TASK_RUNNING); return -EWOULDBLOCK; } if(signal_pending(current)) { remove_wait_queue(&mouse_wait, &wait); current->state = TASK_RUNNING; return -ERESTARTSYS; } schedule(); set_current_state(TASK_INTERRUPTIBLE); } remove_wait_wait(&mouse_wait, &wait); set_current_state(TASK_RUNNING);
Detr�s de todos los envoltorios en el c�digo original lo que est� sucediendo es esto:
![]() | Nota |
---|---|
Este no es un t�pico f�cil. No tengas miedo de releer la descripci�n unas pocas veces y tambi�n de mirar en otros controladores de dispositivos para ver si funciona. Finalmente si todav�a no puedes cogerlo, puedes usar el c�digo como modelo para escribir otros controladores de dispositivos y confiar en m�. |
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 */ };
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; }
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; }
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); } }
Este documento ha sido traducido por Rub�n Melc�n <melkon@terra.es>; y es publicado por el Proyecto Lucas
Versi�n de la traduci�n 0.04 ( Julio de 2002 ).
Si tienes comentarios sobre la traducci�n, ponte en contacto con Rub�n Melc�n <melkon@terra.es>