From mboxrd@z Thu Jan 1 00:00:00 1970 From: Remy Bruno Subject: Re: RME AES32 & MADI Date: Tue, 13 Feb 2007 11:44:06 +0100 Message-ID: <20070213104406.GA9387@trinnov.com> References: <20070131121148.GA20540@trinnov.com> <200702051027.29226.ritsch@iem.at> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="HcAYCG3uE/tztfnV" Return-path: Content-Disposition: inline In-Reply-To: <200702051027.29226.ritsch@iem.at> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: alsa-devel-bounces@lists.sourceforge.net Errors-To: alsa-devel-bounces@lists.sourceforge.net To: Winfried Ritsch Cc: Takashi Iwai , alsa-devel@lists.sourceforge.net List-Id: alsa-devel@alsa-project.org --HcAYCG3uE/tztfnV Content-Type: text/plain; charset=iso-8859-15 Content-Disposition: inline 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/) > -- --HcAYCG3uE/tztfnV Content-Type: text/plain; charset=iso-8859-15 Content-Disposition: attachment; filename=patch-hdspm 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, --HcAYCG3uE/tztfnV Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- 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 --HcAYCG3uE/tztfnV Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Alsa-devel mailing list Alsa-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/alsa-devel --HcAYCG3uE/tztfnV--