Este documento apresenta um plano de ensino sobre drivers de dispositivos no Linux, abordando tópicos como introdução a drivers, estruturas de dados, desenvolvimento de um driver simples e interface com o sistema operacional.
8. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
É dada permissão para copiar, distribuir e/ou modificar este documento sob os termos
da Licença de Documentação Livre GNU, Versão 1.1 ou qualquer versão posterior
publicada pela Free Software Foundation; com o Capítulo Invariante SOBRE ESSA
APOSTILA. Uma cópia da licença está inclusa na seção entitulada "Licença de Docu-
mentação Livre GNU".
Os 10 mandamentos do aluno de educação online
• 1. Acesso a Internet: ter endereço eletrônico, um provedor e um equipamento adequado é
pré-requisito para a participação nos cursos a distância.
• 2. Habilidade e disposição para operar programas: ter conhecimentos básicos de Informá-
tica é necessário para poder executar as tarefas.
• 3. Vontade para aprender colaborativamente: interagir, ser participativo no ensino a distân-
cia conta muitos pontos, pois irá colaborar para o processo ensino-aprendizagem pessoal,
dos colegas e dos professores.
• 4. Comportamentos compatíveis com a etiqueta: mostrar-se interessado em conhecer seus
colegas de turma respeitando-os e fazendo ser respeitado pelo mesmo.
• 5. Organização pessoal: planejar e organizar tudo é fundamental para facilitar a sua revisão
e a sua recuperação de materiais.
• 6. Vontade para realizar as atividades no tempo correto: anotar todas as suas obrigações e
realizá-las em tempo real.
• 7. Curiosidade e abertura para inovações: aceitar novas idéias e inovar sempre.
• 8. Flexibilidade e adaptação: requisitos necessário a mudança tecnológica, aprendizagens
e descobertas.
• 9. Objetividade em sua comunicação: comunicar-se de forma clara, breve e transparente é
ponto-chave na comunicação pela Internet.
• 10. Responsabilidade: ser responsável por seu próprio aprendizado. O ambiente virtual não
controla a sua dedicação, mas reflete os resultados do seu esforço e da sua colaboração.
Como participar dos fóruns e Wikipédia
Você tem um problema e precisa de ajuda?
Podemos te ajudar de 2 formas:
A primeira é o uso dos fóruns de notícias e de dúvidas gerais que se distinguem pelo uso:
O fórum de notícias tem por objetivo disponibilizar um meio de acesso rápido a informações
que sejam pertinentes ao curso (avisos, notícias). As mensagens postadas nele são enviadas a
7
9. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
todos participantes. Assim, se o monitor ou algum outro participante tiver uma informação que
interesse ao grupo, favor postá-la aqui.
Porém, se o que você deseja é resolver alguma dúvida ou discutir algum tópico específico do
curso, é recomendado que você faça uso do Fórum de dúvidas gerais que lhe dá recursos mais
efetivos para esta prática.
. O fórum de dúvidas gerais tem por objetivo disponibilizar um meio fácil, rápido e interativo
para solucionar suas dúvidas e trocar experiências. As mensagens postadas nele são enviadas
a todos participantes do curso. Assim, fica muito mais fácil obter respostas, já que todos podem
ajudar.
Se você receber uma mensagem com algum tópico que saiba responder, não se preocupe com a
formalização ou a gramática. Responda! E não se esqueça de que antes de abrir um novo tópico
é recomendável ver se a sua pergunta já foi feita por outro participante.
A segunda forma se dá pelas Wikis:
Uma wiki é uma página web que pode ser editada colaborativamente, ou seja, qualquer par-
ticipante pode inserir, editar, apagar textos. As versões antigas vão sendo arquivadas e podem
ser recuperadas a qualquer momento que um dos participantes o desejar. Assim, ela oferece um
ótimo suporte a processos de aprendizagem colaborativa. A maior wiki na web é o site "Wikipé-
dia", uma experiência grandiosa de construção de uma enciclopédia de forma colaborativa, por
pessoas de todas as partes do mundo. Acesse-a em português pelos links:
• Página principal da Wiki - http://pt.wikipedia.org/wiki/
Agradecemos antecipadamente a sua colaboração com a aprendizagem do grupo!
Primeiros Passos
Para uma melhor aprendizagem é recomendável que você siga os seguintes passos:
• Ler o Plano de Ensino e entender a que seu curso se dispõe a ensinar;
• Ler a Ambientação do Moodle para aprender a navegar neste ambiente e se utilizar das
ferramentas básicas do mesmo;
• Entrar nas lições seguindo a seqüência descrita no Plano de Ensino;
• Qualquer dúvida, reporte ao Fórum de Dúvidas Gerais.
Perfil do Tutor
Segue-se uma descrição do tutor ideal, baseada no feedback de alunos e de tutores.
O tutor ideal é um modelo de excelência: é consistente, justo e profissional nos respectivos
valores e atitudes, incentiva mas é honesto, imparcial, amável, positivo, respeitador, aceita as
idéias dos estudantes, é paciente, pessoal, tolerante, apreciativo, compreensivo e pronto a ajudar.
8
10. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
A classificação por um tutor desta natureza proporciona o melhor feedback possível, é crucial, e,
para a maior parte dos alunos, constitui o ponto central do processo de aprendizagem.’ Este tutor
ou instrutor:
• fornece explicações claras acerca do que ele espera, e do estilo de classificação que irá
utilizar;
• gosta que lhe façam perguntas adicionais;
• identifica as nossas falhas, mas corrige-as amavelmente’, diz um estudante, ’e explica por-
que motivo a classificação foi ou não foi atribuída’;
• tece comentários completos e construtivos, mas de forma agradável (em contraste com um
reparo de um estudante: ’os comentários deixam-nos com uma sensação de crítica, de
ameaça e de nervosismo’)
• dá uma ajuda complementar para encorajar um estudante em dificuldade;
• esclarece pontos que não foram entendidos, ou corretamente aprendidos anteriormente;
• ajuda o estudante a alcançar os seus objetivos;
• é flexível quando necessário;
• mostra um interesse genuíno em motivar os alunos (mesmo os principiantes e, por isso,
talvez numa fase menos interessante para o tutor);
• escreve todas as correções de forma legível e com um nível de pormenorização adequado;
• acima de tudo, devolve os trabalhos rapidamente;
9
12. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
(Traduzido pelo João S. O. Bueno através do CIPSGA em 2001)
Esta é uma tradução não oficial da Licençaa de Documentação Livre GNU em Português
Brasileiro. Ela não é publicada pela Free Software Foundation, e não se aplica legalmente a dis-
tribuição de textos que usem a GFDL - apenas o texto original em Inglês da GNU FDL faz isso.
Entretanto, nós esperamos que esta tradução ajude falantes de português a entenderem melhor
a GFDL.
This is an unofficial translation of the GNU General Documentation License into Brazilian Por-
tuguese. It was not published by the Free Software Foundation, and does not legally state the
distribution terms for software that uses the GFDL–only the original English text of the GFDL does
that. However, we hope that this translation will help Portuguese speakers understand the GFDL
better.
Licença de Documentação Livre GNU Versão 1.1, Março de 2000
Copyright (C) 2000 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
É permitido a qualquer um copiar e distribuir cópias exatas deste documento de licença, mas
não é permitido alterá-lo.
INTRODUÇÃO
O propósito desta Licença é deixar um manual, livro-texto ou outro documento escrito "livre"no
sentido de liberdade: assegurar a qualquer um a efetiva liberdade de copiá-lo ou redistribui-lo,
com ou sem modificações, comercialmente ou não. Secundariamente, esta Licença mantém
para o autor e editor uma forma de ter crédito por seu trabalho, sem ser considerado responsável
pelas modificações feitas por terceiros.
Esta Licença é um tipo de "copyleft"("direitos revertidos"), o que significa que derivações do
documento precisam ser livres no mesmo sentido. Ela complementa a GNU Licença Pública Ge-
ral (GNU GPL), que é um copyleft para software livre.
Nós fizemos esta Licença para que seja usada em manuais de software livre, por que software
livre precisa de documentação livre: um programa livre deve ser acompanhado de manuais que
provenham as mesmas liberdades que o software possui. Mas esta Licença não está restrita a
manuais de software; ela pode ser usada para qualquer trabalho em texto, independentemente
do assunto ou se ele é publicado como um livro impresso. Nós recomendamos esta Licença prin-
cipalmente para trabalhos cujo propósito seja de introdução ou referência.
APLICABILIDADE E DEFINIÇÕES
Esta Licença se aplica a qualquer manual ou outro texto que contenha uma nota colocada pelo
detentor dos direitos autorais dizendo que ele pode ser distribuído sob os termos desta Licença.
11
13. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
O "Documento"abaixo se refere a qualquer manual ou texto. Qualquer pessoa do público é um
licenciado e é referida como "você".
Uma "Versão Modificada"do Documento se refere a qualquer trabalho contendo o documento
ou uma parte dele, quer copiada exatamente, quer com modificações e/ou traduzida em outra
língua.
Uma "Seção Secundária"é um apêndice ou uma seção inicial do Documento que trata ex-
clusivamente da relação dos editores ou dos autores do Documento com o assunto geral do
Documento (ou assuntos relacionados) e não contém nada que poderia ser incluído diretamente
nesse assunto geral (Por exemplo, se o Documento é em parte um livro texto de matemática, a
Seção Secundária pode não explicar nada de matemática).
Essa relação poderia ser uma questão de ligação histórica com o assunto, ou matérias relaci-
onadas, ou de posições legais, comerciais, filosóficas, éticas ou políticas relacionadas ao mesmo.
As "Seções Invariantes"são certas Seções Secundárias cujos títulos são designados, como
sendo de Seções Invariantes, na nota que diz que o Documento é publicado sob esta Licença.
Os "Textos de Capa"são certos trechos curtos de texto que são listados, como Textos de Capa
Frontal ou Textos da Quarta Capa, na nota que diz que o texto é publicado sob esta Licença.
Uma cópia "Transparente"do Documento significa uma cópia que pode ser lida automatica-
mente, representada num formato cuja especificação esteja disponível ao público geral, cujos
conteúdos possam ser vistos e editados diretamente e sem mecanismos especiais com editores
de texto genéricos ou (para imagens compostas de pixels) programas de pintura genéricos ou
(para desenhos) por algum editor de desenhos grandemente difundido, e que seja passível de
servir como entrada a formatadores de texto ou para tradução automática para uma variedade
de formatos que sirvam de entrada para formatadores de texto. Uma cópia feita em um formato
de arquivo outrossim Transparente cuja constituição tenha sido projetada para atrapalhar ou de-
sencorajar modificações subsequentes pelos leitores não é Transparente. Uma cópia que não é
"Transparente"é chamada de "Opaca".
Exemplos de formatos que podem ser usados para cópias Transparentes incluem ASCII sim-
ples sem marcações, formato de entrada do Texinfo, formato de entrada do LaTex, SGML ou XML
usando uma DTD disponibilizada publicamente, e HTML simples, compatível com os padrões, e
projetado para ser modificado por pessoas. Formatos opacos incluem PostScript, PDF, formatos
proprietários que podem ser lidos e editados apenas com processadores de texto proprietários,
SGML ou XML para os quais a DTD e/ou ferramentas de processamento e edição não estejam
disponíveis para o público, e HTML gerado automaticamente por alguns editores de texto com
finalidade apenas de saída.
A "Página do Título"significa, para um livro impresso, a página do título propriamente dita,
mais quaisquer páginas subsequentes quantas forem necessárias para conter, de forma legível,
o material que esta Licença requer que apareça na página do título. Para trabalhos que não
tenham uma página do título, "Página do Título"significa o texto próximo da aparição mais proe-
minente do título do trabalho, precedendo o início do corpo do texto.
12
14. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
FAZENDO CÓPIAS EXATAS
Você pode copiar e distribuir o Documento em qualquer meio, de forma comercial ou não
comercial, desde que esta Licença, as notas de copyright, e a nota de licença dizendo que esta
Licença se aplica ao documento estejam reproduzidas em todas as cópias, e que você não acres-
cente nenhuma outra condição, quaisquer que sejam, às desta Licença.
Você não pode usar medidas técnicas para obstruir ou controlar a leitura ou confecção de
cópias subsequentes das cópias que você fizer ou distribuir. Entretanto, você pode aceitar com-
pensação em troca de cópias. Se você distribuir uma quantidade grande o suficiente de cópias,
você também precisa respeitar as condições da seção 3.
Você também pode emprestar cópias, sob as mesmas condições colocadas acima, e também
pode exibir cópias publicamente.
FAZENDO CÓPIAS EM QUANTIDADE
Se você publicar cópias do Documento em número maior que 100, e a nota de licença do
Documento obrigar Textos de Capa, você precisará incluir as cópias em capas que tragam, clara
e legivelmente, todos esses Textos de Capa: Textos de Capa da Frente na capa da frente, e
Textos da Quarta Capa na capa de trás. Ambas as capas também precisam identificar clara e
legivelmente você como o editor dessas cópias. A capa da frente precisa apresentar o titulo com-
pleto com todas as palavras do título igualmente proeminentes e visíveis. Você pode adicionar
outros materiais às capas. Fazer cópias com modificações limitadas às capas, tanto quanto estas
preservem o título do documento e satisfaçam a essas condições, pode ser tratado como cópia
exata em outros aspectos.
Se os textos requeridos em qualquer das capas for muito volumoso para caber de forma
legível, você deve colocar os primeiros (tantos quantos couberem de forma razoável) na capa
verdadeira, e continuar os outros nas páginas adjacentes.
Se você publicar ou distribuir cópias Opacas do Documento em número maior que 100, você
precisa ou incluir uma cópia Transparente que possa ser lida automaticamente com cada cópia
Opaca, ou informar, em ou com, cada cópia Opaca a localização de uma cópia Transparente
completa do Documento acessível publicamente em uma rede de computadores, a qual o público
usuário de redes tenha acesso a download gratuito e anônimo utilizando padrões públicos de
protocolos de rede. Se você utilizar o segundo método, você precisará tomar cuidados razoavel-
mente prudentes, quando iniciar a distribuição de cópias Opacas em quantidade, para assegurar
que esta cópia Transparente vai permanecer acessível desta forma na localização especificada
por pelo menos um ano depois da última vez em que você distribuir uma cópia Opaca (direta-
mente ou através de seus agentes ou distribuidores) daquela edição para o público.
É pedido, mas não é obrigatório, que você contate os autores do Documento bem antes de
redistribuir qualquer grande número de cópias, para lhes dar uma oportunidade de prover você
com uma versão atualizada do Documento.
13
15. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
MODIFICAÇÕES
Você pode copiar e distribuir uma Versão Modificada do Documento sob as condições das se-
ções 2 e 3 acima, desde que você publique a Versão Modificada estritamente sob esta Licença,
com a Versão Modificada tomando o papel do Documento, de forma a licenciar a distribuição
e modificação da Versão Modificada para quem quer que possua uma cópia da mesma. Além
disso, você precisa fazer o seguinte na versão modificada:
A. Usar na Página de Título (e nas capas, se houver alguma) um título distinto daquele do Do-
cumento, e daqueles de versões anteriores (que deveriam, se houvesse algum, estarem listados
na seção "Histórico do Documento"). Você pode usar o mesmo título de uma versão anterior se
o editor original daquela versão lhe der permissão;
B. Listar na Página de Título, como autores, uma ou mais das pessoas ou entidades responsá-
veis pela autoria das modificações na Versão Modificada, conjuntamente com pelo menos cinco
dos autores principais do Documento (todos os seus autores principais, se ele tiver menos que
cinco);
C. Colocar na Página de Título o nome do editor da Versão Modificada, como o editor;
D. Preservar todas as notas de copyright do Documento;
E. Adicionar uma nota de copyright apropriada para suas próprias modificações adjacente às
outras notas de copyright;
F. Incluir, imediatamente depois das notas de copyright, uma nota de licença dando ao público
o direito de usar a Versão Modificada sob os termos desta Licença, na forma mostrada no tópico
abaixo;
G. Preservar nessa nota de licença as listas completas das Seções Invariantes e os Textos de
Capa requeridos dados na nota de licença do Documento;
H. Incluir uma cópia inalterada desta Licença;
I. Preservar a seção entitulada "Histórico", e seu título, e adicionar à mesma um item dizendo
pelo menos o título, ano, novos autores e editor da Versão Modificada como dados na Página de
Título. Se não houver uma sessão denominada "Histórico"no Documento, criar uma dizendo o
título, ano, autores, e editor do Documento como dados em sua Página de Título, então adicionar
um item descrevendo a Versão Modificada, tal como descrito na sentença anterior;
J. Preservar o endereço de rede, se algum, dado no Documento para acesso público a uma
cópia Transparente do Documento, e da mesma forma, as localizações de rede dadas no Docu-
mento para as versões anteriores em que ele foi baseado. Elas podem ser colocadas na seção
"Histórico". Você pode omitir uma localização na rede para um trabalho que tenha sido publicado
pelo menos quatro anos antes do Documento, ou se o editor original da versão a que ela se refira
der sua permissão;
K. Em qualquer seção entitulada "Agradecimentos"ou "Dedicatórias", preservar o título da
14
16. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
seção e preservar a seção em toda substância e fim de cada um dos agradecimentos de contri-
buidores e/ou dedicatórias dados;
L. Preservar todas as Seções Invariantes do Documento, inalteradas em seus textos ou em
seus títulos. Números de seção ou equivalentes não são considerados parte dos títulos da seção;
M. Apagar qualquer seção entitulada "Endossos". Tal sessão não pode ser incluída na Versão
Modificada;
N. Não reentitular qualquer seção existente com o título "Endossos"ou com qualquer outro
título dado a uma Seção Invariante.
Se a Versão Modificada incluir novas seções iniciais ou apêndices que se qualifiquem como
Seções Secundárias e não contenham nenhum material copiado do Documento, você pode optar
por designar alguma ou todas aquelas seções como invariantes. Para fazer isso, adicione seus
títulos à lista de Seções Invariantes na nota de licença da Versão Modificada. Esses títulos preci-
sam ser diferentes de qualquer outro título de seção.
Você pode adicionar uma seção entitulada "Endossos", desde que ela não contenha qual-
quer coisa além de endossos da sua Versão Modificada por várias pessoas ou entidades - por
exemplo, declarações de revisores ou de que o texto foi aprovado por uma organização como a
definição oficial de um padrão.
Você pode adicionar uma passagem de até cinco palavras como um Texto de Capa da Frente
, e uma passagem de até 25 palavras como um Texto de Quarta Capa, ao final da lista de Textos
de Capa na Versão Modificada. Somente uma passagem de Texto da Capa da Frente e uma de
Texto da Quarta Capa podem ser adicionados por (ou por acordos feitos por) qualquer entidade.
Se o Documento já incluir um texto de capa para a mesma capa, adicionado previamente por
você ou por acordo feito com alguma entidade para a qual você esteja agindo, você não pode
adicionar um outro; mas você pode trocar o antigo, com permissão explícita do editor anterior que
adicionou a passagem antiga.
O(s) autor(es) e editor(es) do Documento não dão permissão por esta Licença para que seus
nomes sejam usados para publicidade ou para assegurar ou implicar endossamento de qualquer
Versão Modificada.
COMBINANDO DOCUMENTOS
Você pode combinar o Documento com outros documentos publicados sob esta Licença, sob
os termos definidos na seção 4 acima para versões modificadas, desde que você inclua na com-
binação todas as Seções Invariantes de todos os documentos originais, sem modificações, e liste
todas elas como Seções Invariantes de seu trabalho combinado em sua nota de licença.
O trabalho combinado precisa conter apenas uma cópia desta Licença, e Seções Invariantes
Idênticas com multiplas ocorrências podem ser substituídas por apenas uma cópia. Se houver
múltiplas Seções Invariantes com o mesmo nome mas com conteúdos distintos, faça o título de
15
17. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
cada seção único adicionando ao final do mesmo, em parênteses, o nome do autor ou editor
origianl daquela seção, se for conhecido, ou um número que seja único. Faça o mesmo ajuste
nos títulos de seção na lista de Seções Invariantes nota de licença do trabalho combinado.
Na combinação, você precisa combinar quaisquer seções entituladas "Histórico"dos diver-
sos documentos originais, formando uma seção entitulada "Histórico"; da mesma forma combine
quaisquer seções entituladas "Agradecimentos", ou "Dedicatórias". Você precisa apagar todas as
seções entituladas como "Endosso".
COLETÂNEAS DE DOCUMENTOS
Você pode fazer uma coletânea consitindo do Documento e outros documentos publicados
sob esta Licença, e substituir as cópias individuais desta Licença nos vários documentos com
uma única cópia incluida na coletânea, desde que você siga as regras desta Licença para cópia
exata de cada um dos Documentos em todos os outros aspectos.
Você pode extrair um único documento de tal coletânea, e distribuí-lo individualmente sob
esta Licença, desde que você insira uma cópia desta Licença no documento extraído, e siga esta
Licença em todos os outros aspectos relacionados à cópia exata daquele documento.
AGREGAÇÃO COM TRABALHOS INDEPENDENTES
Uma compilação do Documento ou derivados dele com outros trabalhos ou documentos se-
parados e independentes, em um volume ou mídia de distribuição, não conta como uma Ver-
são Modificada do Documento, desde que nenhum copyright de compilação seja reclamado pela
compilação. Tal compilação é chamada um "agregado", e esta Licença não se aplica aos outros
trabalhos auto-contidos compilados junto com o Documento, só por conta de terem sido assim
compilados, e eles não são trabalhos derivados do Documento.
Se o requerido para o Texto de Capa na seção 3 for aplicável a essas cópias do Documento,
então, se o Documento constituir menos de um quarto de todo o agregado, os Textos de Capa
do Documento podem ser colocados em capas adjacentes ao Documento dentro do agregado.
Senão eles precisarão aparecer nas capas de todo o agregado.
TRADUÇÃO
Tradução é considerada como um tipo de modificação, então você pode distribuir traduções
do Documento sob os termos da seção 4. A substituição de Seções Invariantes por traduções
requer uma permissão especial dos detentores do copyright das mesmas, mas você pode incluir
traduções de algumas ou de todas as Seções Invariantes em adição às versões orignais dessas
Seções Invariantes. Você pode incluir uma tradução desta Licença desde que você também in-
clua a versão original em Inglês desta Licença. No caso de discordância entre a tradução e a
16
18. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
versão original em Inglês desta Licença, a versão original em Inglês prevalecerá.
TÉRMINO
Você não pode copiar, modificar, sublicenciar, ou distribuir o Documento exceto como expres-
samente especificado sob esta Licença. Qualquer outra tentativa de copiar, modificar, sublicen-
ciar, ou distribuir o Documento é nula, e resultará automaticamente no término de seus direitos
sob esta Licença. Entretanto, terceiros que tenham recebido cópias, ou direitos de você sob esta
Licença não terão suas licenças terminadas, tanto quanto esses terceiros permaneçam em total
acordo com esta Licença.
REVISÕES FUTURAS DESTA LICENÇA
A Free Software Foundation pode publicar novas versões revisadas da Licença de Documen-
tação Livre GNU de tempos em tempos. Tais novas versões serão similares em espirito à versão
presente, mas podem diferir em detalhes ao abordarem novos porblemas e preocupações. Veja
http://www.gnu.org/copyleft/.
A cada versão da Licença é dado um número de versão distinto. Se o Documento especificar
que uma versão particular desta Licença "ou qualquer versão posterior"se aplica ao mesmo, você
tem a opção de seguir os termos e condições daquela versão específica, ou de qualquer versão
posterior que tenha sido publicada (não como rascunho) pela Free Software Foundation. Se o
Documento não especificar um número de Versão desta Licença, você pode escolher qualquer
versão já publicada (não como rascunho) pela Free Software Foundation.
ADENDO: Como usar esta Licença para seus documentos
Para usar esta Licença num documento que você escreveu, inclua uma cópia desta Licença
no documento e ponha as seguintes notas de copyright e licenças logo após a página de título:
Copyright (c) ANO SEU NOME.
É dada permissão para copiar, distribuir e/ou modificar este documento sob os termos da Licença
de Documentação Livre GNU, Versão 1.1 ou qualquer versão posterior publicada pela Free Soft-
ware Foundation; com as Seções Invariantes sendo LISTE SEUS TÍTULOS, com os Textos da
Capa da Frente sendo LISTE, e com os Textos da Quarta-Capa sendo LISTE. Uma cópia da li-
cença está inclusa na seção entitulada "Licença de Documentação Livre GNU".
Se você não tiver nenhuma Seção Invariante, escreva "sem Seções Invariantes"ao invés de
dizer quais são invariantes. Se você não tiver Textos de Capa da Frente, escreva "sem Textos de
Capa da Frente"ao invés de "com os Textos de Capa da Frente sendo LISTE"; o mesmo para os
Textos da Quarta Capa.
Se o seu documento contiver exemplos não triviais de código de programas, nós recomenda-
mos a publicação desses exemplos em paralelo sob a sua escolha de licença de software livre,
17
19. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
tal como a GNU General Public License, para permitir o seu uso em software livre.
18
21. Capítulo 1
Driver de Dispositivo Linux
Drivers de dispositivo são a interface necessária entre o sistema operacional e o hardware do seu
computador. Drivers são responsáveis por controlar de forma correta os dispositivos e esconder
do próprio sistema operacional os detalhes de baixo nível.
20
22. Capítulo 2
Plano de ensino
2.1 Objetivo
Capacitar o usuário para o desenvolviemento de drivers de dispositivo para o Kernel 2.6.x do
SO GNU/Linux.
2.2 Público Alvo
Técnicos e Programadores com experiência em programação usando C que desejam um
caminho para criar os próprios drivers de dispositivo.
2.3 Pré-requisitos
É necessário sólido conhecimento em lógica de programação e familiaridade com a linguagem
C, além de domínio do SO GNU/Linux.
2.4 Descrição
O curso de Driver de Dispositivo Linux será realizado na modalidade EAD e utilizará a plata-
forma Moodle como ferramenta de aprendizagem. O material didático estará disponível on-line
de acordo com as datas pré-estabelecidas no calendário. A versão utilizada para o Kernel do
Linux será a 2.6.18; O curso está dividido da seguinte maneira:
2.5 Cronograma
• Introdução;
• Interface SO<->driver.
• Código de exemplo.
• Estruturas do dispositivo.
• Aprimoração do driver exemplo
21
23. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
• Alocação e manipulação de memória
• Finalização do driver exemplo
As lições contém o contéudo principal. Elas poderão ser acessadas quantas vezes forem neces-
sárias, desde que esteja dentro da semana programada. Ao final de uma lição, você receberá
uma nota de acordo com o seu desempenho. Responda com atenção às perguntas de cada lição,
pois elas serão consideradas na sua nota final. Caso sua nota numa determinada lição for menor
do que 6.0, sugerimos que você faça novamente esta lição.
Ao final do curso será disponibilizada a avaliação referente ao curso. Tanto as notas das lições
quanto a da avaliação serão consideradas para a nota final. Todos os módulos ficarão visíveis
para que possam ser consultados durante a avaliação final.
Aconselhamos a leitura da "Ambientação do Moodle"para que você conheça a plataforma de
Ensino a Distância, evitando dificuldades advindas do "desconhecimento"sobre a mesma.
Os instrutores estarão a sua disposição ao longo de todo curso. Qualquer dúvida deverá ser
enviada no fórum. Diariamente os monitores darão respostas e esclarecimentos.
2.6 Programa
O curso de Driver de Dispositivo Linux oferecerá o seguinte conteúdo:
• Estudo das estruturas do kernel
• Estudo das áreas de memória
• Estudo da criação de arquivos de dispositivo
• Programação em C dos drivers de exemplo
2.7 Avaliação
Toda a avaliação será feita on-line.
Aspectos a serem considerados na avaliação:
• Iniciativa e autonomia no processo de aprendizagem e de produção de conhecimento;
• Capacidade de pesquisa e abordagem criativa na solução dos problemas apresentados.
Instrumentos de avaliação:
• Participação ativa nas atividades programadas.
• Avaliação ao final do curso.
• O participante fará várias avaliações referente ao conteúdo do curso. Para a aprovação e
obtenção do certificado o participante deverá obter nota final maior ou igual a 6.0 de acordo
com a fórmula abaixo:
• Nota Final = ((ML x 7) + (AF x 3)) / 10 = Média aritmética das lições
• AF = Avaliações
22
24. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
2.8 Bibliografia
• The Linux Kernel: http://www.kernel.org
• LinuxDevCenter: http://www.linuxdevcenter.com
23
25. Capítulo 3
Introdução
O que são drivers de dispositivo e como eles funcionam? Quais os tipos de driver de disposi-
tivo? Como funciona a interação do sistema operacional com o driver?
3.1 Driver de Dispositivo?
Quando um programa precisa fazer um acesso a sua impressora para imprimir qualquer coisa,
é utilizado um device driver. Sem um desses, o programa necessitaria de acesso direto a im-
pressora e, pior ainda, teria que saber exatamente como o controlador físico dessa impressora
funciona. Isso provavelmente ficaria ainda pior: todo programa que fosse imprimir funcionaria so-
mente para uma impressora ou teria que saber como funcionam todas as impressoras do mundo,
além de saber como identificá-las. Certamente, isso é inviável.
Device drivers fornecem um nível de abstração para o desenvolvimento de programas que
necessitam acesso a um dispositivo físico. Isso quer dizer que, ao invés de embutir em todos
os programas o código para controlar a impressora X, simplesmente chamo uma função (por
exemplo, print()) em meu programa e o sistema operacional se encarrega de procurar nos drivers
carregados o código correspondente, e delega a essa porção de código a responsabilidade pelo
controle da impressora. Se amanhã eu decidir que preciso de uma impressora Y e não mais da
X, basta instalar os drivers da impressora Y e nada mais precisará de alteração.
Assim funciona com basicamente tudo: discos, mouses, teclados, placas de vídeo, etc. Ge-
ralmente você precisa identificá-los somente uma vez, e o sistema operacional se encarrega de
encontrar os drivers corretos e esse sim é responsável pelo controle adequado do hardware.
Na maioria dos sistemas operacionais, os device drivers mais importantes (também os mais
genéricos) e utilizados em grande escala pelo computador geralmente estão compilados dentro
do kernel (núcleo do sistema), e os utilizados com menos freqüência ou que não exigem demanda
muito grande são carregados como módulos. Também são módulos os drivers que não estão
disponíveis inicialmente pelo sistema operacional - drivers disponibilizados por terceiros ou os
que você criar.
Drivers devem ser programados e tratados cuidadosamente: um código destinado a ser driver
de dispositivo funcionará com permissão ao hardware e ao sistema em si, podendo danificá-los
seriamente.
A maior parte do curso será abordada dentro do sistema operacional GNU/Linux, pois, pela
característica de ser código aberto, possui a transparência necessária para o processo de criação
de device drivers.
24
26. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
3.2 Tipos de Dispositivos
Basicamente os dispositivos de hardware são separados da seguinte forma: dispositivos de
caractere e dispositivos de bloco (Character device e Block device, respectivamente; há ainda
os dispositivos de rede que possuem características diferentes e não serão abordados por en-
quanto). A diferença entre eles é que o acesso aos dados de um dispositivo de caractere é
seqüencial, enquanto nos dispositivos de bloco o acesso geralmente é aleatório.
Isso é, um dispositivo de caractere é tão rápido quanto possível para escrever e ler dados
do seu hardware e portanto não precisa de um buffer (o dispositivo em si não trabalha com um
buffer). Uma outra característica de um dispositivo seqüencial é que não é possível ’retroceder’ a
posição dos dados (na verdade, não faz o menor sentido). São dispositivos de streamming. Um
bom exemplo de um dispositivo de caractere é o teclado: não faz sentido, via hardware, "ler a tecla
que foi digitada 10 teclas atrás", mas no entanto cada tecla pressionada é imediatamente enviada
ao sistema operacional. Dispositivos de caracteres também têm esse nome pois geralmente o
acesso é feito "um caractere (1 byte)"por vez.
Já num dispositivo de bloco, por sua característica de acesso aleatório, é imprescindível o uso
de um buffer. Na verdade, enquanto um programa utiliza um dispositivo de bloco, ele pode até
ter a impressão que está lendo e escrevendo diretamente no dispositivo (como faria normalmente
em um dispositivo de caractere), mas, na verdade, está realizando tais operações no buffer do
dispositivo e esse, por sua vez, se encarrega de fazer a mudança fisicamente, na hora certa.
Analisando o seu disco rígido é fácil chegar a conclusão de que ele é um dispositivo de bloco,
pois você pode acessar dados que estão em partes diferentes do disco. Se o acesso ao disco
fosse seqüencial, essa operação seria simplesmente impossível. Uma outra razão para que seja
chamado dispositivo de blocos é que o acesso ao dispositivo é feito em blocos de dados (512
bytes, por exemplo).
No entanto, para a maioria dos usuários do Linux/Unix, não faz diferença se o dispositivo é de
bloco ou de caractere: é possível ler e escrever nesse dispositivo como se ele fosse um arquivo
qualquer. A distinção de que tipo de dispositivo e como ler e escrever nele fica por conta do
sistema operacional e do driver.
3.3 Interface do Driver com o Sistema Operacional
mesma forma que o sistema operacional cria a possibilidade de um programa imprimir utili-
zando a simples função print(), um device driver deve possibilitar o sistema operacional controlar
essa mesma impressora utilizando uma função como control_printer(), independente da impres-
sora. Isso quer dizer que o SO não se importa se você vai usar uma impressora da marca X ou
Y, ele simplesmente vai chamar a função control_printer(), e o seu device driver deve responder a
essa chamada de função da mesma forma que o sistema operacional responde à função print() do
programa. Em outros termos, enquanto o device driver é a implementação virtual da impressora,
a função control_printer() é a sua interface com o sistema operacional. Para dar mais um realce
à idéia de interface e implementação: se hoje você utiliza discos SCSI e amanhã decidir utilizar
discos IDE, a única mudança é o driver que será carregado. O Sistema operacional continuará
chamando as mesmas funções de acesso ao disco.
Sendo um pouco mais exato, cada device driver deve implementar uma struct cujos seus
elementos são os ponteiros para as funções de controle, e o kernel, quando carrega esse driver,
registra essa struct na memória. Assim que o driver é efetivamente carregado, o kernel chama a
função de inicialização. O trabalho da função de inicialização consiste em registrar o dispositivo
25
27. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
na tabela de dispositivos e dar a ele a identificação necessária, além de inicializar outras structs
que o driver vai utilizar. Na utilização do dispositivo, o kernel chama as funções de controle,
leitura e escrita disponibilizadas. Quando o driver é descarregado, o kernel chama a função de
finalização, responsável por desregistrar o dispositivo no sistema e limpar da memória. Vamos
ver tudo isso com mais detalhes, pode ficar tranqüilo :)
26
28. Capítulo 4
Hello Kernel!
Um Driver simples e que não faz nada!
4.1 Kello Hernell!
Para exemplificar a interface do sistema operacional com o driver, vamos criar um "Hello Ker-
nel". O driver não faz nada de muito importante, só exibe uma mensagem quando é carregado e
outra quando é descarregado.
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ »¶ Ú Ø Ö
Ð Ñ
Ó × ÖÒ Ð ¶»
×Ø Ø
ÒØ ÐÐÓ ´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ Ã ÐÐÓ¸ À ÖÒ Ð ℄ Ò µ
»¶ Ó × × ÕÙ Þ Ñ Ó× Ö Ú Ö× ×ÔÓ× Ø ÚÓ× ¶»
Ö ØÙÖÒ ¼
×Ø Ø
ÚÓ Ý ´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ Ý ¸ Ã ÖÒ Ð Ò µ
ÑÓ ÙÐ Ò Ø´ ÐÐÓ µ
ÑÓ ÙÐ Ü Ø´ Ý µ
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
4.2 Como funciona?
Dissecando o nosso módulo (que não tem muito o que ser dissecado, na verdade), encontra-
mos algumas coisas parecidas com programas normais, outras, nem tanto. A primeira coisa a ser
notada são os arquivos de include: nada de stdio.h nem string.h. Entretanto, temos <linux/init.h>
e <linux/module.h>. Esses dois cabeçalhos devem aparecer em todos os módulos carregáveis.
<linux/module.h> tem muitas definições importantes e símbolos utilizados em módulos e init.h
27
29. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
disponibiliza module_init e module_exit, além de outras coisas. Drivers geralmente utilizam muito
mais includes, mas esses você vai encontrar em qualquer um deles.
Você provavelmente deve ter percebido que não temos uma função main(). Ao invés dela
existem as chamadas macros module_init e module_exit, que recebe como parâmetros, respec-
tivamente, as funções de inicialização e de saída do módulo. Quando o driver for carregado,
ele chama a função registrada por module_init e quando descarregar, a função registrada em
module_exit.
Para imprimir na tela, temos uma função que engana. Parece muito a velha conhecida printf.
No entanto, printk é uma função controlada unicamente pelo kernel, pois esse não pode de-
pender de funções disponibilizadas por bibliotecas que podem não estar presentes no futuro (se
utilizássemos printf, nosso módulo dependeria da presença da libc, que muito provavelmente não
estará disponível). Outras características que diferem printk de printf (além de trocar f por k): o
argumento de urgência (KERN_ALERT, que é definida como <1>. Quanto maior o número entre
<>, menor a prioridade. Dependendo do valor, a mensagem pode nem mesmo ser exibida) que
vem antes da string que será exibida. Outra é que printk não suporta números de ponto flutuante
(float).
A diferença mais importante de um módulo para um programa comum é que módulos são
orientados ao evento. Em outras palavras, enquanto o seu programa favorito abre, executa o que
tem que executar e depois sai, um módulo é carregado no kernel informando o que sabe fazer e
com quem. Depois disso não faz mais nada. Fica lá, parado, junto com um monte de módulos,
esperando ordens que podem aparecer ou não.
Para compilar esse módulo é necessário um pouco mais de trabalho. Primeiramente, para
kernels da versão 2.6.x, você vai precisar dos fontes do kernel instalados e compilados. Em
versões 2.4.x, apenas os headers do kernel eram necessários.
Vai ser necessário criar um makefile um pouco diferente dos padrões para que a compilação
funcione. O kernel tem seu próprio ’jeitinho’ de utilizar makefiles, chamado kbuild.
Por hora, nosso Makefile vai se parecer com isso
¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
Ó ¹Ñ ÐÐÓ ÖÒ ÐºÓ
¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
Esse makefile deve estar no mesmo diretório do código do seu módulo. Compile-o da seguinte
forma:
make -C /caminho/do/fonte/linux M=‘pwd‘ modules
(Digite esse comando dentro da pasta que está o seu makefile e o seu módulo) No final, você
vai ter um arquivo do formato hellokernel.ko.
Carregue o módulo utilizando o comando insmod hellokernel.ko, e o descarregue com rmmod
hellokernel.ko. Se tudo correu bem, o driver vai exibir as respectivas mensagens que programa-
mos.
28
30. Capítulo 5
Arquivos de Dispositivo
Acesso aos dispositivos via os arquivos do /dev. Arquivos de dispositivos? Como assim?
5.1 Tudo é um arquivo!
"No Linux, tudo é um arquivo". Essa é a máxima da maioria dos usuários do Linux. Enquanto
outros sistemas operacionais mais populares representam dispositivos de armazenamento por
letras e "escondem"a localização dos outros dispositivos (e como eles são controlados), no sis-
tema operacional do pingüim todos os dispositivos tem uma correspondência no diretório /dev
(com exceção das interfaces de rede), onde são, de fato, arquivos. Sendo assim, você pode
testar o comando _ echo "Oi dispositivo!» /dev/tty1 _ e dependendo de onde você utilizar esse
comando, aparecerá na sua tela a mensagem "Oi dispositivo!"(/dev/tty* são dispositivos de termi-
nais). Quem provê esse tipo de praticidade é em parte o sistema operacional e em parte o seu
driver de dispositivo. Quando você chama o comando "echo"com redirecionamento de saída (>)
para um arquivo de dispositivo, o sistema operacional logo descobre qual é o driver que o controla
e envia a mensagem a ele.
Talvez você se pergunte agora: "como o sistema operacional vai descobrir qual driver controla
aquele dispositivo?". Ou, pior, como o SO sabe que tipo de arquivo é esse? Por que é um
dispositivo? Se você já utilizou alguma vez o comando mknod, deve lembrar-se que ele cria a
representação (em forma de arquivo) para os dispositivos.
Analisemos o comando com um exemplo: Ñ ÒÓ » Ú»Ñ Ù ×ÔÓ× Ø ÚÓ
¼ ¼
O primeiro parâmetro obviamente é o nome do arquivo que representará o dispositivo. O
parâmetro c diz que está sendo criado um dispositivo de caractere. O que nos interessa agora
são os dois números subseqüentes, 60 e 0. O 60 seria o "major number"e 0 o "minor number".
Major/minor numbers são utilizados como a identidade virtual do hardware. Junto com o tipo de
dispositivo (no nosso caso, um dispositivo de caractere indicado com o parâmetro ’c’) e com esses
números, o sistema operacional é capaz de identificar qual driver está controlando o dispositivo
e faz a ligação entre eles dois. Vários dispositivos podem utilizar o mesmo major number (indi-
cando assim que são controlados pelo mesmo driver), mas cada um deles tem um minor number
único. Sendo um pouco mais claro, major numbers identificam para o sistema operacional, qual
dispositivo controla aquele hardware e minor numbers identificam para o driver qual a variação
que aquele hardware possui, para que esse possa adequar-se. Eu sei que vou acabar repetindo
isso em algum ponto do curso. Se você não entendeu muito bem, continue lendo. Lembre-se
que os números de dispositivo indicam apenas qual driver está controlando aquele hardware, e
não o seu tipo. Isso significa que um mesmo driver pode controlar todos os tipos de dispositivos
29
31. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
do mundo: vai saber diferenciá-los pelo minor number. Obviamente que isso é uma tática sem
sentido (para não dizer burra). O módulo seria um bloco gigantesco de código e muito lento, sem
contar que, se eu preciso controlar as LEDs do meu gabinete, é praticamente uma piada carregar
os controladores de um mouse.
O driver por sua vez, quando é carregado na memória deve passar o major number do dis-
positivo e quantos minor numbers ele pretende controlar, e o kernel registrará na sua tabela de
dispositivos aquele driver. Dessa forma, o SO "casa"o arquivo de dispositivo com o seu driver. O
tcl é muito útil para quem quer manipular string, ele oferece uma vasta quantidade de comandos
para esse fim, como nosso curso é apenas uma introdução à linguagem não abordaremos todos
os comandos.
5.2 Major e Minor Numbers
A representação de major e minor numbers dentro do kernel fica por conta de um tipo de dado
declarado em linux/types.h. É o tipo dev_t que, na verdade, é um espaço de 32 bits onde 12 bits
são reservados para major numbers e os 20 bits restantes são reservados para minor numbers.
As macros/funções que trabalham com o tipo dev_t estão no cabeçalho linux/kdev_t.h. As mais
importantes para o esse momento no curso são MAJOR, MINOR e MKDEV.
MAJOR e MINOR retornam major e minor numbers, respectivamente, de uma dada variável
do tipo dev_t. MKDEV faz o contrário. Sabendo o major e o minor number, ele constrói a estrutura
e a retorna no formato de dev_t.
MAJOR(dev_t dev); MINOR(dev_t dev); MKDEV(int major, int minor);
Ex: dev_t dev = MKDEV(60, 0); int major = MAJOR(dev); int minor = MINOR(dev);
Como dito anteriormente, cada device driver deve declarar major e minor numbers que vai
controlar. Existem duas formas de fazer isso, com funções prototipadas em linux/fs.h. A primeira
é usar a função register_chrdev_region para drivers de caractere, que tem essa cara:
int register_chrdev_region(dev_t first, unsigned int count, char *name);
first é o nosso número de dispositivo (que pode ter sido criado com MKDEV, por exemplo).
Geralmente, mas não necessariamente, o minor number em first é 0. count é a quantidade de
devices que o driver controla; isso é, quantos minor numbers ele vai utilizar. name é o nome do
dispositivo que vai aparecer em /proc/devices. Não confunda isso com o nome em /dev. Quem
controla isso é o comando mknod. A função retorna 0 se tudo correr bem, e qualquer outro
número se houver algum erro. A desvantagem dessa função é que o controle sobre os números
é precário: você pode pedir números já alocados. Para contornar essa situação, existe uma
função de alocação dinâmica de números de dispositivos. A função tem esse protótipo:
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
dev deve ser um ponteiro do tipo dev_t, onde será armazenado o resultado da alocação dos
números de dispositivo. firstminor é o primeiro minor a ser utilizado. Os outros parâmetros são
iguais aos de register_chrdev_region. A grande utilidade dessa função é que a probabilidade
de colisão de números é pouca, pois retorna o primeiro número de dispositivo não utilizado.
No entanto, isso torna mais difícil a utilização do comando mknod, pois você deve buscar em
/proc/devices o número para utilizar.
Uma dessas funções (register_chrdev_region ou alloc_chrdev_region) deve estar na sua fun-
ção de inicialização. Quando o device driver for descarregado, a função unregister_chrdev_region
deve estar presente na função de finalização.
unregister_chrdev_region tem esse protótipo:
void unregister_chrdev_region(dev_t first, unsigned int count);
30
32. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
Os parâmetros first e count são os mesmos de register_chrdev_region. Vale lembrar que
essas funções são para drivers de caractere. As funções de driver de bloco têm um jeito muito
parecido.
Já dá para deixar nosso módulo um pouquinho mais interessante.
kernumbers.c
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
Ò
ÐÙ Ð ÒÙÜ»ØÝÔ ×º
Ò
ÐÙ Ð ÒÙÜ» Ú Øº
Ò
ÐÙ Ð ÒÙÜ» ׺
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ »¶ Ú Ø Ö
Ð Ñ
Ó × ÖÒ Ð ¶»
»¶ Î Ö Ú × ÐÓ × ×× ÖÕÙ ÚÓº ÈÓ ÑÓ× ÔÖ
× Ö Ð × Ñ × Ø Ö ¶»
×Ø Ø
ÒØ Ñ ÓÖ
×Ø Ø
Ú Ø Ú
×Ø Ø
ÒØ ÐÐÓ ´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ Ã ÐÐÓ¸ À ÖÒ Ð ℄ Ò µ
»¶ Ê ×ØÖ ÙÑ Ö Ú Ö
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö×
ÓÑ Ó ÒÓÑ Ö Ú Ö ¶»
´ ÐÐÓ
Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ Ö Ú Ö µµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
Ò Ó Ó× Ò Ñ ÖÓ× Ö Ú Ö Ò µ
Ü Ø´½µ
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
»¶ ÇÙØÖ ×
Ó × × ÕÙ Þ Ñ Ó× Ö Ú Ö× ×ÔÓ× Ø ÚÓ× ¶»
Ö ØÙÖÒ ¼
×Ø Ø
ÚÓ Ý ´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ Ý ¸ Ã ÖÒ Ð Ò µ
»¶ ×Ö ×ØÖ Ó ÒÓ××Ó Ö Ú Ö ¶»
ÙÒÖ ×Ø Ö
Ö Ú Ö ÓÒ´² Ú¸ ¿µ
ÑÓ ÙÐ Ò Ø´ ÐÐÓ µ
ÑÓ ÙÐ Ü Ø´ Ý µ
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
O código é auto-explicativo. O Makefile deve ser alterado de acordo com o novo nome do
módulo. Para verificar se está tudo ok, você pode dar uma olhada no arquivo /proc/devices e
/proc/modules:
Ø »ÔÖÓ
»ÑÓ ÙÐ × Ö Ô ÖÒÙÑ Ö× e
Ø »ÔÖÓ
» Ú
× Ö Ô Ö Ú Ö
O primeiro deve mostrar o seu módulo na lista de módulos carregados e o segundo mostra o nú-
mero utilizado pelo seu "dispositivo".
31
33. Capítulo 6
Estruturas
As estruturas mais importantes para um driver de dispositivo: filp, fops e inode.
6.1 File Operations
6.1.1 Introdução
Até agora foi a parte fácil da implementação de um driver de dispositivo. Se você queria saber
apenas como funcionam os módulos, pode parar por aqui, pois a partir de agora a gente entra
na parte em que o curso fica interessante (e complicado). Vamos levar o nosso driver um pouco
mais a sério: implementaremos a estrutura de operações de arquivo. No entanto, o nosso driver
vai fazer todas as operações num dispositivo de caractere "fictício".
Como já dito, quando o driver é carregado na memória, além de registrar major e minor num-
bers, ele deve registrar a estrutura de operações de arquivo referente ao driver (lembre-se que
mesmo os dispositivos são representados como arquivos no linux e por isso precisam declarar
quais operações estão disponíveis para esse arquivo). A definição dessas estruturas estão em
<linux/fs.h>.
Mesmo que o parágrafo acima não tenha ficado muito claro, tudo fica mais óbvio quando
temos um pedaço de código para analisar, certo? Enfim chega de bate-papo. Vamos dar uma
boa olhada na estrutura de operações de arquivo. É uma das mais importantes.
6.1.2 Fops
Esta é a famosa "fops (file operations)":
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ß
×ØÖÙ
Ø ÑÓ ÙÐ ¶ÓÛÒ Ö
ÐÓ Ø ´¶ÐÐ× µ ´×ØÖÙ
Ø Ð ¶¸ ÐÓ Ø¸ Òص
×× Þ Ø ´¶Ö µ ´×ØÖÙ
Ø Ð ¶¸
Ö Ù× Ö ¶¸ × Þ Ø¸ ÐÓ Ø ¶µ
×× Þ Ø ´¶ÛÖ Ø µ ´×ØÖÙ
Ø Ð ¶¸
ÓÒ×Ø
Ö Ù× Ö ¶¸ × Þ Ø¸ ÐÓ Ø ¶µ
×× Þ Ø ´¶ Ó Ö µ ´×ØÖÙ
Ø Ó
¶¸
ÓÒ×Ø ×ØÖÙ
Ø ÓÚ
¶¸ ÙÒ× Ò ÐÓÒ ¸ ÐÓ Øµ
×× Þ Ø ´¶ Ó ÛÖ Ø µ ´×ØÖÙ
Ø Ó
¶¸
ÓÒ×Ø ×ØÖÙ
Ø ÓÚ
¶¸ ÙÒ× Ò ÐÓÒ ¸ ÐÓ Øµ
ÒØ ´¶Ö Öµ ´×ØÖÙ
Ø Ð ¶¸ ÚÓ ¶¸ ÐÐ Ö Øµ
ÙÒ× Ò ÒØ ´¶ÔÓÐе ´×ØÖÙ
Ø Ð ¶¸ ×ØÖÙ
Ø ÔÓÐÐ Ø Ð ×ØÖÙ
Ø ¶µ
ÒØ ´¶ Ó
Øе ´×ØÖÙ
Ø ÒÓ ¶¸ ×ØÖÙ
Ø Ð ¶¸ ÙÒ× Ò Òظ ÙÒ× Ò ÐÓÒ µ
ÐÓÒ ´¶ÙÒÐÓ
Ó
Øе ´×ØÖÙ
Ø Ð ¶¸ ÙÒ× Ò Òظ ÙÒ× Ò ÐÓÒ µ
32
34. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
ÐÓÒ ´¶
ÓÑÔ Ø Ó
Øе ´×ØÖÙ
Ø Ð ¶¸ ÙÒ× Ò Òظ ÙÒ× Ò ÐÓÒ µ
ÒØ ´¶ÑÑ Ôµ ´×ØÖÙ
Ø Ð ¶¸ ×ØÖÙ
Ø ÚÑ Ö ×ØÖÙ
Ø ¶µ
ÒØ ´¶ÓÔ Òµ ´×ØÖÙ
Ø ÒÓ ¶¸ ×ØÖÙ
Ø Ð ¶µ
ÒØ ´¶ ÐÙ× µ ´×ØÖÙ
Ø Ð ¶¸ Ð ÓÛÒ Ö Ø µ
ÒØ ´¶Ö Ð × µ ´×ØÖÙ
Ø ÒÓ ¶¸ ×ØÖÙ
Ø Ð ¶µ
ÒØ ´¶ ×ÝÒ
µ ´×ØÖÙ
Ø Ð ¶¸ ×ØÖÙ
Ø ÒØÖÝ ¶¸ ÒØ Ø ×ÝÒ
µ
ÒØ ´¶ Ó ×ÝÒ
µ ´×ØÖÙ
Ø Ó
¶¸ ÒØ Ø ×ÝÒ
µ
ÒØ ´¶ ×ÝÒ
µ ´ Òظ ×ØÖÙ
Ø Ð ¶¸ Òص
ÒØ ´¶ÐÓ
µ ´×ØÖÙ
Ø Ð ¶¸ Òظ ×ØÖÙ
Ø Ð ÐÓ
¶µ
×× Þ Ø ´¶× Ò Ô µ ´×ØÖÙ
Ø Ð ¶¸ ×ØÖÙ
Ø Ô ¶¸ Òظ × Þ Ø¸ ÐÓ Ø ¶¸ Òص
ÙÒ× Ò ÐÓÒ ´¶ Ø ÙÒÑ ÔÔ Ö µ´×ØÖÙ
Ø Ð ¶¸ ÙÒ× Ò ÐÓÒ ¸ ÙÒ× Ò ÐÓÒ ¸
ÙÒ× Ò ÐÓÒ ¸ ÙÒ× Ò ÐÓÒ µ
ÒØ ´¶
Ð ×µ´ Òص
ÒØ ´¶ Ö ÒÓØ Ýµ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ ÙÒ× Ò ÐÓÒ Ö µ
ÒØ ´¶ ÐÓ
µ ´×ØÖÙ
Ø Ð ¶¸ Òظ ×ØÖÙ
Ø Ð ÐÓ
¶µ
×× Þ Ø ´¶×ÔÐ
ÛÖ Ø µ´×ØÖÙ
Ø Ô Ô ÒÓ Ò Ó ¶¸ ×ØÖÙ
Ø Ð ¶¸ ÐÓ Ø ¶¸ × Þ Ø¸ ÙÒ
×× Þ Ø ´¶×ÔÐ
Ö µ´×ØÖÙ
Ø Ð ¶¸ ÐÓ Ø ¶¸ ×ØÖÙ
Ø Ô Ô ÒÓ Ò Ó ¶¸ × Þ Ø¸ ÙÒ×
ÒØ ´¶× ØÐ × µ´×ØÖÙ
Ø Ð ¶¸ ÐÓÒ ¸ ×ØÖÙ
Ø Ð ÐÓ
¶¶µ
É uma estrutura um tanto quanto densa. A maioria do seu conteúdo são ponteiros para funções
que você deve implementar. A estrutura em si é apenas a interface. Preencher essa struct é
uma das operações que seu driver deve fazer na inicialização. Para que serve cada uma dessas
funções? Você pergunta. Bom, algumas dão para deduzir pelo nome, outras, nem tanto. De
qualquer forma, vamos analisar os elementos mais importantes para o nosso driver.
struct module *owner: O primeiro ponteiro não é uma função. É um ponteiro para o mó-
dulo que é o "dono"dessa struct. Geralmente, o seu valor é THIS_MODULE. (THIS_MODULE é
definido em <linux/module.h>).
loff_t (*llseek) (struct file *, loff_t, int): Função responsável pela manipulação da cabeça de
leitura (offset) do arquivo. Esse offset é declarado na estrutura de arquivo, que veremos adiante.
Ela retorna a nova posição no arquivo, se for bem sucedida ou algum número negativo caso falhe.
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *): O nome denuncia. É usado para
ler informações do dispositivo. Retorna a quantidade que foi lida com sucesso ou um número
negativo caso falhe. Se esse ponteiro for declarado como NULL, o arquivo não poderá ser lido.
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *): Escreve dados em um
dispositivo. Retorna a quantidade que foi escrita com sucesso ou um número negativo caso falhe.
Se esse ponteiro for declarado como NULL, a escrita no arquivo de dispositivo será impossível.
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t) e ssize_t
(*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t): Fazem a mesma coisa
que read e write, mas de forma assíncrona, isto é, a função pode retornar antes que a operação
termine. Se forem NULL, todas as operaçõe de leitura e escrita serão feitas de forma síncrona.
int (*readdir) (struct file *, void *, filldir_t): Função que permite a leitura de diretórios. Para
driver de dispositivo ela não é implementada.
unsigned int (*poll) (struct file *, struct poll_table_struct *): Função que retorna uma más-
cara informando se é possível ou não utilizar as funções de leitura/escrita sem que elas "blo-
queiem"o fluxo do programa (por exemplo, scanf é uma função que interrompe o programa).
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long): Função utilizada
para mandar comandos especfíficos do hardware em questão, que não são nem de leitura nem
33
35. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
escrita. geralmente são comandos de controle de dispositivo.
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long) e long (*compat_ioctl)
(struct file *, unsigned int, unsigned long): São alternativas mais recentes à ioctl(). ioctl()
utiliza um recurso chamado Big Kernel Lock (BKL). BKLs são utilizadas em sistemas multiproces-
sados (SMP) para garantir a consistência do kernel. Existem partes críticas do kernel que, para
continuarem funcionando, devem esperar a resposta de algum dispositivo que foi controlado com
ioctl() (como por exemplo, o resultado de um cálculo executado por outro processador na mesma
máquina). Assim, antes de se utilizar alguma ioctl() crítica, o kernel deve ser colocado em modo
de espera. unlocked_ioctl() é um recurso relativamente recente no kernel (apareceu por volta da
versão 2.6.11 em forma de um patch) que deve implementar dentro de seu próprio código uma
forma de bloquear a parte significativa para a chamada do kernel. compat_ioctl serve para fazer
chamadas de 32 bits em sistemas de 64 bits. As duas funções não serão abordadas nesse curso,
por serem de uso muito específico. (Por curiosidade, ioctl() não é a única função que utiliza BKL.
open(), llseek() e outras também utilizam).
int (*mmap) (struct file *, struct vm_area_struct *): mmap() é muito importante pois torna
disponível alguma área de memória do dispositivo ao processo chamador, sendo possível controlá-
la.
int (*open) (struct inode *, struct file *): Função sempre chamada quando um arquivo de
dispositivo (/dev/hda1, por exemplo) é aberto. O seu driver não precisa implementá-la e a abertura
sempre irá funcionar. No entanto, sem essa chamada no seu driver, é impossível saber quando o
arquivo de dispositivo está sendo aberto.
int (*flush) (struct file *, fl_owner_t id): Dispositivos que trabalham com buffer geralmente
aguardam o preenchimento de um certo tamanho de bloco na região da sua memória antes
de efetuar a operação de escrita. flush() certifica-se que essa operação será executada. Essa
função é chamanda somente antes da aplicação encerrar as operações com a sua cópia do
descritor do arquivo (file descriptor), e portanto não deve ser confundida com fsync(). Observe
que o programador geralmente não tem controle sobre flush().
int (*release) (struct inode *, struct file *): Chamada quando o arquivo é fechado. Assim
como open(), se for NULL, o seu driver não será avisado dessa operação. Observe que release só
é chamado pelo SO quando todos os aplicativos encerram sua utilização do o dispositivo. Assim,
se dois processos complartilham o mesmo descritor de arquivo (utilizando fork(), por exemplo),
somente flush() é utilizado quando um deles é encerrado. Se ninguém mais utiliza o arquivo, aí
sim é chamado release().
int (*fsync) (struct file *, struct dentry *, int datasync): Essa operação se encarrega de
tratar qualquer dado ainda pendente entre o processo e o dispositivo. É como flush(), mas o
programador pode utilizá-la em qualquer momento.
int (*aio_fsync) (struct kiocb *, int datasync): Como fsync, mas é assíncrona. Isso é, não
deixa o processo chamador em modo de espera.
int (*fasync) (int, struct file *, int): Utilizado para notificar ao dispositivo alguma mudança na
flag FASYNC. Não será abordado nesse curso.
int (*lock) (struct file *, int, struct file_lock *): Implementa a "trava"de arquivo, isto é, se um
processo está "escrevendo"no arquivo, outro processo deve esperar a liberação antes de efetuar
alguma outra operação que precise de lock.
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long
(*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsig-
ned long); int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int
(*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *,
struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct
34
36. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **);
As funções acima sem explicação tratam de tópicos mais avançados, fora do escopo desse
curso, ou são funções de pouco uso em device drivers. Lembre-se que as funções nessa estrutura
não são específicas de drivers de dispositivos, mas pertencem à struct file, que descreve qualquer
arquivo carregado na memória e/ou controlado pelo kernel. Mesmo dentre as funções explicadas,
existem algumas que jamais serão implementadas por nós, como aio_fsync ou unlocked_ioctl.
6.1.3 Inicializando a fops
Há uma coisa que tem que estar clara em sua cabeça, e que talvez ainda não esteja clara
no curso. Perceba que a estrutura file_operations pertence AO KERNEL (mais especificamente,
ao nosso driver). Um programador jamais irá chamar diretamente write() ou read() do dispositivo,
por exemplo. Um usuário do sistema muito menos. Lembra do "echo Oi! > /dev/tty1"? Nesse
momento, o shell abre o arquivo /dev/tty1 com open() (da biblioteca fcntl.h) e o kernel percebe
a chamada e utiliza open() do driver. Então o shell utiliza write() e assim também faz o kernel.
Quando o shell encerra a utilização do arquivo, ele chama close() e o kernel usa flush() e release().
Portanto, os módulos devem implementar essas chamadas e inicializá-las na estrutura de file
operations. Vamos desenvolver um pouco mais o nosso driver:
mydev.c
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
Ò
ÐÙ Ð ÒÙÜ»ØÝÔ ×º
Ò
ÐÙ Ð ÒÙÜ» Ú Øº
Ò
ÐÙ Ð ÒÙÜ» ׺
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ
×Ø Ø
ÒØ Ñ ÓÖ
×Ø Ø
Ú Ø Ú
»¶ ÈÖÓØÓØ ÔÓ× × ÙÒ
Ó × ÔÖ Ò
Ô × ¶»
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
ÓÒ×Ø
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ
»¶ ÁÒ
Ð Þ
Ó ÓÔ× ¶»
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ß
ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸
ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸
ºÖ Ð × ÑÝ Ú Ö Ð × ¸
ºÖ ÑÝ Ú Ö ¸
ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
35
37. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¼¸ Ö Ú Ö µµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
Ö ØÙÖÒ ¼
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×
ÖÖ Ò Ó ÑÓ ÙÐÓ Ò µ
ÙÒÖ ×Ø Ö
Ö Ú Ö ÓÒ´ Ú¸ ¼µ
ÑÓ ÙÐ Ò Ø´ÑÝ Ú Ò Øµ
ÑÓ ÙÐ Ü Ø´ÑÝ Ú Ü Øµ
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
A primeira diferença é que o módulo está com uma carinha mais séria. Uma outra é que
prototipamos as nossas funções básicas. Depois, criamos uma struct file_operations, chamada
mydev, e inicializamos com aquelas funções prototipadas. O resto do código certamente você já
conhece.
Agora você me pergunta: "É possível usar esse módulo só com o protótipo das funções?".
Provavelmente, se está me fazendo essa pergunta, você não compilou e carregou o módulo. A
resposta é NÃO. A princípio, é possível compilar com sucesso esse módulo, mas a compilação
vai dar avisos de símbolos indefinidos. Bom, ignorando isso, tentando um insmod mydev.ko, o
módulo não carrega, alegando agora símbolos desconhecidos.
6.1.4 Algumas operações de mentirinha
Já que o kernel está reclamando que não conhece alguns símbolos, vamos criá-los. Segue o
código, dessa vez com uma implementação.
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
Ò
ÐÙ Ð ÒÙÜ»ØÝÔ ×º
Ò
ÐÙ Ð ÒÙÜ» Ú Øº
Ò
ÐÙ Ð ÒÙÜ» ׺
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ »¶ Ë ÔÖ Ð ¸ ÖÒ Ð
ØÓ ¶»
×Ø Ø
ÒØ Ñ ÓÖ
×Ø Ø
Ú Ø Ú
»¶ ÈÖÓØÓØ ÔÓ× × ÙÒ
Ó × ÔÖ Ò
Ô × ¶»
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
36
39. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú Ö ´µ Ò µ
Ö ØÙÖÒ
ÓÙÒØ
ÑÓ ÙÐ Ò Ø´ÑÝ Ú Ò Øµ
ÑÓ ÙÐ Ü Ø´ÑÝ Ú Ü Øµ
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Pronto, agora o compilador não reclama mais. Nem o insmod. O problema é que nosso
driver ainda não faz absolutamente nada. Se você tentar ler ou escrever nele, provavelmente
o programa que você utilizar vai retornar algum erro do tipo "endereço de dispositivo inválido".
Ainda está faltando uma peça importante. Siga lendo e você vai descobrir o que é.
6.2 Filp
Durante o curso, vamos chamar de filp um ponteiro para a struct file, só para facilitar a refe-
rência (e o nome filp também é comumente utilizado pelos programadores de kernel).
Vamos dar uma olhada no que é de mais pertinente para nós.
unsigned int f_flags: Indica flags do arquivo: se ele está aberto para leitura/escrita ou se o
arquivo está aberto de forma síncrona. Essas flags estão definidas em <linux/fcntl.h>
mode_t f_mode: Permissões de leitura e escrita do arquivo em questão, identificada pelos
bits FMODE_READ e FMODE_WRITE. Uma tentativa de leitura/escrita no arquivo que sem per-
missões para tanto são bloqueadas diretamente pelo kernel, sem nem mesmo chegar a informar
o seu módulo.
loff_t f_pos: Informa a posição da cabeça de leitura no arquivo. Essa posição nunca deve
ser alterada diretamente. As funções read() e write() implementadas em seu driver devem, na
verdade, alterar o ponteiro de offset passado a elas (que, no caso, aponta para o f_pos dentro
dessa struct). No caso de você ter passado batido pela file_operations acima, eu vou trazer a
função write() pra você dar uma olhada: ssize_t (*write) (struct file *, const char __user *, size_t,
loff_t *). Observe que o último parâmetro é um ponteiro do tipo loff_t. A sua função deve alterar
esse ponteiro, ao invés de buscar f_pos na estrutura de arquivo. A única função que altera essa
informação diretamente é llseek, pois, afinal de contas, esse é o seu propósito.
struct file_operations * f_op: A struct que observamos anteriormente. Cada arquivo aberto
no kernel deve ter uma f_op associada com as funções disponíveis. Uma coisa interessante é
que o endereço filp->f_op não fica guardado em nenhuma variável. Isso significa que sempre
que o kernel precisa acessar alguma função daquele arquivo, ele vai buscar em filp->f_op, e
isso possibilita algo muito importante: você pode mudar o endereço de f_op no filp para cada
minor number em um arquivo. Em outras palavras, isso possibilita um mesmo driver controlar
de forma diferente variações do mesmo dispositivo, registrando-o com minor number diferente e
carregando uma f_op na memória moldada às necessidades.
void * private_data: Ponteiro para um bloco de dados para uso particular do arquivo. É útil
como uma região de memória que pode ser utilizada por diversas chamadas de sistema do seu
módulo. É de sua escolha utilizá-lo ou não, mas lembre-se de que qualquer região de memó-
ria alocada num módulo pertence à memória controlada pelo kernel e deve ser cuidadosamente
tratada. Não esqueça de desalocá-la quando terminar de usar ou quando o módulo for descarre-
gado.
Esses são os pontos mais importantes sobre a struct file para nós. Os outros também são
importantes, claro, porém são mais específicos ao arquivo em si e não para nosso driver.
38
40. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
6.3 Estrutura de Inode
6.3.1 Links e inodes
A última struct que vamos dar uma olhada é a de inode. Como você deve(ria?) saber, inode
é uma entrada que descreve o arquivo num sistema de arquivos (file system). Você já criou links
no Linux, não é?
Aulinha de links, com o professor Leonardo:
Existem dois tipos de links entre arquivos no linux. São chamados de soft e hard links. Soft
links apontam para um nome de um arquivo, e se você muda o nome do arquivo que ele aponta,
o link é facilmente quebrado. Já o hard-link é um compromisso com a entrada no sistema de
arquivos, e não com o nome do arquivo. Isso quer dizer que se você faz um hard-link com um
arquivo, está efetivamente apontando para a posição no disco e não para o nome do arquivo.
Qual a vantagem? Você me pergunta. Hard-links criam arquivos linkados independentes do
nome. Significa que alterando o conteúdo de um arquivo você altera o do outro, independente do
nome deles.
Um inode comum pertence à tabela de arquivos do sistema de arquivos, e cada inode contém
muitas infomações, além de dizer em que posição o arquivo está no disco. Um link apontando
para o inode vai estar lá enquanto o inode existir. Arquivos apontando para inodes que não
existem ou inodes sem ninguém apontando para eles são reflexos de inconsistências no sistema
de arquivos (como acontece naquelas vezes em que acaba a energia ou quando você desliga o
computador na pancada).
- Guarde assim: inodes são únicos, nomes de arquivo, não. Da mesma forma que em um
sistema de arquivos eu posso ter vários nomes apontando para o mesmo inode, no kernel do
linux eu posso ter vários descritores de arquivo apontando para o mesmo inode virtual. Portanto,
o inode é uma estrutura muito responsável, pois ela guarda a localização no sistema de arquivos,
tamanho e muitas outras coisas sobre o arquivo.
6.3.2 inode
A estrutura inode é muito grande e sua totalidade está fora das intenções desse curso, mas
existem dois pontos nela que devem ser observados:
dev_t i_rnode; para arquivos que são drivers de dispositivo, essa variável representa o seu
número (major e minor nubers, lembra?). Vale lembrar que o melhor é não trabalhar com essa va-
riável diretamente, pois sua história mostra que sua estrutura é bem diferente em muitas versões
de kernel. O melhor é usar duas funções para recuperar o número diretamente do inode:
ÙÒ× Ò ÒØ Ñ ÒÓÖ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ µ
ÙÒ× Ò ÒØ Ñ ÓÖ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ µ
Agora, vejamos essa union:
ÙÒ ÓÒ ß
×ØÖÙ
Ø Ô Ô ÒÓ Ò Ó ¶ Ô Ô
×ØÖÙ
Ø ÐÓ
Ú
¶ Ú
×ØÖÙ
Ø
Ú ¶
Ú
39
41. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
Bom, cada membro dessa união representa, para a struct inode, o tipo de dispositivo. Se você
utiliza o campo i_cdev, está "dizendo"que aquele inode representa um driver para um dispositivo
de carctere. i_bdev para dispositivos de bloco e i_pipe para pipes (pipes são regiões de memória
que se comportam como uma fila. São criados com o comando mkfifo, análogo ao mknod. Não
abordaremos pipes por enquanto). Vamos continuar usando dispositivos de caractere, pois são
mais simples de implementar. Logo veremos suas funções de registro.
A estrutura de inode e de file não são de nossa responsabilidade: elas são entregues prontas
para nós. Em outras palavras isso significa que não temos tenho que preencher a estrutura file
e nem a inode. Isso seria um completo martírio, e escrever driver ia ser uma coisa para pessoas
com MUITA paciência. Preencher a fops já é uma luta... imagina essas duas aí. Essas estruturas
que são passadas para nós foram criadas pelo próprio kernel quando um programa executa a
chamada open(). Precisamos dela para saber que tipo de arquivo está sendo aberto e os modos
dele. Bem como a posição da cabeça, entre outras coisas.
Vamos tentar tornar o nosso driver funcional agora. A primeira coisa que deve ser feita é pedir
ao kernel um pouco de espaço referente a um dispositivo de caractere:
struct cdev * dev_alloc();
Essa função aloca espaço e inicializa algumas coisas da estrutura cdev, e retorna um ponteiro
para ela. Devemos inicializá-la completamente com
void cdev_init(struct cdev *dev, struct file_operations *fops);
Agora o kernel sabe quais operações o driver sabe executar em cima do dispositivo, colocando
a fops em cdev. Depois de devidamente inicializado, vamos dizer ao kernel que estamos prontos
para funcionar.
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
Os argumentos são o ponteiro para o dispositivo, o número do dispositivo e a quantidade de
dispositivos consecutivos que são controlados por esse driver. Fique muito atento a essa função,
pois, uma vez que o kernel foi informado dessa struct e de sua respectiva fops, ele pode começar
a utilizá-la imediatamente, estando o seu módulo pronto para isso ou não. Esse comportamento
pode levar a falhas catastróficas (como um certo SO popular gosta muito de fazer) do sistema.
Portanto, registrar essa cdev deve ser a última coisa que a sua função de inicialização deve fazer.
40
42. Capítulo 7
Mydev
Sabendo todas as estruturas importantes, já é hora de fazer algo mais funcional: Vamos agora
criar um dispositivo - mydev.c - que faz algo mais útil. Dê uma olhada:
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
Ò
ÐÙ Ð ÒÙÜ»ØÝÔ ×º
Ò
ÐÙ Ð ÒÙÜ» Ú Øº
Ò
ÐÙ Ð ÒÙÜ» ׺
Ò
ÐÙ Ð ÒÙÜ»
Úº
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ
×Ø Ø
ÒØ Ñ ÓÖ
×Ø Ø
Ú Ø Ú
ÒØ ÓÔ Ò Ú
×ØÖÙ
Ø
Ú ÑÝ Ú
Ú
»¶ ÈÖÓØÓØ ÔÓ× × ÙÒ
Ó × ÔÖ Ò
Ô × ¶»
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
ÓÒ×Ø
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ
»¶ ÁÒ
Ð Þ
Ó ÓÔ× ¶»
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ÓÔ× ß
ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸
ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸
ºÖ Ð × ÑÝ Ú Ö Ð × ¸
ºÖ ÑÝ Ú Ö ¸
ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸
41
43. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ Ö Ú Ö µµ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
»¶ ÐÓ
Ö ×ØÖ ×ØÖÙØÙÖ
Ú ÒÓ ÖÒ Ð ¶»
Ú Ò Ø´²ÑÝ Ú
Ú¸ ²ÑÝ Ú ÓÔ×µ
ÑÝ Ú
ÚºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ
Ú ´²ÑÝ Ú
Ú¸ Ú¸ ¿µ
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
ÓÔ Ò Ú ¼
Ö ØÙÖÒ ¼
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×
ÖÖ Ò Ó Ö Ú Ö Ò µ
Ú Ð´²ÑÝ Ú
Úµ
ÙÒÖ ×Ø Ö
Ö Ú Ö ÓÒ´ Ú¸ ¿µ
ÓÔ Ò Ú¹¹
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
´ÓÔ Ò Úµ ß
Ö ØÙÖÒ ¹ ÍË
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×ÔÓ× Ø ÚÓ × Ò Ó Ù× Ó Ò µ
Ö ØÙÖÒ ¼
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×ÔÓ× Ø ÚÓ Ð Ö Ó Ò µ
Ö ØÙÖÒ ¼
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
ÓÒ×Ø
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç Å Ò× Ñ Ö
º Ë Ù Ø Ñ Ò Ó ± Ò ¸
ÓÙÒص
Ö ØÙÖÒ
ÓÙÒØ
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç Ì ÒØ Ø Ú Ð ØÙÖ ÙÑ Ñ Ò× Ñ Ø Ñ Ò Ó ± Ò ¸
ÓÙÒص
Ö ØÙÖÒ
ÓÙÒØ
42
44. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
ÑÓ ÙÐ Ò Ø´ÑÝ Ú Ò Øµ
ÑÓ ÙÐ Ü Ø´ÑÝ Ú Ü Øµ
»¶¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Puxa vida! Tá aí, um driver legal de se ver. É excelente para estudar como são feitas as chamadas
de sistema de cada aplicativo. Nosso driver não faz nada de verdade, só mostra o que está sendo
passado a ele. Impressionante, não é? Dava para imaginar, no início do curso, que a gente ia ver
algo bacana como isso? Observe as diferenças.
O que tem de novo? Bom, registramos a cdev, colocamos a fops e agora exibimos mensagens
sobre o que está sendo passado a nós. Compile e carregue na memória. Não esqueça de fazer o
arquivo de dispositivo correspondente (com mknod, lembra-se?). Teste-o com o comando echo,
dd, cat, etc. Observe como cada um faz um pedido diferente em relação ao tamanho de dados.
Excelente. Agora, você pode se perguntar: por que diabos quando eu digito ’cat nome_do_dispositivo’,
ele tenta ficar lendo indefinidamente? Não sei se você lembra, mas a função read() retorna um
número. Número positivo indica quantos bytes ele leu, e número negativo, um erro qualquer. O 0
(zero) significa fim do arquivo. cat lê até o fim do arquivo, mas nós nunca retornamos 0 em read().
O que acontece com a região de memória que o read() passa para preenchermos? Nada. Fica
lá, do jeito que veio, volta.
43
45. Capítulo 8
A memória e o Kernel
Vamos entender como funciona a alocação de memória dentro do kernel - zonas de memória,
alocação dinâmica, etc
8.1 Como funciona a memória?
Deixe-me explicar um pouco sobre a memória no Linux.
Basicamente, na hora do boot, o kernel divide a memória do seu computador em três zonas:
a primeira é vista de dentro do kernel, e pode ser acessada diretamente por ele, essa zona é
chamada de zona normal ou zona baixa de memória. Atualmente seu tamanho máximo chega
a 1 GB (o que é muito mais do que necessário para um kernel de Linux). A segunda zona
é chamada de zona alta de memória, e pode ir muito mais além de 1GB. É acessada fora do
kernel, no userspace. A terceira zona de memória é chamada de DMA - Direct Memmory Access
(Acesso direto a memória) e geralmente é parte de algum dispositivo e muito dependente da
arquitetura. Cada uma das zonas de memória é mapeada numa região diferente, e, assim sendo,
"ponteiros"que vêm do userspace podem ser inválidos dentro do kernel space e vice-versa. Por
isso que o buffer enviado a read() e write() no exemplo anterior ficou intocado: antes de mexer com
eles, é necessário entender esses conceitos. Sem contar que, se tentamos acessar o ponteiro
passado em buf, a região de memória referenciada por ele pode estar inacessível no momento na
RAM, gerando um page fault. Em um programa normal, tudo bem, é só esperar um pouco que o
dado vai ser acessível. No kernel isso é simplesmente inadmissível! Não dá para ficar esperando
a boa vontade da memória. E como vamos fazer pra utilizar os dados? Bom, tem duas funções
que servem só para isso, definidas em asm/uaccess.h: copy_from_user() e copy_to_user().
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);
unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);
Na primeira, *to é um ponteiro do userspace que receberá os dados, *from é um ponteiro do
kernel space de onde os dados serão copiados e count é o tamanho em bytes a ser copiado de
*from para *to. Na segunda, copy_from_user(), *to é um ponteiro do kernel space, *from é um
ponteiro do user space e count é a quantidade de dados que vai ser copiada de *from para *to.
Tão simples que eu nem precisava ter explicado, não é?
Essas duas funções, meus caros alunos, são duas das engrenagens principais de um dri-
ver de dispositivo. Sem essas funções, a comunicação userspace<->kernelspace teria de ser
reinventada cada vez que um novo driver fosse criado.
Agora, pense nas possibilidades! Ou melhor, pense no /dev/zero. Na verdade, pense nos
dispositivos virtuais controlados pelo driver mem. Você pode até olhar em drivers/char/mem.c pra
44
46. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
ter uma idéia. Bom, o que o /dev/zero faz? Quando você lê dele, enche a saída de zeros. Mas
é zero no sentido de NADA. Não é o zero decimal, nem o de caractere. É NADA mesmo. NULL.
Quando você escreve nele, faz a mesma coisa que escrever em /dev/null.
Mas, fazer um driver desses é fácil, a gente já dá conta com copy_to_user(). Mas ainda está
faltando uma coisa... a função copy_to_user precisa de um ponteiro para o buffer que queremos
copiar, e esse buffer deve variar seu tamanho de acordo com count (que nos é passado através
da chamada da função mydev_read(..., size_t count)). Não dá para simplesmente enviar um "
0"no lugar do ponteiro para o buffer e retornar o count que nos foi passado; os resultados seriam
imprevisíveis.
Então vou apresentar as funções de tratamento de memória do kernel, para resolver esse
problema. Elas estão definidas em linux/slab.h e são tão parecidas com as funções de userspace
que, se eu não falasse, você nem ia notar a diferença.
A primeira delas é a de alocação de memória:
ÚÓ ¶ Ñ ÐÐÓ
´× Þ Ø × Þ ¸ Ô Ø Ð ×µ
E a segunda é a de liberação:
ÚÓ Ö ´ÚÓ ¶ÔØÖµ
kmalloc() funciona como malloc(); retorna um ponteiro para a região alocada de memória,
size_t size é o tamanho que você quer alocar e gfp_t flags define como vai se comportar essa
função. Calma, vou explicar. Algumas situações, você não precisa de acesso instantâneo à
memória do kernel e pode esperar até que alguma região de memória seja liberada para você;
para isso, você usa a flag GFP_KERNEL. Em outras situações, você precisa instantaneamente de
memória, pois o dispositivo e o driver não podem parar. Essa é a flag GFP_ATOMIC. Existe ainda
situações em que você quer que a memória alocada esteja disponível no userspace. Para tanto,
utilize a flag GFP_USER, que aloca e mapeia a memória para o userspace ou GFP_USERHIGH,
que mapeia para o userspace, mas aloca somente na zona alta de memória. Existem ainda flags
mais específicas, como é o caso de __GFP_DMA, que diz à função kmalloc() que a memória a ser
alocada é capaz de operações em DMA. Há outras flags, mas essas são as mais interessantes.
kmalloc, bem como malloc, retorna NULL caso seja impossível alocar a memória requisitada.
kfree() age exatamente igual a free(). Libera uma região de memória. Trabalhando com o
kernel, extremo cuidado com a memória. Lembre-se que a memória no kernelspace não é grande
e deve ser poupada.
Existem algumas outras funções associadas à kmalloc, que são muito úteis também. Elas são
ÚÓ ¶
ÐÐÓ
´× Þ Ø Ò¸ × Þ Ø × Þ ¸ Ô Ø Ð ×µ
ÚÓ ¶ Þ ÐÐÓ
´× Þ Ø × Þ ¸ Ô Ø Ð ×µ
ÚÓ ¶Ñ Ñ× Ø´ÚÓ ¶¸ Òظ ÖÒ Ð × Þ Øµ
kcalloc cria um array de n elementos, cada um com o tamanho size, e devolve um ponteiro para
essa array; kzalloc devolve um ponteiro para a memória alocada, "zerada"por omissão; memset
é equivalente à memset da libc, ou seja, seta toda a região de memória de acordo com seus
parâmetros.
45
47. Capítulo 9
Mydev completo
Vamos agora finalizar o nosso driver
9.1 mydev.c
Vamos para a última parte do nosso curso. O driver, com algumas das funções que aprende-
mos durante todas as aulas, será apresentado de forma completa e funcional. Ele agora é capaz
de armazenar um valor na memória do kernel, que também poderá ser acessado. No final dessa
parte vamos executar alguns programas em nosso dispositivo virtual, só para ver o que acontece.
»¶ ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹
ÙØ Ö ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹ ¶»
Ò
ÐÙ Ð ÒÙÜ» Ò Øº
Ò
ÐÙ Ð ÒÙÜ»ÑÓ ÙÐ º
Ò
ÐÙ Ð ÒÙÜ»ØÝÔ ×º
Ò
ÐÙ Ð ÒÙÜ» Ú Øº
Ò
ÐÙ Ð ÒÙÜ» ׺
Ò
ÐÙ Ð ÒÙÜ»
Úº
Ò
ÐÙ Ð ÒÙÜ»×Ð º
Ò
ÐÙ Ð ÒÙÜ»×ØÖ Ò º
Ò
ÐÙ ×Ñ»Ù
×׺
ÅÇ ÍÄ ÄÁ ÆË ´ Ù Ð Ë » ÈÄ µ
×Ø Ø
ÒØ Ñ ÓÖ
×Ø Ø
Ú Ø Ú
×Ø Ø
ÒØ ÓÔ Ò Ú
×Ø Ø
×ØÖÙ
Ø
Ú ÑÝ Ú
Ú
×Ø Ø
Ö ¶ ÒØ ÖÒ Ð Ù Ö
»¶ ÈÖÓØÓØ ÔÓ× × ÙÒ
Ó × ÔÖ Ò
Ô × ¶»
×Ø Ø
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
×Ø Ø
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ
×Ø Ø
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ Ø ¶
×Ø Ø
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸
ÓÒ×Ø
Ö Ù× Ö ¶ Ù ¸ × Þ Ø
ÓÙÒظ ÐÓ
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ
46
48. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ
»¶ ÁÒ
Ð Þ
Ó ÓÔ× ¶»
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ÓÔ× ß
ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸
ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸
ºÖ Ð × ÑÝ Ú Ö Ð × ¸
ºÖ ÑÝ Ú Ö ¸
ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸
×Ø Ø
ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ ÑÝ Ú µµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
»¶ ÐÓ
Ö ×ØÖ ×ØÖÙØÙÖ
Ú ÒÓ ÖÒ Ð ¶»
Ú Ò Ø´²ÑÝ Ú
Ú¸ ²ÑÝ Ú ÓÔ×µ
ÑÝ Ú
ÚºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ
Ú ´²ÑÝ Ú
Ú¸ Ú¸ ¿µ
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
ÓÔ Ò Ú ¼
ÒØ ÖÒ Ð Ù Ö ÆÍÄÄ
Ö ØÙÖÒ ¼
×Ø Ø
ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×
ÖÖ Ò Ó Ö Ú Ö Ò µ
Ú Ð´²ÑÝ Ú
Úµ
ÙÒÖ ×Ø Ö
Ö Ú Ö ÓÒ´ Ú¸ ¿µ
ÓÔ Ò Ú¹¹
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
´ÓÔ Ò Úµ ß
Ö ØÙÖÒ ¹ ÍË
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×ÔÓ× Ø ÚÓ × Ò Ó Ù× Ó Ò µ
Ö ØÙÖÒ ¼
47