Chinaunix首页 | 论坛 | 博客
  • 博客访问: 110777
  • 博文数量: 24
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 270
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 18:17
文章分类

全部博文(24)

文章存档

2010年(21)

2009年(3)

我的朋友

分类: LINUX

2010-03-15 11:29:15

一,本文继《设备驱动模型之设备浅析》之后,结合一个简单的实例对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只是简单也比较了devicedevice_driver的名称是否相同,相同则返回1busmatch()匹配成功后会继续执行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) |
给主人留下些什么吧!~~