linux设备驱动——andriod平台wlan驱动
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
* its driver.
*/
struct device_driver *driver; /* which driver has allocated this device */ //这个设备挂接的驱动
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device core doesn't touch it */
struct dev_pm_info power;
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
/* arch specific additions */
struct dev_archdata archdata;
struct list_head devres_head;
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
};
const char * name; //设备驱动的名字
struct bus_type * bus; //设备驱动挂接的总线的类型
struct klist klist_devices; //这个驱动对应的设备的链表
struct klist_node knode_bus;
const char * mod_name; /* used for built-in modules */
struct module_kobject * mkobj;
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);
int (*suspend) (struct device * dev, pm_message_t state);
int (*resume) (struct device * dev);
};
const char * name; //总线的名字
struct module * owner;
struct kset drivers; //挂接在该总线上的驱动的集合
struct kset devices; //挂接在该总线上的设备的集合
struct klist klist_devices;
struct klist klist_drivers;
struct device_attribute * dev_attrs; //设备属性
struct driver_attribute * drv_attrs; //驱动属性
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device * dev);
int (*remove)(struct device * dev);
void (*shutdown)(struct device * dev);
int (*suspend_late)(struct device * dev, pm_message_t state);
int (*resume_early)(struct device * dev);
int (*resume)(struct device * dev);
};
贴一下sdio_register_driver函数:
int sdio_register_driver(struct sdio_driver *drv)
{
drv->drv.name = drv->name; //首先忽略下面两行,直接进入driver_register函数.
drv->drv.bus = &sdio_bus_type; //实际上这行代码是关键,而下面的函数中我们要找的仅仅是调用probe函数的地方而已,稍后分析
return driver_register(&drv->drv);
}
来看driver_register函数的内容,由于其中涉及较多有关klist、kobject结构的内容,如果有不明白的地方,请查看同为《linux设备驱动——andriod平台wlan驱动》系列的介绍klist、kobject内容的章节,这里希望有的放矢.它的代码在drivers/base/driver.c中.
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods/n", drv->name);
other = driver_find(drv->name, drv->bus); //在kobject结构组成的链表中查找是否已经存在这个驱动,以前的blog讲过,驱动必然挂接在某个总线上.请复习,返回值是
device_driver结构的指针if (other) {
put_driver(other); //由于之前增加了引用计数,这里在减1
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting.../n", drv->name);
return -EEXIST;
}
ret = bus_add_driver(drv); //此函数是重点!
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups); //这两个函数不用介绍也猜的出来
if (ret)
bus_remove_driver(drv);
return ret;
}
那么我们接着看
int bus_add_driver(struct device_driver *drv) //这个函数我不记得我的blog中是否有讲过(我记得我写过注释,如果没写过,就请自己看吧 呵呵 )
{
.......................................
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv); //这个函数是重点.
if (error)
goto out_unregister;
}
......................................
}
driver_attach函数在drivers/base/dd.c中,很简单的一句话:
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
这个函数会调用__driver_attach函数,我们已经接近目标了.
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev); //此函数就是我们要找的函数了.
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
driver_probe_device函数中有一个really_probe函数,这是我们的最终目的地:
static int really_probe(struct device *dev, struct device_driver *drv)
{
...................................................
if (dev->bus->probe) { //我们看到了这里会调用probe函数,同样这里也会决定你的probe函数是使用一个参数还是两个参数,
ret = dev->bus->probe(dev); 因为这取决于你是如何注册的.也就是是否调用了(仅仅针对于网友的提问)platform_device_register
if (ret) 函数来注册设备.具体看下面的总结.
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
....................................................
}
好了,这里来总结一下得失,同时根据以上列的代码回答网友的提问: if (dev->bus->probe)这个表示是否注册了device结构,如果注册了并且给device结构挂接上了驱动和总线,那么调用挂接在device结构中的总线的probe函数.这里的device结构从哪里冒出来的?它在 bus_for_each_dev函数中:
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)) && !error) //查找每个挂接在sdio总线上的设备,看他们是否有注册,并调用相应的probe函数也就是
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
关于platform_device结构与device结构的关系,就不用我在解释了吧!probe函数的调用,就取决于你在你注册的device结构中挂接的总线的类型了.因为调用 dev->bus->probe(dev); 所以清查看一下你注册是挂接的总线的probe函数的参数即可. 一般来说,参数会是两个,因为一类总线上总是可以挂接多个设备,所以我们还需要一个device_id. 如果行到else部分: else if (drv->probe) .这里调用驱动的probe函数,由于我们注册的是sdio_driver结构.看一看sdio_driver结构的申明,在include/linux/mmc/sdio_func.h中:
struct sdio_driver {
char *name;
const struct sdio_device_id *id_table;
int (*probe)(struct sdio_func *, const struct sdio_device_id *); //很显然probe就是两个参数,而不是一个.
void (*remove)(struct sdio_func *);
struct device_driver drv;
};
至于为什么你的probe是一个参数,我希望你能给出完整的注册流程才能分析,但是我认为根据我刚才分析的流程应该可以自己找出相应的代码了.