结构体原型
struct cdev {
struct kobject kobj; //kobject对象
struct module *owner; //THIS_MODULE,类似于C++中的this指针
const struct file_operations *ops; //操作方法集
struct list_head list;
dev_t dev; //设备号(U32 32bit无符号整型)
unsigned int count; //设备计数
};
结构体空间开辟
struct cdev *cdev_alloc(void)
结构体空间初始化
/*
参数:
cdev设备结构体指针,初始化设备结构体指针;
fops:设备的操作方法集;
PS:为了保证内核空间的安全性,所以需要使用初始化函数实现
*/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
操作方法集的结构体
struct file_operations {
/* 一般传THIS_MODULE */
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 (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
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 (*aio_fsync) (struct kiocb *, 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 **);
long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
};
机构体注册
/**
* [cdev_add 将字符设备结构体添加到内核系统的驱动管理单元(链表)中,由内核进行统一调度]
* @param p [指向的字符设备注册结构体]
* @param dev [字符设备号]
* @param count [字符设备个数]
* @return [ 成功返回0,失败返回错误号]
*/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
字符设备移除
/*将字符设备结构体从内核中移除,并释放结构体空间*/
void cdev_del(struct cdev *p)
实例
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
/* 定义字符设备的操作方法集 */
int my_open(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "%s\n", __func__);
return 0;
}
int my_release(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "%s\n", __func__);
return 0;
}
static dev_t dev;/* 定义设备号变量 */
static unsigned int count = 1;
/* 定义字符设备结构体指针 */
struct cdev *cdevp;
/* 定义字符设备的操作方法集结构体 */
struct file_operations fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_release
};
/* 定义模块加载函数 */
static int __init my_module_init(void)
{
int ret;
/* 申请设备编号:采用动态申请方式 */
ret = alloc_chrdev_region(&dev, 0, count, "mychar");
if (ret != 0)
{
printk(KERN_ERR "register_chrdev_region: ret = %d\n", ret);
return ret;
}
printk(KERN_INFO "register_chrdev_region major:%d,minor:%d\n", MAJOR(dev), MINOR(dev));
/* 设备注册:将设备添加到内核驱动管理链表中,然后由系统进行统一调度 */
/* 开辟字符设备结构体空间 */
cdevp = cdev_alloc();
if (cdevp == NULL)
{
ret = -ENOMEM;
goto mychar_err0;
}
/* 初始化结构体成员 */
cdev_init(cdevp, &fops);
/* 将字符设备结构体cdev添加到system中,由内核统一调度 */
ret = cdev_add(cdevp, dev, count);
if (ret < 0)
{
goto mychar_err1;
}
printk(KERN_INFO "cdev register success\n");
return 0;
mychar_err1:
/* 释放字符设备结构体 */
cdev_del(cdevp);
mychar_err0:
/* 释放设备号 */
unregister_chrdev_region(dev, count);
return ret;
}
/* 定义模块卸载函数 */
static void __exit my_module_exit(void)
{
/* 释放字符设备结构体 */
cdev_del(cdevp);
/* 释放设备号 */
unregister_chrdev_region(dev, count);
}
/* 声明模块的加载入口 */
module_init(my_module_init);
/* 声明模块的卸载入口 */
module_exit(my_module_exit);
网友评论