Linux DVB API 添加 IOCTL 时使用 _IOW
_IOR
_IOWR
工作不正常,只有 _IO
正常
##
static struct file_operations dvb_frontend_fops = {
.owner = THIS_MODULE,
.ioctl = dvb_generic_ioctl,
.poll = dvb_frontend_poll,
.open = dvb_frontend_open,
.release = dvb_frontend_release
};
int dvb_register_frontend(struct dvb_adapter* dvb,
struct dvb_frontend* fe)
{
struct dvb_frontend_private *fepriv;
static const struct dvb_device dvbdev_template = {
.users = ~0,
.writers = 1,
.readers = (~0)-1,
.fops = &dvb_frontend_fops,
.kernel_ioctl = dvb_frontend_ioctl
};
printk ("%s\n", __func__);
printk ("%x\n", FE_SET_DEMOD_TS_CONTROL);
if (mutex_lock_interruptible(&frontend_mutex))
return -ERESTARTSYS;
fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
if (fe->frontend_priv == NULL) {
mutex_unlock(&frontend_mutex);
return -ENOMEM;
}
fepriv = fe->frontend_priv;
init_MUTEX (&fepriv->sem);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
mutex_init(&fepriv->events.mtx);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
mutex_unlock(&frontend_mutex);
return 0;
}
EXPORT_SYMBOL(dvb_register_frontend);
int dvb_generic_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct dvb_device *dvbdev = file->private_data;
printk("%s CMD:%x\n", __func__, cmd);
if (!dvbdev)
return -ENODEV;
if (!dvbdev->kernel_ioctl)
return -EINVAL;
return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
}
EXPORT_SYMBOL(dvb_generic_ioctl);
int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg))
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
printk("%s CMD:%x\n", __func__, cmd);
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_NONE:
/*
* For this command, the pointer is actually an integer
* argument.
*/
parg = (void *) arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
printk("%s():%d\n", __func__, __LINE__);
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}
err = -EFAULT;
printk("%s():%d %p %d\n", __func__, __LINE__, (void __user *)arg, _IOC_SIZE(cmd));
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
goto out;
break;
}
printk("%d\n", parg);
/* call driver */
if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
goto out;
/* Copy results into user buffer */
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;
}
##
从内核代码可以得出
err = -EFAULT;
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
goto out;
_IOW
_IOWR
_IOR
参数传递需要使用指针,如果要直接传递值,只能使用 _IO