Driver de dispositivo IOCTL Linux [fechado]


126

Alguém pode me explicar,

  1. O que é IOCTL?
  2. Para que isso é usado?
  3. Como posso usá-lo?
  4. Por que não consigo definir uma nova função que funcione da mesma maneira IOCTL?

Respostas:


99

An ioctl, que significa "controle de entrada e saída", é um tipo de chamada de sistema específica ao dispositivo. Existem apenas algumas chamadas de sistema no Linux (300-400), que não são suficientes para expressar todas as funções exclusivas que os dispositivos podem ter. Assim, um driver pode definir um ioctl que permite que um aplicativo no espaço do usuário envie pedidos. No entanto, os ioctls não são muito flexíveis e tendem a ficar um pouco confusos (dezenas de "números mágicos" que simplesmente funcionam ... ou não), e também podem ser inseguros, ao passar um buffer para o kernel - o mau manuseio pode quebrar coisas facilmente.

Uma alternativa é a sysfsinterface, na qual você configura um arquivo /sys/e lê / grava para obter informações de e para o driver. Um exemplo de como configurar isso:

static ssize_t mydrvr_version_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%s\n", DRIVER_RELEASE);
}

static DEVICE_ATTR(version, S_IRUGO, mydrvr_version_show, NULL);

E durante a configuração do driver:

device_create_file(dev, &dev_attr_version);

Você teria um arquivo para o seu dispositivo /sys/, por exemplo, /sys/block/myblk/versionpara um driver de bloco.

Outro método para uso mais pesado é o netlink, que é um método IPC (comunicação entre processos) para conversar com seu driver por uma interface de soquete BSD. Isso é usado, por exemplo, pelos drivers WiFi. Você então se comunica com ele no espaço do usuário usando as bibliotecas libnlou libnl3.


3
Essa resposta 'responde' parcialmente à pergunta.
Vishal Sahu

163

A ioctlfunção é útil para implementar um driver de dispositivo para definir a configuração no dispositivo. por exemplo, uma impressora que possua opções de configuração para verificar e definir a família da fonte, o tamanho da fonte etc. ioctlpode ser usada para obter a fonte atual e definir a fonte para uma nova. Um aplicativo de usuário usa ioctlpara enviar um código para uma impressora solicitando que ela retorne a fonte atual ou defina a fonte para uma nova.

int ioctl(int fd, int request, ...)
  1. fdé o descritor de arquivo, aquele retornado por open;
  2. requesté um código de solicitação. por exemplo GETFONT, obterá a fonte atual da impressora, SETFONTdefinirá a fonte na impressora;
  3. o terceiro argumento é void *. Dependendo do segundo argumento, o terceiro pode ou não estar presente, por exemplo, se o segundo argumento for SETFONT, o terceiro argumento pode ser o nome da fonte, como "Arial";

int requestnão é apenas uma macro. É necessário um aplicativo de usuário para gerar um código de solicitação e o módulo do driver do dispositivo para determinar com qual configuração o dispositivo deve ser reproduzido. O aplicativo envia o código de solicitação usando ioctle, em seguida, usa o código de solicitação no módulo do driver de dispositivo para determinar qual ação executar.

Um código de solicitação possui 4 partes principais

    1. A Magic number - 8 bits
    2. A sequence number - 8 bits
    3. Argument type (typically 14 bits), if any.
    4. Direction of data transfer (2 bits).  

Se o código de solicitação for SETFONTdefinir fonte em uma impressora, a direção da transferência de dados será do aplicativo do usuário para o módulo do driver de dispositivo (o aplicativo do usuário envia o nome da fonte "Arial"para a impressora). Se o código de solicitação for GETFONT, a direção é da impressora para o aplicativo do usuário.

Para gerar um código de solicitação, o Linux fornece algumas macros predefinidas semelhantes a funções.

1. _IO(MAGIC, SEQ_NO)ambos são 8 bits, 0 a 255, por exemplo, digamos que queremos pausar a impressora. Isso não requer uma transferência de dados. Então, geraríamos o código de solicitação como abaixo

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 

e agora use ioctlcomo

ret_val = ioctl(fd, PAUSE_PRIN);

A chamada do sistema correspondente no módulo do driver receberá o código e pausará a impressora.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICe SEQ_NOsão os mesmos que acima, e TYPEfornece o tipo do próximo argumento, lembre-se do terceiro argumento de ioctlé void *. W in __IOWindica que o fluxo de dados é do aplicativo do usuário para o módulo do driver. Como exemplo, suponha que desejamos definir a fonte da impressora para "Arial".
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

mais distante,

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 

Agora fonté um ponteiro, o que significa que é um endereço melhor representado como unsigned long, portanto, a terceira parte das _IOWmenções digita como tal. Além disso, esse endereço de fonte é passado para a chamada de sistema correspondente implementada no módulo do driver de dispositivo unsigned long e precisamos convertê-lo no tipo apropriado antes de usá-lo. O espaço do kernel pode acessar o espaço do usuário e, portanto, isso funciona. existem outras duas macros semelhantes a funções __IOR(MAGIC, SEQ_NO, TYPE)e __IORW(MAGIC, SEQ_NO, TYPE)onde o fluxo de dados será do espaço do kernel para o espaço do usuário e nos dois sentidos, respectivamente.

Por favor, deixe-me saber se isso ajuda!


Gostaria de saber se as funções __IOW, __IOR e __IORW acima estão corretas (quero dizer o sublinhado duplo em alguns casos, em alguns casos não. Eu nunca usei o sublinhado duplo) ... Obrigado por uma explicação clara!
Jcoppens # 9/16

Muito bem explicado .. Obrigado! Você pode fornecer um pequeno trecho de código do lado do driver que usa esse ioctl?
Aadishri


Muito bem explicado. Obrigado. Eu acho que é _IOWR não _IORW
Mohamed Samy

Responda como uma postagem no blog.
Fredrick Gauss
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.