sysfs API总结

sysfs是用于表现设备驱动模型的文件系统,它基于ramfs。要学习linux的设备驱动模型,就要先做好底层工作,总结sysfs提供给外界的API就是其中之一。sysfs文件系统中提供了四类文件的创建与管理,分别是目录、普通文件、软链接文件、二进制文件。目录层次往往代表着设备驱动模型的结构,软链接文件则代表着不同部分间的关系。比如某个设备的目录只出现在/sys/devices下,其它地方涉及到它时只好用软链接文件链接过去,保持了设备唯一的实例。而普通文件和二进制文件往往代表了设备的属性,读写这些文件需要调用相应的属性读写。

    sysfs是表现设备驱动模型的文件系统,它的目录层次实际反映的是对象的层次。为了配合这种目录,linux专门提供了两个结构作为sysfs的骨架,它们就是struct kobject和struct kset。我们知道,sysfs是完全虚拟的,它的每个目录其实都对应着一个kobject,要想知道这个目录下有哪些子目录,就要用到kset。从面向对象的角度来讲,kset继承了kobject的功能,既可以表示sysfs中的一个目录,还可以包含下层目录。对于kobject和kset,会在其它文章中专门分析到,这里简单描述只是为了更好地介绍sysfs提供的API。

    sysfs模块提供给外界的接口完全展现在include/linux/sysfs.h中。

  1. struct attribute {  
  2.     const char      *name;  
  3.     struct module       *owner;  
  4.     mode_t          mode;  
  5. };  
  6.   
  7. struct attribute_group {  
  8.     const char      *name;  
  9.     mode_t          (*is_visible)(struct kobject *,  
  10.                           struct attribute *, int);  
  11.     struct attribute    **attrs;  
  12. };  

之前说过普通文件是kobject目录的属性展现。struct attribute就是属性的通用结构,其它部分在使用时还可以把struct attribute内嵌到更大的属性结构中。struct attribute_group是提供一组属性的集合,这样集中的管理更为方便。

  1. #define __ATTR(_name,_mode,_show,_store) { \  
  2.     .attr = {.name = __stringify(_name), .mode = _mode },   \  
  3.     .show   = _show,                    \  
  4.     .store  = _store,                   \  
  5. }  
  6.   
  7. #define __ATTR_RO(_name) { \  
  8.     .attr   = { .name = __stringify(_name), .mode = 0444 }, \  
  9.     .show   = _name##_show,                 \  
  10. }  
  11.   
  12. #define __ATTR_NULL { .attr = { .name = NULL } }  
  13.   
  14. #define attr_name(_attr) (_attr).attr.name  

以上的宏是为了静态初始化属性时更为方便,我们简单将其忽略。

  1. struct bin_attribute {  
  2.     struct attribute    attr;  
  3.     size_t          size;  
  4.     void            *private;  
  5.     ssize_t (*read)(struct kobject *, struct bin_attribute *,  
  6.             char *, loff_t, size_t);  
  7.     ssize_t (*write)(struct kobject *, struct bin_attribute *,  
  8.              char *, loff_t, size_t);  
  9.     int (*mmap)(struct kobject *, struct bin_attribute *attr,  
  10.             struct vm_area_struct *vma);  
  11. };  

struct attribute是通用的属性结构,而struct bin_attribute就是为二进制属性专门设计的,它在sysfs中表现为二进制文件,大多数是设备配置参数的映射。struct bin_attribute恰恰就是把struct attribute内嵌到更大结构的样例。

  1. struct sysfs_ops {  
  2.     ssize_t (*show)(struct kobject *, struct attribute *,char *);  
  3.     ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);  
  4. };  

struct sysfs_ops中包含show和store两个函数指针,它们分别在sysfs文件读和文件写时调用。

  1. int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),  
  2.                 void *data, struct module *owner);  

sysfs_schedule_callback()会创建一个工作队列,稍后调用func(data)。本来sysfs中的属性读写函数是无法删除属性文件或者kobject目录的,因为调用函数时是加锁的,要删除也需要加锁。但这里可以通过工作队列回调的方式实现。

  1. int __must_check sysfs_create_dir(struct kobject *kobj);  
  2. void sysfs_remove_dir(struct kobject *kobj);  
  3. int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);  
  4. int __must_check sysfs_move_dir(struct kobject *kobj,  
  5.                 struct kobject *new_parent_kobj);  

sysfs_create_dir()创建一个kobject对应的目录,目录名就是kobj->name。

sysfs_remove_dir()删除kobj对应的目录。删除一个目录也会相应地删除目录下的文件及子目录。

sysfs_rename_dir()修改kobj对应目录的名称。

sysfs_move_dir()将kobj对应的目录移到new_parent_kobj对应的目录下。

 

  1. int __must_check sysfs_create_file(struct kobject *kobj,  
  2.                    const struct attribute *attr);  
  3. int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,  
  4.                   mode_t mode);  
  5. void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);  

sysfs_create_file()在kobj对应的目录下创建attr对应的属性文件。

sysfs_chmod_file()修改attr对应的属性文件的读写权限。

sysfs_remove_file()在kobj对应的目录下删除attr对应的属性文件。

 

  1. int __must_check sysfs_create_bin_file(struct kobject *kobj,  
  2.                        struct bin_attribute *attr);  
  3. void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);  

sysfs_create_bin_file()在kobj目录下创建attr对应的二进制属性文件。

sysfs_remove_bin_file()在kobj目录下删除attr对应的二进制属性文件。

  1. int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,  
  2.                    const char *name);  
  3. int __must_check sysfs_create_link_nowarn(struct kobject *kobj,  
  4.                       struct kobject *target,  
  5.                       const char *name);  
  6. void sysfs_remove_link(struct kobject *kobj, const char *name);  

sysfs_create_link()在kobj目录下创建指向target目录的软链接,name为软链接文件名称。

sysfs_create_link_nowarn()与sysfs_create_link()功能相同,只是在软链接文件已存在时不会出现警告。

sysfs_remove_link()删除kobj目录下名为name的软链接文件。

  1. int __must_check sysfs_create_group(struct kobject *kobj,  
  2.         const struct attribute_group *grp);  
  3. int sysfs_update_group(struct kobject *kobj,  
  4.          const struct attribute_group *grp);  
  5. void sysfs_remove_group(struct kobject *kobj,  
  6.    const struct attribute_group *grp);  
  7. int sysfs_add_file_to_group(struct kobject *kobj,  
  8.    const struct attribute *attr, const char *group);  
  9. void sysfs_remove_file_from_group(struct kobject *kobj,  
  10.    const struct attribute *attr, const char *group);  

sysfs_create_group()在kobj目录下创建一个属性集合,并显示集合中的属性文件。如果文件已存在,会报错。

sysfs_update_group()在kobj目录下创建一个属性集合,并显示集合中的属性文件。文件已存在也不会报错。sysfs_update_group()也用于group改动影响到文件显示时调用。

sysfs_remove_group()在kobj目录下删除一个属性集合,并删除集合中的属性文件。

sysfs_add_file_to_group()将一个属性attr加入kobj目录下已存在的的属性集合group。

sysfs_remove_file_from_group()将属性attr从kobj目录下的属性集合group中删除。

 

  1. void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);  
  2. void sysfs_notify_dirent(struct sysfs_dirent *sd);  

sysfs_notify()和sysfs_notify_dirent()都是用来唤醒在属性文件上调用select()或poll()而阻塞的用户进程。

  1. struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,  
  2.                       const unsigned char *name);  
  3. struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);  
  4. void sysfs_put(struct sysfs_dirent *sd);  

sysfs_get()增加目录或文件的引用计数。

sysfs_put()减少目录或文件的引用计数,并在降为零时删除相应的文件或目录,这种删除又会减少上层目录的引用计数。

sysfs_get_dirent()是增加目录parent_sd中名为name的目录或文件的引用计数。

虽然同样是引用计数,同样在降为零时有删除动作,但却并非使用kref。这种操作更多地继承了文件系统管理时的传统。

  1. void sysfs_printk_last_file(void);  
  2. int __must_check sysfs_init(void);  

sysfs_printk_last_file()是在sysfs崩溃时打印最后一个访问到的文件路径。

sysfs_init()是在sysfs模块初始化时调用的。

这两个函数都与我们没有什么关系。



<think>好的,用户让我介绍一下Linux驱动API函数,我需要用中文回答。首先,我得回想一下Linux驱动开发的基础知识。用户可能是刚开始学习驱动开发的开发者,或者是对操作系统内部感兴趣的技术爱好者。他们可能需要了解如何与硬件交互,或者想理解驱动的工作原理。 我应该从模块的加载和卸载开始,因为这是驱动的基础,init和exit函数。然后,设备文件的创建,比如class_create和device_create,这些对于用户空间访问设备很重要。接下来是字符设备的核心结构,比如file_operations,里面包含read、write、ioctl等函数指针,需要详细解释每个成员的作用。 然后要考虑注册和注销设备的函数,比如register_chrdev和unregister_chrdev,可能还需要提到动态分配主设备号的方法。用户可能对如何与硬件交互感兴趣,所以需要介绍ioremap和iounmap,以及读写IO端口和内存的函数。 中断处理部分也很关键,request_irq和free_irq,以及tasklet和工作队列的区别,需要简单说明它们的应用场景。内存管理方面,kmalloc、vmalloc和DMA相关的API可能也是用户关心的点。 同步机制如自旋锁、互斥锁,以及等待队列,这些在驱动开发中避免竞态条件很重要。sysfs和proc文件系统的接口,对于调试和提供用户空间配置可能有帮助。 另外,可能需要提到内核版本变化对API的影响,比如高版本内核中的变化,确保用户注意兼容性问题。用户可能在实际开发中遇到问题,所以给出一些示例代码结构,帮助他们理解如何组织驱动代码。 最后,总结一下学习这些API的步骤和资源,比如Linux设备驱动书籍和内核文档,帮助用户进一步学习。需要确保语言通俗易懂,避免过于专业的术语,但也要准确无误。检查是否有遗漏的重要API,比如平台设备驱动相关的函数,或者设备树相关的操作,但可能用户暂时不需要太深入的内容,保持回答的基础性和全面性即可。</think>Linux 驱动开发的核心是使用内核提供的 API 函数与硬件交互并为用户空间提供接口。以下是一些关键 API 函数及其作用,按功能分类介绍: --- ### **1. 模块加载/卸载** - **`module_init(x)` / `module_exit(x)`** 定义驱动模块的初始化函数和退出函数,加载时调用 `init`,卸载时调用 `exit`。 --- ### **2. 设备文件与类** - **`class_create()` / `class_destroy()`** 创建设备类(如 `/sys/class/mydev/`),用于 sysfs 管理。 - **`device_create()` / `device_destroy()`** 在类下创建设备节点(如 `/dev/mydev0`),用户可通过此节点访问驱动。 --- ### **3. 字符设备驱动** - **`register_chrdev()` / `unregister_chrdev()`** 注册/注销字符设备,分配主设备号。 - **`cdev_init()` / `cdev_add()` / `cdev_del()`** 动态初始化字符设备对象并将其添加到内核。 - **`file_operations` 结构体** 定义用户空间操作驱动的函数指针: - `open()`: 打开设备 - `release()`: 关闭设备 - `read()`: 从设备读取数据 - `write()`: 向设备写入数据 - `unlocked_ioctl()`: 控制命令(如配置设备) - `mmap()`: 内存映射(用于 DMA 等场景) --- ### **4. 硬件交互** - **`ioremap()` / `iounmap()`** 将物理地址映射到内核虚拟地址空间,用于访问硬件寄存器。 - **`inb()` / `outb()` / `readl()` / `writel()`** 读写 I/O 端口或内存映射寄存器。 - **`request_irq()` / `free_irq()`** 注册/释放中断处理函数,响应硬件中断。 --- ### **5. 同步与并发** - **`spin_lock()` / `spin_unlock()`** 自旋锁,保护短临界区(如中断上下文)。 - **`mutex_lock()` / `mutex_unlock()`** 互斥锁,用于睡眠安全的临界区。 - **`wait_queue_head_t`** 等待队列,实现阻塞式 I/O(如 `read` 等待数据到达)。 --- ### **6. 内存管理** - **`kmalloc()` / `kfree()`** 分配/释放内核物理连续内存。 - **`vmalloc()` / `vfree()`** 分配虚拟连续(物理可能不连续)的大内存。 - **`dma_alloc_coherent()`** 分配 DMA 可用内存,用于与硬件直接传输数据。 --- ### **7. 其他关键 API** - **`printk()`** 内核日志输出,调试驱动时常用(优先级如 `KERN_INFO`)。 - **`copy_to_user()` / `copy_from_user()`** 在用户空间和内核空间之间安全复制数据。 - **`sysfs_create_file()`** 在 sysfs 中创建设备属性文件,供用户空间配置参数。 --- ### **示例驱动代码结构** ```c #include <linux/module.h> #include <linux/fs.h> static int mydev_open(struct inode *inode, struct file *filp) { /* ... */ } static ssize_t mydev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { /* ... */ } static struct file_operations fops = { .owner = THIS_MODULE, .open = mydev_open, .read = mydev_read, }; static int __init mydev_init(void) { register_chrdev(MAJOR_NUM, "mydev", &fops); class_create(THIS_MODULE, "mydev_class"); device_create(...); return 0; } static void __exit mydev_exit(void) { /* 反向操作 */ } module_init(mydev_init); module_exit(mydev_exit); MODULE_LICENSE("GPL"); ``` --- ### **学习资源** 1. **书籍**:《Linux Device Drivers》(O'Reilly,免费在线版) 2. **内核文档**:`Documentation/driver-api/`(内核源码中) 3. **实战**:从简单字符设备驱动开始,逐步添加中断、DMA 等功能。 Linux 驱动开发需熟悉内核编程规范,并注意不同内核版本的 API 变化(如旧版 `register_chrdev` 与新 `cdev` 接口的差异)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值