diff options
author | Daniel Mack <zonque@gmail.com> | 2013-04-17 00:01:39 +0800 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-04-18 10:03:47 +0200 |
commit | 44dcbbb1cd615634c09d1bf31c124332795903a8 (patch) | |
tree | ef2b5642e14bcbb8fe082e1e60c83975556ac1aa /sound/usb | |
parent | d24f5061ee7b9b58a7e97f3c2a72f0a9b115e7e0 (diff) |
ALSA: snd-usb: add support for bit-reversed byte formats
There is quite some confusion around the bit-ordering in DSD samples,
and no general agreement that defines whether hardware is supposed to
expect the oldest sample in the MSB or the LSB of a byte.
ALSA will hence set the rule that on the software API layer, bytes
always carry the oldest bit in the most significant bit of a byte, and
the driver has to translate that at runtime in order to match the
hardware layout.
This patch adds support for this by adding a boolean flag to the
audio format struct.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.h | 1 | ||||
-rw-r--r-- | sound/usb/pcm.c | 19 |
2 files changed, 19 insertions, 1 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h index ac55477ce6dd..bf2889a2cae5 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -29,6 +29,7 @@ struct audioformat { unsigned char clock; /* associated clock */ struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */ bool dsd_dop; /* add DOP headers in case of DSD samples */ + bool dsd_bitrev; /* reverse the bits of each DSD sample */ }; struct snd_usb_substream; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4cd917cf058e..9723f3ceb155 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/slab.h> +#include <linux/bitrev.h> #include <linux/ratelimit.h> #include <linux/usb.h> #include <linux/usb/audio.h> @@ -1264,7 +1265,12 @@ static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, } else { /* stuff the DSD payload */ int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap; - dst[dst_idx++] = src[idx]; + + if (subs->cur_audiofmt->dsd_bitrev) + dst[dst_idx++] = bitrev8(src[idx]); + else + dst[dst_idx++] = src[idx]; + subs->hwptr_done++; } } @@ -1330,6 +1336,17 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && subs->cur_audiofmt->dsd_dop)) { fill_playback_urb_dsd_dop(subs, urb, bytes); + } else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 && + subs->cur_audiofmt->dsd_bitrev)) { + /* bit-reverse the bytes */ + u8 *buf = urb->transfer_buffer; + for (i = 0; i < bytes; i++) { + int idx = (subs->hwptr_done + i) + % (runtime->buffer_size * stride); + buf[i] = bitrev8(runtime->dma_area[idx]); + } + + subs->hwptr_done += bytes; } else { /* usual PCM */ if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { |