]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] update the i810 audio driver
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 11 Jul 2003 13:50:55 +0000 (06:50 -0700)
committerSteve French <cifs.adm@hostme.bitkeeper.com>
Fri, 11 Jul 2003 13:50:55 +0000 (06:50 -0700)
sound/oss/i810_audio.c

index f4bde838e47417a33e5e986352b49362c8dc8848..a5bded9a0b2925cdfaabc4333099abf4cc702726 100644 (file)
 #ifndef PCI_DEVICE_ID_INTEL_ICH4
 #define PCI_DEVICE_ID_INTEL_ICH4       0x24c5
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH5
+#define PCI_DEVICE_ID_INTEL_ICH5       0x24d5
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_440MX
 #define PCI_DEVICE_ID_INTEL_440MX      0x7195
 #endif
@@ -272,6 +275,7 @@ enum {
        INTELICH2,
        INTELICH3,
        INTELICH4,
+       INTELICH5,
        SI7012,
        NVIDIA_NFORCE,
        AMD768,
@@ -285,6 +289,7 @@ static char * card_names[] = {
        "Intel ICH2",
        "Intel ICH3",
        "Intel ICH4",
+       "Intel ICH5",
        "SiS 7012",
        "NVIDIA nForce Audio",
        "AMD 768",
@@ -303,7 +308,8 @@ static struct {
        {  1, 0x0000 }, /* INTEL440MX */
        {  1, 0x0000 }, /* INTELICH2 */
        {  2, 0x0000 }, /* INTELICH3 */
-        {  3, 0x0003 }, /* INTELICH4 */
+       {  3, 0x0003 }, /* INTELICH4 */
+       {  3, 0x0003 }, /* INTELICH5 */
        /*@FIXME to be verified*/       {  2, 0x0000 }, /* SI7012 */
        /*@FIXME to be verified*/       {  2, 0x0000 }, /* NVIDIA_NFORCE */
        /*@FIXME to be verified*/       {  2, 0x0000 }, /* AMD768 */
@@ -323,6 +329,8 @@ static struct pci_device_id i810_pci_tbl [] __initdata = {
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH4,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH5,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5},
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
        {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
@@ -419,6 +427,9 @@ struct i810_card {
        /* The i810 has a certain amount of cross channel interaction
           so we use a single per card lock */
        spinlock_t lock;
+       
+       /* Control AC97 access serialization */
+       spinlock_t ac97_lock;
 
        /* PCI device stuff */
        struct pci_dev * pci_dev;
@@ -547,80 +558,42 @@ static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
  *     The DSP sample rate must already be set to a supported
  *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
  */
-static void i810_set_spdif_output(struct i810_state *state, int slots, int rate)
+static int i810_set_spdif_output(struct i810_state *state, int slots, int rate)
 {
        int     vol;
        int     aud_reg;
+       int     r = 0;
        struct ac97_codec *codec = state->card->ac97_codec[0];
 
-       if(!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
-               printk(KERN_WARNING "i810_audio: S/PDIF transmitter not available.\n");
-#endif
+       if(!codec->codec_ops->digital) {
                state->card->ac97_status &= ~SPDIF_ON;
        } else {
                if ( slots == -1 ) { /* Turn off S/PDIF */
-                       aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-                       i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-
+                       codec->codec_ops->digital(codec, 0, 0, 0);
                        /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
                        if ( !(state->card->ac97_status & VOL_MUTED) ) {
                                aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
                                i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
                        }
                        state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
-                       return;
+                       return 0;
                }
 
                vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
                state->card->ac97_status = vol & VOL_MUTED;
-
-               /* Set S/PDIF transmitter sample rate */
-               aud_reg = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
-               switch ( rate ) {
-                       case 32000:
-                               aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; 
-                               break;
-                        case 44100:
-                               aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; 
-                               break;
-                       case 48000:
-                               aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; 
-                               break;
-                       default:
-#ifdef DEBUG
-                               printk(KERN_WARNING "i810_audio: %d sample rate not supported by S/PDIF.\n", rate);
-#endif
-                               /* turn off S/PDIF */
-                               aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-                               i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-                               state->card->ac97_status &= ~SPDIF_ON;
-                               return;
-               }
-
-               i810_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
                
-               aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-               aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_VRA | AC97_EA_SPDIF;
-               i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-               state->card->ac97_status |= SPDIF_ON;
-
-               /* Check to make sure the configuration is valid */
-               aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-               if ( ! (aud_reg & 0x0400) ) {
-#ifdef DEBUG
-                       printk(KERN_WARNING "i810_audio: S/PDIF transmitter configuration not valid (0x%04x).\n", aud_reg);
-#endif
+               r = codec->codec_ops->digital(codec, slots, rate, 0);
 
-                       /* turn off S/PDIF */
-                       i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+               if(r)
+                       state->card->ac97_status |= SPDIF_ON;
+               else
                        state->card->ac97_status &= ~SPDIF_ON;
-                       return;
-               }
+
                /* Mute the analog output */
                /* Should this only mute the PCM volume??? */
                i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
        }
+       return r;
 }
 
 /* i810_set_dac_channels
@@ -642,8 +615,9 @@ static void i810_set_dac_channels(struct i810_state *state, int channel)
 {
        int     aud_reg;
        struct ac97_codec *codec = state->card->ac97_codec[0];
-
+       
        /* No codec, no setup */
+       
        if(codec == NULL)
                return;
 
@@ -1835,6 +1809,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                }
 
                spin_unlock_irqrestore(&state->card->lock, flags);
+               synchronize_irq(state->card->pci_dev->irq);
                dmabuf->ready = 0;
                dmabuf->swptr = dmabuf->hwptr = 0;
                dmabuf->count = dmabuf->total_bytes = 0;
@@ -2493,11 +2468,9 @@ found_virt:
        }
        if(file->f_mode & FMODE_WRITE) {
                if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
-                       /* free any read channel allocated earlier */
+                       /* make sure we free the record channel allocated above */
                        if(file->f_mode & FMODE_READ)
-                               card->free_pcm_channel(card,
-                                               dmabuf->read_channel->num);
-
+                               card->free_pcm_channel(card,dmabuf->read_channel->num);
                        kfree (card->states[i]);
                        card->states[i] = NULL;;
                        return -EBUSY;
@@ -2641,23 +2614,32 @@ static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
 {
        struct i810_card *card = dev->private_data;
+       u16 ret;
+       
+       spin_lock(&card->ac97_lock);
        if (card->use_mmio) {
-               return i810_ac97_get_mmio(dev, reg);
+               ret = i810_ac97_get_mmio(dev, reg);
        }
        else {
-               return i810_ac97_get_io(dev, reg);
+               ret = i810_ac97_get_io(dev, reg);
        }
+       spin_unlock(&card->ac97_lock);
+       
+       return ret;
 }
 
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
 {
        struct i810_card *card = dev->private_data;
+       
+       spin_lock(&card->ac97_lock);
        if (card->use_mmio) {
                i810_ac97_set_mmio(dev, reg, data);
        }
        else {
                i810_ac97_set_io(dev, reg, data);
        }
+       spin_unlock(&card->ac97_lock);
 }
 
 
@@ -2803,7 +2785,7 @@ static int i810_ac97_power_up_bus(struct i810_card *card)
         */     
        /* see i810_ac97_init for the next 7 lines (jsaw) */
        inw(card->ac97base);
-       if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+       if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5)
            && (card->use_mmio)) {
                primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
                printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
@@ -2873,7 +2855,7 @@ static int __init i810_ac97_init(struct i810_card *card)
                   possible IO channels. Bit 0:1 of SDM then holds the 
                   last codec ID spoken to. 
                */
-               if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+               if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5)
                    && (card->use_mmio)) {
                        ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
                        printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
@@ -2892,9 +2874,8 @@ static int __init i810_ac97_init(struct i810_card *card)
                                printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
                }
                
-               if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+               if ((codec = ac97_alloc_codec()) == NULL)
                        return -ENOMEM;
-               memset(codec, 0, sizeof(struct ac97_codec));
 
                /* initialize some basic codec information, other fields will be filled
                   in ac97_probe_codec */
@@ -2913,7 +2894,7 @@ static int __init i810_ac97_init(struct i810_card *card)
        
                if(!i810_ac97_probe_and_powerup(card,codec)) {
                        printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
-                       kfree(codec);
+                       ac97_release_codec(codec);
                        break;  /* it didn't work */
                }
                /* Store state information about S/PDIF transmitter */
@@ -2922,32 +2903,22 @@ static int __init i810_ac97_init(struct i810_card *card)
                /* Don't attempt to get eid until powerup is complete */
                eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
 
-               if(eid==0xFFFFFF)
+               if(eid==0xFFFF)
                {
                        printk(KERN_WARNING "i810_audio: no codec attached ?\n");
-                       kfree(codec);
+                       ac97_release_codec(codec);
                        break;
                }
                
                /* Check for an AC97 1.0 soft modem (ID1) */
                
-               if(codec->codec_read(codec, AC97_RESET) & 2)
+               if(codec->modem)
                {
-                       printk(KERN_WARNING "i810_audio: codec %d is an AC97 1.0 softmodem - skipping.\n", ac97_id);
-                       kfree(codec);
+                       printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
+                       ac97_release_codec(codec);
                        continue;
                }
                
-               /* Check for an AC97 2.x soft modem */
-               
-               codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-               if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
-               {
-                       printk(KERN_WARNING "i810_audio: codec %d is an AC97 2.x softmodem - skipping.\n", ac97_id);
-                       kfree(codec);
-                       continue;
-               }
-       
                card->ac97_features = eid;
 
                /* Now check the codec for useful features to make up for
@@ -3027,7 +2998,7 @@ static int __init i810_ac97_init(struct i810_card *card)
 
                if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
                        printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
-                       kfree(codec);
+                       ac97_release_codec(codec);
                        break;
                }
 
@@ -3158,6 +3129,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id
        card->pm_suspended=0;
 #endif
        spin_lock_init(&card->lock);
+       spin_lock_init(&card->ac97_lock);
        devs = card;
 
        pci_set_master(pci_dev);
@@ -3253,7 +3225,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id
                for (i = 0; i < NR_AC97; i++)
                if (card->ac97_codec[i] != NULL) {
                        unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       kfree (card->ac97_codec[i]);
+                       ac97_release_codec(card->ac97_codec[i]);
                }
                goto out_iospace;
        }
@@ -3297,7 +3269,7 @@ static void __devexit i810_remove(struct pci_dev *pci_dev)
        for (i = 0; i < NR_AC97; i++)
                if (card->ac97_codec[i] != NULL) {
                        unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       kfree (card->ac97_codec[i]);
+                       ac97_release_codec(card->ac97_codec[i]);
                        card->ac97_codec[i] = NULL;
                }
        unregister_sound_dsp(card->dev_audio);