1.驱动文件
helloDev.c
Makefile
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#define BUFFER_MAX (10)
#define OK (0)
#define ERROR (-1)
struct cdev *gDev = NULL;
struct file_operations *gFile = NULL;
dev_t devNum;
unsigned int subDevNum = 1;
int reg_major= 232;
int reg_minor = 0;
char *buffer = NULL;
int flag = 0;
int hello_open(struct inode *p, struct file *f) {
printk(KERN_EMERG "hello_open\r\n");
return 0;
}
ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l) {
printk(KERN_EMERG "hello_write\r\n");
return 0;
}
ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l) {
printk(KERN_EMERG "hello_read\r\n");
return 0;
}
int hello_init(void) {
devNum = MKDEV(reg_major, reg_minor);
if (OK == register_chrdev_region(devNum, subDevNum, "helloworld")) {
printk(KERN_EMERG "register_chrdev_region ok\n");
}
else {
printk(KERN_EMERG "register_chrdev_region error\n");
return ERROR;
}
printk(KERN_EMERG "hello driver init\n");
gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
gFile->open = hello_open;
gFile->read = hello_read;
gFile->write = hello_write;
gFile->owner = THIS_MODULE;
cdev_init(gDev, gFile);
cdev_add(gDev, devNum, 3);
return 0;
}
void __exit hello_exit(void) {
cdev_del(gDev);
unregister_chrdev_region(devNum, subDevNum);
return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
2.helloDev.c解析
C语言程序的入口是main函数,而驱动的入口函数是什么呢?
module_init声明了驱动的入口函数是hello_init
当执行insmod指令的时候就会执行这个入口函数
module_exit声明了驱动的删除函数hello_exit
MODULE_LICENSE用于说明版权
devNum = MKDEV(reg_major, reg_major);
根据主设备号reg_major,从设备号号reg_major,MKDEV函数生成一个设备号,MKDEV规则是:
设备号用于唯一标识一个设备,主设备号用于标识一类设备,
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
register_chrdev_region(devNum, subDevNum, "helloworld")
把上面的设备号注册到内核中,subDevNum标识设备数量
注册之后,这个设备号,别人就不可以再使用了
int register_chrdev_region(dev_t from, unsigned count, const char *name)
gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
用于申请一个结构体cdec,cdev表示一个字符设备
gFile = kzalloc(sizeof(struct file_operation), GFP_KERNEL);
用于申请一个file_operation结构体,file表示一个文件,file_operation表示对这个文件的操作
在内核中,设备也是文件
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
int (*iterate_shared) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(struct file *);
#endif
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
loff_t, size_t, unsigned int);
int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
u64);
ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
u64);
};
cdev_init(gDev, gFile);
gDev表示设备,gFile表示文件操作,建立了字符设备和文件操作之间的关系
cdev_add(gDev, devNum, 1);
建立了字符设备gDev和设备号devNum之间的联系