字符设备驱动程序框架
1, 设备号的内部表示形式
类型:dev_t 32=12(主设备号) + 20(次设备号)
相关宏:<linux/kdev_t.h>
MAJOR(dev_t dev)
MINOR(dev_t dev)
MKDEV(int major, int minor);
2. 分配和释放设备号
相关函数:
//静态分配设备号
int register_chrdev_region(dev_t first, unsigned int count,
char *name);
//动态分配设备号
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,
unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);
3.获取设备号的通常写法
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr_devs, "scull");
} else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
"scull");
scull_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
return result;
}
4.一些重要的数据结构
struct file_operations
{
//用于防止一个正在使用的模块被卸载,通常值为THIS_MODULE
struct module *owner;
//seek
loff_t (*llseek) (struct file *, loff_t, int);
//read
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);
//write
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *);
//readdir
int (*readdir) (struct file *, void *, filldir_t);
//poll
unsigned int (*poll) (struct file *, struct poll_table_struct *);
//ioctl
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
//mmap
int (*mmap) (struct file *, struct vm_area_struct *);
//open
int (*open) (struct inode *, struct file *);
//flush
int (*flush) (struct file *);
//release
int (*release) (struct inode *, struct file *);
//fsync
int (*fsync) (struct file *, struct dentry *, int);
int (*aio_fsync)(struct kiocb *, int);
int (*fasync) (int, struct file *, int);
//lock
int (*lock) (struct file *, int, struct file_lock *);
//readv writev
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
//sendfile
ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *);
//sendpage
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *,
int);
//get_unmapped_area
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned
long, unsigned long, unsigned long);
//check_flags
int (*check_flags)(int)
//dir_notify
int (*dir_notify)(struct file *, unsigned long);
...
};
//代表打开的文件
struct file
{
//读写权限
mode_t f_mode;
//文件读写位置
loff_t f_pos;
//文件标志(O_RDONLY, O_NONBLOCK, O_SYNC)
unsigned int f_flags;
//文件操作
struct file_operations *f_op;
//设备文件的私有数据
void *private_data;
//与文件相关的目录,
struct dentry *f_dentry;
...
};
struct inode
{
//对于设备文件来说,此域表示真实的设备号
dev_t i_rdev;
//当引结点指向一个字符设备时,代表内核内部结构的字符设备
struct cdev *i_cdev;
};
//从I结点中获取次设备号
unsigned int iminor(struct inode *inode);
// 从I结点中获取主设备号
unsigned int imajor(struct inode *inode);
5. 注册字符设备
头文件:<linux/cdev.h>
cdev 结构体的定义:
struct cdev
{
struct kobject kobj; /*内嵌的kobject对象*/
struct module *owner; /*所属模块*/
struct file_operations *ops; /*相关的文件操作*/
struct list_head list;
dev_t dev; /*设备模块*/
unsigned int count;
};
分配和初始化字符设备相关结构
方法1(将cdev作为单独的一个结构):
struct cdev *my_cdev = cdev_alloc( ); //分配设备空间
my_cdev->ops = &my_fops;
//设备初始化
void cdev_init(struct cdev *cdev, struct file_operations *fops);
//添加设备
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
//删除设备
void cdev_del(struct cdev *dev);
方法2(将cdev作为自定义设备结构的一个成员):
struct mydev
{
…
struct cdev;
}
设备分配初始化以及删除操作类似
PS: 2.6内核以前的字符设备注册方法
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
int unregister_chrdev(unsigned int major, const char *name);
6. 字符设备驱动程序模板
字符设备驱动模块加载和卸载函数模板
//设备结构体
struct xxx_dev_t
{
struct cdev cdev;
…
};
//设备驱动模块加载函数
static int __init xxx_init(void)
{
…
//初始化cdev
cdev_init(&xxx_dev.cdev, &xxx_fops);
//获取字符设备号
if(xxx_major)
{
register_chrdev_region(xxx_dev_no, 1, DEV_NAME);
}
else
{
alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME);
}
//注册设备
ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1);
}
//设备驱动模块卸载函数
static void __exit xxx_exit(void)
{
//释放占用的设备号
unregister_chrdev_region(xxx_dev_no, 1);
//注销设备
cdev_del(&xxx_dev.cdev);
…
}
字符设备常用I/O操作函数模板
//读设备
ssize_t xxx_read(struct file *filep, char __user *buf, size_t count, loff_t *f_pos)
{
…
copy_to_user(buf, …, …);
…
}
//写设备
ssize_t xxx_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos)
{
…
copy_from_user(…, buf, …);
…
}
//ioctl函数
int xxx_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
{
…
switch(cmd)
{
case XXX_CMD1:
…
break;
case XXX_CMD2:
…
break;
default:
//不能支持的命令
return –ENOTTY;
}
return 0;
}
用户空间与内核空间的数据传输
//内核空间到用户空间数据的复制
unsigned long copy_to_user(void __user *to, const void *from,
unsigned long count);
//用户空间到内核空间的复制
unsigned long copy_from_user(void *to, const void __user *from,
unsinged long count);
上述函数均返回不能被复制的字节数,因此,如果完全复制成功,返回值为0.
如果要复制的内在是简单类型,如char, int,long等,则可以使用简单的put_user()和get_user()函数。
如:
int val;
…
get_user(val, (int*)arg);
…
put_user(val, (int*)arg);
转载于:https://my.oschina.net/fuyajun1983cn/blog/263899
字符设备驱动程序框架相关推荐
- Linux驱动实践:你知道【字符设备驱动程序】的两种写法吗?
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...
- S3C2440 开发板实战(7):字符设备驱动框架+LED驱动
在学习驱动的时候我遇到了很多问题,所以我的学习路线是这样的: 编写驱动发现.ko文件需要放入开发板的目录中,然后就学习通过nfs创建共享文件,在配置nfs时发现网络没有连接上,所以就学习怎样配置IP地 ...
- 设备树下的字符设备驱动框架
设备树下的字符设备驱动框架 没有引入设备树时,相关寄存器物理地址是直接定义在驱动文件中的,通过地址映射成为虚拟地址后,再操作虚拟地址完成GPIO的初始化.设备树的本质也是操作寄存器,只不过寄存器的相关 ...
- Linux 驱动开发 三:字符设备驱动框架
一.参考 (3条消息) Linux 字符设备驱动结构(一)-- cdev 结构体.设备号相关知识解析_知秋一叶-CSDN博客 (3条消息) linux设备驱动框架_不忘初心-CSDN博客_linux设 ...
- Linux之字符设备驱动框架
目录 一.驱动介绍 1.内核模块 2.日志级别 3.模块符号的导出 4.内核模块参数 二.字符设备驱动(一) 1.模块加载 2.注册字符设备驱动 3.内存映射 三.字符设备驱动(二) 1.模块加载 2 ...
- 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)
在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...
- 驱动学习----字符设备驱动框架
字符设备驱动框架 1.字符设备驱动简介 2.file_operations 3.驱动模块的加载和卸载 4.字符设备的注册与注销 5.实现设备具体操作函数 6.添加LICENSE和作者信息 7.linu ...
- 字符设备驱动程序的传统写法
以led驱动程序为例,介绍字符设备驱动程序的传统写法. 驱动程序: 程序代码来源于韦老大视频代码 1 #include <linux/module.h> 2 #include <li ...
- 第12课第3节 字符设备驱动程序之查询方式的按键驱动程序
第12课第3节 字符设备驱动程序之查询方式的按键驱动程序 cat /proc/devices //查询主设备号 insmod ./second_drv.ko ls /dev/button -l pos ...
最新文章
- 推荐一款 Flutter Push 推送功能插件
- 超全超实用的Javascript类库和jQuery插件大全之一:图片,地图和图形
- Database:Database数据库的简介、类型及其区别(关系数据库VS非关系型数据库)、案例应用之详细攻略
- 云未来、新可能 - 绿色、无处不在、可信的计算
- k8s部署ingress:使用heptio-contour部署ingress controller(通过sealos安装,非nginx-ingress类型)
- 仓库移动_移动式仓库、检修作业平台、储油柜胶囊破裂检测装置……这场科技秀超燃!...
- modem(2)---Android modem log查看
- 学生管理系统php网站,学生信息管理系统 网站之modify.php
- go json tag 字符串 整数_json:你或许还不知道的序列化操作(一)
- protected的继承方式有什么特点_草莓的授粉方式有哪些?各有什么特点
- 27.crontab
- 使用matlab生成高斯滤波模板_matlab 高斯滤波(原创)
- [angular1.6]Error: transition superseded ui-router 在angular1.6 报错误问题解决
- 做项目和做产品有什么区别
- Angular入门到精通系列教程(1) - Angular,Vue,React 选型
- Android imagebutton美化+edittext美化 实现登录界面美化
- catti二级笔译综合能力真题_二级笔译CATTI近十年真题及参考答案
- 安装了VCam后,VideoCapture 出问题,FileStorage fs(X.yml, FileStorage::READ)报错
- linux .gz文件 解压缩命令的简单使用
- 计算机教学楼起名,“我为学校楼宇起名”征集
热门文章
- C++ VARIANT 学习小记录
- dmidecode 命令详解(获取硬件信息)
- 如何:从 Windows 窗体 DataGridView 控件中移除自动生成的列
- V4L2开发要点【转】
- 高级持续性威胁检测无法检测出自定义恶意软件?
- Linux命令之乐--expr
- 阿里巴巴陈武:通过亿级用户App的实践验证,锤炼高质量APM体系
- 《从零开始学Swift》学习笔记(Day 7)——Swift 2.0中的print函数几种重载形式
- Android Json生成及解析实例
- [资料整理] Decentralized Services Orchestration, Choreography相关的几篇论文