ALSA: HDA: Add new revision for ALC662
[linux-2.6.git] / sound / pci / cmipci.c
index 3a2d942..9cf99fb 100644 (file)
@@ -20,7 +20,6 @@
 /* Does not work. Warning may block system in capture mode */
 /* #define USE_VAR48KRATE */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -74,7 +73,7 @@ MODULE_PARM_DESC(mpu_port, "MPU-401 port.");
 module_param_array(fm_port, long, NULL, 0444);
 MODULE_PARM_DESC(fm_port, "FM port.");
 module_param_array(soft_ac3, bool, NULL, 0444);
-MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only).");
+MODULE_PARM_DESC(soft_ac3, "Software-conversion of raw SPDIF packets (model 033 only).");
 #ifdef SUPPORT_JOYSTICK
 module_param_array(joystick_port, int, NULL, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address.");
@@ -657,8 +656,8 @@ out:
 }
 
 /*
- * Program pll register bits, I assume that the 8 registers 0xf8 upto 0xff
- * are mapped onto the 8 ADC/DAC sampling frequency which can be choosen
+ * Program pll register bits, I assume that the 8 registers 0xf8 up to 0xff
+ * are mapped onto the 8 ADC/DAC sampling frequency which can be chosen
  * at the register CM_REG_FUNCTRL1 (0x04).
  * Problem: other ways are also possible (any information about that?)
  */
@@ -667,7 +666,7 @@ static void snd_cmipci_set_pll(struct cmipci *cm, unsigned int rate, unsigned in
        unsigned int reg = CM_REG_PLL + slot;
        /*
         * Guess that this programs at reg. 0x04 the pos 15:13/12:10
-        * for DSFC/ASFC (000 upto 111).
+        * for DSFC/ASFC (000 up to 111).
         */
 
        /* FIXME: Init (Do we've to set an other register first before programming?) */
@@ -869,6 +868,13 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
        snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
        //snd_printd("cmipci: chformat = %08x\n", val);
 
+       if (!rec->is_dac && cm->chip_version) {
+               if (runtime->rate > 44100)
+                       snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K);
+               else
+                       snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K);
+       }
+
        rec->running = 0;
        spin_unlock_irq(&cm->reg_lock);
 
@@ -935,13 +941,21 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci
                                                struct snd_pcm_substream *substream)
 {
        size_t ptr;
-       unsigned int reg;
+       unsigned int reg, rem, tries;
+
        if (!rec->running)
                return 0;
 #if 1 // this seems better..
        reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2;
-       ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1);
-       ptr >>= rec->shift;
+       for (tries = 0; tries < 3; tries++) {
+               rem = snd_cmipci_read_w(cm, reg);
+               if (rem < rec->dma_size)
+                       goto ok;
+       } 
+       printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem);
+       return SNDRV_PCM_POS_XRUN;
+ok:
+       ptr = (rec->dma_size - (rem + 1)) >> rec->shift;
 #else
        reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1;
        ptr = snd_cmipci_read(cm, reg) - rec->offset;
@@ -1400,6 +1414,11 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream)
                else
                        snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
        }
+       if (snd_pcm_format_width(substream->runtime->format) > 16)
+               snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
+       else
+               snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
+
        spin_unlock_irq(&cm->reg_lock);
 
        return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream);
@@ -1411,6 +1430,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs)
 
        spin_lock_irq(&cm->reg_lock);
        snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
+       snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
        spin_unlock_irq(&cm->reg_lock);
 
        return snd_cmipci_hw_free(subs);
@@ -1562,7 +1582,8 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |
                                 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
-       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
        .rates =                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
        .rate_min =             44100,
        .rate_max =             48000,
@@ -2289,7 +2310,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
        CMIPCI_SB_SW_MONO("Mic Playback Switch", 0),
        CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0),
-       CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+       CMIPCI_SB_VOL_MONO("Beep Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
        CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
        CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
        CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
@@ -2297,7 +2318,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
        CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
        CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
-       CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+       CMIPCI_DOUBLE("Beep Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
        CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
 };
 
@@ -2344,7 +2365,8 @@ static int snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol,
 {
        struct cmipci_switch_args *args;
        args = (struct cmipci_switch_args *)kcontrol->private_value;
-       snd_assert(args != NULL, return -EINVAL);
+       if (snd_BUG_ON(!args))
+               return -EINVAL;
        return _snd_cmipci_uswitch_get(kcontrol, ucontrol, args);
 }
 
@@ -2388,7 +2410,8 @@ static int snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol,
 {
        struct cmipci_switch_args *args;
        args = (struct cmipci_switch_args *)kcontrol->private_value;
-       snd_assert(args != NULL, return -EINVAL);
+       if (snd_BUG_ON(!args))
+               return -EINVAL;
        return _snd_cmipci_uswitch_put(kcontrol, ucontrol, args);
 }
 
@@ -2484,14 +2507,12 @@ static int snd_cmipci_line_in_mode_info(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_info *uinfo)
 {
        struct cmipci *cm = snd_kcontrol_chip(kcontrol);
-       static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       static const char *const texts[3] = {
+               "Line-In", "Rear Output", "Bass Output"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                cm->chip_version >= 39 ? 3 : 2, texts);
 }
 
 static inline unsigned int get_line_in_mode(struct cmipci *cm)
@@ -2541,14 +2562,9 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
 static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[2] = { "Mic-In", "Center/LFE Output" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       static const char *const texts[2] = { "Mic-In", "Center/LFE Output" };
+
+       return snd_ctl_enum_info(uinfo, 1, 2, texts);
 }
 
 static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol,
@@ -2637,10 +2653,8 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata =
 };
 
 /* card control switches */
-static struct snd_kcontrol_new snd_cmipci_control_switches[] __devinitdata = {
-       // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */
-       DEFINE_CARD_SWITCH("Modem", modem),
-};
+static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata =
+DEFINE_CARD_SWITCH("Modem", modem);
 
 
 static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
@@ -2651,7 +2665,8 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic
        unsigned int idx;
        int err;
 
-       snd_assert(cm != NULL && cm->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!cm || !cm->card))
+               return -EINVAL;
 
        card = cm->card;
 
@@ -2721,20 +2736,25 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic
        }
 
        /* card switches */
-       sw = snd_cmipci_control_switches;
-       for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_control_switches); idx++, sw++) {
-               err = snd_ctl_add(cm->card, snd_ctl_new1(sw, cm));
+       /*
+        * newer chips don't have the register bits to force modem link
+        * detection; the bit that was FLINKON now mutes CH1
+        */
+       if (cm->chip_version < 39) {
+               err = snd_ctl_add(cm->card,
+                                 snd_ctl_new1(&snd_cmipci_modem_switch, cm));
                if (err < 0)
                        return err;
        }
 
        for (idx = 0; idx < CM_SAVED_MIXERS; idx++) {
-               struct snd_ctl_elem_id id;
+               struct snd_ctl_elem_id elem_id;
                struct snd_kcontrol *ctl;
-               memset(&id, 0, sizeof(id));
-               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-               strcpy(id.name, cm_saved_mixer[idx].name);
-               if ((ctl = snd_ctl_find_id(cm->card, &id)) != NULL)
+               memset(&elem_id, 0, sizeof(elem_id));
+               elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               strcpy(elem_id.name, cm_saved_mixer[idx].name);
+               ctl = snd_ctl_find_id(cm->card, &elem_id);
+               if (ctl)
                        cm->mixer_res_ctl[idx] = ctl;
        }
 
@@ -2777,12 +2797,12 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
 #endif
 
 
-static struct pci_device_id snd_cmipci_ids[] = {
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_AL, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = {
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B), 0},
+       {PCI_VDEVICE(AL, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
        {0,},
 };
 
@@ -2917,8 +2937,6 @@ static int snd_cmipci_free(struct cmipci *cm)
                /* reset mixer */
                snd_cmipci_mixer_write(cm, 0, 0);
 
-               synchronize_irq(cm->irq);
-
                free_irq(cm->irq, cm);
        }
 
@@ -2997,11 +3015,11 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
                .dev_free =     snd_cmipci_dev_free,
        };
        unsigned int val;
-       long iomidi;
+       long iomidi = 0;
        int integrated_midi = 0;
        char modelstr[16];
        int pcm_index, pcm_spdif_index;
-       static struct pci_device_id intel_82437vx[] = {
+       static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = {
                { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) },
                { },
        };
@@ -3035,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
        cm->iobase = pci_resource_start(pci, 0);
 
        if (request_irq(pci->irq, snd_cmipci_interrupt,
-                       IRQF_SHARED, card->driver, cm)) {
+                       IRQF_SHARED, KBUILD_MODNAME, cm)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_cmipci_free(cm);
                return -EBUSY;
@@ -3255,9 +3273,9 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        
        switch (pci->device) {
        case PCI_DEVICE_ID_CMEDIA_CM8738:
@@ -3380,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
 #endif /* CONFIG_PM */
 
 static struct pci_driver driver = {
-       .name = "C-Media PCI",
+       .name = KBUILD_MODNAME,
        .id_table = snd_cmipci_ids,
        .probe = snd_cmipci_probe,
        .remove = __devexit_p(snd_cmipci_remove),