--- orig/linux-source-2.6.22-2.6.22/sound/pci/ca0106/ca0106_main.c	2007-07-09 09:32:17.000000000 +1000
+++ ben/linux-source-2.6.22-2.6.22/sound/pci/ca0106/ca0106_main.c	2008-05-21 00:14:05.000000000 +1000
@@ -165,6 +165,8 @@
 module_param_array(subsystem, uint, NULL, 0444);
 MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
 
+#define MODULE_NAME  "snd-ca0106"
+
 #include "ca0106.h"
 
 static struct snd_ca0106_details ca0106_chip_details[] = {
@@ -247,9 +249,9 @@
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
-	.rates =		(SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
-				 SNDRV_PCM_RATE_192000),
-	.rate_min =		48000,
+	.rates =		(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
+	.rate_min =		44100,
 	.rate_max =		192000,
 	.channels_min =		2,  //1,
 	.channels_max =		2,  //6,
@@ -281,6 +283,48 @@
 	.fifo_size =		0,
 };
 
+static unsigned int all_spdif_playback_rates[] =
+	{44100, 48000, 96000, 192000};
+
+static int hw_rule_playback_rate(struct snd_pcm_hw_params *params,
+                                 struct snd_pcm_hw_rule *rule)
+{
+	struct snd_ca0106 *chip = rule->private;
+	int chi, any_44100 = 0, any_non_44100 = 0, mask = 0;
+	struct snd_ca0106_channel *chp = 0;
+	struct snd_pcm_runtime *runtime;
+	snd_assert(chip != NULL, return -EINVAL);
+	
+	if (chip->spdif_enable) {
+		for (chi = 0; chi < 4; ++chi ) {
+			chp = &(chip->playback_channels[chi]);
+			if (!chp->use) continue;
+			snd_assert(chp->epcm != NULL, return -EINVAL);
+			if (!chp->epcm->running) continue;
+			snd_assert(chp->epcm->substream != NULL, return -EINVAL);
+			snd_assert(chp->epcm->substream->runtime != NULL, return -EINVAL);
+			runtime = chp->epcm->substream->runtime;
+			snd_printd("snd_hw_rule_playback_rate: ch=%d, rate=%d.\n",chi,runtime->rate);
+			any_44100 += runtime->rate == 44100;
+			any_non_44100 += runtime->rate != 44100;
+		}
+		if (any_44100 && any_non_44100)
+			printk(KERN_ERR MODULE_NAME ": Detected 44100Hz and other rates in use simultaneously.\n");
+		if (any_44100)
+			mask = 0x1;
+		else if (any_non_44100)
+			mask = 0xE;
+		else
+			mask = 0xF;
+	} else {
+		// 44100Hz is not supported for DAC (FIXME Why?)
+		mask = 0xE;
+	}
+	snd_printd("snd_hw_rule_playback_rate: any_44100=%d, any_non_44100=%d, mask=0x%X, spdif=%d\n",any_44100,any_non_44100,mask,chip->spdif_enable);
+	return snd_interval_list(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE),
+		ARRAY_SIZE(all_spdif_playback_rates), all_spdif_playback_rates, mask);
+}
+
 unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, 
 					  unsigned int reg, 
 					  unsigned int chn)
@@ -455,13 +499,28 @@
         channel->number = channel_id;
 
 	channel->use = 1;
-        //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+
+        snd_printd("open_playback: channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
         //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
 	channel->epcm = epcm;
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                 return err;
 	if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0)
                 return err;
+ 	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                       hw_rule_playback_rate, (void*)chip, SNDRV_PCM_HW_PARAM_RATE,
+                       -1)) < 0)
+                 return err;
+#if 0
+ 	// FIXME Add constraints to deal with the format.
+ 	if (chip->output_frequency_reservation_count == 0) {
+ 		chip->output_frequency_is_44100 = runtime->rate == 44100;
+ 	} else if (chip->output_frequency_is_44100 && runtime->rate != 44100)
+ 		return -EINVAL;
+ 	if (chip->playback_channels_open_count && chip->output_format != runtime->format)
+ 		return -EINVAL;
+#endif
+ 	
 	return 0;
 }
 
@@ -472,6 +531,9 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
         struct snd_ca0106_pcm *epcm = runtime->private_data;
 	chip->playback_channels[epcm->channel_id].use = 0;
+
+ 	snd_printd("close_playback.\n");
+ 
 	/* FIXME: maybe zero others */
 	return 0;
 }
@@ -598,51 +660,77 @@
 static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
 {
 	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime, *runtimei = 0;
 	struct snd_ca0106_pcm *epcm = runtime->private_data;
-	int channel = epcm->channel_id;
+	struct snd_ca0106_channel *chp = 0;
+	int channel = epcm->channel_id, chi, any_44100 = 0, any_non_44100 = 0;
 	u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel));
 	u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
 	u32 hcfg_mask = HCFG_PLAYBACK_S32_LE;
 	u32 hcfg_set = 0x00000000;
 	u32 hcfg;
-	u32 reg40_mask = 0x30000 << (channel<<1);
+	//u32 reg40_mask = 0x30000 << (channel<<1);
+	u32 reg40_mask = 0xFF0000;
 	u32 reg40_set = 0;
 	u32 reg40;
 	/* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */
-	u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */
+//	u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */
+	u32 reg71_mask;
+	u32 reg71_shift;
 	u32 reg71_set = 0;
 	u32 reg71;
 	int i;
-	
-        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
-        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
-	//snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
-	/* Rate can be set per channel. */
-	/* reg40 control host to fifo */
-	/* reg71 controls DAC rate. */
-	switch (runtime->rate) {
-	case 44100:
-		reg40_set = 0x10000 << (channel<<1);
-		reg71_set = 0x01010000; 
-		break;
-        case 48000:
-		reg40_set = 0;
-		reg71_set = 0; 
-		break;
-	case 96000:
-		reg40_set = 0x20000 << (channel<<1);
-		reg71_set = 0x02020000; 
-		break;
-	case 192000:
-		reg40_set = 0x30000 << (channel<<1);
-		reg71_set = 0x03030000; 
-		break;
-	default:
-		reg40_set = 0;
-		reg71_set = 0; 
-		break;
+	if (emu->spdif_enable) {
+		reg71_shift = 24; /* SPDIF Output Rate */
+	} else {
+		reg71_shift = 16; /* I2S Output Rate */
 	}
+	reg71_mask = 0x3 << reg71_shift;
+	
+        snd_printd("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
+        //snd_printd("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
+	//snd_printd("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+ 	// We are forced to build the settings for all the channels
+ 	for (chi = 0; chi < 4; ++chi ) {
+ 		chp = &(emu->playback_channels[chi]);
+ 		if (!chp->use) continue;
+ 		snd_assert(chp->epcm != NULL, return -EINVAL);
+		if (chi != channel && !chp->epcm->running) continue;
+ 		snd_assert(chp->epcm->substream != NULL, return -EINVAL);
+ 		snd_assert(chp->epcm->substream->runtime != NULL, return -EINVAL);
+ 		runtimei = chp->epcm->substream->runtime;
+ 		any_44100 += runtimei->rate == 44100;
+ 		any_non_44100 += runtimei->rate != 44100;
+ 		/* Rate can be set per channel. */
+ 		/* reg40 control host to fifo */
+ 		/* reg71 controls DAC rate. */
+ 		switch (runtimei->rate) {
+ 		case 44100:
+ 			/* We only support 44100 to spdif, not to DAC. (FIXME WHY?)*/
+ 			if (emu->spdif_enable) {
+ 				reg40_set |= 0x550000; /* When using 44100, all channels must be set to that speed. */
+ 				reg71_set |= 0x1 << reg71_shift;
+ 				break;
+ 			} else {
+ 				printk(KERN_ERR MODULE_NAME "prepare_playback: 44100Hz is invalid for DAC.\n");
+ 			}
+ 	        case 48000:
+ 			//reg40_set = 0;
+ 			//reg71_set = 0; 
+ 			break;
+ 		case 96000:
+ 			reg40_set |= 0x20000 << (chi<<1);
+ 			reg71_set |= 0x2 << reg71_shift;
+ 			break;
+ 		case 192000:
+ 			reg40_set |= 0x30000 << (chi<<1);
+ 			reg71_set |= 0x3 << reg71_shift;
+ 			break;
+ 		default:
+			printk(KERN_ERR MODULE_NAME "prepare_playback: Bad sampling frequency %d.\n",runtimei->rate);
+ 		}
+  	}
+	snd_printd("prepare_playback: any_44100=%d, any_non_44100=%d, spdif=%d.\n",any_44100,any_non_44100,emu->spdif_enable);
 	/* Format is a global setting */
 	/* FIXME: Only let the first channel accessed set this. */
 	switch (runtime->format) {
@@ -660,11 +748,15 @@
 	hcfg = (hcfg & ~hcfg_mask) | hcfg_set;
 	outl(hcfg, emu->port + HCFG);
 	reg40 = snd_ca0106_ptr_read(emu, 0x40, 0);
+        snd_printd("ca0106: old reg40=%x\n", reg40);
 	reg40 = (reg40 & ~reg40_mask) | reg40_set;
 	snd_ca0106_ptr_write(emu, 0x40, 0, reg40);
+        snd_printd("ca0106: new reg40=%x\n", reg40);
 	reg71 = snd_ca0106_ptr_read(emu, 0x71, 0);
+        snd_printd("ca0106: old reg71=%x\n", reg71);
 	reg71 = (reg71 & ~reg71_mask) | reg71_set;
 	snd_ca0106_ptr_write(emu, 0x71, 0, reg71);
+        snd_printd("ca0106: new reg71=%x\n", reg71);
 
 	/* FIXME: Check emu->buffer.size before actually writing to it. */
         for(i=0; i < runtime->periods; i++) {
@@ -710,9 +802,9 @@
 	u32 reg71_set = 0;
 	u32 reg71;
 	
-        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
-        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
-	//snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+        snd_printd("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
+        //snd_printd("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
+	//snd_printd("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
 	/* reg71 controls ADC rate. */
 	switch (runtime->rate) {
 	case 44100:
@@ -757,7 +849,7 @@
 	}
 
 
-        //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size,  frames_to_bytes(runtime, 1));
+        snd_printd("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size,  frames_to_bytes(runtime, 1));
 	snd_ca0106_ptr_write(emu, 0x13, channel, 0);
 	snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
 	snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
@@ -1300,6 +1392,7 @@
 #if 1
 	printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model,
 	       chip->revision, chip->serial);
+ 	printk(KERN_INFO MODULE_NAME ": 44100Hz capable rev C. Ben Stanley " __DATE__ ".\n" );
 #endif
 	strcpy(card->driver, "CA0106");
 	strcpy(card->shortname, "CA0106");
