SlideShare uma empresa Scribd logo
1 de 50
Baixar para ler offline
Drivers de Dispositivos Linux
2 de Setembro de 2008
Conteúdo
I Sobre essa apostila 2
II Informações Básicas 4
III GNU Free Documentation License 9
IV Driver de Dsipositivo Linux 18
1 Driver de Dispositivo Linux 19
2 Plano de ensino 20
2.1 Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2 Público Alvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Pré-requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 Cronograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.6 Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.7 Avaliação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.8 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3 Introdução 23
3.1 Driver de Dispositivo? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2 Tipos de Dispositivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.3 Interface do Driver com o Sistema Operacional . . . . . . . . . . . . . . . . . . . . . 24
4 Hello Kernel! 26
4.1 Kello Hernell! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 Como funciona? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5 Arquivos de Dispositivo 28
5.1 Tudo é um arquivo! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.2 Major e Minor Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6 Estruturas 31
6.1 File Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.1.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.1.2 Fops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
6.1.3 Inicializando a fops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.1.4 Algumas operações de mentirinha . . . . . . . . . . . . . . . . . . . . . . . . 35
6.2 Filp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.3 Estrutura de Inode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3.1 Links e inodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3.2 inode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
7 Mydev 40
8 A memória e o Kernel 43
8.1 Como funciona a memória? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9 Mydev completo 45
9.1 mydev.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
9.2 Utilização do mydev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2
Parte I
Sobre essa apostila
3
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
Conteúdo
O conteúdo dessa apostila é fruto da compilação de diversos materiais livres publicados na in-
ternet, disponíveis em diversos sites ou originalmente produzido no CDTC em http://www.cdtc.org.br.
O formato original deste material bem como sua atualização está disponível dentro da licença
GNU Free Documentation License, cujo teor integral encontra-se aqui reproduzido na seção de
mesmo nome, tendo inclusive uma versão traduzida (não oficial).
A revisão e alteração vem sendo realizada pelo CDTC (suporte@cdtc.org.br), desde outubro
de 2006. Criticas e sugestões construtivas são bem-vindas a qualquer tempo.
Autores
A autoria deste conteúdo, atividades e avaliações é de responsabilidade de Leonardo Gui-
lherme de Freitas (lgfreitas@cdtc.org.br) .
O texto original faz parte do projeto Centro de Difusão de Tecnolgia e Conhecimento, que vem
sendo realizado pelo ITI em conjunto com outros parceiros institucionais, atuando em conjunto
com as universidades federais brasileiras que tem produzido e utilizado Software Livre, apoiando
inclusive a comunidade Free Software junto a outras entidades no país.
Informações adicionais podem ser obtidas atréves do email ouvidoria@cdtc.org.br, ou da
home page da entidade, através da URL http://www.cdtc.org.br.
Garantias
O material contido nesta apostila é isento de garantias e o seu uso é de inteira responsabi-
lidade do usuário/leitor. Os autores, bem como o ITI e seus parceiros, não se responsabilizam
direta ou indiretamente por qualquer prejuízo oriundo da utilização do material aqui contido.
Licença
Copyright ©2006,Leonardo Guilherme de Freitas (lgfreitas@cdtc.org.br) .
Permission is granted to copy, distribute and/or modify this document under the terms
of the GNU Free Documentation License, Version 1.1 or any later version published by
the Free Software Foundation; with the Invariant Chapter being SOBRE ESSA APOS-
TILA. A copy of the license is included in the section entitled GNU Free Documentation
License.
4
Parte II
Informações Básicas
5
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
Sobre o CDTC
Objetivo Geral
O Projeto CDTC visa a promoção e o desenvolvimento de ações que incentivem a dissemina-
ção de soluções que utilizem padrões abertos e não proprietários de tecnologia, em proveito do
desenvolvimento social, cultural, político, tecnológico e econômico da sociedade brasileira.
Objetivo Específico
Auxiliar o Governo Federal na implantação do plano nacional de software não-proprietário e
de código fonte aberto, identificando e mobilizando grupos de formadores de opinião dentre os
servidores públicos e agentes políticos da União Federal, estimulando e incentivando o mercado
nacional a adotar novos modelos de negócio da tecnologia da informação e de novos negócios
de comunicação com base em software não-proprietário e de código fonte aberto, oferecendo
treinamento específico para técnicos, profissionais de suporte e funcionários públicos usuários,
criando grupos de funcionários públicos que irão treinar outros funcionários públicos e atuar como
incentivadores e defensores de produtos de software não proprietários e código fonte aberto, ofe-
recendo conteúdo técnico on-line para serviços de suporte, ferramentas para desenvolvimento de
produtos de software não proprietários e de seu código fonte livre, articulando redes de terceiros
(dentro e fora do governo) fornecedoras de educação, pesquisa, desenvolvimento e teste de pro-
dutos de software livre.
Guia do aluno
Neste guia, você terá reunidas uma série de informações importantes para que você comece
seu curso. São elas:
• Licenças para cópia de material disponível
• Os 10 mandamentos do aluno de Educação a Distância
• Como participar dos fóruns e da wikipédia
• Primeiros passos
É muito importante que você entre em contato com TODAS estas informações, seguindo o
roteiro acima.
Licença
Copyright ©2006, Leonardo Guilherme de Freitas (lgfreitas@cdtc.org.br) .
6
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
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
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
Parte III
GNU Free Documentation License
10
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
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
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
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
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
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
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
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
Parte IV
Driver de Dsipositivo Linux
19
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
 Ö Ù× Ö ¶ Ù ¸ × Þ Ø 
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
ÓÒ×Ø 
 Ö Ù× Ö ¶ Ù ¸ × Þ Ø 
ÓÙÒظ ÐÓ Ø ¶
×Ø Ø 
 ÒØ ÑÝ Ú Ò Ø´ÚÓ µ
×Ø Ø 
 ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ
»¶ ÁÒ 
 Ð Þ 
 Ó ÓÔ× ¶»
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ÓÔ× ß
ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸
ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸
ºÖ Ð × ÑÝ Ú Ö Ð × ¸
ºÖ ÑÝ Ú Ö ¸
ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸
×Ø Ø 
 ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö 
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
 
 Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ Ö Ú Ö µµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
 Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
Ö ØÙÖÒ ¼
×Ø Ø 
 ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×
 ÖÖ Ò Ó Ö Ú Ö Ò µ
ÙÒÖ ×Ø Ö 
 Ö Ú Ö ÓÒ´ Ú¸ ¿µ
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú ÓÔ Ò´µ Ò µ
Ö ØÙÖÒ ¼
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú Ö Ð × ´µ Ò µ
Ö ØÙÖÒ ¼
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
ÓÒ×Ø 
 Ö Ù× Ö ¶ Ù ¸
× Þ Ø 
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú ÛÖ Ø ´µ Ò µ
Ö ØÙÖÒ 
ÓÙÒØ
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
 Ö Ù× Ö ¶ Ù ¸ × Þ Ø 
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
37
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
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
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
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
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
×Ø Ø 
 ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö 
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
 
 Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ Ö Ú Ö µµ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
 Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
»¶ ÐÓ
 Ö ×ØÖ ×ØÖÙØÙÖ 
 Ú ÒÓ ÖÒ Ð ¶»

 Ú Ò Ø´²ÑÝ Ú 
 Ú¸ ²ÑÝ Ú ÓÔ×µ
ÑÝ Ú 
 ÚºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ

 Ú ´²ÑÝ Ú 
 Ú¸ Ú¸ ¿µ
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
ÓÔ Ò Ú ¼
Ö ØÙÖÒ ¼
×Ø Ø 
 ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×
 ÖÖ Ò Ó Ö Ú Ö Ò µ

 Ú Ð´²ÑÝ Ú 
 Úµ
ÙÒÖ ×Ø Ö 
 Ö Ú Ö ÓÒ´ Ú¸ ¿µ
ÓÔ Ò Ú¹¹
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
´ÓÔ Ò Úµ ß
Ö ØÙÖÒ ¹ ÍË
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×ÔÓ× Ø ÚÓ × Ò Ó Ù× Ó Ò µ
Ö ØÙÖÒ ¼
ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç ×ÔÓ× Ø ÚÓ Ð Ö Ó Ò µ
Ö ØÙÖÒ ¼
×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
ÓÒ×Ø 
 Ö Ù× Ö ¶ Ù ¸ × Þ Ø 
ÓÙÒظ ÐÓ Ø ¶
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç Å Ò× Ñ Ö 
 º Ë Ù Ø Ñ Ò Ó ± Ò ¸ 
ÓÙÒص
Ö ØÙÖÒ 
ÓÙÒØ
×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ
Ø Ð ¶ ÐÔ¸ 
 Ö Ù× Ö ¶ Ù ¸ × Þ Ø 
ÓÙÒظ ÐÓ Ø ¶ ÔÓ×
ÔÖ ÒØ ´Ã ÊÆ ÁÆ Ç Ì ÒØ Ø Ú Ð ØÙÖ ÙÑ Ñ Ò× Ñ Ø Ñ Ò Ó ± Ò ¸ 
ÓÙÒص
Ö ØÙÖÒ 
ÓÙÒØ
42
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
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
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
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
CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF
×Ø Ø 
 ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ
»¶ ÁÒ 
 Ð Þ 
 Ó ÓÔ× ¶»
×ØÖÙ
Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ÓÔ× ß
ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸
ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸
ºÖ Ð × ÑÝ Ú Ö Ð × ¸
ºÖ ÑÝ Ú Ö ¸
ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸
×Ø Ø 
 ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÖÖ Ò Ó ÑÝ Ú Ò µ
»¶ Ö ×ØÖ Ó Ö Ú Ö 
ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶»
´ ÐÐÓ
 
 Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ ÑÝ Ú µµ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ
 Ò Ó Ó Ö Ú Ö Ò µ
Ö ØÙÖÒ ½
»¶ ÐÓ
 Ö ×ØÖ ×ØÖÙØÙÖ 
 Ú ÒÓ ÖÒ Ð ¶»

 Ú Ò Ø´²ÑÝ Ú 
 Ú¸ ²ÑÝ Ú ÓÔ×µ
ÑÝ Ú 
 ÚºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ

 Ú ´²ÑÝ Ú 
 Ú¸ Ú¸ ¿µ
Ñ ÓÖ Å ÂÇÊ´ Úµ
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ
ÓÔ Ò Ú ¼
ÒØ ÖÒ Ð Ù Ö ÆÍÄÄ
Ö ØÙÖÒ ¼
×Ø Ø 
 ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×
 ÖÖ Ò Ó Ö Ú Ö Ò µ

 Ú Ð´²ÑÝ Ú 
 Úµ
ÙÒÖ ×Ø Ö 
 Ö Ú Ö ÓÒ´ Ú¸ ¿µ
ÓÔ Ò Ú¹¹
ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ
Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ
Ø Ð ¶ ÐÔµ ß
´ÓÔ Ò Úµ ß
Ö ØÙÖÒ ¹ ÍË
ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ×ÔÓ× Ø ÚÓ × Ò Ó Ù× Ó Ò µ
Ö ØÙÖÒ ¼
47
Drivers de dispostivos_linux
Drivers de dispostivos_linux

Mais conteúdo relacionado

Mais procurados

Mais procurados (20)

Apostila cdtc dotproject
Apostila cdtc dotprojectApostila cdtc dotproject
Apostila cdtc dotproject
 
Javascript
JavascriptJavascript
Javascript
 
Sql
SqlSql
Sql
 
Tunelamento
TunelamentoTunelamento
Tunelamento
 
Zope
ZopeZope
Zope
 
Samba
SambaSamba
Samba
 
Wx python
Wx pythonWx python
Wx python
 
X dialog
X dialogX dialog
X dialog
 
Programacao cpp
Programacao cppProgramacao cpp
Programacao cpp
 
Squid guard
Squid guardSquid guard
Squid guard
 
Perl
PerlPerl
Perl
 
Horde
HordeHorde
Horde
 
Inst configdebian
Inst configdebianInst configdebian
Inst configdebian
 
Screen
ScreenScreen
Screen
 
OpenSolaris
OpenSolarisOpenSolaris
OpenSolaris
 
Gerenciadores de boot
Gerenciadores de bootGerenciadores de boot
Gerenciadores de boot
 
Manual do Kile
Manual do KileManual do Kile
Manual do Kile
 
Intro Micro Hardware
Intro Micro HardwareIntro Micro Hardware
Intro Micro Hardware
 
Material LINUX
Material LINUXMaterial LINUX
Material LINUX
 
Introdução micro computador
Introdução micro computadorIntrodução micro computador
Introdução micro computador
 

Semelhante a Drivers de dispostivos_linux

Pascal
PascalPascal
PascalTiago
 
Inkscape
InkscapeInkscape
InkscapeTiago
 
Nagios2
Nagios2Nagios2
Nagios2Tiago
 
Java applet
Java appletJava applet
Java appletTiago
 
Linguagem ruby
Linguagem rubyLinguagem ruby
Linguagem rubyTiago
 
Programacao php moodle
Programacao php moodleProgramacao php moodle
Programacao php moodleTiago
 
Pen linux
Pen linuxPen linux
Pen linuxTiago
 
Dovecot
DovecotDovecot
DovecotTiago
 
Instalacao xoops
Instalacao xoopsInstalacao xoops
Instalacao xoopsTiago
 
Iptables
IptablesIptables
IptablesTiago
 
Drupal
DrupalDrupal
DrupalTiago
 
Programacao gtk
Programacao gtkProgramacao gtk
Programacao gtkTiago
 
Monitoramento
MonitoramentoMonitoramento
MonitoramentoTiago
 
Selinux
SelinuxSelinux
SelinuxTiago
 
Nessus
NessusNessus
NessusTiago
 

Semelhante a Drivers de dispostivos_linux (20)

Pascal
PascalPascal
Pascal
 
Ltsp
LtspLtsp
Ltsp
 
Inkscape
InkscapeInkscape
Inkscape
 
Nagios2
Nagios2Nagios2
Nagios2
 
Java applet
Java appletJava applet
Java applet
 
Linguagem ruby
Linguagem rubyLinguagem ruby
Linguagem ruby
 
Programacao php moodle
Programacao php moodleProgramacao php moodle
Programacao php moodle
 
Plone
PlonePlone
Plone
 
Pen linux
Pen linuxPen linux
Pen linux
 
Dovecot
DovecotDovecot
Dovecot
 
J2me
J2meJ2me
J2me
 
Instalacao xoops
Instalacao xoopsInstalacao xoops
Instalacao xoops
 
Mrtg
MrtgMrtg
Mrtg
 
Iptables
IptablesIptables
Iptables
 
Drupal
DrupalDrupal
Drupal
 
Programacao gtk
Programacao gtkProgramacao gtk
Programacao gtk
 
Monitoramento
MonitoramentoMonitoramento
Monitoramento
 
Nvu
NvuNvu
Nvu
 
Selinux
SelinuxSelinux
Selinux
 
Nessus
NessusNessus
Nessus
 

Mais de Tiago

6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascalTiago
 
Guia rapido de_pascal
Guia rapido de_pascalGuia rapido de_pascal
Guia rapido de_pascalTiago
 
Python bge
Python bgePython bge
Python bgeTiago
 
Curso python
Curso pythonCurso python
Curso pythonTiago
 
Curso python
Curso pythonCurso python
Curso pythonTiago
 
Aula 01 python
Aula 01 pythonAula 01 python
Aula 01 pythonTiago
 
Threading in c_sharp
Threading in c_sharpThreading in c_sharp
Threading in c_sharpTiago
 
Retirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharpRetirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharpTiago
 
Remover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharpRemover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharpTiago
 
Obter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharpObter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharpTiago
 
Metodo using no_c_sharp
Metodo using no_c_sharpMetodo using no_c_sharp
Metodo using no_c_sharpTiago
 
Introdução ao c# para iniciantes
Introdução ao c# para iniciantesIntrodução ao c# para iniciantes
Introdução ao c# para iniciantesTiago
 
Interfaces windows em c sharp
Interfaces windows em c sharpInterfaces windows em c sharp
Interfaces windows em c sharpTiago
 
Filestream sistema arquivos
Filestream  sistema arquivosFilestream  sistema arquivos
Filestream sistema arquivosTiago
 
Curso linux professor rafael
Curso linux professor rafaelCurso linux professor rafael
Curso linux professor rafaelTiago
 
Curso de shell
Curso de shellCurso de shell
Curso de shellTiago
 
Controle lpt em_c_sharp
Controle lpt em_c_sharpControle lpt em_c_sharp
Controle lpt em_c_sharpTiago
 
Classes csharp
Classes csharpClasses csharp
Classes csharpTiago
 
C# o basico
C#   o basicoC#   o basico
C# o basicoTiago
 
C# classes
C#   classesC#   classes
C# classesTiago
 

Mais de Tiago (20)

6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal
 
Guia rapido de_pascal
Guia rapido de_pascalGuia rapido de_pascal
Guia rapido de_pascal
 
Python bge
Python bgePython bge
Python bge
 
Curso python
Curso pythonCurso python
Curso python
 
Curso python
Curso pythonCurso python
Curso python
 
Aula 01 python
Aula 01 pythonAula 01 python
Aula 01 python
 
Threading in c_sharp
Threading in c_sharpThreading in c_sharp
Threading in c_sharp
 
Retirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharpRetirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharp
 
Remover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharpRemover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharp
 
Obter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharpObter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharp
 
Metodo using no_c_sharp
Metodo using no_c_sharpMetodo using no_c_sharp
Metodo using no_c_sharp
 
Introdução ao c# para iniciantes
Introdução ao c# para iniciantesIntrodução ao c# para iniciantes
Introdução ao c# para iniciantes
 
Interfaces windows em c sharp
Interfaces windows em c sharpInterfaces windows em c sharp
Interfaces windows em c sharp
 
Filestream sistema arquivos
Filestream  sistema arquivosFilestream  sistema arquivos
Filestream sistema arquivos
 
Curso linux professor rafael
Curso linux professor rafaelCurso linux professor rafael
Curso linux professor rafael
 
Curso de shell
Curso de shellCurso de shell
Curso de shell
 
Controle lpt em_c_sharp
Controle lpt em_c_sharpControle lpt em_c_sharp
Controle lpt em_c_sharp
 
Classes csharp
Classes csharpClasses csharp
Classes csharp
 
C# o basico
C#   o basicoC#   o basico
C# o basico
 
C# classes
C#   classesC#   classes
C# classes
 

Drivers de dispostivos_linux

  • 1. Drivers de Dispositivos Linux 2 de Setembro de 2008
  • 2. Conteúdo I Sobre essa apostila 2 II Informações Básicas 4 III GNU Free Documentation License 9 IV Driver de Dsipositivo Linux 18 1 Driver de Dispositivo Linux 19 2 Plano de ensino 20 2.1 Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.2 Público Alvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.3 Pré-requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.4 Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.5 Cronograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.6 Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.7 Avaliação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.8 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3 Introdução 23 3.1 Driver de Dispositivo? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.2 Tipos de Dispositivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.3 Interface do Driver com o Sistema Operacional . . . . . . . . . . . . . . . . . . . . . 24 4 Hello Kernel! 26 4.1 Kello Hernell! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 4.2 Como funciona? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 5 Arquivos de Dispositivo 28 5.1 Tudo é um arquivo! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 5.2 Major e Minor Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 6 Estruturas 31 6.1 File Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 6.1.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 6.1.2 Fops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 1
  • 3. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF 6.1.3 Inicializando a fops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.1.4 Algumas operações de mentirinha . . . . . . . . . . . . . . . . . . . . . . . . 35 6.2 Filp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 6.3 Estrutura de Inode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 6.3.1 Links e inodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 6.3.2 inode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 7 Mydev 40 8 A memória e o Kernel 43 8.1 Como funciona a memória? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 9 Mydev completo 45 9.1 mydev.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 9.2 Utilização do mydev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 2
  • 4. Parte I Sobre essa apostila 3
  • 5. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF Conteúdo O conteúdo dessa apostila é fruto da compilação de diversos materiais livres publicados na in- ternet, disponíveis em diversos sites ou originalmente produzido no CDTC em http://www.cdtc.org.br. O formato original deste material bem como sua atualização está disponível dentro da licença GNU Free Documentation License, cujo teor integral encontra-se aqui reproduzido na seção de mesmo nome, tendo inclusive uma versão traduzida (não oficial). A revisão e alteração vem sendo realizada pelo CDTC (suporte@cdtc.org.br), desde outubro de 2006. Criticas e sugestões construtivas são bem-vindas a qualquer tempo. Autores A autoria deste conteúdo, atividades e avaliações é de responsabilidade de Leonardo Gui- lherme de Freitas (lgfreitas@cdtc.org.br) . O texto original faz parte do projeto Centro de Difusão de Tecnolgia e Conhecimento, que vem sendo realizado pelo ITI em conjunto com outros parceiros institucionais, atuando em conjunto com as universidades federais brasileiras que tem produzido e utilizado Software Livre, apoiando inclusive a comunidade Free Software junto a outras entidades no país. Informações adicionais podem ser obtidas atréves do email ouvidoria@cdtc.org.br, ou da home page da entidade, através da URL http://www.cdtc.org.br. Garantias O material contido nesta apostila é isento de garantias e o seu uso é de inteira responsabi- lidade do usuário/leitor. Os autores, bem como o ITI e seus parceiros, não se responsabilizam direta ou indiretamente por qualquer prejuízo oriundo da utilização do material aqui contido. Licença Copyright ©2006,Leonardo Guilherme de Freitas (lgfreitas@cdtc.org.br) . Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Chapter being SOBRE ESSA APOS- TILA. A copy of the license is included in the section entitled GNU Free Documentation License. 4
  • 7. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF Sobre o CDTC Objetivo Geral O Projeto CDTC visa a promoção e o desenvolvimento de ações que incentivem a dissemina- ção de soluções que utilizem padrões abertos e não proprietários de tecnologia, em proveito do desenvolvimento social, cultural, político, tecnológico e econômico da sociedade brasileira. Objetivo Específico Auxiliar o Governo Federal na implantação do plano nacional de software não-proprietário e de código fonte aberto, identificando e mobilizando grupos de formadores de opinião dentre os servidores públicos e agentes políticos da União Federal, estimulando e incentivando o mercado nacional a adotar novos modelos de negócio da tecnologia da informação e de novos negócios de comunicação com base em software não-proprietário e de código fonte aberto, oferecendo treinamento específico para técnicos, profissionais de suporte e funcionários públicos usuários, criando grupos de funcionários públicos que irão treinar outros funcionários públicos e atuar como incentivadores e defensores de produtos de software não proprietários e código fonte aberto, ofe- recendo conteúdo técnico on-line para serviços de suporte, ferramentas para desenvolvimento de produtos de software não proprietários e de seu código fonte livre, articulando redes de terceiros (dentro e fora do governo) fornecedoras de educação, pesquisa, desenvolvimento e teste de pro- dutos de software livre. Guia do aluno Neste guia, você terá reunidas uma série de informações importantes para que você comece seu curso. São elas: • Licenças para cópia de material disponível • Os 10 mandamentos do aluno de Educação a Distância • Como participar dos fóruns e da wikipédia • Primeiros passos É muito importante que você entre em contato com TODAS estas informações, seguindo o roteiro acima. Licença Copyright ©2006, Leonardo Guilherme de Freitas (lgfreitas@cdtc.org.br) . 6
  • 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
  • 11. Parte III GNU Free Documentation License 10
  • 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
  • 20. Parte IV Driver de Dsipositivo Linux 19
  • 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
  • 38. CDTC Centro de Difusão de Tecnologia e Conhecimento Brasília/DF ×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ Ø Ð ¶ ÐÔ¸ Ö Ù× Ö ¶ Ù ¸ × Þ Ø ÓÙÒظ ÐÓ Ø ¶ ÔÓ× ×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ Ø Ð ¶ ÐÔ¸ ÓÒ×Ø Ö Ù× Ö ¶ Ù ¸ × Þ Ø ÓÙÒظ ÐÓ Ø ¶ ×Ø Ø ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ×Ø Ø ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ »¶ ÁÒ Ð Þ Ó ÓÔ× ¶» ×ØÖÙ Ø Ð ÓÔ Ö Ø ÓÒ× ÑÝ Ú ÓÔ× ß ºÓÛÒ Ö ÌÀÁË ÅÇ ÍÄ ¸ ºÓÔ Ò ÑÝ Ú ÓÔ Ò¸ ºÖ Ð × ÑÝ Ú Ö Ð × ¸ ºÖ ÑÝ Ú Ö ¸ ºÛÖ Ø ÑÝ Ú ÛÖ Ø ¸ ×Ø Ø ÒØ ÑÝ Ú Ò Ø´ÚÓ µ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÖÖ Ò Ó ÑÝ Ú Ò µ »¶ Ö ×ØÖ Ó Ö Ú Ö ÓÑ ¿ Ñ ÒÓÖ ÒÙÑ Ö× ¶» ´ ÐÐÓ Ö Ú Ö ÓÒ´² Ú¸ ¼¸ ¿¸ Ö Ú Ö µµ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÀÓÙÚ ÙÑ ÔÖÓ Ð Ñ ÐÓ Ò Ó Ó Ö Ú Ö Ò µ Ö ØÙÖÒ ½ Ñ ÓÖ Å ÂÇÊ´ Úµ ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÆÓ××Ó Ñ ÓÖ ÒÙÑ Ö ± Ò ¸ Ñ ÓÖµ Ö ØÙÖÒ ¼ ×Ø Ø ÚÓ ÑÝ Ú Ü Ø´ÚÓ µ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ × ÖÖ Ò Ó Ö Ú Ö Ò µ ÙÒÖ ×Ø Ö Ö Ú Ö ÓÒ´ Ú¸ ¿µ ÒØ ÑÝ Ú ÓÔ Ò´×ØÖÙ Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ Ø Ð ¶ ÐÔµ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú ÓÔ Ò´µ Ò µ Ö ØÙÖÒ ¼ ÒØ ÑÝ Ú Ö Ð × ´×ØÖÙ Ø ÒÓ ¶ ÒÓ ¸ ×ØÖÙ Ø Ð ¶ ÐÔµ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú Ö Ð × ´µ Ò µ Ö ØÙÖÒ ¼ ×× Þ Ø ÑÝ Ú ÛÖ Ø ´×ØÖÙ Ø Ð ¶ ÐÔ¸ ÓÒ×Ø Ö Ù× Ö ¶ Ù ¸ × Þ Ø ÓÙÒظ ÐÓ Ø ¶ ÔÓ×µ ß ÔÖ ÒØ ´Ã ÊÆ Ä ÊÌ ÑÝ Ú ÛÖ Ø ´µ Ò µ Ö ØÙÖÒ ÓÙÒØ ×× Þ Ø ÑÝ Ú Ö ´×ØÖÙ Ø Ð ¶ ÐÔ¸ Ö Ù× Ö ¶ Ù ¸ × Þ Ø ÓÙÒظ ÐÓ Ø ¶ ÔÓ× 37
  • 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