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

📄 ymfpci.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	spin_unlock_irqrestore(&unit->reg_lock, flags);	set_current_state(TASK_RUNNING);	remove_wait_queue(&ypcm->dmabuf.wait, &waita);	/*	 * This function may take up to 4 seconds to reach this point	 * (32K circular buffer, 8000 Hz). User notices.	 */}/* Can just stop, without wait. Or can we? */static void ymf_stop_adc(struct ymf_state *state){	struct ymf_unit *unit = state->unit;	unsigned long flags;	spin_lock_irqsave(&unit->reg_lock, flags);	ymf_capture_trigger(unit, &state->rpcm, 0);	spin_unlock_irqrestore(&unit->reg_lock, flags);}/* *  Hardware start management */static void ymfpci_hw_start(ymfpci_t *unit){	unsigned long flags;	spin_lock_irqsave(&unit->reg_lock, flags);	if (unit->start_count++ == 0) {		ymfpci_writel(unit, YDSXGR_MODE,		    ymfpci_readl(unit, YDSXGR_MODE) | 3);		unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;	}	spin_unlock_irqrestore(&unit->reg_lock, flags);}static void ymfpci_hw_stop(ymfpci_t *unit){	unsigned long flags;	long timeout = 1000;	spin_lock_irqsave(&unit->reg_lock, flags);	if (--unit->start_count == 0) {		ymfpci_writel(unit, YDSXGR_MODE,		    ymfpci_readl(unit, YDSXGR_MODE) & ~3);		while (timeout-- > 0) {			if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0)				break;		}	}	spin_unlock_irqrestore(&unit->reg_lock, flags);}/* *  Playback voice management */static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[]){	ymfpci_voice_t *voice, *voice2;	int idx;	for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {		voice = &codec->voices[idx];		voice2 = pair ? &codec->voices[idx+1] : NULL;		if (voice->use || (voice2 && voice2->use))			continue;		voice->use = 1;		if (voice2)			voice2->use = 1;		switch (type) {		case YMFPCI_PCM:			voice->pcm = 1;			if (voice2)				voice2->pcm = 1;			break;		case YMFPCI_SYNTH:			voice->synth = 1;			break;		case YMFPCI_MIDI:			voice->midi = 1;			break;		}		ymfpci_hw_start(codec);		rvoice[0] = voice;		if (voice2) {			ymfpci_hw_start(codec);			rvoice[1] = voice2;		}		return 0;	}	return -EBUSY;	/* Your audio channel is open by someone else. */}static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice){	ymfpci_hw_stop(unit);	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;	pvoice->ypcm = NULL;}/* */static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice){	struct ymf_pcm *ypcm;	int redzone;	int pos, delta, swptr;	int played, distance;	struct ymf_state *state;	struct ymf_dmabuf *dmabuf;	char silence;	if ((ypcm = voice->ypcm) == NULL) {		return;	}	if ((state = ypcm->state) == NULL) {		ypcm->running = 0;	// lock it		return;	}	dmabuf = &ypcm->dmabuf;	spin_lock(&codec->reg_lock);	if (ypcm->running) {		YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",		   voice->number, codec->active_bank, dmabuf->count,		   voice->bank[0].start, voice->bank[1].start);		silence = (ymf_pcm_format_width(state->format.format) == 16) ?		    0 : 0x80;		/* We need actual left-hand-side redzone size here. */		redzone = ymf_calc_lend(state->format.rate);		redzone <<= (state->format.shift + 1);		swptr = dmabuf->swptr;		pos = voice->bank[codec->active_bank].start;		pos <<= state->format.shift;		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */			printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",			    codec->dev_audio, voice->number,			    dmabuf->hwptr, pos, dmabuf->dmasize);			pos = 0;		}		if (pos < dmabuf->hwptr) {			delta = dmabuf->dmasize - dmabuf->hwptr;			memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);			delta += pos;			memset(dmabuf->rawbuf, silence, pos);		} else {			delta = pos - dmabuf->hwptr;			memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);		}		dmabuf->hwptr = pos;		if (dmabuf->count == 0) {			printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",			    codec->dev_audio, voice->number, dmabuf->hwptr);			ymf_playback_trigger(codec, ypcm, 0);		}		if (swptr <= pos) {			distance = pos - swptr;		} else {			distance = dmabuf->dmasize - (swptr - pos);		}		if (distance < redzone) {			/*			 * hwptr inside redzone => DMA ran out of samples.			 */			if (delta < dmabuf->count) {				/*				 * Lost interrupt or other screwage.				 */				printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"				    " hwptr %d swptr %d distance %d count %d\n",				    codec->dev_audio, voice->number, delta,				    dmabuf->hwptr, swptr, distance, dmabuf->count);			} else {				/*				 * Normal end of DMA.				 */				YMFDBGI("ymfpci%d: %d: done: delta %d"				    " hwptr %d swptr %d distance %d count %d\n",				    codec->dev_audio, voice->number, delta,				    dmabuf->hwptr, swptr, distance, dmabuf->count);			}			played = dmabuf->count;			if (ypcm->running) {				ymf_playback_trigger(codec, ypcm, 0);			}		} else {			/*			 * hwptr is chipping away towards a remote swptr.			 * Calculate other distance and apply it to count.			 */			if (swptr >= pos) {				distance = swptr - pos;			} else {				distance = dmabuf->dmasize - (pos - swptr);			}			if (distance < dmabuf->count) {				played = dmabuf->count - distance;			} else {				played = 0;			}		}		dmabuf->total_bytes += played;		dmabuf->count -= played;		if (dmabuf->count < dmabuf->dmasize / 2) {			wake_up(&dmabuf->wait);		}	}	spin_unlock(&codec->reg_lock);}static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap){	struct ymf_pcm *ypcm;	int redzone;	struct ymf_state *state;	struct ymf_dmabuf *dmabuf;	int pos, delta;	int cnt;	if ((ypcm = cap->ypcm) == NULL) {		return;	}	if ((state = ypcm->state) == NULL) {		ypcm->running = 0;	// lock it		return;	}	dmabuf = &ypcm->dmabuf;	spin_lock(&unit->reg_lock);	if (ypcm->running) {		redzone = ymf_calc_lend(state->format.rate);		redzone <<= (state->format.shift + 1);		pos = cap->bank[unit->active_bank].start;		// pos <<= state->format.shift;		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */			printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",			    unit->dev_audio, ypcm->capture_bank_number,			    dmabuf->hwptr, pos, dmabuf->dmasize);			pos = 0;		}		if (pos < dmabuf->hwptr) {			delta = dmabuf->dmasize - dmabuf->hwptr;			delta += pos;		} else {			delta = pos - dmabuf->hwptr;		}		dmabuf->hwptr = pos;		cnt = dmabuf->count;		cnt += delta;		if (cnt + redzone > dmabuf->dmasize) {			/* Overflow - bump swptr */			dmabuf->count = dmabuf->dmasize - redzone;			dmabuf->swptr = dmabuf->hwptr + redzone;			if (dmabuf->swptr >= dmabuf->dmasize) {				dmabuf->swptr -= dmabuf->dmasize;			}		} else {			dmabuf->count = cnt;		}		dmabuf->total_bytes += delta;		if (dmabuf->count) {		/* && is_sleeping  XXX */			wake_up(&dmabuf->wait);		}	}	spin_unlock(&unit->reg_lock);}static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd){	if (ypcm->voices[0] == NULL) {		return -EINVAL;	}	if (cmd != 0) {		codec->ctrl_playback[ypcm->voices[0]->number + 1] = virt_to_bus(ypcm->voices[0]->bank);		if (ypcm->voices[1] != NULL)			codec->ctrl_playback[ypcm->voices[1]->number + 1] = virt_to_bus(ypcm->voices[1]->bank);		ypcm->running = 1;	} else {		codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;		if (ypcm->voices[1] != NULL)			codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0;		ypcm->running = 0;	}	return 0;}static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd){	u32 tmp;	if (cmd != 0) {		tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);		ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);		ypcm->running = 1;	} else {		tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);		ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);		ypcm->running = 0;	}}static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices){	struct ymf_unit *unit;	int err;	unit = ypcm->state->unit;	if (ypcm->voices[1] != NULL && voices < 2) {		ymfpci_voice_free(unit, ypcm->voices[1]);		ypcm->voices[1] = NULL;	}	if (voices == 1 && ypcm->voices[0] != NULL)		return 0;		/* already allocated */	if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)		return 0;		/* already allocated */	if (voices > 1) {		if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {			ymfpci_voice_free(unit, ypcm->voices[0]);			ypcm->voices[0] = NULL;		}				if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)			return err;		ypcm->voices[0]->ypcm = ypcm;		ypcm->voices[1]->ypcm = ypcm;	} else {		if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)			return err;		ypcm->voices[0]->ypcm = ypcm;	}	return 0;}static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,    int rate, int w_16, unsigned long addr, unsigned int end, int spdif){	u32 format;	u32 delta = ymfpci_calc_delta(rate);	u32 lpfQ = ymfpci_calc_lpfQ(rate);	u32 lpfK = ymfpci_calc_lpfK(rate);	ymfpci_playback_bank_t *bank;	int nbank;	format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);	if (stereo)		end >>= 1;	if (w_16)		end >>= 1;	for (nbank = 0; nbank < 2; nbank++) {		bank = &voice->bank[nbank];		bank->format = format;		bank->loop_default = 0;	/* 0-loops forever, otherwise count */		bank->base = addr;		bank->loop_start = 0;		bank->loop_end = end;		bank->loop_frac = 0;		bank->eg_gain_end = 0x40000000;		bank->lpfQ = lpfQ;		bank->status = 0;		bank->num_of_frames = 0;		bank->loop_count = 0;		bank->start = 0;		bank->start_frac = 0;		bank->delta =		bank->delta_end = delta;		bank->lpfK =		bank->lpfK_end = lpfK;		bank->eg_gain = 0x40000000;		bank->lpfD1 =		bank->lpfD2 = 0;		bank->left_gain = 		bank->right_gain =		bank->left_gain_end =		bank->right_gain_end =		bank->eff1_gain =		bank->eff2_gain =		bank->eff3_gain =		bank->eff1_gain_end =		bank->eff2_gain_end =		bank->eff3_gain_end = 0;		if (!stereo) {			if (!spdif) {				bank->left_gain = 				bank->right_gain =				bank->left_gain_end =				bank->right_gain_end = 0x40000000;			} else {				bank->eff2_gain =				bank->eff2_gain_end =				bank->eff3_gain =				bank->eff3_gain_end = 0x40000000;			}		} else {			if (!spdif) {				if ((voice->number & 1) == 0) {					bank->left_gain =					bank->left_gain_end = 0x40000000;				} else {					bank->format |= 1;					bank->right_gain =					bank->right_gain_end = 0x40000000;				}			} else {				if ((voice->number & 1) == 0) {					bank->eff2_gain =					bank->eff2_gain_end = 0x40000000;				} else {					bank->format |= 1;					bank->eff3_gain =					bank->eff3_gain_end = 0x40000000;				}			}		}	}}/* * XXX Capture channel allocation is entirely fake at the moment. * We use only one channel and mark it busy as required. */static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank){	struct ymf_capture *cap;	int cbank;	cbank = 1;		/* Only ADC slot is used for now. */	cap = &unit->capture[cbank];	if (cap->use)		return -EBUSY;	cap->use = 1;	*pbank = cbank;	return 0;}static int ymf_playback_prepare(struct ymf_state *state){	struct ymf_pcm *ypcm = &state->wpcm;	int err, nvoice;	if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {		/* Somebody started 32 mpg123's in parallel? */		printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",		    state->unit->dev_audio);		return err;	}	for (nvoice = 0; nvoice < state->format.voices; nvoice++) {		ymf_pcm_init_voice(ypcm->voices[nvoice],

⌨️ 快捷键说明

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