Introdução
Nesse terceiro texto da saga "introdução ao desenvolvimento de drivers para kernel linux" vou falar sobre atributos de classes. Os atributos de classes são arquivos criados no /sys/class/classe_do_driver
que serão usados como forma de interagir com o SO.
O que são atributos de classes
Os atributos de classe, como mencionado na introdução são uma forma de comunicação do SO com o driver. Quando estamos desenvolvendo um driver para algum dispositivo podemos precisar de algumas informações que o kernel pode nos fornecer.
A comunicação entre driver x Kernel é feita a partir de um arquivo que fica no /sys/class/classe_do_driver
, e o nome do arquivo é dado por nós mesmo na hora de declarar o atributo. Então, como no texto anterior criamos uma classe chamada 7segment o diretorio da classe fica declarado em /sys/class/7segment
. Como expliquei no texto anterior, essa classe 7segment
vamos usar futuramente para exibir um valor em um circuito simples com um display de 7 segmentos. Então, se precisarmos exibir algum número no display, podemos pegar o numero que esta declarado no atributo de classe da classe 7segment
. Então, criaremos um atributo de classe para a classe 7segment
e leremos esse atributo com o número para exibir no display.
Gostaria de salientar, que nesse texto somente faleremos e implementaremos os códigos relacionados ao atributo de classe, e a implementação da comunicação com o display ficará para os próximos textos.
Ficará mais claro com a implementação prática do código.
Caso tenha caído de paraquedas nesse texto, aqui esta o link com os códigos e links dessa serie.
Mãos no código
Para começar vamos criar os arquivos básicos, um attribute.c
com a classe ja criada, assim como ensinamos no texto anterior, um attribute.h
e um Makefile:
attribute.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "attribute.h"
MODULE_AUTHOR("SEU NOME <seu_email@email.com>");
MODULE_DESCRIPTION("Classes de dispositivos");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");
static int __init class_init(void)
{
device_class = (struct class *) kzalloc(sizeof(struct class), GFP_ATOMIC);
if(!device_class)
pr_err("ERRO NA ALOCACAO DA CLASSE");
device_class->name = "7segment";
class_register(device_class);
pr_info("class registrada");
return 0;
}
static void __exit class_exit(void)
{
class_unregister(device_class);
class_destroy(device_class);
pr_info("Modulo removido");
}
module_init(class_init);
module_exit(class_exit);
attribute.h
#ifndef __MY_CLASS_H__
#define __MY_CLASS_H__
static struct class *device_class = NULL;
#endif
Makefile
obj-m += attribute.o
all: run
run:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Como declarar um atributo de classe
Agora vamos começar a criar nosso atributo de classe. Para isso, no attribute.h vamos criar uma variável do tipo class_attribute
, que que fica declarado dentro do header device.h
no path include/linux/device.h
da árvore de código do kernel.
atrribute.h
//...
static struct class_attribute *attr = NULL;
//...
E após declara-lo, vamos alocar memória para ele na nossa função de inicialização do módulo após ter registrado nossa classe:
//...
static int __init class_init(void)
{
//...
//declarao e registro da classe
attr = (struct class_attribute *) kzalloc(sizeof(struct class_attribute), GFP_ATOMIC);
attr->show = show_value;
attr->store = store_value;
attr->attr.name = "value";
attr->attr.mode = 0777;
class_create_file(device_class, attr);
//...
Agora vamos a alguns esclarecimentos. O atributo nome é o mais óbvio de todos, ele espera receber um nome de atributo, aqui chamamos apenas de "value". Como mencionei, quando criamos o atributo ele cria um arquivo no diretorio /sys/class/classe_do_device
, como chamamos nosso atributo de "value" e nossa classe de 7segment então ele ficará no path /sys/class/7segment/value
. Esse arquivo conterá o valor do atributo.
O atributo mode, recebe as permissoes do arquivo, aqui demos a permissao mais aberta de todas (777 - leitura e escrita pra qualquer ususario) porque isso é apenas um tutorial extremamente introdutório, é importante que você entenda sobre as permissões e coloque uma adequada quando fizer isso em produção.
Temos outros dois atributos: show e value. Eles esperam duas funções uma que será chamada quando o arquivo for aberto (show) e uma que será chamada quando o arquivo for fechado (store). Então precisamos declarar a assinatura dessas funções no nosso header e também declarar uma variável que vai receber o valor que esta no atributo.
attribute.h
//...
static ssize_t show_value(const struct class *class,
const struct class_attribute *attr, char* buf);
static ssize_t store_value(const struct class *class,
const struct class_attribute *attr, const char* buf, size_t count);
volatile int value_display;
E agora no attribute.c vamos implementa-las
attribute.c
static ssize_t show_value(const struct class *class,
const struct class_attribute *attr, char* buf)
{
pr_info("valor do display %d - LEITURA", value_display);
return sprintf(buf, "%d", value_display);
}
static ssize_t store_value(const struct class *class,
const struct class_attribute *attr, const char* buf, size_t count)
{
sscanf(buf, "%d", &value_display);
pr_info("valor do display %d - ESCRITA", value_display);
return count;
}
Perfeito, agora quando abrirmos o arquivo sys/class/7segment/value
a função show_value
vai executar e poderemos ler o valor que esta nele, e quando editarmos esse arquivo a função store_value()
vai ser executada e salvar o nosso novo valor em sys/class/7segment/value
.
Compilando e inserindo o modulo no kernel
Vamos compilar e inserir o módulo no kernel.
make
sudo insmod attribute.ko
E vamos conferir os logs sudo dmesg
E obtemos a seguinte saída
[ 958.089903] attribute: loading out-of-tree module taints kernel.
Incluímos nosso código no kernel.
Agora, vamos dar um ls
em sys/class/7segment
.
E veja só que coisa mais bonita:
Bom, agora vamos manipular o valor dentro do arquivo value
e verificar os logs do Kernel.
Vou abrir o arquivo e colocar la dentro o valor 8 e vou consultar os logs sudo dmesg
Pronto, conseguimos gravar um novo atributo e ler ele do arquivo de atributo de classe.
Revisão
- Vimos o que são atributos de classe
- Aprendemos a criar um atributo de classe
- Aprendemos a ler e gravar um novo atributo de classe
Top comments (0)