# Objetivo geral

O objetivo do estudo de caso, através da análise do funcionamento do driver USB Linux para o dispositibo DreamCheeky USB Missile Launcher é o de complementar os estudos feitos em sala de aula, de forma a observar na prática os processos feito pelo computador para reconhecer um dispositivo USB e tratá-lo de acordo com as suas características.

# Introdução

Com o objetivo de criar um driver USB Linux para o dispositivo Dream Cheeky USB Missile Launcher, este estudo de caso explica o processo de criação de um driver de dispositivo USB para o kernel Linux. Depois de ter a engenharia reversa do protocolo de comunicação USB, é apresentado a arquitetura do driver de dispositivo USB. Embora o autor tenha tido que mergulhar em especificidades do dispositivo para o qual o driver foi desenvolvido, o processo pode ser aplicado a outros dispositivos USB também.

## Informações gerais

* Autores do grupo
** Gabriel Henrique
** Diego Fraga
** Lauro Henrique M Ribeiro
* Versão do kernel
** Linux 2.6.31 kernel
* Identificação do driver analisado
* lista de arquivos de códigos-fontes analisados
** http://code.google.com/p/mavam/source/browse/#svn/trunk/ml-driver
* outras informações relevantes
** O driver analisado não é disponibilizado pelo fabricante para sistemas Linux.
** O driver foi produzido a partir da estrutura básica do Skeleton_driver, sugerido no livro Linux Device Driver 3rd
** As mensagens de entrada e saída do dispositivo foram capturadas com programas de snoopy a partir do driver fornecido pelo fabricante para sistemas Windows.

## Carga (load ou init)

* Processo de carga do módulo
A carga do módulo é feita através do comando insmod ou modprobe. No entanto o comando modprobe é desnecessário pois o driver analisado não possui dependências de outros módulos.
* Parâmetros que podem ser passados na carga do módulo
** O driver aceita apenas parametros de debug durante a carga.
** As linhas 132 e 133 indicam nome, tipo e permissão dos parametros que podem ser passados.
*** S_IRUGO indica que o parâmetro ficará disponível em modo somente leitura para qualquer usuário.
*** S_IWUSR indica que o usario root poderá alterar o parametro.
** O parametro debug_level é inicializado, por padrão, com 1, indicando que deverão ser exibidas mensagens informativas. O valor podeŕa ser alterado para 0,2,3,4, para indicar quais mensagens serão exibidas.
* Como passar um parâmetro para o módulo, etc;
** A passagem de parametros é feita durante a carregamento de modulo com o comando insmod:
** # insmod ml_driver.ko debug_level=1.
*** Esse comando gera a seguinte mensagem para o kernel
*** usbcore: registered new interface driver missile_launcher
*** [info] usb_ml_init(657): driver registered successfully

## Reconhecimento ou detecção (probe)

* Quais dispositivos podem ser reconhecidos
** O driver analisado foi desenvolvido para um equipamento especifico, o USB missile Launcher, VendorID: 0x0a81, ProductID 0x0701.
** Os dispositivos reconheciveis sao definidos na struct struct usb_device_id ml_table.
* Como se processa a identificação do dispositivo
    Os valores de VendorID e ProductID na lista de dispositivos reconheciveis sao utilizados pela funcao static int ml_probe(struct usb_interface *interface, const struct usb_device_id *id) para verificar se o dispositivo conectado é suportado pelo driver.
    A função ml_probe é chamada sempre que, através do ponteiro probe da estrutura do USB driver, um novo dispositivo é acoplado ao barramento, ou seja, sempre que um dispositivo que bate com a informação provida pela ml_table.
    A função probe recebe como parametros a interface utilizada pelo novo dispositivo e uma entrada da tabela ml_table, indicando qual dispositivofoi detectado.
* O que ocorre quando o driver não é reconhecido
    Quando um dispositivo é reconhecido e todas as estruturas são alocadas com sucesso a função probe retorna 0, indicando que o dispositivo esta pronto para ser utilizado.
    Porém, sempre que durante o processo de reconhecimento ou de alocação ocorre algum erro, é utilizada um comando goto exit ou goto error;, indicando que não o dispositivo nao foi reconhecido ou que o driver não é capaz de controlar este dispositivo.

## Inicialização de estruturas

* quais estruturas são inicializadas
    Apos o reconhecimento do dispositivo a a função probe aloca memória para a estrutura interna do dispositivo (struct usb_ml),que contém informações sobre o status do dispositivo conectado, inicializa semáforos e spin-locks.
    Alem disso a função ml_probe também faz registro de estruturas de buffer e de URB(USB request block).
    O dispositivo estudado possui dois Endpoints: Endpoint 0 e Endpoint de interrupção. Portanto deve ser alocadas estruturas para armazenar informaçes sobre esses dois endpoints.

## Registro do driver (register)

Quando o módulo é carregado, a estrutura led_driver precisa ser registrada com o USB core. Isto é realizado com uma chamda a função usb_register.

### A função usb_register registra um driver USB com o USB_core. A lista de interfaces acopladas serão examinados novamente sempre que um novo driver é adicionado, permitindo que o novo driver para prender a todos os dispositivos reconhecidos. Retorna um código de erro negativo em caso de falha e 0 em caso de sucesso

Do mesmo modo, quando o driver é descarregado do sistema, ele deve "desregistrar" ele mesmo do USB core:
* Como o driver é reconhecido
* Quais procedimentos (comandos) para verificar qual dispositivo específico que foi reconhecido
* Quais drivers que foram carregados para o dispositivo, etc;

## Comunicação

A comunicação via USB se dá através dos chamados endpoints. Um endpoint pode transportar dados em uma única direção, seja do computador para o dispositivo (chamado OUT endpoint) ou do dispositivo para o computador (chamado IN endpoint). Os endpoints são descritos no kernel por um ponteiro que aponta para uma estrutura chamada usb_endpoint_descriptor, que contém todos os dados específicos da USB nos mesmos formatos especificados pelo próprio driver
A implementação do driver USB Linux utiliza um bloco de requisição USB (URB) como "suporte de dados" para se comunicar com dispositivos USB. URBS são como mensagens de dados que são enviadas de forma assíncrona a partir de e para os Endpoints. Lembrando que o padrão USB inclui quatro tipos de Endpoints. Da mesma forma, quatro tipos diferentes de URBS existem, ou seja, o controle, bulk, de interrupção e isócronos URBS. Uma vez que um URB é alocado e inicializado pelo driver, ele será submetido ao núcleo USB, que encaminha para o dispositivo. Se a URB foi entregue com sucesso para o núcleo USB, um manipulador de conclusão é executado. Em seguida, o núcleo USB de controle retorna para o driver de dispositivo.
Como o nosso lançador de mísseis possui dois Endpoints (Endpoint 0 e o Endpoint de interrupção), temos que lidar com o controle e a interrupção de URBS. Os comandos de engenharia reversa são, basicamente, embalado em um controle URB e depois enviado para o dispositivo. Além disso, estamos continuamente recebendo informações sobre o estado das interrupções periódicas URBs. Por exemplo, para enviar dados simples para o lançador de mísseis, a função usb_control_msg função é utilizada:
O comando cmd é inserido no buffer buf contendo os dados a serem enviados para o dispositivo. Se o URB é concluída com êxito, o manipulador correspondente é executado. Ele executa nada demais, exceto dizer ao driver que lançou um (ainda não corrigido) comando através da write syscall:
* arquivos especiais de dispositivo (/proc, /dev e /sys)
    A funcção ml_probe cria o arquivo especial /dev/mlx, após o resgistro do dispositivo, e é através deste arquivo que o dispositivo sera acessado.
* tipos de comunicação utilizados pelo driver (control, bulk, etc);
    Durante o processo de inicialização de estruturas são criados dois endpoints; de controle e interrupt.

## Finalização

* Mensagens de remoção do dispositivo:
    A fase de desconexão do dispositivo é invocada quando o USB core detecta que o dispositivo não está mais presente no sistema. No caso do driver ml_driver, a função associada a este evento é a função ml_disconnect(struct usb_interface *interface)
    Essa função tem o objetivo de desalocar as estruturas alocadas durante o processo de probe e de interromper as URBs que ainda estiverem ativas.
* desalocação/liberação de estruturas;

## Considerações finais

    A comunicação dos dispositivos com o espaço do usuário - e conseqüentemente com as aplicações - se dá por meio de entradas nos diretórios /proc, /sys e /dev do Linux. Para o dispositivo missile laucher é criada uma entrada no diretorio /dev/ml.
    O criador do driver desenvolveu uma aplicação para o usuário se comunicar com o dispositivo, que é responsavel por receber as solicitações do usuário e enviar para o dispositivo. Além do projeto de trabalho futuro o desenvolvimento de um driver Linux para um lançador de mísseis com uma web cam acoplada.

# Bibliografia/Referências

* http://code.google.com/p/mavam/source/browse/#svn/trunk/ml-driver
* http://matthias.vallentin.net/2007/04/writing-linux-kernel-driver-for-unknown.html
* http://lxr.free-electrons.com/
* http://www.makelinux.net/
Documentação Linux
/usr/src/linux-source-2.6.31/Documentation/usb/hiddev.txt /usr/src/linux-source-2.6.31/Documentation/usb/URB.txt