patch-2.3.99-pre7 linux/drivers/sound/trident.c
Next file: linux/drivers/sound/trident.h
Previous file: linux/drivers/sound/sys_timer.c
Back to the patch index
Back to the overall index
- Lines: 265
- Date:
Wed May 10 16:56:43 2000
- Orig file:
v2.3.99-pre6/linux/drivers/sound/trident.c
- Orig date:
Wed Apr 26 16:34:08 2000
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/trident.c linux/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 @@
/* 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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 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 @@
if (dmabuf->channel == NULL) {
kfree (card->states[i]);
- card->states[i] = NULL;;
+ card->states[i] = NULL;
return -ENODEV;
}
@@ -1954,6 +1987,11 @@
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 @@
}
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 @@
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);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)