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: