[ALSA] Current driver does not utilize 44.1kHz high quality sampling rate converter.
authorTeru KAMOGASHIRA <teru@sodan.ecc.u-tokyo.ac.jp>
Mon, 4 Dec 2006 17:03:53 +0000 (18:03 +0100)
committerJaroslav Kysela <perex@suse.cz>
Fri, 9 Feb 2007 08:02:16 +0000 (09:02 +0100)
Following patch will make the driver to use the 44.1kHz SRC automatically
if the pcm source is 44.1kHz signed 16bit stereo.
The SRC is available in YMF754 only.

Signed-off-by: Teru KAMOGASHIRA <teru@sodan.ecc.u-tokyo.ac.jp>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
include/sound/ymfpci.h
sound/pci/ymfpci/ymfpci_main.c

index eef46fa..203d2b4 100644 (file)
@@ -270,6 +270,7 @@ struct snd_ymfpci_pcm {
        struct snd_pcm_substream *substream;
        struct snd_ymfpci_voice *voices[2];     /* playback only */
        unsigned int running: 1,
+                    use_441_slot: 1,
                     output_front: 1,
                     output_rear: 1,
                     swap_rear: 1;
@@ -324,6 +325,7 @@ struct snd_ymfpci {
 
        u32 active_bank;
        struct snd_ymfpci_voice voices[64];
+       int src441_used;
 
        struct snd_ac97_bus *ac97_bus;
        struct snd_ac97 *ac97;
@@ -346,7 +348,7 @@ struct snd_ymfpci {
        int mode_dup4ch;
        int rear_opened;
        int spdif_opened;
-       struct {
+       struct snd_ymfpci_pcm_mixer {
                u16 left;
                u16 right;
                struct snd_kcontrol *ctl;
index 5bde816..8b07693 100644 (file)
@@ -171,6 +171,17 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate)
        return val[0];
 }
 
+static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm)
+{
+       unsigned int value;
+       struct snd_ymfpci_pcm_mixer *mixer;
+       
+       mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number];
+       value = min_t(unsigned int, mixer->left, 0x7fff) >> 1;
+       value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16;
+       snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value);
+}
+
 /*
  *  Hardware start management
  */
@@ -282,6 +293,10 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic
        snd_assert(pvoice != NULL, return -EINVAL);
        snd_ymfpci_hw_stop(chip);
        spin_lock_irqsave(&chip->voice_lock, flags);
+       if (pvoice->number == chip->src441_used) {
+               chip->src441_used = -1;
+               pvoice->ypcm->use_441_slot = 0;
+       }
        pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
        pvoice->ypcm = NULL;
        pvoice->interrupt = NULL;
@@ -386,7 +401,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
                chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
-               if (ypcm->voices[1] != NULL)
+               if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
                        chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
                ypcm->running = 1;
                break;
@@ -394,7 +409,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_SUSPEND:
                chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
-               if (ypcm->voices[1] != NULL)
+               if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
                        chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
                ypcm->running = 0;
                break;
@@ -481,6 +496,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
        unsigned int nbank;
        u32 vol_left, vol_right;
        u8 use_left, use_right;
+       unsigned long flags;
 
        snd_assert(voice != NULL, return);
        if (runtime->channels == 1) {
@@ -499,11 +515,27 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
                vol_left = cpu_to_le32(0x40000000);
                vol_right = cpu_to_le32(0x40000000);
        }
+       spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
        format = runtime->channels == 2 ? 0x00010000 : 0;
        if (snd_pcm_format_width(runtime->format) == 8)
                format |= 0x80000000;
+       else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
+                runtime->rate == 44100 && runtime->channels == 2 &&
+                voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
+                                  ypcm->chip->src441_used == voice->number)) {
+               ypcm->chip->src441_used = voice->number;
+               ypcm->use_441_slot = 1;
+               format |= 0x10000000;
+               snd_ymfpci_pcm_441_volume_set(ypcm);
+       }
+       if (ypcm->chip->src441_used == voice->number &&
+           (format & 0x10000000) == 0) {
+               ypcm->chip->src441_used = -1;
+               ypcm->use_441_slot = 0;
+       }
        if (runtime->channels == 2 && (voiceidx & 1) != 0)
                format |= 1;
+       spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
        for (nbank = 0; nbank < 2; nbank++) {
                bank = &voice->bank[nbank];
                memset(bank, 0, sizeof(*bank));
@@ -1714,7 +1746,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
                spin_lock_irqsave(&chip->voice_lock, flags);
                if (substream->runtime && substream->runtime->private_data) {
                        struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
-                       ypcm->update_pcm_vol = 2;
+                       if (!ypcm->use_441_slot)
+                               ypcm->update_pcm_vol = 2;
+                       else
+                               snd_ymfpci_pcm_441_volume_set(ypcm);
                }
                spin_unlock_irqrestore(&chip->voice_lock, flags);
                return 1;
@@ -2253,7 +2288,7 @@ static int saved_regs_index[] = {
        YDSXGR_PRIADCLOOPVOL,
        YDSXGR_NATIVEDACINVOL,
        YDSXGR_NATIVEDACOUTVOL,
-       // YDSXGR_BUF441OUTVOL,
+       YDSXGR_BUF441OUTVOL,
        YDSXGR_NATIVEADCINVOL,
        YDSXGR_SPDIFLOOPVOL,
        YDSXGR_SPDIFOUTVOL,
@@ -2368,6 +2403,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
        chip->reg_area_phys = pci_resource_start(pci, 0);
        chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
        pci_set_master(pci);
+       chip->src441_used = -1;
 
        if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
                snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);