Linux驱动之设备模型(6)

来源:互联网 发布:即时通讯软件 开源 编辑:程序博客网 时间:2024/05/29 04:30

7.设备驱动

7.1  设备驱动

l  在Linux设备模型中,设备驱动用device_driver结构来表示

structdevice_driver {

         const char                  *name;       /*名字*/

         struct bus_type                 *bus;      /* 附属的总线 */

         struct module           *owner;

         const struct of_device_id         *of_match_table;

 

         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);

         const struct attribute_group **groups;  /* 属性组 */

 

         /*电源管理操作*/

         const struct dev_pm_ops *pm;

 

         struct driver_private *p;  /* 私有数据:内嵌的kobject,设备链表,总线链表节点*/

};

 

7.2  驱动属性

l  驱动属性由driver_attribute来表示

structdriver_attribute {

         struct attribute attr;

         ssize_t (*show)(struct device_driver*driver, char *buf);

         ssize_t (*store)(struct device_driver*driver, const char *buf,

                             size_t count);

};

DRIVER_ATTR(_name,_mode, _show, _store)

 

l  属性操作

n  创建属性

intdriver_create_file(struct device_driver *driver,

                            const structdriver_attribute *attr);

n  删除属性

voiddriver_remove_file(struct device_driver *driver,

                                const struct driver_attribute *attr);

 

7.3 驱动基本操作

l  驱动注册和注销

int driver_register(struct device_driver *drv)

void driver_unregister(struct device_driver *drv)

 

l  驱动注册分析

n  driver_register

intdriver_register(struct device_driver *drv)

{

         int ret;

         struct device_driver *other;

 

         BUG_ON(!drv->bus->p);

 

         /* 检查是否定义了probe,remove,shutdown方法 */

         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_typemethods\n", drv->name);

        

         /* 检查总线上是否已经注册了此驱动 */

         other = driver_find(drv->name,drv->bus);

         if (other) {

                   put_driver(other);

         }

 

         /* 向总线添加驱动,稍后重点分析 */

         ret = bus_add_driver(drv);

        

         /* 添加相应属性 */

ret = driver_add_groups(drv, drv->groups);

}

 

n  bus_add_driver

intbus_add_driver(struct device_driver *drv)

{

         /* 引用计数加1 */

         bus = bus_get(drv->bus);

 

         /* 初始化和添加kobject */

         error =kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,

                                          "%s", drv->name);

 

         if(drv->bus->p->drivers_autoprobe) {

                   error = driver_attach(drv);

         }

         /* 把驱动关联到总线的驱动链表中 */

         klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);

 

         /* 创建属性 */

         error = driver_create_file(drv,&driver_attr_uevent);

         error = driver_add_attrs(bus, drv);

 

         /* 向用户空间发送KOBJ_ADDuevent */

         kobject_uevent(&priv->kobj,KOBJ_ADD);

}

 

n  driver_attach

int driver_attach(structdevice_driver *drv)

{

         return bus_for_each_dev(drv->bus,NULL, drv, __driver_attach);

}

遍历总线上的所有设备,当有驱动支持的设备时,调用__driver_attach函数完成相应的工作__driver_attach()->driver_probe_device()->driver_probe_device()->bus->probe()->

drv->probe () 优先调用总线中定义的probe函数,如果bus中未定义probe,则再调用驱动中定义的probe。

 

7.4  实例分析

/*

* for learn driver

*/

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/device.h>

#include <linux/string.h>

 

extern struct bus_type scbus_type;

 

static char *Version = "revision 1.0,scdriver";

 

static int sc_probe(struct device *dev)

{

         printk("driverfound device\n");

         return0;

}

 

static int sc_remove(struct device *dev)

{

         printk("deviceremove\n");

         return0;

}

 

struct device_driver scdriver = {

         .name       = "scdevice0",     /* 驱动名字,用来匹配支持的设备 */

         .bus = &scbus_type,     /* 依附的总线类型 */

         .probe      = sc_probe,      /* 设备和驱动匹配时调用 */

         .remove   = sc_remove,     /* 设备移除时调用 */

};

 

/*

* export driver attribute

*/

static ssize_t driver_show_version(structdevice_driver *driver, char *buf)

{

         returnsprintf(buf, "%s\n", Version);

}

static DRIVER_ATTR(version, S_IRUGO,driver_show_version, NULL);

 

static int __init scdriver_init(void)

{

         intret;

  /* 注册驱动 */

         ret= driver_register(&scdriver);

         if(ret)

                   returnret;

         /*创建属性 */

         ret= driver_create_file(&scdriver, &driver_attr_version);

         if(ret)

                   gotoerr_create;

 

         printk("drvierregistered\n");

         return0;

 

err_create:

         driver_unregister(&scdriver);

         returnret;

}

 

static void __exit scdriver_exit(void)

{

         driver_remove_file(&scdriver,&driver_attr_version);

         driver_unregister(&scdriver);

}

 

module_init(scdriver_init);

module_exit(scdriver_exit);

 

MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("CJOK<cjok.liao@gmail.com>");

 

试验结果:

原创粉丝点击