欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux设备驱动开发-file_operations结构体day02

程序员文章站 2022-06-05 17:29:01
...

作者: kiki
参考书:<linux设备驱动开发详解-宋宝华>
转载请注明出处!
day02
摘要: file_operations()结构体的结构与成员函数

1.file_operations结构体
其成员函数是字符设备驱动与内核虚拟文件系统的接口,是用户空间对Linux进行系统调用最终的落实者,把系统调用和驱动程序关联起来.
注意: __usr是一个宏,其后的指针指向用户空间.
(1)读设备

/*读设备*/
ssize_t xxx_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)
{
  ...
  copy_to_user(buf,...,...);
  ...
}

filp是文件结构体指针
buf是用户空间内存的地址,不宜直接读写
count是要读的字节数
f_pos是读的位置相对于文件开头的偏移

(2)写设备

ssize_t xxx_write(struct file *filp,const char__user *buf,size_t count,loff_t *f_pos)
{
  ...
  copy_from_user(...,buf,...);
  ...
}

filp是文件结构体指针
buf是用户空间内存的地址,不宜直接读写
count是要写的字节数
f_pos是写的位置相对于文件开头的偏移
**说明:**由于用户空间不能直接访问内核空间的内存,所以借助
copy_from_user(),用户空间缓冲区到内核空间的复制
copy_to_user(),内核空间到用户空间缓冲区的复制

当要复制的内存是简单类型时, 如char , int , long , 等,可以用下列函数进行操作:

int val; /*内核空间整型变量*/
...
get_user(val,(int*)arg);   /*用户到内核,arg是用户空间的地址*/
...
put_user(val,(int*)arg);    /*内核到用户,arg时用户空间的地址*/

内核空间在访问用户空间的缓冲区时,需要先检查其合法性,通过access_ok(type,addr,size) 判断,来确定传入的缓冲区的确属于用户空间.如果不做这项检查,操作系统内核很容易被攻击,就会存在安全漏洞.
此函数检查用户空间中的内存块是否可用。如果可用,则返回真(非0值),否则返回假 (0) 。例:

static ssize_t read_port(struct file *file,char __user *buf,size_t count,loff_t *ppos)
{
	unsigned long i = *ppos;
	char __user *tmp = buf;
	
	if (!access_ok(VERIFY_WRITE,buf,count))
		return -EFAULT;
	while (count-- > 0 && i<65536){
		if (__put_user(inb(i),tmp) < 0)
			return -EFAULT;
		i++;
		tmp++;
	}
	*ppos = i;
	return tmp-buf;
}

__put_user()与put_user()的区别:后者会自动进行access_ok()检查.上述代码用到__put_user()是因为我们手动做access_ok()检查.

get_user()和__get_user()区别相似.

copy_from_user()和copy_to_user()内部也进行了access_ok()检查.

(3)I/O控制函数

long xxx_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
	...
	switch (cmd){
	case XXX_CMD1:
		...
		break;
	case XXX_CMD2:
		...
		break;
	default:
		/*不能支持的命令*/
		return -ENOTTY;
	}
	return 0;
}

cmd参数为事先定义的I/O控制命令,arg为对应于该命令的参数.例:
SET_BAUDRATE是设置波特率的命令
arg就应该是波特率值.

2.字符设备驱动中,需要定义一个file_operations实例,并将具体设备驱动函数赋给file_operations的成员:

struct file_operations xxx_fops = {
	.owner = THIS_MODULE,
	.read = xxx_read,
	.write = xxx_write,
	.unlocked_ioctl = xxx_ioctl,
	...
};

以上代码中xxx_fops与day01中模块加载函数的
cdev_init(&xxx_dev.cdev,&xxx_fops)函数进行与cdev的连接.

相关标签: 驱动