summaryrefslogtreecommitdiffstats
path: root/drivers/sound/trident.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
commitba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch)
tree78670a0139bf4d5ace617b29b7eba82bbc74d602 /drivers/sound/trident.c
parentb77bf69998121e689c5e86cc5630d39a0a9ee6ca (diff)
Merge with Linux 2.3.99-pre7 and various other bits.
Diffstat (limited to 'drivers/sound/trident.c')
-rw-r--r--drivers/sound/trident.c128
1 files changed, 84 insertions, 44 deletions
diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c
index 575a65616..a1f462f3b 100644
--- a/drivers/sound/trident.c
+++ b/drivers/sound/trident.c
@@ -101,6 +101,7 @@
#include <linux/ac97_codec.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
+#include <linux/bitops.h>
#include "trident.h"
@@ -284,7 +285,7 @@ struct trident_card {
/* Function support */
struct trident_channel *(*alloc_pcm_channel)(struct trident_card *);
struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *);
- void (*free_pcm_channel)(struct trident_card *, int chan);
+ void (*free_pcm_channel)(struct trident_card *, unsigned int chan);
void (*address_interrupt)(struct trident_card *);
};
@@ -434,13 +435,19 @@ static void trident_stop_voice(struct trident_card * card, unsigned int channel)
#endif
}
-static int trident_check_channel_interrupt(struct trident_card * card, int channel)
+static u32 trident_get_interrupt_mask (struct trident_card * card,
+ unsigned int b)
{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 reg, addr = bank->addresses->aint;
+ struct trident_pcm_bank *bank = &card->banks[b];
+ u32 addr = bank->addresses->aint;
+ return inl(TRID_REG(card, addr));
+}
- reg = inl(TRID_REG(card, addr));
+static int trident_check_channel_interrupt(struct trident_card * card,
+ unsigned int channel)
+{
+ unsigned int mask = 1 << (channel & 0x1f);
+ u32 reg = trident_get_interrupt_mask (card, channel >> 5);
#ifdef DEBUG
if (reg & mask)
@@ -450,7 +457,8 @@ static int trident_check_channel_interrupt(struct trident_card * card, int chann
return (reg & mask) ? TRUE : FALSE;
}
-static void trident_ack_channel_interrupt(struct trident_card * card, int channel)
+static void trident_ack_channel_interrupt(struct trident_card * card,
+ unsigned int channel)
{
unsigned int mask = 1 << (channel & 0x1f);
struct trident_pcm_bank *bank = &card->banks[channel >> 5];
@@ -473,11 +481,7 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c
int idx;
bank = &card->banks[BANK_B];
- if (bank->bitmap == ~0UL) {
- /* no more free channels avaliable */
- printk(KERN_ERR "trident: no more channels available on Bank B.\n");
- return NULL;
- }
+
for (idx = 31; idx >= 0; idx--) {
if (!(bank->bitmap & (1 << idx))) {
struct trident_channel *channel = &bank->channels[idx];
@@ -486,6 +490,9 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c
return channel;
}
}
+
+ /* no more free channels avaliable */
+ printk(KERN_ERR "trident: no more channels available on Bank B.\n");
return NULL;
}
@@ -496,12 +503,7 @@ static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card)
bank = &card->banks[BANK_A];
- if (bank->bitmap == ~0UL) {
- /* no more free channels avaliable */
- printk(KERN_ERR "trident: no more channels available on Bank B.\n");
- return NULL;
- }
- for (idx = 0; idx <= 31; idx++) {
+ for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) {
if (!(bank->bitmap & (1 << idx))) {
struct trident_channel *channel = &bank->channels[idx];
bank->bitmap |= 1 << idx;
@@ -509,6 +511,9 @@ static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card)
return channel;
}
}
+
+ /* no more free channels avaliable */
+ printk(KERN_ERR "trident: no more channels available on Bank B.\n");
return NULL;
}
@@ -529,7 +534,8 @@ static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *ca
}
-static void trident_free_pcm_channel(struct trident_card *card, int channel)
+static void trident_free_pcm_channel(struct trident_card *card,
+ unsigned int channel)
{
int bank;
@@ -539,12 +545,10 @@ static void trident_free_pcm_channel(struct trident_card *card, int channel)
bank = channel >> 5;
channel = channel & 0x1f;
- if (card->banks[bank].bitmap & (1 << (channel))) {
- card->banks[bank].bitmap &= ~(1 << (channel));
- }
+ card->banks[bank].bitmap &= ~(1 << (channel));
}
-static void ali_free_pcm_channel(struct trident_card *card, int channel)
+static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel)
{
int bank;
@@ -554,9 +558,7 @@ static void ali_free_pcm_channel(struct trident_card *card, int channel)
bank = channel >> 5;
channel = channel & 0x1f;
- if (card->banks[bank].bitmap & (1 << (channel))) {
- card->banks[bank].bitmap &= ~(1 << (channel));
- }
+ card->banks[bank].bitmap &= ~(1 << (channel));
}
@@ -569,14 +571,16 @@ static int trident_load_channel_registers(struct trident_card *card, u32 *data,
if (channel > 63)
return FALSE;
- /* select hardware channel to write */
+ /* select hardware channel to write */
outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
- /* output the channel registers */
+
+ /* Output the channel registers, but don't write register
+ three to an ALI chip. */
+
for (i = 0; i < CHANNEL_REGS; i++) {
+ if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451)
+ continue;
outl(data[i], TRID_REG(card, CHANNEL_START + 4*i));
- if (i == 2)
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451)
- i++; //skip i=3
}
return TRUE;
@@ -1229,21 +1233,50 @@ static void trident_address_interrupt(struct trident_card *card)
static void ali_address_interrupt(struct trident_card *card)
{
int i;
- struct trident_state *state;
-
+ u32 mask = trident_get_interrupt_mask (card, BANK_A);
+
+#ifdef DEBUG
+ /* Sanity check to make sure that every state has a channel
+ and vice versa. */
+ u32 done = 0;
+ unsigned ns = 0;
+ unsigned nc = 0;
for (i = 0; i < NR_HW_CH; i++) {
- if (trident_check_channel_interrupt(card, i)) {
- trident_ack_channel_interrupt(card, i);
- if ((state = card->states[i]) != NULL) {
- state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
- trident_update_ptr(state);
- } else {
+ if (card->banks[BANK_A].bitmap & (1<<i))
+ nc ++;
+
+ if (card->states[i]) {
+ u32 bit = 1 << card->states[i]->dmabuf.channel->num;
+ if (bit & done)
+ printk (KERN_ERR "trident: channel allocated to two states\n");
+ ns++;
+
+ done |= bit;
+ }
+ }
+ if (ns != nc)
+ printk (KERN_ERR "trident: number of states != number of channels\n");
+#endif
+
+ for (i = 0; mask && i < NR_HW_CH; i++) {
+ struct trident_state *state = card->states[i];
+ if (!state)
+ continue;
+
+ trident_ack_channel_interrupt(card, state->dmabuf.channel->num);
+ mask &= ~ (1<<state->dmabuf.channel->num);
+ state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
+ trident_update_ptr(state);
+ }
+
+ if (mask)
+ for (i = 0; i < NR_HW_CH; i++)
+ if (mask & (1<<i)) {
printk("ali: spurious channel irq %d.\n", i);
trident_stop_voice(card, i);
trident_disable_voice_irq(card, i);
}
- }
- }
+
}
static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -1897,7 +1930,7 @@ static int trident_open(struct inode *inode, struct file *file)
if (dmabuf->channel == NULL) {
kfree (card->states[i]);
- card->states[i] = NULL;;
+ card->states[i] = NULL;
return -ENODEV;
}
@@ -1954,6 +1987,11 @@ static int trident_open(struct inode *inode, struct file *file)
state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
up(&state->open_sem);
+#ifdef DEBUG
+ printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n",
+ state->virt,
+ dmabuf->channel->num);
+#endif
MOD_INC_USE_COUNT;
return 0;
}
@@ -2343,13 +2381,16 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
}
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
- iobase = pci_dev->resource[0].start;
+ iobase = pci_resource_start (pci_dev, 0);
if (check_region(iobase, 256)) {
printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
iobase);
return -ENODEV;
}
+ if (pci_enable_device(pci_dev))
+ return -ENODEV;
+
if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "trident: out of memory\n");
return -ENOMEM;
@@ -2371,7 +2412,6 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
devs = card;
pci_set_master(pci_dev);
- pci_enable_device(pci_dev);
printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
card_names[pci_id->driver_data], card->iobase, card->irq);