Commit 4a6b58ed authored by Alan Cox's avatar Alan Cox Committed by Steve French

[PATCH] update the i810 audio driver

parent dbf3cb27
...@@ -117,6 +117,9 @@ ...@@ -117,6 +117,9 @@
#ifndef PCI_DEVICE_ID_INTEL_ICH4 #ifndef PCI_DEVICE_ID_INTEL_ICH4
#define PCI_DEVICE_ID_INTEL_ICH4 0x24c5 #define PCI_DEVICE_ID_INTEL_ICH4 0x24c5
#endif #endif
#ifndef PCI_DEVICE_ID_INTEL_ICH5
#define PCI_DEVICE_ID_INTEL_ICH5 0x24d5
#endif
#ifndef PCI_DEVICE_ID_INTEL_440MX #ifndef PCI_DEVICE_ID_INTEL_440MX
#define PCI_DEVICE_ID_INTEL_440MX 0x7195 #define PCI_DEVICE_ID_INTEL_440MX 0x7195
#endif #endif
...@@ -272,6 +275,7 @@ enum { ...@@ -272,6 +275,7 @@ enum {
INTELICH2, INTELICH2,
INTELICH3, INTELICH3,
INTELICH4, INTELICH4,
INTELICH5,
SI7012, SI7012,
NVIDIA_NFORCE, NVIDIA_NFORCE,
AMD768, AMD768,
...@@ -285,6 +289,7 @@ static char * card_names[] = { ...@@ -285,6 +289,7 @@ static char * card_names[] = {
"Intel ICH2", "Intel ICH2",
"Intel ICH3", "Intel ICH3",
"Intel ICH4", "Intel ICH4",
"Intel ICH5",
"SiS 7012", "SiS 7012",
"NVIDIA nForce Audio", "NVIDIA nForce Audio",
"AMD 768", "AMD 768",
...@@ -304,6 +309,7 @@ static struct { ...@@ -304,6 +309,7 @@ static struct {
{ 1, 0x0000 }, /* INTELICH2 */ { 1, 0x0000 }, /* INTELICH2 */
{ 2, 0x0000 }, /* INTELICH3 */ { 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 }, /* SI7012 */
/*@FIXME to be verified*/ { 2, 0x0000 }, /* NVIDIA_NFORCE */ /*@FIXME to be verified*/ { 2, 0x0000 }, /* NVIDIA_NFORCE */
/*@FIXME to be verified*/ { 2, 0x0000 }, /* AMD768 */ /*@FIXME to be verified*/ { 2, 0x0000 }, /* AMD768 */
...@@ -323,6 +329,8 @@ static struct pci_device_id i810_pci_tbl [] __initdata = { ...@@ -323,6 +329,8 @@ static struct pci_device_id i810_pci_tbl [] __initdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3}, PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH4, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, 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_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012}, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
...@@ -420,6 +428,9 @@ struct i810_card { ...@@ -420,6 +428,9 @@ struct i810_card {
so we use a single per card lock */ so we use a single per card lock */
spinlock_t lock; spinlock_t lock;
/* Control AC97 access serialization */
spinlock_t ac97_lock;
/* PCI device stuff */ /* PCI device stuff */
struct pci_dev * pci_dev; struct pci_dev * pci_dev;
u16 pci_id; u16 pci_id;
...@@ -547,80 +558,42 @@ static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate ) ...@@ -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 * The DSP sample rate must already be set to a supported
* S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. * 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 vol;
int aud_reg; int aud_reg;
int r = 0;
struct ac97_codec *codec = state->card->ac97_codec[0]; struct ac97_codec *codec = state->card->ac97_codec[0];
if(!(state->card->ac97_features & 4)) { if(!codec->codec_ops->digital) {
#ifdef DEBUG
printk(KERN_WARNING "i810_audio: S/PDIF transmitter not available.\n");
#endif
state->card->ac97_status &= ~SPDIF_ON; state->card->ac97_status &= ~SPDIF_ON;
} else { } else {
if ( slots == -1 ) { /* Turn off S/PDIF */ if ( slots == -1 ) { /* Turn off S/PDIF */
aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS); codec->codec_ops->digital(codec, 0, 0, 0);
i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
/* If the volume wasn't muted before we turned on S/PDIF, unmute it */ /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
if ( !(state->card->ac97_status & VOL_MUTED) ) { if ( !(state->card->ac97_status & VOL_MUTED) ) {
aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO); aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED)); i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
} }
state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON); state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
return; return 0;
} }
vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO); vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
state->card->ac97_status = vol & VOL_MUTED; state->card->ac97_status = vol & VOL_MUTED;
/* Set S/PDIF transmitter sample rate */ r = codec->codec_ops->digital(codec, slots, rate, 0);
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); if(r)
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; state->card->ac97_status |= SPDIF_ON;
else
/* 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
/* turn off S/PDIF */
i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
state->card->ac97_status &= ~SPDIF_ON; state->card->ac97_status &= ~SPDIF_ON;
return;
}
/* Mute the analog output */ /* Mute the analog output */
/* Should this only mute the PCM volume??? */ /* Should this only mute the PCM volume??? */
i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED)); i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
} }
return r;
} }
/* i810_set_dac_channels /* i810_set_dac_channels
...@@ -644,6 +617,7 @@ static void i810_set_dac_channels(struct i810_state *state, int channel) ...@@ -644,6 +617,7 @@ static void i810_set_dac_channels(struct i810_state *state, int channel)
struct ac97_codec *codec = state->card->ac97_codec[0]; struct ac97_codec *codec = state->card->ac97_codec[0];
/* No codec, no setup */ /* No codec, no setup */
if(codec == NULL) if(codec == NULL)
return; return;
...@@ -1835,6 +1809,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -1835,6 +1809,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
} }
spin_unlock_irqrestore(&state->card->lock, flags); spin_unlock_irqrestore(&state->card->lock, flags);
synchronize_irq(state->card->pci_dev->irq);
dmabuf->ready = 0; dmabuf->ready = 0;
dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->swptr = dmabuf->hwptr = 0;
dmabuf->count = dmabuf->total_bytes = 0; dmabuf->count = dmabuf->total_bytes = 0;
...@@ -2493,11 +2468,9 @@ static int i810_open(struct inode *inode, struct file *file) ...@@ -2493,11 +2468,9 @@ static int i810_open(struct inode *inode, struct file *file)
} }
if(file->f_mode & FMODE_WRITE) { if(file->f_mode & FMODE_WRITE) {
if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { 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) if(file->f_mode & FMODE_READ)
card->free_pcm_channel(card, card->free_pcm_channel(card,dmabuf->read_channel->num);
dmabuf->read_channel->num);
kfree (card->states[i]); kfree (card->states[i]);
card->states[i] = NULL;; card->states[i] = NULL;;
return -EBUSY; return -EBUSY;
...@@ -2641,23 +2614,32 @@ static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data) ...@@ -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) static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
{ {
struct i810_card *card = dev->private_data; struct i810_card *card = dev->private_data;
u16 ret;
spin_lock(&card->ac97_lock);
if (card->use_mmio) { if (card->use_mmio) {
return i810_ac97_get_mmio(dev, reg); ret = i810_ac97_get_mmio(dev, reg);
} }
else { 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) static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
{ {
struct i810_card *card = dev->private_data; struct i810_card *card = dev->private_data;
spin_lock(&card->ac97_lock);
if (card->use_mmio) { if (card->use_mmio) {
i810_ac97_set_mmio(dev, reg, data); i810_ac97_set_mmio(dev, reg, data);
} }
else { else {
i810_ac97_set_io(dev, reg, data); 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) ...@@ -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) */ /* see i810_ac97_init for the next 7 lines (jsaw) */
inw(card->ac97base); 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)) { && (card->use_mmio)) {
primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3; primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
printk(KERN_INFO "i810_audio: Primary codec has ID %d\n", 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) ...@@ -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 possible IO channels. Bit 0:1 of SDM then holds the
last codec ID spoken to. 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)) { && (card->use_mmio)) {
ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3; ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n", 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) ...@@ -2892,9 +2874,8 @@ static int __init i810_ac97_init(struct i810_card *card)
printk(KERN_ERR "i810_audio: Primary codec not ready.\n"); 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; return -ENOMEM;
memset(codec, 0, sizeof(struct ac97_codec));
/* initialize some basic codec information, other fields will be filled /* initialize some basic codec information, other fields will be filled
in ac97_probe_codec */ in ac97_probe_codec */
...@@ -2913,7 +2894,7 @@ static int __init i810_ac97_init(struct i810_card *card) ...@@ -2913,7 +2894,7 @@ static int __init i810_ac97_init(struct i810_card *card)
if(!i810_ac97_probe_and_powerup(card,codec)) { if(!i810_ac97_probe_and_powerup(card,codec)) {
printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id); 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 */ break; /* it didn't work */
} }
/* Store state information about S/PDIF transmitter */ /* Store state information about S/PDIF transmitter */
...@@ -2922,29 +2903,19 @@ static int __init i810_ac97_init(struct i810_card *card) ...@@ -2922,29 +2903,19 @@ static int __init i810_ac97_init(struct i810_card *card)
/* Don't attempt to get eid until powerup is complete */ /* Don't attempt to get eid until powerup is complete */
eid = i810_ac97_get(codec, AC97_EXTENDED_ID); eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
if(eid==0xFFFFFF) if(eid==0xFFFF)
{ {
printk(KERN_WARNING "i810_audio: no codec attached ?\n"); printk(KERN_WARNING "i810_audio: no codec attached ?\n");
kfree(codec); ac97_release_codec(codec);
break; break;
} }
/* Check for an AC97 1.0 soft modem (ID1) */ /* 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);
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); printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
kfree(codec); ac97_release_codec(codec);
continue; continue;
} }
...@@ -3027,7 +2998,7 @@ static int __init i810_ac97_init(struct i810_card *card) ...@@ -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) { if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
printk(KERN_ERR "i810_audio: couldn't register mixer!\n"); printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
kfree(codec); ac97_release_codec(codec);
break; break;
} }
...@@ -3158,6 +3129,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id ...@@ -3158,6 +3129,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id
card->pm_suspended=0; card->pm_suspended=0;
#endif #endif
spin_lock_init(&card->lock); spin_lock_init(&card->lock);
spin_lock_init(&card->ac97_lock);
devs = card; devs = card;
pci_set_master(pci_dev); pci_set_master(pci_dev);
...@@ -3253,7 +3225,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id ...@@ -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++) for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL) { if (card->ac97_codec[i] != NULL) {
unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
kfree (card->ac97_codec[i]); ac97_release_codec(card->ac97_codec[i]);
} }
goto out_iospace; goto out_iospace;
} }
...@@ -3297,7 +3269,7 @@ static void __devexit i810_remove(struct pci_dev *pci_dev) ...@@ -3297,7 +3269,7 @@ static void __devexit i810_remove(struct pci_dev *pci_dev)
for (i = 0; i < NR_AC97; i++) for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL) { if (card->ac97_codec[i] != NULL) {
unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); 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; card->ac97_codec[i] = NULL;
} }
unregister_sound_dsp(card->dev_audio); unregister_sound_dsp(card->dev_audio);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment