trident.c

来自「linux 内核源代码」· C语言 代码 · 共 2,292 行 · 第 1/5 页

C
2,292
字号
};/* table to map from channel attribute to CHANNELMASK for SiS 7018 */static int attr2mask[] = {	DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET,	DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF};/* Added by Matt Wu 01-05-2001 for spdif in */static int ali_close_multi_channels(void);static void ali_delay(struct trident_card *card, int interval);static void ali_detect_spdif_rate(struct trident_card *card);static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val);static u16 ali_ac97_read(struct ac97_codec *codec, u8 reg);static struct trident_card *devs;static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);static int trident_open_mixdev(struct inode *inode, struct file *file);static int trident_ioctl_mixdev(struct inode *inode, struct file *file,				unsigned int cmd, unsigned long arg);static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val);static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg);static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate);static void ali_enable_special_channel(struct trident_state *stat);static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card);static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);static unsigned int ali_get_spdif_in_rate(struct trident_card *card);static void ali_setup_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_setup_spdif_out(struct trident_card *card, int flag);static int ali_write_5_1(struct trident_state *state,			 const char __user *buffer,			 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);#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count)	do { \        (dma_ptr) += (offset);	  \	(buffer) += (offset);	  \        (cnt) -= (offset);	  \	(copy_count) += (offset); \} while (0)static inline int lock_set_fmt(struct trident_state* state){	if (test_and_set_bit(0, &state->fmt_flag))		return -EFAULT;	return 0;}static inline void unlock_set_fmt(struct trident_state* state){	clear_bit(0, &state->fmt_flag);}static inttrident_enable_loop_interrupts(struct trident_card *card){	u32 global_control;	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));	switch (card->pci_id) {	case PCI_DEVICE_ID_SI_7018:		global_control |= (ENDLP_IE | MIDLP_IE | BANK_B_EN);		break;	case PCI_DEVICE_ID_ALI_5451:	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:	case PCI_DEVICE_ID_INTERG_5050:		global_control |= (ENDLP_IE | MIDLP_IE);		break;	default:		return 0;	}	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));	pr_debug("trident: Enable Loop Interrupts, globctl = 0x%08X\n",		 inl(TRID_REG(card, T4D_LFO_GC_CIR)));	return 1;}static inttrident_disable_loop_interrupts(struct trident_card *card){	u32 global_control;	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));	global_control &= ~(ENDLP_IE | MIDLP_IE);	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));	pr_debug("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",		 global_control);	return 1;}static voidtrident_enable_voice_irq(struct trident_card *card, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);	struct trident_pcm_bank *bank = &card->banks[channel >> 5];	u32 reg, addr = bank->addresses->aint_en;	reg = inl(TRID_REG(card, addr));	reg |= mask;	outl(reg, TRID_REG(card, addr));#ifdef DEBUG	reg = inl(TRID_REG(card, addr));	pr_debug("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",		 channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A",		 reg, addr);#endif /* DEBUG */}static voidtrident_disable_voice_irq(struct trident_card *card, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);	struct trident_pcm_bank *bank = &card->banks[channel >> 5];	u32 reg, addr = bank->addresses->aint_en;	reg = inl(TRID_REG(card, addr));	reg &= ~mask;	outl(reg, TRID_REG(card, addr));	/* Ack the channel in case the interrupt was set before we disable it. */	outl(mask, TRID_REG(card, bank->addresses->aint));#ifdef DEBUG	reg = inl(TRID_REG(card, addr));	pr_debug("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",		 channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A",		 reg, addr);#endif /* DEBUG */}static voidtrident_start_voice(struct trident_card *card, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);	struct trident_pcm_bank *bank = &card->banks[channel >> 5];	u32 addr = bank->addresses->start;#ifdef DEBUG	u32 reg;#endif /* DEBUG */	outl(mask, TRID_REG(card, addr));#ifdef DEBUG	reg = inl(TRID_REG(card, addr));	pr_debug("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n",		 channel, addr == T4D_START_B ? "START_B" : "START_A",		 reg, addr);#endif /* DEBUG */}static voidtrident_stop_voice(struct trident_card *card, unsigned int channel){	unsigned int mask = 1 << (channel & 0x1f);	struct trident_pcm_bank *bank = &card->banks[channel >> 5];	u32 addr = bank->addresses->stop;#ifdef DEBUG	u32 reg;#endif /* DEBUG */	outl(mask, TRID_REG(card, addr));#ifdef DEBUG	reg = inl(TRID_REG(card, addr));	pr_debug("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n",		 channel, addr == T4D_STOP_B ? "STOP_B" : "STOP_A",		 reg, addr);#endif /* DEBUG */}static u32trident_get_interrupt_mask(struct trident_card *card, unsigned int channel){	struct trident_pcm_bank *bank = &card->banks[channel];	u32 addr = bank->addresses->aint;	return inl(TRID_REG(card, addr));}static inttrident_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)		pr_debug("trident: channel %d has interrupt, %s = 0x%08x\n",			 channel, reg == T4D_AINT_B ? "AINT_B" : "AINT_A",			 reg);#endif /* DEBUG */	return (reg & mask) ? 1 : 0;}static voidtrident_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];	u32 reg, addr = bank->addresses->aint;	reg = inl(TRID_REG(card, addr));	reg &= mask;	outl(reg, TRID_REG(card, addr));#ifdef DEBUG	reg = inl(TRID_REG(card, T4D_AINT_B));	pr_debug("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",		 channel, reg);#endif /* DEBUG */}static struct trident_channel *trident_alloc_pcm_channel(struct trident_card *card){	struct trident_pcm_bank *bank;	int idx;	bank = &card->banks[BANK_B];	for (idx = 31; idx >= 0; idx--) {		if (!(bank->bitmap & (1 << idx))) {			struct trident_channel *channel = &bank->channels[idx];			bank->bitmap |= 1 << idx;			channel->num = idx + 32;			return channel;		}	}	/* no more free channels available */	printk(KERN_ERR "trident: no more channels available on Bank B.\n");	return NULL;}static voidtrident_free_pcm_channel(struct trident_card *card, unsigned int channel){	int bank;	unsigned char b;	if (channel < 31 || channel > 63)		return;	if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX ||	    card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) {		b = inb(TRID_REG(card, T4D_REC_CH));		if ((b & ~0x80) == channel)			outb(0x0, TRID_REG(card, T4D_REC_CH));	}	bank = channel >> 5;	channel = channel & 0x1f;	card->banks[bank].bitmap &= ~(1 << (channel));}static struct trident_channel *cyber_alloc_pcm_channel(struct trident_card *card){	struct trident_pcm_bank *bank;	int idx;	/* The cyberpro 5050 has only 32 voices and one bank */	/* .. at least they are not documented (if you want to call that	 * crap documentation), perhaps broken ? */	bank = &card->banks[BANK_A];	for (idx = 31; idx >= 0; idx--) {		if (!(bank->bitmap & (1 << idx))) {			struct trident_channel *channel = &bank->channels[idx];			bank->bitmap |= 1 << idx;			channel->num = idx;			return channel;		}	}	/* no more free channels available */	printk(KERN_ERR "cyberpro5050: no more channels available on Bank A.\n");	return NULL;}static voidcyber_free_pcm_channel(struct trident_card *card, unsigned int channel){	if (channel > 31)		return;	card->banks[BANK_A].bitmap &= ~(1 << (channel));}static inline voidcyber_outidx(int port, int idx, int data){	outb(idx, port);	outb(data, port + 1);}static inline intcyber_inidx(int port, int idx){	outb(idx, port);	return inb(port + 1);}static intcyber_init_ritual(struct trident_card *card){	/* some black magic, taken from SDK samples */	/* remove this and nothing will work */	int portDat;	int ret = 0;	unsigned long flags;	/*	 *      Keep interrupts off for the configure - we don't want to	 *      clash with another cyberpro config event	 */	spin_lock_irqsave(&card->lock, flags);	portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE);	/* enable, if it was disabled */	if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) {		printk(KERN_INFO "cyberpro5050: enabling audio controller\n");		cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE,			     portDat | CYBER_BMSK_AUENZ_ENABLE);		/* check again if hardware is enabled now */		portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE);	}	if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) {		printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n");		ret = -1;	} else {		cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE,			     CYBER_BMSK_AUDIO_INT_ENABLE);		cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x01);		cyber_outidx(CYBER_PORT_AUDIO, 0xba, 0x20);		cyber_outidx(CYBER_PORT_AUDIO, 0xbb, 0x08);		cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x02);		cyber_outidx(CYBER_PORT_AUDIO, 0xb3, 0x06);		cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x00);	}	spin_unlock_irqrestore(&card->lock, flags);	return ret;}/*  called with spin lock held */static inttrident_load_channel_registers(struct trident_card *card, u32 * data,			       unsigned int channel){	int i;	if (channel > 63)		return 0;	/* select hardware channel to write */	outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));	/* 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 (card->pci_id == PCI_DEVICE_ID_ALI_5451 ||	    card->pci_id == PCI_DEVICE_ID_INTERG_5050) {		outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1));		outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2));	}	return 1;}/* called with spin lock held */static inttrident_write_voice_regs(struct trident_state *state){	unsigned int data[CHANNEL_REGS + 1];	struct trident_channel *channel;	channel = state->dmabuf.channel;	data[1] = channel->lba;	data[4] = channel->control;	switch (state->card->pci_id) {	case PCI_DEVICE_ID_ALI_5451:		data[0] = 0;	/* Current Sample Offset */		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);		data[3] = 0;		break;	case PCI_DEVICE_ID_SI_7018:	case PCI_DEVICE_ID_INTERG_5050:		data[0] = 0;	/* Current Sample Offset */		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);		data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff);		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:		data[0] = 0;	/* Current Sample Offset */		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);		data[3] = channel->fm_vol & 0xffff;		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:		data[0] = (channel->delta << 24);		data[2] = ((channel->delta << 16) & 0xff000000) |			(channel->eso & 0x00ffffff);		data[3] = channel->fm_vol & 0xffff;		break;	default:		return 0;	}	return trident_load_channel_registers(state->card, data, channel->num);}static intcompute_rate_play(u32 rate){	int delta;	/* We special case 44100 and 8000 since rounding with the equation	   does not give us an accurate enough value. For 11025 and 22050	   the equation gives us the best answer. All other frequencies will	   also use the equation. JDW */	if (rate == 44100)		delta = 0xeb3;	else if (rate == 8000)		delta = 0x2ab;	else if (rate == 48000)		delta = 0x1000;	else		delta = (((rate << 12) + rate) / 48000) & 0x0000ffff;	return delta;}static intcompute_rate_rec(u32 rate)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?