在 Linux 驱动开发中,struct file_operations
是字符设备驱动的核心接口,定义了驱动支持的所有文件操作(如 open
/read
/write
)。它是驱动与用户空间交互的桥梁,每个函数对应一个系统调用。
1. 结构体定义
定义在 <linux/fs.h>
中,核心成员如下:
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
// 其他成员(如 poll、mmap 等)
};
2. 关键成员函数
(1) open
和 release
-
open
:首次打开设备时调用,用于初始化硬件或分配资源。static int my_open(struct inode *inode, struct file *file) { // 获取设备私有数据(如硬件寄存器地址) struct my_device *dev = container_of(inode->i_cdev, struct my_device, cdev); file->private_data = dev; // 初始化硬件... return 0; }
-
release
:文件关闭时调用,释放资源。static int my_release(struct inode *inode, struct file *file) { struct my_device *dev = file->private_data; // 关闭硬件... return 0; }
(2) read
和 write
-
read
:从设备读取数据到用户空间。static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev = file->private_data; // 从硬件读取数据到内核缓冲区 copy_to_user(buf, dev->kernel_buffer, count); // 复制到用户空间 return count; }
-
write
:将用户空间数据写入设备。static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev = file->private_data; copy_from_user(dev->kernel_buffer, buf, count); // 从用户空间复制 // 写入硬件... return count; }
(3) unlocked_ioctl
- 处理设备特定的控制命令(如配置寄存器)。
static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct my_device *dev = file->private_data; switch (cmd) { case MY_IOCTL_CMD: // 处理命令... return 0; default: return -EINVAL; } }
3. 驱动中的使用示例
// 1. 定义 file_operations 实例
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
.unlocked_ioctl = my_ioctl,
};
// 2. 注册字符设备
static int __init my_init(void) {
dev_t dev = MKDEV(major, 0);
cdev_init(&my_cdev, &my_fops);
return cdev_add(&my_cdev, dev, 1);
}
4. 关键注意事项
-
线程安全:
- 使用互斥锁(如
mutex_lock
)保护共享资源:static DEFINE_MUTEX(my_mutex); static int my_open(...) { mutex_lock(&my_mutex); // 初始化操作... mutex_unlock(&my_mutex); return 0; }
- 使用互斥锁(如
-
用户空间交互:
- 使用
copy_to_user
/copy_from_user
安全访问用户内存。 - 返回负数错误码(如
-EFAULT
表示内存错误)。
- 使用
-
权限检查:
if (!capable(CAP_SYS_ADMIN)) return -EPERM; // 拒绝非特权用户访问
-
偏移量管理:
- 通过
loff_t *ppos
跟踪文件读写位置(如支持lseek
)。
- 通过
5. 高级主题
- 异步 I/O:实现
.aio_read
/.aio_write
支持异步操作。 - 轮询/select:实现
.poll
函数通知文件就绪状态。 - 内存映射:通过
.mmap
将设备内存映射到用户空间。
总结
struct file_operations
是驱动与用户空间的接口契约。通过填充此结构体,驱动开发者将硬件操作映射到标准文件操作,使得用户空间程序可以通过 open()
/read()
/write()
等系统调用与设备交互。正确实现这些函数是编写稳定字符设备驱动的关键。