Merge "sound: usb: Map interface context information to interface number"

This commit is contained in:
Linux Build Service Account 2017-01-16 23:06:08 -08:00 committed by Gerrit - the friendly Code Review server
commit b3a739e9c7

View file

@ -69,6 +69,7 @@ struct intf_info {
size_t xfer_buf_size; size_t xfer_buf_size;
phys_addr_t xfer_buf_pa; phys_addr_t xfer_buf_pa;
u8 *xfer_buf; u8 *xfer_buf;
u8 intf_num;
u8 pcm_card_num; u8 pcm_card_num;
u8 pcm_dev_num; u8 pcm_dev_num;
u8 direction; u8 direction;
@ -391,10 +392,9 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
} }
static int prepare_qmi_response(struct snd_usb_substream *subs, static int prepare_qmi_response(struct snd_usb_substream *subs,
struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len, struct qmi_uaudio_stream_req_msg_v01 *req_msg,
int card_num, int pcm_dev_num) struct qmi_uaudio_stream_resp_msg_v01 *resp, int info_idx)
{ {
int ret = -ENODEV;
struct usb_interface *iface; struct usb_interface *iface;
struct usb_host_interface *alts; struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd; struct usb_interface_descriptor *altsd;
@ -403,10 +403,11 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
struct uac_format_type_i_discrete_descriptor *fmt_v1; struct uac_format_type_i_discrete_descriptor *fmt_v1;
struct uac_format_type_i_ext_descriptor *fmt_v2; struct uac_format_type_i_ext_descriptor *fmt_v2;
struct uac1_as_header_descriptor *as; struct uac1_as_header_descriptor *as;
int protocol; int ret = -ENODEV;
int protocol, card_num, pcm_dev_num;
void *hdr_ptr; void *hdr_ptr;
u8 *xfer_buf; u8 *xfer_buf;
u32 len, mult, remainder; u32 len, mult, remainder, xfer_buf_len;
unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0, unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0,
xfer_buf_va = 0; xfer_buf_va = 0;
phys_addr_t xhci_pa, xfer_buf_pa; phys_addr_t xhci_pa, xfer_buf_pa;
@ -418,13 +419,9 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err; goto err;
} }
if (uadev[card_num].info && pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8;
uadev[card_num].info[subs->interface].in_use) { card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16;
pr_err("%s interface# %d already in use card# %d\n", __func__, xfer_buf_len = req_msg->xfer_buff_size;
subs->interface, card_num);
ret = -EBUSY;
goto err;
}
alts = &iface->altsetting[subs->altset_idx]; alts = &iface->altsetting[subs->altset_idx];
altsd = get_iface_desc(alts); altsd = get_iface_desc(alts);
@ -655,18 +652,19 @@ skip_sync:
uadev[card_num].card_num = card_num; uadev[card_num].card_num = card_num;
/* cache intf specific info to use it for unmap and free xfer buf */ /* cache intf specific info to use it for unmap and free xfer buf */
uadev[card_num].info[subs->interface].data_xfer_ring_va = tr_data_va; uadev[card_num].info[info_idx].data_xfer_ring_va = tr_data_va;
uadev[card_num].info[subs->interface].data_xfer_ring_size = PAGE_SIZE; uadev[card_num].info[info_idx].data_xfer_ring_size = PAGE_SIZE;
uadev[card_num].info[subs->interface].sync_xfer_ring_va = tr_sync_va; uadev[card_num].info[info_idx].sync_xfer_ring_va = tr_sync_va;
uadev[card_num].info[subs->interface].sync_xfer_ring_size = PAGE_SIZE; uadev[card_num].info[info_idx].sync_xfer_ring_size = PAGE_SIZE;
uadev[card_num].info[subs->interface].xfer_buf_va = xfer_buf_va; uadev[card_num].info[info_idx].xfer_buf_va = xfer_buf_va;
uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa; uadev[card_num].info[info_idx].xfer_buf_pa = xfer_buf_pa;
uadev[card_num].info[subs->interface].xfer_buf_size = len; uadev[card_num].info[info_idx].xfer_buf_size = len;
uadev[card_num].info[subs->interface].xfer_buf = xfer_buf; uadev[card_num].info[info_idx].xfer_buf = xfer_buf;
uadev[card_num].info[subs->interface].pcm_card_num = card_num; uadev[card_num].info[info_idx].pcm_card_num = card_num;
uadev[card_num].info[subs->interface].pcm_dev_num = pcm_dev_num; uadev[card_num].info[info_idx].pcm_dev_num = pcm_dev_num;
uadev[card_num].info[subs->interface].direction = subs->direction; uadev[card_num].info[info_idx].direction = subs->direction;
uadev[card_num].info[subs->interface].in_use = true; uadev[card_num].info[info_idx].intf_num = subs->interface;
uadev[card_num].info[info_idx].in_use = true;
set_bit(card_num, &uaudio_qdev->card_slot); set_bit(card_num, &uaudio_qdev->card_slot);
@ -723,7 +721,7 @@ static void uaudio_dev_cleanup(struct uaudio_dev *dev)
continue; continue;
uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]); uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]);
pr_debug("%s: release resources: intf# %d card# %d\n", __func__, pr_debug("%s: release resources: intf# %d card# %d\n", __func__,
if_idx, dev->card_num); dev->info[if_idx].intf_num, dev->card_num);
} }
/* iommu_unmap dcba iova for a usb device */ /* iommu_unmap dcba iova for a usb device */
@ -867,6 +865,28 @@ static int map_pcm_format(unsigned int fmt_received)
} }
} }
static int info_idx_from_ifnum(int card_num, int intf_num, bool enable)
{
int i;
/*
* default index 0 is used when info is allocated upon
* first enable audio stream req for a pcm device
*/
if (enable && !uadev[card_num].info)
return 0;
for (i = 0; i < uadev[card_num].num_intf; i++) {
if (enable && !uadev[card_num].info[i].in_use)
return i;
else if (!enable &&
uadev[card_num].info[i].intf_num == intf_num)
return i;
}
return -EINVAL;
}
static int handle_uaudio_stream_req(void *req_h, void *req) static int handle_uaudio_stream_req(void *req_h, void *req)
{ {
struct qmi_uaudio_stream_req_msg_v01 *req_msg; struct qmi_uaudio_stream_req_msg_v01 *req_msg;
@ -877,7 +897,7 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
struct intf_info *info; struct intf_info *info;
int pcm_format; int pcm_format;
u8 pcm_card_num, pcm_dev_num, direction; u8 pcm_card_num, pcm_dev_num, direction;
int intf_num = -1, ret = 0; int info_idx = -EINVAL, ret = 0;
req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req; req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req;
@ -921,7 +941,8 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
} }
mutex_lock(&chip->dev_lock); mutex_lock(&chip->dev_lock);
intf_num = subs->interface; info_idx = info_idx_from_ifnum(pcm_card_num, subs->interface,
req_msg->enable);
if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm
|| !subs->stream->chip) { || !subs->stream->chip) {
ret = -ENODEV; ret = -ENODEV;
@ -929,6 +950,16 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
goto response; goto response;
} }
if (req_msg->enable) {
if (info_idx < 0) {
pr_err("%s interface# %d already in use card# %d\n",
__func__, subs->interface, pcm_card_num);
ret = -EBUSY;
mutex_unlock(&chip->dev_lock);
goto response;
}
}
subs->pcm_format = pcm_format; subs->pcm_format = pcm_format;
subs->channels = req_msg->number_of_ch; subs->channels = req_msg->number_of_ch;
subs->cur_rate = req_msg->bit_rate; subs->cur_rate = req_msg->bit_rate;
@ -937,19 +968,18 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
ret = snd_usb_enable_audio_stream(subs, req_msg->enable); ret = snd_usb_enable_audio_stream(subs, req_msg->enable);
if (!ret && req_msg->enable) if (!ret && req_msg->enable)
ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size, ret = prepare_qmi_response(subs, req_msg, &resp, info_idx);
pcm_card_num, pcm_dev_num);
mutex_unlock(&chip->dev_lock); mutex_unlock(&chip->dev_lock);
response: response:
if (!req_msg->enable && ret != -EINVAL) { if (!req_msg->enable && ret != -EINVAL) {
if (intf_num >= 0) { if (info_idx >= 0) {
mutex_lock(&chip->dev_lock); mutex_lock(&chip->dev_lock);
info = &uadev[pcm_card_num].info[intf_num]; info = &uadev[pcm_card_num].info[info_idx];
uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info); uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info);
pr_debug("%s:release resources: intf# %d card# %d\n", pr_debug("%s:release resources: intf# %d card# %d\n",
__func__, intf_num, pcm_card_num); __func__, subs->interface, pcm_card_num);
mutex_unlock(&chip->dev_lock); mutex_unlock(&chip->dev_lock);
} }
if (atomic_read(&uadev[pcm_card_num].in_use)) if (atomic_read(&uadev[pcm_card_num].in_use))