字符型驱动
字符设备驱动结构
cdev结构体
用于完成描述一个字符设备。顶层。
- 结构体定义
struct cdev {
struct kobject kobj; /* 内嵌的kobject对象 */
struct module *owner; /* 所属模块*/
struct file_operations *ops; /* 文件操作结构体*/
struct list_head list;
dev_t dev; /* 设备号*/
unsigned int count;
};
- cedv的操作
void cdev_init(struct cdev *, struct file_operations *);//初始化结构体
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned);//注册字符设备,通常在驱动加载模块中调用
void cdev_del(struct cdev *);//注销设备,通常在驱动卸载模块中调用
dev设备号
- 设备号定义与相互转换
设备号为dev_t类型,32位,其中12位为主设备号(major),20位为次设备号(minor)。两者转换方法如下。
dev_t dev_num;
int dev_major,dev_minor;
//设备号到主次设备号,分离
dev_major=MAJOR(dev_num);
dev_minor=MINOR(dev_num);
//主次设备号到设备号,结合
dev_num=MKDEV(dev_major,dev_minor)
- 设备号分配与释放
- 在调用cdev_add()函数向系统注册字符设备之前,应首先申请设备号。
申请方式有两种:
register_chrdev_region(dev_t first,uint count,char *name);//(设备号起始值,设备个数,设备名)指定分配
alloc_chrdev_region(dev_t *dev_num,uint baseminor,uint count,char *name)//(用于接受分配设备号,次设备号起始值,设备个数,设备名)动态分配。
- 在调用cdev_del()注销字符设备后,应释放申请的设备号。
unregister_chrdev_region(dev_t first, unsigned count);
file_operations结构体
file_operations结构体中的成员函数是字符设备驱动程序设计的主体内容,包括open()、write()、read()、close()等。
该结构体成员较多,因此这里只展示常用成员:
struct file_operations {
struct module *owner;
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
loff_t (*llseek) (struct file *, loff_t, int);//修改文件的当前读写位置
int (*mmap) (struct file *, struct vm_area_struct *);
字符驱动程序框架
字符设备驱动程序设计框架
1.实现字符设备功能函数
基本功能函数:
static int char_device_open(struct inode *inode, struct file *filp);
static int char_device_release(struct inode *inode, struct file *filp);
static ssize_t char_device_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos);
static ssize_t char_device_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos);
2.定义和赋值file_operations结构
主要是以下7项:
static const struct file_operations char_device_fops={
.owner = THIS_MODULE,
.open = char_device_open,
.release = char_device_release,
.read = char_device_read,
.write = char_device_write,
};
3.初始化设备
完成设备初始化需要完成设备号申请,字符设备结构初始化、字符设备添加。
a.设备号申请
设备号由dev_t 类型定义,12位主设备号(major)20位次设备号(minor),共32位。dev_t类型和int类型相互转化方法为:
dev_major=MAJOR(dev_num); dev_minor=MINOR(dev_num); //dev_t到int
dev_num=MKDEV(dev_major,dev_minor)//int到dev_t
设备号有两种申请方式:
register_chrdev_region(devno,1,"char_device");//指定主设备号申请
alloc_chrdev_region(&devno,0,1,"char_device");//内核分配主设备号申请
b. 字符设备结构初始化
cdev_init(&(char_device_devp->cdev),&globalmem_fops);
c.激活字符设备
cdev_add(&(char_device_devp->cdev),devno,1);
- 设备退出
设备退出时,需要删除设备、释放设备号。
cdev_del(&globalmem_devp->cdev);
unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
待归类知识点
内存申请函数
内存申请函数有:kmalloc()、kzalloc()、vmalloc() 。
- kmalloc()
申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过128KB。分配过程是原子操作,不能被中断。对应释放函数kfree()。 - kzalloc()
与 kmalloc() 相似,参数及返回值是一样的,可以说是前者是后者的一个变种,因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外,还会对申请到的内存内容清零。对应释放函数kfree()。
-vmalloc()
在虚拟内存空间给出一块连续的内存区,但这片连续的虚拟内存在物理内存中并不一定连续。由于 vmalloc() 没有保证申请到的是连续的物理内存,因此对申请的内存大小没有限制,如果需要申请较大的内存空间就需要用此函数了。vmalloc() 和 vfree() 可以睡眠,因此不能从中断上下文调用。对应释放函数vfree()。