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>");
试验结果: