Introducción al concepto de unidad de caracteres Linux

1. Marco basado en caracteres

P: ¿Cómo las aplicaciones abren, leen y escriben para encontrar las funciones de abrir, leer y escribir del controlador?

Respuesta: La aplicación de abrir, leer y escribir se implementa en la biblioteca C. Activa una excepción a través de la instrucción swi val. Esta excepción ingresará al espacio del kernel. En la función de manejo de excepciones del kernel, hay una entrada basada en Val para decidir si llamar a las funciones system_open o system_read, system_write, estas funciones tienen diferentes atributos de acuerdo con nuestros archivos abiertos diferentes, diferentes archivos tienen diferentes atributos (como el tipo de dispositivo (dispositivo de caracteres o dispositivo de bloque o dispositivo de red), según el número del dispositivo principal) Estos atributos encuentran el controlador de nivel inferior.

 

P: ¿Cuál es el número de dispositivo principal y cuál es el número de dispositivo secundario?

Respuesta: El número de dispositivo principal de Linux se usa para distinguir entre diferentes tipos de dispositivos de hardware, como la diferencia entre el LED y el puerto serie; el
número de dispositivo secundario de Linux se usa para distinguir entre diferentes dispositivos de hardware, como la diferencia entre el puerto serie 1 y el puerto serie 2;

 

P: ¿Qué método se utiliza para encontrar la función abierta del controlador?

Respuesta: a través de una función de registro + nodo de dispositivo

Las funciones de registro son las siguientes (las funciones de registro antiguas, las nuevas se discutirán más adelante):

register_chrdev (unsigned int major, const char * name, const struct file_operations * fops)

Parámetro 1: número de dispositivo principal (importante)

Parámetro 2: Nombre (no importante)

Parámetro 3: estructura de operaciones de archivo (importante)

Nodo de dispositivo:

Se puede crear de forma manual o automática. Por el momento, solo se creará manualmente.

mknod / dev / xxx c 252 0

Cree un nodo de dispositivo llamado / dev / xxx, c representa el nodo del dispositivo de caracteres, 252 es el número de dispositivo principal y 0 es el número de dispositivo secundario.

 

P: El programa de aplicación generalmente es ejecutado por la función principal, entonces, ¿cuál es el programa de controlador que debe ejecutarse primero?

Respuesta: A través de una macro, especifique la función de entrada del controlador, y la función de entrada se ejecutará cuando se cargue el controlador.

Por ejemplo: module_init (first_drv_init); // Se usa para modificar la función de entrada

Naturalmente, la función de salida del controlador se ejecutará cuando el controlador esté descargado.

Por ejemplo: module_exit (first_drv_exit); // Se usa para modificar la función de exportación
 

 

El programa fuente del controlador es el siguiente:

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
 
 
int major;
static int first_drv_open(struct inode * inode, struct file * filp)
{
	printk("first_drv_open\n");
	return 0;
}
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
	printk("first_drv_write\n");
	return 0;
}
 
/* File operations struct for character device */
static const struct file_operations first_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= first_drv_open,
	.write      = first_drv_write,
};
 
/* 驱动入口函数 */
static int first_drv_init(void)
{
	/* 主设备号设置为0表示由系统自动分配主设备号 */
	major = register_chrdev(0, "first_drv", &first_drv_fops);
	return 0;
}
 
/* 驱动出口函数 */
static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv");
}
 
module_init(first_drv_init);  //用于修饰入口函数
module_exit(first_drv_exit);  //用于修饰出口函数	
 
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL");  //遵循GPL协议

El código fuente de Makefile es el siguiente:

ifneq ($(KERNELRELEASE),)
 
obj-m := first_drv.o
 
else
	
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
 
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
 
endif

El procedimiento de prueba es el siguiente:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
int main(void)
 
{
	int fd;
	int val = 1;
	fd = open("/dev/xxx",O_RDWR);    //打开名为  /dev/xxx  的设备节点
	if(fd < 0)
	{
		printf("open error\n");
	}
	
	write(fd,&val,4);
	
	return 0;
}

Los pasos de prueba en la placa de desarrollo son los siguientes:

[WJ2440]# insmod first_drv.ko 
[WJ2440]# ./first_test 
open error                    //没有创建设备节点
[WJ2440]# cat proc/devices 
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 81 video4linux
 89 i2c
 90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 tq2440_serial
252 first_drv                //我们创建的字符设备,主设备号252
253 usb_endpoint
254 rtc
 
Block devices:
259 blkext
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[WJ2440]# mknod /dev/xxx c 252 0        //手动创建一个字符设备节点
[WJ2440]# ls -l /dev/xxx 
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
[WJ2440]# ./first_test                 //有设备节点后成功我们的应用程序运行了
first_drv_open
first_drv_write
[WJ2440]# 

Este artículo se refiere a:

https://blog.csdn.net/lwj103862095/article/details/17468587

42 artículos originales publicados · Me gusta 10 · Visitantes más de 10,000

Supongo que te gusta

Origin blog.csdn.net/qq_37659294/article/details/104302700
Recomendado
Clasificación