diff options
Diffstat (limited to 'sound/usb')
| -rw-r--r-- | sound/usb/line6/midi.c | 2 | ||||
| -rw-r--r-- | sound/usb/mixer.c | 26 | ||||
| -rw-r--r-- | sound/usb/mixer_maps.c | 3 | ||||
| -rw-r--r-- | sound/usb/pcm.c | 9 | ||||
| -rw-r--r-- | sound/usb/quirks-table.h | 47 | ||||
| -rw-r--r-- | sound/usb/usb_audio_qmi_svc.c | 91 | ||||
| -rw-r--r-- | sound/usb/usb_audio_qmi_v01.c | 60 | ||||
| -rw-r--r-- | sound/usb/usb_audio_qmi_v01.h | 23 |
8 files changed, 134 insertions, 127 deletions
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index cebea9b7f769..6a9be1df7851 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -125,7 +125,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, } usb_fill_int_urb(urb, line6->usbdev, - usb_sndbulkpipe(line6->usbdev, + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), transfer_buffer, length, midi_sent, line6, line6->interval); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index deb6baf4f2ca..81e7d4717194 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -355,17 +355,20 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { struct snd_usb_audio *chip = cval->head.mixer->chip; - unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */ + /* enough space for one range */ + unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)]; unsigned char *val; - int idx = 0, ret, size; + int idx = 0, ret, val_size, size; __u8 bRequest; + val_size = uac2_ctl_value_size(cval->val_type); + if (request == UAC_GET_CUR) { bRequest = UAC2_CS_CUR; - size = uac2_ctl_value_size(cval->val_type); + size = val_size; } else { bRequest = UAC2_CS_RANGE; - size = sizeof(buf); + size = sizeof(__u16) + 3 * val_size; } memset(buf, 0, sizeof(buf)); @@ -398,16 +401,17 @@ error: val = buf + sizeof(__u16); break; case UAC_GET_MAX: - val = buf + sizeof(__u16) * 2; + val = buf + sizeof(__u16) + val_size; break; case UAC_GET_RES: - val = buf + sizeof(__u16) * 3; + val = buf + sizeof(__u16) + val_size * 2; break; default: return -EINVAL; } - *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16))); + *value_ret = convert_signed_value(cval, + snd_usb_combine_bytes(val, val_size)); return 0; } @@ -970,6 +974,14 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, } break; + case USB_ID(0x0d8c, 0x0103): + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, + "set volume quirk for CM102-A+/102S+\n"); + cval->min = -256; + } + break; + case USB_ID(0x0471, 0x0101): case USB_ID(0x0471, 0x0104): case USB_ID(0x0471, 0x0105): diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 1f8fb0d904e0..f5cf23ffb35b 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -351,8 +351,11 @@ static struct usbmix_name_map bose_companion5_map[] = { /* * Dell usb dock with ALC4020 codec had a firmware problem where it got * screwed up when zero volume is passed; just skip it as a workaround + * + * Also the extension unit gives an access error, so skip it as well. */ static const struct usbmix_name_map dell_alc4020_map[] = { + { 4, NULL }, /* extension unit */ { 16, NULL }, { 19, NULL }, { 0 } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4c929106a1bf..07d9ae103988 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -348,6 +348,15 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, alts = &iface->altsetting[1]; goto add_sync_ep; + case USB_ID(0x1397, 0x0002): + ep = 0x81; + iface = usb_ifnum_to_if(dev, 1); + + if (!iface || iface->num_altsetting == 0) + return -EINVAL; + + alts = &iface->altsetting[1]; + goto add_sync_ep; } if (attr == USB_ENDPOINT_SYNC_ASYNC && altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8a59d4782a0f..69bf5cf1e91e 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3277,4 +3277,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +{ + /* + * Bower's & Wilkins PX headphones only support the 48 kHz sample rate + * even though it advertises more. The capture interface doesn't work + * even on windows. + */ + USB_DEVICE(0x19b5, 0x0021), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + /* Capture */ + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Playback */ + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_FILL_MAX | + UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + } + } +}, + #undef USB_DEVICE_VENDOR_SPEC diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 6969b7f4d409..dc66b6016f8d 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,7 +46,8 @@ /* event ring iova base address */ #define IOVA_BASE 0x1000 -#define IOVA_XFER_RING_BASE (IOVA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1)) +#define IOVA_DCBA_BASE 0x2000 +#define IOVA_XFER_RING_BASE (IOVA_DCBA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1)) #define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32) #define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE) #define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE) @@ -81,9 +82,10 @@ struct uaudio_dev { /* audio control interface */ struct usb_host_interface *ctrl_intf; unsigned int card_num; - unsigned int usb_core_id; atomic_t in_use; struct kref kref; + unsigned long dcba_iova; + size_t dcba_size; wait_queue_head_t disconnect_wq; /* interface specific */ @@ -100,6 +102,9 @@ struct uaudio_qmi_dev { struct iommu_domain *domain; /* list to keep track of available iova */ + struct list_head dcba_list; + size_t dcba_iova_size; + unsigned long curr_dcba_iova; struct list_head xfer_ring_list; size_t xfer_ring_iova_size; unsigned long curr_xfer_ring_iova; @@ -146,6 +151,7 @@ static struct msg_desc uaudio_stream_ind_desc = { enum mem_type { MEM_EVENT_RING, + MEM_DCBA, MEM_XFER_RING, MEM_XFER_BUF, }; @@ -171,26 +177,6 @@ enum usb_qmi_audio_format { USB_QMI_PCM_FORMAT_U32_BE, }; -static enum usb_audio_device_speed_enum_v01 -get_speed_info(enum usb_device_speed udev_speed) -{ - switch (udev_speed) { - case USB_SPEED_LOW: - return USB_AUDIO_DEVICE_SPEED_LOW_V01; - case USB_SPEED_FULL: - return USB_AUDIO_DEVICE_SPEED_FULL_V01; - case USB_SPEED_HIGH: - return USB_AUDIO_DEVICE_SPEED_HIGH_V01; - case USB_SPEED_SUPER: - return USB_AUDIO_DEVICE_SPEED_SUPER_V01; - case USB_SPEED_SUPER_PLUS: - return USB_AUDIO_DEVICE_SPEED_SUPER_PLUS_V01; - default: - pr_err("%s: udev speed %d\n", __func__, udev_speed); - return USB_AUDIO_DEVICE_SPEED_INVALID_V01; - } -} - static unsigned long uaudio_get_iova(unsigned long *curr_iova, size_t *curr_iova_size, struct list_head *head, size_t size) { @@ -290,6 +276,10 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa, if (uaudio_qdev->er_phys_addr == pa) map = false; break; + case MEM_DCBA: + va = uaudio_get_iova(&uaudio_qdev->curr_dcba_iova, + &uaudio_qdev->dcba_iova_size, &uaudio_qdev->dcba_list, size); + break; case MEM_XFER_RING: va = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova, &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list, @@ -374,7 +364,10 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, else unmap = false; break; - + case MEM_DCBA: + uaudio_put_iova(va, size, &uaudio_qdev->dcba_list, + &uaudio_qdev->dcba_iova_size); + break; case MEM_XFER_RING: uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list, &uaudio_qdev->xfer_ring_iova_size); @@ -416,7 +409,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, void *hdr_ptr; u8 *xfer_buf; u32 len, mult, remainder, xfer_buf_len; - unsigned long va, tr_data_va = 0, tr_sync_va = 0, xfer_buf_va = 0; + unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0, + xfer_buf_va = 0; phys_addr_t xhci_pa, xfer_buf_pa; iface = usb_ifnum_to_if(subs->dev, subs->interface); @@ -561,13 +555,6 @@ skip_sync_ep: resp->interrupter_num = uaudio_qdev->intr_num; resp->interrupter_num_valid = 1; - ret = usb_get_controller_id(subs->dev); - if (ret < 0) - goto err; - - resp->controller_num = ret; - resp->controller_num_valid = 1; - /* map xhci data structures PA memory to iova */ /* event ring */ @@ -595,17 +582,33 @@ skip_sync_ep: resp->xhci_mem_info.evt_ring.size = PAGE_SIZE; uaudio_qdev->er_phys_addr = xhci_pa; - resp->speed_info = get_speed_info(subs->dev->speed); - if (resp->speed_info == USB_AUDIO_DEVICE_SPEED_INVALID_V01) + /* dcba */ + xhci_pa = usb_get_dcba_dma_addr(subs->dev); + if (!xhci_pa) { + pr_err("%s:failed to get dcba dma address\n", __func__); goto unmap_er; + } + + if (!uadev[card_num].dcba_iova) { /* mappped per usb device */ + va = uaudio_iommu_map(MEM_DCBA, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_er; + + uadev[card_num].dcba_iova = va; + uadev[card_num].dcba_size = PAGE_SIZE; + } - resp->speed_info_valid = 1; + dcba_va = uadev[card_num].dcba_iova; + resp->xhci_mem_info.dcba.va = PREPEND_SID_TO_IOVA(dcba_va, + uaudio_qdev->sid); + resp->xhci_mem_info.dcba.pa = xhci_pa; + resp->xhci_mem_info.dcba.size = PAGE_SIZE; /* data transfer ring */ xhci_pa = resp->xhci_mem_info.tr_data.pa; va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE); if (!va) - goto unmap_er; + goto unmap_dcba; tr_data_va = va; resp->xhci_mem_info.tr_data.va = PREPEND_SID_TO_IOVA(va, @@ -678,7 +681,6 @@ skip_sync: } uadev[card_num].card_num = card_num; - uadev[card_num].usb_core_id = resp->controller_num; /* cache intf specific info to use it for unmap and free xfer buf */ uadev[card_num].info[info_idx].data_xfer_ring_va = tr_data_va; @@ -706,6 +708,8 @@ unmap_sync: uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE); unmap_data: uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE); +unmap_dcba: + uaudio_iommu_unmap(MEM_DCBA, dcba_va, PAGE_SIZE); unmap_er: uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); err: @@ -751,6 +755,11 @@ static void uaudio_dev_cleanup(struct uaudio_dev *dev) dev->info[if_idx].intf_num, 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 */ @@ -799,8 +808,6 @@ static void uaudio_disconnect_cb(struct snd_usb_audio *chip) pr_debug("%s: sending qmi indication disconnect\n", __func__); disconnect_ind.dev_event = USB_AUDIO_DEV_DISCONNECT_V01; disconnect_ind.slot_id = dev->udev->slot_id; - disconnect_ind.controller_num = dev->usb_core_id; - disconnect_ind.controller_num_valid = 1; ret = qmi_send_ind(svc->uaudio_svc_hdl, svc->curr_conn, &uaudio_stream_ind_desc, &disconnect_ind, sizeof(disconnect_ind)); @@ -1222,7 +1229,11 @@ static int uaudio_qmi_plat_probe(struct platform_device *pdev) goto free_domain; } - /* initialize xfer ring and xfer buf iova list */ + /* initialize dcba, xfer ring and xfer buf iova list */ + INIT_LIST_HEAD(&uaudio_qdev->dcba_list); + uaudio_qdev->curr_dcba_iova = IOVA_DCBA_BASE; + uaudio_qdev->dcba_iova_size = SNDRV_CARDS * PAGE_SIZE; + INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list); uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE; uaudio_qdev->xfer_ring_iova_size = diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c index 4fa8445badde..beff1aaf4981 100644 --- a/sound/usb/usb_audio_qmi_v01.c +++ b/sound/usb/usb_audio_qmi_v01.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2017, The Linux Foundation. All rights reserved. + /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -633,46 +633,6 @@ struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = { interrupter_num), }, { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x1C, - .offset = offsetof( - struct qmi_uaudio_stream_resp_msg_v01, - speed_info_valid), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum usb_audio_device_speed_enum_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x1C, - .offset = offsetof( - struct qmi_uaudio_stream_resp_msg_v01, - speed_info), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x1D, - .offset = offsetof( - struct qmi_uaudio_stream_resp_msg_v01, - controller_num_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x1D, - .offset = offsetof( - struct qmi_uaudio_stream_resp_msg_v01, - controller_num), - }, - { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .is_array = QMI_COMMON_TLV_TYPE, @@ -866,24 +826,6 @@ struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = { interrupter_num), }, { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x19, - .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, - controller_num_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x19, - .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, - controller_num), - }, - { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .is_array = QMI_COMMON_TLV_TYPE, diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h index addc0ed3de2a..f3b6eb05d5f0 100644 --- a/sound/usb/usb_audio_qmi_v01.h +++ b/sound/usb/usb_audio_qmi_v01.h @@ -1,4 +1,4 @@ - /* Copyright (c) 2017, The Linux Foundation. All rights reserved. + /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -77,17 +77,6 @@ enum usb_audio_device_indication_enum_v01 { USB_AUDIO_DEVICE_INDICATION_ENUM_MAX_VAL_V01 = INT_MAX, }; -enum usb_audio_device_speed_enum_v01 { - USB_AUDIO_DEVICE_SPEED_ENUM_MIN_VAL_V01 = INT_MIN, - USB_AUDIO_DEVICE_SPEED_INVALID_V01 = 0, - USB_AUDIO_DEVICE_SPEED_LOW_V01 = 1, - USB_AUDIO_DEVICE_SPEED_FULL_V01 = 2, - USB_AUDIO_DEVICE_SPEED_HIGH_V01 = 3, - USB_AUDIO_DEVICE_SPEED_SUPER_V01 = 4, - USB_AUDIO_DEVICE_SPEED_SUPER_PLUS_V01 = 5, - USB_AUDIO_DEVICE_SPEED_ENUM_MAX_VAL_V01 = INT_MAX, -}; - struct qmi_uaudio_stream_req_msg_v01 { uint8_t enable; uint32_t usb_token; @@ -129,12 +118,8 @@ struct qmi_uaudio_stream_resp_msg_v01 { struct apps_mem_info_v01 xhci_mem_info; uint8_t interrupter_num_valid; uint8_t interrupter_num; - uint8_t speed_info_valid; - enum usb_audio_device_speed_enum_v01 speed_info; - uint8_t controller_num_valid; - uint8_t controller_num; }; -#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 202 +#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 191 extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[]; struct qmi_uaudio_stream_ind_msg_v01 { @@ -158,10 +143,8 @@ struct qmi_uaudio_stream_ind_msg_v01 { struct apps_mem_info_v01 xhci_mem_info; uint8_t interrupter_num_valid; uint8_t interrupter_num; - uint8_t controller_num_valid; - uint8_t controller_num; }; -#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 181 +#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 177 extern struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[]; #endif |
