免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6971 | 回复: 4
打印 上一主题 下一主题

读sysfs文件的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-07-06 16:33 |只看该作者 |倒序浏览
现在需要在驱动中实现sysfs文件节点,其中的show函数是上层读的接口

假设我上层要读三个int型值
驱动中的show函数
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]);
}
这样写可以吗?

还有上层的read怎么写能等到那三个值呢

身边没有做linux驱动的,只有来这里问了

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
2 [报告]
发表于 2010-07-07 07:42 |只看该作者
这个应该不需要自己写了吧
可以跟踪一下读sysfs时的函数调用流程,看看中间涉及哪些函数
buf是在哪里创建的

论坛徽章:
0
3 [报告]
发表于 2010-07-07 10:40 |只看该作者
本帖最后由 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,设备驱动架构,,等...每个部分都够我们研究。
由于水平的限制,不晓得说清楚没,如有问题谅解.

论坛徽章:
0
4 [报告]
发表于 2010-07-07 11:30 |只看该作者
应该可以吧。上层就在c中 open对应文件,用read函数,read传进来的void *就是对应show中的buf。

论坛徽章:
0
5 [报告]
发表于 2010-07-26 17:12 |只看该作者
没啥问题啊,直接在上层cat这个文件就能读出来了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP