v4l2 编程接口(一) ― ioctl(三)

2014-11-24 09:08:18 · 作者: · 浏览: 1
...
/* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */
if (_IOC_DIR(cmd) != _IOC_NONE) {
/* 判断参数大小是否超过128字节 */
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* 如果超过128字节则从堆中申请 */
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}

err = -EFAULT;
/* 如果包含写命令 */
if (_IOC_DIR(cmd) & _IOC_WRITE) {
/* 计算需要拷贝的有效数据长度,有的命令不需要全部拷贝 */
unsigned long n = cmd_input_size(cmd);
/* 从用户空间拷贝参数值 */
if (copy_from_user(parg, (void __user *)arg, n))
goto out;

/* 将剩下的空间清零 */
if (n < _IOC_SIZE(cmd))
memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
} else {
/* 如果是只读命令则将整个buffer清零 */
memset(parg, 0, _IOC_SIZE(cmd));
}
}

...
/* 调用 v4l2_ioctl_ops 的成员函数处理命令 */
err = __video_do_ioctl(file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
...
if (err < 0)
goto out;

out_ext_ctrl:
/* 如果包含读命令则将参数值拷贝到用户空间 */
switch (_IOC_DIR(cmd)) {
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
err = -EFAULT;
break;
}

out:
kfree(mbuf);
return err;
}
EXPORT_SYMBOL(video_ioctl2);
然后我们在 struct v4l2_file_operations 中将 ioctl 成员设置为 video_ioctl2 即可。