diff options
-rw-r--r-- | drivers/usb/gadget/function/f_qc_rndis.c | 91 |
1 files changed, 68 insertions, 23 deletions
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index 45c39d3c4225..434af820e827 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -1245,16 +1245,19 @@ usb_function *rndis_qc_bind_config_vendor(struct usb_function_instance *fi, rndis->func.resume = rndis_qc_resume; rndis->func.free_func = rndis_qc_free; - _rndis_qc = rndis; - status = rndis_ipa_init(&rndis_ipa_params); if (status) { pr_err("%s: failed to init rndis_ipa\n", __func__); - kfree(rndis); - return ERR_PTR(status); + goto fail; } + _rndis_qc = rndis; + return &rndis->func; +fail: + kfree(rndis); + _rndis_qc = NULL; + return ERR_PTR(status); } static struct usb_function *qcrndis_alloc(struct usb_function_instance *fi) @@ -1264,74 +1267,116 @@ static struct usb_function *qcrndis_alloc(struct usb_function_instance *fi) static int rndis_qc_open_dev(struct inode *ip, struct file *fp) { + int ret = 0; + unsigned long flags; pr_info("Open rndis QC driver\n"); + spin_lock_irqsave(&rndis_lock, flags); if (!_rndis_qc) { pr_err("rndis_qc_dev not created yet\n"); - return -ENODEV; + ret = -ENODEV; + goto fail; } if (rndis_qc_lock(&_rndis_qc->open_excl)) { pr_err("Already opened\n"); - return -EBUSY; + ret = -EBUSY; + goto fail; } fp->private_data = _rndis_qc; - pr_info("rndis QC file opened\n"); +fail: + spin_unlock_irqrestore(&rndis_lock, flags); - return 0; + if (!ret) + pr_info("rndis QC file opened\n"); + + return ret; } static int rndis_qc_release_dev(struct inode *ip, struct file *fp) { - struct f_rndis_qc *rndis = fp->private_data; - + unsigned long flags; pr_info("Close rndis QC file\n"); - rndis_qc_unlock(&rndis->open_excl); + spin_lock_irqsave(&rndis_lock, flags); + + if (!_rndis_qc) { + pr_err("rndis_qc_dev not present\n"); + spin_unlock_irqrestore(&rndis_lock, flags); + return -ENODEV; + } + rndis_qc_unlock(&_rndis_qc->open_excl); + spin_unlock_irqrestore(&rndis_lock, flags); return 0; } static long rndis_qc_ioctl(struct file *fp, unsigned cmd, unsigned long arg) { - struct f_rndis_qc *rndis = fp->private_data; + u8 qc_max_pkt_per_xfer = 0; + u32 qc_max_pkt_size = 0; int ret = 0; + unsigned long flags; - pr_info("Received command %d\n", cmd); + spin_lock_irqsave(&rndis_lock, flags); + if (!_rndis_qc) { + pr_err("rndis_qc_dev not present\n"); + ret = -ENODEV; + goto fail; + } + + qc_max_pkt_per_xfer = _rndis_qc->ul_max_pkt_per_xfer; + qc_max_pkt_size = _rndis_qc->max_pkt_size; + + if (rndis_qc_lock(&_rndis_qc->ioctl_excl)) { + ret = -EBUSY; + goto fail; + } + + spin_unlock_irqrestore(&rndis_lock, flags); - if (rndis_qc_lock(&rndis->ioctl_excl)) - return -EBUSY; + pr_info("Received command %d\n", cmd); switch (cmd) { case RNDIS_QC_GET_MAX_PKT_PER_XFER: ret = copy_to_user((void __user *)arg, - &rndis->ul_max_pkt_per_xfer, - sizeof(rndis->ul_max_pkt_per_xfer)); + &qc_max_pkt_per_xfer, + sizeof(qc_max_pkt_per_xfer)); if (ret) { pr_err("copying to user space failed\n"); ret = -EFAULT; } pr_info("Sent UL max packets per xfer %d\n", - rndis->ul_max_pkt_per_xfer); + qc_max_pkt_per_xfer); break; case RNDIS_QC_GET_MAX_PKT_SIZE: ret = copy_to_user((void __user *)arg, - &rndis->max_pkt_size, - sizeof(rndis->max_pkt_size)); + &qc_max_pkt_size, + sizeof(qc_max_pkt_size)); if (ret) { pr_err("copying to user space failed\n"); ret = -EFAULT; } pr_debug("Sent max packet size %d\n", - rndis->max_pkt_size); + qc_max_pkt_size); break; default: pr_err("Unsupported IOCTL\n"); ret = -EINVAL; } - rndis_qc_unlock(&rndis->ioctl_excl); + spin_lock_irqsave(&rndis_lock, flags); + if (!_rndis_qc) { + pr_err("rndis_qc_dev not present\n"); + ret = -ENODEV; + goto fail; + } + + rndis_qc_unlock(&_rndis_qc->ioctl_excl); + +fail: + spin_unlock_irqrestore(&rndis_lock, flags); return ret; } @@ -1385,11 +1430,11 @@ static int qcrndis_set_inst_name(struct usb_function_instance *fi, return -ENOMEM; } + spin_lock_init(&rndis_lock); opts->rndis = rndis; ret = misc_register(&rndis_qc_device); if (ret) pr_err("rndis QC driver failed to register\n"); - spin_lock_init(&rndis_lock); ret = ipa_data_setup(USB_IPA_FUNC_RNDIS); if (ret) { |