Linux设备驱动模型:
1. struct bus_type 的对象来表示一个总线
struct device_driver 对象来表示一个挂在总线上的设备驱动
总线:
一个总线可以挂多个设备和多个驱动。
由总线的match函数来匹配设备对应的驱动, 匹配规则在总线match函数里实现
int (*match)(struct device *dev, struct device_driver *drv)
{
return 1//表示dev与drv匹配上了
return 0//表示不匹配, 总线会继续匹配直到设备与驱动一一对过
}
struct bus_type {
.name //总线名
.match //匹配函数
//////
以下函数当总线实现时,不管device_driver里实不实现这些函数,
都会调用总线的这些函数
.probe //设备探测函数
.remove //设备移除
.suspend //省电休眠
.resume //唤醒
};
bus_register(&mybus);
bus_unregister(&mybus);
如果总线与驱动, 设备不是同一个文件里实的话
则EXPORT_SYMBOL(mybus);
在驱动与设备里
extern struct bus_type mybus;
////////////////////////
void (*release)(struct device *dev);
设备:
struct device {
.init_name //设备在总线上的名字, 在总线上是唯一的
.bus //属于哪个总线,指向总线的地址
.release //设备释放函数, 必须要实现
...
.driver //如果总线匹配成功后, 此指针指向device_driver对象的地址
};
device_register(&mydev);
device_unregister(&mydev);
//////////////////////
驱动:
struct device_driver {
.name //驱动在总线上的名字
.bus //属于哪个总线, 指向总线的地址
.probe //当总线匹配上时, 驱动探测设备
/////////
.remove //设备移除时触发函数
.suspend //驱动省电的行为
.resume //驱动恢复工作
};
driver_register(&mydrv);
driver_unregister(&mydrv);
///////////////
匹配过程:
总线的match -->> 驱动的probe
Linux platform 平台设备驱动模型
struct bus_type platform_bus_type = {
.name = "platform",
.match = platform_match,
....
};
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
//match根据平台设备的name与平台驱动的driver成员的name比较, 一致的话则认为匹配成功
//平台设备
<linux/platform_device.h>
struct platform_device {
const char * name; //总线match时使用
int id; //如多个设备共用一个驱动时, id不能一样
struct device dev; //dev.platform_data可以挂自定义的数据,
dev里的release成员要实现
dev.driver_data也可以挂数据
u32 num_resources; //多少个资源
struct resource * resource; //资源对象的始地址
};
///Platform 设备
<linux/ioport.h>
struct resource {
resource_size_t start; //32bit/64bit数值
resource_size_t end; //数值
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
flags:
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
//获取指定的资源 type为指定flags类型, num为同类型中的第几个资源
int platform_get_irq(struct platform_device *pdev, unsigned int num);
struct resource *platform_get_resource_byname(struct platform_device *dev,
unsigned int type, char *name)
int platform_device_register(struct platform_device *);
void platform_device_unregister(struct platform_device *);
//Platfrom驱动
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; //driver里的name用于总线与设备匹配
const struct platform_device_id *id_table;
};
int platform_driver_register(struct platform_driver *);
void platform_driver_unregister(struct platform_driver *);