- 论坛徽章:
- 0
|
本帖最后由 wmmy2008 于 2010-07-07 10:44 编辑
回复 1# xxw19840406
简单写个流程,,这里并没有分析linxu VFS(太多了),只是简单分析了一下sysfs与vfs的接口部分(sys属性文件的读写流程)
首先看一下sysfs 属性文件的操作方法
const struct file_operations sysfs_file_operations = {
.read = sysfs_read_file,
.write = sysfs_write_file,
.llseek = generic_file_llseek,
.open = sysfs_open_file,
.release = sysfs_release,
.poll = sysfs_poll,
}; 定于在 fs/sysfs/file.c
属性文件的打开,读写操作都会调用上面定义的open,read,write回调,至于vfs是如何调用到上面的文件操作方法的,这个需要
去看看vfs层的open,read,write了,这里就不分析了。
先看看打开sysfs下属性文件都做了些啥子操作:
static int sysfs_open_file(struct inode *inode, struct file *file)
{
..........
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; //找到属性文件父目录对应的kobj(在sysyfs下一个目录文件对应一个kobj)
struct sysfs_buffer *buffer;
struct sysfs_ops *ops; //属性文件的操作方法
..............
/* every kobject with an attribute needs a ktype assigned */
if (kobj->ktype && kobj->ktype->sysfs_ops)
ops = kobj->ktype->sysfs_ops;//这里很重要了,sysfs属性文件的操作方法其实就是要找到父目录kobj的对象ktype
所以可以看出sysfs同一目录下文件操作方法是一样的.
else {
printk(KERN_ERR "missing sysfs attribute operations for "
"kobject: %s\n", kobject_name(kobj));
WARN_ON(1);
goto err_out;
}
................
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (!buffer)
goto err_out;
mutex_init(&buffer->mutex);
buffer->needs_read_fill = 1;
buffer->ops = ops; //把操作方法赋给buffer->ops
file->private_data = buffer; //在后面的read,write等操作时 会用到
........
}
所以可以看出这个函数操作还是比较简单的。。最重要还是要找到文件的操作方法。
接下来分析一下read操作:
static ssize_t
sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct sysfs_buffer * buffer = file->private_data; //取得open时创建的buffer
ssize_t retval = 0;
mutex_lock(&buffer->mutex);
if (buffer->needs_read_fill || *ppos == 0) {
retval = fill_read_buffer(file->f_path.dentry,buffer); //读取文件
if (retval)
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
__func__, count, *ppos, buffer->page);
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count); //拷贝数据到userspace
out:
mutex_unlock(&buffer->mutex);
return retval;
}
接的看fill_read_buffer()这是个关键的函数:
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
struct sysfs_ops * ops = buffer->ops; //取得文件操作方法
int ret = 0;
ssize_t count;
...................
count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); //读操作
..............
return ret;
}
其他的函数大家自己可以去分析,,这里主要看最关键的一个函数ops->show();通过上面分析可以知道这里的回调函数就是定义在
父目录kobj->ktype 中定义的sys_ops文件操作方法.
ops->show(kobj, attr_sd->s_attr.attr, buffer->page);看看read的三个参数,第一:父目录对应的kobj;第二:文件的属性结构;
第三:就是一个buffer,用来存放读取到的数据.它是在open文件的时候动态分配的空间,,,最后调用simple_read_from_buffer()
把这个buffer中的数据拷贝到userspace,,读操作就完了。
write操作的流程都是差不多的,这里不分析了。
.................................................................
好了看看你的这个用户接口函数:
static ssize_t show_data(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int arr[3];
//arr[1] = ...; arr[2] = ...
return sprintf(buf, "%d,%d,%d\n", arr[0], arr[1], arr[2]);
}
从这个函数的接口可以看出,你创建的是一个设备属性文件..
在kernel有一个API,device_create_file(struct device *dev, struct device_attribute *attr)可以创建这样的文件(当然不一定要用此函数)
但是你这个接口函数又是怎么调用到的呢?通过上面的分析我们知道,read,write..文件时就是调用的属性文件父目录kobj->ktype定义
的文件操作方法。。我们现在就去找找dev->kobj->ktype定义是啥子样子的.
//定义在 driver/base/core.c
static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
};
static struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct device_attribute *dev_attr = to_dev_attr(attr);
struct device *dev = to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->show)
ret = dev_attr->show(dev, dev_attr, buf); //在这里就去调用用户定义的show函数(就是你定义的这个函数)
if (ret >= (ssize_t)PAGE_SIZE) {
print_symbol("dev_attr_show: %s returned bad count\n",
(unsigned long)dev_attr->show);
}
return ret;
}
分析到这里就应该很清晰了,应该搞清楚sysfs下属性文件的读写流程了。传递的参数也是很清晰..你只需要cat 这个文件就可以调用到你的函数了...
还有这个架构确是比较复杂,涉及到很多东西,,如:vfs,sysfs,设备驱动架构,,等...每个部分都够我们研究。
由于水平的限制,不晓得说清楚没,如有问题谅解. |
|