--- 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");