All of lore.kernel.org
 help / color / mirror / Atom feed
From: Remy Bruno <remy.bruno@trinnov.com>
To: Winfried Ritsch <ritsch@iem.at>
Cc: Takashi Iwai <tiwai@suse.de>, alsa-devel@lists.sourceforge.net
Subject: Re: RME AES32 & MADI
Date: Tue, 13 Feb 2007 11:44:06 +0100	[thread overview]
Message-ID: <20070213104406.GA9387@trinnov.com> (raw)
In-Reply-To: <200702051027.29226.ritsch@iem.at>

[-- Attachment #1: Type: text/plain, Size: 3504 bytes --]

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@iem.at - 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/)
> --

[-- Attachment #2: patch-hdspm --]
[-- Type: text/plain, Size: 12010 bytes --]

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,

[-- Attachment #3: Type: text/plain, Size: 374 bytes --]

-------------------------------------------------------------------------
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

[-- Attachment #4: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

  parent reply	other threads:[~2007-02-13 10:44 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-31 12:11 RME AES32 & MADI Remy Bruno
2007-02-02 18:39 ` Takashi Iwai
2007-02-05  9:27   ` Winfried Ritsch
2007-02-05 10:11     ` Takashi Iwai
2007-02-13 10:44     ` Remy Bruno [this message]
2007-02-14 15:00       ` Takashi Iwai
2007-02-20 17:04         ` Remy Bruno
2007-02-22 15:37           ` Takashi Iwai
2007-02-28 17:29             ` Remy Bruno
2007-03-08 13:40               ` Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070213104406.GA9387@trinnov.com \
    --to=remy.bruno@trinnov.com \
    --cc=alsa-devel@lists.sourceforge.net \
    --cc=ritsch@iem.at \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.