最近在看驱动模型,是越看越糊涂,以前接触比较多的都是一些字符驱动,对字符驱动的框架有一定的了解。后来因为想在驱动中实现设备文件的创建,又了解了一下,sysfs文件系统和udev设备文件系统,必然就涉及到了驱动模型。可是发现驱动模型和以前接触的字符驱动没什么联系。
比如,以前写字符驱动,主要的内容就是实现file_operations结构体里的函数,然后就是申请设备号,注册字符设备,根本就没有涉及到设备驱动模型。而驱动模型里,device_driver根本没有涉及到设备操作的函数、file_operations等,只有一些电源管理,热插拔相关的函数。platform_device里也主要是resource的管理,所以感觉两者根本就没关系,也很奇怪为什么要弄两套东西来实现,而且两者也对应不起来。
后来看了一些内核中的驱动源码,发现很多都是用miscdevice、platform_device、platform_driver实现的,而且流程很相似:

1、在系统初始化阶段注册platform_device,主要是添加设备对应的resource进链表,以便系统对设备占用的资源统一管理;
2、实现platform_driver并注册,在这部分,需要实现的主要有platform_driver结构体中的probe,还有remove、shutdown等一些关于热插拔、电源管理方面的函数。
3、然后在模块初始化函数(xx_init)里注册platform_driver(platform_driver_register)

其中设备资源的获取(platform_get_resource),如IO内存、IO端口、中断号,申请(request),物理地址到虚拟地址的映射(ioremap),misc_device的注册(misc_register),时钟的获取(clk_get)及使能(clk_enable)都是在probe函数里实现的,probe函数是在platform_driver注册,或者新设备添加时,platform_device和platform_driver匹配(通过名字)成功后执行的,有别于以往接触的字符驱动里的注册流程。
对于misc_device对于设备操作函数的实现和字符设备一样,都是填充file_operations结构体,然后在模块初始化函数里注册(misc_register)。
对于platform驱动模型,似乎就是platform_device负责设备资源,platform_driver负责电源管理以及资源的申请,中断的注册等设备初始化及启动有关的操作,然后就是设备操作方法(file_operations)的注册(misc_register或者cdev_add),cdev或者misc_device就负责file_operations。

但是目前还有不少疑问:
1、设备号的申请在哪里,它是怎么放到驱动模型里的device结构体中的?
2、platform_driver结构体和其中的device_driver结构体中都有probe、remove、shutdown等,为什么要在外层放重复的东西,二者有什么关系和区别嘛?
3、misc_register实现里最终和platform_device_register一样都会调用device_add,这样在设备驱动模型里不是有两个device和device_driver对应,而实际的物理设备只有一个嘛?
4、看起来好像驱动模型是对实际的设备及驱动的抽象,提取它们的信息包装成内核对象kobject,然后按照它们之间的关系对其进行分类、分层次管理(建立一棵树),借由这些对象,由系统管理设备资源的注册申请、释放以及实际驱动(file_operations)的注册时机(由此可以实现热插拔,即插即用)和电源管理(系统可以根据设备树来决定设备关闭的顺序,device->device_driver->shutdown)。
所以设备驱动模型中,device只是用来建立设备树,最终会根据结构体中的device_driver中的电源管理函数实现合理的电源开关顺序?
而对于热插拔有关的功能,和device与device_driver的匹配过程有关,而与设备树层次关系无关?
( 以上是目前想到的不明白的地方,遗漏的地方想起会再添加。改天找老师好好问问,太复杂了! )

===============================================
最近研究Linux设备驱动程序遇到混乱,请大侠过来理理头绪。
Linux设备模型中:bus_type、device、device_driver
《Linux设备驱动程序》的linux设备模型章中说到设备模型中,所有设备都通过总线相连。
添加设备devA,必须指定其device结构体的bus_type域,初始化其他域,然后调用device_register(&devA),将设备devA
注册到指定总线。
添加该设备驱动driverA,也必须指定其device_driver结构体的bus_type域,初始化其他域,然后调用driver_register(&driverA),
将该驱动注册到总线上。
如果驱动driverA和设备devA匹配成功,即调用probe函数成功,则建立他们之间的符号链接,即将设备与驱动捆绑起来。
而实际我看Linux源代码中却大量使用platform_device,
struct platform_device {       
const char        * name;        
u32                id;                
struct device        dev;       
u32                num_resources;     
struct resource        * resource;
};

struct platform_driver {                                                                                 
int (*probe)(struct platform_device *);                           
int (*remove)(struct platform_device *);                          
void (*shutdown)(struct platform_device *);                       
int (*suspend)(struct platform_device *, pm_message_t state);     
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);                    
int (*resume)(struct platform_device *);                          
struct device_driver driver;                                      
};
从结构体可以看出,platform_device是device派生出,platform_driver是device_driver派生出
同样添加设备PlatformDevA,初始化platform_device结构体的dev域时,没有初始化其bus_type域,而实际将该设备添加在sys\bus\platform\devices目录下,
在源代码中哪里可以看到这部分代码。
同样添加驱动PlatformDrvA,初始化platform_driver结构体的driver域时,没有初始化其bus_type域,而实际将该驱动添加在sys\bus\platform\drivers目录下,
在源代码中哪里可以看到这部分代码。

还有
struct miscdevice  {                                  
int minor;                         
const char *name;                  
const struct file_operations *fops;
struct list_head list;             
struct device *parent;             
struct device *this_device;        
}; 
与字符型设备
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
从结构体可以看出,miscdevice是device派生出,它与platform_device区别:
1、platform_device中有设备使用的资源的信息resource。
2、miscdevice中有该设备的使用方法file_operations。
从设备驱动源代码中:
第一步
static struct platform_device at91sam9260_adc_device = {
.name       = "at91_adc",
.id     = -1,
.dev        = {
.platform_data  = &adc_data,
},  
.resource   = adc_resources,
.num_resources  = ARRAY_SIZE(adc_resources),
};
static struct resource spi0_resources[] = {
[0] = {
.start  = AT91SAM9260_BASE_SPI0,
.end    = AT91SAM9260_BASE_SPI0 + SZ_16K - 1,
.flags  = IORESOURCE_MEM,
},
[1] = {
.start  = AT91SAM9260_ID_SPI0,
.end    = AT91SAM9260_ID_SPI0,
.flags  = IORESOURCE_IRQ,
},
};
//向系统添加此设备,注册设备的资源
platform_device_register(&at91sam9260_adc_device);

第二步:
static struct file_operations at91_adc_fops = {
.owner =        THIS_MODULE,
.ioctl =        at91_adc_ioctl,
.read =        at91_adc_readdata,       
.open =                at91_adc_open,        
.release =        at91_adc_release,        
};
static struct miscdevice at91_adc_dev = {        
.minor =        MISC_DYNAMIC_MINOR,
.name =                "adc",
.fops =                &at91_adc_fops,
};
//向系统添加此设备,注册设备的使用方法
misc_register(&at91_adc_dev);

第三步:
static struct platform_driver at91_i2c_driver = {
.probe                = at91_adc_probe,
.remove                = __devexit_p(at91_adc_remove),
.suspend        = at91_adc_suspend,
.resume                = at91_adc_resume,
.driver                = {
.name        = "at91_adc",
.owner        = THIS_MODULE,
},
};
//注册此设备驱动
platform_driver_register(&at91_i2c_driver);

这三个结构体关系:
(基类)
kobject --------------------
/     \                      \
/       \                      \
device     cdev                   driver
/     \ (设备驱动操作方法)           \
/       \                              \
miscdevice         platform_device               platform_driver
(设备驱动操作方法)    (设备的资源)                   (设备驱动) 
我的疑问:
1、当写字符型设备驱动时,我一般只使用cdev结构体,使用此种方式,好像无法在sysfs中显示出该设备。
2、miscdevice是否支持字符设备和块设备,如果使用它怎么辨别块设备或字符设备。
3、miscdevice、platform_device、platform_driver是否可以作为通用的设备驱动方法,由platform_device注册设备资源
platform_driver注册设备驱动、miscdevice注册设备使用方法。

===============================================
以上是网上搜到的一个帖子,和我的疑问有些相似,而且有些地方我也没搞清楚。
这个帖子转载不少,可是少有人回复,回复的也没什么实质性内容。
不过这个同学整理的部分还是比较清晰的,值得看看!

内核驱动中常见的miscdevice、platform_device、platform_driver相关推荐

  1. Windows内核驱动中操作文件

    一. 在驱动中使用文件 在Windows执行体中,通过文件对象来代表文件,该文件对象是一种由对象管理器管理的执行体对象.例如:目录也是由文件对象代表的. 内核组件通过对象名来引用文件,即在文件的全路径 ...

  2. linux内核驱动中对字符串的操作【转】

    转自:http://www.360doc.com/content/12/1224/10/3478092_255969530.shtml Linux内核中关于字符串的相关操作,首先包含头文件: [cpp ...

  3. 转:linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值.cmd除了可区别数字外,还包含有助于处理的几种相应信息. cmd的大小为 32位,共分 4 个 ...

  4. linux 内核驱动中对文件的读写

    转载地址 http://www.360doc.com/content/12/1224/10/3478092_255969804.shtml 有时候需要在Linux kernel--大多是在需要调试的驱 ...

  5. linux内核驱动中对文件的读写 【转】

    本文转载自:http://blog.chinaunix.net/uid-13059007-id-5766941.html 有时候需要在Linux kernel--大多是在需要调试的驱动程序--中读写文 ...

  6. linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值.cmd除了可区别数字外,还包含有助于处理的几种相应信息. cmd的大小为 32位,共分 4 个 ...

  7. ARM 内核移植中常见的错误

    1.下载linux-2.6.36.1.tar.bz2       问题:tar -zxvf 解压压缩文件出现问题,无法识别.       解决:1.通过file linux-2.6.36.1.tar. ...

  8. 【内核驱动】 内核驱动中添加系统调用

    开发环境: Redhat6.5 开发板: Tiny4412 (ARM Cortex A9) 1. 系统调用概述 系统调用请点击 系统调用概述 2. 实现系统调用的步骤 添加一个系统调用比较简单,下面以 ...

  9. linux中 字符串,linux内核驱动中对字符串的操作

    size_t strlcat(char *dest, const char *src, size_t count) 功能:把src所指字符串的前count个字符添加到dest结尾处(覆盖dest结尾处 ...

最新文章

  1. python中数据类型为list_python_数据类型_list
  2. python_day21面向对象的进阶(反射,内置方法,)
  3. 谷歌Android运用商铺下架染辣手机软件
  4. Spring 事务底层原理,你会了吗?
  5. CentOS 7下搭建配置 SVN 服务器
  6. ie传递给系统调用的数据区域太小_内存区域与内存溢出异常
  7. java国王毒酒答案,换换脑子500桶酒国王用囚犯找毒酒答案-500桶酒其中1桶是毒酒找毒酒答案最新版【附公式详解】-东坡下载...
  8. 高品质深圳市地图shp数据arcgis软件道路地名县区边界水系地铁站点2021年
  9. php手机号最新正则表达式,最新手机号码正则表达式
  10. 艾萨克·阿西莫夫《日暮》
  11. Python 爬虫实践:《战狼2》豆瓣影评分析
  12. 学习CANopen --- [3] NMT报文
  13. linux之域名更改
  14. 蓝桥杯 - 历届试题 小朋友排队 C语言实现
  15. 七月:交通车辆管理、门禁考勤,智能化升级的最优方案你get到了吗?
  16. java 反射为何耗性能_Java反射的性能成本
  17. 企业邮箱“成员收发权限”功能详解【如何开通企业邮箱】
  18. 官宣丨全球边缘计算大会参会指南出来啦!
  19. 超导量子计算机原型机,【中国科学报】超导量子计算原型机“祖冲之号”问世...
  20. 有赞android电话面试,挖财 / 有赞电话面试 题目分享

热门文章

  1. springboot jar服务器运行后无法请求_Spring Boot微服务中Chaos Monkey的应用
  2. 代码编程教学_少儿编程教学环境开发之代码实战篇
  3. 007_Checkbox多选框
  4. 013_logback中的SyslogAppender
  5. 织梦配置多个mysql_一台机器,多个mysqld服务
  6. mq 接口 java_Rabbitmq Java Client Api详解
  7. python代码评测结果tle_Python的备忘细节小抄
  8. redis指定配置文件启动_深入学习 Redis 集群搭建方案及实现原理
  9. 需要使用新应用以打开此steam链接_steam社区界面打不开怎么办?完美解决方法看这里...
  10. Android学习视频