您的位置:首页 > 运维架构 > Linux

Linux总线设备驱动模型学习

2015-06-27 13:31 549 查看
Linux总线驱动模型主要在2.6以后内核提出

功能:主要对热插拔、跨平台移植性的要求支持

当外部设备接入总线后,总线会与挂载到总线上的每个驱动一一进行匹配,如果匹配上就调用被匹配上的驱动。

Linux内核中,总线由bos_type结构表示,定义在<linux/device.h>

struct bus_type

{

const
char *name;
总线名称

int
(*match)(struct device*dev,stuuctdevice_driver*drv);驱动与设备的匹配函数

......

}

int (*match)(structdevice*dev,stuuctdevice_driver*drv)

当一个新设备或者新驱动被添加到这个总线时,该函数被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非0.

总线的注册使用如下函数:

bus_register(struct bus_type*bus)

若成功,新的总线将被添加进系统,并可在/sys/bus下看到相应的目录。

/sys/bus目录下面存放的是总线文件

在相应总线文件里面存放有devices、drivers两个文件

devices文件存放挂载到此总线上的设备

drivers文件存放挂载到此总线上的驱动

总线的注销使用:

void bus_unregister(structbus_type*bus)

Linux内核中,驱动由device_driver结构体表示

struct device_driver

{

const
char *name;
驱动名称

struct
bus_type *bus;驱动程序所在的总线

int
(*probe)(struct device*dev);当总线上的设备与此驱动匹配上就调用此函数,处理匹配上的设备

......

}

驱动的注册使用如下函数:

int driver_register(structdevice_driver*drv)

驱动的注销使用:

void driver_uinregister(structdevice_driver*drv)

Linux内核中,设备由struct device结构表示

struct device

{

const
char *init_name;设备的名字

struct
bus tpye
*bus; 设备所在的总线

.......

}

当给init_name赋值后内核会把init_name的值赋给dev->kobj.name变量,并且把init_name赋值为NULL,所以在match函数中要使用dev->kobj.name与驱动名匹配

设备的注册使用如下函数

int device_register(structdevice*dev)

设备的注销使用

void device_unregister(structdevice*dev)

挂载到同一总线的设备名与驱动名需要一样,才能使用(*match)(structdevice*dev,stuuctdevice_driver*drv)函数通过通过匹配他们的名字匹配上

虚拟设备一般使用名字匹配

USB等设备使用设备特定硬件ID匹配

bus.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>

/* 需要遵循GPL协议才能调用bus_register、bus_unregister函数 */
MODULE_LICENSE("GPL");

/* 驱动与设备的匹配函数:
当给init_name赋值后内核会把init_name的值赋给dev->kobj.name
并且把init_name赋值为NULL,所以在match函数中要使用dev->kobj.name
与驱动名匹配*/
int my_match(struct device *dev, struct device_driver *drv)
{
    return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));
}  

/* 总线结构体 */
struct bus_type my_bus_type = 
{
	.name = "my_bus",
	.match = my_match,
};
//输出此符号,让别的模块调用
EXPORT_SYMBOL(my_bus_type);

int my_bus_init()
{
	int ret;
	
	ret = bus_register(&my_bus_type);
	
	return ret;
}

void my_bus_exit()
{
	bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);


device.c:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

extern struct bus_type my_bus_type;

/* 当给init_name赋值后内核会把init_name的值赋给dev->kobj.name
并且把init_name赋值为NULL,所以在match函数中要使用dev->kobj.name
与驱动名匹配*/
struct device my_dev = {
     .init_name = "my_dev",
     .bus = &my_bus_type,	
};

int my_device_init()
{
	int ret;
     ret = device_register(&my_dev);
     return ret;
     
}

void my_device_exit()
{
	device_unregister(&my_dev);
}

module_init(my_device_init);
module_exit(my_device_exit);


driver.c:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

//extern指明后面的变量来自外部
extern struct bus_type my_bus_type;		//调用bus.c文件中声明过的总线变量

int my_probe(struct device *dev)
{
    printk("driver found the device it can handle!\n");
	//硬件初始化。。。
    return 0;
}

struct device_driver my_driver = {
    .name = "my_dev",
    .bus = &my_bus_type,	
    .probe = my_probe,		//当设备与驱动匹配上后,调用此函数
};

int my_driver_init()
{
	int ret;
	
	ret = driver_register(&my_driver);
	
	return ret;
}

void my_driver_exit()
{
	driver_unregister(&my_driver);	
}

module_init(my_driver_init);
module_exit(my_driver_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: