首页 > 编程知识 正文

sdio 驱动,SDIO的总线

时间:2023-05-06 05:47:48 阅读:260158 作者:2397

Linux 2.6.38

SDIO总线:

static struct bus_type sdio_bus_type = { .name = "sdio", .dev_attrs = sdio_dev_attrs, .match = sdio_bus_match, .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, .pm = SDIO_PM_OPS_PTR, };

一条总线上有一个设备链表klist_devices,记录挂在此bus上的device;一个驱动链表(待查)klist_drivers,记录挂在此bus上的driver。

当注册新设备或者新驱动的时候,遍历驱动/设备链表,总线上的match回调函数得到调用进行驱动/设备的匹配。纯粹的叙述总显得空洞,那就简单看下设备/驱动的注册流程。

注册device:

int device_add(struct device *dev)-->void bus_probe_device(struct device *dev)---->int device_attach(struct device *dev)------>int __device_attach(struct device_driver *drv, void *data) {if (!driver_match_device(drv, dev))return 0;return driver_probe_device(drv, dev);}-------->int driver_probe_device(struct device_driver *drv, struct device *dev)---------->int really_probe(struct device *dev, struct device_driver *drv) { if (dev->bus->probe) { ret = dev->bus->probe(dev); }注册driver:

int driver_register(struct device_driver *drv)-->int bus_add_driver(struct device_driver *drv)---->int driver_attach(struct device_driver *drv)------>int __driver_attach(struct device *dev, void *data) {if (!driver_match_device(drv, dev))return 0;driver_probe_device(drv, dev);}-------->int driver_probe_device(struct device_driver *drv, struct device *dev)----------> int really_probe(struct device *dev, struct device_driver *drv) { if (dev->bus->probe) { ret = dev->bus->probe(dev); }看至此有没有想起一个词叫做”殊途同归“?如果device没有绑定驱动,那么先match一下;match成功后才进行probe,否则直接返回0。

driver_match_device是一个inline函数,实现:

static inline int driver_match_device(struct device_driver *drv, struct device *dev){return drv->bus->match ? drv->bus->match(dev, drv) : 1;}


对于sdio总线,match实现如下:

static int sdio_bus_match(struct device *dev, struct device_driver *drv){struct sdio_func *func = dev_to_sdio_func(dev);struct sdio_driver *sdrv = to_sdio_driver(drv);if (sdio_match_device(func, sdrv))return 1;return 0;}dev_to_sdio_func/to_sdio_driver,根据结构体中某个成员获取整个结构体(的地址),最终都是封装的宏container_of(ptr, type, member):

/** * container_of - cast a member of a structure out to the containing structure * @ptr:the pointer to the member. * @type:the type of the container struct this is embedded in. * @member:the name of the member within the struct. * */#define container_of(ptr, type, member) ({const typeof( ((type *)0)->member ) *__mptr = (ptr);(type *)( (char *)__mptr - offsetof(type,member) );})它就像是一个魅影,出现在kernel的任何子系统中,在2.6.38的源码下搜索结果:

Referenced in 2338 filescontainer_of宏的原理还是很简单的:在C/C++中,一个结构体中的成员偏移在编译时地址就固定下来了,所以成员的地址减去它的offset就是结构体的地址。

Let's go on:

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,struct sdio_driver *sdrv){const struct sdio_device_id *ids;ids = sdrv->id_table;if (ids) {while (ids->class || ids->vendor || ids->device) {if (sdio_match_one(func, ids))return ids;ids++;}}return NULL;}id_table成员由driver的提供方赋值,第5行就是去除该值,用于接下来的匹配。sdio总线match时用的是sdio_device_id类型数据:

/* SDIO */#define SDIO_ANY_ID (~0)struct sdio_device_id {__u8class;/* Standard interface or SDIO_ANY_ID */__u16vendor;/* Vendor or SDIO_ANY_ID */__u16device;/* Device ID or SDIO_ANY_ID */kernel_ulong_t driver_data/* Data private to the driver */__attribute__((aligned(sizeof(kernel_ulong_t))));};之前都是准备工作,所谓磨刀不误砍柴工而已,该砍柴了:

static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,const struct sdio_device_id *id){if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)return NULL;if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)return NULL;if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)return NULL;return id;}如果class/vendor/device某一项不为SDIO_ANY_ID就和sdio_func中的对应项进行比对。sdio_match_device某次返回结果不为NULL,结束匹配操作返回OK。
之前说过,match成功后进行probe。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。