1.字符設備
字符設備、字符設備驅動與用戶空間訪問該設備的程序三者之間的關系
Linux內核中:
a -- 使用cdev結構體來描述字符設備;
b -- 通過其成員dev_t來定義設備號(分為主、次設備號)以確定字符設備的唯一性;
c -- 通過其成員file_operations來定義字符設備驅動提供給VFS的接口函數,如常見的open()、read()、write()等;
在Linux字符設備驅動中:
a -- 模塊加載函數通過 register_chrdev_region( ) 或 alloc_chrdev_region( )來靜態或者動態獲取設備號;
b -- 通過 cdev_init( ) 建立cdev與 file_operations之間的連接,通過 cdev_add( ) 向系統添加一個cdev以完成注冊;
c -- 模塊卸載函數通過cdev_del( )來注銷cdev,通過 unregister_chrdev_region( )來釋放設備號;
用戶空間訪問該設備的程序:
a -- 通過Linux系統調用,如open( )、read( )、write( ),來“調用”file_operations來定義字符設備驅動提供給VFS的接口函數;
2.例子
hello.c
#include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> static int major = 99; //主設備號(用於區分設備類) static int minor = 0; //次設備號(用於區分哪個設備) static dev_t devno; static struct cdev cdev1; struct class *hello_class; static int hello_open(struct inode *inodep, struct file *filep) { printk(KERN_ALERT "hello are opened \r\n"); return 0; } static struct file_operations hello_ops = { .open = hello_open, }; static int hello_init(void) { int ret; printk(KERN_ALERT "hello_init\r\n"); //第一步:將主設備號、次設備號轉化成dev_t類型 devno = MKDEV(major, minor); ret = register_chrdev_region(devno, 1, "hello"); if (ret < 0) { printk(KERN_ERR "my register_chrdev_region fail \r\n"); return ret; } printk(KERN_INFO "register_chrdev_region success\n"); //第二步:注冊字符設備驅動 cdev_init(&cdev1, &hello_ops); ret = cdev_add(&cdev1, devno, 1); if (ret < 0) { printk(KERN_ERR "Uable to add dev\n"); return ret; } printk(KERN_INFO "cdev_add success\n"); //第三步:2.6內核之后要向sys文件系統中添加設備 hello_class = class_create(THIS_MODULE, "hello"); device_create(hello_class, NULL, devno, NULL, "hello"); printk(KERN_INFO "device created success\n"); return 0; } static void hello_exit(void) { cdev_del(&cdev1); unregister_chrdev_region(devno, 1); printk(KERN_ALERT "hell_exit\r\n"); } MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);
test.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> main() { int fd; fd = open("/dev/hello",O_RDWR); if(fd<0) { perror("open fail \n"); return ; }else { printf("open /dev/hello success! \n"); } close(fd); }
makefile
#General Purpose Makefile for cross compile Linux Kernel module ifneq ($(KERNELRELEASE),) obj-m := hello.o #+=是連接字符串 else ARCH := arm CROSS_COMPILE := arm-linux-gnueabihf- KERN_DIR := /home/zqh/lichee/linux-zero-4.14.y #選擇內核路徑 PWD :=$(shell pwd) #當前路徑 all: $(info "1st") make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERN_DIR) M=$(PWD) modules clean: rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order .*.o.ko.cmd .*.ko.cmd .*.mod.o.cmd .*.o.cmd endif