Análisis del controlador de teclado Linux

  
 El teclado es el más sencillo de todos los controladores, pero contiene el marco básico del controlador. Será de gran beneficio estudiar más a fondo otros controladores complejos. El siguiente es un análisis paso a paso del desarrollo del controlador. Se adopta el método de consulta. 1. Registro y revocación del módulo del kernel
Al cargar el módulo, la función de registro del módulo del kernel se ejecuta por primera vez. Sus funciones incluyen el registro del kernel de dispositivos y la inicialización de variables.
cabeza int estática, cola;
int _init Keypad_init (void) {resultado

int;
resultado = register_chrdev (KEY_LED_MAJOR, KEY_LED_NAME, &Keypad_fops);
Keypad_clear ();
init_waitqueue_head (&cola);
prink ("% s% s inicializado \\ n "., KEY_LED_NAME, KEY_LED_VERSION); //no puede utilizar retorno 0 prinf
;
}
module_init (Keypad_init); //módulo de carga
vacío _exit Keypad_cleanup (void) {

del_timer (&temporizador);
unregister_chrdev (KEY_LED_MAJOR, KEY_LED_NAME);
prink (" teclado controlador eliminado \\ n ");
}
module_exit (Keypad_cleanup);. //descargar el módulo
dos controladores del sistema de archivos y la interfaz de hardware virtuales
file_operations static struct Keypad_fops = {
abrir: Keypad_open,
leer: Keypad_read,
encuesta: Keypad_poll,
fasync: Keypad_fasync,
de prensa: Keypad_release,
};
después de la finalización de la interfaz es definir algunos de estos La implementación de varias funciones específicas! Ahora avancemos al siguiente paso. ¿Crees que en realidad no es difícil? No seas tan feliz temprano? Cuando se implementan estas funciones, intervienen muchas tecnologías, incluidos los temporizadores del núcleo, * implementaciones específicas de colas de espera (modo de bloqueo), técnicas de implementación específicas de métodos asíncronos y colas circulares. ¿Estás emocionado de ver tantas tecnologías? Te lo explicaré de una manera común. Espero que puedas entenderlo.
(Más información, bienvenido a iniciar sesión: qiangren.blog.edu.cn)
Tres. Implementación de la función de interfaz de operación abierta del dispositivo (Keypad_open)
El dispositivo abierto generalmente incluye dos operaciones principales, una es completar el dispositivo inicialización, dos dispositivos se añaden al contador de referencia 1
static int Keypad_open (struct inode * inode, archivo struct * filp)
{
read_xy ();
try_module_get (THIS_MODULE); //esta función Linux kernel 2.6 se incrementa, a diferencia del núcleo 2.4, la función es un valor de contador en 1 Usa return 0;}

estática read_xy (void) {

new_data (); //Obtener la función de valor-clave
keypad_starttimer (); //Habilitar el temporizador del kernel para obtener nuevos cambios de teclado en el tiempo de ciclo fijo
}
La siguiente función de adquisición de valor de teclado clave read_xy ()
main de kEY_CS (que corresponde a la dirección de lectura, antes de que pueda ser definida en función del dispositivo de hardware en particular, como kEY_CS #define (* (volátil unsigned short *) (0xf820000)) aquí debería diferir dependiendo leer
El valor de la clave ingresada se almacena en el caché buf []. El puntero de escritura del búfer de anillo es principal, y el puntero de lectura es de cola.
///////////////////////////////////definición de la estructura de datos del evento del teclado /////////////////////////////////////////typedef struct {
ulong status; //El valor del botón
ulong click; //si se presiona un botón, un expresado, 0 indica que no hay
} KEY_EVENT
estática KEY_EVENT cur_data, buf [bUFSIZE]; //bUFSIZE definiciones de macro utilizados para definir el tamaño de la memoria intermedia de anillo
estática new_data void (void) {

if ((KEY_CS &! 0xff) = 0xFF) //leer los datos de dirección de KEY_CS, un 0 indica si una tecla ha sido pulsada (circuito de hardware aquí Está activo bajo)
{switch (KEY_CS &0xff) {
case ~ KEY0 &0xff:
cur_data.status = 1; ///////se presiona 1 bajo
descanso; Venta de CASE ~ TECLA1 &0xff:
cur_data.status = 2; //2 se presiona Usa romper;
/////////Otros agregados, entiendes? ?
}
cur_data.click = 1;}

else if (KEY_CS &0xFF 0xFF ==) {
cur_data.click = 0;
cur_data.status = 0;
}
if (head! = tail) {////////La aplicación del búfer de cola circular comienza aquí ^ _ ^
int last = head--;
if (última < 0) ////////Si antes de tener que primero, a continuación, pasar a la cola, a fin de lograr una cola circular
última = BUFSIZE-1;
}
//////información clave almacenada en la memoria intermedia de cola circular
buf [cabeza] = cur_data;
si (++ cabeza == BUFSIZE)
cabeza = 0;
si (cabeza == cola &&tail ++ = BUFSIZE)
tail = 0;
if (fasync)
kill_fasync (&fasyc, SIGIO, POLL_IN);
wake_up_interruptible (&queue);
}
hoy a escribir a usted primero, se pondrán en marcha las siguientes secciones, así que estad atentos
a continuación presentamos varias otras funciones de interfaz de archivos para lograr
IV. keypad_release función de apagado introdujo por primera vez (), ¿Por qué Preséntalo primero? La razón es muy simple, debería ser relativamente simple, deje que todos hagan el ejercicio de calentamiento, después de introducir esto, continúe presentando una función más complicada, vea si puede comerlo. La operación principal de la operación de apagado es: apagar el dispositivo de forma asíncrona. notificación, contador de dispositivo se decrementa, eliminar la señal de interrupción de temporizador
static int Keypad_release (struct inode * inode, struct)
{
Keypad_fasync (-1, filp, 0);
module_put (THIS_MODULE);
del_timer (&timer);
return 0;
}
5. Implementación de la función de la interfaz de operación de lectura del dispositivo Keypad_read () - La función principal es leer el valor clave del búfer. llamando get_data () implementado por las copias de función del copy_to_user () para el área de datos de usuario
estática ssize_t Keypad_read (struct file * filp, char * buf, recuento ssize_t, loff_t * l)
{
DECLEARE_WAITQUEUE (esperar, actual); //declarar cola, se añade el proceso actual a la cola de espera
KEY_EVENT t;
ulong out_buf [2];
si (cabeza == cola) //el ciclo actual hay datos en la cola
{
si (filp- > f_flags &O_NONBLOCK) leen //si el usuario Use el modo de no bloqueo para leer
devolver _EAGAIN;
add_wait_queue (&queue, &wait); //Agregar el proceso actual a la cola de espera
current- > state = TASK_INTERRUPTIBLE; //Establecer la actual estado del proceso, mientras que
((cabeza == cola) &! y signal_pending (actual)) //si no hay datos en cola circular, y el proceso actual no está sujeta a la señal
{
shedule (); //proceso de programación
current- > STATE = TASK_INTERRUPTIBLE;
}
current- > STATE = TASK_RUNNING;
remove_wait_queue (&cola, &esperar);
si (cabeza == cola) guía de regreso recuento;
t = get_data (); //llamar a la función get_data (), para obtener los datos en la memoria intermedia se les dará una descripción detallada
out_buf [0] abajo = t. estado;
out_buf [1] = t.click;
copy_to_user (buf, &out_buf, sizeof (out_buf)); //obtener las claves copiados en el área de datos de usuario
vuelven recuento; < Br>
}
}
Es natural que introduzcamos la implementación de la función get_data (). La función de esta función es leer los valores clave que queremos del búfer de cola circular que definimos. en realidad es muy simple si usted entiende ciclo El principio de la cola en anillo, no hay más explicaciones aquí, debe tener el conocimiento general de la estructura de datos
estática KEY_EVENT get_data (void)
{
int last = tail
if (++ tail == BUFSIZE)
cola = 0;
volver buf [última];
}
arriba para ver si usted sabe, a continuación, puede entrar en el siguiente estudio, introduce el temporizador del núcleo el uso, el uso de la cola de lograr obstructiva de E /S, las llamadas al sistema tras encuesta, método de notificación asíncrona, introducción a, voy a dar un ejemplo práctico, para el archivo utilizado sistema operativo llama para
Para los controladores de teclado que escribimos, son básicamente los mismos. Sin más preámbulos, vamos a empezar nuestro desarrollo maravilloso conductor!
Copyright © Conocimiento de Windows All Rights Reserved