<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guilherme Giácomo Simões</title>
    <description>The latest articles on DEV Community by Guilherme Giácomo Simões (@simoes).</description>
    <link>https://dev.to/simoes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F771147%2Fc2f61db6-62c3-4359-9497-f40c6ad485cf.jpeg</url>
      <title>DEV Community: Guilherme Giácomo Simões</title>
      <link>https://dev.to/simoes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simoes"/>
    <language>en</language>
    <item>
      <title>Introdução aos drivers USB</title>
      <dc:creator>Guilherme Giácomo Simões</dc:creator>
      <pubDate>Tue, 03 Oct 2023 02:36:28 +0000</pubDate>
      <link>https://dev.to/simoes/introducao-aos-drivers-usb-4i77</link>
      <guid>https://dev.to/simoes/introducao-aos-drivers-usb-4i77</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Nesse quarto texto da série "introdução ao desenvolvimento de driver para linux" vamos introduzir um pouco do conceito das conexões USB, como se comunicam e como iniciar um "hello world" para um driver de usb.&lt;br&gt;
Se você caiu de paraquedas nesse texto, aqui esta o &lt;a href="https://github.com/GuilhermeGiacomoSimoes/introducao_dev_driver_linux" rel="noopener noreferrer"&gt;link com todos os codigos e textos dessa serie&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Protocolo USB
&lt;/h2&gt;

&lt;p&gt;Nessa introdução ao protocoloco USB, vou falar brevemente sobre o assunto. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pinagem&lt;/strong&gt;&lt;br&gt;
Se você pegar um cabo USB e abri-lo, vai perceber que ele tem 4 cabos dentro dele envolto na "capa". Eles tem cada um suas funções. O cabo vermelho é um VCC e tem tensão de 5v, o cabo preto é um GND, o cabo verde (chamado de DATA+ ou simplesmente D+) e o cabo branco (chamado de DATA- ou simplesmente D-) são usados para envio e recebimento de dados. Os dados são transferidos através dos conectores D+ e D- enquanto os conectores VCC e GND fornecem energia ao dispositivo USB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpqk67pub42ghyf6655u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpqk67pub42ghyf6655u.png" alt="Imagem de exemplo de um cabo USB sem a "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comunicação&lt;/strong&gt;&lt;br&gt;
Toda transferencia de dados, independente da direção é iniciada pelo host. O host controla o dispositivo USB. O host também controla o tempo de comunicação com o dispositivo mantendo intervalos de tempo chamados frames.&lt;br&gt;
Para inicio do frames, o host emite uma sequência de início de frame (SOF - Start Of Frame ) nas linhas de dados USB no início de cada frame.&lt;br&gt;
O host USB conduz transações de comunicação com os dispositivos durante o frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedbj53huzeohksapl3e5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedbj53huzeohksapl3e5.png" alt="USB Frame"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O mecanismo de transferência de dados envolve o host gravar e ler de um determinado espaço de memória. Esses locais de memória são chamados de endpoints. O tamanho de um endpoint pode variar muito dependendo do dispositivos.&lt;br&gt;
O número de endpoints começa em 0 e podem chegar até 32. Os endpoints do dispositivo são encontrados em pares numerados, então, cada índice do endpoint tem dois endereços, chamados de IN e OUT. Então o endpoint 1 tem o endereço 1_IN e 1_OUT, o endpoint 2 tem o 2_IN e o 2_OUT e assim por diante. &lt;/p&gt;

&lt;p&gt;Os endpoints OUT transportam dados que saem do host para o device, enquanto os endpoints IN contêm dados enviados do device para o host.&lt;br&gt;
O software do dispositivo fica responsável por ir até o endpoint OUT e verificar se tem algo para ler. Caso durante o monitoramento o software do dispositivo identifique uma mensagem no OUT, ele copia essa mensagem e executa alguma ação. Se o software do dispositivo deseja enviar uma mensagem ele coloca essa mensagem no endpoint IN. A mensagem permanecerá no endpoint IN até que o host decida ler ela.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4z3dlwzqssveu7wruu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4z3dlwzqssveu7wruu0.png" alt="Imagem ilustrativa demonstrando o processo de comunicação"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As informações sobre todos os parâmetros do endpoint e requisitos de comunicação são definidas pelo device e fornecidas ao host quando o dispositivo é conectado ao host e enumerado com sucesso. &lt;br&gt;
Todo dispositivo USB na verdade reserva o endpoint 0 (0_in e 0_out) como um endpoint de controle. O endpoint 0_in contém uma descrição do dispositivo USB, o código do fabricante, o código do dispositivo, entre várias outras informações que são lidas pelo host durante a enumeração. O 0_out fornece ao host a capacidade de enviar comandos ao dispositivo como Redefinir, Suspender ou Restaurar um dispositivo suspenso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non Return To Zero&lt;/strong&gt;&lt;br&gt;
No seguimento de comunicação, um código de linha Sem Retorno a Zero (Non Return To Zero ou simplesmente NRZ) é um código binário no qual, o nível lógico alto é geralmente representado por uma tensão positiva, e o nível lógico baixo é representado por uma tensão negativa. Por isso então no USB temos o D+ e o D- para envio e recebimento de dados. D+ é para representar nível lógico alto e D- é para representar nível lógico baixo. &lt;br&gt;
O NRZ, tem esse nome justamente porque ele nunca é zero, não tem um sinal de repouso nem nada do tipo. A tensão ou é positiva ou negativa. Como na imagem abaixo: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0e37hhecf0tg8seyd8d7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0e37hhecf0tg8seyd8d7.png" alt="NRZ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non Return To Zero Inverted&lt;/strong&gt;&lt;br&gt;
Bom, o USB não se comunica através do NRZ, mas sim através de uma variante do NRZ conhecida como NRZI (Non Return to Zero Inverted). Ela é como o NRZ, nunca é zero, porém nesse tipo de encodamento, o nível lógico 1 significa que nenhuma mudança no bit ocorreu enquanto que o nível lógico 0 significa que o bit mudou. Parece um pouco confuso, mas não é tanto assim. Vamos pensar no seguinte binário: 0011. Veja que os dois primeiros dígitos são 0s. Logo ele vai emitir 11, porque não há mudança no nível lógico. Porém entre os bits 01, ele emitirá um bit 0 (ou uma tensão negativa através do D-) para indicar que houve uma mudança no nível lógico. E a sequência 0011, encodada para NRZI fica representada por 1101.&lt;br&gt;
Agora usando um exemplo mais complexo, dado a sequência binária a seguir: 111010000100. Ela poderá ser representada pelo NRZI da seguinte forma: 111000111001. Então quando tem uma alteração do nível lógico da informação, o nível lógico do D+ e D- mudam conforme mencionado anteriormente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bit stiffing&lt;/strong&gt;&lt;br&gt;
Quando longas séries de 0s são transmitidas usando NRZI, causa uma transição nos níveis. Mas quando longas séries de 1s são transmitidas, nenhuma transição ocorre de acordo com o esquema de codificação NRZI. O bit sempre permanece o mesmo. Nenhuma transição de níveis por muito tempo pode confundir o receptor e dessincroniza-lo.&lt;br&gt;
O Bit stiffing é um processo no qual um 0 é inserido nos dados brutos a cada seis 1s consecutivos.&lt;br&gt;
A inserção de zero provoca transição de nível. O receptor deve reconhecer os bits preenchidos e descartá-los após decodificar os dados NRZI.&lt;br&gt;
Caso nenhuma transição ocorra no sinal NRZI após seis 1s consecutivos, o receptor decide que o bit stiffing não foi feito e descarta os dados recebidos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Mãos no código
&lt;/h2&gt;

&lt;p&gt;Vamos começar uma breve introdução aos drivers USBs, e nos próximos textos faremos algo mais complexo. &lt;br&gt;
Para começar vou criar um &lt;code&gt;hello_world_usb.c&lt;/code&gt; bem simples com os imports e funções básicas padrões de todo modulo de driver&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/init.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/module.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/kernel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SEU NOME &amp;lt;seu_email@email.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Introducao a criacao de driver pra linux"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GPL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_VERSION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;hello_world_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;hello_world_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Adeus mundo cruel&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;module_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world_init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;module_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world_exit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bom, para começar falando sobre a implementação do driver, preciso dizer que praticamente tudo de baixo nivel relacionado a USB é abstraído pelo kernel. Então ele facilita muito nossa comunicação de driver USB com o dispositivo.&lt;br&gt;
Inclusive existe uma interface chamada &lt;code&gt;usb_driver&lt;/code&gt; para que possamos implementar o nosso driver USB com facilidade. Essa lib fica dentro do path &lt;code&gt;include/linux/usb.h&lt;/code&gt; da árvore de código do linux. Então já podemos importar ela no inicio do nosso módulo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;///...&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/usb.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos usar a struct &lt;code&gt;usb_driver&lt;/code&gt; para começar nosso driver. Mas antes vamos comentar um pouco sobre ela. &lt;br&gt;
Ela tem vários parâmetros, vou comentar todos. Aqui esta ela:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_driver&lt;/span&gt; &lt;span class="n"&gt;skel_driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"skeleton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_probe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_disconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suspend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_suspend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_resume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pre_reset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_pre_reset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_reset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_post_reset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skel_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;supports_autosuspend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.name&lt;/code&gt;: Esse parâmetro deixa bem explicito para que ele serve. Ele é uma descrição do driver e normalmente é o mesmo nome do modulo.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.probe&lt;/code&gt;: Chamado na inicialização do driver para verificar se o driver está disposto ou precisa gerenciar uma interface de algum dispositivo em particular. Por ex, no nosso caso, usaremos esse cara para gerenciar um usb e controlar um display de 7segmentos, então ele vai precisar gerenciar um dispositivo em particular. Se precisasse gerenciar um mouse, não precisaria informar uma interface específica.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.disconnect&lt;/code&gt;: Função chamada quando o dispositivo usb é desconectado ou o modulo é removido.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.suspend&lt;/code&gt;: Chamado quando o dispositivo será suspenso pelo sistema no contexto de suspensão do sistema ou de suspensão do tempo de execução.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.resume&lt;/code&gt;: Chamado quando o dispositivo volta da suspensao do sistema operacional.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.pre_reset&lt;/code&gt;: Chamado por usb_reset_device() quando o dispositivo esta prestes a ser reiniciado&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.post_reset&lt;/code&gt;: Chamado por usb_reset_device() após o dispositivo ser reiniciado.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.id_table&lt;/code&gt;: Os drivers USB usam uma tabela de ID para suportar hotplugging (conectar e usar). Exporte esse id_table com MODULE_DEVICE_TABLE(). Se você não exportar sua função &lt;code&gt;probe&lt;/code&gt; jamais sera chamada.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.supports_autosuspend&lt;/code&gt;: Se for 0 o nucleo USB do kernel jamais permitira a suspensão automatica para interfaces vinculadas a esse driver.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No usb_driver somente é obrigatório fornecer o campo name, probe, disconnect e id_table. O resto é opcional.&lt;br&gt;
Os métodos probe() e disconnect() são chamados em um contexto onde podem suspender o device. Mas não abuse desse privilégio. A maior parte do trabalho de conexão a um device deve ser realizada quando o device for inicializado e desfeito no último fechamento. O código de desconexão precisa resolver problemas de simultaneidade com relação aos métodos open() e close(), bem como forcar a conclusão de todas as solicitações de E/S pendentes.&lt;/p&gt;

&lt;p&gt;Como somente é obrigatório o campo name, probe, disconnect e id_table, não vamos inventar moda aqui em um texto introdutório sobre o assunto, vamos usar somente o obrigatório. Iremos declarar a struct no nosso &lt;code&gt;hello_world_usb.c&lt;/code&gt; no inicio do arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_driver&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello world usb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb_probe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb_disconnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;//....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para permitir que o sistema linux-hotplug carregue o driver automaticamente quando o dispositivo for conectado, você precisa criar um MODULE_DEVICE_TABLE. O código a seguir informa aos scripts hotplug que este modulo oferece suporte a um único dispositivo com um ID de fornecedor e ID de produto específicos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_device_id&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb_table&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;USB_DEVICE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USB_VENDOR_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;USB_PRODUCT_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DEVICE_TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb_table&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lembra que dissemos acima sobre o endpoint 0 do USB? Então, essas informações de código de fornecedor (USB_VENDOR_ID) e código do produto (USB_PRODUCT_ID) estarão armazenadas la. Não vamos aprender a ler elas nesse texto por ser um conteúdo introdutório, mas nos próximos textos com certeza iremos aprender sobre isso. &lt;br&gt;
Bom, ele precisa ter o VENDOR_ID e o PRODUCT_ID no endppoint 0, para ler, e achar dentro da tabela de dispositivos o VENDOR_ID e PRODUCT_ID correspondente ao que ele leu no endpoint 0, para então chamar o modulo de driver correto. &lt;/p&gt;

&lt;p&gt;Nesse caso, vou fazer o seguinte: Tenho um Arduino aqui em casa e vou conecta-lo ao meu computador, e rodar o comando &lt;code&gt;lsusb&lt;/code&gt;. Dessa forma ele vai listar os dispositivos conectados ao meu computador e vai me dar algumas breves informações sobre eles. Esse é o resultado do meu &lt;code&gt;lsusb&lt;/code&gt;: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4obppn9o5r84upbdy15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4obppn9o5r84upbdy15.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repare na linha onde tem a descrição Arduino SA Uno R3 que temos várias informações com relação ao dispositivo. Na sexta coluna onde tem a informação &lt;code&gt;2341:0043&lt;/code&gt; esses são o VENDOR ID e o PRODUCT ID do meu Arduino. Então 2341 é o vendor_id e o 0043 é o product_id. Isso é um hexadecimal. Vou declarar meu VENDOR_ID e PRODUCT_ID no código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="cp"&gt;#define USB_VENDOR_ID 0x2341
#define USB_PRODUCT_ID 0x0043
&lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então quando eu conectar o meu Arduino, a minha função probe deve ser executada. Vou declarar minha função probe e disconnect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hello_world_usb_probe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_interface&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_device_id&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dispositivo %s foi conectado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;USB_PRODUCT_ID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;hello_world_usb_disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;usb_interface&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;intf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dispositivo %s desconectado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;USB_PRODUCT_ID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E também precisamos montar nossa função &lt;code&gt;__init&lt;/code&gt; e nela precisamos chamar a função &lt;code&gt;usb_register&lt;/code&gt; para registrar nosso novo driver USB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;hello_world_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usb_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hello_world_usb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pr_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"usb_register falhou para o driver %s. Erro numero %s"&lt;/span&gt;
                &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello_world_usb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E na minha função &lt;code&gt;__exit&lt;/code&gt; preciso remover o meu driver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;hello_world_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;usb_deregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hello_world_usb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Adeus mundo cruel&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos declarar nosso Makefile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;obj-m&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; hello_world_usb.o

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="p"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;PWD&lt;span class="p"&gt;)&lt;/span&gt; modules

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="p"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;PWD&lt;span class="p"&gt;)&lt;/span&gt; clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos compilar e instalar nosso modulo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;insmod hello_world_usb.ko
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apos a insercao do modulo de driver, quando eu insiro meu dispositivo USB o meu &lt;code&gt;dmesg&lt;/code&gt; tem a seguinte saida:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsyqppkjadikz6qryt29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsyqppkjadikz6qryt29.png" alt="Saida dmesg apos a insercao do modulo de driver"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ele reconheceu a conexão e printou a mensagem que esperávamos. Agora quando eu remover o dispositivo USB:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtmdbni09u4sl4iz26pr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtmdbni09u4sl4iz26pr.png" alt="Saida dmesg após remover o device"&gt;&lt;/a&gt;&lt;br&gt;
Obtemos a mensagem esperada que colocamos na nossa função de disconnect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revisão&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aprendemos como funciona a pinagem da conexão USB.&lt;/li&gt;
&lt;li&gt;Aprendemos como funciona a comunicação USB.&lt;/li&gt;
&lt;li&gt;Aprendemos a criar um driver introdutório para um dispositivo USB existente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/doc/html/next/driver-api/usb/writing_usb_driver.html" rel="noopener noreferrer"&gt;Documentação oficial do linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electroschematics.com/usb-how-things-work/" rel="noopener noreferrer"&gt;USB Pinout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.beyondlogic.org/usbnutshell/usb1.shtml" rel="noopener noreferrer"&gt;USB in a NutShell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microchipdeveloper.com/usb:how-it-works" rel="noopener noreferrer"&gt;How USB communication work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Driver de display de 7seg</title>
      <dc:creator>Guilherme Giácomo Simões</dc:creator>
      <pubDate>Tue, 19 Sep 2023 16:41:54 +0000</pubDate>
      <link>https://dev.to/simoes/driver-de-display-de-7seg-3fi3</link>
      <guid>https://dev.to/simoes/driver-de-display-de-7seg-3fi3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introdução&lt;/strong&gt;&lt;br&gt;
Começando agora o quarto episódio da série "introdução ao desenvolvimento de drivers para o kernel linux".&lt;br&gt;
Se você caiu de paraquedas nesse texto, o link com todos os episódios dessa série, está &lt;a href="https://github.com/GuilhermeGiacomoSimoes/introducao_dev_driver_linux"&gt;aqui&lt;/a&gt;&lt;br&gt;
Hoje finalmente escreveremos nosso primeiro driver para linux. Mais especificamente para o raspberry pi (no meu caso 3). A versão do kernel do meu raspberry é a 6.1-rc7. &lt;br&gt;
Eu vou começar pelo raspberry por alguns motivos. Primeiro que vamos mapear os pinos do GPIO do raspberry para ser usado por nosso driver e para isso precisamos introduzir o conceito de device-tree que é importante para os desenvolvedores de driver, e segundo porque é uma comunicação simples de fazer e me parece um bom caminho para começar.&lt;br&gt;
Nos próximos textos faremos drivers para USB utilizando classes existentes. &lt;/p&gt;

&lt;p&gt;Queria salientar que esse é um texto maior e mais denso do que os anteriores, então é preciso que você leia, releia e pratique para conseguir entender os conceitos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Circuito&lt;/strong&gt;&lt;br&gt;
O circuito é muito simples. Somente um display de 7 segmentos em uma protoboard com resistires de +/- 220Ω. O display de 7segmentos espera uma corrente entre 6mA e 20mA. A tensão emitida pela GPIO do raspberry é 3,3v. Então 3,3v/220Ω = 15mA. Estamos dentro do range de 6mA a 20mA. O esquema do circuito fica como abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8cUEs004--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsggyefhd4lkqwd3fr87.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8cUEs004--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsggyefhd4lkqwd3fr87.jpg" alt="7 segmento circuito" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Da pra perceber que não sou a melhor pessoa do mundo para fazer esquemas de circuito, mas acho que da para ter uma noção. Para ajudar, vou deixar também uma tabela com a descrição das conexões:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Segmento&lt;/th&gt;
&lt;th&gt;GPIO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Aqui a foto de como ficou meu circuito montado na protoboard:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LZSMFsEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uol87uy3x8omzkiyxrs7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LZSMFsEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uol87uy3x8omzkiyxrs7.jpg" alt="Imagem protoboard 1" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Q-IYx7b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsmpm5z7r6s41ro4anzy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Q-IYx7b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsmpm5z7r6s41ro4anzy.jpg" alt="Imagem protoboard 2" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que sao device-tree&lt;/strong&gt;&lt;br&gt;
No kernel linux temos uma estrutura de dados chamado &lt;code&gt;device-tree&lt;/code&gt; que fica responsável por informar a descrição dos periféricos de IO para o kernel.&lt;/p&gt;

&lt;p&gt;Em varias situações do nosso dia-a-dia temos que usar documentos ou ferramentas que nos ajudam a descrever certas funcionalidades de algo. Manuais de usuario nos auxiliam a entender as funcionalidades de um produto. Device-tree em sistemas Linux Embarcados compartilham dessa mesma particularidade, e servem para descrever com precisão como sera configurado e utilizado o hardware.&lt;/p&gt;

&lt;p&gt;O que faremos aqui é o chamado &lt;code&gt;overlay&lt;/code&gt; do &lt;code&gt;device-tree&lt;/code&gt;. Um overlay do &lt;code&gt;device-tree&lt;/code&gt; consiste em um arquivo de dados que altera a estrutura atual do &lt;code&gt;device-tree&lt;/code&gt; do hardware em questão. Assim como os módulos ele pode ser acoplado dinamicamente ao kernel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicando a estrutura do device-tree&lt;/strong&gt;&lt;br&gt;
Segue abaixo nosso device-tree para acoplar ao kernel chamado &lt;code&gt;overlay.dts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dts-v1/;
/plugin/;
/{   
  compatible = "brcm,bcm2835";
  fragment@0 {         
    target-path = "/";         
    __overlay__{             
      my_device{
        compatible = "ggs-prd,7segment";
        status = "okay";                 
        a-gpio = &amp;lt;&amp;amp;gpio 2 0&amp;gt;;      
        b-gpio = &amp;lt;&amp;amp;gpio 3 0&amp;gt;;
        c-gpio = &amp;lt;&amp;amp;gpio 4 0&amp;gt;;
        d-gpio = &amp;lt;&amp;amp;gpio 5 0&amp;gt;;
        e-gpio = &amp;lt;&amp;amp;gpio 6 0&amp;gt;;
        f-gpio = &amp;lt;&amp;amp;gpio 7 0&amp;gt;;
        g-gpio = &amp;lt;&amp;amp;gpio 9 0&amp;gt;;
        dp-gpio = &amp;lt;&amp;amp;gpio 10 0&amp;gt;;
    };         
    };      
  }; 
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A primeira linha &lt;code&gt;/dts-v1/;&lt;/code&gt; é usada para informar a versão do dts.&lt;/p&gt;

&lt;p&gt;A segunda linha &lt;code&gt;/plugin/&lt;/code&gt; é usada para informar que esse overlay de device-tree é um plugin&lt;/p&gt;

&lt;p&gt;A linha &lt;code&gt;compatible = "brcm,bcm2835";&lt;/code&gt; descreve para qual plataforma esse device-tree foi feito para funcionar. Aqui existe uma regra super importante, ele começa sempre na mais compativel e vai para a menos compativel. Então nesse caso a plataforma mais compativel para a qual esse device-tree foi feito é a brcm, e a segunda é a bcm2835. &lt;br&gt;
É importante sempre mencionar todas as plataformas para a qual você quer que o overlay funcione porque vão acontecer erros nas plataformas que não forem mencionadas. &lt;br&gt;
Nesse caso, brcm e bcm2835 fazem referencia a fabricante Broadcom, responsavel por fabricar os chips do raspberry pi.&lt;/p&gt;

&lt;p&gt;A linha com &lt;code&gt;fragment@0&lt;/code&gt; é o inicio dos fragmentos do device-tree. Aqui descreveremos qual dispositivo sera sobreposto.&lt;/p&gt;

&lt;p&gt;A linha que contem o segundo "compatible" &lt;code&gt;compatible = "ggs-prd,7segment";&lt;/code&gt; é super importante, ele é o identificador do nosso driver em questão. Ele indica o nome do driver e qual a empresa ou dev responsavel pela manutenção dele. Esse segundo compatible é indispensável para nossos próximos passos para que o modulo reconheça qual overlay contém as alterações necessárias para que o driver funcione corretamente.&lt;/p&gt;

&lt;p&gt;Nas linhas &lt;code&gt;a-gpio = &amp;lt;&amp;amp;gpio 2 0&amp;gt;;&lt;/code&gt;, &lt;code&gt;b-gpio = &amp;lt;&amp;amp;gpio 3 0&amp;gt;;&lt;/code&gt; e assim por diante, apesar de nao parecer é um conceito muito simples. Estamos mapeando as portas gpio para serem uma porta de saida de dados. Por isso o 0 no fim. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Criando um novo driver&lt;/strong&gt;&lt;br&gt;
Para começar, vamos criar dois arquivos 7segment.c e um 7segment.h. E criar uma classe e um atributo de classe como ensinamos nos textos anteriores:&lt;/p&gt;

&lt;p&gt;7segment.h&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef __7SEGMENT_H__
#define __7SEGMENT_H__
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#endif 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7segment.c&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/init.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/module.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/kernel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/slab.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/device.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"7segment.h"&lt;/span&gt;&lt;span class="c1"&gt; &lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SEU NOME &amp;lt;seu_email@email.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"7segment"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GPL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_VERSION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valor do display %s - LEITURA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sscanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valor do display %d - ESCRITA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kzalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;GFP_ATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="n"&gt;pr_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERRO NA ALOCACAO DA CLASSE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"7segment"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;class_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kzalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;GFP_ATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mo"&gt;0777&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;class_create_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"class registrada"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;class_unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;class_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Modulo removido"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;module_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;module_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, nada de diferente do que fizemos nos textos anteriores. É exatamente o mesmo codigo do texto &lt;a href="https://dev.to/simoes/atributos-de-classes-42d"&gt;anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Agora precisamos realizar a integracao do nosso novo device-tree com o nosso driver para conseguirmos alterar o estado das GPIOs do raspberry. &lt;br&gt;
Para isso, primeiro vou criar uma struct do tipo &lt;code&gt;of_device_id&lt;/code&gt; que está declarado em &lt;code&gt;/include/linux/of_device.h&lt;/code&gt; e passar como parametro para ela o compatible do driver explicado anteriormente. Ele vai vincular o nosso driver atual com esse "identificador" e ela conseguirá identificar todos os devices na device-tree que utilizam esse driver.&lt;br&gt;
Então vamos declarar e atribuir o parametro na struct dentro do nosso 7segment.h&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;of_device_id&lt;/span&gt; &lt;span class="n"&gt;driver_ids&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;compatible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ggs-prd,7segment"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, precisamos criar uma struct do tipo &lt;code&gt;platform_driver&lt;/code&gt; que fica declarada em &lt;code&gt;/include/linux/platform_device.h&lt;/code&gt; que é uma interface para criação de um driver genérico, ela vai receber como parâmetro nossa struct declarada anteriormente (&lt;code&gt;of_device_id driver_ids[]&lt;/code&gt;) e as funções de inicialização e remoção do driver que não serão as mesmas das funções de inicialização e remoção do módulo.&lt;/p&gt;

&lt;p&gt;Então vamos declarar a struct &lt;code&gt;platform_driver&lt;/code&gt; e tambem declarar as assinaturas das funções de inicialização e remoção do driver no nosso 7segment.h:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;gpio_init_probe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_device&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;gpio_exit_remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_device&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_driver&lt;/span&gt; &lt;span class="n"&gt;display_driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpio_init_probe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpio_exit_remove&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"display_driver"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;THIS_MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;of_match_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora no nosso 7segment.c vamos dar inicio a implementação das funções probe e remove do driver e tambem importar nossas bibliotecas of_device.h e platform_device.h:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/of_device.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/platform_device.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;gpio_init_probe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_device&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Driver inicializado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;gpio_exit_remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_device&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Driver removido"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso, vamos criar no nosso 7segment.h as variaveis referentes a cada gpio em uso no display no nosso raspberry. Essas variaveis serão do tipo gpio_desc, struct declarada em &lt;code&gt;include/linux/gpio/consumer.h&lt;/code&gt; elas serão mapeadas para cada porta do raspberry que configuramos como saida no nosso overlay de device-tree e poderemos manipular o valor logico delas (1 ou 0):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;gpio_desc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não podemos nos esquecer de importar o consumer.h &lt;br&gt;
no nosso 7segment.c:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/gpio/consumer.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, vamos mapear nossas variáveis para as portas gpio do rasp e setá-las com valor lógico 0 por padrão usando a função &lt;code&gt;devm_gpiod_get&lt;/code&gt; da lib &lt;code&gt;gpio/consumer.h&lt;/code&gt; dentro da nossa função &lt;code&gt;gpio_init_probe&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;gpio_init_probe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;platform_device&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Driver inicializado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;devm_gpiod_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pdev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"g"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIOD_OUT_LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, com as funções de inicialização e remoção do driver prontos, e preciso registrá-lo no módulo, pra isso os seguintes trechos foram, respectivamente, acrescentados nas funções de inicialização e remoção do módulo.&lt;/p&gt;

&lt;p&gt;Na função de inicialização deve ser registrado o driver  no fim da função, antes do &lt;code&gt;return 0;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;platform_driver_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;display_driver&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pr_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERRO! nao foi possivel carregar o driver"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;segments_display_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...    &lt;/span&gt;
   &lt;span class="n"&gt;platform_driver_unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;display_driver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto registramos nosso driver. Agora, precisamos criar na nossa função &lt;code&gt;store_value&lt;/code&gt; que a função que é executada quando o arquivo de atributo de classe e fechado algumas condições para mudar as portas GPIOs do raspberry de acordo com o número que esta dentro da variável &lt;code&gt;value_display&lt;/code&gt; antes do nosso &lt;code&gt;return count;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 
        &lt;span class="n"&gt;gpiod_set_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Repare que não nos atentamos a legibilidade do código aqui, você tem a liberdade de depois abstrair isso em funções e melhorar a qualidade desse trecho de código&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Caso o valor não esteja no range de 0..9 vamos exibir a letra E de erro.&lt;/p&gt;

&lt;p&gt;Agora vamos criar nosso Makefile como todos os outros que ja criamos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;

&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;

&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt; &lt;span class="n"&gt;uname&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PWD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;modules&lt;/span&gt;

&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt; &lt;span class="n"&gt;uname&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PWD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Porém, faremos algumas alterações, porque precisamos compilar o nosso device-tree e fazer o overlay dele no kernel.&lt;br&gt;
Para compilar precisamos do seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dtc -@ &lt;span class="nt"&gt;-I&lt;/span&gt; dts &lt;span class="nt"&gt;-O&lt;/span&gt; dtb &lt;span class="nt"&gt;-o&lt;/span&gt; overlay.dtbo overlay.dts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para fazer o overlay dele no kernel precisamos do seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dtoverlay overlay.dtbo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então vamos criar uma rotina no Makefile chamada dt&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;#...
&lt;/span&gt;&lt;span class="nl"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;overlay.dts&lt;/span&gt;
    dtc -@ &lt;span class="nt"&gt;-I&lt;/span&gt; dts &lt;span class="nt"&gt;-O&lt;/span&gt; dtb &lt;span class="nt"&gt;-o&lt;/span&gt; overlay.dtbo overlay.dts
    &lt;span class="nb"&gt;sudo &lt;/span&gt;dtoverlay overlay.dtbo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E na rotina &lt;code&gt;all:&lt;/code&gt; vamos chamar além do nosso run tambem o nosso dt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run dt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O nosso Makefile fica assim&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;obj-m&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; 7segment.o

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run dt&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; modules

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; clean

&lt;span class="nl"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;overlay.dts&lt;/span&gt;
    dtc -@ &lt;span class="nt"&gt;-I&lt;/span&gt; dts &lt;span class="nt"&gt;-O&lt;/span&gt; dtb &lt;span class="nt"&gt;-o&lt;/span&gt; overlay.dtbo overlay.dts
    &lt;span class="nb"&gt;sudo &lt;/span&gt;dtoverlay overlay.dtbo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito, agora vamos rodar o &lt;code&gt;make&lt;/code&gt; e inserir nosso modulo no kernel e ver o resultado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make
&lt;span class="nb"&gt;sudo &lt;/span&gt;insmod 7segment.ko
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosso resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;99897.183680] 7segment: loading out-of-tree module taints kernel.
&lt;span class="o"&gt;[&lt;/span&gt;99897.185331] class registrada
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora quando rodarmos o comando &lt;code&gt;sudo echo "8" &amp;gt; /sys/class/7segment/value&lt;/code&gt; a letra 8 será exibida no nosso display. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revisão&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aprendemos o que é um device-tree.&lt;/li&gt;
&lt;li&gt;Aprendemos como substituir o atual device-tree do kernel por um que nós mesmo criamos.&lt;/li&gt;
&lt;li&gt;Aprendemos como registrar um novo driver de dispositivo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doc oficial &lt;a href="https://docs.kernel.org/"&gt;Linux&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Livro &lt;a href="https://www.amazon.com.br/Linux-Kernel-Development-Cookbook-programming-ebook/dp/B07RW915K4"&gt;linux kernel programming comprehensive guide&lt;/a&gt; de  Kaiwan N Billimoria &lt;/li&gt;
&lt;li&gt;Artigo &lt;a href="https://embarcados.com.br/driver-linux-para-display-de-7-segmentos/"&gt;driver-linux-para-display-de-7-segmentos&lt;/a&gt; de Brenda Jacomelli&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>lkm</category>
      <category>drivers</category>
    </item>
    <item>
      <title>Atributos de classes</title>
      <dc:creator>Guilherme Giácomo Simões</dc:creator>
      <pubDate>Fri, 15 Sep 2023 13:13:53 +0000</pubDate>
      <link>https://dev.to/simoes/atributos-de-classes-42d</link>
      <guid>https://dev.to/simoes/atributos-de-classes-42d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introdução&lt;/strong&gt;&lt;br&gt;
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 &lt;code&gt;/sys/class/classe_do_driver&lt;/code&gt; que serão usados como forma de interagir com o SO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que são atributos de classes&lt;/strong&gt;&lt;br&gt;
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. &lt;br&gt;
A comunicação entre driver x Kernel é feita a partir de um arquivo que fica no &lt;code&gt;/sys/class/classe_do_driver&lt;/code&gt;, 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 &lt;code&gt;/sys/class/7segment&lt;/code&gt;. Como expliquei no texto anterior, essa classe &lt;code&gt;7segment&lt;/code&gt; 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 &lt;code&gt;7segment&lt;/code&gt;. Então, criaremos um atributo de classe para a classe &lt;code&gt;7segment&lt;/code&gt; e leremos esse atributo com o número para exibir no display. &lt;br&gt;
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. &lt;br&gt;
Ficará mais claro com a implementação prática do código. &lt;/p&gt;

&lt;p&gt;Caso tenha caído de paraquedas nesse texto, aqui esta o &lt;a href="https://github.com/GuilhermeGiacomoSimoes/introducao_dev_driver_linux"&gt;link&lt;/a&gt; com os códigos e links dessa serie.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mãos no código&lt;/strong&gt;&lt;br&gt;
Para começar vamos criar os arquivos básicos, um &lt;code&gt;attribute.c&lt;/code&gt; com a classe ja criada, assim como ensinamos no texto anterior, um &lt;code&gt;attribute.h&lt;/code&gt; e um Makefile:&lt;/p&gt;

&lt;p&gt;attribute.c:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/init.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/module.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/kernel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/slab.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/device.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"attribute.h"&lt;/span&gt;&lt;span class="c1"&gt; &lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SEU NOME &amp;lt;seu_email@email.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Classes de dispositivos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GPL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_VERSION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kzalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;GFP_ATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="n"&gt;pr_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERRO NA ALOCACAO DA CLASSE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"7segment"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;class_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"class registrada"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;class_unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;class_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Modulo removido"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;module_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;module_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;attribute.h&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef __MY_CLASS_H__
#define __MY_CLASS_H__
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#endif 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Makefile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;obj-m&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; attribute.o

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; modules

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    make &lt;span class="nt"&gt;-C&lt;/span&gt; /lib/modules/&lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;/build &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Como declarar um atributo de classe&lt;/strong&gt;&lt;br&gt;
Agora vamos começar a criar nosso atributo de classe. Para isso, no attribute.h vamos criar uma variável do tipo &lt;code&gt;class_attribute&lt;/code&gt;, que que fica declarado dentro do header &lt;code&gt;device.h&lt;/code&gt; no path &lt;code&gt;include/linux/device.h&lt;/code&gt; da árvore de código do kernel.&lt;/p&gt;

&lt;p&gt;atrribute.h&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="c1"&gt;//declarao e registro da classe&lt;/span&gt;

    &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kzalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;GFP_ATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mo"&gt;0777&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;class_create_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;/sys/class/classe_do_device&lt;/code&gt;, como chamamos nosso atributo de "value" e nossa classe de 7segment então ele ficará no path &lt;code&gt;/sys/class/7segment/value&lt;/code&gt;. Esse arquivo conterá o valor do atributo. &lt;br&gt;
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. &lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;attribute.h&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora no attribute.c vamos implementa-las&lt;br&gt;
attribute.c&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;show_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valor do display %d - LEITURA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;store_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sscanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valor do display %d - ESCRITA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfeito, agora quando abrirmos o arquivo &lt;code&gt;sys/class/7segment/value&lt;/code&gt; a função &lt;code&gt;show_value&lt;/code&gt; vai executar e poderemos ler o valor que esta nele, e quando editarmos esse arquivo a função &lt;code&gt;store_value()&lt;/code&gt; vai ser executada e salvar o nosso novo valor em &lt;code&gt;sys/class/7segment/value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compilando e inserindo o modulo no kernel&lt;/strong&gt;&lt;br&gt;
Vamos compilar e inserir o módulo no kernel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;insmod attribute.ko
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E vamos conferir os logs &lt;code&gt;sudo dmesg&lt;/code&gt;&lt;br&gt;
E obtemos a seguinte saída&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;  958.089903] attribute: loading out-of-tree module taints kernel.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Incluímos nosso código no kernel.&lt;/p&gt;

&lt;p&gt;Agora, vamos dar um &lt;code&gt;ls&lt;/code&gt; em &lt;code&gt;sys/class/7segment&lt;/code&gt;.&lt;br&gt;
E veja só que coisa mais bonita:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uN5rV60v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lunzvnddv4x11a1xakjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uN5rV60v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lunzvnddv4x11a1xakjf.png" alt="listagem do diretorio sys/class/7segment" width="578" height="77"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bom, agora vamos manipular o valor dentro do arquivo &lt;code&gt;value&lt;/code&gt; e verificar os logs do Kernel.&lt;br&gt;
Vou abrir o arquivo e colocar la dentro o valor 8 e vou consultar os logs &lt;code&gt;sudo dmesg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x3LPPbnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qmmfqvujwxbrxkmmltn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x3LPPbnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qmmfqvujwxbrxkmmltn.png" alt="Saida dos logs do kernel" width="512" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pronto, conseguimos gravar um novo atributo e ler ele do arquivo de atributo de classe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revisão&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vimos o que são atributos de classe&lt;/li&gt;
&lt;li&gt;Aprendemos a criar um atributo de classe&lt;/li&gt;
&lt;li&gt;Aprendemos a ler e gravar um novo atributo de classe&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>lkm</category>
      <category>linuxkernelmodule</category>
      <category>drivers</category>
    </item>
    <item>
      <title>Classe de dispositivos</title>
      <dc:creator>Guilherme Giácomo Simões</dc:creator>
      <pubDate>Wed, 13 Sep 2023 20:21:56 +0000</pubDate>
      <link>https://dev.to/simoes/classe-de-dispositivos-3h4a</link>
      <guid>https://dev.to/simoes/classe-de-dispositivos-3h4a</guid>
      <description>&lt;p&gt;Nesse segundo texto sobre a introdução ao desenvolvimento de drivers de dispositivos pro kernel linux, vamos falar sobre classes de dispositivos.&lt;/p&gt;

&lt;p&gt;Caso tenha caído de paraquedas nesse texto, aqui esta o &lt;a href="https://github.com/GuilhermeGiacomoSimoes/introducao_dev_driver_linux"&gt;link&lt;/a&gt; do github com o compilado dos códigos e links dessa serie.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que são classes de dispositivos?&lt;/strong&gt;&lt;br&gt;
Classes de dispositivos é uma forma de classificar a familia do dispositivo do qual voce esta escrevendo o driver e tambem uma forma de facilitar uma comunicação do kernel com o driver em questão.&lt;/p&gt;

&lt;p&gt;Os dispositivos são enumerados nas classes e cada vez que um novo driver é atribuído a classe ele incrementa um atributo de classe chamado devnum, e atribui esse devnum ao dispositivo. O devnum nunca é decrementado, por tanto se você remover o dispositivo e inserir novamente ele receberá outro devnum.&lt;/p&gt;

&lt;p&gt;Após inserirmos o módulo de driver no kernel, ele criará um diretório com o nome da sua classe no caminho &lt;code&gt;/sys/class&lt;/code&gt; .&lt;br&gt;
Se quisermos ver as classes de dispositivos registradas no nosso kernel, podemos listar os diretorios em &lt;code&gt;/sys/class&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CaepjaDs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v9vofoexyauxc7s7cu2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CaepjaDs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v9vofoexyauxc7s7cu2l.png" alt="listagem das classes registradas no kernel" width="553" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos observar que temos classes de bluetooth, graphics, cpuid, etc. &lt;br&gt;
Essas são as classes registradas no meu kernel, e podemos criar uma nova classe de dispositivo, ou usar alguma já existente como a classe de usb ou bluetooth. &lt;br&gt;
Nesse texto, vamos criar nossa própria classe. Toda classe deve ficar declarada em um arquivo header para que seja usada pelos drivers, extensões e interfaces. Como os dispositivos estão vinculados aos drivers, eles devem ser adicionados a classe a qual pertencem.&lt;/p&gt;

&lt;p&gt;Para criar uma classe de dispositivo e consequentemente um diretorio para essa classe no &lt;code&gt;/sys/class&lt;/code&gt; , é preciso registrar essas informações em uma struct chamada &lt;code&gt;class&lt;/code&gt; que fica declarada dentro do header &lt;code&gt;include/linux/device.h&lt;/code&gt;. , portanto…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mãos no codigo&lt;/strong&gt;&lt;br&gt;
Entao, sem mais enrolação, vamos criar um novo módulo chamado &lt;code&gt;my_class.c&lt;/code&gt;, lembrando que todos os códigos completos estão no link do github citado acima.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/init.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/module.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/kernel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SEU NOME &amp;lt;seu_email@email.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Classes de dispositivos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GPL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_VERSION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;module_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;module_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim como seu Makefile padrão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;obj-m&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; my_class.o

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;make&lt;/span&gt; &lt;span class="err"&gt;-C&lt;/span&gt; &lt;span class="err"&gt;/lib/modules/$(shell&lt;/span&gt; &lt;span class="err"&gt;uname&lt;/span&gt; &lt;span class="err"&gt;-r)/build&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; modules

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;make&lt;/span&gt; &lt;span class="err"&gt;-C&lt;/span&gt; &lt;span class="err"&gt;/lib/modules/$(shell&lt;/span&gt; &lt;span class="err"&gt;uname&lt;/span&gt; &lt;span class="err"&gt;-r)/build&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(PWD)&lt;/span&gt; clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos declarar também um header &lt;code&gt;my_class.h&lt;/code&gt; pra organizar nosso código e dentro do header vamos já criar nossa variável device_class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef __MY_CLASS_H__
#define __MY_CLASS_H__
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora precisamos tanto importar o header &lt;code&gt;device.h&lt;/code&gt; quanto o nosso header &lt;code&gt;my_class.&lt;/code&gt;h dentro do &lt;code&gt;my_class.c&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/device.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"my_class.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para criarmos a nossa classe, precisamos agora alocar memória para a struct e preencher seus atributos.&lt;br&gt;
Provavelmente você esta acostumado a usar o &lt;code&gt;malloc()&lt;/code&gt; para alocação de memória em aplicações C em nível de usuário. Porém o &lt;code&gt;malloc()&lt;/code&gt; faz parte da biblioteca &lt;code&gt;stdlib.h&lt;/code&gt; e nós não temos acesso as bibliotecas no nível do kernel.&lt;br&gt;
Porém, no kernel temos um header chamado &lt;code&gt;slab.h&lt;/code&gt; que tem o poder de fazer alocações de memória, então, podemos importar ele no nosso &lt;code&gt;my_class.c&lt;/code&gt;: &lt;code&gt;#include &amp;lt;linux/slab.h&amp;gt;&lt;/code&gt;. E depois usar a função &lt;code&gt;kzalloc()&lt;/code&gt; para alocar memória para a nossa classe.&lt;/p&gt;

&lt;p&gt;Uma coisa a se frizar da função &lt;code&gt;kzalloc()&lt;/code&gt; é que ela recebe dois parametros, ao contrario de &lt;code&gt;malloc()&lt;/code&gt; que só recebe um: A quantidade de bytes a ser alocado. &lt;br&gt;
O kzalloc() recebe a quantidade de bytes a ser alocado e mais uma flag, que diz respeito ao controle do comportamento dos alocadores.&lt;/p&gt;

&lt;p&gt;Segundo a Documentação oficial:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eles informam quais zonas de memória podem ser usadas, o quanto o alocador deve tentar encontrar memória livre, se a memória pode ser acessada pelo espaço do usuário, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Caso queira mais informações sobre as flags de alocacao de memoria, pode acessar esse &lt;a href="https://dri.freedesktop.org/docs/drm/core-api/memory-allocation.html"&gt;link&lt;/a&gt;.&lt;br&gt;
No nosso caso, vamos utilizar a flag &lt;code&gt;GFP_ATOMIC&lt;/code&gt; , que sinaliza ao alocador que a reserva de memória é extremamente justificada e o kernel terá problemas caso a alocação não seja feita. Porém para a maioria dos casos, &lt;code&gt;GFP_KERNEL&lt;/code&gt; resolve.&lt;/p&gt;

&lt;p&gt;Então alocaremos memória para a nossa classe dentro da nossa função de inicialização do modulo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/slab.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;device_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kzalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;GFP_ATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;pr_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERRO NA ALOCACAO DA CLASSE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após a nossa alocação de classe vamos preencher somente um atributo dessa classe: O seu nome.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt; &lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"7segment"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O atributo name é bem óbvio. Ele é somente o nome da classe do nosso dispositivo. Aqui declarei "7segment" porque nos próximos textos, usaremos esse modulo e construiremos um circuito simples em uma protoboard e controlaremos um display de 7 segmentos através do kernel.&lt;/p&gt;

&lt;p&gt;Por fim, chamaremos uma função dentro da função de inicialização que registrará nossa classe e criará um diretório para a classe dentro de &lt;code&gt;/sys/class&lt;/code&gt; com o nome que especificamos, nesse caso 7segment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;class_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, na função de &lt;code&gt;__exit&lt;/code&gt; precisamos matar a classe de dispositivo que criamos, então vamos incrementar essa linha de código na função de &lt;code&gt;__exit&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt; &lt;span class="n"&gt;class_unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;class_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Somente para fins de visualização, vamos colocar dois &lt;code&gt;pr_info()&lt;/code&gt; , um no&lt;code&gt;__init&lt;/code&gt; e outro no &lt;code&gt;__exit&lt;/code&gt; para printar algo no console&lt;/p&gt;

&lt;p&gt;No init:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;class_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"class registrada"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E no exit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__exit&lt;/span&gt; &lt;span class="nf"&gt;class_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
 &lt;span class="n"&gt;pr_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Modulo removido"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos compilar: &lt;code&gt;make&lt;/code&gt; . &lt;br&gt;
Vamos limpar o nosso log para melhor visualizar o resultado do nosso módulo &lt;code&gt;sudo dmesg -C&lt;/code&gt;.&lt;br&gt;
E por fim vamos inserir o módulo no kernel: &lt;code&gt;sudo insmod my_class.ko&lt;/code&gt; . &lt;br&gt;
Após isso a saída do nosso sudo dmesg :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; 1107.594074] my_class: loading out-of-tree module taints kernel.
&lt;span class="o"&gt;[&lt;/span&gt; 1107.594093] my_class: class registrada
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Além disso, se consultarmos o diretorio &lt;code&gt;/sys/class&lt;/code&gt; temos o diretório da classe 7segment que criamos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xZ-9cbFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wc7gmaonl36nt82ntpw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xZ-9cbFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wc7gmaonl36nt82ntpw0.png" alt="saida do dmesg" width="543" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando removermos o modulo: &lt;code&gt;sudo rmmod my_class&lt;/code&gt; . O diretório da classe também é removido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revisão&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Aprendemos o que é uma classe de dispositivo.&lt;/li&gt;
&lt;li&gt;Como criar uma nova classe de dispositivo.&lt;/li&gt;
&lt;li&gt;Vimos também uma BREVÍSSIMA introdução sobre a alocação de memória no kernel.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>lkm</category>
      <category>linuxkernelmodule</category>
      <category>drivers</category>
    </item>
    <item>
      <title>Hello world linux kernel module</title>
      <dc:creator>Guilherme Giácomo Simões</dc:creator>
      <pubDate>Wed, 13 Sep 2023 20:06:49 +0000</pubDate>
      <link>https://dev.to/simoes/hello-world-linux-kernel-module-1m6h</link>
      <guid>https://dev.to/simoes/hello-world-linux-kernel-module-1m6h</guid>
      <description>&lt;p&gt;Começa aqui a série que pretendo fazer sobre o desenvolvimento de device drivers para o kernel linux. &lt;br&gt;
Esse texto é um conteúdo bem introdutório sobre o assunto, porém é esperado que você tenha conhecimento em linguagem C.&lt;/p&gt;

&lt;p&gt;Aqui está o &lt;a href="https://github.com/GuilhermeGiacomoSimoes/introducao_dev_driver_linux"&gt;link&lt;/a&gt; para o repositório com os códigos contidos nessa série.&lt;br&gt;
O linux é conhecido por ser um Kernel monolito. Porém, na verdade, podemos afirmar que ele é monolito e ao mesmo tempo modular. Porque temos a possibilidade de "injetar" códigos no kernel, sem precisar recompilar o kernel toda vez que fizermos uma mudança. &lt;br&gt;
Existe um pacote chamado linux-headers que contém alguns utilitários para injetar um código no kernel sem que ele esteja na árvore do código.&lt;br&gt;
Para instalar o linux-headers:&lt;br&gt;
&lt;code&gt;sudo apt install linux-headers&lt;/code&gt;&lt;br&gt;
Caso esteja em um raspberry também ira precisar desse pacote:&lt;br&gt;
&lt;code&gt;sudo apt install raspberrypi-kernel-headers&lt;/code&gt;&lt;br&gt;
Para fins de estudo, também recomendo clonar o repositório do linux&lt;br&gt;
&lt;code&gt;git clone https://github.com/torvalds/linux&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Para começar essa BREVÍSSIMA introdução de como escrevermos módulos de drivers pra kernel linux, vou começar com o famigerado hello world. E nem será um driver em si , será somente um arquivo que vamos injetar no kernel e printar a mensagem "hello world" nos logs do kernel.&lt;br&gt;
Então aqui esta nosso código do nosso hello_world.c&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;linux/init.h&amp;gt;
#include &amp;lt;linux/module.h&amp;gt;
#include &amp;lt;linux/kernel.h&amp;gt;

MODULE_AUTHOR("SEU NOME &amp;lt;seu_email@email.com&amp;gt;");
MODULE_DESCRIPTION("Introducao a criacao de driver pra linux");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");

static int __init hello_world_init(void)
{
 pr_info("Hello World\n");
 return 0;  /* successo */
}

static void __exit hello_world_exit(void)
{
 pr_info("Adeus mundo cruel\n");
}

module_init(hello_world_init);
module_exit(hello_world_exit);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos a explicação desse pequeno trecho de código:&lt;br&gt;
Começando pelos imports, esses 3 primeiros imports são necessarios para um modulo linux.&lt;/p&gt;

&lt;p&gt;O primeiro &lt;code&gt;&amp;lt;linux/init.h&amp;gt;&lt;/code&gt; fica no caminho &lt;code&gt;include/linux/init.h&lt;/code&gt; da árvore de código do kernel, e ela é responsável por nos dar a possibilidade de usarmos a macro &lt;code&gt;__init&lt;/code&gt; nas funções de inicialização do modulo bem como a macro &lt;code&gt;__exit&lt;/code&gt; nas funções de destruição do modulo.&lt;/p&gt;

&lt;p&gt;O import &lt;code&gt;&amp;lt;linux/module.h&amp;gt;&lt;/code&gt; fica no caminho &lt;code&gt;include/linux/module.h&lt;/code&gt;, nos da as implementações das funções &lt;code&gt;module_init()&lt;/code&gt; e também &lt;code&gt;module_exit()&lt;/code&gt; para informarmos ao kernel, quais funções são responsáveis pela criação e destruição do modulo. Também, esse cabeçalho contém as funções &lt;code&gt;MODULE_AUTHOR&lt;/code&gt;, &lt;code&gt;MODULE_DESCRIPTION&lt;/code&gt;, &lt;code&gt;MODULE_LICENSE&lt;/code&gt; e &lt;code&gt;MODULE_VERSION&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O cabeçalho &lt;code&gt;&amp;lt;linux/kernel.h&amp;gt;&lt;/code&gt; que fica no caminho &lt;code&gt;include/linux/kernel.h&lt;/code&gt; é um tanto quanto confuso, porque ele contém algumas coisas que não tem relação entre si, e no momento de escrita desse texto, a divisão dessas coisas ja esta em andamento, e o kernel.h é mantido para garantir a compatibilidade com os módulos que estão usando esse header. Aqui vamos usar esse cabeçalho única e exclusivamente porque eu, infelizmente, ainda não tenho conhecimento dos arquivos que estão recebendo o split do kernel.h nesse momento.&lt;/p&gt;

&lt;p&gt;Quando inserirmos esse modulo no kernel a função &lt;code&gt;hello_world_init&lt;/code&gt; sera invocada, e quando removermos o modulo do kernel a função &lt;code&gt;hello_world_exit&lt;/code&gt; será invocada. Isso é uma regra de todo módulo linux.&lt;/p&gt;

&lt;p&gt;A função &lt;code&gt;pr_info()&lt;/code&gt; serve para registrar uma mensagem nos logs do kernel. Você pode ver essas mensagens rodando o comando &lt;code&gt;sudo dmesg&lt;/code&gt; . &lt;br&gt;
No desenvolvimento do kernel, não temos acesso as bibliotecas que normalmente temos quando desenvolvemos um sistema em C no espaço de usuário. No nível do kernel, você deve usar as libs do próprio kernel, ou fazer suas próprias libs. Você com certeza está habituado com a lib &lt;code&gt;&amp;lt;stdio.h&amp;gt;&lt;/code&gt; , ela permite que usemos a função &lt;code&gt;printf()&lt;/code&gt; e &lt;code&gt;scanf()&lt;/code&gt; , mas como mencionado, ela não está disponível para nós aqui. Então, temos a implementação de algo muito parecido no kernel: As funções &lt;code&gt;pr_info()&lt;/code&gt; , &lt;code&gt;pr_err()&lt;/code&gt; , &lt;code&gt;pr_emerg()&lt;/code&gt; , &lt;code&gt;pr_alert()&lt;/code&gt; , &lt;code&gt;pr_crit()&lt;/code&gt; , &lt;code&gt;pr_warning()&lt;/code&gt;, &lt;code&gt;pr_devel()&lt;/code&gt; e &lt;code&gt;pr_notice()&lt;/code&gt; . Cada uma dessas funções vai printar no console do kernel com alguma cor diferente e uma etiqueta, diferente. Aqui está um exemplo de um pr_emerg:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[ 257.712077] Hello world @ log-level KERN_EMERG [0]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sem mais delongas, para injetar esse codigo ao kernel, primeiro vamos compilar esse arquivo:&lt;br&gt;
&lt;code&gt;make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules&lt;/code&gt;.&lt;br&gt;
Após isso, será gerado o binario chamado hello_world.ko e podemos inserir ele no kernel: &lt;code&gt;sudo dmesg -C &amp;amp;&amp;amp; sudo insmod hellow_world.ko&lt;/code&gt; . &lt;br&gt;
Pronto, inserimos um codigo ao kernel, sem que necessariamente ele estivesse na arvore de codigo do kernel. &lt;/p&gt;

&lt;p&gt;Claro que no futuro, caso desejarmos que esse módulo faça parte da arvore, podemos simplesmente mover ele para dentro da arvore, compilar o kernel e instalar ele na maquina. Mas isso vai ficar para um outro texto.&lt;/p&gt;

&lt;p&gt;Agora se rodarmos o comando &lt;code&gt;sudo dmesg&lt;/code&gt; poderemos ver o log do kernel, com a mensagem "Hello world".&lt;/p&gt;

&lt;p&gt;Pronto, fizemos nosso primeiro modulo para o kernel do Linux. Agora, para removermos esse codigo do kernel, podemos rodar o comando &lt;code&gt;sudo rmmod hello_world&lt;/code&gt; e quando checarmos os logs com &lt;code&gt;sudo dmesg&lt;/code&gt; podemos ver a mensagem "Adeus mundo cruel".&lt;/p&gt;

&lt;p&gt;Agora, somente para efeitos de facilidade, vamos criar um Makefile para esse cara, e automatizar nossa compilação do modulo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;obj+= hello_world.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
Agora quando formos compilar, basta rodar o comando make.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Revisão&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aprendemos que o Kernel Linux pode ser modular, apesar de ser conhecido por ser um kernel monólito.&lt;/li&gt;
&lt;li&gt;Aprendemos como escrever um código extremamente simples e inserir ele no kernel sem que ele esteja realmente na árvore de código do kernel.&lt;/li&gt;
&lt;li&gt;Aprendemos que no espaço do kernel não existe bibliotecas como &lt;code&gt;stdio.h&lt;/code&gt; e precisamos usar as bibliotecas do próprio kernel ou implementar nossas próprias bibliotecas.&lt;/li&gt;
&lt;li&gt;Aprendemos como visualizar os logs do kernel com o comando &lt;code&gt;sudo dmesg&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>lkm</category>
      <category>drivers</category>
    </item>
  </channel>
</rss>
