Sie sind auf Seite 1von 8

Universidade Federal do Rio Grande do Sul Escola de Engenharia Departamento de Engenharia Eltrica ENG04476 Microprocessadores II Roteiro de Laboratrio 9 Criao

de Nodos no /dev Prof. Walter Fetter Lages 29 de setembro de 2013 1 Objetivo


O objetivo deste laboratrio compreender os mecanismos criao dos nodos no diretrio /dev, que servem como ponto de acesso aos dispositivos de hardware pelos programas de usurio.

2 Fundamentao Terica
No Un*x os dispositivos so acessados pelos programas do usurio atravs de nodos, usualmente no diretrio /dev. Assim, as mesmas funes utilizadas para acessar arquivos podem ser utilizadas para acessar o hardware. A associao entre o nome do nodo e o driver do dispositivo feita atravs de dois nmeros denominados major e minor. Cada nodo que representa um dispositivo possui associado um major e um minor. Similarmente, cada driver possui associado um major. Assim, o major identica o tipo de dispositivo que o driver suporta, enquanto o minor identica, qual dos diversos dispositivos iguais suportados pelo mesmo driver est efetivamente sendo acessado. Por exemplo, as 3 impressoras conectadas em um PC so representadas pelos nodos /dev/lp0, /dev/lp1e /dev/lp2. Todos eles possuem o major 6, mas cada um possui um minor diferente, 0, 1 e 2, respectivamente. O driver que suporta as impressoras est associado ao major 6. Ao serem chamadas, as funes do driver recebem como parmetro o minor referente a qual impressora est sendo acessada.

2.1 Criao Manual dos Nodos


A forma original de criao dos nodos no diretrio /dev manualmente, atravs do comando: mknod [OPTION]... NAME TYPE [MAJOR MINOR] onde OPTION -m MODE ou --mode=MODE, sendo MODE as permisses de acesso ao nodo, NAME o nome do nodo, TYPE o tipo do nodo: b, para dispositivo de bloco, c ou u para dispositivo de caractere e p, para pipe. Por exemplo, o dispositivo para o mixer da placa de som seria criado com o comando mknod -m 0660 /dev/mixer c 14 0 No entanto, embora simples este mtodo no funciona bem com a maioria dos sistemas atuais. Atualmente, a maioria dos sistemas utiliza um sistema de arquivos temporrio, baseado em RAM para o /dev. Ou seja, cada vez que o computador reinicializado, o contedo do /dev perdido. O nodo teria que ser criado novamente cada vez que o sistema reinicializado.

2.2 Criao dos Nodos pelo udev


O udev um sistema para criar os nodos de dispositivos no /dev de forma automtica. Tambm permite que quando um nodo criado sejam criados links simblicos para ele, suas permisses sejam ajustadas e/ou que seja executado um programa. A operao do udev baseada em uma srie de regras, que especicam o que deve ocorrer quando um determinado driver carregado ou quando um determinado nodo criado. Os arquivos com essas regras so armazenados no diretrios /lib/udev/rules.d para as regras padro e /etc/udev/rules.d para as regras personalizadas. Est fora do escopo deste laboratrio entender toda a sintaxe das regras do udev. Sero apenas utilizadas algumas construes necessrias para criar nodos para os dispositivos. O udev funciona com o auxlio de um daemon denominado udevd, que monitora os eventos gerados pelo kernel e executa as regras apropriadas. 2.2.1 Nodos Estticos

Nodos estticos so copiados, ao ser iniciado o udevd, do diretrio /lib/ udev/devices para o diretrio /dev. Assim, a forma mais fcil de criar um nodo permanente em um sistema que utilize o udev criar um nodo em 2

/lib/udev/devices. No entanto, fazendo-se isto o nodo passar a existir permanentemente, o que no o mais adequado, na maioria dos casos. O ideal seria que o nodo de um dispositivo existisse no udev quando o dispositivo de hardware correspondente est conectado ao sistema e o seu driver carregado. Quando o dispositivo de hardware removido e seu driver descarregado, o ideal que o nodo correspondente no udev deixe de existir. Com isso evita-se a poluio do /dev com nodos que no podem ser utilizados. Assim, nodos estticos devem ser utilizados apenas para os nodos de dispositivos que no possuem evento do kernel associado e que portanto no podem ser carregados dinamicamente pelo udev, ou para dispositivos que precissam ser acessados antes do udevd ser executado. 2.2.2 Criao do Nodo por Script na Carga do Mdulo

O udev pode ser congurado para executar um programa quando ocorre um determinado evento do kernel. Tipicamente, este evento a insero ou remoo de algum mdulo do kernel. Pode-se utilizar as regras do udev para selecionar o nome do nodo a ser criado em funo do nome do mdulo carregado, dos identicadores do do dispositivo associado no barramento PCI ou USB, do MAC address de um dispositivo de rede e de uma srie de outras propriedades. Aqui ser utilizado apenas o nome do mdulo do kernel, j que o dispositivo a ser utilizado no possui nenhuma outra propriedade especial que possa ser detectada. O arquivo com a regra para o udev deve possuir a extenso .rules e como os arquivos de regras so processados em ordem alfabtica, conveno iniciar o nome com um nmero de 2 dgitos, de forma a forar a ordem de processamento dos arquivos, j que uma regra pode atuar a partir do resultado de outra. Um mesmo arquivo pode conter vrias regras. No caso do dispositivo utilizado neste laboratrio, a regra ser includa no arquivo /etc/udev/rules.d/99-eng04476.rules, e tem a forma mostrada na listagem 1. Listagem 1: Arquivo de regras para o udev. KERNEL=="led", RUN+="/etc/udev/led.sh %k 42 0666" O funcionamento da regra tal que se todas as chaves forem satisfeitas, a regra aplicada. No caso, a chave KERNEL deve ser igual ao nome do mdulo do kernel para que a regra seja aplicada. Ao ser aplicada a regra adiciona um programa (na verdade um script) chave RUN, que especica um programa para ser executado para o evento detectado. Se no for fornecido o path absoluto, 3

assumido que o programa est em /lib/udev. No exemplo, so passados trs parmetros para o programa, %k, que substitudo pelo valor da chave KERNEL, 42 que o major do nodo a ser criado e 0666, que o modo do nodo a ser criado. Alm desses parmetros tambm passada a varivel de ambiente ACTION com o tipo do evento que foi gerado, normalmente "add", quando o nodo deve ser criado ou "remove", quando o nodo deve ser removido. O script utilizado para criar os nodos mostrado na listagem 2. Note que o script cria quatro nodos ao ser carregado o mdulo, porque este o nmero de dispositivos de hardware suportados pelo driver implementado no mdulo. Listagem 2: Script para ser utilizado com o udev.
#!/bin/bash # KERNEL=$1 MAJOR=$2 MODE=$3 case "${ACTION}" in "add") for MINOR in {0..3} ; do mknod -m $MODE /dev/$KERNEL$MINOR c $MAJOR $MINOR done; ;; "remove") for MINOR in {0..3} ; do rm -f /dev/$KERNEL$MINOR done; esac

3 Criao do Nodo pelo Prprio Driver


Outra forma, mais simples e prtica para criar os nodos no /dev fazer com que o prprio mdulo que implementa o driver para o dispositivo crie o nodo ao ser carregado e remova-o ao ser descarregado. Com isso, evita-se a necessidade de ter um script para fazer isso e eventuais inconsistncias entre os valores de major e minor utilizados pelo driver e pelo script. Verses mais recentes do kernel podem alocar major dinamicamente, de forma que no mais necessrio alocar explicitamente um major para cada dispositivo. Por outro lado, complica as coisas para a criao dos nodos de dispositivos, pois o major no ser sempre o mesmo. A criao do nodo pelo prprio driver resolve este problema. Para que o kernel aloque dinamicamente um major para o driver basta passar 0 no parmetro correspondente o major na chamada funo register_chrdev(), que retornar o major alocado. 4

Antes de criar um nodo para o dispositivo atravs do driver conveniente criar uma classe para o dispositivo (ou utilizar uma classe j existente). Esta classe ir gerar uma entrada no diretrio /sys/class onde sero armazenadas as informaes dos dispositivos criados. O nome desta classe tambm pode ser utilizado nas regras do udev atravs da chave SUBSYSTEM. A classe criada com a macro: #include <linux/device.h> class_create(owner,name) onde owner tipicamente a constante THIS_MODULE. A macro retorna um ponteiro para uma struct class, que utilizada para criar os nodos para os dispositivos. Tendo-se a classe, pode-se criar os nodos para os dispositivos com a funo: #include <linux/device.h> struct device *device_create(struct class *cls, struct device *parent, dev_t devt,void *drvdata, const char *fmt, ...); onde cls o ponteiro para a classe, parent o ponteiro para dispositivo pai, se houver algum, devt o descritor do dispositivo, criado a partir da macro MADEV(major,minor), drvdata um ponteiro para dados privados do dispositivo, e fmt uma string, no formato utilizado pela funo printf() com o nome do nodo a ser criado. Os parmetros adicionais dependem do formato especicado em fmt. Quando no foram mais necessrios os nodos dos dispositivos e a classe devem ser removidos com as funes: #include <linux/device.h> void device_destroy(struct class *cls, dev_t devt); void class_destroy(struct class *cls); A listagem 3 mostra um mdulo que implementa um driver que cria seus prprios nodos para os dispositivos suportados.

Listagem 3: Mdulo com driver que cria os prprios nodos para os dispositivos suportados.
#include #include #include #include #include #include <linux/module.h> <linux/version.h> <asm/io.h> <asm/uaccess.h> <linux/fs.h> <linux/device.h>

#define MCR 4 #define DEVICE_NAME "led" #define CLASS_NAME "eng04476" static int major=0; /* kernel allocated */ static struct class *ledclass=NULL; static unsigned int baseadd[4]={0x3f8,0x2f8,0x3e8,0x2e8}; static unsigned int count; MODULE_AUTHOR("Walter Fetter Lages <w.fetter@ieee.org>"); MODULE_DESCRIPTION("LED Driver"); MODULE_SUPPORTED_DEVICE(DEVICE_NAME); MODULE_LICENSE("GPL"); module_param(major,int,0); MODULE_PARM_DESC(major,"major number for the driver; default is kernel allocated"); module_param_array(baseadd,uint,&count,0); MODULE_PARM_DESC(baseadd,"port [, port [, port [, port] ] ] base address"); static ssize_t led_write(struct file *file,const char *buf, size_t count,loff_t *ppos) { int base; unsigned char data; int error; if(count != sizeof(unsigned char)) return -EINVAL; base=baseadd[MINOR(file->f_dentry->d_inode->i_rdev)]; if( (error=get_user(data,buf)) ) return error; outb(data,base+MCR); return sizeof(unsigned char); } static int led_open(struct inode *inode,struct file *file) { int base; base=baseadd[MINOR(file->f_dentry->d_inode->i_rdev)]; outb(0,base+MCR); return 0; } static int led_release(struct inode *inode,struct file *file) { int base; base=baseadd[MINOR(file->f_dentry->d_inode->i_rdev)]; outb(0,base+MCR); return 0;

} static struct file_operations led_fops= { .owner=THIS_MODULE, .write=led_write, .open=led_open, .release=led_release }; int init_module(void) { int minor; dev_t ledno; if((major=register_chrdev(major,DEVICE_NAME,&led_fops))==-1) { printk("major %d cant be registered.\n",major); return -EIO; } ledclass=class_create(THIS_MODULE,CLASS_NAME); for(minor=0;minor < 4;minor++) { ledno=MKDEV(major,minor); device_create(ledclass,NULL,ledno,NULL,DEVICE_NAME "%d",minor); } return 0; } void cleanup_module(void) { int minor; dev_t ledno; for(minor=0;minor < 4;minor++) { ledno=MKDEV(major,minor); device_destroy(ledclass,ledno); } if(ledclass != NULL) class_destroy(ledclass); unregister_chrdev(major,DEVICE_NAME); }

Note que mesmo com o driver criando os prprios nodos para os dispositivos, ainda necessrio utilizar o udev para congurar as permisses de acesso, proprietrio e grupo do nodo criado, e talvez criar links simblicos para ele. A listagem 4 mostra uma regra do udev tpica para estes casos. Listagem 4: Arquivo de regras para o udev, sendo os nodos criados pelo prprio driver. SUBSYSTEM=="eng04476", KERNEL=="led[0-3]", MODE="0666"

4 Experimento
Neste laboratrio ser utilizado o driver desenvolvido no laboratrio anterior para acionar um LED conectado no sinal RTS de uma porta serial e ler um interruptor conectado entre os sinais DTR e DSR, alm do driver mostrado na listagem 3. 1. Verique os nodos estticos criados no sistema em /lib/udev/devices. 2. Inicialmente ser utilizado o mesmo driver desenvolvido no laboratrio anterior, cujos nodos para dispositivo so criados pelo mtodo do script. O script j est instalado nas mquinas do laboratrio. Para que ele funcione, o nome do arquivo do mdulo deve ser led.c. Caso contrrio, as regras do udev no iro reconhecer que o driver foi carregado. 3. Compile o mdulo do laboratrio passado com o nome apropriado. 4. Verique no diretrio /etc/udev/rules.d as regras apropriadas para o mdulo em questo. Verique tambm o script utilizado pela regra. 5. Em outro terminal, execute o programa $ /sbin/udevadm monitor --property para car monitorando os eventos gerados para o udev. 6. Carregue o mdulo e verique se os nodos para os dispositivos foram criados. 7. Verique os eventos gerados. 8. Descarregue o mdulo e verique os eventos gerados. 9. Compile o mdulo da listagem 3. 10. Carregue o mdulo e verique se os nodos para os dispositivos foram criados 11. Verique a classe criada no diretrio /sys/class. 12. Verique os eventos gerados. 13. Remova o mdulo e verique os eventos gerados. 14. Tente explicar o funcionamento da regra mostrada na listagem 4.

Das könnte Ihnen auch gefallen