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

字符设备驱动程序框架相关推荐

  1. Linux驱动实践:你知道【字符设备驱动程序】的两种写法吗?

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  2. S3C2440 开发板实战(7):字符设备驱动框架+LED驱动

    在学习驱动的时候我遇到了很多问题,所以我的学习路线是这样的: 编写驱动发现.ko文件需要放入开发板的目录中,然后就学习通过nfs创建共享文件,在配置nfs时发现网络没有连接上,所以就学习怎样配置IP地 ...

  3. 设备树下的字符设备驱动框架

    设备树下的字符设备驱动框架 没有引入设备树时,相关寄存器物理地址是直接定义在驱动文件中的,通过地址映射成为虚拟地址后,再操作虚拟地址完成GPIO的初始化.设备树的本质也是操作寄存器,只不过寄存器的相关 ...

  4. Linux 驱动开发 三:字符设备驱动框架

    一.参考 (3条消息) Linux 字符设备驱动结构(一)-- cdev 结构体.设备号相关知识解析_知秋一叶-CSDN博客 (3条消息) linux设备驱动框架_不忘初心-CSDN博客_linux设 ...

  5. Linux之字符设备驱动框架

    目录 一.驱动介绍 1.内核模块 2.日志级别 3.模块符号的导出 4.内核模块参数 二.字符设备驱动(一) 1.模块加载 2.注册字符设备驱动 3.内存映射 三.字符设备驱动(二) 1.模块加载 2 ...

  6. 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)

    在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...

  7. 驱动学习----字符设备驱动框架

    字符设备驱动框架 1.字符设备驱动简介 2.file_operations 3.驱动模块的加载和卸载 4.字符设备的注册与注销 5.实现设备具体操作函数 6.添加LICENSE和作者信息 7.linu ...

  8. 字符设备驱动程序的传统写法

    以led驱动程序为例,介绍字符设备驱动程序的传统写法. 驱动程序: 程序代码来源于韦老大视频代码 1 #include <linux/module.h> 2 #include <li ...

  9. 第12课第3节 字符设备驱动程序之查询方式的按键驱动程序

    第12课第3节 字符设备驱动程序之查询方式的按键驱动程序 cat /proc/devices //查询主设备号 insmod ./second_drv.ko ls /dev/button -l pos ...

最新文章

  1. 推荐一款 Flutter Push 推送功能插件
  2. 超全超实用的Javascript类库和jQuery插件大全之一:图片,地图和图形
  3. Database:Database数据库的简介、类型及其区别(关系数据库VS非关系型数据库)、案例应用之详细攻略
  4. 云未来、新可能 - 绿色、无处不在、可信的计算
  5. k8s部署ingress:使用heptio-contour部署ingress controller(通过sealos安装,非nginx-ingress类型)
  6. 仓库移动_移动式仓库、检修作业平台、储油柜胶囊破裂检测装置……这场科技秀超燃!...
  7. modem(2)---Android modem log查看
  8. 学生管理系统php网站,学生信息管理系统 网站之modify.php
  9. go json tag 字符串 整数_json:你或许还不知道的序列化操作(一)
  10. protected的继承方式有什么特点_草莓的授粉方式有哪些?各有什么特点
  11. 27.crontab
  12. 使用matlab生成高斯滤波模板_matlab 高斯滤波(原创)
  13. [angular1.6]Error: transition superseded ui-router 在angular1.6 报错误问题解决
  14. 做项目和做产品有什么区别
  15. Angular入门到精通系列教程(1) - Angular,Vue,React 选型
  16. Android imagebutton美化+edittext美化 实现登录界面美化
  17. catti二级笔译综合能力真题_二级笔译CATTI近十年真题及参考答案
  18. 安装了VCam后,VideoCapture 出问题,FileStorage fs(X.yml, FileStorage::READ)报错
  19. linux .gz文件 解压缩命令的简单使用
  20. 计算机教学楼起名,“我为学校楼宇起名”征集

热门文章

  1. C++ VARIANT 学习小记录
  2. dmidecode 命令详解(获取硬件信息)
  3. 如何:从 Windows 窗体 DataGridView 控件中移除自动生成的列
  4. V4L2开发要点【转】
  5. 高级持续性威胁检测无法检测出自定义恶意软件?
  6. Linux命令之乐--expr
  7. 阿里巴巴陈武:通过亿级用户App的实践验证,锤炼高质量APM体系
  8. 《从零开始学Swift》学习笔记(Day 7)——Swift 2.0中的print函数几种重载形式
  9. Android Json生成及解析实例
  10. [资料整理] Decentralized Services Orchestration, Choreography相关的几篇论文