跟上回一樣,我用這個小程序來讀
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
char *name = "/sys/bus/ldd/version";
char buf[500];
int fd;
int size;
fd = open(name, O_RDONLY);
printf("fd:%d
",fd);
size = read(fd,buf,sizeof(buf));
printf("size:%d
",size);
printf("%s",buf);
close(fd);
return -1;
}
(1)sysfs_open_file() open() ->/*用戶空間*/
-> 系統調用->
sys_open() -> filp_open()-> dentry_open() -> sysfs_open_file()/*內核空間*/
static int sysfs_open_file(struct inode * inode, struct file * filp)
{
return check_perm(inode,filp);
}
static int check_perm(struct inode * inode, struct file * file)
{
struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
struct attribute * attr = to_attr(file->f_dentry);
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error = 0;
if (!kobj || !attr)
goto Einval;
/* Grab the module reference for this attribute if we have one */
if (!try_module_get(attr->owner)) {
error = -ENODEV;
goto Done;
}
/* if the kobject has no ktype, then we assume that it is a subsystem
* itself, and use ops for it.
*/
if (kobj->kset && kobj->kset->ktype)
ops = kobj->kset->ktype->sysfs_ops;
else if (kobj->ktype)
ops = kobj->ktype->sysfs_ops;
else
ops = &subsys_sysfs_ops;
/* No sysfs operations, either from having no subsystem,
* or the subsystem have no operations.
*/
if (!ops)
goto Eaccess;
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
*/
if (file->f_mode & FMODE_WRITE) {
if (!(inode->i_mode & S_IWUGO) || !ops->store)
goto Eaccess;
}
/* File needs read support.
* The inode's perms must say it's ok, and we there
* must be a show method for it.
*/
if (file->f_mode & FMODE_READ) {
if (!(inode->i_mode & S_IRUGO) || !ops->show)
goto Eaccess;
}
/* No error? Great, allocate a buffer for the file, and store it
* it in file->private_data for easy access.
*/
buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
if (buffer) {
memset(buffer,0,sizeof(struct sysfs_buffer));
init_MUTEX(&buffer->sem);
buffer->needs_read_fill = 1;
buffer->ops = ops;
file->private_data = buffer;
} else
error = -ENOMEM;
goto Done;
Einval:
error = -EINVAL;
goto Done;
Eaccess:
error = -EACCES;
module_put(attr->owner);
Done:
if (error && kobj)
kobject_put(kobj);
return error;
}
check_perm()檢查一下權限,創建一個sysfs的緩沖區sysfs_buffer buffer,並設置其sysfs_ops sysfs_buffer->ops。在我們這個故事裡,sysfs_buffer->ops被設置成bus_sysfs_ops。最後讓file->private_data = buffer。
(2)sysfs read file()流程如下:
read()->/*用戶空間*/
-> 系統調用->
sys_read() -> vfs_read() -> sysfs_read_file()/*內核空間*/
看看sysfs_read_file()函數,
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;
ssize_t retval = 0;
down(&buffer->sem);
if (buffer->needs_read_fill) {
if ((retval = fill_read_buffer(file->f_dentry,buffer)))
goto out;
}
pr_debug("%s: count = %d, ppos = %lld, buf = %s
",
__FUNCTION__,count,*ppos,buffer->page);
retval = flush_read_buffer(buffer,buf,count,ppos);
out:
up(&buffer->sem);
return retval;
}
順著sysfs_read_file()往下走:
sysfs_read_file()
---> fill_read_buffer()
---> sysfs_buffer->bus_sysfs_ops->bus_attr_show()
---> bus_attribute->show_bus_version() //注意這個函數是我們在lddbus.c裡面定義的
---> flush_read_buffer()
fill_read_buffer()的是真正的讀,它把內容讀到sysfs定義的緩沖區sysfs_buffer。flush_read_buffer()是把緩沖區copy到用戶空間。詳細內容我就不貼了。