Hello,
Sorry for my late reply. Here is the patch, it's great if you can test it on
old MADI cards. This patch does the following:
- Support for recent MADI cards (including DDS, channel maps)
- Full (hopefully!) support for master mode for AES32 cards (including DDS)
As I already said, I'm not sure I've understood the "rules" principle, so it's
certainly better if you check what I changed...
Regards,
Remy
On Monday 05 February at 10:27, Winfried Ritsch wrote:
> Hello,
>
> Am Freitag, 2. Februar 2007 19:39 schrieb Takashi Iwai:
> > At Wed, 31 Jan 2007 13:11:48 +0100,
> >
> > Remy Bruno wrote:
> > > Hello,
> > >
> > > I have been working on the AES32 and will soon provide a patch to get it
> > > (hopefully) fully operational (hdspm code).
> > >
> > > Moreover, I also worked on the MADI card, but the original hdspm driver
> > > didn't work for me (ie the code before my modifications to support
> > > AES32). I had to deal with the following points:
> > > - it needed the DDS feature (clock divisor), as for the AES32 and
> > > hdsp9632 cards (this may be a new behavior for recent cards)
> > > - the channel map needed to always be channel_map_madi_ss (and never
> > > channel_map_madi_ds, even at 96k), as for AES32. Otherwise, the
> > > routing was not correct.
> > > - not enough DMA memory was beeing allocated (only for
> > > "params_channels(params)" channels whereas it should be allocated for
> > > all the channels, otherwise it didn't work at 96kHz) (alsa-lib was
> > > complaining, so I don't think an old MADI card would work either)
> > > - I had to play with the channel and rate rules
> > > (snd_hdspm_hw_rule_channels_rate and so on) to get it working. Not
> > > completely clear to me how it works but it didn't work as it was
> > >
> > > So here come my questions:
> > > - Was the MADI driver completely fonctionnal before now? In other
> > > words, maybe an older revision of the card was working as the code
> > > suggested (ie differently than the revision I have, which is 204), can
> > > anyone confirm this?
> >
> > The early version has surely worked, IIRC.
> > But, Winfried should know better....
> >
> Yes we are still working with MADI-Cards, on early version one version Rev 1.1
> and a newer card. The only thing is, that there are some troubles with the
> correct Statusinformation, which are not functional limiting the card.
>
> We did not test DS mode extensively, but i can think of I tested it once MADI
> to MADI and it worked.
>
> > > - As a corollary: should I keep the compatibility with the old code? IE
> > > keep using channel_map_madi_ds, etc. for revisions < 204?
> >
> > Well, the only question is whether it breaks the older models.
> >
> If you post a patch or code so I can test it on old cards, it should be OK if
> you change this.
>
> BTW:
> Also I never finished to make a memory map interface for the mixer and meters,
> since it needs 16384 Bytes Mixer and the same for meters of values to copy,
> which is more ctl-interface can transfer at one time. Should we work on that,
> or everybody uses individual access to fader and meters for the software ?
>
> mfg
> winfried
>
> --
> --
> - ao.Univ.Prof. DI Winfried Ritsch
> - ritsch@xxxxxx - http://iem.at/ritsch
> - Institut fuer Elektronische Musik und Akustik
> - University of Music and Dramatic Art Graz
> - Tel. ++43-316-389-3510 (3170) Fax ++43-316-389-3171
> - PGP-ID 69617A69 (see keyserver http://wwwkeys.eu.gpg.net/)
> --
diff -r 1ce859e9fd4a pci/rme9652/hdspm.c
--- a/pci/rme9652/hdspm.c Fri Feb 09 20:52:55 2007 +0100
+++ b/pci/rme9652/hdspm.c Mon Feb 12 13:25:26 2007 +0100
@@ -91,8 +91,10 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MAD
#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 */
@@ -389,9 +391,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MAD
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 */
@@ -818,6 +819,27 @@ static int hdspm_set_interrupt_interval(
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)
@@ -943,12 +965,17 @@ static int hdspm_set_rate(struct hdspm *
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;
@@ -3184,8 +3211,8 @@ snd_hdspm_proc_read_aes32(struct snd_inf
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");
@@ -3377,13 +3404,16 @@ static int snd_hdspm_set_defaults(struct
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 */
@@ -3658,11 +3688,10 @@ static int snd_hdspm_hw_params(struct sn
/* 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;
@@ -3698,6 +3727,13 @@ static int snd_hdspm_hw_params(struct sn
"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;
}
@@ -3904,6 +3940,61 @@ static int snd_hdspm_hw_rule_channels_ra
struct snd_interval *r =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ if (r->min > 48000 && r->max <= 96000) {
+ struct snd_interval t = {
+ .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 = hdspm->ss_channels,
+ .max = hdspm->ss_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ }
+ return 0;
+}
+
+static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule * rule)
+{
+ struct hdspm *hdspm = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ 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->ds_channels) {
+ struct snd_interval t = {
+ .min = 64000,
+ .max = 96000,
+ .integer = 1,
+ };
+
+ return snd_interval_refine(r, &t);
+ }
+ return 0;
+}
+
+static int snd_hdspm_hw_rule_channels_rate_aes32(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule * rule)
+{
+ struct hdspm *hdspm = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
if (r->min > 48000) {
struct snd_interval t = {
.min = 1,
@@ -3922,7 +4013,7 @@ static int snd_hdspm_hw_rule_channels_ra
return 0;
}
-static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
+static int snd_hdspm_hw_rule_rate_channels_aes32(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule * rule)
{
struct hdspm *hdspm = rule->private;
@@ -3931,37 +4022,71 @@ static int snd_hdspm_hw_rule_rate_channe
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->qs_channels) {
+ struct snd_interval t = {
+ .min = 128000,
+ .max = 192000,
+ .integer = 1,
+ };
+ return snd_interval_refine(r, &t);
+ } else if (c->max <= hdspm->ds_channels) {
struct snd_interval t = {
.min = 64000,
.max = 96000,
.integer = 1,
};
-
return snd_interval_refine(r, &t);
}
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);
runtime->hw = snd_hdspm_playback_subinfo;
+ runtime->dma_area = hdspm->playback_buffer;
+ runtime->dma_bytes = HDSPM_DMA_AREA_BYTES;
if (hdspm->capture_substream == NULL)
hdspm_stop_audio(hdspm);
@@ -3977,14 +4102,21 @@ static int snd_hdspm_playback_open(struc
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;
}
@@ -4011,6 +4143,8 @@ static int snd_hdspm_capture_open(struct
spin_lock_irq(&hdspm->lock);
snd_pcm_set_sync(substream);
runtime->hw = snd_hdspm_capture_subinfo;
+ runtime->dma_area = hdspm->capture_buffer;
+ runtime->dma_bytes = HDSPM_DMA_AREA_BYTES;
if (hdspm->playback_substream == NULL)
hdspm_stop_audio(hdspm);
@@ -4024,14 +4158,21 @@ static int snd_hdspm_capture_open(struct
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;
}
@@ -4184,7 +4325,8 @@ static int __devinit snd_hdspm_prealloca
pcm = hdspm->pcm;
/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */
- wanted = HDSPM_DMA_AREA_BYTES;
+ /* Two times, for both input and output */
+ wanted = 2 * HDSPM_DMA_AREA_BYTES;
if ((err =
snd_pcm_lib_preallocate_pages_for_all(pcm,
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel