diff options
Diffstat (limited to 'drivers/usb/gadget')
| -rw-r--r-- | drivers/usb/gadget/composite.c | 12 | ||||
| -rw-r--r-- | drivers/usb/gadget/configfs.c | 5 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_accessory.c | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_audio_source.c | 8 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 7 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_gsi.c | 218 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_mass_storage.c | 8 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_midi.c | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_mtp.c | 41 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/u_data_ipa.c | 4 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/u_ether.c | 3 | ||||
| -rw-r--r-- | drivers/usb/gadget/functions.c | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/udc/fsl_qe_udc.c | 7 |
13 files changed, 159 insertions, 160 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index a53b23789d7a..9622514e3df9 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1942,7 +1942,9 @@ unknown: if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; - composite_setup_complete(gadget->ep0, req); + if (value != -ESHUTDOWN) + composite_setup_complete(gadget->ep0, + req); } return value; } @@ -2031,7 +2033,8 @@ try_fun_setup: if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; - composite_setup_complete(gadget->ep0, req); + if (value != -ESHUTDOWN) + composite_setup_complete(gadget->ep0, req); } } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) { WARN(cdev, @@ -2461,6 +2464,11 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) spin_lock_irqsave(&cdev->lock, flags); if (cdev->delayed_status == 0) { + if (!cdev->config) { + spin_unlock_irqrestore(&cdev->lock, flags); + return; + } + spin_unlock_irqrestore(&cdev->lock, flags); WARN(cdev, "%s: Unexpected call\n", __func__); } else if (--cdev->delayed_status == 0) { diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 4964bb1a24b1..ed0ff7b1fc15 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -426,11 +426,6 @@ static int config_usb_cfg_link( } f = usb_get_function(fi); - if (f == NULL) { - /* Are we trying to symlink PTP without MTP function? */ - ret = -EINVAL; /* Invalid Configuration */ - goto out; - } if (IS_ERR(f)) { ret = PTR_ERR(f); goto out; diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 61057befc136..cd096fb9078f 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -255,6 +255,7 @@ static inline struct acc_dev *func_to_dev(struct usb_function *f) static struct usb_request *acc_request_new(struct usb_ep *ep, int buffer_size) { struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!req) return NULL; @@ -1079,6 +1080,7 @@ acc_function_unbind(struct usb_configuration *c, struct usb_function *f) static void acc_start_work(struct work_struct *data) { char *envp[2] = { "ACCESSORY=START", NULL }; + kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp); } diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index bcd817439dbf..db7903d19c43 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -310,6 +310,7 @@ static struct device_attribute *audio_source_function_attributes[] = { static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size) { struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!req) return NULL; @@ -377,10 +378,9 @@ static void audio_send(struct audio_dev *audio) /* compute number of frames to send */ now = ktime_get(); - msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time); - do_div(msecs, 1000000); - frames = msecs * SAMPLE_RATE; - do_div(frames, 1000); + msecs = div_s64((ktime_to_ns(now) - ktime_to_ns(audio->start_time)), + 1000000); + frames = div_s64((msecs * SAMPLE_RATE), 1000); /* Readjust our frames_sent if we fall too far behind. * If we get too far behind it is better to drop some frames than diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 739cf9790cd4..ab44bd316217 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1581,6 +1581,8 @@ static int functionfs_init(void) pr_err("failed registering file system (%d)\n", ret); ffs_ipc_log = ipc_log_context_create(NUM_PAGES, "f_fs", 0); + if (IS_ERR_OR_NULL(ffs_ipc_log)) + ffs_ipc_log = NULL; return ret; } @@ -1591,6 +1593,11 @@ static void functionfs_cleanup(void) pr_info("unloading\n"); unregister_filesystem(&ffs_fs_type); + + if (ffs_ipc_log) { + ipc_log_context_destroy(ffs_ipc_log); + ffs_ipc_log = NULL; + } } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 2f08a6c9d476..e46edc83430c 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -40,7 +40,6 @@ MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); static struct workqueue_struct *ipa_usb_wq; -static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); static int gsi_alloc_trb_buffer(struct f_gsi *gsi); @@ -48,6 +47,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi); static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned len, gfp_t flags); static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt); +static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f) +{ + bool remote_wakeup_allowed; + + if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) + remote_wakeup_allowed = f->func_wakeup_allowed; + else + remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; + + log_event_dbg("%s: remote_wakeup_allowed:%s", __func__, + remote_wakeup_allowed ? "true" : "false"); + return remote_wakeup_allowed; +} + void post_event(struct gsi_data_port *port, u8 event) { unsigned long flags; @@ -477,16 +490,22 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port) log_event_dbg("%s: EP Disable for data", __func__); - /* Block doorbell to GSI to avoid USB wrapper from - * ringing doorbell in case IPA clocks are OFF - */ - usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, + if (gsi->d_port.in_ep) { + /* + * Block doorbell to GSI to avoid USB wrapper from + * ringing doorbell in case IPA clocks are OFF. + */ + usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); + gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; + usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE); + } - usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE); - - if (gsi->d_port.out_ep) + if (gsi->d_port.out_ep) { + gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE); + } + gsi->d_port.net_ready_trigger = false; } @@ -523,19 +542,21 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) int ret = 0; bool block_db, f_suspend; struct f_gsi *gsi = d_port_to_gsi(d_port); + struct usb_function *f = &gsi->function; + + f_suspend = f->func_wakeup_allowed; + log_event_dbg("%s: f_suspend:%d", __func__, f_suspend); - f_suspend = gsi->function.func_wakeup_allowed; if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend, GSI_EP_OP_CHECK_FOR_SUSPEND)) { ret = -EFAULT; goto done; } - log_event_dbg("%s: Calling xdci_suspend", __func__); + log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id, - true); - + usb_gsi_remote_wakeup_allowed(f)); if (!ret) { d_port->sm_state = STATE_SUSPENDED; log_event_dbg("%s: STATE SUSPENDED", __func__); @@ -553,10 +574,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_err("%s: Error %d for %d", __func__, ret, gsi->prot_id); } - - log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); - done: + log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); return ret; } @@ -591,7 +610,6 @@ static void ipa_work_handler(struct work_struct *w) struct device *dev; struct device *gad_dev; struct f_gsi *gsi; - bool block_db; event = read_event(d_port); @@ -653,6 +671,29 @@ static void ipa_work_handler(struct work_struct *w) __func__); break; } + + /* + * Update desc and reconfigure USB GSI OUT and IN + * endpoint for RNDIS Adaptor enable case. + */ + if (d_port->out_ep && !d_port->out_ep->desc && + gsi->out_ep_desc_backup) { + d_port->out_ep->desc = gsi->out_ep_desc_backup; + d_port->out_ep->ep_intr_num = 1; + log_event_dbg("%s: OUT ep_op_config", __func__); + usb_gsi_ep_op(d_port->out_ep, + &d_port->out_request, GSI_EP_OP_CONFIG); + } + + if (d_port->in_ep && !d_port->in_ep->desc && + gsi->in_ep_desc_backup) { + d_port->in_ep->desc = gsi->in_ep_desc_backup; + d_port->in_ep->ep_intr_num = 2; + log_event_dbg("%s: IN ep_op_config", __func__); + usb_gsi_ep_op(d_port->in_ep, + &d_port->in_request, GSI_EP_OP_CONFIG); + } + ipa_connect_channels(d_port); ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; @@ -714,15 +755,7 @@ static void ipa_work_handler(struct work_struct *w) if (event == EVT_HOST_NRDY) { log_event_dbg("%s: ST_CON_HOST_NRDY\n", __func__); - block_db = true; - /* stop USB ringing doorbell to GSI(OUT_EP) */ - usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, - GSI_EP_OP_SET_CLR_BLOCK_DBL); - gsi_rndis_ipa_reset_trigger(gsi); - usb_gsi_ep_op(d_port->in_ep, NULL, - GSI_EP_OP_ENDXFER); - usb_gsi_ep_op(d_port->out_ep, NULL, - GSI_EP_OP_ENDXFER); + ipa_disconnect_handler(d_port); } ipa_disconnect_work_handler(d_port); @@ -1086,9 +1119,9 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf, list_add_tail(&cpkt->list, &c_port->cpkt_resp_q); spin_unlock_irqrestore(&c_port->lock, flags); - ret = gsi_ctrl_send_notification(gsi); + if (!gsi_ctrl_send_notification(gsi)) + c_port->modem_to_host++; - c_port->modem_to_host++; log_event_dbg("Exit %zu", count); return ret ? ret : count; @@ -1345,26 +1378,6 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->params); } -static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) -{ - unsigned long flags; - - if (!rndis) { - log_event_err("%s: gsi prot ctx is %pK", __func__, rndis); - return; - } - - spin_lock_irqsave(&rndis->d_port.lock, flags); - if (!rndis) { - log_event_err("%s: No RNDIS instance", __func__); - spin_unlock_irqrestore(&rndis->d_port.lock, flags); - return; - } - - rndis->d_port.net_ready_trigger = false; - spin_unlock_irqrestore(&rndis->d_port.lock, flags); -} - void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param) { struct f_gsi *rndis = param->v; @@ -1392,33 +1405,18 @@ static int queue_notification_request(struct f_gsi *gsi) { int ret; unsigned long flags; - struct usb_cdc_notification *event; - struct gsi_ctrl_pkt *cpkt; ret = usb_func_ep_queue(&gsi->function, gsi->c_port.notify, gsi->c_port.notify_req, GFP_ATOMIC); - if (ret == -ENOTSUPP || (ret < 0 && ret != -EAGAIN)) { + if (ret < 0) { spin_lock_irqsave(&gsi->c_port.lock, flags); gsi->c_port.notify_req_queued = false; - /* check if device disconnected while we dropped lock */ - if (atomic_read(&gsi->connected) && - !list_empty(&gsi->c_port.cpkt_resp_q)) { - cpkt = list_first_entry(&gsi->c_port.cpkt_resp_q, - struct gsi_ctrl_pkt, list); - list_del(&cpkt->list); - log_event_err("%s: drop ctrl pkt of len %d error %d", - __func__, cpkt->len, ret); - gsi_ctrl_pkt_free(cpkt); - } - gsi->c_port.cpkt_drop_cnt++; spin_unlock_irqrestore(&gsi->c_port.lock, flags); - } else { - ret = 0; - event = gsi->c_port.notify_req->buf; - log_event_dbg("%s: Queued Notify type %02x", __func__, - event->bNotificationType); } + log_event_dbg("%s: ret:%d req_queued:%d", + __func__, ret, gsi->c_port.notify_req_queued); + return ret; } @@ -2130,7 +2128,6 @@ static void gsi_suspend(struct usb_function *f) { bool block_db; struct f_gsi *gsi = func_to_gsi(f); - bool remote_wakeup_allowed; /* Check if function is already suspended in gsi_func_suspend() */ if (f->func_is_suspended) { @@ -2138,49 +2135,17 @@ static void gsi_suspend(struct usb_function *f) return; } - if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) - remote_wakeup_allowed = f->func_wakeup_allowed; - else - remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - - log_event_info("%s: remote_wakeup_allowed %d", - __func__, remote_wakeup_allowed); - - if (!remote_wakeup_allowed) { - if (gsi->prot_id == IPA_USB_RNDIS) - rndis_flow_control(gsi->params, true); - /* - * When remote wakeup is disabled, IPA is disconnected - * because it cannot send new data until the USB bus is - * resumed. Endpoint descriptors info is saved before it - * gets reset by the BAM disconnect API. This lets us - * restore this info when the USB bus is resumed. - */ - if (gsi->d_port.in_ep) - gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; - if (gsi->d_port.out_ep) - gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; - - ipa_disconnect_handler(&gsi->d_port); - - post_event(&gsi->d_port, EVT_DISCONNECTED); - queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); - log_event_dbg("%s: Disconnecting", __func__); - } else { - block_db = true; - usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, - GSI_EP_OP_SET_CLR_BLOCK_DBL); - post_event(&gsi->d_port, EVT_SUSPEND); - queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); - } - + block_db = true; + usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, + GSI_EP_OP_SET_CLR_BLOCK_DBL); + post_event(&gsi->d_port, EVT_SUSPEND); + queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("gsi suspended"); } static void gsi_resume(struct usb_function *f) { struct f_gsi *gsi = func_to_gsi(f); - bool remote_wakeup_allowed; struct usb_composite_dev *cdev = f->config->cdev; log_event_dbg("%s", __func__); @@ -2193,49 +2158,24 @@ static void gsi_resume(struct usb_function *f) f->func_is_suspended) return; - if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) - remote_wakeup_allowed = f->func_wakeup_allowed; - else - remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; - if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); - if (!remote_wakeup_allowed) { - - /* Configure EPs for GSI */ - if (gsi->d_port.out_ep) { - gsi->d_port.out_ep->desc = gsi->out_ep_desc_backup; - gsi->d_port.out_ep->ep_intr_num = 1; - usb_gsi_ep_op(gsi->d_port.out_ep, - &gsi->d_port.out_request, GSI_EP_OP_CONFIG); - } - gsi->d_port.in_ep->desc = gsi->in_ep_desc_backup; - if (gsi->prot_id != IPA_USB_DIAG) - gsi->d_port.in_ep->ep_intr_num = 2; - else - gsi->d_port.in_ep->ep_intr_num = 3; - - usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request, - GSI_EP_OP_CONFIG); - post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS); - - /* - * Linux host does not send RNDIS_MSG_INIT or non-zero - * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. - * Trigger state machine explicitly on resume. - */ - if (gsi->prot_id == IPA_USB_RNDIS) - rndis_flow_control(gsi->params, false); - } else - post_event(&gsi->d_port, EVT_RESUMED); + /* + * Linux host does not send RNDIS_MSG_INIT or non-zero + * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. + * Trigger state machine explicitly on resume. + */ + if (gsi->prot_id == IPA_USB_RNDIS && + !usb_gsi_remote_wakeup_allowed(f)) + rndis_flow_control(gsi->params, false); + post_event(&gsi->d_port, EVT_RESUMED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); - log_event_dbg("%s: completed", __func__); } @@ -3132,7 +3072,7 @@ MODULE_DESCRIPTION("GSI function driver"); static int fgsi_init(void) { ipa_usb_wq = alloc_workqueue("k_ipa_usb", - WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1); if (!ipa_usb_wq) { log_event_err("Failed to create workqueue for IPA"); return -ENOMEM; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 97d86b6ac69b..e309dec68a75 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2289,8 +2289,11 @@ reset: } common->running = 0; - if (!new_fsg || rc) + if (!new_fsg || rc) { + /* allow usb LPM after eps are disabled */ + usb_gadget_autopm_put_async(common->gadget); return rc; + } common->fsg = new_fsg; fsg = common->fsg; @@ -2333,6 +2336,9 @@ reset: bh->outreq->complete = bulk_out_complete; } + /* prevents usb LPM until thread runs to completion */ + usb_gadget_autopm_get_noresume(common->gadget); + common->running = 1; for (i = 0; i < ARRAY_SIZE(common->luns); ++i) if (common->luns[i]) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 8919cc26b98e..5bcff5d2cd8d 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1160,7 +1160,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) card = midi->card; midi->card = NULL; if (card) - snd_card_free(card); + snd_card_free_when_closed(card); usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 972ea68b16e4..bf7460f25e61 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -137,6 +137,7 @@ struct mtp_dev { unsigned dbg_read_index; unsigned dbg_write_index; bool is_ptp; + struct mutex read_mutex; }; static struct usb_interface_descriptor mtp_interface_desc = { @@ -412,6 +413,7 @@ static inline struct mtp_dev *func_to_mtp(struct usb_function *f) static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) { struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!req) return NULL; @@ -640,11 +642,18 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + goto done; + } requeue_req: /* queue a request */ req = dev->rx_req[0]; req->length = len; dev->rx_done = 0; + mutex_unlock(&dev->read_mutex); ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); if (ret < 0) { r = -EIO; @@ -670,6 +679,7 @@ requeue_req: usb_ep_dequeue(dev->ep_out, req); goto done; } + mutex_lock(&dev->read_mutex); if (dev->state == STATE_BUSY) { /* If we got a 0-len packet, throw it back and try again. */ if (req->actual == 0) @@ -683,6 +693,7 @@ requeue_req: } else r = -EIO; + mutex_unlock(&dev->read_mutex); done: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) @@ -937,6 +948,12 @@ static void receive_file_work(struct work_struct *data) while (count > 0 || write_req) { if (count > 0) { + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } /* queue a request */ read_req = dev->rx_req[cur_buf]; cur_buf = (cur_buf + 1) % RX_REQ_MAX; @@ -945,6 +962,7 @@ static void receive_file_work(struct work_struct *data) read_req->length = mtp_rx_req_len; dev->rx_done = 0; + mutex_unlock(&dev->read_mutex); ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); if (ret < 0) { r = -EIO; @@ -957,15 +975,23 @@ static void receive_file_work(struct work_struct *data) if (write_req) { DBG(cdev, "rx %pK %d\n", write_req, write_req->actual); start_time = ktime_get(); + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } ret = vfs_write(filp, write_req->buf, write_req->actual, &offset); DBG(cdev, "vfs_write %d\n", ret); if (ret != write_req->actual) { r = -EIO; + mutex_unlock(&dev->read_mutex); if (dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; break; } + mutex_unlock(&dev->read_mutex); dev->perf[dev->dbg_write_index].vfs_wtime = ktime_to_us(ktime_sub(ktime_get(), start_time)); dev->perf[dev->dbg_write_index].vfs_wbytes = ret; @@ -989,6 +1015,12 @@ static void receive_file_work(struct work_struct *data) break; } + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } /* Check if we aligned the size due to MTU constraint */ if (count < read_req->length) read_req->actual = (read_req->actual > count ? @@ -1009,6 +1041,7 @@ static void receive_file_work(struct work_struct *data) write_req = read_req; read_req = NULL; + mutex_unlock(&dev->read_mutex); } } @@ -1352,6 +1385,7 @@ static int mtp_ctrlrequest(struct usb_composite_dev *cdev, } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS && w_index == 0 && w_value == 0) { struct mtp_device_status *status = cdev->req->buf; + status->wLength = __constant_cpu_to_le16(sizeof(*status)); @@ -1374,6 +1408,7 @@ static int mtp_ctrlrequest(struct usb_composite_dev *cdev, /* respond with data transfer or status phase? */ if (value >= 0) { int rc; + cdev->req->zero = value < w_length; cdev->req->length = value; rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); @@ -1469,12 +1504,14 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) struct usb_request *req; int i; + mutex_lock(&dev->read_mutex); while ((req = mtp_req_get(dev, &dev->tx_idle))) mtp_request_free(req, dev->ep_in); for (i = 0; i < RX_REQ_MAX; i++) mtp_request_free(dev->rx_req[i], dev->ep_out); while ((req = mtp_req_get(dev, &dev->intr_idle))) mtp_request_free(req, dev->ep_intr); + mutex_unlock(&dev->read_mutex); dev->state = STATE_OFFLINE; dev->is_ptp = false; kfree(f->os_desc_table); @@ -1733,6 +1770,7 @@ static struct mtp_instance *to_mtp_instance(struct config_item *item) static void mtp_attr_release(struct config_item *item) { struct mtp_instance *fi_mtp = to_mtp_instance(item); + usb_put_function_instance(&fi_mtp->func_inst); } @@ -1853,7 +1891,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, pr_err("\t2: Create MTP function\n"); pr_err("\t3: Create and symlink PTP function" " with a gadget configuration\n"); - return NULL; + return ERR_PTR(-EINVAL); /* Invalid Configuration */ } dev = fi_mtp->dev; @@ -1877,6 +1915,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, dev->is_ptp = !mtp_config; fi->f = &dev->function; + mutex_init(&dev->read_mutex); return &dev->function; } EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index 4975ba474f97..5718f71bcdea 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -428,6 +428,7 @@ static void ipa_data_connect_work(struct work_struct *w) if (!gadget) { spin_unlock_irqrestore(&port->port_lock, flags); + usb_gadget_autopm_put_async(port->gadget); pr_err("%s: gport is NULL.\n", __func__); return; } @@ -691,6 +692,8 @@ disconnect_usb_bam_ipa_out: usb_bam_disconnect_ipa(port->usb_bam_type, &port->ipa_params); is_ipa_disconnected = true; } + if (port->func_type == USB_IPA_FUNC_RMNET) + teth_bridge_disconnect(port->ipa_params.src_client); unconfig_msm_ep_in: spin_lock_irqsave(&port->port_lock, flags); /* check if USB cable is disconnected or not */ @@ -713,6 +716,7 @@ out: spin_lock_irqsave(&port->port_lock, flags); port->is_connected = false; spin_unlock_irqrestore(&port->port_lock, flags); + usb_gadget_autopm_put_async(port->gadget); } /** diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 81ce22e91883..43e054666b68 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -743,7 +743,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, /* throttle highspeed IRQ rate back slightly */ if (gadget_is_dualspeed(dev->gadget) && - (dev->gadget->speed == USB_SPEED_HIGH)) { + (dev->gadget->speed == USB_SPEED_HIGH) && + !list_empty(&dev->tx_reqs)) { dev->tx_qlen++; if (dev->tx_qlen == (dev->qmult/2)) { req->no_interrupt = 0; diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c index 389c1f3d0fee..b13f839e7368 100644 --- a/drivers/usb/gadget/functions.c +++ b/drivers/usb/gadget/functions.c @@ -58,7 +58,7 @@ struct usb_function *usb_get_function(struct usb_function_instance *fi) struct usb_function *f; f = fi->fd->alloc_func(fi); - if ((f == NULL) || IS_ERR(f)) + if (IS_ERR(f)) return f; f->fi = fi; return f; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index c73689b72f95..b38a33584d4a 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -1878,11 +1878,8 @@ static int qe_get_frame(struct usb_gadget *gadget) tmp = in_be16(&udc->usb_param->frame_n); if (tmp & 0x8000) - tmp = tmp & 0x07ff; - else - tmp = -EINVAL; - - return (int)tmp; + return tmp & 0x07ff; + return -EINVAL; } static int fsl_qe_start(struct usb_gadget *gadget, |
