Aula 7 - Criando um Device Driver
Este tutorial descreve a criação de um device drive básico
Comando Úteis
- modprobe argumento - Carrega o módulo do kernel do Linux, verificando suas dependências.
- modinfo argumento - Fornece informações sobre o módulo.
- insmod argumento - Carrega o módulo no kernel do Linux.
- rmmod argumento - Remove o módulo no Kernel do Linux.
Informações
No diretório /dev está contido arquivos de dispositivos, arquivos especiais e simples nós para a arvore do sistema de arquivo.
Identificação:
- Major number: identifica o driver associado com o dispositivo, especificando o tipo de dispositvo.
- Minor number: identifica o dispositivo a ele referenciado.
Data Structures Importantes
- File Operations: o file_operations structure é o meio em que o dispositivo "char" estabelece um conexão. Cada campo do file_operations structure implementa específicas funções para manipulação do dispositivo. Cabendo desenvolvedor estabelecer links esntre as funções do file_operation structure e o código. Ex:
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
#retirada nas versão mais novas do kernel
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
- File Structure: representa abrir um arquivo(open file), ele é criado pelo kernel na abertura sendo passado para qualquer função que opera no arquivo até o último fechamento.
- Inode Structure: é usada internamente pelo kernel para representar arquivos.
Código Exemplo
Quando for programar código para o kernel (módulos, drivers, etc), a Standily Liby C não é usada, por padrão, a implementação tem que usar as funções do próprio kernel.
/*
* "Hello, world!"
*/
/*
* Alguns headers necessário para o Device Driver
*/
#include <linux/init.h>
#include <linux/module.h>
/*
* A função init() é a primeira função executada quando o módulo
* é carregado. Ele executará somente uma vez quando o módulo
* é carregado
*/
static int __init
hello_init(void)
{
printk("Hello, world!\n");
return 0;
}
/*
* A função macro do Kernel
*/
module_init(hello_init);
/*
* Similar a init(), essa função é chamada quando queremos
* descarregar o módulo no kernel
*/
static void __exit
hello_exit(void)
{
printk("Goodbye, world!\n");
}
module_exit(hello_exit);
/*
* Algumas informações para o módulo
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jack Beagle <http://embarcadosunifor.blogspot.com.br>");
MODULE_DESCRIPTION("\"Hello, world!\" modulo mínimo");
MODULE_VERSION("printk");
* "Hello, world!"
*/
/*
* Alguns headers necessário para o Device Driver
*/
#include <linux/init.h>
#include <linux/module.h>
/*
* A função init() é a primeira função executada quando o módulo
* é carregado. Ele executará somente uma vez quando o módulo
* é carregado
*/
static int __init
hello_init(void)
{
printk("Hello, world!\n");
return 0;
}
/*
* A função macro do Kernel
*/
module_init(hello_init);
/*
* Similar a init(), essa função é chamada quando queremos
* descarregar o módulo no kernel
*/
static void __exit
hello_exit(void)
{
printk("Goodbye, world!\n");
}
module_exit(hello_exit);
/*
* Algumas informações para o módulo
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jack Beagle <http://embarcadosunifor.blogspot.com.br>");
MODULE_DESCRIPTION("\"Hello, world!\" modulo mínimo");
MODULE_VERSION("printk");
Makefile
Abaixo o exemplo de um makefile, para geração de um modulo para o Hello Word.
# obj-m é uma lista para os modulodos do kernel para build.
# O .o e outros objetos serão automaticamente gerados
obj-m := hello.o
# KDIR é a localização dos arquivos do kernel que
# serão utlizados para da build
KDIR := /lib/modules/$(shell uname -r)/build
# PWD é o diretório atual e da localização do nosso
# módulo.
PWD := $(shell pwd)
# Faz a linkagem de nosso modulo e o arquivos do kernel para
# compilar e gerar os arquivos necessários..
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
# O .o e outros objetos serão automaticamente gerados
obj-m := hello.o
# KDIR é a localização dos arquivos do kernel que
# serão utlizados para da build
KDIR := /lib/modules/$(shell uname -r)/build
# PWD é o diretório atual e da localização do nosso
# módulo.
PWD := $(shell pwd)
# Faz a linkagem de nosso modulo e o arquivos do kernel para
# compilar e gerar os arquivos necessários..
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
Carregando o módulo
Entre no diretório do projeto:
- make
Para carrega o módulo:
Verificar:
- sudo insmod ./hello.ko
- dmesg | tail
Remover módulo:
- sudo rmmod hello
Verificar:
- dmesg | tail
Debugando
- Printk: Fornece mensagens de acordo com o logleves das mensagens
printk (KERN_DEBUG "Erro:% s:% i \ n", __ FILE__, __ line_ & _);
printk (KERN_CRIT "Erro Grave % p \ n", ptr);
Há oito possíveis seqüências de LogLevel definidos no <linux/kernel.h> :
KERN_EMERG
Usado para mensagens de emergência, geralmente aqueles que precedem um acidente.
KERN_ALERT
Uma situação que requer ação imediata.
KERN_CRIT
Condições críticas, muitas vezes relacionados com graves falhas de hardware ou software.
KERN_ERR
Usado para relatar condições de erro; drivers de dispositivos, muitas vezes, usar KERN_ERR relatar dificuldades de hardware.
KERN_WARNING
Avisos sobre situações problemáticas que não, em si mesmos, criar sérios problemas com o sistema.
KERN_NOTICE
Situações que são normais, mas ainda digno de nota. Uma série de condições relacionadas à segurança são relatados a este nível.
KERN_INFO
Mensagens informativas. Muitos motoristas imprimir informações sobre o hardware que encontram no momento da inicialização, a este nível.
Nenhum comentário:
Postar um comentário