引子:
在jz2440韦东山写的led驱动,并没有实现open函数。在测试app中,仍使用
open(filename, O_RDWR)打开设备并随后对其进行ioctl以及read等操作。
【App中filename = "/dev/leds" 或"/dev/led1" "/dev/led2" "/dev/led3"】
而在《linux设备驱动开发详解》中的一个驱动,实现了open。
-
int xx_open(struct inode inode ,struct file* filp)
-
{
-
struct xx_dev *dev;
-
dev = container_of(inode->i_cdev , struct xx_dev ,cdev);
-
filp->private_data = dev ;
-
return 0;
-
}
那么,open实现与否有何影响?
_______________________________________________________________________________
-
QQ 潘老师 12:45:31
-
字符设备框架中open接口是必须实现的
-
原因如下:
-
1、一切皆是"文件",字符设备也是"文件"
-
2、要操作一个文件必须先open,才能read/write
-
字符设备的原理如下:
-
1、cdev表征一个字符设备对象
-
通过cdev_alloc构造,cdev_init初始化好
-
然后用cdev_add把这个对象插入内核管理数据区(链表,插入节点)
-
2、mknod创建设备文件
-
就是在VFS树形结构中创建了一个节点inode
-
inode根据类型,字符设备的默认open方法仅仅查找cdev对象节点
-
3、open过程
-
open通过设备文件查找到inode,并回调inode中的默认打开方面找到cdev对象,这样就找到了cdev中封装的file_operations,即操作方法函数集合,同时open过程会创建一个file对象(原因是open的时候有标志:譬如只读、只写、阻塞等等,两次打开的时候标志可以不一致,则每次创建一个file对象来抽象"文件",实际就是存储这些标志,并保存指向cdev中保存的file_operations方法)
-
4、read/write过程
-
通过文件描述符找到open时创建的file对象,就找到了open时初始化好的file中指向file_operations,则找到了驱动中对应的操作函数
-
百度知道Wu_Roc
-
如果不实现open的话,驱动会默认设备的打开永远成功。打开成功时open返回0。
-
内核里是若open函数未定义的话,会跳过这个函数。但是其他步骤不变。
-
关键代码:__dentry_open函数里
-
...
-
if (open) {
-
error = open(inode, f);
-
if (error)
-
goto cleanup_all;
-
}
-
...
-
所以sys_open调用的话会依旧照常进行。如果你定义了open,他就会调用的你写的open,如果没定义,就跳过这一步。
-
这里说明不实现open是允许的。
经过多方对比参考,在下面这个文章找到了想要的答案:
http://blog.sina.com.cn/s/blog_95268f5001015bkd.html
大多数linux驱动工程师都遵循一个"潜规则",那就是将文件的私有的数据private_data指向设备结构体,在read(),write,ioctl(),llseek等函数通过private_data访问设备结构体。一般,我们在open里,讲设备结构体赋值给文件私有数据指针,然后我们在ioctl,read,write等函数里面,通过filep找到设备结构体,并对设备进行操作。代码如下:
-
struct globalmem_dev{
-
struct cdev cdev;//cdev结构体,用于描述设备的结构体
-
unsigned char mem[GLOBALMEM_SIZE];//全局内存
-
};//自定义设备结构体
-
struct globalmem_dev *globalmem_devp;//指向设备的结构体指针
-
int globalmem_open(struct inode *inode,struct file *filp)
-
{
-
filp->private_data = globalmem_devp;//将设备结构体指针赋给文件私有数据指针,也就是将文件的私有的数据private_data指向设备结构体
-
return 0;
-
}
-
//设备控制函数
-
static int globalmem_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd,unsigned longarg)
-
{
-
struct globalmem_dev *dev = filp->private_data;//获得设备结构体指针
-
switch (cmd) {
-
case MEM_CLEAR :
-
memset(dev->mem,0,GLOBALMEM_SIZE);//清除全局内存
-
printk(KERN_INFO "globalmem is set to zero\n");
-
break;
-
-
default :
-
return -EINVAL;
-
}
-
return 0;
-
}
从中可以看出,open的实现结合read,write,实现了一种规范化的操作。在用户程序中,我们通过filename找到设备的inode或者filep,然后找到设备【具体过程不清楚】,并对其进行读写和控制。【待补充】
{
10.21:
struct globalmem_dev *dev = filp->private_data;
可以通过MINOR(dev->cdev->devno)得到minor,再switch(minor){ casexx : .....},这样似乎是在韦东山的代码上加了一层封装。
}
而在韦东山的代码中,因为没有实现open,使用了