一,本文继《设备驱动模型之设备浅析》之后,结合一个简单的实例对driver这一块作一些分析。(基于TCC8900 + linux-2.6.28)
二,实例驱动如下:
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h>
extern struct bus_type test_bus_type;
static int test_probe(struct device *dev) { printk("test_drv found a device which can be handled!\n"); return 0; } static int test_remove(struct device * dev) { printk("test_drv found a device removed!\n"); return 0; } struct device_driver test_driver = { .name = "test_dev", .bus = &test_bus_type, .probe = test_probe, .remove = test_remove, }; static ssize_t test_driver_show(struct device_driver * driver, char * buf) { return sprintf(buf, "%s\n", "test_drv: this driver is for test!"); } static DRIVER_ATTR(drv, S_IRUGO, test_driver_show, NULL); static int __init test_driver_init(void) { int ret = 0;
/*注册驱动*/ ret = driver_register(&test_driver); if (ret){ printk(KERN_WARNING "test_drv driver_register error: %d\n", ret); return ret; } /*创建属性文件*/ if(driver_create_file(&test_driver, &driver_attr_drv)) printk(KERN_INFO "cannot create driver attribute!\n"); return ret; } static void __exit test_driver_exit(void) { driver_unregister(&test_driver); } module_init(test_driver_init); module_exit(test_driver_exit); MODULE_AUTHOR("J.H.Luo"); MODULE_LICENSE("Dual BSD/GPL");
|
1,在本例中,会用到test_bus实例中的总线。
2,设备驱动device_driver的定义:
struct device_driver { const char *name;//驱动的名称
struct bus_type *bus;//驱动所在的总线
struct module *owner; const char *mod_name; /* used for built-in modules */
int (*probe) (struct device *dev);//探测函数
int (*remove) (struct device *dev);//移除设备时调用
void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); struct attribute_group **groups;
struct pm_ops *pm;
struct driver_private *p; };
|
3,接下来跟踪一下驱动的注册过程:
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); if (other) { put_driver(other); 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; }
|
具体的添加驱动的工作是在bus_add_driver()里完成的:
int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; /*获取驱动所在的总线*/ bus = bus_get(drv->bus); if (!bus) return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); /*就像bus_type里有一个struct bus_type_private一样, Device_driver里也有一个对应的struct driver_private, 这个结构体很重要, 因为就是通过它,把这个驱动加到sysfs层次里去的*/ priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); if (error) goto out_unregister; /*下面就通过driver_attach()进行匹配设备工作*/ if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); /*加入到/sys/module层次中*/ module_add_driver(drv->owner, drv); /*创建uevent属性*/ error = driver_create_file(drv, &driver_attr_uevent); if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", __func__, drv->name); } /*创建unbind, bind属性文件*/ error = add_bind_files(drv); if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); }
kobject_uevent(&priv->kobj, KOBJ_ADD); return error; out_unregister: kobject_put(&priv->kobj); out_put_bus: bus_put(bus); return error; }
|
我们更关心的应该是它是怎样匹配设备的,换句话就是这个驱动它能处理哪些设备,继续跟踪一下driver_attach():
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } 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) error = fn(dev, data); klist_iter_exit(&i); return error; }
|
遍历挂在bus上的设备,并调用__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 (drv->bus->match && !drv->bus->match(dev, drv)) return 0;
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; }
|
如果bus定义了match函数,则调用这个match(), 在我们前面的test_bus实例中,match只是简单也比较了device和device_driver的名称是否相同,相同则返回1;bus的match()匹配成功后会继续执行driver_probe_device:
int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0;
if (!device_is_registered(dev)) return -ENODEV; /*why match again?*/ if (drv->bus->match && !drv->bus->match(dev, drv)) goto done;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev->bus_id, drv->name);
ret = really_probe(dev, drv);
done: return ret; }
static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0;
atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev->bus_id); WARN_ON(!list_empty(&dev->devres_head)); /*设备与驱动的关系就在这里确定下来了*/ dev->driver = drv; /*在sysfs中创建相应的链接文件*/ if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev->bus_id); goto probe_failed; } /*这里微微有点像C++的多态性的感觉,如果bus定义了probe函数,就调用里的probe, 如果bus里没有,而drv里有probe则调用drv里的probe。 在我们这里例子里,bus没有定义probe, driver里定义了下面的probe: static int test_probe(struct device *dev) { printk("test_drv found a device which can be handled!\n"); return 0; } 所以匹配成功后就会打印出这样一句话*/
if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev); if (ret) goto probe_failed; }
driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev->bus_id, drv->name); goto done;
probe_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL;
if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, ret); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; }
|
OK,整个device_driver的注册过程跟踪到这里就基本完成了。
三,最后结合前两个实例来综合测试一下:
/nand2 # insmod bus_test.ko /nand2 # insmod device_test.ko /nand2 # insmod driver_test.ko test_drv found a device which can be handled! /nand2 # cd /sys/bus/test_bus/drivers/ /sys/bus/test_bus/drivers # ls test_dev /sys/bus/test_bus/drivers # ls -l test_dev/ --w------- 1 0 0 4096 Jan 1 00:01 bind -r--r--r-- 1 0 0 4096 Jan 1 00:01 drv lrwxrwxrwx 1 0 0 0 Jan 1 00:01 test_dev -> ../../../../devices/test_bus0/test_dev --w------- 1 0 0 4096 Jan 1 00:01 uevent --w------- 1 0 0 4096 Jan 1 00:01 unbind /sys/bus/test_bus/drivers # ls -l ../devices/test_dev/ lrwxrwxrwx 1 0 0 0 Jan 1 00:02 bus -> ../../../bus/test_bus -rw-rw-rw- 1 0 0 4096 Jan 1 00:02 dev_info lrwxrwxrwx 1 0 0 0 Jan 1 00:02 driver -> ../../../bus/test_bus/drivers/test_dev drwxr-xr-x 2 0 0 0 Jan 1 00:02 power lrwxrwxrwx 1 0 0 0 Jan 1 00:02 subsystem -> ../../../bus/test_bus -rw-r--r-- 1 0 0 4096 Jan 1 00:02 uevent /sys/bus/test_bus/drivers # rmmod device_test test_drv found a device removed!
|
------------------------------------------
本文乃原创!
转载请注明出处:http://sparklecliz.cublog.cn/
------------------------------------------
阅读(2007) | 评论(0) | 转发(0) |