Linux驱动之设备模型(5)
2016-05-19 16:54
471 查看
Linux驱动之设备模型(5)
(2013-02-21 11:11:20)
转载▼
标签: | 分类: 设备模型 |
6.设备
6.1 设备
l Linux设备模型中每一个设备用device结构来表示
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name;
const struct device_type *type;
struct bus_type *bus;
struct device_driver *driver;
void *platform_data;
dev_t devt;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups;
void (*release)(structdevice *dev);
};
6.2 设备属性
l 设备属性由device_attribute来表示
struct device_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 设备注册和注销
int device_register(struct device *dev);
void device_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;
dev = get_device(dev);
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);
error = kobject_add(&dev->kobj,dev->kobj.parent, NULL);
error = device_create_file(dev,&uevent_attr);
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);
kobject_uevent(&dev->kobj,KOBJ_ADD);
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
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
int bus_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()
int device_attach(struct device *dev)
{
if (dev->driver) {
ret =device_bind_driver(dev);
} else {
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,并将此设备挂接到之前创建的总线上
#include
#include
#include
#include
extern struct bus_type scbus_type;
extern struct device scbus;
static char *Version = "revision1.0";
void screlease(struct device *dev)
{
printk("scbusrelease\n");
}
struct device scdevice = {
.parent = &scbus,
.init_name = "scdevice0",
.bus = &scbus_type,
.release = screlease,
};
static ssize_t show_device_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", Version);
}
DEVICE_ATTR(version, 0ow_device_version, NULL);
static int __init scdevice_init(void)
{
int ret;
ret= device_register(&scdevice);
if(ret)
return ret;
ret= device_create_file(&scdevice, &dev_attr_version);
if(ret)
goto err_create;
printk("Createa scdevice");
return 0;
err_create:
device_unregister(&scdevice);
return ret;
}
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");
试验结果:
相关文章推荐
- Linux驱动之设备模型(4)
- Linux驱动之设备模型(3)
- linux下安装图片识别环境
- Linux驱动之设备模型(2)
- Linux系统中如何添加自己的库文件路径
- Linux驱动之设备模型(1)
- linux登录windows服务器
- 从linux拷贝到HDFS分区表报错,查看是编码问题
- linux下vim插件tagbar的安装
- linux 程序动态调用.so文件中的函数
- Linux stat file命令下的三个时间以及find指令
- VirtualBox CentOS安装增强功能与设置共享文件夹
- 强制重启Linux系统的几种方法
- 【Linux进阶】CentOS安装GitLab
- 为什么要学习 Linux?
- CentOS-6.3安装配置JDK-7
- 使用linux系统的实用命令总结
- CentOS删除svn版本库
- linux密码生成
- linux mysql 5.7 修改默认字符集为utf8