Loading drivers/usb/host/xhci-mem.c +28 −2 Original line number Diff line number Diff line Loading @@ -1789,6 +1789,8 @@ void xhci_free_command(struct xhci_hcd *xhci, int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) { int size; u32 iman_reg; u64 erdp_reg; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; Loading @@ -1800,14 +1802,38 @@ int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) if (xhci->sec_erst[intr_num].entries) { /* * disable irq, ack pending interrupt and clear EHB for xHC to * generate interrupt again when new event ring is setup */ iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); iman_reg &= ~IMAN_IE; writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); if (iman_reg & IMAN_IP) writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); /* make sure IP gets cleared before clearing EHB */ mb(); erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); xhci_write_64(xhci, erdp_reg | ERST_EHB, &xhci->sec_ir_set[intr_num]->erst_dequeue); dma_free_coherent(dev, size, xhci->sec_erst[intr_num].entries, xhci->sec_erst[intr_num].erst_dma_addr); xhci->sec_erst[intr_num].entries = NULL; } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed SEC ERST#%d", intr_num); if (xhci->sec_event_ring[intr_num]) xhci_ring_free(xhci, xhci->sec_event_ring[intr_num]); xhci->sec_event_ring[intr_num] = NULL; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed sec event ring"); Loading sound/usb/usb_audio_qmi_svc.c +124 −87 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ struct intf_info { size_t xfer_buf_size; phys_addr_t xfer_buf_pa; u8 *xfer_buf; u8 pcm_card_num; u8 pcm_dev_num; u8 direction; bool in_use; }; Loading Loading @@ -115,6 +118,7 @@ struct uaudio_qmi_svc { struct qmi_handle *uaudio_svc_hdl; void *curr_conn; struct work_struct recv_msg_work; struct work_struct qmi_disconnect_work; struct workqueue_struct *uaudio_wq; ktime_t t_request_recvd; ktime_t t_resp_sent; Loading Loading @@ -385,7 +389,7 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, static int prepare_qmi_response(struct snd_usb_substream *subs, struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len, int card_num) int card_num, int pcm_dev_num) { int ret = -ENODEV; struct usb_interface *iface; Loading @@ -411,6 +415,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, goto err; } if (uadev[card_num].info && uadev[card_num].info[subs->interface].in_use) { pr_err("%s interface# %d already in use card# %d\n", __func__, subs->interface, card_num); ret = -EBUSY; goto err; } alts = &iface->altsetting[subs->altset_idx]; altsd = get_iface_desc(alts); protocol = altsd->bInterfaceProtocol; Loading Loading @@ -627,12 +639,6 @@ skip_sync: kref_get(&uadev[card_num].kref); } if (uadev[card_num].info[subs->interface].in_use) { pr_err("%s interface# %d already in use card# %d\n", __func__, subs->interface, card_num); goto unmap_xfer_buf; } uadev[card_num].card_num = card_num; /* cache intf specific info to use it for unmap and free xfer buf */ Loading @@ -644,6 +650,9 @@ skip_sync: uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa; uadev[card_num].info[subs->interface].xfer_buf_size = len; uadev[card_num].info[subs->interface].xfer_buf = xfer_buf; uadev[card_num].info[subs->interface].pcm_card_num = card_num; uadev[card_num].info[subs->interface].pcm_dev_num = pcm_dev_num; uadev[card_num].info[subs->interface].direction = subs->direction; uadev[card_num].info[subs->interface].in_use = true; set_bit(card_num, &uaudio_qdev->card_slot); Loading @@ -665,9 +674,71 @@ err: return ret; } void uaudio_disconnect_cb(struct snd_usb_audio *chip) static void uaudio_dev_intf_cleanup(struct usb_device *udev, struct intf_info *info) { uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; info->data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va, info->sync_xfer_ring_size); info->sync_xfer_ring_va = 0; info->sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va, info->xfer_buf_size); info->xfer_buf_va = 0; usb_free_coherent(udev, info->xfer_buf_size, info->xfer_buf, info->xfer_buf_pa); info->xfer_buf_size = 0; info->xfer_buf = NULL; info->xfer_buf_pa = 0; info->in_use = false; } static void uaudio_dev_cleanup(struct uaudio_dev *dev) { int if_idx; /* free xfer buffer and unmap xfer ring and buf per interface */ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { if (!dev->info[if_idx].in_use) continue; uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]); pr_debug("%s: release resources: intf# %d card# %d\n", __func__, if_idx, dev->card_num); } /* iommu_unmap dcba iova for a usb device */ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); dev->dcba_iova = 0; dev->dcba_size = 0; dev->num_intf = 0; /* free interface info */ kfree(dev->info); dev->info = NULL; clear_bit(dev->card_num, &uaudio_qdev->card_slot); /* all audio devices are disconnected */ if (!uaudio_qdev->card_slot) { uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); pr_debug("%s: all audio devices disconnected\n", __func__); } dev->udev = NULL; } static void uaudio_disconnect_cb(struct snd_usb_audio *chip) { int ret, if_idx; int ret; struct uaudio_dev *dev; int card_num = chip->card_num; struct uaudio_qmi_svc *svc = uaudio_svc; Loading Loading @@ -713,57 +784,7 @@ void uaudio_disconnect_cb(struct snd_usb_audio *chip) mutex_lock(&chip->dev_lock); } /* free xfer buffer and unmap xfer ring and buf per interface */ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { if (!dev->info[if_idx].in_use) continue; usb_free_coherent(dev->udev, dev->info[if_idx].xfer_buf_size, dev->info[if_idx].xfer_buf, dev->info[if_idx].xfer_buf_pa); uaudio_iommu_unmap(MEM_XFER_RING, dev->info[if_idx].data_xfer_ring_va, dev->info[if_idx].data_xfer_ring_size); dev->info[if_idx].data_xfer_ring_va = 0; dev->info[if_idx].data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, dev->info[if_idx].sync_xfer_ring_va, dev->info[if_idx].sync_xfer_ring_size); dev->info[if_idx].sync_xfer_ring_va = 0; dev->info[if_idx].sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, dev->info[if_idx].xfer_buf_va, dev->info[if_idx].xfer_buf_size); dev->info[if_idx].xfer_buf_va = 0; dev->info[if_idx].xfer_buf_size = 0; pr_debug("%s: release resources: intf# %d card# %d\n", __func__, if_idx, card_num); } /* iommu_unmap dcba iova for a usb device */ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); dev->dcba_iova = 0; dev->dcba_size = 0; dev->num_intf = 0; /* free interface info */ kfree(dev->info); dev->info = NULL; clear_bit(card_num, &uaudio_qdev->card_slot); /* all audio devices are disconnected */ if (!uaudio_qdev->card_slot) { uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); pr_debug("%s: all audio devices disconnected\n", __func__); } dev->udev = NULL; uaudio_dev_cleanup(dev); done: mutex_unlock(&chip->dev_lock); } Loading @@ -789,7 +810,7 @@ static void uaudio_dev_release(struct kref *kref) } /* maps audio format received over QMI to asound.h based pcm format */ int map_pcm_format(unsigned int fmt_received) static int map_pcm_format(unsigned int fmt_received) { switch (fmt_received) { case USB_QMI_PCM_FORMAT_S8: Loading Loading @@ -903,7 +924,7 @@ static int handle_uaudio_stream_req(void *req_h, void *req) if (!ret && req_msg->enable) ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size, pcm_card_num); pcm_card_num, pcm_dev_num); mutex_unlock(&chip->dev_lock); Loading @@ -912,31 +933,7 @@ response: if (intf_num >= 0) { mutex_lock(&chip->dev_lock); info = &uadev[pcm_card_num].info[intf_num]; uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; info->data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va, info->sync_xfer_ring_size); info->sync_xfer_ring_va = 0; info->sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va, info->xfer_buf_size); info->xfer_buf_va = 0; usb_free_coherent(uadev[pcm_card_num].udev, info->xfer_buf_size, info->xfer_buf, info->xfer_buf_pa); info->xfer_buf_size = 0; info->xfer_buf = NULL; info->xfer_buf_pa = 0; info->in_use = false; uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info); pr_debug("%s:release resources: intf# %d card# %d\n", __func__, intf_num, pcm_card_num); mutex_unlock(&chip->dev_lock); Loading Loading @@ -980,6 +977,43 @@ static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle, return 0; } static void uaudio_qmi_disconnect_work(struct work_struct *w) { struct intf_info *info; int idx, if_idx; struct snd_usb_substream *subs; struct snd_usb_audio *chip = NULL; /* find all active intf for set alt 0 and cleanup usb audio dev */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!atomic_read(&uadev[idx].in_use)) continue; for (if_idx = 0; if_idx < uadev[idx].num_intf; if_idx++) { if (!uadev[idx].info || !uadev[idx].info[if_idx].in_use) continue; info = &uadev[idx].info[if_idx]; subs = find_snd_usb_substream(info->pcm_card_num, info->pcm_dev_num, info->direction, &chip, uaudio_disconnect_cb); if (!subs || !chip || atomic_read(&chip->shutdown)) { pr_debug("%s:no subs for c#%u, dev#%u dir%u\n", __func__, info->pcm_card_num, info->pcm_dev_num, info->direction); continue; } snd_usb_enable_audio_stream(subs, 0); } atomic_set(&uadev[idx].in_use, 0); mutex_lock(&chip->dev_lock); uaudio_dev_cleanup(&uadev[idx]); mutex_unlock(&chip->dev_lock); } } static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, void *conn_h) { Loading @@ -991,6 +1025,8 @@ static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, } svc->curr_conn = NULL; queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work); return 0; } Loading Loading @@ -1195,6 +1231,7 @@ static int uaudio_qmi_svc_init(void) } INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg); INIT_WORK(&svc->qmi_disconnect_work, uaudio_qmi_disconnect_work); uaudio_svc = svc; Loading Loading
drivers/usb/host/xhci-mem.c +28 −2 Original line number Diff line number Diff line Loading @@ -1789,6 +1789,8 @@ void xhci_free_command(struct xhci_hcd *xhci, int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) { int size; u32 iman_reg; u64 erdp_reg; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; Loading @@ -1800,14 +1802,38 @@ int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) if (xhci->sec_erst[intr_num].entries) { /* * disable irq, ack pending interrupt and clear EHB for xHC to * generate interrupt again when new event ring is setup */ iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); iman_reg &= ~IMAN_IE; writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); if (iman_reg & IMAN_IP) writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); /* make sure IP gets cleared before clearing EHB */ mb(); erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); xhci_write_64(xhci, erdp_reg | ERST_EHB, &xhci->sec_ir_set[intr_num]->erst_dequeue); dma_free_coherent(dev, size, xhci->sec_erst[intr_num].entries, xhci->sec_erst[intr_num].erst_dma_addr); xhci->sec_erst[intr_num].entries = NULL; } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed SEC ERST#%d", intr_num); if (xhci->sec_event_ring[intr_num]) xhci_ring_free(xhci, xhci->sec_event_ring[intr_num]); xhci->sec_event_ring[intr_num] = NULL; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed sec event ring"); Loading
sound/usb/usb_audio_qmi_svc.c +124 −87 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ struct intf_info { size_t xfer_buf_size; phys_addr_t xfer_buf_pa; u8 *xfer_buf; u8 pcm_card_num; u8 pcm_dev_num; u8 direction; bool in_use; }; Loading Loading @@ -115,6 +118,7 @@ struct uaudio_qmi_svc { struct qmi_handle *uaudio_svc_hdl; void *curr_conn; struct work_struct recv_msg_work; struct work_struct qmi_disconnect_work; struct workqueue_struct *uaudio_wq; ktime_t t_request_recvd; ktime_t t_resp_sent; Loading Loading @@ -385,7 +389,7 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, static int prepare_qmi_response(struct snd_usb_substream *subs, struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len, int card_num) int card_num, int pcm_dev_num) { int ret = -ENODEV; struct usb_interface *iface; Loading @@ -411,6 +415,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, goto err; } if (uadev[card_num].info && uadev[card_num].info[subs->interface].in_use) { pr_err("%s interface# %d already in use card# %d\n", __func__, subs->interface, card_num); ret = -EBUSY; goto err; } alts = &iface->altsetting[subs->altset_idx]; altsd = get_iface_desc(alts); protocol = altsd->bInterfaceProtocol; Loading Loading @@ -627,12 +639,6 @@ skip_sync: kref_get(&uadev[card_num].kref); } if (uadev[card_num].info[subs->interface].in_use) { pr_err("%s interface# %d already in use card# %d\n", __func__, subs->interface, card_num); goto unmap_xfer_buf; } uadev[card_num].card_num = card_num; /* cache intf specific info to use it for unmap and free xfer buf */ Loading @@ -644,6 +650,9 @@ skip_sync: uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa; uadev[card_num].info[subs->interface].xfer_buf_size = len; uadev[card_num].info[subs->interface].xfer_buf = xfer_buf; uadev[card_num].info[subs->interface].pcm_card_num = card_num; uadev[card_num].info[subs->interface].pcm_dev_num = pcm_dev_num; uadev[card_num].info[subs->interface].direction = subs->direction; uadev[card_num].info[subs->interface].in_use = true; set_bit(card_num, &uaudio_qdev->card_slot); Loading @@ -665,9 +674,71 @@ err: return ret; } void uaudio_disconnect_cb(struct snd_usb_audio *chip) static void uaudio_dev_intf_cleanup(struct usb_device *udev, struct intf_info *info) { uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; info->data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va, info->sync_xfer_ring_size); info->sync_xfer_ring_va = 0; info->sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va, info->xfer_buf_size); info->xfer_buf_va = 0; usb_free_coherent(udev, info->xfer_buf_size, info->xfer_buf, info->xfer_buf_pa); info->xfer_buf_size = 0; info->xfer_buf = NULL; info->xfer_buf_pa = 0; info->in_use = false; } static void uaudio_dev_cleanup(struct uaudio_dev *dev) { int if_idx; /* free xfer buffer and unmap xfer ring and buf per interface */ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { if (!dev->info[if_idx].in_use) continue; uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]); pr_debug("%s: release resources: intf# %d card# %d\n", __func__, if_idx, dev->card_num); } /* iommu_unmap dcba iova for a usb device */ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); dev->dcba_iova = 0; dev->dcba_size = 0; dev->num_intf = 0; /* free interface info */ kfree(dev->info); dev->info = NULL; clear_bit(dev->card_num, &uaudio_qdev->card_slot); /* all audio devices are disconnected */ if (!uaudio_qdev->card_slot) { uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); pr_debug("%s: all audio devices disconnected\n", __func__); } dev->udev = NULL; } static void uaudio_disconnect_cb(struct snd_usb_audio *chip) { int ret, if_idx; int ret; struct uaudio_dev *dev; int card_num = chip->card_num; struct uaudio_qmi_svc *svc = uaudio_svc; Loading Loading @@ -713,57 +784,7 @@ void uaudio_disconnect_cb(struct snd_usb_audio *chip) mutex_lock(&chip->dev_lock); } /* free xfer buffer and unmap xfer ring and buf per interface */ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { if (!dev->info[if_idx].in_use) continue; usb_free_coherent(dev->udev, dev->info[if_idx].xfer_buf_size, dev->info[if_idx].xfer_buf, dev->info[if_idx].xfer_buf_pa); uaudio_iommu_unmap(MEM_XFER_RING, dev->info[if_idx].data_xfer_ring_va, dev->info[if_idx].data_xfer_ring_size); dev->info[if_idx].data_xfer_ring_va = 0; dev->info[if_idx].data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, dev->info[if_idx].sync_xfer_ring_va, dev->info[if_idx].sync_xfer_ring_size); dev->info[if_idx].sync_xfer_ring_va = 0; dev->info[if_idx].sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, dev->info[if_idx].xfer_buf_va, dev->info[if_idx].xfer_buf_size); dev->info[if_idx].xfer_buf_va = 0; dev->info[if_idx].xfer_buf_size = 0; pr_debug("%s: release resources: intf# %d card# %d\n", __func__, if_idx, card_num); } /* iommu_unmap dcba iova for a usb device */ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); dev->dcba_iova = 0; dev->dcba_size = 0; dev->num_intf = 0; /* free interface info */ kfree(dev->info); dev->info = NULL; clear_bit(card_num, &uaudio_qdev->card_slot); /* all audio devices are disconnected */ if (!uaudio_qdev->card_slot) { uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); pr_debug("%s: all audio devices disconnected\n", __func__); } dev->udev = NULL; uaudio_dev_cleanup(dev); done: mutex_unlock(&chip->dev_lock); } Loading @@ -789,7 +810,7 @@ static void uaudio_dev_release(struct kref *kref) } /* maps audio format received over QMI to asound.h based pcm format */ int map_pcm_format(unsigned int fmt_received) static int map_pcm_format(unsigned int fmt_received) { switch (fmt_received) { case USB_QMI_PCM_FORMAT_S8: Loading Loading @@ -903,7 +924,7 @@ static int handle_uaudio_stream_req(void *req_h, void *req) if (!ret && req_msg->enable) ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size, pcm_card_num); pcm_card_num, pcm_dev_num); mutex_unlock(&chip->dev_lock); Loading @@ -912,31 +933,7 @@ response: if (intf_num >= 0) { mutex_lock(&chip->dev_lock); info = &uadev[pcm_card_num].info[intf_num]; uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; info->data_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va, info->sync_xfer_ring_size); info->sync_xfer_ring_va = 0; info->sync_xfer_ring_size = 0; uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va, info->xfer_buf_size); info->xfer_buf_va = 0; usb_free_coherent(uadev[pcm_card_num].udev, info->xfer_buf_size, info->xfer_buf, info->xfer_buf_pa); info->xfer_buf_size = 0; info->xfer_buf = NULL; info->xfer_buf_pa = 0; info->in_use = false; uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info); pr_debug("%s:release resources: intf# %d card# %d\n", __func__, intf_num, pcm_card_num); mutex_unlock(&chip->dev_lock); Loading Loading @@ -980,6 +977,43 @@ static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle, return 0; } static void uaudio_qmi_disconnect_work(struct work_struct *w) { struct intf_info *info; int idx, if_idx; struct snd_usb_substream *subs; struct snd_usb_audio *chip = NULL; /* find all active intf for set alt 0 and cleanup usb audio dev */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!atomic_read(&uadev[idx].in_use)) continue; for (if_idx = 0; if_idx < uadev[idx].num_intf; if_idx++) { if (!uadev[idx].info || !uadev[idx].info[if_idx].in_use) continue; info = &uadev[idx].info[if_idx]; subs = find_snd_usb_substream(info->pcm_card_num, info->pcm_dev_num, info->direction, &chip, uaudio_disconnect_cb); if (!subs || !chip || atomic_read(&chip->shutdown)) { pr_debug("%s:no subs for c#%u, dev#%u dir%u\n", __func__, info->pcm_card_num, info->pcm_dev_num, info->direction); continue; } snd_usb_enable_audio_stream(subs, 0); } atomic_set(&uadev[idx].in_use, 0); mutex_lock(&chip->dev_lock); uaudio_dev_cleanup(&uadev[idx]); mutex_unlock(&chip->dev_lock); } } static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, void *conn_h) { Loading @@ -991,6 +1025,8 @@ static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, } svc->curr_conn = NULL; queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work); return 0; } Loading Loading @@ -1195,6 +1231,7 @@ static int uaudio_qmi_svc_init(void) } INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg); INIT_WORK(&svc->qmi_disconnect_work, uaudio_qmi_disconnect_work); uaudio_svc = svc; Loading