字符设备驱动

字符设备驱动

1.1 主设备号与此设备号

在构建字符设备驱动时候需要获得设备编号,类似于汽车牌照,没有没办法上路。主设备号标识设备对应的驱动程序,而次设备号由内核使用,用于确定/dev下的设备文件对应的具体设备。eg:虚拟控制台和串口终端有驱动程序4管理,而不同的终端分别有不同的次设备号。

MAJOR(dev_t dev); 获取主设备号

MINOR(dev_t dev); 获取此设备号

MKDEV(int major, int minor); 将主次设备号转化为dev_t类型

1.2 设备号分配与释放

分配

在已知主设备号时

int register_chrdev_region(dev_t first, unsigned int count, const char name);

first 设备编号起始值,count 连续设备编号个数, name与该设备关联的设备名称,会出现在/proc/devices和sysfs中,函数成功返回0

未知主设备号时

int alloc_chrdev_region(dev_t dev, unsigned int firstminor, unsigned int count, const char *name)

dev 用于存放申请的设备号, firstminor 要使用第一个此设备编号,此函数相比较于前面函数优点可以避免设备号重复的冲突

释放

void unregister_chrdev_region(dev_t dev, unsigned int count)

注意 :在调用cdev_del()注销字符设备时需要先调用unregister_chrdev_region()释放设备号

2 字符设备注册

在上面申请”牌照(设备号)“之后需要将牌照和 ’汽车(设备驱动)“绑定激活

void cdev_init(struct cdev *cdev, struct file_operation *fops) 初始化cdev成员,建立file_operations之间联系

int cdev_add(struct cdev *dev, dev_t num, unsigned int count)

void cdev_del(struct cdev *dev) 添加和删除一个cdev,即字符设备的注册与注销

3、cdev结构体成员

cdev结构体用于描述字符设备,

struct cdev {

struct kobject kobj;//内嵌的kobject对象    

struct module *owner;所属模块,通常为THIS_MODULE

const struct file_operations *ops;//文件操作结构体 ops 见上面4

struct list_head list; //实现链表,包含所有该设备的设备特殊文件的inode ???

dev_t dev; //设备号    

unsigned int count;//与该设备关联的设备数目

};

4 file_operations结构体成员函数

file_operations是VFS和磁盘文件系统、普通外设之间的结构,即是字符设备和内核的接口,对字符设备文件的打开、关闭、读写、控制等最终会该结构体中的函数调用。其功能如下

  • 对设备初始化和释放
  • 把数据从内核传送到硬件和从硬件读取数据
  • 读取应用程序传送给设备文件的数据和回送应用程序请求的数据
  • 检测和处理设备出现的错误

file_operations结构体成员函数数目十分庞大,只针对结构体中的打开、关闭、读写等主要成员进行分析

struct module *owner 一般被定义 THIS_MODULE,用来在操作正在被使用时阻止模块被卸载

loff_t (*llseek)(struct file*, loff_t, int) 文件定为函数,file* 文件指针,请求偏移量,文件定位起始位(0 文件开头,1当前位置)

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 内核读取用户空间数据,常与copy_to_user()搭配使用

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);  内核向用户空间写数据,与copy_from_user()搭配使用

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 设备相关控制命令

int (*open) (struct inode *, struct file *); 打开文件时被调用

int (*release) (struct inode *, struct file *)  ; 关闭文件,并释放资源

5、file结构体成员

系统每打开一个文件内核空间都会有一个struct file与其关联,设备文件同理。他由内核打开时创建,并传递给在文件上操作的任何函数,最常用的私有数据指针private_data,read(),write(),ioctl(),llseek()等函数通过它访问设备结构体。文件所有实例都关闭后,内核会释放该数据结构。

struct file {

         const struct file_operations    *f_op; 
         unsigned int           f_flags;
         fmode_t              f_mode; 
         loff_t                 f_pos;
         struct fown_struct       f_owner;
         void                  *private_data;

 };
  • f_mode 确定文件读写,通过FMODE_READ和FMODE_WRITE确定
  • f_flags 文件标志,O_RDONLY,O_NONBLOCK,O_SYCN,所有文件标志在linux/fcntl.h中定义,O_NONBLOCK可以用来判断设备文件是以阻塞还是非阻塞方式打开
  • private_data 比较常用,open系统调用时会将这个指针定义为NULL,如果需要也可在open中指向分配的数据,但要注意需要在release中释放内存
  • f_ops 当前读写位置,read、write都是以它为最后参数来更新位置

6 inode结构体

VFS中每个文件都会关联一个inode,用来管理文件的属性(文件访问权限,大小,生成时间,访问时间,最后修改信息,文件系统最基本单位,也是连接任何子目录、文件桥梁)

struct inode {

         umode_t             i_mode;
         dev_t                i_rdev;
         struct list_head        i_devices;
         union {
                 struct pipe_inode_info  *i_pipe;
                 struct block_device     *i_bdev;
                 struct cdev             *i_cdev;
        };
       void *i_private; /* fs or device private pointer */
};
  • i_mode 存储文件类型面向块,还是面向字符
  • i_rdev 主从设备号,
  • i_cdev 见3

7字符设备打开时流程

当打开字符设备文件时,内核为该文件分配file结构体,通过inode判断读写状态,读取inode.i_cdev>file_operations.open函数,可以在其中指定file.private_data,可以通过file_operations中的read、write等完成对字符设备的数据从内核传送到硬件和从硬件读取数据,读取应用程序传送给设备文件的数据和回送应用程序请求的数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值