diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/sound/usb | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/sound/usb')
-rw-r--r-- | kernel/sound/usb/bcd2000/bcd2000.c | 2 | ||||
-rw-r--r-- | kernel/sound/usb/card.c | 110 | ||||
-rw-r--r-- | kernel/sound/usb/card.h | 1 | ||||
-rw-r--r-- | kernel/sound/usb/endpoint.c | 102 | ||||
-rw-r--r-- | kernel/sound/usb/midi.c | 58 | ||||
-rw-r--r-- | kernel/sound/usb/mixer.c | 114 | ||||
-rw-r--r-- | kernel/sound/usb/mixer.h | 2 | ||||
-rw-r--r-- | kernel/sound/usb/mixer_maps.c | 12 | ||||
-rw-r--r-- | kernel/sound/usb/mixer_quirks.c | 167 | ||||
-rw-r--r-- | kernel/sound/usb/mixer_quirks.h | 4 | ||||
-rw-r--r-- | kernel/sound/usb/pcm.c | 138 | ||||
-rw-r--r-- | kernel/sound/usb/proc.c | 4 | ||||
-rw-r--r-- | kernel/sound/usb/quirks-table.h | 34 | ||||
-rw-r--r-- | kernel/sound/usb/quirks.c | 24 | ||||
-rw-r--r-- | kernel/sound/usb/stream.c | 11 | ||||
-rw-r--r-- | kernel/sound/usb/usbaudio.h | 13 |
16 files changed, 529 insertions, 267 deletions
diff --git a/kernel/sound/usb/bcd2000/bcd2000.c b/kernel/sound/usb/bcd2000/bcd2000.c index 820d6ca8c..d060dddcc 100644 --- a/kernel/sound/usb/bcd2000/bcd2000.c +++ b/kernel/sound/usb/bcd2000/bcd2000.c @@ -70,7 +70,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static DEFINE_MUTEX(devices_mutex); -DECLARE_BITMAP(devices_used, SNDRV_CARDS); +static DECLARE_BITMAP(devices_used, SNDRV_CARDS); static struct usb_driver bcd2000_driver; #ifdef CONFIG_SND_DEBUG diff --git a/kernel/sound/usb/card.c b/kernel/sound/usb/card.c index 045059398..1f09d9591 100644 --- a/kernel/sound/usb/card.c +++ b/kernel/sound/usb/card.c @@ -365,13 +365,15 @@ static int snd_usb_audio_create(struct usb_interface *intf, } mutex_init(&chip->mutex); - init_rwsem(&chip->shutdown_rwsem); + init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; chip->dev = dev; chip->card = card; chip->setup = device_setup[idx]; chip->autoclock = autoclock; - chip->probing = 1; + atomic_set(&chip->active, 1); /* avoid autopm during probing */ + atomic_set(&chip->usage_count, 0); + atomic_set(&chip->shutdown, 0); chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); @@ -495,13 +497,13 @@ static int usb_audio_probe(struct usb_interface *intf, mutex_lock(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) { if (usb_chip[i] && usb_chip[i]->dev == dev) { - if (usb_chip[i]->shutdown) { + if (atomic_read(&usb_chip[i]->shutdown)) { dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); err = -EIO; goto __error; } chip = usb_chip[i]; - chip->probing = 1; + atomic_inc(&chip->active); /* avoid autopm */ break; } } @@ -561,8 +563,8 @@ static int usb_audio_probe(struct usb_interface *intf, usb_chip[chip->index] = chip; chip->num_interfaces++; - chip->probing = 0; usb_set_intfdata(intf, chip); + atomic_dec(&chip->active); mutex_unlock(®ister_mutex); return 0; @@ -570,7 +572,7 @@ static int usb_audio_probe(struct usb_interface *intf, if (chip) { if (!chip->num_interfaces) snd_card_free(chip->card); - chip->probing = 0; + atomic_dec(&chip->active); } mutex_unlock(®ister_mutex); return err; @@ -585,23 +587,23 @@ static void usb_audio_disconnect(struct usb_interface *intf) struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_card *card; struct list_head *p; - bool was_shutdown; if (chip == (void *)-1L) return; card = chip->card; - down_write(&chip->shutdown_rwsem); - was_shutdown = chip->shutdown; - chip->shutdown = 1; - up_write(&chip->shutdown_rwsem); mutex_lock(®ister_mutex); - if (!was_shutdown) { + if (atomic_inc_return(&chip->shutdown) == 1) { struct snd_usb_stream *as; struct snd_usb_endpoint *ep; struct usb_mixer_interface *mixer; + /* wait until all pending tasks done; + * they are protected by snd_usb_lock_shutdown() + */ + wait_event(chip->shutdown_wait, + !atomic_read(&chip->usage_count)); snd_card_disconnect(card); /* release the pcm resources */ list_for_each_entry(as, &chip->pcm_list, list) { @@ -631,28 +633,52 @@ static void usb_audio_disconnect(struct usb_interface *intf) } } -#ifdef CONFIG_PM - -int snd_usb_autoresume(struct snd_usb_audio *chip) +/* lock the shutdown (disconnect) task and autoresume */ +int snd_usb_lock_shutdown(struct snd_usb_audio *chip) { - int err = -ENODEV; + int err; - down_read(&chip->shutdown_rwsem); - if (chip->probing || chip->in_pm) - err = 0; - else if (!chip->shutdown) - err = usb_autopm_get_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); + atomic_inc(&chip->usage_count); + if (atomic_read(&chip->shutdown)) { + err = -EIO; + goto error; + } + err = snd_usb_autoresume(chip); + if (err < 0) + goto error; + return 0; + error: + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); return err; } +/* autosuspend and unlock the shutdown */ +void snd_usb_unlock_shutdown(struct snd_usb_audio *chip) +{ + snd_usb_autosuspend(chip); + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); +} + +#ifdef CONFIG_PM + +int snd_usb_autoresume(struct snd_usb_audio *chip) +{ + if (atomic_read(&chip->shutdown)) + return -EIO; + if (atomic_inc_return(&chip->active) == 1) + return usb_autopm_get_interface(chip->pm_intf); + return 0; +} + void snd_usb_autosuspend(struct snd_usb_audio *chip) { - down_read(&chip->shutdown_rwsem); - if (!chip->shutdown && !chip->probing && !chip->in_pm) + if (atomic_read(&chip->shutdown)) + return; + if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); } static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) @@ -665,30 +691,20 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) if (chip == (void *)-1L) return 0; - if (!PMSG_IS_AUTO(message)) { + chip->autosuspended = !!PMSG_IS_AUTO(message); + if (!chip->autosuspended) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); - if (!chip->num_suspended_intf++) { - list_for_each_entry(as, &chip->pcm_list, list) { - snd_pcm_suspend_all(as->pcm); - as->substream[0].need_setup_ep = - as->substream[1].need_setup_ep = true; - } - list_for_each(p, &chip->midi_list) { - snd_usbmidi_suspend(p); - } + if (!chip->num_suspended_intf++) { + list_for_each_entry(as, &chip->pcm_list, list) { + snd_pcm_suspend_all(as->pcm); + as->substream[0].need_setup_ep = + as->substream[1].need_setup_ep = true; } - } else { - /* - * otherwise we keep the rest of the system in the dark - * to keep this transparent - */ - if (!chip->num_suspended_intf++) - chip->autosuspended = 1; - } - - if (chip->num_suspended_intf == 1) + list_for_each(p, &chip->midi_list) + snd_usbmidi_suspend(p); list_for_each_entry(mixer, &chip->mixer_list, list) snd_usb_mixer_suspend(mixer); + } return 0; } @@ -705,7 +721,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) if (--chip->num_suspended_intf) return 0; - chip->in_pm = 1; + atomic_inc(&chip->active); /* avoid autopm */ /* * ALSA leaves material resumption to user space * we just notify and restart the mixers @@ -725,7 +741,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) chip->autosuspended = 0; err_out: - chip->in_pm = 0; + atomic_dec(&chip->active); /* allow autopm after this point */ return err; } diff --git a/kernel/sound/usb/card.h b/kernel/sound/usb/card.h index ef580b43f..71778ca4b 100644 --- a/kernel/sound/usb/card.h +++ b/kernel/sound/usb/card.h @@ -122,6 +122,7 @@ struct snd_usb_substream { unsigned int buffer_periods; /* current periods per buffer */ unsigned int altset_idx; /* USB data format: index of alternate setting */ unsigned int txfr_quirk:1; /* allow sub-frame alignment */ + unsigned int tx_length_quirk:1; /* add length specifier to transfers */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */ diff --git a/kernel/sound/usb/endpoint.c b/kernel/sound/usb/endpoint.c index 03b074419..7b1cb365f 100644 --- a/kernel/sound/usb/endpoint.c +++ b/kernel/sound/usb/endpoint.c @@ -183,13 +183,53 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, ep->retire_data_urb(ep->data_subs, urb); } +static void prepare_silent_urb(struct snd_usb_endpoint *ep, + struct snd_urb_ctx *ctx) +{ + struct urb *urb = ctx->urb; + unsigned int offs = 0; + unsigned int extra = 0; + __le32 packet_length; + int i; + + /* For tx_length_quirk, put packet length at start of packet */ + if (ep->chip->tx_length_quirk) + extra = sizeof(packet_length); + + for (i = 0; i < ctx->packets; ++i) { + unsigned int offset; + unsigned int length; + int counts; + + if (ctx->packet_size[i]) + counts = ctx->packet_size[i]; + else + counts = snd_usb_endpoint_next_packet_size(ep); + + length = counts * ep->stride; /* number of silent bytes */ + offset = offs * ep->stride + extra * i; + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = length + extra; + if (extra) { + packet_length = cpu_to_le32(length); + memcpy(urb->transfer_buffer + offset, + &packet_length, sizeof(packet_length)); + } + memset(urb->transfer_buffer + offset + extra, + ep->silence_value, length); + offs += counts; + } + + urb->number_of_packets = ctx->packets; + urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra; +} + /* * Prepare a PLAYBACK urb for submission to the bus. */ static void prepare_outbound_urb(struct snd_usb_endpoint *ep, struct snd_urb_ctx *ctx) { - int i; struct urb *urb = ctx->urb; unsigned char *cp = urb->transfer_buffer; @@ -201,24 +241,7 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep, ep->prepare_data_urb(ep->data_subs, urb); } else { /* no data provider, so send silence */ - unsigned int offs = 0; - for (i = 0; i < ctx->packets; ++i) { - int counts; - - if (ctx->packet_size[i]) - counts = ctx->packet_size[i]; - else - counts = snd_usb_endpoint_next_packet_size(ep); - - urb->iso_frame_desc[i].offset = offs * ep->stride; - urb->iso_frame_desc[i].length = counts * ep->stride; - offs += counts; - } - - urb->number_of_packets = ctx->packets; - urb->transfer_buffer_length = offs * ep->stride; - memset(urb->transfer_buffer, ep->silence_value, - offs * ep->stride); + prepare_silent_urb(ep, ctx); } break; @@ -355,8 +378,10 @@ static void snd_complete_urb(struct urb *urb) if (unlikely(urb->status == -ENOENT || /* unlinked */ urb->status == -ENODEV || /* device removed */ urb->status == -ECONNRESET || /* unlinked */ - urb->status == -ESHUTDOWN || /* device disabled */ - ep->chip->shutdown)) /* device disconnected */ + urb->status == -ESHUTDOWN)) /* device disabled */ + goto exit_clear; + /* device disconnected */ + if (unlikely(atomic_read(&ep->chip->shutdown))) goto exit_clear; if (usb_pipeout(ep->pipe)) { @@ -529,7 +554,7 @@ static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) { unsigned int i; - if (!force && ep->chip->shutdown) /* to be sure... */ + if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */ return -EBADFD; clear_bit(EP_FLAG_RUNNING, &ep->flags); @@ -592,6 +617,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, unsigned int max_packs_per_period, urbs_per_period, urb_packs; unsigned int max_urbs, i; int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; + int tx_length_quirk = (ep->chip->tx_length_quirk && + usb_pipeout(ep->pipe)); if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { /* @@ -608,13 +635,34 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, /* assume max. frequency is 25% higher than nominal */ ep->freqmax = ep->freqn + (ep->freqn >> 2); - maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) - >> (16 - ep->datainterval); + /* Round up freqmax to nearest integer in order to calculate maximum + * packet size, which must represent a whole number of frames. + * This is accomplished by adding 0x0.ffff before converting the + * Q16.16 format into integer. + * In order to accurately calculate the maximum packet size when + * the data interval is more than 1 (i.e. ep->datainterval > 0), + * multiply by the data interval prior to rounding. For instance, + * a freqmax of 41 kHz will result in a max packet size of 6 (5.125) + * frames with a data interval of 1, but 11 (10.25) frames with a + * data interval of 2. + * (ep->freqmax << ep->datainterval overflows at 8.192 MHz for the + * maximum datainterval value of 3, at USB full speed, higher for + * USB high speed, noting that ep->freqmax is in units of + * frames per packet in Q16.16 format.) + */ + maxsize = (((ep->freqmax << ep->datainterval) + 0xffff) >> 16) * + (frame_bits >> 3); + if (tx_length_quirk) + maxsize += sizeof(__le32); /* Space for length descriptor */ /* but wMaxPacketSize might reduce this */ if (ep->maxpacksize && ep->maxpacksize < maxsize) { /* whatever fits into a max. size packet */ - maxsize = ep->maxpacksize; - ep->freqmax = (maxsize / (frame_bits >> 3)) + unsigned int data_maxsize = maxsize = ep->maxpacksize; + + if (tx_length_quirk) + /* Need to remove the length descriptor to calc freq */ + data_maxsize -= sizeof(__le32); + ep->freqmax = (data_maxsize / (frame_bits >> 3)) << (16 - ep->datainterval); } @@ -868,7 +916,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep) int err; unsigned int i; - if (ep->chip->shutdown) + if (atomic_read(&ep->chip->shutdown)) return -EBADFD; /* already running? */ diff --git a/kernel/sound/usb/midi.c b/kernel/sound/usb/midi.c index 417ebb11c..b21b76690 100644 --- a/kernel/sound/usb/midi.c +++ b/kernel/sound/usb/midi.c @@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint { u8 running_status_length; } ports[0x10]; u8 seen_f5; + bool in_sysex; + u8 last_cin; u8 error_resubmit; int current_port; }; @@ -468,6 +470,39 @@ static void snd_usbmidi_maudio_broken_running_status_input( } /* + * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4 + * but the previously seen CIN, but still with three data bytes. + */ +static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + unsigned int i, cin, length; + + for (i = 0; i + 3 < buffer_length; i += 4) { + if (buffer[i] == 0 && i > 0) + break; + cin = buffer[i] & 0x0f; + if (ep->in_sysex && + cin == ep->last_cin && + (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0) + cin = 0x4; +#if 0 + if (buffer[i + 1] == 0x90) { + /* + * Either a corrupted running status or a real note-on + * message; impossible to detect reliably. + */ + } +#endif + length = snd_usbmidi_cin_length[cin]; + snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length); + ep->in_sysex = cin == 0x4; + if (!ep->in_sysex) + ep->last_cin = cin; + } +} + +/* * CME protocol: like the standard protocol, but SysEx commands are sent as a * single USB packet preceded by a 0x0F byte. */ @@ -660,6 +695,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = { .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { + .input = ch345_broken_sysex_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * AKAI MPD16 protocol: * @@ -1341,6 +1382,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, * Various chips declare a packet size larger than 4 bytes, but * do not actually work with larger packets: */ + case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */ case USB_ID(0x0a92, 0x1020): /* ESI M4U */ case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */ case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ @@ -1903,11 +1945,14 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi *umidi) hostif = &intf->altsetting[1]; intfd = get_iface_desc(hostif); + /* If either or both of the endpoints support interrupt transfer, + * then use the alternate setting + */ if (intfd->bNumEndpoints != 2 || - (get_endpoint(hostif, 0)->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || - (get_endpoint(hostif, 1)->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + !((get_endpoint(hostif, 0)->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT || + (get_endpoint(hostif, 1)->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) return; dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n", @@ -2375,6 +2420,10 @@ int snd_usbmidi_create(struct snd_card *card, err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; + case QUIRK_MIDI_CH345: + umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; default: dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type); @@ -2405,7 +2454,6 @@ int snd_usbmidi_create(struct snd_card *card, else err = snd_usbmidi_create_endpoints(umidi, endpoints); if (err < 0) { - snd_usbmidi_free(umidi); return err; } diff --git a/kernel/sound/usb/mixer.c b/kernel/sound/usb/mixer.c index cd8ed2e39..4f8575700 100644 --- a/kernel/sound/usb/mixer.c +++ b/kernel/sound/usb/mixer.c @@ -282,6 +282,21 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) return val; } +static int uac2_ctl_value_size(int val_type) +{ + switch (val_type) { + case USB_MIXER_S32: + case USB_MIXER_U32: + return 4; + case USB_MIXER_S16: + case USB_MIXER_U16: + return 2; + default: + return 1; + } + return 0; /* unreachable */ +} + /* * retrieve a mixer value @@ -296,14 +311,11 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int timeout = 10; int idx = 0, err; - err = snd_usb_autoresume(chip); + err = snd_usb_lock_shutdown(chip); if (err < 0) return -EIO; - down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { - if (chip->shutdown) - break; idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, @@ -319,8 +331,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, err = -EINVAL; out: - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); return err; } @@ -328,14 +339,14 @@ 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[2 + 3 * sizeof(__u16)]; /* enough space for one range */ + unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */ unsigned char *val; int idx = 0, ret, size; __u8 bRequest; if (request == UAC_GET_CUR) { bRequest = UAC2_CS_CUR; - size = sizeof(__u16); + size = uac2_ctl_value_size(cval->val_type); } else { bRequest = UAC2_CS_RANGE; size = sizeof(buf); @@ -343,21 +354,15 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, memset(buf, 0, sizeof(buf)); - ret = snd_usb_autoresume(chip) ? -EIO : 0; + ret = snd_usb_lock_shutdown(chip) ? -EIO : 0; if (ret) goto error; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - ret = -ENODEV; - } else { - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, + idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); - } - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); if (ret < 0) { error: @@ -446,7 +451,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set) { struct snd_usb_audio *chip = cval->head.mixer->chip; - unsigned char buf[2]; + unsigned char buf[4]; int idx = 0, val_len, err, timeout = 10; validx += cval->idx_off; @@ -454,8 +459,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, if (cval->head.mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; } else { /* UAC_VERSION_2 */ - /* audio class v2 controls are always 2 bytes in size */ - val_len = sizeof(__u16); + val_len = uac2_ctl_value_size(cval->val_type); /* FIXME */ if (request != UAC_SET_CUR) { @@ -469,13 +473,14 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, value_set = convert_bytes_value(cval, value_set); buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; - err = snd_usb_autoresume(chip); + buf[2] = (value_set >> 16) & 0xff; + buf[3] = (value_set >> 24) & 0xff; + + err = snd_usb_lock_shutdown(chip); if (err < 0) return -EIO; - down_read(&chip->shutdown_rwsem); + while (timeout-- > 0) { - if (chip->shutdown) - break; idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, @@ -490,8 +495,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = -EINVAL; out: - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); return err; } @@ -715,15 +719,21 @@ static int check_input_term(struct mixer_build *state, int id, term->name = d->iTerminal; } else { /* UAC_VERSION_2 */ struct uac2_input_terminal_descriptor *d = p1; - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le32_to_cpu(d->bmChannelConfig); - term->name = d->iTerminal; - /* call recursively to get the clock selectors */ + /* call recursively to verify that the + * referenced clock entity is valid */ err = check_input_term(state, d->bCSourceID, term); if (err < 0) return err; + + /* save input term properties after recursion, + * to ensure they are not overriden by the + * recursion calls */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le32_to_cpu(d->bmChannelConfig); + term->name = d->iTerminal; } return 0; case UAC_FEATURE_UNIT: { @@ -798,24 +808,25 @@ static int check_input_term(struct mixer_build *state, int id, /* feature unit control information */ struct usb_feature_control_info { const char *name; - unsigned int type; /* control type (mute, volume, etc.) */ + int type; /* data type for uac1 */ + int type_uac2; /* data type for uac2 if different from uac1, else -1 */ }; static struct usb_feature_control_info audio_feature_info[] = { - { "Mute", USB_MIXER_INV_BOOLEAN }, - { "Volume", USB_MIXER_S16 }, - { "Tone Control - Bass", USB_MIXER_S8 }, - { "Tone Control - Mid", USB_MIXER_S8 }, - { "Tone Control - Treble", USB_MIXER_S8 }, - { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ - { "Auto Gain Control", USB_MIXER_BOOLEAN }, - { "Delay Control", USB_MIXER_U16 }, - { "Bass Boost", USB_MIXER_BOOLEAN }, - { "Loudness", USB_MIXER_BOOLEAN }, + { "Mute", USB_MIXER_INV_BOOLEAN, -1 }, + { "Volume", USB_MIXER_S16, -1 }, + { "Tone Control - Bass", USB_MIXER_S8, -1 }, + { "Tone Control - Mid", USB_MIXER_S8, -1 }, + { "Tone Control - Treble", USB_MIXER_S8, -1 }, + { "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemeted yet */ + { "Auto Gain Control", USB_MIXER_BOOLEAN, -1 }, + { "Delay Control", USB_MIXER_U16, USB_MIXER_U32 }, + { "Bass Boost", USB_MIXER_BOOLEAN, -1 }, + { "Loudness", USB_MIXER_BOOLEAN, -1 }, /* UAC2 specific */ - { "Input Gain Control", USB_MIXER_U16 }, - { "Input Gain Pad Control", USB_MIXER_BOOLEAN }, - { "Phase Inverter Control", USB_MIXER_BOOLEAN }, + { "Input Gain Control", USB_MIXER_S16, -1 }, + { "Input Gain Pad Control", USB_MIXER_S16, -1 }, + { "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, }; /* private_free callback */ @@ -1215,6 +1226,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, int readonly_mask) { struct uac_feature_unit_descriptor *desc = raw_desc; + struct usb_feature_control_info *ctl_info; unsigned int len = 0; int mapped_name = 0; int nameid = uac_feature_unit_iFeature(desc); @@ -1240,7 +1252,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = control; cval->cmask = ctl_mask; - cval->val_type = audio_feature_info[control-1].type; + ctl_info = &audio_feature_info[control-1]; + if (state->mixer->protocol == UAC_VERSION_1) + cval->val_type = ctl_info->type; + else /* UAC_VERSION_2 */ + cval->val_type = ctl_info->type_uac2 >= 0 ? + ctl_info->type_uac2 : ctl_info->type; + if (ctl_mask == 0) { cval->channels = 1; /* master channel */ cval->master_readonly = readonly_mask; @@ -1336,6 +1354,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, } } + snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl); + range = (cval->max - cval->min) / cval->res; /* * Are there devices with volume range more than 255? I use a bit more diff --git a/kernel/sound/usb/mixer.h b/kernel/sound/usb/mixer.h index d3268f0ee..3417ef347 100644 --- a/kernel/sound/usb/mixer.h +++ b/kernel/sound/usb/mixer.h @@ -33,6 +33,8 @@ enum { USB_MIXER_U8, USB_MIXER_S16, USB_MIXER_U16, + USB_MIXER_S32, + USB_MIXER_U32, }; typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, diff --git a/kernel/sound/usb/mixer_maps.c b/kernel/sound/usb/mixer_maps.c index 6a803eff8..ddca65473 100644 --- a/kernel/sound/usb/mixer_maps.c +++ b/kernel/sound/usb/mixer_maps.c @@ -348,13 +348,6 @@ static struct usbmix_name_map bose_companion5_map[] = { { 0 } /* terminator */ }; -/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */ -static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000}; -static struct usbmix_name_map dragonfly_1_2_map[] = { - { 7, NULL, .dB = &dragonfly_1_2_dB }, - { 0 } /* terminator */ -}; - /* * Control map entries */ @@ -470,11 +463,6 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x05a7, 0x1020), .map = bose_companion5_map, }, - { - /* Dragonfly DAC 1.2 */ - .id = USB_ID(0x21b4, 0x0081), - .map = dragonfly_1_2_map, - }, { 0 } /* terminator */ }; diff --git a/kernel/sound/usb/mixer_quirks.c b/kernel/sound/usb/mixer_quirks.c index 337c317ea..279025650 100644 --- a/kernel/sound/usb/mixer_quirks.c +++ b/kernel/sound/usb/mixer_quirks.c @@ -37,6 +37,7 @@ #include <sound/control.h> #include <sound/hwdep.h> #include <sound/info.h> +#include <sound/tlv.h> #include "usbaudio.h" #include "mixer.h" @@ -308,11 +309,10 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, struct snd_usb_audio *chip = mixer->chip; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto out; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + if (chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 0x24, @@ -329,8 +329,7 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); - out: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -340,7 +339,7 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); struct usb_mixer_interface *mixer = list->mixer; int index = kcontrol->private_value & 0xff; - int value = ucontrol->value.integer.value[0]; + unsigned int value = ucontrol->value.integer.value[0]; int old_value = kcontrol->private_value >> 8; int err; @@ -441,16 +440,15 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - err = 0; - else - err = snd_usb_ctl_msg(mixer->chip->dev, + err = snd_usb_lock_shutdown(mixer->chip); + if (err < 0) + return; + err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3); - up_read(&mixer->chip->shutdown_rwsem); + snd_usb_unlock_shutdown(mixer->chip); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -481,11 +479,9 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, int err; unsigned char buf[2]; - down_read(&chip->shutdown_rwsem); - if (mixer->chip->shutdown) { - err = -ENODEV; - goto out; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; buf[0] = 0x01; buf[1] = value ? 0x02 : 0x01; @@ -493,8 +489,7 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 0x0400, 0x0e00, buf, 2); - out: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -554,15 +549,14 @@ static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, struct snd_usb_audio *chip = mixer->chip; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 0x08, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 50, 0, &status, 1); - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -623,11 +617,9 @@ static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) int err; unsigned char buff[3]; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto err; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; /* Prepare for magic command to toggle clock source */ err = snd_usb_ctl_msg(chip->dev, @@ -683,7 +675,7 @@ static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) goto err; err: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -778,15 +770,14 @@ static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) unsigned int pval = list->kctl->private_value; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), - (pval >> 16) & 0xff, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - pval >> 24, pval & 0xffff, NULL, 0, 1000); - up_read(&chip->shutdown_rwsem); + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + (pval >> 16) & 0xff, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + pval >> 24, pval & 0xffff, NULL, 0, 1000); + snd_usb_unlock_shutdown(chip); return err; } @@ -802,7 +793,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, return 0; kcontrol->private_value &= ~(0xff << 24); - kcontrol->private_value |= newval; + kcontrol->private_value |= (unsigned int)newval << 24; err = snd_ni_update_cur_val(list); return err < 0 ? err : 1; } @@ -944,18 +935,17 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) value[0] = pval >> 24; value[1] = 0; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - pval & 0xff00, - snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), - value, 2); - up_read(&chip->shutdown_rwsem); + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, + snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), + value, 2); + snd_usb_unlock_shutdown(chip); return err; } @@ -1519,11 +1509,9 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, unsigned char data[3]; int rate; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; @@ -1551,7 +1539,7 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, err = 0; end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -1562,11 +1550,9 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) u8 reg; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); err = snd_usb_ctl_msg(chip->dev, @@ -1594,7 +1580,7 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) goto end; end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -1650,11 +1636,9 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) u8 reg = list->kctl->private_value; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), @@ -1665,8 +1649,7 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) NULL, 0); - end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -1843,3 +1826,39 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, } } +static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl) +{ + /* Approximation using 10 ranges based on output measurement on hw v1.2. + * This seems close to the cubic mapping e.g. alsamixer uses. */ + static const DECLARE_TLV_DB_RANGE(scale, + 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970), + 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160), + 6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710), + 8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560), + 15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324), + 17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031), + 20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393), + 27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032), + 32, 40, TLV_DB_MINMAX_ITEM(-968, -490), + 41, 50, TLV_DB_MINMAX_ITEM(-441, 0), + ); + + usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n"); + kctl->tlv.p = scale; + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; +} + +void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, + struct usb_mixer_elem_info *cval, int unitid, + struct snd_kcontrol *kctl) +{ + switch (mixer->chip->usb_id) { + case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ + if (unitid == 7 && cval->min == 0 && cval->max == 50) + snd_dragonfly_quirk_db_scale(mixer, kctl); + break; + } +} + diff --git a/kernel/sound/usb/mixer_quirks.h b/kernel/sound/usb/mixer_quirks.h index bdbfab093..177c329cd 100644 --- a/kernel/sound/usb/mixer_quirks.h +++ b/kernel/sound/usb/mixer_quirks.h @@ -9,5 +9,9 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, int unitid); +void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, + struct usb_mixer_elem_info *cval, int unitid, + struct snd_kcontrol *kctl); + #endif /* SND_USB_MIXER_QUIRKS_H */ diff --git a/kernel/sound/usb/pcm.c b/kernel/sound/usb/pcm.c index b4ef410e5..9245f52d4 100644 --- a/kernel/sound/usb/pcm.c +++ b/kernel/sound/usb/pcm.c @@ -80,7 +80,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; - if (subs->stream->chip->shutdown) + if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; @@ -391,6 +391,20 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, */ attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; + if ((is_playback && (attr != USB_ENDPOINT_SYNC_ASYNC)) || + (!is_playback && (attr != USB_ENDPOINT_SYNC_ADAPTIVE))) { + + /* + * In these modes the notion of sync_endpoint is irrelevant. + * Reset pointers to avoid using stale data from previously + * used settings, e.g. when configuration and endpoints were + * changed + */ + + subs->sync_endpoint = NULL; + subs->data_endpoint->sync_master = NULL; + } + err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); if (err < 0) return err; @@ -398,10 +412,17 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, if (altsd->bNumEndpoints < 2) return 0; - if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) || + if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC || + attr == USB_ENDPOINT_SYNC_ADAPTIVE)) || (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) return 0; + /* + * In case of illegal SYNC_NONE for OUT endpoint, we keep going to see + * if we don't find a sync endpoint, as on M-Audio Transit. In case of + * error fall back to SYNC mode and don't create sync endpoint + */ + /* check sync-pipe endpoint */ /* ... and check descriptor size before accessing bSynchAddress because there is a version of the SB Audigy 2 NX firmware lacking @@ -415,6 +436,8 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, get_endpoint(alts, 1)->bmAttributes, get_endpoint(alts, 1)->bLength, get_endpoint(alts, 1)->bSynchAddress); + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; } ep = get_endpoint(alts, 1)->bEndpointAddress; @@ -425,6 +448,8 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, "%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", fmt->iface, fmt->altsetting, is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; } @@ -436,8 +461,11 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, implicit_fb ? SND_USB_ENDPOINT_TYPE_DATA : SND_USB_ENDPOINT_TYPE_SYNC); - if (!subs->sync_endpoint) + if (!subs->sync_endpoint) { + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; + } subs->data_endpoint->sync_master = subs->sync_endpoint; @@ -707,12 +735,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - down_read(&subs->stream->chip->shutdown_rwsem); - if (subs->stream->chip->shutdown) - ret = -ENODEV; - else - ret = set_format(subs, fmt); - up_read(&subs->stream->chip->shutdown_rwsem); + ret = snd_usb_lock_shutdown(subs->stream->chip); + if (ret < 0) + return ret; + ret = set_format(subs, fmt); + snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) return ret; @@ -735,13 +762,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; - down_read(&subs->stream->chip->shutdown_rwsem); - if (!subs->stream->chip->shutdown) { + if (!snd_usb_lock_shutdown(subs->stream->chip)) { stop_endpoints(subs, true); snd_usb_endpoint_deactivate(subs->sync_endpoint); snd_usb_endpoint_deactivate(subs->data_endpoint); + snd_usb_unlock_shutdown(subs->stream->chip); } - up_read(&subs->stream->chip->shutdown_rwsem); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -763,11 +789,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - down_read(&subs->stream->chip->shutdown_rwsem); - if (subs->stream->chip->shutdown) { - ret = -ENODEV; - goto unlock; - } + ret = snd_usb_lock_shutdown(subs->stream->chip); + if (ret < 0) + return ret; if (snd_BUG_ON(!subs->data_endpoint)) { ret = -EIO; goto unlock; @@ -816,7 +840,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) ret = start_endpoints(subs, true); unlock: - up_read(&subs->stream->chip->shutdown_rwsem); + snd_usb_unlock_shutdown(subs->stream->chip); return ret; } @@ -1218,9 +1242,11 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) stop_endpoints(subs, true); - if (!as->chip->shutdown && subs->interface >= 0) { + if (subs->interface >= 0 && + !snd_usb_lock_shutdown(subs->stream->chip)) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; + snd_usb_unlock_shutdown(subs->stream->chip); } subs->pcm_substream = NULL; @@ -1357,6 +1383,56 @@ static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, subs->hwptr_done++; } } + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; +} + +static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb, + int offset, int stride, unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; + + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { + /* err, the transferred area goes over buffer boundary. */ + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; + memcpy(urb->transfer_buffer + offset, + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + offset + bytes1, + runtime->dma_area, bytes - bytes1); + } else { + memcpy(urb->transfer_buffer + offset, + runtime->dma_area + subs->hwptr_done, bytes); + } + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; +} + +static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs, + struct urb *urb, int stride, + unsigned int bytes) +{ + __le32 packet_length; + int i; + + /* Put __le32 length descriptor at start of each packet. */ + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int length = urb->iso_frame_desc[i].length; + unsigned int offset = urb->iso_frame_desc[i].offset; + + packet_length = cpu_to_le32(length); + offset += i * sizeof(packet_length); + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length += sizeof(packet_length); + memcpy(urb->transfer_buffer + offset, + &packet_length, sizeof(packet_length)); + copy_to_urb(subs, urb, offset + sizeof(packet_length), + stride, length); + } + /* Adjust transfer size accordingly. */ + bytes += urb->number_of_packets * sizeof(packet_length); + return bytes; } static void prepare_playback_urb(struct snd_usb_substream *subs, @@ -1434,27 +1510,17 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, } subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; } else { /* usual PCM */ - if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { - /* err, the transferred area goes over buffer boundary. */ - unsigned int bytes1 = - runtime->buffer_size * stride - subs->hwptr_done; - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes1); - memcpy(urb->transfer_buffer + bytes1, - runtime->dma_area, bytes - bytes1); - } else { - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes); - } - - subs->hwptr_done += bytes; + if (!subs->tx_length_quirk) + copy_to_urb(subs, urb, 0, stride, bytes); + else + bytes = copy_to_urb_quirk(subs, urb, stride, bytes); + /* bytes is now amount of outgoing data */ } - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; - /* update delay with exact number of samples queued */ runtime->delay = subs->last_delay; runtime->delay += frames; diff --git a/kernel/sound/usb/proc.c b/kernel/sound/usb/proc.c index 5f761ab34..0ac89e294 100644 --- a/kernel/sound/usb/proc.c +++ b/kernel/sound/usb/proc.c @@ -46,14 +46,14 @@ static inline unsigned get_high_speed_hz(unsigned int usb_rate) static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (!chip->shutdown) + if (!atomic_read(&chip->shutdown)) snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); } static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (!chip->shutdown) + if (!atomic_read(&chip->shutdown)) snd_iprintf(buffer, "%04x:%04x\n", USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); diff --git a/kernel/sound/usb/quirks-table.h b/kernel/sound/usb/quirks-table.h index e4756651a..c60a776e8 100644 --- a/kernel/sound/usb/quirks-table.h +++ b/kernel/sound/usb/quirks-table.h @@ -2664,6 +2664,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + USB_DEVICE(0x1235, 0x000a), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Novation", */ + /* .product_name = "Nocturn", */ + .ifnum = 0, + .type = QUIRK_MIDI_RAW_BYTES + } +}, +{ USB_DEVICE(0x1235, 0x000e), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "Novation", */ @@ -2820,6 +2829,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), .idProduct = 0x1020, }, +/* QinHeng devices */ +{ + USB_DEVICE(0x1a86, 0x752d), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "QinHeng", + .product_name = "CH345", + .ifnum = 1, + .type = QUIRK_MIDI_CH345 + } +}, + /* KeithMcMillen Stringport */ { USB_DEVICE(0x1f38, 0x0001), @@ -3182,10 +3202,9 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), { /* * ZOOM R16/24 in audio interface mode. - * Mixer descriptors are garbage, further quirks will be needed - * to make any of it functional, thus disabled for now. - * Playback stream appears to start and run fine but no sound - * is produced, so also disabled for now. + * Playback requires an extra four byte LE length indicator + * at the start of each isochronous packet. This quirk is + * enabled in create_standard_audio_quirk(). */ USB_DEVICE(0x1686, 0x00dd), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -3193,14 +3212,9 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .type = QUIRK_COMPOSITE, .data = (const struct snd_usb_audio_quirk[]) { { - /* Mixer */ - .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE, - }, - { /* Playback */ .ifnum = 1, - .type = QUIRK_IGNORE_INTERFACE, + .type = QUIRK_AUDIO_STANDARD_INTERFACE, }, { /* Capture */ diff --git a/kernel/sound/usb/quirks.c b/kernel/sound/usb/quirks.c index 00ebc0ca0..c458d60d5 100644 --- a/kernel/sound/usb/quirks.c +++ b/kernel/sound/usb/quirks.c @@ -115,6 +115,9 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip, struct usb_interface_descriptor *altsd; int err; + if (chip->usb_id == USB_ID(0x1686, 0x00dd)) /* Zoom R16/24 */ + chip->tx_length_quirk = 1; + alts = &iface->altsetting[0]; altsd = get_iface_desc(alts); err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber); @@ -535,6 +538,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk, [QUIRK_MIDI_FTDI] = create_any_midi_quirk, + [QUIRK_MIDI_CH345] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, @@ -1117,10 +1121,13 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) switch (chip->usb_id) { case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ + case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ + case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ + case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ return true; } return false; @@ -1200,8 +1207,12 @@ void snd_usb_set_interface_quirk(struct usb_device *dev) * "Playback Design" products need a 50ms delay after setting the * USB interface. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) + switch (le16_to_cpu(dev->descriptor.idVendor)) { + case 0x23ba: /* Playback Design */ + case 0x0644: /* TEAC Corp. */ mdelay(50); + break; + } } void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, @@ -1216,6 +1227,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); + /* + * "TEAC Corp." products need a 20ms delay after each + * class compliant request + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); + /* Marantz/Denon devices with USB DAC functionality need a delay * after each class compliant request */ @@ -1264,6 +1283,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ + case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; @@ -1271,6 +1291,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */ case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ + case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ + case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; diff --git a/kernel/sound/usb/stream.c b/kernel/sound/usb/stream.c index 310a3822d..8ee14f236 100644 --- a/kernel/sound/usb/stream.c +++ b/kernel/sound/usb/stream.c @@ -92,6 +92,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->direction = stream; subs->dev = as->chip->dev; subs->txfr_quirk = as->chip->txfr_quirk; + subs->tx_length_quirk = as->chip->tx_length_quirk; subs->speed = snd_usb_get_speed(subs->dev); subs->pkt_offset_adj = 0; @@ -377,7 +378,15 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, snd_usb_init_substream(as, stream, fp); - list_add(&as->list, &chip->pcm_list); + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a + * fix to swap capture stream order in conf/cards/USB-audio.conf + */ + if (chip->usb_id == USB_ID(0x0763, 0x2003)) + list_add(&as->list, &chip->pcm_list); + else + list_add_tail(&as->list, &chip->pcm_list); + chip->pcm_devs++; snd_usb_proc_pcm_format_add(as); diff --git a/kernel/sound/usb/usbaudio.h b/kernel/sound/usb/usbaudio.h index 91d038043..b665d8555 100644 --- a/kernel/sound/usb/usbaudio.h +++ b/kernel/sound/usb/usbaudio.h @@ -37,12 +37,13 @@ struct snd_usb_audio { struct usb_interface *pm_intf; u32 usb_id; struct mutex mutex; - struct rw_semaphore shutdown_rwsem; - unsigned int shutdown:1; - unsigned int probing:1; - unsigned int in_pm:1; unsigned int autosuspended:1; + atomic_t active; + atomic_t shutdown; + atomic_t usage_count; + wait_queue_head_t shutdown_wait; unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ + unsigned int tx_length_quirk:1; /* Put length specifier in transfers */ int num_interfaces; int num_suspended_intf; @@ -94,6 +95,7 @@ enum quirk_type { QUIRK_MIDI_AKAI, QUIRK_MIDI_US122L, QUIRK_MIDI_FTDI, + QUIRK_MIDI_CH345, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX, @@ -115,4 +117,7 @@ struct snd_usb_audio_quirk { #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) +int snd_usb_lock_shutdown(struct snd_usb_audio *chip); +void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); + #endif /* __USBAUDIO_H */ |