0%

dvb api `_IOW` 工作不正常

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