vserver 2.0 rc7
[linux-2.6.git] / sound / pci / intel8x0m.c
index 91df930..67da096 100644 (file)
@@ -35,6 +35,7 @@
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
+#include <sound/control.h>
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -46,6 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
                "{Intel,82801CA-ICH3},"
                "{Intel,82801DB-ICH4},"
                "{Intel,ICH5},"
+               "{Intel,ICH6},"
+               "{Intel,ICH7},"
                "{Intel,MX440},"
                "{SiS,7013},"
                "{NVidia,NForce Modem},"
@@ -54,7 +57,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
                "{NVidia,NForce3 Modem},"
                "{AMD,AMD768}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
@@ -93,6 +96,12 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
 #ifndef PCI_DEVICE_ID_INTEL_ICH5_6
 #define PCI_DEVICE_ID_INTEL_ICH5_6     0x24d6
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH6_6
+#define PCI_DEVICE_ID_INTEL_ICH6_6     0x266d
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH7_6
+#define PCI_DEVICE_ID_INTEL_ICH7_6     0x27dd
+#endif
 #ifndef PCI_DEVICE_ID_SI_7013
 #define PCI_DEVICE_ID_SI_7013          0x7013
 #endif
@@ -247,7 +256,7 @@ struct _snd_intel8x0m {
        snd_pcm_t *pcm[2];
        ichdev_t ichd[2];
 
-       int in_ac97_init: 1;
+       unsigned int in_ac97_init: 1;
 
        ac97_bus_t *ac97_bus;
        ac97_t *ac97;
@@ -268,6 +277,8 @@ static struct pci_device_id snd_intel8x0m_ids[] = {
        { 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
        { 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
        { 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */
+       { 0x8086, 0x266d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH6 */
+       { 0x8086, 0x27dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH7 */
        { 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
        { 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
        { 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7013 */
@@ -281,9 +292,60 @@ static struct pci_device_id snd_intel8x0m_ids[] = {
 #endif
        { 0, }
 };
+static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
+                                           snd_ctl_elem_value_t *ucontrol);
+static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
+                                           snd_ctl_elem_value_t *ucontrol);
+static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
+                                            snd_ctl_elem_info_t *uinfo);
+
+#define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff))
+#define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff)
+#define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff)
+
+static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = {
+  { .name  = "Off-hook Switch",
+    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+    .info  = snd_intel8x0m_switch_default_info,
+    .get   = snd_intel8x0m_switch_default_get,
+    .put   = snd_intel8x0m_switch_default_put,
+    .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH)
+  }
+};
 
 MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
 
+static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
+                                            snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
+                                           snd_ctl_elem_value_t *ucontrol)
+{
+       unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
+       unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
+       intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int status;
+       status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0;
+       ucontrol->value.integer.value[0] = status;
+       return 0;
+}
+static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
+                                           snd_ctl_elem_value_t *ucontrol)
+{
+       unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
+       unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
+       intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask;
+       return snd_ac97_update_bits(chip->ac97, reg,
+                                   mask, new_status);
+}
 /*
  *  Lowlevel I/O - busmaster
  */
@@ -638,17 +700,12 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea
 
 static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 {
-       ichdev_t *ichdev = get_ichdev(substream);
        /* hook off/on on start/stop */
-       /* TODO: move it to ac97 controls */
+       /* Moved this to mixer control */
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
-                                    AC97_GPIO_LINE1_OH, AC97_GPIO_LINE1_OH);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
-                                    AC97_GPIO_LINE1_OH, ~AC97_GPIO_LINE1_OH);
                break;
        default:
                return -EINVAL;
@@ -890,6 +947,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
        ac97_t *x97;
        int err;
        unsigned int glob_sta = 0;
+       unsigned int idx;
        static ac97_bus_ops_t ops = {
                .write = snd_intel8x0_codec_write,
                .read = snd_intel8x0_codec_read,
@@ -921,10 +979,14 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
                return err;
        }
        chip->ac97 = x97;
-       if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97 ) {
+       if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97) {
                chip->ichd[ICHD_MDMIN].ac97 = x97;
                chip->ichd[ICHD_MDMOUT].ac97 = x97;
        }
+       for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) {
+               if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0)
+                       goto __err;
+       }
 
        chip->in_ac97_init = 0;
        return 0;
@@ -1078,7 +1140,7 @@ static int snd_intel8x0_free(intel8x0_t *chip)
 /*
  * power management
  */
-static int intel8x0m_suspend(snd_card_t *card, unsigned int state)
+static int intel8x0m_suspend(snd_card_t *card, pm_message_t state)
 {
        intel8x0_t *chip = card->pm_private_data;
        int i;
@@ -1091,7 +1153,7 @@ static int intel8x0m_suspend(snd_card_t *card, unsigned int state)
        return 0;
 }
 
-static int intel8x0m_resume(snd_card_t *card, unsigned int state)
+static int intel8x0m_resume(snd_card_t *card)
 {
        intel8x0_t *chip = card->pm_private_data;
        pci_enable_device(chip->pci);
@@ -1298,6 +1360,8 @@ static struct shortname_table {
        { PCI_DEVICE_ID_INTEL_ICH3_6, "Intel 82801CA-ICH3" },
        { PCI_DEVICE_ID_INTEL_ICH4_6, "Intel 82801DB-ICH4" },
        { PCI_DEVICE_ID_INTEL_ICH5_6, "Intel ICH5" },
+       { PCI_DEVICE_ID_INTEL_ICH6_6, "Intel ICH6" },
+       { PCI_DEVICE_ID_INTEL_ICH7_6, "Intel ICH7" },
        { 0x7446, "AMD AMD768" },
        { PCI_DEVICE_ID_SI_7013, "SiS SI7013" },
        { PCI_DEVICE_ID_NVIDIA_MCP_MODEM, "NVidia nForce" },