您的位置:首页 > 运维架构 > Linux

Linux驱动之设备模型(5)

2012-03-18 16:05 197 查看
6.设备

6.1 设备

l Linux设备模型中每一个设备用device结构来表示

struct device {

struct device *parent; /* 父设备,通常是某种总线或者是宿主设备 */

struct device_private *p; /* 私有数据指针:子设备链表,父设备链表节点,驱动程序链表节点,总线链表节点 */

struct kobject kobj; /* 连接到结构体系中的kobject */

const char *init_name; /* initial name of the device */

const struct device_type *type; /* 设备类型 */

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

struct device_driver *driver; /* 关联的驱动程序 */

void *platform_data; /* Platform specific data*/

dev_t devt; /* dev_t, creates the sysfs"dev" */

struct klist_node knode_class; /* */

struct class *class; /* 设备所属的类 */

const struct attribute_group **groups; /* optional groups */

void (*release)(structdevice *dev); /* 当引用计数(kobject->kref)减为0时调用 */

};

6.2 设备属性

l 设备属性由device_attribute来表示

structdevice_attribute {

struct attribute attr;

ssize_t (*show)(struct device *dev,struct device_attribute *attr,

char *buf);

ssize_t (*store)(struct device *dev,struct device_attribute *attr,

const char *buf, size_t count);

};

DEVICE_ATTR(_name,_mode, _show, _store)

l 属性操作

n 添加属性

int device_create_file(struct device *device,

conststruct device_attribute *entry);

n 删除属性

void device_remove_file(struct device *dev,

const struct device_attribute*attr);

6.3 设备注册和注销

l 设备注册和注销

intdevice_register(struct device *dev);

voiddevice_unregister(struct device *dev);

l 设备注册分析

注册函数由初始化设备(device_initialize)和添加设备到系统(device_add)中两步构成,主要分析一下第二步

n device_add,添加设备

int device_add(structdevice *dev)

{

struct device *parent = NULL;

struct class_interface *class_intf;

int error = -EINVAL;

/* 引用计数加1 */

dev = get_device(dev);

/*

* for statically allocated devices, whichshould all be converted

* some day, we need to initialize the name. We prevent reading back

* the name, and force the use of dev_name()

*/

if (dev->init_name) {

dev_set_name(dev,"%s", dev->init_name);

dev->init_name = NULL;

}

/* 增加父设备的引用计数 */

parent = get_device(dev->parent);

setup_parent(dev, parent);

/* 把内嵌的kobject注册到设备模型中 */

error = kobject_add(&dev->kobj,dev->kobj.parent, NULL);

/*创建属性文件uevent */

error = device_create_file(dev,&uevent_attr);

/* 如果定义了devt,则产生dev属性 */

if (MAJOR(dev->devt)) {

error = device_create_file(dev,&devt_attr);

}

/* 创建属性文件 */

error = device_add_class_symlinks(dev);

error = device_add_attrs(dev);

/* 把设备添加到总线上,这个是重点,稍后分析*/

error = bus_add_device(dev);

/*产生KOBJ_ADD uevent */

kobject_uevent(&dev->kobj,KOBJ_ADD);

/* 给设备探测相应的驱动 */

bus_probe_device(dev);

/* 如果设备有父设备,将它加入parent的子设备链中 */

if (parent)

klist_add_tail(&dev->p->knode_parent,

&parent->p->klist_children);

/* 如果设备附属于某个类,则需完成相应工作*/

if (dev->class) {

/* 把设备添加到class的设备链表中,完成关联*/

klist_add_tail(&dev->knode_class,

&dev->class->p->klist_devices);

/* notify any interfaces thatthe device is here */

list_for_each_entry(class_intf,

&dev->class->p->class_interfaces, node)

if(class_intf->add_dev)

class_intf->add_dev(dev,class_intf);

}

}

n bus_add_device

intbus_add_device(struct device *dev)

{

/* 引用计数加一 */

struct bus_type *bus =bus_get(dev->bus);

if (bus) {

/* 创建相应的属性文件 */

error = device_add_attrs(bus,dev);

error =sysfs_create_link(&bus->p->devices_kset->kobj,

&dev->kobj,dev_name(dev));

error =sysfs_create_link(&dev->kobj,

&dev->bus->p->subsys.kobj,"subsystem");

/* 把设备加入到总线的设备链中,这步才是重点*/

klist_add_tail(&dev->p->knode_bus,&bus->p->klist_devices);

}

}

n bus_probe_device,为设备探测相应的驱动

bus_probe_device()->device_attach()

intdevice_attach(struct device *dev)

{

if (dev->driver) {

/* 如果设备已经依附于某个驱动,进行绑定 */

ret =device_bind_driver(dev);

} else {

/* 遍历bus->p->klist_drivers寻找匹配的驱动,然后执行回调函数__device_attach */

ret = bus_for_each_drv(dev->bus, NULL, dev,__device_attach);

}

out_unlock:

device_unlock(dev);

return ret;

}

__device_attach()->driver_probe_device()->really_probe()->bus->probe()->drv->probe() 总线中定义的probe函数会优先执行,如果总线中没有定义probe才会执行驱动中定义的probe

6.4 实例解析

创建一个设备和它的属性version,并将此设备挂接到之前创建的总线上

/*

* for learn device

*/

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/device.h>

extern struct bus_type scbus_type;

extern struct device scbus;

static char *Version = "revision1.0";

/* 析构函数,引用计数减为0时调用 */

void screlease(struct device *dev)

{

printk("scbusrelease\n");

}

struct device scdevice = {

.parent = &scbus, /* 父设备,此处为依附的总线 */

.init_name = "scdevice0",

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

.release = screlease,

};

/*

* export device attribute

*/

static ssize_t show_device_version(structdevice *dev,

structdevice_attribute *attr, char *buf)

{

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

}

DEVICE_ATTR(version, 0666,show_device_version, NULL);

static int __init scdevice_init(void)

{

intret;

/*注册设备 */

ret= device_register(&scdevice);

if(ret)

returnret;

/*创建属性 */

ret= device_create_file(&scdevice, &dev_attr_version);

if(ret)

gotoerr_create;

printk("Createa scdevice");

return0;

err_create:

device_unregister(&scdevice);

returnret;

}

static void __exit scdevice_exit(void)

{

device_remove_file(&scdevice,&dev_attr_version);

device_unregister(&scdevice);

printk("Removea scdevice");

}

module_init(scdevice_init);

module_exit(scdevice_exit);

MODULE_LICENSE("Dual BSD/GPL");

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

试验结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: