diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.h | 1 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 92 | ||||
-rw-r--r-- | sound/usb/midi.c | 11 | ||||
-rw-r--r-- | sound/usb/mixer.c | 2 | ||||
-rw-r--r-- | sound/usb/mixer_maps.c | 12 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 39 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.h | 4 | ||||
-rw-r--r-- | sound/usb/pcm.c | 74 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 23 | ||||
-rw-r--r-- | sound/usb/quirks.c | 4 | ||||
-rw-r--r-- | sound/usb/stream.c | 1 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 1 |
12 files changed, 197 insertions, 67 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h index ef580b43f..71778ca4b 100644 --- a/sound/usb/card.h +++ b/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/sound/usb/endpoint.c b/sound/usb/endpoint.c index e6f71894e..7b1cb365f 100644 --- a/sound/usb/endpoint.c +++ b/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; @@ -594,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) { /* @@ -610,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); } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index bec63e0d2..5b4c58c3e 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1945,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", diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index f494dced3..4f8575700 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1354,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/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 6a803eff8..ddca65473 100644 --- a/sound/usb/mixer_maps.c +++ b/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/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index d3608c0a2..0ce888dce 100644 --- a/sound/usb/mixer_quirks.c +++ b/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" @@ -338,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; @@ -1825,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/sound/usb/mixer_quirks.h b/sound/usb/mixer_quirks.h index bdbfab093..177c329cd 100644 --- a/sound/usb/mixer_quirks.h +++ b/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/sound/usb/pcm.c b/sound/usb/pcm.c index cdac5179d..9245f52d4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1383,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, @@ -1460,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/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index ecc2a4ea0..c60a776e8 100644 --- a/sound/usb/quirks-table.h +++ b/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", */ @@ -3193,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) { @@ -3204,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/sound/usb/quirks.c b/sound/usb/quirks.c index eef9b8e4b..b6c0c8e3b 100644 --- a/sound/usb/quirks.c +++ b/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); @@ -1122,6 +1125,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ 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; diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 970086015..8ee14f236 100644 --- a/sound/usb/stream.c +++ b/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; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 4b4327b45..b665d8555 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -43,6 +43,7 @@ struct snd_usb_audio { 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; |