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

📄 ymfpci_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		return 0;		/* already allocated */	if (voices > 1) {		if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {			snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[0]);			ypcm->voices[0] = NULL;		}			}	err = snd_ymfpci_voice_alloc(ypcm->chip, YMFPCI_PCM, voices > 1, &ypcm->voices[0]);	if (err < 0)		return err;	ypcm->voices[0]->ypcm = ypcm;	ypcm->voices[0]->interrupt = snd_ymfpci_pcm_interrupt;	if (voices > 1) {		ypcm->voices[1] = &ypcm->chip->voices[ypcm->voices[0]->number + 1];		ypcm->voices[1]->ypcm = ypcm;	}	return 0;}static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx,				      snd_pcm_runtime_t *runtime,				      int has_pcm_volume){	ymfpci_voice_t *voice = ypcm->voices[voiceidx];	u32 format;	u32 delta = snd_ymfpci_calc_delta(runtime->rate);	u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);	u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);	snd_ymfpci_playback_bank_t *bank;	unsigned int nbank;	u32 vol_left, vol_right;	u8 use_left, use_right;	snd_assert(voice != NULL, return);	if (runtime->channels == 1) {		use_left = 1;		use_right = 1;	} else {		use_left = (voiceidx & 1) == 0;		use_right = !use_left;	}	if (has_pcm_volume) {		vol_left = cpu_to_le32(ypcm->chip->pcm_mixer				       [ypcm->substream->number].left << 15);		vol_right = cpu_to_le32(ypcm->chip->pcm_mixer					[ypcm->substream->number].right << 15);	} else {		vol_left = cpu_to_le32(0x40000000);		vol_right = cpu_to_le32(0x40000000);	}	format = runtime->channels == 2 ? 0x00010000 : 0;	if (snd_pcm_format_width(runtime->format) == 8)		format |= 0x80000000;	if (runtime->channels == 2 && (voiceidx & 1) != 0)		format |= 1;	for (nbank = 0; nbank < 2; nbank++) {		bank = &voice->bank[nbank];		memset(bank, 0, sizeof(*bank));		bank->format = cpu_to_le32(format);		bank->base = cpu_to_le32(runtime->dma_addr);		bank->loop_end = cpu_to_le32(ypcm->buffer_size);		bank->lpfQ = cpu_to_le32(lpfQ);		bank->delta =		bank->delta_end = cpu_to_le32(delta);		bank->lpfK =		bank->lpfK_end = cpu_to_le32(lpfK);		bank->eg_gain =		bank->eg_gain_end = cpu_to_le32(0x40000000);		if (ypcm->output_front) {			if (use_left) {				bank->left_gain =				bank->left_gain_end = vol_left;			}			if (use_right) {				bank->right_gain =				bank->right_gain_end = vol_right;			}		}		if (ypcm->output_rear) {			if (use_left) {				bank->eff2_gain =				bank->eff2_gain_end = vol_left;			}			if (use_right) {				bank->eff3_gain =				bank->eff3_gain_end = vol_right;			}		}	}}static int __devinit snd_ymfpci_ac3_init(ymfpci_t *chip){	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),				4096, &chip->ac3_tmp_base) < 0)		return -ENOMEM;	chip->bank_effect[3][0]->base =	chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr);	chip->bank_effect[3][0]->loop_end =	chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024);	chip->bank_effect[4][0]->base =	chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048);	chip->bank_effect[4][0]->loop_end =	chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024);	spin_lock_irq(&chip->reg_lock);	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3);	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_ymfpci_ac3_done(ymfpci_t *chip){	spin_lock_irq(&chip->reg_lock);	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));	spin_unlock_irq(&chip->reg_lock);	// snd_ymfpci_irq_wait(chip);	if (chip->ac3_tmp_base.area) {		snd_dma_free_pages(&chip->ac3_tmp_base);		chip->ac3_tmp_base.area = NULL;	}	return 0;}static int snd_ymfpci_playback_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm = runtime->private_data;	int err;	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)		return err;	if ((err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params))) < 0)		return err;	return 0;}static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm;		if (runtime->private_data == NULL)		return 0;	ypcm = runtime->private_data;	/* wait, until the PCI operations are not finished */	snd_ymfpci_irq_wait(chip);	snd_pcm_lib_free_pages(substream);	if (ypcm->voices[1]) {		snd_ymfpci_voice_free(chip, ypcm->voices[1]);		ypcm->voices[1] = NULL;	}	if (ypcm->voices[0]) {		snd_ymfpci_voice_free(chip, ypcm->voices[0]);		ypcm->voices[0] = NULL;	}	return 0;}static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm = runtime->private_data;	unsigned int nvoice;	ypcm->period_size = runtime->period_size;	ypcm->buffer_size = runtime->buffer_size;	ypcm->period_pos = 0;	ypcm->last_pos = 0;	for (nvoice = 0; nvoice < runtime->channels; nvoice++)		snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,					  substream->pcm == chip->pcm);	return 0;}static int snd_ymfpci_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ymfpci_capture_hw_free(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	/* wait, until the PCI operations are not finished */	snd_ymfpci_irq_wait(chip);	return snd_pcm_lib_free_pages(substream);}static int snd_ymfpci_capture_prepare(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm = runtime->private_data;	snd_ymfpci_capture_bank_t * bank;	int nbank;	u32 rate, format;	ypcm->period_size = runtime->period_size;	ypcm->buffer_size = runtime->buffer_size;	ypcm->period_pos = 0;	ypcm->last_pos = 0;	ypcm->shift = 0;	rate = ((48000 * 4096) / runtime->rate) - 1;	format = 0;	if (runtime->channels == 2) {		format |= 2;		ypcm->shift++;	}	if (snd_pcm_format_width(runtime->format) == 8)		format |= 1;	else		ypcm->shift++;	switch (ypcm->capture_bank_number) {	case 0:		snd_ymfpci_writel(chip, YDSXGR_RECFORMAT, format);		snd_ymfpci_writel(chip, YDSXGR_RECSLOTSR, rate);		break;	case 1:		snd_ymfpci_writel(chip, YDSXGR_ADCFORMAT, format);		snd_ymfpci_writel(chip, YDSXGR_ADCSLOTSR, rate);		break;	}	for (nbank = 0; nbank < 2; nbank++) {		bank = chip->bank_capture[ypcm->capture_bank_number][nbank];		bank->base = cpu_to_le32(runtime->dma_addr);		bank->loop_end = cpu_to_le32(ypcm->buffer_size << ypcm->shift);		bank->start = 0;		bank->num_of_loops = 0;	}	return 0;}static snd_pcm_uframes_t snd_ymfpci_playback_pointer(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm = runtime->private_data;	ymfpci_voice_t *voice = ypcm->voices[0];	if (!(ypcm->running && voice))		return 0;	return le32_to_cpu(voice->bank[chip->active_bank].start);}static snd_pcm_uframes_t snd_ymfpci_capture_pointer(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm = runtime->private_data;	if (!ypcm->running)		return 0;	return le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;}static void snd_ymfpci_irq_wait(ymfpci_t *chip){	wait_queue_t wait;	int loops = 4;	while (loops-- > 0) {		if ((snd_ymfpci_readl(chip, YDSXGR_MODE) & 3) == 0)		 	continue;		init_waitqueue_entry(&wait, current);		add_wait_queue(&chip->interrupt_sleep, &wait);		atomic_inc(&chip->interrupt_sleep_count);		schedule_timeout_uninterruptible(msecs_to_jiffies(50));		remove_wait_queue(&chip->interrupt_sleep, &wait);	}}static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs){	ymfpci_t *chip = dev_id;	u32 status, nvoice, mode;	ymfpci_voice_t *voice;	status = snd_ymfpci_readl(chip, YDSXGR_STATUS);	if (status & 0x80000000) {		chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;		spin_lock(&chip->voice_lock);		for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {			voice = &chip->voices[nvoice];			if (voice->interrupt)				voice->interrupt(chip, voice);		}		for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {			if (chip->capture_substream[nvoice])				snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]);		}#if 0		for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) {			if (chip->effect_substream[nvoice])				snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]);		}#endif		spin_unlock(&chip->voice_lock);		spin_lock(&chip->reg_lock);		snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000);		mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2;		snd_ymfpci_writel(chip, YDSXGR_MODE, mode);		spin_unlock(&chip->reg_lock);		if (atomic_read(&chip->interrupt_sleep_count)) {			atomic_set(&chip->interrupt_sleep_count, 0);			wake_up(&chip->interrupt_sleep);		}	}	status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG);	if (status & 1) {		if (chip->timer)			snd_timer_interrupt(chip->timer, chip->timer->sticks);	}	snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status);	if (chip->rawmidi)		snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs);	return IRQ_HANDLED;}static snd_pcm_hardware_t snd_ymfpci_playback ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_MMAP_VALID | 				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */	.period_bytes_min =	64,	.period_bytes_max =	256 * 1024, /* FIXME: enough? */	.periods_min =		3,	.periods_max =		1024,	.fifo_size =		0,};static snd_pcm_hardware_t snd_ymfpci_capture ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_PAUSE |				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */	.period_bytes_min =	64,	.period_bytes_max =	256 * 1024, /* FIXME: enough? */	.periods_min =		3,	.periods_max =		1024,	.fifo_size =		0,};static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime){	kfree(runtime->private_data);}static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm;	ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);	if (ypcm == NULL)		return -ENOMEM;	ypcm->chip = chip;	ypcm->type = PLAYBACK_VOICE;	ypcm->substream = substream;	runtime->hw = snd_ymfpci_playback;	runtime->private_data = ypcm;	runtime->private_free = snd_ymfpci_pcm_free_substream;	/* FIXME? True value is 256/48 = 5.33333 ms */	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX);	return 0;}/* call with spinlock held */static void ymfpci_open_extension(ymfpci_t *chip){	if (! chip->rear_opened) {		if (! chip->spdif_opened) /* set AC3 */			snd_ymfpci_writel(chip, YDSXGR_MODE,					  snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30));		/* enable second codec (4CHEN) */		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010);	}}/* call with spinlock held */static void ymfpci_close_extension(ymfpci_t *chip){	if (! chip->rear_opened) {		if (! chip->spdif_opened)			snd_ymfpci_writel(chip, YDSXGR_MODE,					  snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30));		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) & ~0x0010);	}}static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ymfpci_pcm_t *ypcm;	snd_kcontrol_t *kctl;	int err;		if ((err = snd_ymfpci_playback_open_1(substream)) < 0)		return err;	ypcm = runtime->private_data;	ypcm->output_front = 1;	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;	spin_lock_irq(&chip->reg_lock);	if (ypcm->output_rear) {		ymfpci_open_extension(chip);		chip->rear_opened++;	}	spin_unlock_irq(&chip->reg_lock);	kctl = chip->pcm_mixer[substream->number].ctl;	kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;	snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);	return 0;}static int snd_ymfpci_playback_spdif_open(snd_pcm_substream_t * substream){	ymfpci_t *chip = snd_pcm_substream_chip(substream);

⌨️ 快捷键说明

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