⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trident.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* restart the dma machine in case it is halted */	start_dac(state);}static int drain_dac(struct trident_state *state, int nonblock){	DECLARE_WAITQUEUE(wait, current);	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	unsigned long tmo;	int count;	unsigned long diff = 0;	if (dmabuf->mapped || !dmabuf->ready)		return 0;	add_wait_queue(&dmabuf->wait, &wait);	for (;;) {		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE		   every time to make the process really go to sleep */		set_current_state(TASK_INTERRUPTIBLE);		spin_lock_irqsave(&state->card->lock, flags);		count = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		if (count <= 0)			break;		if (signal_pending(current))			break;		if (nonblock) {			remove_wait_queue(&dmabuf->wait, &wait);			set_current_state(TASK_RUNNING);			return -EBUSY;		}		/* No matter how much data is left in the buffer, we have to wait until		   CSO == ESO/2 or CSO == ESO when address engine interrupts */	 	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 ||		    state->card->pci_id == PCI_DEVICE_ID_INTERG_5050)		{				diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize ;			diff = diff % (dmabuf->dmasize);			tmo  = (diff * HZ) / dmabuf->rate;		}		else		{			tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;		}		tmo >>= sample_shift[dmabuf->fmt];		if (!schedule_timeout(tmo ? tmo : 1) && tmo){			break;		}	}	remove_wait_queue(&dmabuf->wait, &wait);	set_current_state(TASK_RUNNING);	if (signal_pending(current))		return -ERESTARTSYS;	return 0;}/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */static void trident_update_ptr(struct trident_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned hwptr, swptr;	int clear_cnt = 0;	int diff;	unsigned char silence;	unsigned half_dmasize;	/* update hardware pointer */	hwptr = trident_get_dma_addr(state);	diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;	dmabuf->hwptr = hwptr;	dmabuf->total_bytes += diff;	/* error handling and process wake up for ADC */	if (dmabuf->enable == ADC_RUNNING) {		if (dmabuf->mapped) {			dmabuf->count -= diff;			if (dmabuf->count >= (signed)dmabuf->fragsize)				wake_up(&dmabuf->wait);		} else {			dmabuf->count += diff;			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {				/* buffer underrun or buffer overrun, we have no way to recover				   it here, just stop the machine and let the process force hwptr				   and swptr to sync */				__stop_adc(state);				dmabuf->error++;			}			if (dmabuf->count < (signed)dmabuf->dmasize/2)				wake_up(&dmabuf->wait);		}	}	/* error handling and process wake up for DAC */	if (dmabuf->enable == DAC_RUNNING) {		if (dmabuf->mapped) {			dmabuf->count += diff;			if (dmabuf->count >= (signed)dmabuf->fragsize)				wake_up(&dmabuf->wait);		} else {			dmabuf->count -= diff;			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {				/* buffer underrun or buffer overrun, we have no way to recover				   it here, just stop the machine and let the process force hwptr				   and swptr to sync */				__stop_dac(state);				dmabuf->error++;			}			else if (!dmabuf->endcleared) {				swptr = dmabuf->swptr;				silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80);				if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) {					/* We must clear end data of 1/2 dmabuf if needed.					   According to 1/2 algorithm of Address Engine Interrupt,					   check the validation of the data of half dmasize. */					half_dmasize = dmabuf->dmasize / 2;					if ((diff = hwptr - half_dmasize) < 0 )						diff = hwptr;					if ((dmabuf->count + diff) < half_dmasize) {						//there is invalid data in the end of half buffer						if ((clear_cnt = half_dmasize - swptr) < 0)							clear_cnt += half_dmasize;						//clear the invalid data						memset (dmabuf->rawbuf + swptr,							silence, clear_cnt);						if (state->chans_num == 6) {						clear_cnt = clear_cnt / 2;						swptr = swptr / 2;							memset (state->other_states[0]->dmabuf.rawbuf + swptr,								silence, clear_cnt);							memset (state->other_states[1]->dmabuf.rawbuf + swptr,								silence, clear_cnt);							memset (state->other_states[2]->dmabuf.rawbuf + swptr,								silence, clear_cnt);							memset (state->other_states[3]->dmabuf.rawbuf + swptr,								silence, clear_cnt);						}						dmabuf->endcleared = 1;					}				} else if (dmabuf->count < (signed) dmabuf->fragsize) {					clear_cnt = dmabuf->fragsize;					if ((swptr + clear_cnt) > dmabuf->dmasize)						clear_cnt = dmabuf->dmasize - swptr;					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);					if (state->chans_num == 6) {						clear_cnt = clear_cnt / 2;						swptr = swptr / 2;						memset (state->other_states[0]->dmabuf.rawbuf + swptr,							silence, clear_cnt);						memset (state->other_states[1]->dmabuf.rawbuf + swptr,							silence, clear_cnt);						memset (state->other_states[2]->dmabuf.rawbuf + swptr,							silence, clear_cnt);						memset (state->other_states[3]->dmabuf.rawbuf + swptr,							silence, clear_cnt);					}					dmabuf->endcleared = 1;				}			}			/* trident_update_ptr is called by interrupt handler or by process via			   ioctl/poll, we only wake up the waiting process when we have more			   than 1/2 buffer free (always true for interrupt handler) */			if (dmabuf->count < (signed)dmabuf->dmasize/2)				wake_up(&dmabuf->wait);		}	}	dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE;}static void trident_address_interrupt(struct trident_card *card){	int i;	struct trident_state *state;		/* Update the pointers for all channels we are running. */	/* FIXME: should read interrupt status only once */	for (i = 0; i < NR_HW_CH; i++) {		if (trident_check_channel_interrupt(card, 63 - i)) {			trident_ack_channel_interrupt(card, 63 - i);			if ((state = card->states[i]) != NULL) {				trident_update_ptr(state);			} else {				printk("trident: spurious channel irq %d.\n",				       63 - i);				trident_stop_voice(card, 63 - i);				trident_disable_voice_irq(card, 63 - i);			}		}	}}static void ali_hwvol_control(struct trident_card *card, int opt){	u16 dwTemp, volume[2], mute, diff, *pVol[2];	dwTemp = ali_ac97_read(card->ac97_codec[0], 0x02);	mute = dwTemp & 0x8000;	volume[0] = dwTemp & 0x001f;	volume[1] = (dwTemp & 0x1f00) >> 8;	if (volume[0] < volume [1]) {		pVol[0] = &volume[0];		pVol[1] = &volume[1];	} else {		pVol[1] = &volume[0];		pVol[0] = &volume[1];	}	diff = *(pVol[1]) - *(pVol[0]);	if (opt == 1) {                     // MUTE		dwTemp ^= 0x8000;		ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);	} else if (opt == 2) {   // Down		if (mute)			return;		if (*(pVol[1]) < 0x001f) {			(*pVol[1])++;			*(pVol[0]) = *(pVol[1]) - diff;		}		dwTemp &= 0xe0e0;		dwTemp |= (volume[0]) | (volume[1] << 8);		ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);		card->ac97_codec[0]->mixer_state[0] = ((32-volume[0])*25/8) | (((32-volume[1])*25/8) << 8);	} else if (opt == 4) {   // Up		if (mute)			return;		if (*(pVol[0]) >0) {			(*pVol[0])--;			*(pVol[1]) = *(pVol[0]) + diff;		}		dwTemp &= 0xe0e0;		dwTemp |= (volume[0]) | (volume[1] << 8);		ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);		card->ac97_codec[0]->mixer_state[0] = ((32-volume[0])*25/8) | (((32-volume[1])*25/8) << 8);	} 	else 	{		/* Nothing needs doing */	}}/* *	Re-enable reporting of vol change after 0.1 seconds */static void ali_timeout(unsigned long ptr){	struct trident_card *card = (struct trident_card *)ptr;	u16 temp = 0;	/* Enable GPIO IRQ (MISCINT bit 18h)*/	temp = inw(TRID_REG(card, T4D_MISCINT + 2));	temp |= 0x0004;	outw(temp, TRID_REG(card, T4D_MISCINT + 2));}/* *	Set up the timer to clear the vol change notification */ static void ali_set_timer(struct trident_card *card){	/* Add Timer Routine to Enable GPIO IRQ */	del_timer(&card->timer);	/* Never queue twice */	card->timer.function = ali_timeout;	card->timer.data = (unsigned long) card;	card->timer.expires = jiffies + HZ/10;	add_timer(&card->timer);}/* *	Process a GPIO event */ static void ali_queue_task(struct trident_card *card, int opt){	u16 temp;	/* Disable GPIO IRQ (MISCINT bit 18h)*/	temp = inw(TRID_REG(card, T4D_MISCINT + 2));	temp &= (u16)(~0x0004);	outw(temp, TRID_REG(card, T4D_MISCINT + 2));	/* Adjust the volume */	ali_hwvol_control(card, opt);		/* Set the timer for 1/10th sec */	ali_set_timer(card);}static void cyber_address_interrupt(struct trident_card *card){	int i,irq_status;	struct trident_state *state;	/* Update the pointers for all channels we are running. */	/* FIXED: read interrupt status only once */	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)) ) {			/* clear bit by writing a 1, zeroes are ignored */ 					outl( (1 <<(31-i)), TRID_REG(card, T4D_AINT_A));		#ifdef DEBUG		printk("cyber_interrupt: channel %d\n", 31-i);#endif			if ((state = card->states[i]) != NULL) {				trident_update_ptr(state);			} else {				printk("cyber5050: spurious channel irq %d.\n",				       31 - i);				trident_stop_voice(card, 31 - i);				trident_disable_voice_irq(card, 31 - i);			}		}	}}static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct trident_card *card = (struct trident_card *)dev_id;	u32 event;	u32 gpio;	spin_lock(&card->lock);	event = inl(TRID_REG(card, T4D_MISCINT));#ifdef DEBUG	printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);#endif	if (event & ADDRESS_IRQ) {		card->address_interrupt(card);	}	if(card->pci_id == PCI_DEVICE_ID_ALI_5451)	{		/* GPIO IRQ (H/W Volume Control) */		event = inl(TRID_REG(card, T4D_MISCINT));		if (event & (1<<25)) {			gpio = inl(TRID_REG(card, ALI_GPIO));			if (!timer_pending(&card->timer)) 				ali_queue_task(card, gpio&0x07);		}		event = inl(TRID_REG(card, T4D_MISCINT));		outl(event | (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT));		spin_unlock(&card->lock);		return;	}	/* manually clear interrupt status, bad hardware design, blame T^2 */	outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),	     TRID_REG(card, T4D_MISCINT));	spin_unlock(&card->lock);}/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to   the user's buffer.  it is filled by the dma machine and drained by this loop. */static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct trident_state *state = (struct trident_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	ssize_t ret = 0;	unsigned long flags;	unsigned swptr;	int cnt;#ifdef DEBUG	printk("trident: trident_read called, count = %d\n", count);#endif	VALIDATE_STATE(state);	if (ppos != &file->f_pos)		return -ESPIPE;			if (dmabuf->mapped)		return -ENXIO;	if (!access_ok(VERIFY_WRITE, buffer, count))		return -EFAULT;			down(&state->sem);	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))		goto out;	while (count > 0) {		spin_lock_irqsave(&state->card->lock, flags);		if (dmabuf->count > (signed) dmabuf->dmasize) {			/* buffer overrun, we are recovering from sleep_on_timeout,			   resync hwptr and swptr, make process flush the buffer */			dmabuf->count = dmabuf->dmasize;			dmabuf->swptr = dmabuf->hwptr;		}		swptr = dmabuf->swptr;		cnt = dmabuf->dmasize - swptr;		if (dmabuf->count < cnt)			cnt = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			unsigned long tmo;			/* buffer is empty, start the dma machine and wait for data to be			   recorded */			start_adc(state);			if (file->f_flags & O_NONBLOCK) {				if (!ret) ret = -EAGAIN;				goto out;			}						up(&state->sem);			/* No matter how much space left in the buffer, we have to wait until			   CSO == ESO/2 or CSO == ESO when address engine interrupts */			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);			tmo >>= sample_shift[dmabuf->fmt];			/* There are two situations when sleep_on_timeout returns, one is when			   the interrupt is serviced correctly and the process is waked up by			   ISR ON TIME. Another is when timeout is expired, which means that			   either interrupt is NOT serviced correctly (pending interrupt) or it			   is TOO LATE for the process to be scheduled to run (scheduler latency)			   which results in a (potential) buffer overrun. And worse, there is			   NOTHING we can do to prevent it. */			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {#ifdef DEBUG				printk(KERN_ERR "trident: recording schedule timeout, "				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,				       dmabuf->hwptr, dmabuf->swptr);#endif				/* a buffer overrun, we delay the recovery until next time the				   while loop begin and we REALLY have space to record */			}			if (signal_pending(current)) {				if(!ret) ret = -ERESTARTSYS;				goto out;			}			down(&state->sem);			if(dmabuf->mapped)			{

⌨️ 快捷键说明

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