Commit 789672c3 authored by Muli Ben-Yehuda's avatar Muli Ben-Yehuda Committed by Linus Torvalds

[PATCH] sound/oss/trident.c [1/2] merge driver from 2.4-ac

This patch (1/2) brings the sound/oss/trident.c driver up to date with
the driver in the 2.4-ac tree. It fixes the following bugs:

* fix wrong cast in suspend/resume (Eric Lemar via Ian Soboroff)

* fix bug where we would free with free_pages() memory allocated via
pci_alloc_consistent().

* add a missing unlock on an error path.

* rewrite the code to read/write registers of audio codecs for Ali5451
(Lei Hu)

It also does various cleanups so that the code conforms to
Documentation/CodingStyle and is nicer to work with.
parent 61887e47
...@@ -36,6 +36,35 @@ ...@@ -36,6 +36,35 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* History * History
* v0.14.10f
* July 24 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* patch from Eric Lemar (via Ian Soboroff): in suspend and resume,
* fix wrong cast from pci_dev* to struct trident_card*.
* v0.14.10e
* July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* rewrite the DMA buffer allocation/deallcoation functions, to make it
* modular and fix a bug where we would call free_pages on memory
* obtained with pci_alloc_consistent. Also remove unnecessary #ifdef
* CONFIG_PROC_FS and various other cleanups.
* v0.14.10d
* July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* made several printk(KERN_NOTICE...) into TRDBG(...), to avoid spamming
* my syslog with hundreds of messages.
* v0.14.10c
* July 16 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* Cleaned up Lei Hu's 0.4.10 driver to conform to Documentation/CodingStyle
* and the coding style used in the rest of the file.
* v0.14.10b
* June 23 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* add a missing unlock_set_fmt, remove a superflous lock/unlock pair
* with nothing in between.
* v0.14.10a
* June 21 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* use a debug macro instead of #ifdef CONFIG_DEBUG, trim to 80 columns
* per line, use 'do {} while (0)' in statement macros.
* v0.14.10
* June 6 2002 Lei Hu <Lei_hu@ali.com.tw>
* rewrite the part to read/write registers of audio codec for Ali5451
* v0.14.9e * v0.14.9e
* January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport * January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport
* support to avoid resource conflict with pcigame.c * support to avoid resource conflict with pcigame.c
...@@ -161,20 +190,21 @@ ...@@ -161,20 +190,21 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/soundcard.h> #include <linux/soundcard.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/ac97_codec.h> #include <linux/ac97_codec.h>
#include <linux/wrapper.h> #include <linux/wrapper.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/gameport.h> #include <linux/gameport.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <asm/io.h>
#include <asm/dma.h>
#if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC #if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC
#include <asm/hwrpb.h> #include <asm/hwrpb.h>
...@@ -182,9 +212,7 @@ ...@@ -182,9 +212,7 @@
#include "trident.h" #include "trident.h"
#include <linux/pm.h> #define DRIVER_VERSION "0.14.10f"
#define DRIVER_VERSION "0.14.9e"
/* magic numbers to protect our data structures */ /* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
...@@ -202,7 +230,13 @@ ...@@ -202,7 +230,13 @@
/* minor number of /dev/swmodem (temporary, experimental) */ /* minor number of /dev/swmodem (temporary, experimental) */
#define SND_DEV_SWMODEM 7 #define SND_DEV_SWMODEM 7
static const unsigned ali_multi_channels_5_1[] = { /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/ ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL}; static const unsigned ali_multi_channels_5_1[] = {
/*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/
ALI_CENTER_CHANNEL,
ALI_LEF_CHANNEL,
ALI_SURR_LEFT_CHANNEL,
ALI_SURR_RIGHT_CHANNEL
};
static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 };
...@@ -292,7 +326,7 @@ struct trident_state { ...@@ -292,7 +326,7 @@ struct trident_state {
} dmabuf; } dmabuf;
/* 5.1channels */ /* 5.1 channels */
struct trident_state *other_states[4]; struct trident_state *other_states[4];
int multi_channels_adjust_count; int multi_channels_adjust_count;
unsigned chans_num; unsigned chans_num;
...@@ -319,6 +353,7 @@ struct trident_pcm_bank_address { ...@@ -319,6 +353,7 @@ struct trident_pcm_bank_address {
u32 aint; u32 aint;
u32 aint_en; u32 aint_en;
}; };
static struct trident_pcm_bank_address bank_a_addrs = static struct trident_pcm_bank_address bank_a_addrs =
{ {
T4D_START_A, T4D_START_A,
...@@ -326,6 +361,7 @@ static struct trident_pcm_bank_address bank_a_addrs = ...@@ -326,6 +361,7 @@ static struct trident_pcm_bank_address bank_a_addrs =
T4D_AINT_A, T4D_AINT_A,
T4D_AINTEN_A T4D_AINTEN_A
}; };
static struct trident_pcm_bank_address bank_b_addrs = static struct trident_pcm_bank_address bank_b_addrs =
{ {
T4D_START_B, T4D_START_B,
...@@ -333,6 +369,7 @@ static struct trident_pcm_bank_address bank_b_addrs = ...@@ -333,6 +369,7 @@ static struct trident_pcm_bank_address bank_b_addrs =
T4D_AINT_B, T4D_AINT_B,
T4D_AINTEN_B T4D_AINTEN_B
}; };
struct trident_pcm_bank { struct trident_pcm_bank {
/* register addresses to control bank operations */ /* register addresses to control bank operations */
struct trident_pcm_bank_address *addresses; struct trident_pcm_bank_address *addresses;
...@@ -398,6 +435,7 @@ static u16 mask2attr [] = ...@@ -398,6 +435,7 @@ static u16 mask2attr [] =
HSET, MIC, MODEM_LINE1, MODEM_LINE2, HSET, MIC, MODEM_LINE1, MODEM_LINE2,
I2S_LR, SPDIF_LR I2S_LR, SPDIF_LR
}; };
/* table to map from channel attribute to CHANNELMASK for SiS 7018 */ /* table to map from channel attribute to CHANNELMASK for SiS 7018 */
static int attr2mask [] = { static int attr2mask [] = {
DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET, DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET,
...@@ -406,7 +444,7 @@ static int attr2mask [] = { ...@@ -406,7 +444,7 @@ static int attr2mask [] = {
/* Added by Matt Wu 01-05-2001 for spdif in */ /* Added by Matt Wu 01-05-2001 for spdif in */
static int ali_close_multi_channels(void); static int ali_close_multi_channels(void);
static void ali_delay(struct trident_card *card,int interval); static void ali_delay(struct trident_card *card, int interval);
static void ali_detect_spdif_rate(struct trident_card *card); static void ali_detect_spdif_rate(struct trident_card *card);
static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val); static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val);
...@@ -438,8 +476,11 @@ static void ali_setup_spdif_in(struct trident_card *card); ...@@ -438,8 +476,11 @@ static void ali_setup_spdif_in(struct trident_card *card);
static void ali_disable_spdif_in(struct trident_card *card); static void ali_disable_spdif_in(struct trident_card *card);
static void ali_disable_special_channel(struct trident_card *card, int ch); static void ali_disable_special_channel(struct trident_card *card, int ch);
static void ali_setup_spdif_out(struct trident_card *card, int flag); static void ali_setup_spdif_out(struct trident_card *card, int flag);
static int ali_write_5_1(struct trident_state *state, const char *buffer,int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt); static int ali_write_5_1(struct trident_state *state, const char *buffer,
static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums); int cnt_for_multi_channel, unsigned int *copy_count,
unsigned int *state_cnt);
static int ali_allocate_other_states_resources(struct trident_state *state,
int chan_nums);
static void ali_free_other_states_resources(struct trident_state *state); static void ali_free_other_states_resources(struct trident_state *state);
...@@ -450,22 +491,29 @@ static struct ali_saved_registers { ...@@ -450,22 +491,29 @@ static struct ali_saved_registers {
unsigned mixer_regs[ALI_MIXER_REGS]; unsigned mixer_regs[ALI_MIXER_REGS];
} ali_registers; } ali_registers;
#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) (dma_ptr) += (offset); \ #define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) do { \
(buffer) += (offset); \ (dma_ptr) += (offset); \
(cnt) -= (offset); \ (buffer) += (offset); \
(copy_count) += (offset); (cnt) -= (offset); \
(copy_count) += (offset); \
#define lock_set_fmt(state) {spin_lock_irqsave(&state->card->lock, flags); \ } while (0)
if (state->fmt_flag) { \
spin_unlock_irqrestore(&state->card->lock, flags); \
return -EFAULT; \ #define lock_set_fmt(state) do { \
} \ spin_lock_irqsave(&state->card->lock, flags); \
state->fmt_flag = 1; \ if (state->fmt_flag) { \
spin_unlock_irqrestore(&state->card->lock, flags);} spin_unlock_irqrestore(&state->card->lock, flags); \
return -EFAULT; \
} \
state->fmt_flag = 1; \
spin_unlock_irqrestore(&state->card->lock, flags); \
} while (0)
#define unlock_set_fmt(state) {spin_lock_irqsave(&state->card->lock, flags); \ #define unlock_set_fmt(state) do { \
state->fmt_flag = 0; \ spin_lock_irqsave(&state->card->lock, flags); \
spin_unlock_irqrestore(&state->card->lock, flags);} state->fmt_flag = 0; \
spin_unlock_irqrestore(&state->card->lock, flags); \
} while (0)
static int trident_enable_loop_interrupts(struct trident_card * card) static int trident_enable_loop_interrupts(struct trident_card * card)
{ {
...@@ -490,10 +538,9 @@ static int trident_enable_loop_interrupts(struct trident_card * card) ...@@ -490,10 +538,9 @@ static int trident_enable_loop_interrupts(struct trident_card * card)
outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR)); outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
#ifdef DEBUG TRDBG("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n", inl(TRID_REG(card, T4D_LFO_GC_CIR)));
inl(TRID_REG(card, T4D_LFO_GC_CIR)));
#endif
return (TRUE); return (TRUE);
} }
...@@ -505,10 +552,9 @@ static int trident_disable_loop_interrupts(struct trident_card * card) ...@@ -505,10 +552,9 @@ static int trident_disable_loop_interrupts(struct trident_card * card)
global_control &= ~(ENDLP_IE | MIDLP_IE); global_control &= ~(ENDLP_IE | MIDLP_IE);
outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR)); outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
#ifdef DEBUG TRDBG("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n", global_control);
global_control);
#endif
return (TRUE); return (TRUE);
} }
...@@ -524,9 +570,9 @@ static void trident_enable_voice_irq(struct trident_card * card, unsigned int ch ...@@ -524,9 +570,9 @@ static void trident_enable_voice_irq(struct trident_card * card, unsigned int ch
#ifdef DEBUG #ifdef DEBUG
reg = inl(TRID_REG(card, addr)); reg = inl(TRID_REG(card, addr));
printk("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", TRDBG("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr); channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
#endif #endif /* DEBUG */
} }
static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel) static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel)
...@@ -544,9 +590,9 @@ static void trident_disable_voice_irq(struct trident_card * card, unsigned int c ...@@ -544,9 +590,9 @@ static void trident_disable_voice_irq(struct trident_card * card, unsigned int c
#ifdef DEBUG #ifdef DEBUG
reg = inl(TRID_REG(card, addr)); reg = inl(TRID_REG(card, addr));
printk("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", TRDBG("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr); channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
#endif #endif /* DEBUG */
} }
static void trident_start_voice(struct trident_card * card, unsigned int channel) static void trident_start_voice(struct trident_card * card, unsigned int channel)
...@@ -557,15 +603,15 @@ static void trident_start_voice(struct trident_card * card, unsigned int channel ...@@ -557,15 +603,15 @@ static void trident_start_voice(struct trident_card * card, unsigned int channel
#ifdef DEBUG #ifdef DEBUG
u32 reg; u32 reg;
#endif #endif /* DEBUG */
outl(mask, TRID_REG(card, addr)); outl(mask, TRID_REG(card, addr));
#ifdef DEBUG #ifdef DEBUG
reg = inl(TRID_REG(card, addr)); reg = inl(TRID_REG(card, addr));
printk("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n", TRDBG("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n",
channel, addr==T4D_START_B? "START_B":"START_A",reg,addr); channel, addr==T4D_START_B? "START_B":"START_A",reg,addr);
#endif #endif /* DEBUG */
} }
static void trident_stop_voice(struct trident_card * card, unsigned int channel) static void trident_stop_voice(struct trident_card * card, unsigned int channel)
...@@ -576,15 +622,15 @@ static void trident_stop_voice(struct trident_card * card, unsigned int channel) ...@@ -576,15 +622,15 @@ static void trident_stop_voice(struct trident_card * card, unsigned int channel)
#ifdef DEBUG #ifdef DEBUG
u32 reg; u32 reg;
#endif #endif /* DEBUG */
outl(mask, TRID_REG(card, addr)); outl(mask, TRID_REG(card, addr));
#ifdef DEBUG #ifdef DEBUG
reg = inl(TRID_REG(card, addr)); reg = inl(TRID_REG(card, addr));
printk("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n", TRDBG("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n",
channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr); channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr);
#endif #endif /* DEBUG */
} }
static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel) static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel)
...@@ -601,9 +647,9 @@ static int trident_check_channel_interrupt(struct trident_card * card, unsigned ...@@ -601,9 +647,9 @@ static int trident_check_channel_interrupt(struct trident_card * card, unsigned
#ifdef DEBUG #ifdef DEBUG
if (reg & mask) if (reg & mask)
printk("trident: channel %d has interrupt, %s = 0x%08x\n", TRDBG("trident: channel %d has interrupt, %s = 0x%08x\n",
channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg); channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg);
#endif #endif /* DEBUG */
return (reg & mask) ? TRUE : FALSE; return (reg & mask) ? TRUE : FALSE;
} }
...@@ -619,9 +665,9 @@ static void trident_ack_channel_interrupt(struct trident_card * card, unsigned i ...@@ -619,9 +665,9 @@ static void trident_ack_channel_interrupt(struct trident_card * card, unsigned i
#ifdef DEBUG #ifdef DEBUG
reg = inl(TRID_REG(card, T4D_AINT_B)); reg = inl(TRID_REG(card, T4D_AINT_B));
printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n", TRDBG("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
channel, reg); channel, reg);
#endif #endif /* DEBUG */
} }
static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card) static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card)
...@@ -869,9 +915,7 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned ...@@ -869,9 +915,7 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned
trident_write_voice_regs(state); trident_write_voice_regs(state);
#ifdef DEBUG TRDBG("trident: called trident_set_dac_rate : rate = %d\n", rate);
printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
#endif
return rate; return rate;
} }
...@@ -891,9 +935,8 @@ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned ...@@ -891,9 +935,8 @@ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned
trident_write_voice_regs(state); trident_write_voice_regs(state);
#ifdef DEBUG TRDBG("trident: called trident_set_adc_rate : rate = %d\n", rate);
printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
#endif
return rate; return rate;
} }
...@@ -935,11 +978,11 @@ static void trident_play_setup(struct trident_state *state) ...@@ -935,11 +978,11 @@ static void trident_play_setup(struct trident_state *state)
if (dmabuf->fmt & TRIDENT_FMT_STEREO) if (dmabuf->fmt & TRIDENT_FMT_STEREO)
/* stereo */ /* stereo */
channel->control |= CHANNEL_STEREO; channel->control |= CHANNEL_STEREO;
#ifdef DEBUG
printk("trident: trident_play_setup, LBA = 0x%08x, " TRDBG("trident: trident_play_setup, LBA = 0x%08x, "
"Delta = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", "Delta = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
channel->lba, channel->delta, channel->eso, channel->control); channel->lba, channel->delta, channel->eso, channel->control);
#endif
trident_write_voice_regs(state); trident_write_voice_regs(state);
} }
...@@ -1021,11 +1064,11 @@ static void trident_rec_setup(struct trident_state *state) ...@@ -1021,11 +1064,11 @@ static void trident_rec_setup(struct trident_state *state)
if (dmabuf->fmt & TRIDENT_FMT_STEREO) if (dmabuf->fmt & TRIDENT_FMT_STEREO)
/* stereo */ /* stereo */
channel->control |= CHANNEL_STEREO; channel->control |= CHANNEL_STEREO;
#ifdef DEBUG
printk("trident: trident_rec_setup, LBA = 0x%08x, " TRDBG("trident: trident_rec_setup, LBA = 0x%08x, "
"Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
channel->lba, channel->delta, channel->eso, channel->control); channel->lba, channel->delta, channel->eso, channel->control);
#endif
trident_write_voice_regs(state); trident_write_voice_regs(state);
} }
...@@ -1058,11 +1101,10 @@ static inline unsigned trident_get_dma_addr(struct trident_state *state) ...@@ -1058,11 +1101,10 @@ static inline unsigned trident_get_dma_addr(struct trident_state *state)
return 0; return 0;
} }
#ifdef DEBUG
printk("trident: trident_get_dma_addr: chip reported channel: %d, " TRDBG("trident: trident_get_dma_addr: chip reported channel: %d, "
"cso = 0x%04x\n", "cso = 0x%04x\n", dmabuf->channel->num, cso);
dmabuf->channel->num, cso);
#endif
/* ESO and CSO are in units of Samples, convert to byte offset */ /* ESO and CSO are in units of Samples, convert to byte offset */
cso <<= sample_shift[dmabuf->fmt]; cso <<= sample_shift[dmabuf->fmt];
...@@ -1160,27 +1202,18 @@ static void start_dac(struct trident_state *state) ...@@ -1160,27 +1202,18 @@ static void start_dac(struct trident_state *state)
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1 #define DMABUF_MINORDER 1
/* allocate DMA buffer, playback and recording buffer should be allocated seperately */ /* alloc a DMA buffer of with a buffer of this order */
static int alloc_dmabuf(struct trident_state *state) static int alloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev, int order)
{ {
struct dmabuf *dmabuf = &state->dmabuf;
void *rawbuf = NULL; void *rawbuf = NULL;
int order;
struct page *page, *pend; struct page *page, *pend;
/* alloc as big a chunk as we can, FIXME: is this necessary ?? */ if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) &dmabuf->dma_handle)))
if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
PAGE_SIZE << order,
&dmabuf->dma_handle)))
break;
if (!rawbuf)
return -ENOMEM; return -ENOMEM;
#ifdef DEBUG TRDBG("trident: allocated %ld (order = %d) bytes at %p\n",
printk("trident: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf);
PAGE_SIZE << order, order, rawbuf);
#endif
dmabuf->ready = dmabuf->mapped = 0; dmabuf->ready = dmabuf->mapped = 0;
dmabuf->rawbuf = rawbuf; dmabuf->rawbuf = rawbuf;
...@@ -1194,21 +1227,37 @@ static int alloc_dmabuf(struct trident_state *state) ...@@ -1194,21 +1227,37 @@ static int alloc_dmabuf(struct trident_state *state)
return 0; return 0;
} }
/* free DMA buffer */ /* allocate the main DMA buffer, playback and recording buffer should be */
static void dealloc_dmabuf(struct trident_state *state) /* allocated seperately */
static int alloc_main_dmabuf(struct trident_state *state)
{ {
struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf = &state->dmabuf;
struct page *page, *pend; int order;
int ret = -ENOMEM;
/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
if (!(ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order)))
return 0;
/* else try again */
}
return ret;
}
/* deallocate a DMA buffer */
static void dealloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev)
{
struct page *page, *pend;
if (dmabuf->rawbuf) { if (dmabuf->rawbuf) {
/* undo marking the pages as reserved */ /* undo marking the pages as reserved */
pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
mem_map_unreserve(page); mem_map_unreserve(page);
pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,
dmabuf->rawbuf, dmabuf->dma_handle); dmabuf->rawbuf, dmabuf->dma_handle);
dmabuf->rawbuf = NULL;
} }
dmabuf->rawbuf = NULL;
dmabuf->mapped = dmabuf->ready = 0; dmabuf->mapped = dmabuf->ready = 0;
} }
...@@ -1220,16 +1269,16 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) ...@@ -1220,16 +1269,16 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
unsigned bufsize, dma_nums; unsigned bufsize, dma_nums;
unsigned long flags; unsigned long flags;
int ret, i, order; int ret, i, order;
struct page *page, *pend;
lock_set_fmt(state); lock_set_fmt(state);
if (state->chans_num == 6) if (state->chans_num == 6)
dma_nums = 5; dma_nums = 5;
else dma_nums = 1; else
dma_nums = 1;
for (i = 0; i < dma_nums; i++) { for (i = 0; i < dma_nums; i++) {
if (i > 0) { if (i > 0) {
s = state->other_states[i - 1]; s = state->other_states[i - 1];
dmabuf = &s->dmabuf; dmabuf = &s->dmabuf;
dmabuf->fmt = state->dmabuf.fmt; dmabuf->fmt = state->dmabuf.fmt;
dmabuf->rate = state->dmabuf.rate; dmabuf->rate = state->dmabuf.rate;
...@@ -1243,35 +1292,25 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) ...@@ -1243,35 +1292,25 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
/* allocate DMA buffer if not allocated yet */ /* allocate DMA buffer if not allocated yet */
if (!dmabuf->rawbuf) { if (!dmabuf->rawbuf) {
if (i == 0) { if (i == 0) {
if ((ret = alloc_dmabuf(state))) { if ((ret = alloc_main_dmabuf(state))) {
unlock_set_fmt(state); unlock_set_fmt(state);
return ret; return ret;
} }
} } else {
else { ret = -ENOMEM;
if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) { if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) {
dmabuf->rawbuf = pci_alloc_consistent(state->card->pci_dev, ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order);
PAGE_SIZE << order,
&dmabuf->dma_handle);
} }
if (!dmabuf->rawbuf) { if (ret) {
free_pages((unsigned long)state->dmabuf.rawbuf, state->dmabuf.buforder); /* release the main DMA buffer */
state->dmabuf.rawbuf = NULL; dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
i-=2; /* release the auxiliary DMA buffers */
for (; i >= 0; i--) { for (i-=2; i >= 0; i--)
pci_free_consistent(state->card->pci_dev, dealloc_dmabuf(&state->other_states[i]->dmabuf,
PAGE_SIZE << state->other_states[i]->dmabuf.buforder, state->card->pci_dev);
state->other_states[i]->dmabuf.rawbuf,
state->other_states[i]->dmabuf.dma_handle);
}
unlock_set_fmt(state); unlock_set_fmt(state);
return -ENOMEM; return ret;
} }
dmabuf->ready = dmabuf->mapped = 0;
dmabuf->buforder = order;
pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
mem_map_reserve(page);
} }
} }
/* FIXME: figure out all this OSS fragment stuff */ /* FIXME: figure out all this OSS fragment stuff */
...@@ -1301,22 +1340,20 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) ...@@ -1301,22 +1340,20 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
dmabuf->dmasize); dmabuf->dmasize);
spin_lock_irqsave(&s->card->lock, flags); spin_lock_irqsave(&s->card->lock, flags);
if (rec) { if (rec)
trident_rec_setup(s); trident_rec_setup(s);
} else { else
trident_play_setup(s); trident_play_setup(s);
}
spin_unlock_irqrestore(&s->card->lock, flags); spin_unlock_irqrestore(&s->card->lock, flags);
/* set the ready flag for the dma buffer */ /* set the ready flag for the dma buffer */
dmabuf->ready = 1; dmabuf->ready = 1;
#ifdef DEBUG TRDBG("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, "
printk("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, " "fragsize = %d dmasize = %d\n",
"fragsize = %d dmasize = %d\n", dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize);
dmabuf->fragsize, dmabuf->dmasize);
#endif
} }
unlock_set_fmt(state); unlock_set_fmt(state);
return 0; return 0;
...@@ -1540,19 +1577,21 @@ static void trident_address_interrupt(struct trident_card *card) ...@@ -1540,19 +1577,21 @@ static void trident_address_interrupt(struct trident_card *card)
{ {
int i; int i;
struct trident_state *state; struct trident_state *state;
unsigned int channel;
/* Update the pointers for all channels we are running. */ /* Update the pointers for all channels we are running. */
/* FIXME: should read interrupt status only once */ /* FIXME: should read interrupt status only once */
for (i = 0; i < NR_HW_CH; i++) { for (i = 0; i < NR_HW_CH; i++) {
if (trident_check_channel_interrupt(card, 63 - i)) { channel = 63 - i;
trident_ack_channel_interrupt(card, 63 - i); if (trident_check_channel_interrupt(card, channel)) {
trident_ack_channel_interrupt(card, channel);
if ((state = card->states[i]) != NULL) { if ((state = card->states[i]) != NULL) {
trident_update_ptr(state); trident_update_ptr(state);
} else { } else {
printk("trident: spurious channel irq %d.\n", printk(KERN_WARNING "trident: spurious channel "
63 - i); "irq %d.\n", channel);
trident_stop_voice(card, 63 - i); trident_stop_voice(card, channel);
trident_disable_voice_irq(card, 63 - i); trident_disable_voice_irq(card, channel);
} }
} }
} }
...@@ -1660,29 +1699,29 @@ static void cyber_address_interrupt(struct trident_card *card) ...@@ -1660,29 +1699,29 @@ static void cyber_address_interrupt(struct trident_card *card)
{ {
int i,irq_status; int i,irq_status;
struct trident_state *state; struct trident_state *state;
unsigned int channel;
/* Update the pointers for all channels we are running. */ /* Update the pointers for all channels we are running. */
/* FIXED: read interrupt status only once */ /* FIXED: read interrupt status only once */
irq_status=inl(TRID_REG(card, T4D_AINT_A) ); irq_status=inl(TRID_REG(card, T4D_AINT_A) );
#ifdef DEBUG
printk("cyber_address_interrupt: irq_status 0x%X\n",irq_status);
#endif
for (i = 0; i < NR_HW_CH; i++) {
if (irq_status & ( 1 << (31 - i)) ) {
TRDBG("cyber_address_interrupt: irq_status 0x%X\n",irq_status);
for (i = 0; i < NR_HW_CH; i++) {
channel = 31 - i;
if (irq_status & ( 1 << channel) ) {
/* clear bit by writing a 1, zeroes are ignored */ /* clear bit by writing a 1, zeroes are ignored */
outl( (1 <<(31-i)), TRID_REG(card, T4D_AINT_A)); outl( (1 << channel), TRID_REG(card, T4D_AINT_A));
#ifdef DEBUG TRDBG("cyber_interrupt: channel %d\n", channel);
printk("cyber_interrupt: channel %d\n", 31-i);
#endif
if ((state = card->states[i]) != NULL) { if ((state = card->states[i]) != NULL) {
trident_update_ptr(state); trident_update_ptr(state);
} else { } else {
printk("cyber5050: spurious channel irq %d.\n", printk(KERN_WARNING "cyber5050: spurious "
31 - i); "channel irq %d.\n", channel);
trident_stop_voice(card, 31 - i); trident_stop_voice(card, channel);
trident_disable_voice_irq(card, 31 - i); trident_disable_voice_irq(card, channel);
} }
} }
} }
...@@ -1697,9 +1736,7 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1697,9 +1736,7 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&card->lock); spin_lock(&card->lock);
event = inl(TRID_REG(card, T4D_MISCINT)); event = inl(TRID_REG(card, T4D_MISCINT));
#ifdef DEBUG TRDBG("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
#endif
if (event & ADDRESS_IRQ) { if (event & ADDRESS_IRQ) {
card->address_interrupt(card); card->address_interrupt(card);
...@@ -1737,9 +1774,7 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ ...@@ -1737,9 +1774,7 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
unsigned swptr; unsigned swptr;
int cnt; int cnt;
#ifdef DEBUG TRDBG("trident: trident_read called, count = %d\n", count);
printk("trident: trident_read called, count = %d\n", count);
#endif
VALIDATE_STATE(state); VALIDATE_STATE(state);
if (ppos != &file->f_pos) if (ppos != &file->f_pos)
...@@ -1793,12 +1828,11 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ ...@@ -1793,12 +1828,11 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
which results in a (potential) buffer overrun. And worse, there is which results in a (potential) buffer overrun. And worse, there is
NOTHING we can do to prevent it. */ NOTHING we can do to prevent it. */
if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
#ifdef DEBUG TRDBG(KERN_ERR "trident: recording schedule timeout, "
printk(KERN_ERR "trident: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
"dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr);
dmabuf->hwptr, dmabuf->swptr);
#endif
/* a buffer overrun, we delay the recovery until next time the /* a buffer overrun, we delay the recovery until next time the
while loop begin and we REALLY have space to record */ while loop begin and we REALLY have space to record */
} }
...@@ -1852,9 +1886,8 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count ...@@ -1852,9 +1886,8 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
unsigned int state_cnt; unsigned int state_cnt;
unsigned int copy_count; unsigned int copy_count;
#ifdef DEBUG TRDBG("trident: trident_write called, count = %d\n", count);
printk("trident: trident_write called, count = %d\n", count);
#endif
VALIDATE_STATE(state); VALIDATE_STATE(state);
if (ppos != &file->f_pos) if (ppos != &file->f_pos)
return -ESPIPE; return -ESPIPE;
...@@ -1922,12 +1955,11 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count ...@@ -1922,12 +1955,11 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
which results in a (potential) buffer underrun. And worse, there is which results in a (potential) buffer underrun. And worse, there is
NOTHING we can do to prevent it. */ NOTHING we can do to prevent it. */
if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
#ifdef DEBUG TRDBG(KERN_ERR "trident: playback schedule timeout, "
printk(KERN_ERR "trident: playback schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
"dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr);
dmabuf->hwptr, dmabuf->swptr);
#endif
/* a buffer underrun, we delay the recovery until next time the /* a buffer underrun, we delay the recovery until next time the
while loop begin and we REALLY have data to play */ while loop begin and we REALLY have data to play */
} }
...@@ -2106,10 +2138,8 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm ...@@ -2106,10 +2138,8 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
VALIDATE_STATE(state); VALIDATE_STATE(state);
mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
((file->f_mode & FMODE_READ) && dmabuf->mapped); ((file->f_mode & FMODE_READ) && dmabuf->mapped);
#ifdef DEBUG TRDBG("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", _IOC_NR(cmd), arg ? *(int *)arg : 0);
_IOC_NR(cmd), arg ? *(int *)arg : 0);
#endif
switch (cmd) switch (cmd)
{ {
...@@ -2269,6 +2299,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm ...@@ -2269,6 +2299,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
{ {
printk(KERN_ERR "trident: Record is working on the card!\n"); printk(KERN_ERR "trident: Record is working on the card!\n");
ret = -EBUSY; ret = -EBUSY;
unlock_set_fmt(state);
break; break;
} }
...@@ -2454,8 +2485,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm ...@@ -2454,8 +2485,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
if (dmabuf->mapped) if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1; dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->card->lock, flags); spin_unlock_irqrestore(&state->card->lock, flags);
ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo))?-EFAULT:0;
-EFAULT : 0;
break; break;
case SNDCTL_DSP_GETOPTR: case SNDCTL_DSP_GETOPTR:
...@@ -2673,10 +2703,8 @@ static int trident_open(struct inode *inode, struct file *file) ...@@ -2673,10 +2703,8 @@ static int trident_open(struct inode *inode, struct file *file)
state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
up(&card->open_sem); up(&card->open_sem);
#ifdef DEBUG TRDBG("trident: open virtual channel %d, hard channel %d\n",
printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n",
state->virt, dmabuf->channel->num); state->virt, dmabuf->channel->num);
#endif
return 0; return 0;
} }
...@@ -2686,7 +2714,6 @@ static int trident_release(struct inode *inode, struct file *file) ...@@ -2686,7 +2714,6 @@ static int trident_release(struct inode *inode, struct file *file)
struct trident_state *state = (struct trident_state *)file->private_data; struct trident_state *state = (struct trident_state *)file->private_data;
struct trident_card *card; struct trident_card *card;
struct dmabuf *dmabuf; struct dmabuf *dmabuf;
unsigned long flags;
lock_kernel(); lock_kernel();
card = state->card; card = state->card;
...@@ -2698,20 +2725,15 @@ static int trident_release(struct inode *inode, struct file *file) ...@@ -2698,20 +2725,15 @@ static int trident_release(struct inode *inode, struct file *file)
drain_dac(state, file->f_flags & O_NONBLOCK); drain_dac(state, file->f_flags & O_NONBLOCK);
} }
#ifdef DEBUG TRDBG("trident: closing virtual channel %d, hard channel %d\n",
printk(KERN_ERR "trident: closing virtual channel %d, hard channel %d\n", state->virt, dmabuf->channel->num);
state->virt, dmabuf->channel->num);
#endif
/* stop DMA state machine and free DMA buffers/channels */ /* stop DMA state machine and free DMA buffers/channels */
down(&card->open_sem); down(&card->open_sem);
if (file->f_mode & FMODE_WRITE) { if (file->f_mode & FMODE_WRITE) {
stop_dac(state); stop_dac(state);
lock_set_fmt(state); dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
unlock_set_fmt(state);
dealloc_dmabuf(state);
state->card->free_pcm_channel(state->card, dmabuf->channel->num); state->card->free_pcm_channel(state->card, dmabuf->channel->num);
/* Added by Matt Wu */ /* Added by Matt Wu */
...@@ -2727,7 +2749,7 @@ static int trident_release(struct inode *inode, struct file *file) ...@@ -2727,7 +2749,7 @@ static int trident_release(struct inode *inode, struct file *file)
} }
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
stop_adc(state); stop_adc(state);
dealloc_dmabuf(state); dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
state->card->free_pcm_channel(state->card, dmabuf->channel->num); state->card->free_pcm_channel(state->card, dmabuf->channel->num);
/* Added by Matt Wu */ /* Added by Matt Wu */
...@@ -2876,62 +2898,74 @@ static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg) ...@@ -2876,62 +2898,74 @@ static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg)
return ((u16) (data >> 16)); return ((u16) (data >> 16));
} }
/* Write AC97 codec registers for ALi*/ /* rewrite ac97 read and write mixer register by hulei for ALI*/
static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val) static int acquirecodecaccess(struct trident_card *card)
{ {
unsigned int address, mask; u16 wsemamask=0x6000; /* bit 14..13 */
unsigned int wCount1 = 0xffff; u16 wsemabits;
unsigned int wCount2= 0xffff; u16 wcontrol ;
unsigned long chk1, chk2; int block = 0;
unsigned long flags; int ncount = 25;
u32 data; while (1) {
wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
data = ((u32) val) << 16; wsemabits = wcontrol & wsemamask;
if(!card)
BUG();
address = ALI_AC97_WRITE;
mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
if (secondary)
mask |= ALI_AC97_SECONDARY;
if (card->revision == ALI_5451_V02)
mask |= ALI_AC97_WRITE_MIXER_REGISTER;
spin_lock_irqsave(&card->lock, flags); if (wsemabits==0x4000)
while (wCount1--) { return 1; /* 0x4000 is audio ,then success */
if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_WRITE) == 0) { if (ncount-- < 0)
data |= (mask | (reg & AC97_REG_ADDR)); break;
if (wsemabits == 0)
chk1 = inl(TRID_REG(card, ALI_STIMER)); {
chk2 = inl(TRID_REG(card, ALI_STIMER)); unlock:
while (wCount2-- && (chk1 == chk2)) outl(((u32)(wcontrol & 0x1eff)|0x00004000), TRID_REG(card, ALI_AC97_WRITE));
chk2 = inl(TRID_REG(card, ALI_STIMER)); continue;
if (wCount2 == 0) {
spin_unlock_irqrestore(&card->lock, flags);
return;
}
outl(data, TRID_REG(card, address)); //write!
spin_unlock_irqrestore(&card->lock, flags);
return; //success
} }
inw(TRID_REG(card, address)); //wait for a read cycle udelay(20);
} }
if(!block)
{
TRDBG("accesscodecsemaphore: try unlock\n");
block = 1;
goto unlock;
}
printk(KERN_ERR "accesscodecsemaphore: fail\n");
return 0;
}
printk(KERN_ERR "ali: AC97 CODEC write timed out.\n"); static void releasecodecaccess(struct trident_card *card)
spin_unlock_irqrestore(&card->lock, flags); {
return; unsigned long wcontrol;
wcontrol = inl(TRID_REG(card, ALI_AC97_WRITE));
outl((wcontrol & 0xffff1eff), TRID_REG(card, ALI_AC97_WRITE));
}
static int waitforstimertick(struct trident_card *card)
{
unsigned long chk1, chk2;
unsigned int wcount = 0xffff;
chk1 = inl(TRID_REG(card, ALI_STIMER));
while(1) {
chk2 = inl(TRID_REG(card, ALI_STIMER));
if( (wcount > 0) && chk1 != chk2)
return 1;
if(wcount <= 0)
break;
udelay(50);
}
printk(KERN_NOTICE "waitforstimertick :BIT_CLK is dead\n");
return 0;
} }
/* Read AC97 codec registers for ALi*/ /* Read AC97 codec registers for ALi*/
static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg) static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
{ {
unsigned int address, mask; unsigned int address, mask;
unsigned int wCount1 = 0xffff; unsigned int ncount;
unsigned int wCount2= 0xffff; unsigned long aud_reg;
unsigned long chk1, chk2;
unsigned long flags;
u32 data; u32 data;
u16 wcontrol;
if(!card) if(!card)
BUG(); BUG();
...@@ -2943,37 +2977,102 @@ static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg) ...@@ -2943,37 +2977,102 @@ static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY; mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY;
if (secondary) if (secondary)
mask |= ALI_AC97_SECONDARY; mask |= ALI_AC97_SECONDARY;
if (!acquirecodecaccess(card))
printk(KERN_ERR "access codec fail\n");
wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
wcontrol &= 0xfe00;
wcontrol |= (0x8000|reg);
outw(wcontrol,TRID_REG(card, ALI_AC97_WRITE));
spin_lock_irqsave(&card->lock, flags);
data = (mask | (reg & AC97_REG_ADDR)); data = (mask | (reg & AC97_REG_ADDR));
while (wCount1--) {
if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) { if(!waitforstimertick(card)) {
chk1 = inl(TRID_REG(card, ALI_STIMER)); printk(KERN_ERR "BIT_CLOCK is dead\n");
chk2 = inl(TRID_REG(card, ALI_STIMER)); goto releasecodec;
while (wCount2-- && (chk1 == chk2)) }
chk2 = inl(TRID_REG(card, ALI_STIMER));
if (wCount2 == 0) { udelay(20);
printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
spin_unlock_irqrestore(&card->lock, flags); ncount=10;
return 0;
} while(1) {
outl(data, TRID_REG(card, address)); //read! if ((inw(TRID_REG(card,ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ) != 0)
wCount2 = 0xffff; break;
while (wCount2--) { if(ncount <=0)
if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) { break;
data = inl(TRID_REG(card, address)); if(ncount--==1) {
spin_unlock_irqrestore(&card->lock, flags); TRDBG("ali_ac97_read :try clear busy flag\n");
return ((u16) (data >> 16)); aud_reg = inl(TRID_REG(card, ALI_AC97_WRITE));
} outl((aud_reg & 0xffff7fff), TRID_REG(card, ALI_AC97_WRITE));
}
} }
inw(TRID_REG(card, address)); //wait a read cycle udelay(10);
} }
spin_unlock_irqrestore(&card->lock, flags);
data = inl(TRID_REG(card, address));
return ((u16) (data >> 16));
releasecodec:
releasecodecaccess(card);
printk(KERN_ERR "ali: AC97 CODEC read timed out.\n"); printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
return 0; return 0;
} }
/* Write AC97 codec registers for hulei*/
static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
{
unsigned int address, mask;
unsigned int ncount;
u32 data;
u16 wcontrol;
data = ((u32) val) << 16;
if(!card)
BUG();
address = ALI_AC97_WRITE;
mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
if (secondary)
mask |= ALI_AC97_SECONDARY;
if (card->revision == ALI_5451_V02)
mask |= ALI_AC97_WRITE_MIXER_REGISTER;
if (!acquirecodecaccess(card))
printk(KERN_ERR "access codec fail\n");
wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
wcontrol &= 0xff00;
wcontrol |= (0x8100|reg);/* bit 8=1: (ali1535 )reserved /ali1535+ write */
outl(( data |wcontrol), TRID_REG(card,ALI_AC97_WRITE ));
if(!waitforstimertick(card)) {
printk(KERN_ERR "BIT_CLOCK is dead\n");
goto releasecodec;
}
ncount = 10;
while(1) {
wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
if(!wcontrol & 0x8000)
break;
if(ncount <= 0)
break;
if(ncount-- == 1) {
TRDBG("ali_ac97_set :try clear busy flag!!\n");
outw(wcontrol & 0x7fff, TRID_REG(card, ALI_AC97_WRITE));
}
udelay(10);
}
releasecodec:
releasecodecaccess(card);
return;
}
static void ali_enable_special_channel(struct trident_state *stat) static void ali_enable_special_channel(struct trident_state *stat)
{ {
struct trident_card *card = stat->card; struct trident_card *card = stat->card;
...@@ -3305,11 +3404,18 @@ static int ali_setup_multi_channels(struct trident_card *card, int chan_nums) ...@@ -3305,11 +3404,18 @@ static int ali_setup_multi_channels(struct trident_card *card, int chan_nums)
ali_ac97_write(card->ac97_codec[0], 0x02, 8080); ali_ac97_write(card->ac97_codec[0], 0x02, 8080);
ali_ac97_write(card->ac97_codec[0], 0x36, 0); ali_ac97_write(card->ac97_codec[0], 0x36, 0);
ali_ac97_write(card->ac97_codec[0], 0x38, 0); ali_ac97_write(card->ac97_codec[0], 0x38, 0);
ali_ac97_write(card->ac97_codec[1], 0x36, 0); /*
ali_ac97_write(card->ac97_codec[1], 0x38, 0); * On a board with a single codec you won't get the
ali_ac97_write(card->ac97_codec[1], 0x02, 0x0606); * surround. On other boards configure it.
ali_ac97_write(card->ac97_codec[1], 0x18, 0x0303); */
ali_ac97_write(card->ac97_codec[1], 0x74, 0x3); if(card->ac97_codec[1]!=NULL)
{
ali_ac97_write(card->ac97_codec[1], 0x36, 0);
ali_ac97_write(card->ac97_codec[1], 0x38, 0);
ali_ac97_write(card->ac97_codec[1], 0x02, 0x0606);
ali_ac97_write(card->ac97_codec[1], 0x18, 0x0303);
ali_ac97_write(card->ac97_codec[1], 0x74, 0x3);
}
return 1; return 1;
} }
} }
...@@ -3464,7 +3570,7 @@ static void ali_restore_regs(struct trident_card *card) ...@@ -3464,7 +3570,7 @@ static void ali_restore_regs(struct trident_card *card)
static int trident_suspend(struct pci_dev *dev, u32 unused) static int trident_suspend(struct pci_dev *dev, u32 unused)
{ {
struct trident_card *card = (struct trident_card *) dev; struct trident_card *card = pci_get_drvdata(dev);
if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { if(card->pci_id == PCI_DEVICE_ID_ALI_5451) {
ali_save_regs(card); ali_save_regs(card);
...@@ -3474,7 +3580,7 @@ static int trident_suspend(struct pci_dev *dev, u32 unused) ...@@ -3474,7 +3580,7 @@ static int trident_suspend(struct pci_dev *dev, u32 unused)
static int trident_resume(struct pci_dev *dev) static int trident_resume(struct pci_dev *dev)
{ {
struct trident_card *card = (struct trident_card *) dev; struct trident_card *card = pci_get_drvdata(dev);
if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { if(card->pci_id == PCI_DEVICE_ID_ALI_5451) {
ali_restore_regs(card); ali_restore_regs(card);
...@@ -3601,7 +3707,10 @@ protection is no harm because all DMAs of multi-channels and interrupt ...@@ -3601,7 +3707,10 @@ protection is no harm because all DMAs of multi-channels and interrupt
depend on a master state's DMA, and changing the counters of the master depend on a master state's DMA, and changing the counters of the master
state DMA is protected by a spinlock. state DMA is protected by a spinlock.
*/ */
static int ali_write_5_1(struct trident_state *state, const char *buf, int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt) static int ali_write_5_1(struct trident_state *state,
const char *buf, int cnt_for_multi_channel,
unsigned int *copy_count,
unsigned int *state_cnt)
{ {
struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf = &state->dmabuf;
...@@ -3707,7 +3816,7 @@ static void ali_free_other_states_resources(struct trident_state *state) ...@@ -3707,7 +3816,7 @@ static void ali_free_other_states_resources(struct trident_state *state)
other_states_count = state->chans_num - 2; /* except PCM L/R channels*/ other_states_count = state->chans_num - 2; /* except PCM L/R channels*/
for ( i = 0; i < other_states_count; i++) { for ( i = 0; i < other_states_count; i++) {
s = state->other_states[i]; s = state->other_states[i];
dealloc_dmabuf(s); dealloc_dmabuf(&s->dmabuf, card->pci_dev);
ali_disable_special_channel(s->card, s->dmabuf.channel->num); ali_disable_special_channel(s->card, s->dmabuf.channel->num);
state->card->free_pcm_channel(s->card, s->dmabuf.channel->num); state->card->free_pcm_channel(s->card, s->dmabuf.channel->num);
card->states[s->virt] = NULL; card->states[s->virt] = NULL;
...@@ -3715,7 +3824,6 @@ static void ali_free_other_states_resources(struct trident_state *state) ...@@ -3715,7 +3824,6 @@ static void ali_free_other_states_resources(struct trident_state *state)
} }
} }
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *res; struct proc_dir_entry *res;
static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{ {
...@@ -3753,7 +3861,6 @@ static int ali_write_proc(struct file *file, const char *buffer, unsigned long c ...@@ -3753,7 +3861,6 @@ static int ali_write_proc(struct file *file, const char *buffer, unsigned long c
return count; return count;
} }
#endif
/* OSS /dev/mixer file operation methods */ /* OSS /dev/mixer file operation methods */
static int trident_open_mixdev(struct inode *inode, struct file *file) static int trident_open_mixdev(struct inode *inode, struct file *file)
...@@ -3821,7 +3928,7 @@ static int ali_reset_5451(struct trident_card *card) ...@@ -3821,7 +3928,7 @@ static int ali_reset_5451(struct trident_card *card)
pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff); pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);
udelay(5000); udelay(5000);
wCount = 200; wCount = 2000;
while(wCount--) { while(wCount--) {
wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL); wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
if((wReg & 0x000f) == 0x000f) if((wReg & 0x000f) == 0x000f)
...@@ -4087,13 +4194,11 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device ...@@ -4087,13 +4194,11 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
/* ALi SPDIF OUT function */ /* ALi SPDIF OUT function */
if(card->revision == ALI_5451_V02) { if(card->revision == ALI_5451_V02) {
ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
#ifdef CONFIG_PROC_FS
res = create_proc_entry("ALi5451", 0, NULL); res = create_proc_entry("ALi5451", 0, NULL);
if (res) { if (res) {
res->write_proc = ali_write_proc; res->write_proc = ali_write_proc;
res->data = card; res->data = card;
} }
#endif
} }
/* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */ /* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
...@@ -4186,7 +4291,7 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device ...@@ -4186,7 +4291,7 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
ali_ac97_set(card, 0, AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); ali_ac97_set(card, 0, AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN);
} }
} }
#endif #endif /* CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC */
/* edited by HMSEO for GT sound*/ /* edited by HMSEO for GT sound*/
} }
rc = 0; rc = 0;
...@@ -4204,12 +4309,10 @@ out: return rc; ...@@ -4204,12 +4309,10 @@ out: return rc;
out_free_irq: out_free_irq:
free_irq(card->irq, card); free_irq(card->irq, card);
out_proc_fs: out_proc_fs:
#ifdef CONFIG_PROC_FS
if (res) { if (res) {
remove_proc_entry("ALi5451", NULL); remove_proc_entry("ALi5451", NULL);
res = NULL; res = NULL;
} }
#endif
kfree(card); kfree(card);
devs = NULL; devs = NULL;
out_release_region: out_release_region:
...@@ -4234,9 +4337,7 @@ static void __devexit trident_remove(struct pci_dev *pci_dev) ...@@ -4234,9 +4337,7 @@ static void __devexit trident_remove(struct pci_dev *pci_dev)
ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL);
ali_disable_spdif_in(card); ali_disable_spdif_in(card);
#ifdef CONFIG_PROC_FS
remove_proc_entry("ALi5451", NULL); remove_proc_entry("ALi5451", NULL);
#endif
} }
/* Unregister gameport */ /* Unregister gameport */
...@@ -4283,8 +4384,9 @@ static int __init trident_init_module (void) ...@@ -4283,8 +4384,9 @@ static int __init trident_init_module (void)
if (!pci_present()) /* No PCI bus in this machine! */ if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV; return -ENODEV;
printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro 5050 PCI Audio, version " printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro "
DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); "5050 PCI Audio, version " DRIVER_VERSION ", "
__TIME__ " " __DATE__ "\n");
if (!pci_register_driver(&trident_pci_driver)) { if (!pci_register_driver(&trident_pci_driver)) {
pci_unregister_driver(&trident_pci_driver); pci_unregister_driver(&trident_pci_driver);
......
...@@ -360,5 +360,16 @@ static inline unsigned ld2(unsigned int x) ...@@ -360,5 +360,16 @@ static inline unsigned ld2(unsigned int x)
return r; return r;
} }
#endif /* __TRID4DWAVE_H */ #ifdef DEBUG
#define TRDBG(msg, args...) do { \
printk(KERN_DEBUG msg , ##args ); \
} while (0)
#else /* !defined(DEBUG) */
#define TRDBG(msg, args...) do { } while (0)
#endif /* DEBUG */
#endif /* __TRID4DWAVE_H */
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