From 44dcbbb1cd615634c09d1bf31c124332795903a8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 17 Apr 2013 00:01:39 +0800 Subject: 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 Signed-off-by: Takashi Iwai --- sound/usb/card.h | 1 + sound/usb/pcm.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'sound/usb') 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 #include +#include #include #include #include @@ -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) { -- cgit v1.2.2