Story Transcript
Bloque I: Principios de sistemas operativos
UNIVERSIDAD DE CANTABRIA
Tema 1. Principios básicos de los sistemas operativos Tema 2. Concurrencia Tema 3. Ficheros Tema 4. Sincronización y programación dirigida por eventos Tema 5. Planificación y despacho Tema 6. Sistemas de tiempo real y sistemas empotrados Tema 7. Gestión de memoria Tema 8. Gestión de dispositivos de entrada-salida
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS 8
© Michael González, J. Javier Gutiérrez 19/ma/11
Notas:
1
UNIVERSIDAD DE CANTABRIA
Tema 8. Gestión de dispositivos de entrada-salida • Características de los dispositivos de entrada/salida • Entrada/salida por consulta • Entrada/salida por interrupciones • Entrada/salida por acceso directo a memoria • Organización de manejadores de dispositivos (drivers) de entrada/salida • Programación de manejadores de dispositivos de entrada/salida • Implementación de drivers
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
2
1. Características de los dispositivos de entrada/salida
UNIVERSIDAD DE CANTABRIA
Los dispositivos de entrada/salida (I/O) forman junto con la CPU y la memoria los elementos más importantes del computador Uno de sus objetivos principales es la eficiencia en las operaciones de entrada/salida, minimizando el trabajo a realizar por la CPU Las velocidades de los dispositivos de I/O son muy variadas: • dispositivos lentos (p.e., ratón, teclado) • dispositivos medios (p.e., impresora) • dispositivos rápidos (p.e., red, disco) Para acomodar las velocidades se usan circuitos de interfaz
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
3
Interfaces de entrada/salida
UNIVERSIDAD DE CANTABRIA
Se encargan de la comunicación entre la CPU y el dispositivo Unidad de Control Regs. CPU
Circuito de Interfaz de I/O
Regs. ALU
Dispositivo de I/O
Líneas de control Datos
Programa
Líneas de direcciones Líneas de datos
Memoria
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
4
Conexión de las interfaces de entrada/salida
UNIVERSIDAD DE CANTABRIA
Conexión mapeada en memoria • el circuito de interfaz se conecta como si fuera memoria • se accede a los registros leyendo o escribiendo una variable en una posición de memoria concreta Conexión mediante puertos de entrada/salida • el circuito de interfaz se conecta mediante líneas especiales • se accede a los registros mediante instrucciones especiales (in, out), especificando un número de puerto
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Tipos de entrada/salida
5
UNIVERSIDAD DE CANTABRIA
Entrada/salida por consulta o programada • la CPU accede a los registros desde programa • para saber si el dispositivo está listo, se hace una consulta periódica Entrada/salida por interrupciones • el dispositivo avisa a la CPU cuando está listo • la entrada/salida se hace mediante una rutina de servicio de interrupción Entrada/salida por acceso directo a memoria • el dispositivo accede directamente a la memoria • avisa a la CPU del inicio o final de la operación GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
6
2. Entrada/salida por consulta
UNIVERSIDAD DE CANTABRIA
La operación de I/O es controlada por la CPU Antes de realizar la operación se comprueba el (los) registro(s) de estado, para ver si el dispositivo está listo Ventajas: sencillez Desventajas: • ritmo de transferencia limitado por la velocidad de la CPU • tiempo de respuesta elevado, mayor que el periodo de consulta • sobrecarga de la CPU para operaciones de consulta que podrían evitarse
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
7
3. Entrada/salida por interrupciones
UNIVERSIDAD DE CANTABRIA
Permite al dispositivo marcar el instante en que se hace la transferencia de datos El mecanismo de interrupción está presente en casi todos los computadores
IRQ
IRQ Regs.
Mask CPU
Circuito de Interfaz de I/O
Unidad de control IACK
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
8
Identificación de la fuente de interrupción
UNIVERSIDAD DE CANTABRIA
Por consulta IRQ CPU
I/O-1
I/O-3
Por múltiples líneas
IRQ0
CPU
I/O-2
IRQ1 IRQ2
I/O-1
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
I/O-2
I/O-3
© Michael González, J. Javier Gutiérrez 19/ma/11
Gestión de interrupciones
9
UNIVERSIDAD DE CANTABRIA
Las interrupciones se pueden enmascarar • se utiliza para evitar la interrupción cuando se accede a datos compartidos con ella Para cada interrupción se puede instalar una rutina de servicio de interrupción • al llegar la interrupción, el procesador interrumpe el programa en ejecución y enmascara esa interrupción • después ejecuta la rutina de servicio de interrupción • al acabar, el procesador restaura el estado anterior y el programa interrumpido continúa
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
10
La rutina de servicio de interrupción
UNIVERSIDAD DE CANTABRIA
Estructura habitual • Acceder al dispositivo causante de la interrupción y hacer que cese la petición de interrupción • Si es necesario, acceder al controlador de interrupciones para hacer lo mismo • realizar la transferencia de datos El modelo es el de una tarea concurrente más • ejecuta a la máxima prioridad del sistema
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
11
4. Entrada/salida por acceso directo a memoria
UNIVERSIDAD DE CANTABRIA
El ritmo de transferencia es superior al de los otros métodos El instante de I/O lo marca el dispositivo con interrupciones Hay líneas para desconectar a la CPU de la memoria Memoria Regs.
DMA acknowledge
CPU
Circuito de Interfaz de I/O
DMA request
IRQ IACK
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
12
Funcionamiento de la I/O directa
UNIVERSIDAD DE CANTABRIA
Registros del dispositivo: • IODIR: Dirección de memoria para la operación de I/O • CONT: Contador de número de bytes a transferir Funcionamiento habitual: • La CPU carga los valores en los registros del dispositivo • El dispositivo solicita el uso de la memoria: DMA-request • La CPU se lo concede: DMA-acknowledge • El dispositivo transfiere los datos. Para cada uno, incrementa IODIR y decrementa CONT • Cuando CONT llega a 0 se devuelve el control de la memoria a la CPU (DMA-request) y se envía una interrupción de aviso GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
5. Organización de drivers de entrada/salida
13
UNIVERSIDAD DE CANTABRIA
Un driver para un dispositivo es una interfaz entre el sistema operativo y el hardware de ese dispositivo Los drivers forman parte del núcleo y tienen acceso restringido a estructuras del sistema operativo El objetivo del driver es ofrecer un mecanismo de uso general, con operaciones como: -
abrir (open) y cerrar (close) leer (read) escribir (write) controlar (ioctl)
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
14
El driver en el contexto del sistema operativo
UNIVERSIDAD DE CANTABRIA
Usuarios Aplicaciones
Shell
Servicios (API) Drivers I/O
Sistema operativo
Núcleo/Kernel Hardware
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Tipos de dispositivos y módulos
15
UNIVERSIDAD DE CANTABRIA
En Linux 2.6 se distinguen tres tipos de dispositivos y módulos: • de caracteres: E/S directa o por interrupciones • de bloques: E/S por acceso directo a memoria • de red: E/S por dispositivos de comunicaciones Esta clasificación no es rígida y se podría considerar otra ortogonal como: • módulos USB, módulos serie, módulos SCSI (Small Computer Systems Interface), etc. • cada dispositivo USB estaría controlado por un módulo USB, pero el dispositivo en sí mismo se comportaría como de caracteres (puerto serie USB), de bloques (tarjeta de memoria USB), o una interfaz de red (interfaz Ethernet USB) GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
16
Dispositivos de caracteres
UNIVERSIDAD DE CANTABRIA
Se puede utilizar como si se tratara de un fichero, como una tira o conjunto de bytes Normalmente implementa las llamadas al sistema: open, close, read y write Ejemplos de dispositivos de caracteres: • consola (/dev/console) • puertos serie (/dev/ttys0) El acceso a estos dispositivos se realiza a través de nodos (nodes) del sistema de ficheros
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Módulos de Linux
17
UNIVERSIDAD DE CANTABRIA
Los drivers se implementan mediante módulos del núcleo: • objetos software con una interfaz bien definida, que se cargan dinámicamente en el núcleo del sistema operativo El módulo en Linux debe tener al menos dos operaciones: • init_function: para instalarlo - debe preparar el módulo para la posterior ejecución del resto de las funciones o puntos de entrada del módulo
• cleanup_function: para desinstalarlo - debe eliminar todo rastro del módulo
El código de un módulo sólo debe llamar a funciones incluidas en el kernel y no en librerías, ya que el módulo se enlaza directamente con el kernel. GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
18
Módulos de Linux (cont.)
UNIVERSIDAD DE CANTABRIA
Los pasos para construir un módulo de Linux serían: 1. editar el fichero con las operaciones de inicialización y finalización del módulo - tenemos un fichero.c
2. compilar el módulo - se puede editar un Makefile para ahorrar trabajo - obtenemos el fichero.ko
3. cargar el módulo - con insmod
Para descargar el módulo se hace con rmmod
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Ejemplo de módulo Linux
19
UNIVERSIDAD DE CANTABRIA
Fichero sencillo.c: #include #include MODULE_LICENSE("GPL"); static int instala (void) { printk(KERN_ALERT "Sencillo instalado\n"); return 0; } static void desinstala (void) { printk (KERN_ALERT "Sencillo desinstalado\n"); } module_init(instala); module_exit(desinstala) GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
20
Estructura de un módulo del núcleo
UNIVERSIDAD DE CANTABRIA
• "Includes" para las funciones de los módulos de núcleo • MODULE_LICENSE: Macro con el tipo de licencia (un texto) • Dos funciones: una de instalación y otra de desinstalación, con los prototipos como en el ejemplo • module_init: con esta macro declaramos cuál de nuestras funciones es la de instalación • module_exit: con esta macro declaramos cuál de nuestras funciones es la de desinstalación
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Compilación de módulos de Linux
21
UNIVERSIDAD DE CANTABRIA
La compilación: • Se hace con un make, creando un fichero Makefile con la siguiente línea (sencillo.o es el nombre del fichero objeto): obj-m := sencillo.o
• La orden make debe incluir el contexto del kernel y una orden que le indique el directorio de trabajo: make -C /lib/modules/linux-2.6.15.23/build M=‘pwd‘ modules
• donde hay que reemplazar /lib/modules/linux-2.6.15.23 por el directorio donde se hallan los fuentes del kernel - es necesario disponer de las cabeceras de las fuentes del kernel • el módulo recibe el nombre sencillo.ko
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
22
Compilación de módulos de Linux (cont.)
UNIVERSIDAD DE CANTABRIA
Es posible facilitar la compilación indicando la información anterior dentro del fichero Makefile: obj-m := sencillo.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) CC = /usr/bin/gcc-4.0 default: $(MAKE) -C $(KDIR) CC=$CC SUBDIRS=$(PWD) modules
tabulador GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
ruta del compilador (opcional) © Michael González, J. Javier Gutiérrez 19/ma/11
Cabeceras de las fuentes del kernel
23
UNIVERSIDAD DE CANTABRIA
Se suelen encontrar en un paquete aparte • linux-headers-2.6.xx.xx Comprobar también que están instaladas las utilidades para carga y descarga dinámica de módulos • module-init-tools
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
24
Instalación o desinstalación de módulos
UNIVERSIDAD DE CANTABRIA
• se debe hacer en modo superusuario (root) • se instala con insmod (que, además, ejecuta la init_function): • se desinstala mediante rmmod (ejecuta la cleanup_function): /sbin/insmod sencillo.ko /sbin/rmmod sencillo
• la orden lsmod muestra los módulos actualmente instalados - lee el fichero /proc/modules - muestra la siguiente información: nombre, tamaño, contador de uso y lista de módulos referidos
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Depuración en módulos de Linux
25
UNIVERSIDAD DE CANTABRIA
No se pueden usar las llamadas normales al sistema operativo desde dentro del núcleo • printk: similar al printf, pero ejecutable desde el núcleo; escribe en la consola y en /var/log/messages - la macro KERN_ALERT le da prioridad alta al mensaje (linux/kernel.h) - se puede consultar con tail /var/log/messages dmesg
Las funciones que se pueden usar desde el kernel se declaran en los directorios: include/linux y en include/asm situados en las fuentes del kernel, normalmente en: - /usr/src/linux-xx-xx GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
26
Drivers de Linux
UNIVERSIDAD DE CANTABRIA
Se crean como un caso particular de los módulos Los drivers utilizan números especiales para su identificación que tienen que ser registrados en la instalación y borrados en la desinstalación La instalación de un driver no da acceso a ningún dispositivo concreto: • el acceso se obtiene con la creación posterior de un fichero de dispositivo: - forma parte del sistema de ficheros - sobre él se podrán ejecutar las operaciones ofrecidas por el driver
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Identificación de dispositivos y drivers
27
UNIVERSIDAD DE CANTABRIA
Los dispositivos se representan mediante nombres especiales en el sistema de ficheros (habitualmente en /dev) Usan números de identificación • Número mayor (major): identifica a un driver, para el acceso a una unidad funcional separada • Número menor (minor): - identifica subunidades de un dispositivo mayor - o diferentes modos de uso del dispositivo
Drivers: se identifican con un nombre y un dato del tipo dev_t • El fichero /proc/devices muestra los dispositivos mayores
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
28
El tipo dev_t
UNIVERSIDAD DE CANTABRIA
Los números de dispositivo se guardan en un dato del tipo dev_t, para el que hay dos macros: int MAJOR(dev_t dev); int MINOR(dev_t dev);
• la primera nos devuelve el número mayor, y la segunda el menor Se puede construir un valor del tipo dev_t con la macro: dev_t MKDEV(unsigned int major, unsigned int minor);
Los números mayores se pueden asignar de forma estática o dinámica.
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Asignación estática de números mayores
29
UNIVERSIDAD DE CANTABRIA
Si deseamos un número mayor concreto, podemos usar: int register_chrdev_region (dev_t first, //número mayor y primer menor unsigned int count, //cuántos núm. menores char *name) //nombre del dispositivo
• Reserva el número mayor indicado y unos cuantos números menores • Si hay error, retorna un entero distinto de cero Peligro de colisiones de número
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
30
Asignación dinámica de números mayores
UNIVERSIDAD DE CANTABRIA
La asignación de número mayor para un dispositivo de caracteres se hace en la init_function mediante la función definida en : int alloc_chrdev_region (dev_t *dev, //retorna número mayor y menor unsigned int firstminor, // primer número menor unsigned int count, //cuántos núm. menores char *name) //nombre del dispositivo
• Reserva un número mayor para el driver y unos cuantos números menores • Devuelve en dev el número mayor y el primer número menor • Si hay error, retorna un entero distinto de cero
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Creación del fichero de dispositivo
31
UNIVERSIDAD DE CANTABRIA
El nombre del dispositivo aparecerá en /proc/devices y sysfs Luego creamos el fichero especial de dispositivo • habitualmente en /dev • se crean mediante la utilidad mknod Por ejemplo, así se crea un fichero para números mayor y menor 123 y 0, respectivamente mknod /dev/nombre_disp c 123 0 Puede ser necesario cambiar los permisos de acceso, para el uso por usuarios normales
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
32
Desinstalación del driver
UNIVERSIDAD DE CANTABRIA
Se hace desde la cleanup_function: void unregister_chrdev_region (dev_t first, unsigned int count);
• First indica el número mayor y el primer número menor • Count indica cuántos números menores hay que desinstalar
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
6. Programación de drivers de entrada/salida
33
UNIVERSIDAD DE CANTABRIA
El driver es un módulo software que debe responder a una interfaz bien definida con el kernel, con determinados puntos de entrada (funciones C): open release read write ioctl
abrir el dispositivo para usarlo cerrar el dispositivo leer bytes del dispositivo escribir bytes en el dispositivo orden de control sobre el dispositivo
Las que no se usen no se implementan
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
34
Programación de drivers de entrada/ salida (cont.)
UNIVERSIDAD DE CANTABRIA
Otros puntos de entrada menos frecuentes: llseek
posicionar el puntero de lectura/escritura
aio_read aio_write
lectura asíncrona (en paralelo al proceso) escritura asíncrona
readdir
leer información de directorio (no se usa en dispositivos)
poll
preguntar si se puede leer o escribir
mmap
mapear el dispositivo en memoria
flush
volcar los buffers al dispositivo
fsync
sincronizar el dispositivo
aio_fsync
sincronizar el dispositivo en paralelo al proceso
fasync
notificación de operación asíncrona
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Programación de drivers de entrada/ salida (cont.)
35
UNIVERSIDAD DE CANTABRIA
Otros puntos de entrada menos frecuentes: lock readv
reservar el dispositivo leer sobre múltiples áreas de memoria
sendfile
escribir sobre múltiples áreas de memoria enviar un fichero a un dispositivo
sendpage
enviar datos, página a página
get_unmapped_area check_flags
obtener zona de memoria comprobar las opciones pasadas a fcntl()
dir_notify
fcntl() requiere aviso de modificaciones a directorio
writev
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
36
Interfaces de los puntos de entrada más frecuentes
UNIVERSIDAD DE CANTABRIA
Convenio de nombres: anteponer el nombre del dispositivo al del punto de entrada; por ejemplo, para el dispositivo ptr int ptr_open (struct inode *inode, struct file *filp) void ptr_release (struct inode *inode, struct file *filp) ssize_t ptr_read (struct file *filp, char __user *buff, size_t count, loff_t *offp) ssize_t ptr_write (struct file *filp, const char __user *buff, size_t count, loff_t *offp) int ptr_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
La notación __user indica que el dato no puede usarse directamente desde el driver; es ignorada por el compilador GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Estructuras básicas de los drivers
37
UNIVERSIDAD DE CANTABRIA
Definidas en : • struct file_operations - contiene una tabla de punteros a las funciones del driver
• struct file - sirve para representar en el kernel un fichero abierto
• struct inode - estructura con la que el kernel representa internamente los ficheros
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
38
Tabla de punteros
UNIVERSIDAD DE CANTABRIA
struct file_operations { struct module *owner; ... // punteros a puntos de entrada }
El campo owner es un puntero al módulo propietario del driver • Se suele poner al valor THIS_MODULE
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Tabla de punteros (cont.)
39
UNIVERSIDAD DE CANTABRIA
Los restantes campos de esta estructura son punteros a las funciones del driver, en este orden: llseek
mmap
readv
read
open
writev
aio_read
flush
sendfile
write
release
sendpage
aio_write
fsync
get_unmapped_area
readdir
aio_fsync
check_flags
poll
fasync
dir_notify
ioctl
lock
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
40
Estructura de fichero
UNIVERSIDAD DE CANTABRIA
La información relevante para los drivers es la siguiente: struct file { mode_t f_mode; loff_t f_pos; unsigned int f_flags; struct file_operations *f_op; void *private_data; struct dentry *f_dentry; ... } • La crea el kernel en la operación open (puede haber muchas para
el mismo dispositivo) • Se le pasa a cualquier función que opera con el dispositivo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Estructura de fichero (cont.)
41
UNIVERSIDAD DE CANTABRIA
La descripción de los campos de struct file es: • f_mode: Modo de lectura (FMODE_READ), escritura (FMODE_WRITE) o ambos • f_pos: posición actual para lectura o escritura - valor de 64 bits, long long - se puede leer pero no se debería modificar - si read o write necesitan actualizar la posición deberían usar el parámetro que se les pasa • f_flags: Opciones del fichero usadas al abrir - Ej.: O_RDONLY, O_NONBLOCK, O_SYNC - los permisos de lectura escritura se deberían chequear en f_mode
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
42
Estructura de fichero (cont.)
UNIVERSIDAD DE CANTABRIA
• f_op: tabla de punteros a los puntos de entrada del driver (ver página 39) - esta tabla se podría cambiar completamente en el open dependiendo por ejemplo del número menor para identificar un modo de funcionamiento • private_data: puntero para guardar información específica del
driver - al principio vale null; el open debe asignarle memoria - el release debe liberar esa memoria • f_dentry: datos internos del sistema operativo - el punto más importante de esta estructura es que se puede acceder al inodo filp->f_dentry->d_inode
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Estructura de inodos
43
UNIVERSIDAD DE CANTABRIA
Contiene información útil para los ficheros, tal como el estado del fichero, hora de creación y modificación, etc., pero la información importante para los drivers es: struct inode { dev_t i_rdev; struct cdev *i_cdev; ... }
• i_rdev: identificador del dispositivo • i_cdev: apunta a la estructura interna del kernel para dispositivos de caracteres GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
44
Estructura de inodos (cont.)
UNIVERSIDAD DE CANTABRIA
Es única para el dispositivo Podemos usar estas macros para averiguar los números mayor y menor: unsigned int imajor(struct inode *inode) unsigned int iminor(struct inode *inode)
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Registro del driver de caracteres
45
UNIVERSIDAD DE CANTABRIA
Antes de usar el driver, es preciso alojar en memoria, inicializar y registrar la estructura cdev • con las funciones de Alojar: struct cdev *cdev_alloc(void);
Inicializar void cdev_init(struct cdev *dev, struct file_operations *fops);
Además, hay que inicializar el campo owner: cdev->owner=THIS_MODULE;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
46
Registro del driver de caracteres (cont.)
UNIVERSIDAD DE CANTABRIA
Añadir el driver al kernel int cdev_add(struct cdev *dev, dev_t num, // id. dispositivo unsigned int count); // cuántos disp.
• si falla, retorna un número distinto de cero, y no se añade el dispositivo al sistema • si va bien, el dispositivo se dice que está vivo Eliminarlo void cdev_del(struct cdev *dev); GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Punto de entrada open
47
UNIVERSIDAD DE CANTABRIA
Interfaz: int ptr_open (struct inode *inodep, struct file *filp)
Abre el dispositivo: • Chequea errores del dispositivo • Inicializa el dispositivo si es la primera vez que se abre • Crea y rellena si hace falta filp->private_data • Identifica el número menor y actualiza f_op si procede
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
48
Punto de entrada release
UNIVERSIDAD DE CANTABRIA
Interfaz: void ptr_release (struct inode *inodep, struct file *filp)
Cierra el dispositivo: • Libera si hace falta la memoria asignada a filp->private_data
• Cierra el dispositivo si es preciso
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Punto de entrada read
49
UNIVERSIDAD DE CANTABRIA
Interfaz: ssize_t ptr_read (struct file *filp, char __user *buff, size_t count, loff_t *offp)
Lee datos del dispositivo: • count es la cantidad de bytes a leer • buff es el buffer de usuario en el que se depositan los datos - está en el espacio del usuario • offp la posición del fichero a la que se accede
• retorna el número de bytes leídos o un valor negativo si hay algún error GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
50
Punto de entrada write
UNIVERSIDAD DE CANTABRIA
Interfaz: ssize_t ptr_write (struct file *filp, const char __user *buff, size_t count, loff_t *offp)
Escribe datos del dispositivo: • count es la cantidad de bytes a escribir • buff es el buffer de usuario en el que están los datos - está en el espacio del usuario • offp la posición del fichero a la que se accede
• retorna el número de bytes escritos o un valor negativo si hay algún error GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Punto de entrada ioctl
51
UNIVERSIDAD DE CANTABRIA
Interfaz: int ptr_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
Envía una orden de control al dispositivo: • cmd es la orden • arg es un argumento para ejecutar la orden La interpretación de la orden es dependiente del dispositivo Retorna cero si va bien, o un código de error si va mal.
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
52
Ejemplo: Driver de prueba //
UNIVERSIDAD DE CANTABRIA
basico.h
int basico_open(struct inode *inodep, struct file *filp); int basico_release(struct inode *inodep, struct file *filp); ssize_t basico_read (struct file *filp, char *buff, size_t count, loff_t *offp); ssize_t basico_write (struct file *filp, const char *buff, size_t count, loff_t *offp);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Driver de prueba: includes #include #include #include #include #include #include
53
UNIVERSIDAD DE CANTABRIA
"basico.h"
MODULE_LICENSE("GPL");
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
54
Driver de prueba: variables globales
UNIVERSIDAD DE CANTABRIA
static struct file_operations basico_fops = { THIS_MODULE, // owner NULL, // lseek NULL, // read NULL, // aio_read NULL, // write NULL, // aio_write NULL, // readdir NULL, // poll NULL, // ioctl NULL, // mmap NULL, // open NULL, // flush NULL, // release NULL, // fsync // lo mismo para todos los demás puntos de entrada NULL // dir_notify };
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Driver de prueba: variables globales (cont.)
55
UNIVERSIDAD DE CANTABRIA
// Datos del dispositivo, incluyendo la estructura cdev struct basico_datos { struct cdev *cdev; // Estructura para dispositivos de caracteres dev_t dev; // información con el numero mayor y menor int dato_cualquiera; }; static struct basico_datos datos;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
56
Driver de prueba: instalación y desinstalación del driver
UNIVERSIDAD DE CANTABRIA
static int modulo_instalacion(void) { int result; // ponemos los puntos de entrada basico_fops.open=basico_open; basico_fops.release=basico_release; basico_fops.write=basico_write; basico_fops.read=basico_read; // reserva dinamica del número mayor del módulo // numero menor = cero, numero de dispositivos =1 result=alloc_chrdev_region(&datos.dev,0,1,"basico"); if (result < 0) { printk(KERN_WARNING "basico> (init_mod) fallo con major %d\n", MAJOR(datos.dev)); return result; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Driver de prueba: instalación y desinstalación del driver (cont.)
57
UNIVERSIDAD DE CANTABRIA
// iniciamos datos datos.dato_cualquiera=33; // por ejemplo datos.cdev=cdev_alloc(); cdev_init(datos.cdev, &basico_fops); datos.cdev->owner = THIS_MODULE; result= cdev_add(datos.cdev, datos.dev, 1); if (result!=0) { printk(KERN_WARNING "basico> (init_module) Error%d al añadir", result); // deshacer la reserva y salir unregister_chrdev_region(datos.dev,1); return result; }
}
// todo correcto: mensaje y salimos printk(KERN_INFO "basico> (init_module) OK con major %d\n", MAJOR(datos.dev)); return 0;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
58
Driver de prueba: instalación y desinstalación del driver
UNIVERSIDAD DE CANTABRIA
static void modulo_salida(void) { cdev_del(datos.cdev); unregister_chrdev_region(datos.dev,1); printk( KERN_INFO "basico> (cleanup_module) descargado OK\n"); } module_init(modulo_instalacion); module_exit(modulo_salida);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Driver de prueba: puntos de entrada
59
UNIVERSIDAD DE CANTABRIA
int basico_open(struct inode *inodep, struct file *filp) { int menor= iminor(inodep); printk(KERN_INFO "basico> (open) menor= %d\n",menor); return 0; } int basico_release(struct inode *inodep, struct file *filp) { int menor= iminor(inodep); printk(KERN_INFO "basico> (release) menor= %d\n",menor); return 0; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
60
Driver de prueba: puntos de entrada (cont.)
UNIVERSIDAD DE CANTABRIA
ssize_t basico_read (struct file *filp, char *buff, size_t count, loff_t *offp) { printk(KERN_INFO "basico> (read) count=%d\n",(int) count); return (ssize_t) 0; } ssize_t basico_write (struct file *filp, const char *buff, size_t count, loff_t *offp) { printk(KERN_INFO "basico> (write) count=%d\n",(int) count); return (ssize_t) count; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Programa de prueba para el driver #include #include #include #include #include #include #include
61
UNIVERSIDAD DE CANTABRIA
int main() { int fd,err; char *mistring="Hola yo soy un mensaje"; char strleido[100]; ssize_t leidos, escritos; strleido[0]=0; // lo hago vacío fd=open("/dev/basico0", O_RDWR); if (fd==-1) { perror("Error al abrir el fichero"); exit(1); } GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
62
Programa de prueba (cont.)
UNIVERSIDAD DE CANTABRIA
printf("Fichero abierto\n"); escritos=write(fd,mistring,strlen(mistring)+1); printf("Bytes escritos: %d\n",escritos); leidos=read(fd,&strleido,100); strleido[leidos]=’\0’; printf("Bytes leidos: %d\n",leidos); printf("String leido: %s\n",strleido); err=close(fd); if (err==-1) { perror("Error al cerrar el fichero"); exit(1); } printf("Fichero cerrado\n"); }
exit(0);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
7. Implementación de drivers
63
UNIVERSIDAD DE CANTABRIA
Reserva de memoria para variables dinámicas: en
• dentro del kernel debe usarse kmalloc y kfree: void *kmalloc(size_t size, int flags); void kfree(void *obj); • kmalloc reserva un número de bytes >= size y nos retorna su
dirección; flags controla el comportamiento de la función • kfree libera la memoria reservada con kmalloc El tamaño máximo que puede ser asignado por kmalloc está limitado (siempre menor que 128KB) • existen otras funciones para conseguir más memoria como vmalloc GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
64
Copia de datos del espacio del usuario al del kernel
UNIVERSIDAD DE CANTABRIA
El espacio de direcciones del kernel es diferente al de los procesos (espacio de usuario) Las funciones read y write necesitan copiar datos respectivamente hacia y desde el espacio de usuario Las funciones para estas copias están en : unsigned long copy_to_user(void *to, const void *from, unsigned long count); unsigned long copy_from_user(void *to, const void *from, unsigned long count);
- retornan el número de bytes no copiados - o un error, si el puntero de usuario no es válido por ejemplo GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Ejemplo: buffer virtual //
65
UNIVERSIDAD DE CANTABRIA
buffervirtual.h
#define MAX 100 int buffervirtual_open(struct inode *inodep, struct file *filp); int buffervirtual_release(struct inode *inodep, struct file *filp); ssize_t buffervirtual_read (struct file *filp, char *buff, size_t count, loff_t *offp); ssize_t buffervirtual_write (struct file *filp, const char *buff, size_t count, loff_t *offp);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
66
Buffer virtual: includes #include #include #include #include #include #include #include #include
UNIVERSIDAD DE CANTABRIA
"buffervirtual.h"
MODULE_LICENSE("GPL");
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Buffer virtual: variables globales
67
UNIVERSIDAD DE CANTABRIA
static struct file_operations buffervirtual_fops = { THIS_MODULE, // owner NULL, // lseek NULL, // read NULL, // aio_read NULL, // write NULL, // aio_write NULL, // readdir NULL, // poll NULL, // ioctl NULL, // mmap NULL, // open NULL, // flush NULL, // release NULL, // fsync // lo mismo para todos los demás puntos de entrada NULL // dir_notify };
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
68
Buffer virtual: variables globales
UNIVERSIDAD DE CANTABRIA
// Datos del dispositivo, incluyendo la estructura cdev struct bv_datos { struct cdev *cdev; // Estructura de dispositivos de caracteres dev_t dev; // información con el numero mayor y menor char *buffer; // este sera nuestro buffer }; static struct bv_datos datos;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Buffer virtual: instalación y desinstalación del driver
69
UNIVERSIDAD DE CANTABRIA
static int modulo_instalacion(void) { int result; // ponemos los puntos de entrada buffervirtual_fops.open=buffervirtual_open; buffervirtual_fops.release=buffervirtual_release; buffervirtual_fops.write=buffervirtual_write; buffervirtual_fops.read=buffervirtual_read; // reserva dinamica del número mayor del módulo // numero menor = cero, numero de dispositivos =1 result=alloc_chrdev_region(&datos.dev,0,1,"buffervirtual"); if (result < 0) { printk(KERN_WARNING "bv> (init_module) fallo con major %d\n", MAJOR(datos.dev)); return result; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
70
Buffer virtual: instalación y desinstalación del driver (cont.)
UNIVERSIDAD DE CANTABRIA
// reservamos MAX bytes de espacio para el buffer datos.buffer = kmalloc(MAX, GFP_KERNEL); if (datos.buffer==NULL) { result = -ENOMEM; unregister_chrdev_region(datos.dev,1); printk( KERN_WARNING "bv> (init_module) Error, no hay mem.\n"); return result; } // instalamos driver datos.cdev=cdev_alloc(); cdev_init(datos.cdev, &buffervirtual_fops); datos.cdev->owner = THIS_MODULE; result= cdev_add(datos.cdev, datos.dev, 1); if (result!=0) { printk(KERN_WARNING "bv> (init_module) Error %d al añadir", result); // deshacer la reserva y salir kfree(datos.buffer); GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Buffer virtual: instalación y desinstalación del driver (cont.) }
}
71
UNIVERSIDAD DE CANTABRIA
unregister_chrdev_region(datos.dev,1); return result;
// todo correcto: mensaje y salimos printk(KERN_INFO "bv> (init_module) OK con major %d\n", MAJOR(datos.dev)); return 0;
static void modulo_salida(void) { kfree(datos.buffer); cdev_del(datos.cdev); unregister_chrdev_region(datos.dev,1); printk( KERN_INFO "bv> (cleanup_module) descargado OK\n"); } module_init(modulo_instalacion); module_exit(modulo_salida); GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
72
Buffer virtual: puntos de entrada del driver (cont.)
UNIVERSIDAD DE CANTABRIA
int buffervirtual_open(struct inode *inodep, struct file *filp) { int menor= iminor(inodep); printk(KERN_INFO "bv> (open) menor= %d\n",menor); return 0; } int buffervirtual_release(struct inode *inodep, struct file *filp) { int menor= iminor(inodep); printk(KERN_INFO "bv> (release) menor= %d\n",menor); return 0; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Buffer virtual: puntos de entrada del driver (cont.)
73
UNIVERSIDAD DE CANTABRIA
ssize_t buffervirtual_read (struct file *filp, char *buff, size_t count, loff_t *offp) { ssize_t cuenta; unsigned long not_copied;
}
printk(KERN_INFO "bv> (read) count=%d\n",(int) count); cuenta=(ssize_t) count; if (cuenta>MAX) { cuenta=MAX; } not_copied=copy_to_user(buff,datos.buffer, (unsigned long)cuenta); if (not_copied!=0) { printk(KERN_WARNING "bv> (read) AVISO, no se leyeron datos\n"); return(-EFAULT); } return cuenta;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
74
Buffer virtual: puntos de entrada del driver (cont.)
UNIVERSIDAD DE CANTABRIA
ssize_t buffervirtual_write (struct file *filp, const char *buff, size_t count, loff_t *offp) { ssize_t cuenta; unsigned long not_copied;
}
printk(KERN_INFO "bv> (write) count=%d\n",(int) count); cuenta=(ssize_t) count; if (cuenta>MAX) { cuenta=MAX; } not_copied=copy_from_user(datos.buffer,buff, (unsigned long)cuenta); if (not_copied!=0) { printk(KERN_WARNING "bv> (write) AVISO, no escribió bien\n"); return(-EFAULT); } return cuenta;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Acceso al hardware
75
UNIVERSIDAD DE CANTABRIA
Se dispone en de funciones para acceso a los puertos de entrada/salida: unsigned inb (unsigned port); void outb (unsigned char byte, unsigned port);
Estas funciones leen o escriben, respectivamente, un byte (8 bits) en el puerto indicado Hay funciones también para leer enteros de 16 o 32 bits. Hay funciones equivalentes que hacen una pausa después de leer o escribir: unsigned inb_p (unsigned port); void outb_p (unsigned char byte, unsigned port); GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
76
Temporizadores del kernel
UNIVERSIDAD DE CANTABRIA
Los temporizadores se usan para planificar la ejecución de una función en un instante de tiempo dado • de forma asíncrona a los threads de usuario • tienen la resolución de un jiffie • la función que se ejecuta es en respuesta a una interrupción software - hay que prever la sincronización (p.e., con spinlocks o variables atómicas) - no se puede dormir o llamar al planificador (schedule()) - no puede usar funciones bloqueantes (p.e., kmalloc())
• puede volver a registrarse para ejecutar más tarde (p.e., actividad periódica)
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Temporizadores del kernel (cont.)
77
UNIVERSIDAD DE CANTABRIA
La estructura de datos de un timer se encuentra en : struct timer_list { /*...*/ // otros miembros internos unsigned long expires; //valor absoluto de jiffies void (*function)(unsigned long); // función manejadora unsigned long data; // argumento para el manejador // para más datos hacer cast de un puntero };
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
78
Temporizadores del kernel (cont.)
UNIVERSIDAD DE CANTABRIA
Inicializar el temporizador void init_timer(struct timer_list *timer);
Añadir a la lista de temporizadores activos void add_timer(struct timer_list *timer);
Cambia el instante de expiración int mod_timer(struct timer_list *timer, unsigned long expires);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Temporizadores del kernel (cont.)
79
UNIVERSIDAD DE CANTABRIA
Elimina el temporizador antes de que el tiempo expire int del_timer(struct timer_list *timer);
Elimina el temporizador, garantizando que al finalizar la función no se está ejecutando int del_timer_sync(struct timer_list *timer);
• debe asegurarse que la función del timer no usa add_timer sobre sí misma al eliminarlo • es la función preferida para eliminar GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
80
Ejemplo: entrada/salida digital
UNIVERSIDAD DE CANTABRIA
Es una de las aplicaciones que tiene el puerto paralelo; nosotros vamos a construir y programar un dispositivo velocímetro que: • puede medir la velocidad de giro de una rueda, y por tanto la velocidad del vehículo que la lleva • puede presentar en un display: -
la velocidad instantánea la velocidad media (desde la inicialización) la distancia recorrida (desde la inicialización) la distancia total recorrida (desde el arranque del sistema) y el tiempo (desde la inicialización)
• dispone además de dos botones para cambiar el modo de presentación en el display, y para inicializar el dispositivo • también tiene 5 leds que permiten identificar el modo elegido GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
81
Esquema de conexión del dispositivo velocímetro
Linux
UNIVERSIDAD DE CANTABRIA
Puerto Paralelo
Velocidad actual Velocidad media Tiempo Reset Cambia modo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Distancia parcial Distancia total
82
Líneas del puerto paralelo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Modelo de programación del puerto paralelo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
UNIVERSIDAD DE CANTABRIA
83
UNIVERSIDAD DE CANTABRIA
84
Recursos del puerto paralelo
UNIVERSIDAD DE CANTABRIA
En el PC las direcciones de los registros y los niveles de interrupción utilizados son los siguientes: Puerto
LPT1
LPT2
LPT3
Datos Estado
0x0378 0x0379
0x0278 0x0279
0x03BC 0x03BD
Control
0x037A
0x027A
0x03BE
IRQ7
IRQ5
IRQ7
Interrupción
Habrá que configurar la BIOS del PC para elegir tanto el puerto que se utiliza como el modo de operación
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Hardware del dispositivo velocímetro
85
UNIVERSIDAD DE CANTABRIA
Medidor del movimiento de la rueda: • un fototransitor y un diodo led enfrentados permiten detectar el paso de los radios de la rueda • la señal del fototransitor se digitaliza mediante un comparador • la salida del comparador se conecta a la línea ACK del puerto paralelo (permite generar una interrupción cada vez que pasa un radio) • este mecanismo permite contar radios: - o lo que es lo mismo, vueltas, distancia ... - si se anotan además los tiempos en los que se detecta el paso del radio se obtienen las velocidades
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
86
Hardware del dispositivo velocímetro (cont.)
UNIVERSIDAD DE CANTABRIA
Botones: • se conectan directamente a dos entradas del puerto paralelo - Reset a BUSY - Cambio de modo a PE
• habrá que leer periódicamente los valores de las entradas para saber si se han pulsado Display: • consta de dos displays led de 7 segmentos conectados a sendos convertidores BCD a 7 segmentos • los convertidores se controlan con las 8 líneas de datos en las que se podrán escribir valores de 0 a 99 (en BCD) • los displays están conectados al revés GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
87
Hardware del dispositivo velocímetro (cont.)
UNIVERSIDAD DE CANTABRIA
Leds de modo seleccionado: • se conectan a las salidas del puerto paralelo mediante un decodificador de 3 a 8 El control desde los registros del puerto queda del modo siguiente LED
Reg. Control
Botón
Reg. Estado
Velocidad actual
0x03
Reset
0x80
Velocidad media Tiempo transcurrido
0x02 0x01
Cambia modo
0x20
Distancia parcial
0x00
Distancia total
0x04
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
88
Hardware del dispositivo velocímetro (cont.)
UNIVERSIDAD DE CANTABRIA
Desde el punto de vista del uso del puerto como entradas salidas digitales, no nos interesa la información de protocolo • únicamente importa la relación entre los bits de los registros y las líneas de control y estado - registro de control IRQ
P17
P13
P15
P16
P14
P1
- registro de estado P11
P10
P12
- el registro de datos mantiene directamente los valores escritos
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Diseño del driver: Velocímetro
89
UNIVERSIDAD DE CANTABRIA
Vamos a contemplar dos aproximaciones en el diseño del driver: • opción 1: - hacer el driver lo más sencillo posible con la funcionalidad imprescindible: acceso a los registros y control de las interrupciones - dejar el resto a la aplicación
• opción 2: - hacer que el driver se encarge del control total del dispositivo - ofrecer a la aplicación operaciones de consulta y control alternativo al que ofrece el propio dispositivo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
90
Diseño del driver: Velocímetro (cont.)
UNIVERSIDAD DE CANTABRIA
• Solución a la opción 1: - hacer que la operación read lea el registro de estado con la información de los botones y write escriba en el registro de datos la información del display - si se usan interrupciones, los controles de distancia, tiempo y velocidad quedarían dentro del driver (paso del radio) - el ioctl escribe el registro de control para encencer el led correspondiente al modo, y ofrece operaciones de consulta - el control de los botones pulsados lo tendrá que hacer la aplicación y llevará registro del modo actual; también presentará la información correspondiente en el display - si no se usan interrupciones, la aplicación también se encargará de calcular las distancias, tiempos y velocidades
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Diseño del driver: Velocímetro (cont.)
91
UNIVERSIDAD DE CANTABRIA
• Solución a la opción 2: - tanto si se usa la interrupción como si no, el driver controla completamente la medida de la distancia, el tiempo y la velocidad - también se encarga de controlar si los botones se han pulsado, ejecutando las acciones oportunas, con activación de los led y presentación de datos en el display - la operación read no es relevante para el control y se puede usar para obtener información de estado del velocímetro - la operación write tampoco es relevante para el control y puede suministrar algún tipo de información al driver - el ioctl puede ejecutar comandos de cambio de modo o inicialización alternativos a los botones
Esta es la opción que vamos a implementar
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
92
Detalles del diseño: Velocímetro
UNIVERSIDAD DE CANTABRIA
¿Se van a usar interrupciones? • Sí: la detección del paso del radio es inmediata • No: habrá que programar una actividad periódica dependiente de la velocidad máxima que se pretenda medir Aparición de datos en el display: • estamos ante una interfaz humana y el periodo de presentación de datos es importante - si para ser muy exactos lo hacemos con un periodo bajo, es posible que los cambios muy rápidos hagan que no se vea nada - si se hace con un periodo muy alto, los cambios por ejemplo de la velocidad, pueden dar saltos muy grandes entre valores
• un valor razonable puede estar en 500 ms GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Detalles del diseño: Velocímetro (cont.)
93
UNIVERSIDAD DE CANTABRIA
Atención al pulsado de los botones: • de nuevo estamos ante una interfaz humana, y en este caso lo importante es el periodo de atención a que el ususario pulse uno de los botones - un periodo bajo, aunque se consiga detectar que el botón ha sido pulsado, puede dar una sensasión de que el sistema no reacciona
• un periodo razonable para dar sensación de instantaneidad puede ser 50 ms Vamos a implementar la versión de polling programando una actividad periódica que atienda al cambio en la línea que provoca la interrupción
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
94
Diseño detallado: Velocímetro polling
UNIVERSIDAD DE CANTABRIA
Open: • Controla el acceso al velocímetro como un recurso exclusivo Read: • Obtiene en formato de texto la información interna del estado del velocímetro en el instante de la llamada: velocidad actual, velocidad media, distancia parcial, distancia total y tiempo Write: • Graba en el driver un mensaje que va a ser mostrado como introducción a la información de estado que suministra la operación de lectura
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Diseño detallado: Velocímetro polling (cont.)
95
UNIVERSIDAD DE CANTABRIA
Ioctl: • Establece el nuevo modo de presentación, como alternativa al uso del botón de cambio de modo Tres temporizadores para la realización de las actividades periódicas: • temporizador de control de botones • temporizador de control de interrupción • temporizador de presentación de datos
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
96
Velocímetro: fichero de cabeceras //
UNIVERSIDAD DE CANTABRIA
velocimetro.h
int velocimetro_open(struct inode *inodep, struct file *filp); int velocimetro_release(struct inode *inodep, struct file *filp); ssize_t velocimetro_read (struct file *filp, char *buff, size_t count, loff_t *offp); ssize_t velocimetro_write (struct file *filp, const char *buff, size_t count, loff_t *offp); int velocimetro_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: comandos de ioctl //
97
UNIVERSIDAD DE CANTABRIA
velocimetro_ioctl.h
#define #define #define #define #define
SELECT_V_ACT SELECT_V_MED SELECT_TIEMPO SELECT_D_PAR SELECT_D_TOT
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
0x03 0x02 0x01 0x00 0x04
© Michael González, J. Javier Gutiérrez 19/ma/11
98
Velocímetro: includes //
UNIVERSIDAD DE CANTABRIA
velocimetro.c driver
#include #include #include #include #include #include #include #include #include #include #include #include #include
"velocimetro.h"
MODULE_LICENSE("GPL");
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: constantes
99
UNIVERSIDAD DE CANTABRIA
// Direccion base del puerto paralelo LPT1 #define LPT1_BASE 0x378 // Offset de los registros del puerto paralelo #define DATOS 0 #define ESTADO 1 #define CONTROL 2 // Palabras de control #define V_ACT 0x03 #define V_MED 0x02 #define TIEMPO 0x01 #define D_PAR 0x00 #define D_TOT 0x04 // Mascaras de estado #define RESET 0x80 #define MODO 0x20 #define INTER 0x40 GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
100
Velocímetro: constantes (cont.)
UNIVERSIDAD DE CANTABRIA
// Numero de registros de puerto paralelo #define NUM_REGS 3 // Periodo del temporizador #define PERIODO 50 // Periodo del temporizador de interrupcion #define PERIODO_INT 5 // Periodo del temporizador de presentacion de datos #define PERIODO_PRES 500 // Longitud maxima del mensaje #define MAX 30
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: datos del dispositivo struct veloc_datos { struct cdev *cdev; // dev_t dev; // char modo; // atomic_t distancia; // atomic_t distancia_t; // atomic_t distancia_ant;// unsigned long t_inic; // unsigned long t_ant; // unsigned long t_act; // int v_act; // int v_media; // char *mensaje; char *buffer; struct semaphore acceso; spinlock_t uso_datos; };
101
UNIVERSIDAD DE CANTABRIA
Character device structure informacion con el numero mayor y menor modo de la aplicacion distancia recorrida: contador de int. distancia total para calcular la velocidad actual instante inicial instante previo instante actual velocidad actual velocidad media // mensaje de presentación de informacion // buffer de informacion // controla el acceso al driver // controla acceso a los parametros
static struct veloc_datos datos; GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
102
Velocímetro: datos del dispositivo (cont.) // // // //
UNIVERSIDAD DE CANTABRIA
Datos que se le pasan a la funcion manejadora del temporizador, incluyendo el propio temporizador Lee cada PERIODO ms el valor de los botones para ver si han sido pulsados
struct datos_temporizador { char estado_reset; // char estado_reset_prev; // char estado_modo; // char estado_modo_prev; // unsigned long jiffies_previos; struct timer_list timer; atomic_t apagando; };
controlan el reset controlan el cambio de modo
static struct datos_temporizador datos_timer;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: datos del dispositivo (cont.)
103
UNIVERSIDAD DE CANTABRIA
// Datos que se le pasan a la funcion manejadora del temporizador, // que emula la interrupción incluyendo el propio temporizador // Lee cada PERIODO_INT ms el valor de la interrupción struct datos_temporizador_int { char estado_int; // char estado_int_prev; // controlan el flanco de la int. unsigned long jiffies_previos; struct timer_list timer; atomic_t apagando; }; static struct datos_temporizador_int datos_int; // Datos que se le pasan a la funcion manejadora del temporizador // Presenta cada PERIODO_PRES ms los datos en el display struct datos_temporizador_pres { unsigned long jiffies_previos; struct timer_list timer; atomic_t apagando; }; static struct datos_temporizador_pres datos_pres; GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
104
Velocímetro: funciones auxiliares
UNIVERSIDAD DE CANTABRIA
// Calcula la velocidad actual y la instantánea cada periodo // del timer de presentación de datos static void calcula_velocidades(void) { long op; // actualiza el instante actual datos.t_act=jiffies; // velocidad actual en radios/segundo // radio como unidad de distancia, 5 radios/vuelta op=(long)datos.t_act-(long)datos.t_ant; if (op!=0) datos.v_act=(int)(((long)(atomic_read(&datos.distancia)atomic_read(&datos.distancia_ant))*(long)PERIODO_PRES)/op);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: funciones auxiliares (cont.)
105
UNIVERSIDAD DE CANTABRIA
// actualiza distancia e instante anteriores atomic_set(&datos.distancia_ant,atomic_read(&datos.distancia)); datos.t_ant=datos.t_act; // velocidad media en radios/segundo op=(long)datos.t_act-(long)datos.t_inic; if (op!=0) datos.v_media= (int) (((long)atomic_read(&datos.distancia)*(long)1000)/op); }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
106
Velocímetro: funciones auxiliares (cont.)
UNIVERSIDAD DE CANTABRIA
// Muestra el parámetro apropiado en el display static void display(void) { int dato=0; char msh,lsh; switch (datos.modo) { case V_ACT: // velocidad en radios/segundo dato=datos.v_act; break; case V_MED: // velocidad en radios/segundo dato=datos.v_media; break; case TIEMPO: // tiempo en segundos dato=((long)jiffies-(long)datos.t_inic)/1000; break; GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: funciones auxiliares (cont.)
107
UNIVERSIDAD DE CANTABRIA
case D_PAR: // distancia en radios dato=atomic_read(&datos.distancia); break; case D_TOT: // distancia en radios dato=atomic_read(&datos.distancia_t); break; default: printk(KERN_WARNING "veloc> (display) error \n");
}
} // corrige el orden de los displays de 7 segmentos // colocados al reves en la placa y extrae BCD msh= (dato/10)%10; lsh= (dato%10)owner = THIS_MODULE; result= cdev_add(datos.cdev, datos.dev, 1); if (result!=0) { printk(KERN_WARNING "veloc> (init_module) Error %d al anadir",result); goto error_instalacion_dev; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
110
Velocímetro: instalación (cont.)
UNIVERSIDAD DE CANTABRIA
// reserva el rango de direcciones de I/O if (check_region (LPT1_BASE, NUM_REGS)!=0) { printk(KERN_WARNING "veloc> (init_module) Borrando region I/O\n"); release_region (LPT1_BASE, NUM_REGS); } region=request_region (LPT1_BASE, NUM_REGS, "velocimetro"); if (region==NULL) { result=-ENODEV; printk(KERN_WARNING "veloc> (init_module) direcc. I/O no disp.!!\n"); goto error_reserva_IO; } printk(KERN_INFO "veloc> (init_module) Reservadas I/O. Rango:%x..%x\n", LPT1_BASE, LPT1_BASE + NUM_REGS -1);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: instalación (cont.)
111
UNIVERSIDAD DE CANTABRIA
// inicializamos datos del temporizador datos_timer.jiffies_previos=jiffies; atomic_set(&datos_timer.apagando,0); datos_timer.estado_reset = 1; datos_timer.estado_reset_prev = 1; datos_timer.estado_modo = 1; datos_timer.estado_modo_prev = 1; // inicializamos datos del temporizador de interrupcion datos_int.jiffies_previos=jiffies; atomic_set(&datos_int.apagando,0); datos_int.estado_int = 1; datos_int.estado_int_prev = 1; // inicializamos datos del temporizador de presentacion datos_pres.jiffies_previos=jiffies; atomic_set(&datos_pres.apagando,0);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
112
Velocímetro: instalación (cont.)
UNIVERSIDAD DE CANTABRIA
// inicializamos datos del dispositivo datos.modo=3; atomic_set(&datos.distancia,0); atomic_set(&datos.distancia_t,0); atomic_set(&datos.distancia_ant,0); datos.t_inic=jiffies; datos.t_ant=datos.t_inic; datos.t_act=datos.t_inic; datos.v_act=0; datos.v_media=0; sema_init(&datos.acceso,1); spin_lock_init(&datos.uso_datos); if ((datos.mensaje= kmalloc(MAX,GFP_KERNEL))==NULL) { printk( KERN_WARNING "veloc> (init_module) Error, no hay memoria\n"); result = -ENOMEM; goto error_mensaje; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: instalación (cont.)
113
UNIVERSIDAD DE CANTABRIA
datos.mensaje[0]=0; if ((datos.buffer= kmalloc(3*MAX,GFP_KERNEL))==NULL) { printk( KERN_WARNING "veloc> (init_module) Error, no hay memoria\n"); result = -ENOMEM; goto error_buffer; } // creamos el temporizador y lo activamos init_timer(&datos_timer.timer); datos_timer.timer.expires=jiffies+PERIODO; datos_timer.timer.function=manejador; datos_timer.timer.data=(unsigned long) &datos_timer; // cast add_timer(&datos_timer.timer);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
114
Velocímetro: instalación (cont.)
UNIVERSIDAD DE CANTABRIA
// creamos el temporizador de interrupcion y lo activamos init_timer(&datos_int.timer); datos_int.timer.expires=jiffies+PERIODO_INT; datos_int.timer.function=manejador_int; datos_int.timer.data=(unsigned long) &datos_int; // cast add_timer(&datos_int.timer); // creamos el temporizador de presentacion y lo activamos init_timer(&datos_pres.timer); datos_pres.timer.expires=jiffies+PERIODO_PRES; datos_pres.timer.function=manejador_presenta_datos; datos_pres.timer.data=(unsigned long) &datos_pres; // cast add_timer(&datos_pres.timer); // inicializa registros de control y datos outb(datos.modo,LPT1_BASE+CONTROL); display(); // todo correcto: mensaje y salimos printk( KERN_INFO "veloc> (init_module) OK con major %d\n", MAJOR(datos.dev)); return 0; GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: instalación (cont.)
115
UNIVERSIDAD DE CANTABRIA
// Errores error_buffer: kfree(datos.mensaje); error_mensaje: error_reserva_IO: cdev_del(datos.cdev); error_instalacion_dev: unregister_chrdev_region(datos.dev,1);
}
error_reserva_numeros: return result;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
116
Velocímetro: desinstalación
UNIVERSIDAD DE CANTABRIA
static void modulo_salida(void) { cdev_del(datos.cdev); unregister_chrdev_region(datos.dev,1); // libera memoria kfree(datos.mensaje); kfree(datos.buffer); // libera el temporizador atomic_set(&datos_timer.apagando,1); del_timer_sync(&datos_timer.timer); // libera el temporizador de interrupcion atomic_set(&datos_int.apagando,1); del_timer_sync(&datos_int.timer); // libera el temporizador de presentacion de datos atomic_set(&datos_pres.apagando,1); del_timer_sync(&datos_pres.timer); // Libera direcciones de I/O release_region (LPT1_BASE, NUM_REGS); printk( KERN_INFO "veloc> (cleanup_module) descargado OK\n"); } GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: open/release
117
UNIVERSIDAD DE CANTABRIA
int velocimetro_open(struct inode *inodep, struct file *filp) { int menor= MINOR(inodep->i_rdev); printk(KERN_INFO "veloc> (open) menor= %d\n",menor); // intenta acceder al driver de acceso exclusivo if (down_trylock(&datos.acceso)!=0) { printk(KERN_WARNING "veloc> (open) Esta en uso ... \n"); return -EBUSY; } }
return 0;
int velocimetro_release(struct inode *inodep, struct file *filp) { int menor= MINOR(inodep->i_rdev); printk(KERN_INFO "veloc> (release) menor= %d\n",menor); up(&datos.acceso); return 0; } GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
118
Velocímetro: read
UNIVERSIDAD DE CANTABRIA
ssize_t velocimetro_read (struct file *filp, char *buff, size_t count, loff_t *offp) { unsigned long not_copied=1; printk(KERN_INFO "veloc> (read) count=%d\n",(int) count); spin_lock_bh(&datos.uso_datos); sprintf(datos.buffer, "%s \nD = %d \nDT = %d \nT = %d \nVi = %d \nVmed= %d \n", datos.mensaje, atomic_read(&datos.distancia), atomic_read(&datos.distancia_t), (int)((datos.t_act-datos.t_inic)/1000), datos.v_act, datos.v_media); spin_unlock_bh(&datos.uso_datos);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: read (cont.)
}
119
UNIVERSIDAD DE CANTABRIA
not_copied=copy_to_user(buff,datos.buffer,(unsigned long)(3*MAX)); if (not_copied!=0) { printk(KERN_WARNING "veloc> (read) AVISO, no se leyeron los datos\n"); return(-EFAULT); } return 3*MAX;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
120
Velocímetro: write
UNIVERSIDAD DE CANTABRIA
ssize_t velocimetro_write (struct file *filp, const char *buff, size_t count, loff_t *offp) { ssize_t cuenta; unsigned long not_copied;
}
printk(KERN_INFO "veloc> (write) count=%d\n",(int) count); cuenta=(ssize_t) count; if (cuenta>MAX) { cuenta=MAX; } not_copied=copy_from_user(datos.mensaje,buff,(unsigned long)cuenta); if (not_copied!=0) { printk(KERN_WARNING "veloc> (write) AVISO, no se escribio bien\n"); return(-EFAULT); } return cuenta;
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: ioctl
121
UNIVERSIDAD DE CANTABRIA
int velocimetro_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { printk(KERN_INFO "veloc> (ioctl) cmd=%d\n",(int) cmd); datos.modo=(char)cmd%5; outb(datos.modo,LPT1_BASE+CONTROL); return 0; }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
122
Velocímetro: timer control botones
UNIVERSIDAD DE CANTABRIA
void manejador (unsigned long arg) { struct datos_temporizador *dat =(struct datos_temporizador *) arg; char byte; unsigned long j=jiffies; char DEBUG = 0; // comprueba si hay cambio en los botones byte=inb(LPT1_BASE+ESTADO); if (DEBUG) printk(KERN_INFO "veloc> (timer) estado 0x%x \n",byte&0xff);
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: timer control botones (cont.)
123
UNIVERSIDAD DE CANTABRIA
dat->estado_modo_prev=dat->estado_modo; if (byte & MODO) { dat->estado_modo=1; } else { dat->estado_modo=0; } if ((dat->estado_modo_prev==1) && (dat->estado_modo==0)) { // cambio de modo if (DEBUG) printk(KERN_INFO "veloc> (timer) cambio de modo \n"); datos.modo=(datos.modo+1) % 5; outb(datos.modo,LPT1_BASE+CONTROL); }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
124
Velocímetro: timer control botones (cont.)
UNIVERSIDAD DE CANTABRIA
dat->estado_reset_prev=dat->estado_reset; if (byte & RESET) { dat->estado_reset=1; } else { dat->estado_reset=0; } if ((dat->estado_reset_prev==1) && (dat->estado_reset==0)) { // pasa estado de reset if (DEBUG) printk(KERN_INFO "veloc> (timer) reset \n"); datos.modo=3; outb(datos.modo,LPT1_BASE+CONTROL); datos.t_inic=jiffies; datos.t_ant=datos.t_inic; datos.t_act=datos.t_inic; atomic_set(&datos.distancia,0); atomic_set(&datos.distancia_ant,0); }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: timer control botones (cont.)
}
125
UNIVERSIDAD DE CANTABRIA
// programa de nuevo el timer dat->timer.expires+=PERIODO; dat->jiffies_previos=j; if(atomic_read(&dat->apagando)==0) { add_timer(&dat->timer); //solo si no estamos apagando }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
126
Velocímetro: timer control interrupción
UNIVERSIDAD DE CANTABRIA
void manejador_int (unsigned long arg) { struct datos_temporizador_int *dat = (struct datos_temporizador_int *) arg; char byte; unsigned long j=jiffies; char DEBUG = 0; // comprueba si hay cambio en la interrupcion byte=inb(LPT1_BASE+ESTADO); if (DEBUG) printk(KERN_INFO "veloc> (int) contador %d \n", atomic_read(&datos.distancia)); dat->estado_int_prev=dat->estado_int; if (byte & INTER) { dat->estado_int=1; } else { dat->estado_int=0; } GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Velocímetro: timer control interrupción
127
UNIVERSIDAD DE CANTABRIA
if ((dat->estado_int_prev==1) && (dat->estado_int==0)) { // anota otra interrupción if (DEBUG) printk(KERN_INFO "veloc> (timer) reset \n"); atomic_inc(&datos.distancia); atomic_inc(&datos.distancia_t); }
}
// programa de nuevo el timer dat->timer.expires+=PERIODO_INT; dat->jiffies_previos=j; if(atomic_read(&dat->apagando)==0) { add_timer(&dat->timer); //solo si no estamos apagando }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
128
Velocímetro: timer presentación
UNIVERSIDAD DE CANTABRIA
void manejador_presenta_datos (unsigned long arg) { struct datos_temporizador_pres *dat = (struct datos_temporizador_pres *) arg; unsigned long j=jiffies; // calcula las velocidades y muestra el parametro acorde al modo spin_lock_bh(&datos.uso_datos); calcula_velocidades(); spin_unlock_bh(&datos.uso_datos); display();
}
// programa de nuevo el timer dat->timer.expires+=PERIODO_PRES; dat->jiffies_previos=j; if(atomic_read(&dat->apagando)==0) { add_timer(&dat->timer); //solo si no estamos apagando }
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Programa de prueba
129
UNIVERSIDAD DE CANTABRIA
Dado que el driver incorpora toda la funcionalidad de control del velocímetro desde el momento de la instalación el hardware está operativo y funcionando • no es necesario un programa de prueba El programa de prueba • escribe el mensaje para la información • lee la información de estado del dispositivo y la muestra en pantalla cada segundo • finaliza con una señal (p.e., Ctrl+c) - se pone el dispositivo en modo de muestra del tiempo - se cierra el dispositivo
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
130
Comentarios sobre el ejemplo
UNIVERSIDAD DE CANTABRIA
Hemos utilizado el puerto paralelo como una interfaz de entradas/ salidas digitales para una aplicación de control Hemos optado por un diseño en el que se ofrece a la aplicación una funcionalidad de alto nivel Hemos corregido por software dos problemas detectados en el hardware: • posición de los displays de 7 segmentos • las variaciones en la línea que detecta el paso del radio de la rueda
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
Comentarios sobre el ejemplo (cont.)
131
UNIVERSIDAD DE CANTABRIA
Hemos usado mecanismos de sincronización: • un semáforo para controlar el uso exclusivo del driver por parte de las aplicaciones • variables atómicas para los contadores de distancia • un spinlock para el uso agrupado de los datos del driver Hemos usado mecanismos de temporización: • temporizador de control de botones • temporizador de control de la línea de interrupción • temporizador de presentación de datos
GRUPO DE COMPUTADORES Y TIEMPO REAL FACULTAD DE CIENCIAS
© Michael González, J. Javier Gutiérrez 19/ma/11
132