Linux内核提供了多种用户态和内核态的通讯机制,本文将重点介绍sysfs文件系统。其他的通讯机制可以参考前文:
01
—
sysfs文件系统介绍
Sysfs(SystemFilesystem)是Linux内核提供的一种虚拟文件系统,用于向用户空间公开有关设备和驱动程序的信息。它类似于/proc文件系统linux 内核 sprintf,并且专注于设备和驱动程序信息,而非进程信息。
Sysfs通过文件和目录的形式组织信息,其中每位文件或目录对应于系统中的一个设备、驱动程序或则其他内核对象。那些文件一般包含有关设备和驱动程序的属性、状态和配置信息。有些文件可以被写入suse linux,用于配置和控制设备。
Sysfs一般被挂载在/sys目录下,它提供了一种便捷的方法,让用户空间的程序可以动态地获取和管理系统中的设备信息,而无需直接访问内核数据结构。
02
—
KernelObject
在Linux内核中,Kobject是内核对象(KernelObject)的具象表示。它是内核中几乎所有子系统的基础,用于表示那些子系统中的各类对象linux解压rar,如设备、驱动程序、总线等。
Kobject提供了一个通用的、层次化的对象模型,用于管理内核中的各类对象。每位Kobject都有一个惟一的名称和一个指向其父Kobject的表针,因而组织成一个层次结构。据悉,Kobject还可以拥有属性(如设备属性、驱动程序属性等),这种属性可以通过sysfs文件系统向用户空间公开。
Sysfs是通过Kobject来表示设备、驱动程序等内核对象的信息的一种形式。当内核中的设备、驱动程序等对象被创建时,相应的Kobject也会被创建,之后通过Sysfs将其信息曝露给用户空间。
structkobject在头文件"linux/kobject.h"中定义,它一般被嵌入到其他结构体中。
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
...
};
其中:
03
—
Sysfs使用方法
Linux内核中使用sysfs的步骤比较简单:(1)在/sys路径下创建目录;(2)创建sysfs文件。下边将详尽展开这两步涉及的内核API。
3.1
—
在/sys下创建目录
struct kobject * kobject_create_and_add ( const char * name, struct kobject * parent);
Linux内核预定义了几个常用的parent参数:
kernel_kobj:在/sys/kernel下创建目录;
firmware_kobj:在/sys/firmware下创建目录;
fs_kobj:在/sys/fs下创建目录。
假如parent取值为NULL,则在/sys下边创建目录。
相应地linux 内核 sprintf,假若须要删掉对应的sysfs目录,可以用:
void kobject_put(struct kobject *kobj);
3.2
—
创建sysfs文件
sysfs文件可以通过sysfs属性来创建,它定义在头文件"sysfs.h"中:
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
};
其中attr表示即将创建的文件(属性),而show和store分别表示对应的sysfs文件在读和写操作时的反弹函数。
structkobj_attribute可以通过__ATTR宏来创建:
__ATTR(name, permission, show_ptr, store_ptr);
打算好attr以后,可以通过sysfs_create_file来创建出sysfs文件:
int sysfs_create_file ( struct kobject * kobj, const struct attribute * attr);
同样地,假若须要删掉对应的sysfs文件,可以用:
void sysfs_remove_file ( struct kobject * kobj, const struct attribute * attr);
将上面介绍的API汇总上去,创建一个sysfs文件的过程代码如下:
struct kobj_attribute my_attr = __ATTR(my_value, 0660, sysfs_show, sysfs_store);
static ssize_t sysfs_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", my_value);
}
static ssize_t sysfs_store(struct kobject *kobj,
struct kobj_attribute *attr,const char *buf, size_t count)
{
sscanf(buf,"%d",&my_value);
return count;
}
/*Creating a directory in /sys/kernel/ */
kobj_ref = kobject_create_and_add("my_sysfs", kernel_kobj);
/*Creating sysfs file for my_value*/
if(sysfs_create_file(kobj_ref,&my_attr.attr)){
printk(KERN_INFO"Failed to create sysfs filen");
goto r_sysfs;
}
kobject_put(kobj_ref);
sysfs_remove_file(kernel_kobj, &my_attr.attr);
04
—
Sysfs完整代码演示
kernel_driver.c
uint32_t read_count = 0;
static struct task_struct *wait_thread;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev my_cdev;
wait_queue_head_t my_waitqueue;
int waitqueue_flag = 0;
static int wait_function(void *unused)
{
while (1)
{
pr_info("Waiting For Event...n");
wait_event_interruptible(my_waitqueue, waitqueue_flag != 0);
if (waitqueue_flag == 2)
{
pr_info("Event Came From Exit Functionn");
return 0;
}
pr_info("Event Came From Read Function - %dn", ++read_count);
waitqueue_flag = 0;
}
do_exit(0);
return 0;
}
static ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
waitqueue_flag = 1;
wake_up_interruptible(&my_waitqueue);
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = my_read,
};
static int __init my_driver_init(void)
{
if ((alloc_chrdev_region(&dev, 0, 1, "my_dev")) < 0)
return -1;
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;
my_cdev.ops = &fops;
if ((cdev_add(&my_cdev, dev, 1)) < 0)
goto r_class;
if (IS_ERR(dev_class = class_create(THIS_MODULE, "my_class")))
goto r_class;
if (IS_ERR(device_create(dev_class, NULL, dev, NULL, "my_device")))
goto r_device;
init_waitqueue_head(&my_waitqueue);
if ((wait_thread = kthread_create(wait_function, NULL, "WaitThread")))
wake_up_process(wait_thread);
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev, 1);
return -1;
}
static void __exit my_driver_exit(void)
{
waitqueue_flag = 2;
wake_up_interruptible(&my_waitqueue);
device_destroy(dev_class, dev);
class_destroy(dev_class);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("feifei ");
MODULE_DESCRIPTION("Simple linux driver");
MODULE_VERSION("1.7");
编译运行演示如下: