我正在学习Linux Device Drivers, 3rd edition的第3.5章。本节介绍一种检索我们自己在open函数中struct inode *inode
定义的自定义结构的方法:
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev;
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
}
return 0;
}
据我了解,在设备打开时,代表设备的struct inode *inode
会传递给scull_open
。然后,提取自定义结构dev
并将其传递给filp->private_data
,以便其他方法(例如scull_read
)可以使用它:
ssize_t scull_read(struct file *filp, char _ _user *buf, size_t count,
loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
/* other codes that uses *dev */
}
在我意识到struct scull_dev *dev
here初始化过程中我们已经有scull_setup_cdev
之前,我觉得这很好。
我很困惑,因为我认为我们可以使struct scull_dev *dev
成为一个全局变量,然后scull_read
和其他方法最终可以访问它而无需使用inode
进行所有传递和file
。
我的问题是,为什么我们不把它变成一个全局变量?
有人能提供一些使用此方法传递数据的实际例子吗?
答案 0 :(得分:10)
主要原因是您的驱动程序可以管理多个设备。例如,您可以创建(mknod
)多个设备/dev/scull1
,/dev/scull2
,/dev/scull3
...然后每个设备都会有不同的scull_dev
关联用它。
使用全局变量,您只能使用一个变量。即使您的驱动程序仅支持一个这样的设备,也没有理由不设计代码未来证据。
答案 1 :(得分:8)
主题安全!如果两个线程/进程同时使用驱动程序怎么办?
答案 2 :(得分:0)
您还可以避免使用私人数据来存储您的实际设备,如果您需要私有数据用于不同的设置,这是一种常见的选择。在这种情况下,您需要在scull_read例程中检索次要编号。它会是这样的:
ssize_t scull_read( struct file *filp,
char __user* buf,
size_t count,
loff_t * f_pos ) {
int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
printk( "reading on minor number %d\n", minor);
/* use dev[minor] in ur code */
return 0;
}
答案 3 :(得分:0)
我不认为这是一个安全问题。它更像是一种设计选择。如果我没有弄错的话,通过scull_dev中的信号量向下和向上来实现线程安全性。如果深入研究代码,可以看到打开,读取,写入所有使用过的down_interruptible()。
我猜作者1)认为直接访问scull_dev并不好看2)想告诉我们如何使用private_data。通过将scull_dev指向结构文件,其指针被发送到每个操作,每个操作都可以在不使用全局变量的情况下访问它。
答案 4 :(得分:0)
scull驱动程序由4个未成年人实现,每个未成年人都有一个单独的scull_dev,每个scull_dev都有" struct cdev"嵌入其中。现在让我们说User已经从/ dev / scull0打开了scull0。在open()函数中,您需要指向正确的scull_dev结构。 scull_dev结构是动态分配的。
您可以在此处查看完整实施 https://github.com/mharsch/ldd3-samples/blob/master/scull/main.c#L450