Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / sound / pci / hda / hda_intel.c
index bfd74a5..1a7e821 100644 (file)
@@ -55,7 +55,7 @@ static char *model;
 static int position_fix;
 static int probe_mask = -1;
 static int single_cmd;
-static int disable_msi;
+static int enable_msi;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -69,8 +69,8 @@ module_param(probe_mask, int, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
-module_param(disable_msi, int, 0);
-MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+module_param(enable_msi, int, 0);
+MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
 
 /* just for backward compatibility */
@@ -83,9 +83,11 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH7},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
+                        "{Intel, ICH9},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
                         "{ATI, RS600},"
+                        "{ATI, RS690},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -336,6 +338,7 @@ struct azx {
        unsigned int initialized :1;
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
+       unsigned int msi :1;
 };
 
 /* driver types */
@@ -396,6 +399,7 @@ static char *driver_short_names[] __devinitdata = {
  */
 #define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
 
+static int azx_acquire_irq(struct azx *chip, int do_disconnect);
 
 /*
  * Interface for HD codec
@@ -520,38 +524,48 @@ static void azx_update_rirb(struct azx *chip)
 static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 {
        struct azx *chip = codec->bus->private_data;
-       int timeout = 50;
+       unsigned long timeout;
 
-       for (;;) {
+ again:
+       timeout = jiffies + msecs_to_jiffies(1000);
+       do {
                if (chip->polling_mode) {
                        spin_lock_irq(&chip->reg_lock);
                        azx_update_rirb(chip);
                        spin_unlock_irq(&chip->reg_lock);
                }
                if (! chip->rirb.cmds)
-                       break;
-               if (! --timeout) {
-                       if (! chip->polling_mode) {
-                               snd_printk(KERN_WARNING "hda_intel: "
-                                          "azx_get_response timeout, "
-                                          "switching to polling mode...\n");
-                               chip->polling_mode = 1;
-                               timeout = 50;
-                               continue;
-                       }
-                       snd_printk(KERN_ERR
-                                  "hda_intel: azx_get_response timeout, "
-                                  "switching to single_cmd mode...\n");
-                       chip->rirb.rp = azx_readb(chip, RIRBWP);
-                       chip->rirb.cmds = 0;
-                       /* switch to single_cmd mode */
-                       chip->single_cmd = 1;
-                       azx_free_cmd_io(chip);
+                       return chip->rirb.res; /* the last value */
+               schedule_timeout_interruptible(1);
+       } while (time_after_eq(timeout, jiffies));
+
+       if (chip->msi) {
+               snd_printk(KERN_WARNING "hda_intel: No response from codec, "
+                          "disabling MSI...\n");
+               free_irq(chip->irq, chip);
+               chip->irq = -1;
+               pci_disable_msi(chip->pci);
+               chip->msi = 0;
+               if (azx_acquire_irq(chip, 1) < 0)
                        return -1;
-               }
-               msleep(1);
+               goto again;
+       }
+
+       if (!chip->polling_mode) {
+               snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
+                          "switching to polling mode...\n");
+               chip->polling_mode = 1;
+               goto again;
        }
-       return chip->rirb.res; /* the last value */
+
+       snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
+                  "switching to single_cmd mode...\n");
+       chip->rirb.rp = azx_readb(chip, RIRBWP);
+       chip->rirb.cmds = 0;
+       /* switch to single_cmd mode */
+       chip->single_cmd = 1;
+       azx_free_cmd_io(chip);
+       return -1;
 }
 
 /*
@@ -813,7 +827,7 @@ static void azx_init_chip(struct azx *chip)
 /*
  * interrupt handler
  */
-static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t azx_interrupt(int irq, void *dev_id)
 {
        struct azx *chip = dev_id;
        struct azx_dev *azx_dev;
@@ -1242,7 +1256,12 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
        struct snd_pcm *pcm;
        struct azx_pcm *apcm;
 
-       snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL);
+       /* if no substreams are defined for both playback and capture,
+        * it's just a placeholder.  ignore it.
+        */
+       if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
+               return 0;
+
        snd_assert(cpcm->name, return -EINVAL);
 
        err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
@@ -1268,7 +1287,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
                                              snd_dma_pci_data(chip->pci),
                                              1024 * 64, 1024 * 128);
        chip->pcm[pcm_dev] = pcm;
-       chip->pcm_devs = pcm_dev + 1;
+       if (chip->pcm_devs < pcm_dev + 1)
+               chip->pcm_devs = pcm_dev + 1;
 
        return 0;
 }
@@ -1359,6 +1379,21 @@ static int __devinit azx_init_stream(struct azx *chip)
        return 0;
 }
 
+static int azx_acquire_irq(struct azx *chip, int do_disconnect)
+{
+       if (request_irq(chip->pci->irq, azx_interrupt,
+                       chip->msi ? 0 : IRQF_SHARED,
+                       "HDA Intel", chip)) {
+               printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
+                      "disabling device\n", chip->pci->irq);
+               if (do_disconnect)
+                       snd_card_disconnect(chip->card);
+               return -1;
+       }
+       chip->irq = chip->pci->irq;
+       return 0;
+}
+
 
 #ifdef CONFIG_PM
 /*
@@ -1375,8 +1410,16 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
                snd_pcm_suspend_all(chip->pcm[i]);
        snd_hda_suspend(chip->bus, state);
        azx_free_cmd_io(chip);
+       if (chip->irq >= 0) {
+               synchronize_irq(chip->irq);
+               free_irq(chip->irq, chip);
+               chip->irq = -1;
+       }
+       if (chip->msi)
+               pci_disable_msi(chip->pci);
        pci_disable_device(pci);
        pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
        return 0;
 }
 
@@ -1385,9 +1428,20 @@ static int azx_resume(struct pci_dev *pci)
        struct snd_card *card = pci_get_drvdata(pci);
        struct azx *chip = card->private_data;
 
+       pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
-       pci_enable_device(pci);
+       if (pci_enable_device(pci) < 0) {
+               printk(KERN_ERR "hda-intel: pci_enable_device failed, "
+                      "disabling device\n");
+               snd_card_disconnect(card);
+               return -EIO;
+       }
        pci_set_master(pci);
+       if (chip->msi)
+               if (pci_enable_msi(pci) < 0)
+                       chip->msi = 0;
+       if (azx_acquire_irq(chip, 1) < 0)
+               return -EIO;
        azx_init_chip(chip);
        snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -1417,15 +1471,14 @@ static int azx_free(struct azx *chip)
                /* disable position buffer */
                azx_writel(chip, DPLBASE, 0);
                azx_writel(chip, DPUBASE, 0);
-
-               synchronize_irq(chip->irq);
        }
 
        if (chip->irq >= 0) {
+               synchronize_irq(chip->irq);
                free_irq(chip->irq, (void*)chip);
-               if (!disable_msi)
-                       pci_disable_msi(chip->pci);
        }
+       if (chip->msi)
+               pci_disable_msi(chip->pci);
        if (chip->remap_addr)
                iounmap(chip->remap_addr);
 
@@ -1480,6 +1533,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->pci = pci;
        chip->irq = -1;
        chip->driver_type = driver_type;
+       chip->msi = enable_msi;
 
        chip->position_fix = position_fix;
        chip->single_cmd = single_cmd;
@@ -1509,16 +1563,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
        }
 
-       if (!disable_msi)
-               pci_enable_msi(pci);
+       if (chip->msi)
+               if (pci_enable_msi(pci) < 0)
+                       chip->msi = 0;
 
-       if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
-                       "HDA Intel", (void*)chip)) {
-               snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+       if (azx_acquire_irq(chip, 0) < 0) {
                err = -EBUSY;
                goto errout;
        }
-       chip->irq = pci->irq;
 
        pci_set_master(pci);
        synchronize_irq(chip->irq);
@@ -1660,14 +1712,23 @@ static struct pci_device_id azx_ids[] = {
        { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
        { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
+       { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
+       { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
        { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
        { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
+       { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
        { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
        { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
        { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
-       { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */
-       { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */
+       { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP51 */
+       { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP55 */
+       { 0x10de, 0x03e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
+       { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
+       { 0x10de, 0x044a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
+       { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
+       { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+       { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);