Skip to content

Commit

Permalink
[ALSA] hdspm - Support for Master mode of AES32 and recent MADI
Browse files Browse the repository at this point in the history
The current MADI driver was found not to completely work, at least on recent
MADI cards (rev 204), in particular at 96kHz. This patch solves this:
  * Add support of DDS feature
  * Channel map fixed
  * Channel/rate rules fixed
  * DMA allocation fixed (need to alloc for all channels and not only for the
    used ones)
Full support for AES32 master mode was added:
  * Add support of DDS feature
  * Channel map fixed
  * Channel/rate rules fixed

Signed-off-by: Remy Bruno <remy.bruno@trinnov.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
  • Loading branch information
Remy Bruno authored and Jaroslav Kysela committed May 11, 2007
1 parent 59ae9d0 commit ffb2c3c
Showing 1 changed file with 115 additions and 62 deletions.
177 changes: 115 additions & 62 deletions sound/pci/rme9652/hdspm.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_controlRegister 64
#define HDSPM_interruptConfirmation 96
#define HDSPM_control2Reg 256 /* not in specs ???????? */
#define HDSPM_freqReg 256 /* for AES32 */
#define HDSPM_midiDataOut0 352 /* just believe in old code */
#define HDSPM_midiDataOut1 356
#define HDSPM_eeprom_wr 384 /* for AES32 */

/* DMA enable for 64 channels, only Bit 0 is relevant */
#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */
Expand Down Expand Up @@ -389,9 +391,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
size is the same regardless of the number of channels, and
also the latency to use.
for one direction !!!
=> need to mupltiply by 2!!
*/
#define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)

/* revisions >= 230 indicate AES32 card */
Expand Down Expand Up @@ -484,28 +485,6 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = {
56, 57, 58, 59, 60, 61, 62, 63
};

static char channel_map_madi_ds[HDSPM_MAX_CHANNELS] = {
0, 2, 4, 6, 8, 10, 12, 14,
16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46,
48, 50, 52, 54, 56, 58, 60, 62,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1
};

static char channel_map_madi_qs[HDSPM_MAX_CHANNELS] = {
0, 4, 8, 12, 16, 20, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1
};


static struct pci_device_id snd_hdspm_ids[] __devinitdata = {
{
Expand Down Expand Up @@ -818,6 +797,27 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames)
return 0;
}

static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
{
u64 n;
u32 r;

if (rate >= 112000)
rate /= 4;
else if (rate >= 56000)
rate /= 2;

/* RME says n = 104857600000000, but in the windows MADI driver, I see:
// return 104857600000000 / rate; // 100 MHz
return 110100480000000 / rate; // 105 MHz
*/
//n = 104857600000000ULL; /* = 2^20 * 10^8 */
n = 110100480000000ULL; /* Value checked for AES32 and MADI */
div64_32(&n, rate, &r);
/* n should be less than 2^32 for being written to FREQ register */
snd_assert((n >> 32) == 0);
hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
}

/* dummy set rate lets see what happens */
static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
Expand Down Expand Up @@ -943,12 +943,16 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
hdspm->control_register |= rate_bits;
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);

if (rate > 96000 /* 64000*/)
hdspm->channel_map = channel_map_madi_qs;
else if (rate > 48000)
hdspm->channel_map = channel_map_madi_ds;
else
hdspm->channel_map = channel_map_madi_ss;
/* For AES32, need to set DDS value in FREQ register
For MADI, also apparently */
hdspm_set_dds_value(hdspm, rate);

if (hdspm->is_aes32 && rate != current_rate)
hdspm_write(hdspm, HDSPM_eeprom_wr, 0);

/* For AES32 and for MADI (at least rev 204), channel_map needs to
* always be channel_map_madi_ss, whatever the sample rate */
hdspm->channel_map = channel_map_madi_ss;

hdspm->system_sample_rate = rate;

Expand Down Expand Up @@ -3184,8 +3188,8 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
snd_iprintf(buffer,
"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n",
hdspm->control_register, hdspm->control2_register,
"Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n",
hdspm->control_register,
status, status2, timecode);

snd_iprintf(buffer, "--- Settings ---\n");
Expand Down Expand Up @@ -3377,13 +3381,16 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)

hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);

if (!hdspm->is_aes32) {
/* No control2 register for AES32 */
#ifdef SNDRV_BIG_ENDIAN
hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
#else
hdspm->control2_register = 0;
hdspm->control2_register = 0;
#endif

hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register);
hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register);
}
hdspm_compute_period_size(hdspm);

/* silence everything */
Expand Down Expand Up @@ -3656,11 +3663,10 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,

/* Memory allocation, takashi's method, dont know if we should spinlock */
/* malloc all buffer even if not enabled to get sure */
/* malloc only needed bytes */
/* Update for MADI rev 204: we need to allocate for all channels,
* otherwise it doesn't work at 96kHz */
err =
snd_pcm_lib_malloc_pages(substream,
HDSPM_CHANNEL_BUFFER_BYTES *
params_channels(params));
snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
if (err < 0)
return err;

Expand Down Expand Up @@ -3696,6 +3702,13 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
"playback" : "capture",
snd_pcm_sgbuf_get_addr(sgbuf, 0));
*/
/*
snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture",
params_rate(params), params_channels(params),
params_buffer_size(params));
*/
return 0;
}

Expand Down Expand Up @@ -3900,16 +3913,16 @@ static int snd_hdspm_hw_rule_channels_rate(struct snd_pcm_hw_params *params,
struct snd_interval *r =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);

if (r->min > 48000) {
if (r->min > 48000 && r->max <= 96000) {
struct snd_interval t = {
.min = 1,
.min = hdspm->ds_channels,
.max = hdspm->ds_channels,
.integer = 1,
};
return snd_interval_refine(c, &t);
} else if (r->max < 64000) {
struct snd_interval t = {
.min = 1,
.min = hdspm->ss_channels,
.max = hdspm->ss_channels,
.integer = 1,
};
Expand All @@ -3927,14 +3940,14 @@ static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
struct snd_interval *r =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);

if (c->min <= hdspm->ss_channels) {
if (c->min >= hdspm->ss_channels) {
struct snd_interval t = {
.min = 32000,
.max = 48000,
.integer = 1,
};
return snd_interval_refine(r, &t);
} else if (c->max > hdspm->ss_channels) {
} else if (c->max <= hdspm->ds_channels) {
struct snd_interval t = {
.min = 64000,
.max = 96000,
Expand All @@ -3946,13 +3959,39 @@ static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
return 0;
}

static int snd_hdspm_hw_rule_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
unsigned int list[3];
struct hdspm *hdspm = rule->private;
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (hdspm->is_aes32) {
list[0] = hdspm->qs_channels;
list[1] = hdspm->ds_channels;
list[2] = hdspm->ss_channels;
return snd_interval_list(c, 3, list, 0);
} else {
list[0] = hdspm->ds_channels;
list[1] = hdspm->ss_channels;
return snd_interval_list(c, 2, list, 0);
}
}


static unsigned int hdspm_aes32_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 };

static struct snd_pcm_hw_constraint_list hdspm_hw_constraints_aes32_sample_rates = {
.count = ARRAY_SIZE(hdspm_aes32_sample_rates),
.list = hdspm_aes32_sample_rates,
.mask = 0
};

static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
{
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;

snd_printdd("Open device substream %d\n", substream->stream);

spin_lock_irq(&hdspm->lock);

snd_pcm_set_sync(substream);
Expand All @@ -3973,14 +4012,21 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels_rate, hdspm,
SNDRV_PCM_HW_PARAM_RATE, -1);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_hdspm_hw_rule_rate_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);

if (hdspm->is_aes32) {
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates);
} else {
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels_rate, hdspm,
SNDRV_PCM_HW_PARAM_RATE, -1);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_hdspm_hw_rule_rate_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
}
return 0;
}

Expand Down Expand Up @@ -4020,14 +4066,21 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels_rate, hdspm,
SNDRV_PCM_HW_PARAM_RATE, -1);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_hdspm_hw_rule_rate_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (hdspm->is_aes32) {
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates);
} else {
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdspm_hw_rule_channels_rate, hdspm,
SNDRV_PCM_HW_PARAM_RATE, -1);

snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_hdspm_hw_rule_rate_channels, hdspm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
}
return 0;
}

Expand Down

0 comments on commit ffb2c3c

Please sign in to comment.