Está en la página 1de 40

Linux Devices Drivers

Gua para desarrollo de Device


Drivers en Linux

Autor: Alejandro Furfaro

Introduccin

Conceptos bsicos

Autor: Alejandro Furfaro

We're back to the times when men where men and


wrote their own device drivers...

Device Drivers

Linus Torvalds

Es cdigo que se ejecuta en modo Kernel.

Es la mediacin entre los dispositivos de hardware y los procesos del sistema o


de usuario.

Se ocupa de resolver el mecanismo de acceso al hardware

No se concentra en la poltica de manejo de la informacin, aspecto que queda


para el software de usuario. Ej: Driver de disco -> acceso al disco. File Systema
Manager -> Formatea los datos para el usuario (poltica de manejo de
informacin)

Linux puede incluirlo:

En el kernel monoltico en forma esttica.

Es mas compacto

Requiere re linkear el kernel completo cada vez que lo vamos a instalar

Forget it!!

Como mdulos run-time linkeables

Mucho mas flexible.

La estructura modular, es lo que se utiliza desde hace ya suficiente tiempo como para
considerarse
Autor: Alejandro
Furfaro el modo standard de trabajar.

Clasificacin de Dispositivos en Linux

Char Devices

Block Devices

Network Devices

Miscellaneous (Bus) Devices

Autor: Alejandro Furfaro

Char Devices

Son los mas simples.


Se acceden como un stream de bytes, tal como si fuesen
nodos del File System. Ej.: TTY's (/dev/console). Serial
ports (/dev/ttyS0).
A diferencia de los archivos comunes, no nos podemos
desplazar hacia atrs y hacia adelante. Acceden a los datos
en forma secuencial.
Registran sus prestaciones a travs de objetos del FS que
responden a las funciones standard de acceso a archivos:

open ( ),
read ( ),
write ( ),
close ( ), etc.

Autor: Alejandro Furfaro

Block Devices

Los block devices agregan complejidad a su interfaz.


Al igual que los char devices, se mapean como Nodos del
File System en el directorio /dev.
Registran sus prestaciones en un array del tipo blk_dev, y
dems estructuras del kernel.
La diferencia pasa por como el kernel maneja internamente
los datos. Por lo regular es de a bloques (512 o 1024 bytes)
Transmiten o reciben bloques de bytes a demanda del
kernel mediante la funcin request. Algo diferente de la
simple interfaz de los char devices.
Son dispositivos que pueden hostear un File System. Ej.:
Discos, Cintas.
Autor: Alejandro Furfaro

Network Devices

Los network devices parecen ser iguales a los


block devices. Pero solo en apariencia

Controlan las interfaces durante las transacciones


de paquetes de datos en red contra un equipo
remoto, pero sin conocer en detalle la composicin
de las transacciones que conforman esos
paquetes.

No siempre se relacionan con dispositivos de


hardware (loopback por ejemplo).

No constituyen dispositivos orientados a stream,


por lo cual, no son fcilmente mapeables en el /dev
7

Autor: Alejandro Furfaro

Dispositivos Miscelneos

En general esta categora agrupa a cualquier


dispositivo o subsistema cuyas caractersticas le
impiden clasificar en alguna de las tres categoras
anteriores.

Algunos autores clasifican en esta categora


especial, a los drivers de los controladores de
buses, ya que son bastante particulares.
PCI
USB
SCSI

Autor: Alejandro Furfaro

Device Drivers: Insercin en el kernel

Autor: Alejandro Furfaro

Relacin con el kernel

Alcance
Kernel

2.4. Aun podemos encontrar estas distros


Kernel 2.6.

Aclararemos las diferencias en donde existan para


salvar los usos en una y otra versin
Causa de las diferencias: Linux Kernel Device
Model, implementado justamente en la versin 2.6

Unificacin

de todos los modelos de driver dispersos


hasta la versin 2.4 del kernel.
Pensado mas para los drivers especficos de buses para
bridges y dispositivos, consolidando un sistema de datos
y de operaciones en estructuras de datos globalmente
accesibles.
10

Autor: Alejandro Furfaro

Linux Device Model

Kernel 2.6.x
Hacia un modelo unificado de dispositivos

Autor: Alejandro Furfaro

11

Kernel 2.6: Linux Device Model

Hasta el kernel 2.6, el Device Model consista simplemente de una


coleccin de estructuras no relacionadas del tipo rbol de dispositivos (y
en ocasiones simplemente listas).

Para agrupar a estos modelos dispersos se recurre a una estructura de


datos comn que pueda relacionarlos con poco overhead, en un Modelo
nico y abarcativo.

Los campos de datos comunes migran del antiguo modelo de bus local a un
modelo global de dispositivos.

Se estandarizan algunas funciones de manipulacin de estos campos.

Las funciones de manipulacin se convierten en un sistema de funciones


auxiliares.

Los drivers de bus las utilizarn para incluir cualquier tem especfico del bus.

Cuando un driver de bus descubre un dispositivo particular, lo inserta en el


rbol global de dispositivos y en su rbol local de dispositivos.

El rbol local del bus no es mas que un subconjunto del rbol global.

Autor: Alejandro Furfaro

12

Kernel 2.6: Linux Device Model

Interfaces existentes entre el bridge y los dispositivos de E/S de una PC actual:

Capacidad plug and play,

Manejo de la energa,

Soporte hot plug.

Los buses modernos (USB, PCI-X, PCMCIA) soportan la mayora de estas


operaciones. Sus drivers en la estructura anterior no eran de fcil insercin.

En el futuro un bus que no soporte una operacin de este tipo ser la excepcin.
De modo que se requiere una reingeniera del modelo de drivers!.

La Especificacin ACPI (Advanced Configuration and Power Interface) de Intel,


Hewlett Packard, Microsoft, fija los requisitos para que un dispositivo se adapte a
cualquiera de los criterios anteriormente enumerados.

Describe estructuras y mecanismos necesarios para disear motherboards cuyas


funcionalidades de power management y configuracin avanzada puedan ser
gestionadas por los sistemas operativos.

Aplica a toda clase de computadoras.

Autor: Alejandro Furfaro

13

Kernel 2.6: Linux Device Model


Lleva
Llevala
lacuenta
cuentade
de
que
hay
conectado
que hay conectado
aacada
cadabus.
bus.
Estructura
Estructura
bus_type
bus_type

Muestra
Muestrala
laforma
forma
en
que
un
en que un
dispositivo
dispositivoest
est
conectado
al
conectado al
sistema.
sistema.
Estructura
Estructuradevice
device
Registra
Registrala
lafuncin
funcin
que
provee
que proveeel
el
dispositivo,
dispositivo,
independientemente
independientemente
de
dedonde
dondeest
est
conectado
conectado
Estructura
Estructura
device_class
device_class

Tres objetos bsicos:


Bus

Device
Class
Autor: Alejandro Furfaro

14

/sys : La Interfaz con el usuario

El Linux Driver Model se pone visible a travs de un file


system ram based: sysfs.
Se define en /etc/fstab mediante la lnea siguiente:
none

/sys

sysfs

defaults

El tope de sysfs contiene las siguiente entradas

block/
bus/
|--/devices (es un link al nodo devices del tope)
--/drivers (contiene un directorio por cada driver que se registra
en el sistema)

class/
devices/
firmware/
net/

Autor: Alejandro Furfaro

15

Conceptos de programacin de
drivers

El Howto?

Autor: Alejandro Furfaro

16

Programacin de Mdulos

Escribir un device driver, es escribir cdigo de


kernel

En modo kernel se dispone de un tipo especial de


programa denominado Mdulo (kernel module)

Una aplicacin convencional realiza una tarea


nica del principio hasta el fin.

Un mdulo, en cambio, se registra a si mismo a fin


de prestar servicios a futuro. Su funcin principal
es efmera, pero queda instalado en el sistema.

Autor: Alejandro Furfaro

17

Programacin de Mdulos
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hola, mundo!\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT Adis, Mundo cruel!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Autor: Alejandro Furfaro

18

Programacin de Mdulos

y la funcin main??????
No usa. entonces?......
insmod y rmmod, se utilizan para manejar nuestro mdulo. insmod lo
instala, y quedar disponible hasta que se ejecute rmmod
insmod hace que se ejecute la funcin module_init ( )
Hace las veces de funcin main del mdulo
rmmod hace que se ejecute la funcin module_exit ( )
Hacen las veces de funciones constructora y destructora.

Autor: Alejandro Furfaro

19

Enlace de un mdulo al kernel 2.6

Autor: Alejandro Furfaro

20

Device Drivers: Recursos

El kernel de LINUX es concurrente, por lo tanto un driver


debe estar escrito con la idea que en un mismo instante
ocurren varias cosas. Debe ser re entrante.

Desde el kernel no tenemos los recursos que usamos en las


aplicaciones:

No se accede a las system call standard

No estn disponibles los IPCs!!!!

Ejemplo. Para averiguar el proceso que invoc alguna de


las funciones el driver, vamos a task_struct.....
printk("The process is \"%s\" (pid %i)\n", current->comm, current->pid);

Autor: Alejandro Furfaro

21

Char devices

Deben existir como file system node en /dev


Se crean con un comando especial:
mknod <nombre> <type> <Mn> <mn>

Numero mayor y menor.


crw-rw-rwcrw------crw------crw-rw-rwcrw-rw-rwcrw------crw------crw-rw-rw-

1
1
1
1
1
1
1
1

root
root
rubini
root
root
root
root
root

root
root
tty
dialout
dialout
sys
sys
root

1,
10,
4,
4,
4,
7,
7,
1,

3
1
1
64
65
1
129
5

Feb
Feb
Aug
Jun
Aug
Feb
Feb
Feb

23
23
16
30
16
23
23
23

1999
1999
22:22
11:19
00:00
1999
1999
1999

null
psaux
tty1
ttyS0
ttyS1
vcs1
vcsa1
zero

El kernel usa el Major number para despachar la ejecucin


del driver correcto en el momento en que se ejecuta la
funcin open () desde el proceso que lo desea acceder.
El Minor number es usado por el driver. El kernel solo lo
pasa al driver para que este lo utilice si lo necesita.
Autor: Alejandro Furfaro

22

Representacin del nmero de device

El kernel usa un tipo definido en linux/types.h, como dev_t.

32 bits: 12 para el major number y 20 para el minor number

Para desentendernos de esta estructura (todo evoluciona y


cambia) hay dos macros en linux/kdev_t.h.

Conociendo el nmero de device (dev_t), obtenemos major y minor


MAJOR(dev_t dev);
MINOR(dev_t dev);

Conociendo major y minor obtenemos el nmero de device


MKDEV(int major, int minor);

Autor: Alejandro Furfaro

23

Mas novedades del kernel 2.6

Funciones para reservar el major number, de modo


de evitar conflictos y recompilaciones

Definidas en <linux/fs.h>:
Reserva

un rango de major numbers

int register_chrdev_region (dev_t first, unsigned int


count, char *name);
Si

conocemos exactamente el major number a utilizar

int alloc_chrdev_region(dev_t *dev, unsigned int


firstminor, unsigned int count, char *name);
Devuelve

los major numbers reservados de una u otra

forma
void unregister_chrdev_region(dev_t first, unsigned int
count);
Autor: Alejandro Furfaro

24

/proc
File System RAM based en el que hay mucha info. En
particular para drivers:
Character devices:
Block devices:
1 mem
2 fd
2 pty
8 sd
3 ttyp
11 sr
4 ttyS
65 sd
6 lp
66 sd
7 vcs
10 misc
13 input
14 sound
21 sg
180 usb
Autor: Alejandro Furfaro

25

Script para ejecutar la instalacin


#!/bin/sh
module=midriver"
device=midriver"
mode="664"
# invoca insmod con todos los argumentos
# usa pathname (las modutils nuevas no miran en . por default)
/sbin/insmod ./$module.ko $* || exit 1
# remueve nodos viejos
rm -f /dev/${device}[0-3]
major=$(awk "\\$2= =\"$module\" {print \\$1}" /proc/devices)
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
# give appropriate group/permissions, and change the group.
# Not all distributions have staff, some have "wheel" instead.
group="staff"
grep -q '^staff:' /etc/group || group="wheel"
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
Autor: Alejandro Furfaro

26

Manejo del major number


if (midriver_major)
{
dev = MKDEV(midriver_major, midriver_minor);
result = register_chrdev_region(dev,
midriver_nr_devs, midriver");
}
else
{
result = alloc_chrdev_region(&dev,
midriver_minor, midriver_nr_devs,
"midriver");
midriver_major = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "midriver: can't get
major d\n", midriver_major);
return result;
}

Autor: Alejandro Furfaro

27

Char Devices:
Esquema de llamadas al sistema
Memoria

User Mode
open()
write()
close()

Kernel
File_op
s
Dev_open
()
Dev_write
()

Device
outb()
Ports

Dev_close
()
Autor: Alejandro Furfaro

28

Char Devices: File Operations (1)


struct module *owner

Es el primer campo de file_operations


No es en s mismo una operacin
Es un puntero al mdulo dueo de la estructura.
Se usa para evitar que el mdulo sea cargado mientras sus operaciones
estn en uso.
A menudo se lo inicializa sencillamente con la macro THIS_MODULE,
definida en <linux/module.h>.

loff_t (*llseek) (struct file *, loff_t, int);


El mtodo llseek se usa para cambiar la posicin actual de lectura/ escritura
en un archivo
La nueva posicin se retorna como un valor positivo
loff_t es un long offset y tiene al menos un ancho de 64 bits an en
plataformas de 32-bit.
Si se produce algn error en su ejecucin retorna un valor negativo
Si este puntero se inicializa en NULL en file_operations, seek () modificar
el contador de posicin en la estructura file (de formas potencialmente
impredecibles).
29
Autor: Alejandro Furfaro

Char Devices: File Operations (2)


ssize_t (*read) (struct file *, char __user *, size_t,
loff_t *);
Lee datos desde un archivo o device.
Un puntero NULL en esta posicin hace que la system call read () sobre este
device devuelva -EINVAL (Invalid argument).
Un valor de retorno no negativo representa el nmero de bytes ledos

ssize_t (*aio_read)(struct kiocb *, char __user *,


size_t, loff_t);
Inicia una lectura asincrnica (puede no completarse antes de retornar).
Si es NULL, todas las operaciones sern ejecutadas en forma sincrnica por
read ().

ssize_t (*write) (struct file *, const char __user *,


size_t, loff_t *);
Enva datos a un archivo o device.
Si este puntero es NULL, la system call write () retorna -EINVAL al programa
que la invoca
Un valor de retorno, no negativo, es el nmero de bytes escritos.
Autor: Alejandro Furfaro

30

Char Devices: File Operations (3)


ssize_t (*aio_write)(struct kiocb *, const char __user *,
size_t, loff_t *);
Inicia una operacin de escritura asincrnica sobre el device.

int (*readdir) (struct file *, void *, filldir_t);


Se usa para leer directorios. Solo lo usan los file systems. Debe ser NULL
para cualquier device.

unsigned int (*poll) (struct file *, struct


poll_table_struct *);
El mtodo poll es el back end de tres system calls: poll (), epoll (), y select ().
Se usa para saber si un read () o un write () a uno o mas descriptores de
archivo va a bloquear.
El mtodo poll () debe retornar una mscara de bits que indica si son factibles
lecturas o escrituras no bloqueantes.
El kernel con esta informacin pone un proceso en estado sleeping hasta que
sea posible la operacin de E/S.
Si un driver deja NULL este mtodo, se asume que puede ser ledo o escrito
sin bloqueo.
Autor: Alejandro Furfaro

31

Char Devices: File Operations (4)


int (*ioctl) (struct inode *, struct file *, unsigned
int, unsigned long);
La system call ioctl () enva comandos device especficos.
El kernel generalmente procesa ioctl () por medio del mtodo definido en
file_operations.
Si no hay un method ioctl (), la system call retorna error para cualquier
requerimiento no predefinido (-ENOTTY, No such ioctl for device).

int (*mmap) (struct file *, struct vm_area_struct *);


mmap requiere el mapeo de un device de memoria al espacio de direcciones
del proceso.
Si este mtodo es NULL, la system call mmap () retorna -ENODEV.

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


Como SIEMPRE es la primer operacin realizada sobre el archivo o device,
no es necesario declararlo
Si es NULL, el device siempre se abre, pero no se notifica al driver.

Autor: Alejandro Furfaro

32

Char Devices: File Operations (5)


int (*flush) (struct file *);
La operacin flush () se invoca cuando un proceso cierra su copia del file
descriptor de un device
Ejecuta (y espera por) cualquier operacin excepcional sobre el device.
No confundir con la operacin fsync () requerida por un programa.
flush () se usa en muy pocos drivers: el driver SCSI de cinta lo use, por
ejemplo, para asegurar que todos los datos escritos estn en la cinta antes de
cerrar el dispositivo
Si es NULL, el kernel simplemente ignora el requerimiento.

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


Se invoca cuando se desea liberar la estructura.
Igual que open () puede ser NULL.
release () no se invoca cada vez que un proceso llama a close (). Si una
estructura file se comparte (como resultado de fork () o dup() ), release () se
invoca cuando todas las copias ejecutan close ().

Autor: Alejandro Furfaro

33

Char Devices: File Operations (6)


int (*fsync) (struct file *, struct dentry *, int);
Es el back end de la system call fsync (), que es llamada por un programa
para flushear cualquier dato pendiente. Si es NULL, retorna -EINVAL.

int (*aio_fsync)(struct kiocb *, int);


Es la versin asincrnica del mtodo fsync.

int (*fasync) (int, struct file *, int);


Se usa para notificar al device que cambi su flag FASYNC.
Puede ser NULL si el driver no soporta notificacin asincrnica.

int (*lock) (struct file *, int, struct file_lock *);


Se usa para implementar file locking.
Es indispensable en archivos, pero rara vez se usa en drivers.

Autor: Alejandro Furfaro

34

Char Devices: File Operations (7)


ssize_t (*readv) (struct file *, const struct iovec *,
unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *,
unsigned long, loff_t *);
Implementan operaciones de lectura escritura fragmentada, que
ocasionalmente necesitan involucrar mltiples reas de memoria
Estas system calls fuerzan operaciones extra de copia sobre los datos.
Si estos punteros se dejan NULL, se llaman en su lugar los mtodos read () y
write () (quiz mas de una vez).

ssize_t (*sendfile)(struct file *, loff_t *, size_t,


read_actor_t, void *);
Implementa el lado read de la system call sendfile (), que mueve los datos
desde un file descriptor hacia otro con mnima copia
Se usa por ejemplo en un web server que necesita enviar los contenidos de
un archivo fuera hacia la red.
Los device drivers normalmente la dejan en NULL.
Autor: Alejandro Furfaro

35

Char Devices: File Operations (8)


ssize_t (*sendpage) (struct file *, struct page *, int,
size_t, loff_t *, int);
sendpage es la otra mitad de sendfile;
El kernel la llama para enviar datos al archivo correspondiente, una pgina a la
vez.
Los device drivers normalmente no implementan sendpage.

unsigned long (*get_unmapped_area) (struct file *,


unsigned long, unsigned long, unsigned long, unsigned
long);
El objetivo de este mtodo es encontrar una ubicacin adecuada en el espacio
de direcciones del proceso para mapearla sobre un segmento de memoria del
device.
Normalmente es el cdigo de manejo de la memoria quien realiza esta tarea
Este mtodo permite a los drivers forzar los requerimientos de alineamiento
que pueda tener cualquier device. La mayora de los drivers dejan este
mtodo NULL.
Autor: Alejandro Furfaro

36

Char Devices: File Operations (9)


int (*check_flags)(int)
Permite al mdulo chequear los flags que se le pasan en una llamada fcntl
(F_SETFL...).

int (*dir_notify)(struct file *, unsigned long);


Se invoca cuando una aplicacin usa fcntl () para pedir modificaciones en un
directorio.
Slo es til en file systems
Los drivers no necesitan implementar dir_notify.

Autor: Alejandro Furfaro

37

Char Devices: File Operations (10)


Es la estructura principal para mapear el sistema de system calls del
sistema operativo sobre el hardware
Declaradas en <linux/fs.h>
struct file_operations
struct file_operations
midriver_fops = {
midriver_fops =
NULL,
//lseek
{
midriver_read,
.owner = THIS_MODULE,
midriver_write,
.read = scull_read,
NULL,
//readdir
.write = scull_write,
NULL,
//poll
.ioctl = scull_ioctl,
midriver_ioctl,
.open = scull_open,
NULL,
//mmap
.release = scull_release,
midriver_open,
};
NULL,
//flush
midriver_release,
NULL,
//fsync
NULL,
//fasync
NULL,
//check_media_change
NULL,
//revalidate
NULL,
//lock
};
Autor: Alejandro Furfaro

38

Otras estructuras del sistema a


considerar: struc file

Definida en <linux/fs.h>
Contiene la informacin lgica de un archivo abierto con
open ().
Campos de inters para un char device

mode_t f_mode; //Modo en que se abri el archivo (FMODE_READ,


FMODE_WRITE)
loff_t f_pos; //Puntero de 64 bits offset dentro del archivo
unsigned int f_flags; //O_RDONLY, O_NONBLOCK, O_SYNC.
struct file_operations *f_op;
void *private_data;

open () la carga con NULL antes de llamar al mtodo open propio del
driver.
Se puede utilizar para guardar datos propios del driver

struct dentry *f_dentry;

Directory entry.
Normalmente no es necesario tenerla en cuenta, salvo si necesitan
acceder al inodo del directorio.

Autor: Alejandro Furfaro

39

Otras estructuras del sistema a


considerar: struct inode

Definida en <linux/fs.h>

Contiene la informacin de un nodo del file system (no de un


archivo abierto)

Campos de inters para un char device

dev_t i_rdev; //contiene el nmero de device (32 bits: 12 major number


20 minor number)

struct cdev *i_cdev; //es una estructura del LDM que representa a un
char device. Si el inodo no contiene un char device este campo es NULL.

Para obtener el major y el minor number a partir de inode


unsigned int iminor (struct inode *inode);
unsigned int imajor (struct inode *inode);

Autor: Alejandro Furfaro

40