Linux中总线设备驱动模型及平台设备驱动实例
本文将简要地介绍Linux总线设备驱动模型及其实现方式,并不会过多地涉及其在内核中的具体实现,最后,本文将会以平台总线为例介绍设备和驱动程序的实现过程。
目录:
一、总线设备驱动模型总体介绍及其实现方式
1.总线设备驱动模型总体介绍
2、总线实现方式
(1):描述
(2):注册和卸载
3、设备实现方式
4、驱动实现方式
二、平台总线设备驱动
1、平台设备的实现方式
2、平台驱动的实现方式
3、平台总线驱动与设备匹配机制
三、按键实例
1.按键设备
2.按键驱动
一、总线设备驱动模型总体介绍及其实现方式
1.总线设备驱动模型总体介绍
如果cpu和外设或者外设和外设想要进行通讯,需要将通信的双方挂载到一条总线上,这里的总线可以是具体的总线,如IIC、CAN总线等,也可以是虚拟的总线,如平台总线。随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备模型(当然也可以选择不用这样的方式实现)。其示意图如下所示:
总线设备驱动模型可分为总线、设备和驱动三个部分,当将一个设备加入到总线上时,内核会在这条总线上寻找该设备对应的驱动;当将一个驱动加入到一条总线上时,内核会在该总线上寻找与该驱动对应的设备。匹配的规则根据不同类型的总线及设备特征进行定义。
2、总线实现方式
(1):总线的描述
在 Linux 内核中, 总线由 bus_type 结构表示,定义在 <linux/device.h>中
struct bus_type {
const char *name; /*总线名称*/
int (*match) (struct device *dev, struct
device_driver *drv); /*驱动与设备的匹配函数*/
………
}
其中,match函数的定义为:
int (*match)(struct device * dev, struct device_driver * drv)
设备和驱动的匹配规则在此函数中定义,match函数的职责为:当一个新设备或者新驱动被添加到这个总线时,该函数被调用,用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零,若不可以则返回0值。
(2):总线的注册和注销
总线的注册使用如下函数
bus_register(struct bus_type *bus)
若成功,新的总线将被添加进系统,并可在/sys/bus 下看到相应的目录。
总线的注销使用:
void bus_unregister(struct bus_type *bus)
若成功,则总线将会从系统中删除。
3、设备的实现方式
(1):设备的描述方式
在 Linux内核中, 设备由struct device结构表示。
struct device {
{
const char *init_name; /*设备的名字*/
struct bus_type *bus; /*设备所在的总线*/
………
}
其中,init_name为设备的名称,*bus指向总线的描述结构。
(2):设备的注册和注销
设备的注册使用如下函数:
int device_register(struct device *dev);
当一个设备成功地添加到一条总线上时可以在/sys/bus/xxx_bus/目录下看到相应的设备。
设备的注销使用如下函数:
void device_unregister(struct device *dev);
4.驱动实现方式
(1):驱动的描述方式
在 Linux内核中, 驱动由 device_driver结构表示:
struct device_driver {
{
const char *name; /*驱动名称*/
struct bus_type *bus; /*驱动程序所在的总线*/
int (*probe) (struct device *dev);/*设备匹配成功后调用的函数*/
………
}
其中,*name为驱动的名称,可以作为一种设备和驱动匹配的条件;*bus指向所要加入的总线的描述结构;*probe函数指针指向一个操作函数,该函数会在设备和驱动匹配成功之后(即match函数返回为1时)被调用,一般用来完成对设备的初始化操作。
(2):驱动的注册和注销
驱动的注册使用如下函数
int driver_register(struct device_driver *drv);
驱动的注销使用:
void driver_unregister(struct device_driver *drv);
二、平台总线设备驱动实例
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线(已经在Linux内核中实现,是上文介绍的总线的一个实例),其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。平台总线的开发主要包括平台设备和平台驱动两个部分的实现,其开发流程图如下所示:
1.设备的实现方式
(1):平台设备的描述方式
平台设备使用struct platform_device来描述:
struct platform_device {
const char *name; /*设备名*/
int id; /*设备编号,配合设备名使用*/
struct device dev;
u32 num_resources;
struct resource *resource; /*设备资源*/
}
其中,*name为设备名,*resource指针指向该平台设备所占有的资源,其用struct resource 结构来描述:
struct resource {
resource_size_t start;/*资源的起始地址*/
resource_size_t end;/*资源的结束地址*/
const char *name;
unsigned long flags; /*资源的类型*/
struct resource *parent, *sibling, *child; };
(2):平台设备的注册和注销
注册平台设备,使用函数:
int platform_device_register(struct platform_device *pdev);
注销平台设备,使用函数:
int platform_device_unregister(struct platform_device *pdev);
2.平台驱动的实现方式
(1):平台驱动的描述方式
平台驱动使用struct platform_driver 描述:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
……
}
其中,*probe函数指针指向设备处理函数,当平台设备和平台驱动匹配成功时被调用。
(1):平台驱动的注册和注销
平台驱动注册使用函数:
int platform_driver_register(struct platform_driver *);
平台驱动注销使用函数:
1 int platform_driver_unregister(struct platform_driver *);
3.平台总线驱动与设备的匹配机制
平台总线驱动和设备采用名称是否相同的方式进行匹配,在平台总线的match函数中对驱动和设备的名称进行比较,若两者名称相同则match函数返回为非0,否则返回为0。另外,平台设备一般直接载入内核进行初始化而不通过模块的方式进行加载(平台设备可以看成是对应于具体设备的资源的集合,将设备和驱动分开有利于程序的移植)。
三、按键实例
1.平台按键的定义和注册
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h> MODULE_LICENSE("GPL"); #define GPFCON 0x56000050
9 //所用的资源描述
static struct resource key_resource[] = {
[] = {
.start = GPFCON,
.end = GPFCON + ,
.flags = IORESOURCE_MEM,
},
[] = {
.start = IRQ_EINT0,
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
},
}; struct platform_device key_device = {
.name = "my-key",
.id = ,
.num_resources = ARRAY_SIZE(key_resource),
.resource = key_resource,
}; static int button_init()
{
platform_device_register(&key_device); return ;
} static void button_exit()
{
platform_device_unregister(&key_device);
} module_init(button_init);
module_exit(button_exit);
2.平台驱动的定义和注册
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h> MODULE_LICENSE("GPL"); struct work_struct *work; struct timer_list buttons_timer; unsigned int key_num = ; wait_queue_head_t key_q; struct resource *res;
struct resource *res_irq;
unsigned int *key_base; void work_func(struct work_struct *work)
{
mod_timer(&buttons_timer, jiffies + (HZ /));
} void buttons_timer_function(unsigned long data)
{
unsigned int key_val; key_val = readw(key_base+)&0x1;
if (key_val == )
key_num = ; key_val = readw(key_base+)&0x4;
if (key_val == )
key_num = ; wake_up(&key_q);
} irqreturn_t key_int(int irq, void *dev_id)
{
//1. 检测是否发生了按键中断 //2. 清除已经发生的按键中断 //3. 提交下半部
schedule_work(work); //return 0;
return IRQ_HANDLED; } void key_hw_init()
{
unsigned short data; data = readw(key_base);
data &= ~0b110011;
data |= 0b100010; writew(data,key_base);
} int key_open(struct inode *node,struct file *filp)
{
return ;
} ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
wait_event(key_q,key_num); copy_to_user(buf, &key_num, ); key_num = ; return ;
} struct file_operations key_fops =
{
.open = key_open,
.read = key_read,
}; struct miscdevice key_miscdev = {
.minor = ,
.name = "key",
.fops = &key_fops,
}; int key_probe(struct platform_device *pdev)
{
int ret,size; ret = misc_register(&key_miscdev); if (ret !=)
printk("register fail!\n"); //注册中断处理程序 res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, ); request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"key",(void *));
request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)); //按键初始化
res = platform_get_resource(pdev, IORESOURCE_MEM, );
size = (res->end - res->start) + ;
key_base = ioremap(res->start, size); key_hw_init(); //. 创建工作
work = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work, work_func); /* 初始化定时器 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function; /* 向内核注册一个定时器 */
add_timer(&buttons_timer); /*初始化等待队列*/
init_waitqueue_head(&key_q); return ;
} int key_remove(struct platform_device *dev)
{
free_irq(res_irq->start, (void *));
free_irq(res_irq->end, (void *)); iounmap(key_base);
misc_deregister(&key_miscdev);
return ;
} static struct platform_driver key_driver = {
.probe = key_probe,
.remove = key_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my-key",
},
}; static int button_init()
{
return platform_driver_register(&key_driver);
} static void button_exit()
{
platform_driver_unregister(&key_driver);
} module_init(button_init);
module_exit(button_exit);
Linux中总线设备驱动模型及平台设备驱动实例的更多相关文章
- 【Linux高级驱动】linux设备驱动模型之平台设备驱动机制
[1:引言: linux字符设备驱动的基本编程流程] 1.实现模块加载函数 a.申请主设备号 register_chrdev(major,name,file_operations); b.创 ...
- Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)
Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...
- Linux Platform驱动模型(一) _设备信息
我在Linux字符设备驱动框架一文中简单介绍了Linux字符设备编程模型,在那个模型中,只要应用程序open()了相应的设备文件,就可以使用ioctl通过驱动程序来控制我们的硬件,这种模型直观,但是从 ...
- 【总结】设备树对platform平台设备驱动带来的变化(史上最强分析)【转】
本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74375086 版权声明:本文为博主原创文章,转载请注明http://blog.c ...
- Linux MTD子系统 _从模型分析到Flash驱动模板
MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...
- Linux设备驱动模型之platform(平台)总线详解
/********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...
- Linux设备驱动模型之I2C总线
一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...
- 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联
转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...
- linux设备驱动那点事儿之平台设备理论篇
一:Platform总线 1.1概述 一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中 ...
随机推荐
- [Head First设计模式]山西面馆中的设计模式——观察者模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 引言 不知不自觉又将设计模式融入生活了,吃个饭也不得安生,也发现生活中的很多场景,都可以用设计模式来模拟.原来设计模式就在 ...
- .net core 跨平台实践
本人采用Ubuntu 14.04 来实现.net core 的跨平台实践. 首先安装Ubuntu14.04系统.安装细节问百度. 1..net core console程序的跨平台 首先新建一个con ...
- 汤森路透为何一定要卖掉SCI?
http://health.sohu.com/20160714/n459331727.shtml
- PHP 语言特性
一.PHP 超级全局变量 PHP 超级全局变量列表: $GLOBALS $_SERVER $_REQUEST $_POST $_GET $_FILES $_ENV $_COOKIE $_SESSION ...
- GNURadio 使用问题
- Python基础知识(一)
- [Machine Learning] 机器学习常见算法分类汇总
声明:本篇博文根据http://www.ctocio.com/hotnews/15919.html整理,原作者张萌,尊重原创. 机器学习无疑是当前数据分析领域的一个热点内容.很多人在平时的工作中都或多 ...
- wdcp安装memcached解决办法
1.下载libevent-1.4.14b-stable.tar.gz和memcached-1.4.15.tar.gz这两个文件,上传到服务器,并给它一个可用的下载地址, 如http://地址/memc ...
- 核型SVM
(本文内容和图片来自林轩田老师<机器学习技法>) 1. 核技巧引入 如果要用SVM来做非线性的分类,我们采用的方法是将原来的特征空间映射到另一个更高维的空间,在这个更高维的空间做线性的SV ...
- MariaDB 多主一从 搭建测试
背景: 目前MySQL依然只支持一个Slave从一个Master复制数据,虽然也可以做到一主多备(M->S),双主复制(M<->M)等架构,但是局限性依然很大.由于项目的要求,需要各 ...