En realidad son solo eso: interfaces. Codificados por un número "mayor" y "menor", proporcionan un enlace al núcleo.
Vienen en dos sabores (bueno, tres, pero las tuberías con nombre están fuera del alcance de esta explicación por ahora): dispositivos de caracteres y dispositivos de bloque.
Los dispositivos de bloque tienden a ser dispositivos de almacenamiento, capaces de almacenar en búfer la salida y almacenar datos para su posterior recuperación.
Los dispositivos de caracteres son cosas como tarjetas de audio o gráficas, o dispositivos de entrada como teclado y mouse.
En cada caso, cuando el kernel carga el controlador correcto (ya sea en el momento del arranque o mediante programas como udev ) escanea los diferentes buses para ver si algún dispositivo manejado por ese controlador está realmente presente en el sistema. Si es así, configura un dispositivo que 'escucha' en el número mayor / menor apropiado.
(Por ejemplo, el Procesador de señal digital de la primera tarjeta de audio encontrada por su sistema obtiene el par de números mayor / menor de 14/3; el segundo obtiene 14,35, etc.)
Depende de udev crear una entrada /dev
nombrada dsp
como un dispositivo de personaje marcado mayor 14 menor 3.
(En versiones de Linux con una huella mínima significativamente más antigua, es /dev/
posible que no se cargue dinámicamente, sino que solo contenga todos los archivos de dispositivo posibles de forma estática).
Luego, cuando un programa de espacio de usuario intenta acceder a un archivo marcado como 'archivo especial de caracteres' con el número mayor / menor apropiado (por ejemplo, su reproductor de audio intenta enviar audio digital /dev/dsp
), el núcleo sabe que estos datos deben se transmitirá a través del controlador al que está asociado el número mayor / menor presumiblemente dicho conductor sabe qué hacer con él a su vez.
Cada archivo, dispositivo o de otro tipo, admite 6 operaciones básicas dentro del VFS:
Además, los archivos del dispositivo admiten el control de E / S, que permite otras operaciones diversas que no están cubiertas por los primeros 6.
En el caso de un personaje especial, buscar y contar no se implementan ya que admiten una interfaz de transmisión . Es decir, leer o escribir directamente, como se hace con la redirección en el shell:
fuente
file_operations
Ejemplo ejecutable mínimoUna vez que vea un ejemplo mínimo, todo se vuelve obvio.
Las ideas clave son:
file_operations
contiene las devoluciones de llamada para cada syscall relacionado con el archivomknod <path> c <major> <minor>
crea un dispositivo de personaje que usa esosfile_operations
cat /proc/devices
character_device.ko
módulo del núcleo:Programa de prueba de Userland:
GitHub QEMU + Buildroot aguas arriba con repetitivo para ejecutarlo realmente:
Ejemplos más complejos:
read
,write
,lseek
Con un buffer interno de tamaño fijo y en debugfs en lugar de un dispositivo de caracteres: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/fops.cpoll
: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.cioctl
: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.canon_inode_getfd
asociafile_operations
a un descriptor de archivo sin ningún archivo de sistema de archivos: /programming/4508998/what-is-anonymous-inode/44388030#44388030fuente
*off = 1;
y por qué está configurado1
?read
llamadas al mismoopen(
descriptor de archivo. El conductor puede hacer lo que quiera con él. La semántica habitual es contener el número de bytes leídos. Sin embargo, en este ejemplo, tenemos una semántica más simple:0
para la primera lectura,1
después de la primera lectura. Intenta ejecutarlo y pon un paso printk o GDB para depurarlo."Carácter a la vez" es un nombre inapropiado (como lo es la idea de que los dispositivos de caracteres no son necesariamente compatibles con buscar y contar). De hecho, los dispositivos de "bloqueo a la vez" (es decir, estrictamente orientados a la grabación, como una unidad de cinta *) deben ser dispositivos de caracteres. También lo es la idea de que un dispositivo de caracteres debe ser necesariamente inescrutable: los controladores de dispositivos de caracteres definen una
file_operations
estructura completa que es libre de definir llseek o no según si el dispositivo admite la operación. Los dispositivos de caracteres que la mayoría de las personas consideran ejemplos son nulos, urandom, dispositivos TTY, tarjeta de sonido, mouse, etc., que no se pueden buscar debido a los detalles de esos dispositivos, pero / dev / vcs, / dev / fb0 , y / dev / kmem también son dispositivos de caracteres y todos son buscables.Como mencioné, un controlador de dispositivo de caracteres define una estructura de operaciones de archivo que tiene punteros de función para todas las operaciones que alguien quiera llamar en un archivo (buscar, leer, escribir, ioctl, etc.) y cada una de ellas se llama una vez cuando la llamada del sistema correspondiente se ejecuta con este archivo de dispositivo abierto. Y leer y escribir, por lo tanto, puede hacer lo que quiera con sus argumentos: puede negarse a aceptar una escritura que sea demasiado grande o solo escribir lo que cabe; solo puede leer los datos correspondientes a un registro en lugar del número total de bytes solicitado.
Entonces, ¿qué es un dispositivo de bloque? Básicamente, los dispositivos de bloque son unidades de disco. Ningún otro tipo de dispositivo (a excepción de las unidades de disco virtual , como ramdisk y loopback) es un dispositivo de bloque. Están integrados en el sistema de solicitud de E / S, la capa del sistema de archivos, el sistema de memoria intermedia / caché y el sistema de memoria virtual de una manera que los dispositivos de caracteres no lo son, incluso cuando está accediendo, por ejemplo, a / dev / sda desde un proceso de usuario . Incluso los "dispositivos en bruto" que la página menciona como excepción son los dispositivos de caracteres .
* Algunos sistemas UNIX implementaron lo que ahora se llama "modo de bloque fijo", que permite que el núcleo agrupe y divida las solicitudes de E / S para que se ajusten a los límites de bloque configurados de la misma manera que se hace para las unidades de disco, como un bloque dispositivo. Se necesita un dispositivo de caracteres para el "modo de bloque variable", que preserva los límites del bloque del programa del usuario, ya que una sola llamada de escritura (2) escribe un bloque y una sola llamada de lectura (2) devuelve un bloque. Dado que el cambio de modo se implementa ahora como un ioctl en lugar de un archivo de dispositivo separado, se utiliza un dispositivo de caracteres. Las unidades de cinta de registro variable son en su mayoría "no buscables" porque la búsqueda implica contar una cantidad de registros en lugar de una cantidad de bytes, y la operación de búsqueda nativa se implementa como un ioctl.
fuente
Los dispositivos de caracteres se pueden crear mediante módulos del núcleo (o el núcleo mismo). Cuando se crea un dispositivo, el creador proporciona punteros a las funciones que implementan manejan llamadas estándar como abrir, leer, etc. El kernel de Linux luego asocia esas funciones con el dispositivo de caracteres, por ejemplo, cuando una aplicación en modo de usuario llama a read () en un archivo de dispositivo de caracteres, dará como resultado una llamada al sistema y luego el núcleo enrutará esta llamada a una función de lectura especificada al crear el controlador. Hay un tutorial paso a paso en la creación de un dispositivo de caracteres aquí , puede crear un proyecto de ejemplo y el paso a través de él utilizando un depurador para comprender cómo se crea el objeto de dispositivo y cuando se invocan los manipuladores.
fuente