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

📄 cs46xx_lib.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	snd_assert (cpcm->pcm_channel != NULL);	if (!cpcm->pcm_channel) {		up (&chip->spos_mutex);		return -ENXIO;	}	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) {		 up (&chip->spos_mutex);		 return -EINVAL;	 }	snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n",		     period_size, params_periods(hw_params),		     params_buffer_bytes(hw_params));#endif	if (params_periods(hw_params) == CS46XX_FRAGS) {		if (runtime->dma_area != cpcm->hw_buf.area)			snd_pcm_lib_free_pages(substream);		runtime->dma_area = cpcm->hw_buf.area;		runtime->dma_addr = cpcm->hw_buf.addr;		runtime->dma_bytes = cpcm->hw_buf.bytes;#ifdef CONFIG_SND_CS46XX_NEW_DSP		if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {			substream->ops = &snd_cs46xx_playback_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {			substream->ops = &snd_cs46xx_playback_rear_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) {			substream->ops = &snd_cs46xx_playback_clfe_ops;		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {			substream->ops = &snd_cs46xx_playback_iec958_ops;		} else {			snd_assert(0);		}#else		substream->ops = &snd_cs46xx_playback_ops;#endif	} else {		if (runtime->dma_area == cpcm->hw_buf.area) {			runtime->dma_area = NULL;			runtime->dma_addr = 0;			runtime->dma_bytes = 0;		}		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {#ifdef CONFIG_SND_CS46XX_NEW_DSP			up (&chip->spos_mutex);#endif			return err;		}#ifdef CONFIG_SND_CS46XX_NEW_DSP		if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_rear_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_clfe_ops;		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;		} else {			snd_assert(0);		}#else		substream->ops = &snd_cs46xx_playback_indirect_ops;#endif	}#ifdef CONFIG_SND_CS46XX_NEW_DSP	up (&chip->spos_mutex);#endif	return 0;}static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream){	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	cpcm = runtime->private_data;	/* if play_back open fails, then this function	   is called and cpcm can actually be NULL here */	if (!cpcm) return -ENXIO;	if (runtime->dma_area != cpcm->hw_buf.area)		snd_pcm_lib_free_pages(substream);    	runtime->dma_area = NULL;	runtime->dma_addr = 0;	runtime->dma_bytes = 0;	return 0;}static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream){	unsigned int tmp;	unsigned int pfie;	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	cpcm = runtime->private_data;#ifdef CONFIG_SND_CS46XX_NEW_DSP    snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);	pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );	pfie &= ~0x0000f03f;#else	/* old dsp */	pfie = snd_cs46xx_peek(chip, BA1_PFIE); 	pfie &= ~0x0000f03f;#endif	cpcm->shift = 2;	/* if to convert from stereo to mono */	if (runtime->channels == 1) {		cpcm->shift--;		pfie |= 0x00002000;	}	/* if to convert from 8 bit to 16 bit */	if (snd_pcm_format_width(runtime->format) == 8) {		cpcm->shift--;		pfie |= 0x00001000;	}	/* if to convert to unsigned */	if (snd_pcm_format_unsigned(runtime->format))		pfie |= 0x00008000;	/* Never convert byte order when sample stream is 8 bit */	if (snd_pcm_format_width(runtime->format) != 8) {		/* convert from big endian to little endian */		if (snd_pcm_format_big_endian(runtime->format))			pfie |= 0x00004000;	}		memset(&cpcm->pcm_rec, 0, sizeof(cpcm->pcm_rec));	cpcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);	cpcm->pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;#ifdef CONFIG_SND_CS46XX_NEW_DSP	tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2);	tmp &= ~0x000003ff;	tmp |= (4 << cpcm->shift) - 1;	/* playback transaction count register */	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2, tmp);	/* playback format && interrupt enable */	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot);#else	snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_buf.addr);	tmp = snd_cs46xx_peek(chip, BA1_PDTC);	tmp &= ~0x000003ff;	tmp |= (4 << cpcm->shift) - 1;	snd_cs46xx_poke(chip, BA1_PDTC, tmp);	snd_cs46xx_poke(chip, BA1_PFIE, pfie);	snd_cs46xx_set_play_sample_rate(chip, runtime->rate);#endif	return 0;}static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP	cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params));#endif	if (runtime->periods == CS46XX_FRAGS) {		if (runtime->dma_area != chip->capt.hw_buf.area)			snd_pcm_lib_free_pages(substream);		runtime->dma_area = chip->capt.hw_buf.area;		runtime->dma_addr = chip->capt.hw_buf.addr;		runtime->dma_bytes = chip->capt.hw_buf.bytes;		substream->ops = &snd_cs46xx_capture_ops;	} else {		if (runtime->dma_area == chip->capt.hw_buf.area) {			runtime->dma_area = NULL;			runtime->dma_addr = 0;			runtime->dma_bytes = 0;		}		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)			return err;		substream->ops = &snd_cs46xx_capture_indirect_ops;	}	return 0;}static int snd_cs46xx_capture_hw_free(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	if (runtime->dma_area != chip->capt.hw_buf.area)		snd_pcm_lib_free_pages(substream);	runtime->dma_area = NULL;	runtime->dma_addr = 0;	runtime->dma_bytes = 0;	return 0;}static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr);	chip->capt.shift = 2;	memset(&chip->capt.pcm_rec, 0, sizeof(chip->capt.pcm_rec));	chip->capt.pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);	chip->capt.pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << 2;	snd_cs46xx_set_capture_sample_rate(chip, runtime->rate);	return 0;}static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){	cs46xx_t *chip = dev_id;	u32 status1;#ifdef CONFIG_SND_CS46XX_NEW_DSP	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	u32 status2;	int i;	cs46xx_pcm_t *cpcm = NULL;#endif	/*	 *  Read the Interrupt Status Register to clear the interrupt	 */	status1 = snd_cs46xx_peekBA0(chip, BA0_HISR);	if ((status1 & 0x7fffffff) == 0) {		snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);		return IRQ_NONE;	}#ifdef CONFIG_SND_CS46XX_NEW_DSP	status2 = snd_cs46xx_peekBA0(chip, BA0_HSR0);	for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {		if (i <= 15) {			if ( status1 & (1 << i) ) {				if (i == CS46XX_DSP_CAPTURE_CHANNEL) {					if (chip->capt.substream)						snd_pcm_period_elapsed(chip->capt.substream);				} else {					if (ins->pcm_channels[i].active &&					    ins->pcm_channels[i].private_data &&					    !ins->pcm_channels[i].unlinked) {						cpcm = ins->pcm_channels[i].private_data;						snd_pcm_period_elapsed(cpcm->substream);					}				}			}		} else {			if ( status2 & (1 << (i - 16))) {				if (ins->pcm_channels[i].active && 				    ins->pcm_channels[i].private_data &&				    !ins->pcm_channels[i].unlinked) {					cpcm = ins->pcm_channels[i].private_data;					snd_pcm_period_elapsed(cpcm->substream);				}			}		}	}#else	/* old dsp */	if ((status1 & HISR_VC0) && chip->playback_pcm) {		if (chip->playback_pcm->substream)			snd_pcm_period_elapsed(chip->playback_pcm->substream);	}	if ((status1 & HISR_VC1) && chip->pcm) {		if (chip->capt.substream)			snd_pcm_period_elapsed(chip->capt.substream);	}#endif	if ((status1 & HISR_MIDI) && chip->rmidi) {		unsigned char c;				spin_lock(&chip->reg_lock);		while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) {			c = snd_cs46xx_peekBA0(chip, BA0_MIDRP);			if ((chip->midcr & MIDCR_RIE) == 0)				continue;			spin_unlock(&chip->reg_lock);			snd_rawmidi_receive(chip->midi_input, &c, 1);			spin_lock(&chip->reg_lock);		}		while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) {			if ((chip->midcr & MIDCR_TIE) == 0)				break;			if (snd_rawmidi_transmit(chip->midi_output, &c, 1) != 1) {				chip->midcr &= ~MIDCR_TIE;				snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);				break;			}			snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c);		}		spin_unlock(&chip->reg_lock);	}	/*	 *  EOI to the PCI part....reenables interrupts	 */	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);	return IRQ_HANDLED;}static snd_pcm_hardware_t snd_cs46xx_playback ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED | 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_RESUME),	.formats =		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |				 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5500,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(256 * 1024),	.period_bytes_min =	CS46XX_MIN_PERIOD_SIZE,	.period_bytes_max =	CS46XX_MAX_PERIOD_SIZE,	.periods_min =		CS46XX_FRAGS,	.periods_max =		1024,	.fifo_size =		0,};static snd_pcm_hardware_t snd_cs46xx_capture ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5500,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(256 * 1024),	.period_bytes_min =	CS46XX_MIN_PERIOD_SIZE,	.period_bytes_max =	CS46XX_MAX_PERIOD_SIZE,	.periods_min =		CS46XX_FRAGS,	.periods_max =		1024,	.fifo_size =		0,};#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic unsigned int period_sizes[] = { 32, 64, 128, 256, 512, 1024, 2048 };static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = {	.count = ARRAY_SIZE(period_sizes),	.list = period_sizes,	.mask = 0};#endifstatic void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime){	cs46xx_pcm_t * cpcm = runtime->private_data;	kfree(cpcm);}static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	cs46xx_pcm_t * cpcm;	snd_pcm_runtime_t *runtime = substream->runtime;	cpcm = kcalloc(1, sizeof(*cpcm), GFP_KERNEL);	if (cpcm == NULL)		return -ENOMEM;	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),				PAGE_SIZE, &cpcm->hw_buf) < 0) {		kfree(cpcm);		return -ENOMEM;	}	runtime->hw = snd_cs46xx_playback;	runtime->private_data = cpcm;	runtime->private_free = snd_cs46xx_pcm_free_substream;	cpcm->substream = substream;#ifdef CONFIG_SND_CS46XX_NEW_DSP	down (&chip->spos_mutex);	cpcm->pcm_channel = NULL; 	cpcm->pcm_channel_id = pcm_channel_id;	snd_pcm_hw_constraint_list(runtime, 0,				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 				   &hw_constraints_period_sizes);	up (&chip->spos_mutex);#else	chip->playback_pcm = cpcm; /* HACK */#endif	if (chip->accept_valid)		substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;	chip->active_ctrl(chip, 1);	return 0;}static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream){	snd_printdd("open front channel\n");	return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int snd_cs46xx_playback_open_rear(snd_pcm_substream_t * substream){	snd_printdd("open rear channel\n");	return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);}static int snd_cs46xx_playback_open_clfe(snd_pcm_substream_t * substream){	snd_printdd("open center - LFE channel\n");	return _cs46xx_playback_open_channel(substream,DSP_PCM_CENTER_LFE_CHANNEL);}static int snd_cs46xx_playback_open_iec958(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_printdd("open raw iec958 channel\n");	down (&chip->spos_mutex);	cs46xx_iec958_pre_open (chip);	up (&chip->spos_mutex);	return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);

⌨️ 快捷键说明

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