Conceito de Drivers em Sistemas Embacrados
Em sistemas embarcados, um driver atua como uma ponte entre aplicações de espaço de usuário e hardwrae subjacente. Como aplicações executam em modo usuário, elas não possuem acesso direto ao hardware. Através de chamadas de sistema como open, read e write, a execução transita para o modo kernel, permitindo interação com dispositivos por meio de nós correspondentes e funções implementadas no driver.
Estrutura Básica de um Driver de Dispositivo de Carácter
Os passos fundamentais para desenvolver um driver são:
- Definir um número de dispositivo principal
- Implementar a estrutura
file_operationscom ponteiros para funções - Codificar as funções de operação do dispositivo
- Criar funções de inicialização e remoção do módulo
- Registrar a estrutura no kernel e criar entradas no sistema de aqruivos
- Utilizar macros para declarar funções de entrada e saída
- Incluir a licença GPL para compatibilidade com o kernel
Implementação do Driver
O desenvolvimento requer três arquivos principais:
- Arquivo do driver:
modulo_driver.c - Aplicação de teste:
teste_driver.c - Makefile para compilação
O código do driver inclui:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
static int major_num = 0;
static char buffer_kernel[1024];
static struct class *classe_dispositivo;
#define LIMITE_TAMANHO(a, b) ((a) < (b) ? (a) : (b))
static int abrir_dispositivo(struct inode *inode, struct file *arquivo) {
printk(KERN_INFO "Dispositivo aberto\n");
return 0;
}
static ssize_t ler_dispositivo(struct file *arquivo, char __user *buffer, size_t tamanho, loff_t *offset) {
int bytes_copiados;
bytes_copiados = copy_to_user(buffer, buffer_kernel, LIMITE_TAMANHO(1024, tamanho));
return bytes_copiados;
}
static ssize_t escrever_dispositivo(struct file *arquivo, const char __user *buffer, size_t tamanho, loff_t *offset) {
int bytes_copiados;
bytes_copiados = copy_from_user(buffer_kernel, buffer, LIMITE_TAMANHO(1024, tamanho));
return bytes_copiados;
}
static int liberar_dispositivo(struct inode *inode, struct file *arquivo) {
printk(KERN_INFO "Dispositivo liberado\n");
return 0;
}
static struct file_operations operacoes_arquivo = {
.owner = THIS_MODULE,
.open = abrir_dispositivo,
.read = ler_dispositivo,
.write = escrever_dispositivo,
.release = liberar_dispositivo,
};
static int __init iniciar_modulo(void) {
int resultado;
major_num = register_chrdev(0, "modulo_exemplo", &operacoes_arquivo);
classe_dispositivo = class_create(THIS_MODULE, "classe_modulo");
if (IS_ERR(classe_dispositivo)) {
unregister_chrdev(major_num, "modulo_exemplo");
return PTR_ERR(classe_dispositivo);
}
device_create(classe_dispositivo, NULL, MKDEV(major_num, 0), NULL, "modulo_exemplo");
return 0;
}
static void __exit remover_modulo(void) {
device_destroy(classe_dispositivo, MKDEV(major_num, 0));
class_destroy(classe_dispositivo);
unregister_chrdev(major_num, "modulo_exemplo");
}
module_init(iniciar_modulo);
module_exit(remover_modulo);
MODULE_LICENSE("GPL");
Aplicação de Exemplo para Teste
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
int descritor_arquivo;
char buffer[1024];
int bytes_lidos;
if (argc < 2) {
printf("Uso: %s -w <texto>\n", argv[0]);
printf(" %s -r\n", argv[0]);
return -1;
}
descritor_arquivo = open("/dev/modulo_exemplo", O_RDWR);
if (descritor_arquivo < 0) {
perror("Falha ao abrir dispositivo");
return -1;
}
if (strcmp(argv[1], "-w") == 0 && argc == 3) {
write(descritor_arquivo, argv[2], strlen(argv[2]) + 1);
} else {
bytes_lidos = read(descritor_arquivo, buffer, sizeof(buffer) - 1);
buffer[bytes_lidos] = '\0';
printf("Dados lidos: %s\n", buffer);
}
close(descritor_arquivo);
return 0;
}
Makefile para Compilação Cruzada
DIR_KERNEL = /caminho/para/kernel
all:
make -C $(DIR_KERNEL) M=$(shell pwd) modules
$(CROSS_COMPILE)gcc -o teste_driver teste_driver.c
clean:
make -C $(DIR_KERNEL) M=$(shell pwd) clean
rm -f teste_driver
obj-m += modulo_driver.o
Instalação e Teste do Driver
Após a compilação, transfira os arquivos modulo_driver.ko e teste_driver para o dispositivo alvo. Execute os comandos:
insmod modulo_driver.ko
./teste_driver -w "Texto de exemplo"
./teste_driver -r
rmmod modulo_driver