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

📄 pcxhr.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 3 页
字号:
		    is_capture ? 'c' : 'p',		    chip->chip_idx, (void*)subs->runtime->dma_addr,		    subs->runtime->dma_bytes, subs->number);	pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);	snd_assert(subs->runtime->dma_bytes < 0x200000);	/* max buffer size is 2 MByte */	rmh.cmd[1] = subs->runtime->dma_bytes * 8;		/* size in bits */	rmh.cmd[2] = subs->runtime->dma_addr >> 24;		/* most significant byte */	rmh.cmd[2] |= 1<<19;					/* this is a circular buffer */	rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;	/* least 3 significant bytes */	rmh.cmd_len = 4;	err = pcxhr_send_msg(chip->mgr, &rmh);	if (err)		snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);	return err;}#if 0static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count){	struct pcxhr_rmh rmh;	int err;	pcxhr_t *chip = snd_pcm_substream_chip(stream->substream);	pcxhr_init_rmh(&rmh, CMD_PIPE_SAMPLE_COUNT);	pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, 0, 0,				  1<<stream->pipe->first_audio);	err = pcxhr_send_msg(chip->mgr, &rmh);	if (err == 0) {		*sample_count = ((snd_pcm_uframes_t)rmh.stat[0]) << 24;		*sample_count += (snd_pcm_uframes_t)rmh.stat[1];	}	snd_printdd("PIPE_SAMPLE_COUNT = %lx\n", *sample_count);	return err;}#endifstatic inline int pcxhr_stream_scheduled_get_pipe(struct pcxhr_stream *stream,						  struct pcxhr_pipe **pipe){	if (stream->status == PCXHR_STREAM_STATUS_SCHEDULE_RUN) {		*pipe = stream->pipe;		return 1;	}	return 0;}static void pcxhr_trigger_tasklet(unsigned long arg){	unsigned long flags;	int i, j, err;	struct pcxhr_pipe *pipe;	struct snd_pcxhr *chip;	struct pcxhr_mgr *mgr = (struct pcxhr_mgr*)(arg);	int capture_mask = 0;	int playback_mask = 0;#ifdef CONFIG_SND_DEBUG_DETECT	struct timeval my_tv1, my_tv2;	do_gettimeofday(&my_tv1);#endif	down(&mgr->setup_mutex);	/* check the pipes concerned and build pipe_array */	for (i = 0; i < mgr->num_cards; i++) {		chip = mgr->chip[i];		for (j = 0; j < chip->nb_streams_capt; j++) {			if (pcxhr_stream_scheduled_get_pipe(&chip->capture_stream[j], &pipe))				capture_mask |= (1 << pipe->first_audio);		}		for (j = 0; j < chip->nb_streams_play; j++) {			if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) {				playback_mask |= (1 << pipe->first_audio);				break;	/* add only once, as all playback streams of					 * one chip use the same pipe					 */			}		}	}	if (capture_mask == 0 && playback_mask == 0) {		up(&mgr->setup_mutex);		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n");		return;	}	snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n",		    playback_mask, capture_mask);	/* synchronous stop of all the pipes concerned */	err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);	if (err) {		up(&mgr->setup_mutex);		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",			   playback_mask, capture_mask);		return;	}	/* unfortunately the dsp lost format and buffer info with the stop pipe */	for (i = 0; i < mgr->num_cards; i++) {		struct pcxhr_stream *stream;		chip = mgr->chip[i];		for (j = 0; j < chip->nb_streams_capt; j++) {			stream = &chip->capture_stream[j];			if (pcxhr_stream_scheduled_get_pipe(stream, &pipe)) {				err = pcxhr_set_format(stream);				err = pcxhr_update_r_buffer(stream);			}		}		for (j = 0; j < chip->nb_streams_play; j++) {			stream = &chip->playback_stream[j];			if (pcxhr_stream_scheduled_get_pipe(stream, &pipe)) {				err = pcxhr_set_format(stream);				err = pcxhr_update_r_buffer(stream);			}		}	}	/* start all the streams */	for (i = 0; i < mgr->num_cards; i++) {		struct pcxhr_stream *stream;		chip = mgr->chip[i];		for (j = 0; j < chip->nb_streams_capt; j++) {			stream = &chip->capture_stream[j];			if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))				err = pcxhr_set_stream_state(stream);		}		for (j = 0; j < chip->nb_streams_play; j++) {			stream = &chip->playback_stream[j];			if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))				err = pcxhr_set_stream_state(stream);		}	}	/* synchronous start of all the pipes concerned */	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);	if (err) {		up(&mgr->setup_mutex);		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",			   playback_mask, capture_mask);		return;	}	/* put the streams into the running state now (increment pointer by interrupt) */	spin_lock_irqsave(&mgr->lock, flags);	for ( i =0; i < mgr->num_cards; i++) {		struct pcxhr_stream *stream;		chip = mgr->chip[i];		for(j = 0; j < chip->nb_streams_capt; j++) {			stream = &chip->capture_stream[j];			if(stream->status == PCXHR_STREAM_STATUS_STARTED)				stream->status = PCXHR_STREAM_STATUS_RUNNING;		}		for (j = 0; j < chip->nb_streams_play; j++) {			stream = &chip->playback_stream[j];			if (stream->status == PCXHR_STREAM_STATUS_STARTED) {				/* playback will already have advanced ! */				stream->timer_period_frag += PCXHR_GRANULARITY;				stream->status = PCXHR_STREAM_STATUS_RUNNING;			}		}	}	spin_unlock_irqrestore(&mgr->lock, flags);	up(&mgr->setup_mutex);#ifdef CONFIG_SND_DEBUG_DETECT	do_gettimeofday(&my_tv2);	snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",		    my_tv2.tv_usec - my_tv1.tv_usec, err);#endif}/* *  trigger callback */static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd){	struct pcxhr_stream *stream;	struct list_head *pos;	struct snd_pcm_substream *s;	int i;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_printdd("SNDRV_PCM_TRIGGER_START\n");		i = 0;		snd_pcm_group_for_each(pos, subs) {			s = snd_pcm_group_substream_entry(pos);			stream = s->runtime->private_data;			stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN;			snd_pcm_trigger_done(s, subs);			i++;		}		if (i==1) {			snd_printdd("Only one Substream %c %d\n",				    stream->pipe->is_capture ? 'C' : 'P',				    stream->pipe->first_audio);			if (pcxhr_set_format(stream))				return -EINVAL;			if (pcxhr_update_r_buffer(stream))				return -EINVAL;			if (pcxhr_set_stream_state(stream))				return -EINVAL;			stream->status = PCXHR_STREAM_STATUS_RUNNING;		} else {			struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);			tasklet_hi_schedule(&chip->mgr->trigger_taskq);		}		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");		snd_pcm_group_for_each(pos, subs) {			s = snd_pcm_group_substream_entry(pos);			stream = s->runtime->private_data;			stream->status = PCXHR_STREAM_STATUS_SCHEDULE_STOP;			if (pcxhr_set_stream_state(stream))				return -EINVAL;			snd_pcm_trigger_done(s, subs);		}		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		/* TODO */	default:		return -EINVAL;	}	return 0;}static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start){	struct pcxhr_rmh rmh;	int err;	pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT);	if (start) {		mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;	/* last dsp time invalid */		rmh.cmd[0] |= PCXHR_GRANULARITY;	}	err = pcxhr_send_msg(mgr, &rmh);	if (err < 0)		snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err);	return err;}/* *  prepare callback for all pcms */static int pcxhr_prepare(struct snd_pcm_substream *subs){	struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);	struct pcxhr_mgr *mgr = chip->mgr;	/*	struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data;	*/	int err = 0;	snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",		    subs->runtime->period_size, subs->runtime->periods,		    subs->runtime->buffer_size);	/*	if(subs->runtime->period_size <= PCXHR_GRANULARITY) {		snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n",			   (unsigned int)subs->runtime->period_size);		return -EINVAL;	}	*/	down(&mgr->setup_mutex);	do {		/* if the stream was stopped before, format and buffer were reset */		/*		if(stream->status == PCXHR_STREAM_STATUS_STOPPED) {			err = pcxhr_set_format(stream);			if(err) break;			err = pcxhr_update_r_buffer(stream);			if(err) break;		}		*/		/* only the first stream can choose the sample rate */		/* the further opened streams will be limited to its frequency (see open) */		/* set the clock only once (first stream) */		if (mgr->sample_rate != subs->runtime->rate) {			err = pcxhr_set_clock(mgr, subs->runtime->rate);			if (err)				break;			if (mgr->sample_rate == 0)				/* start the DSP-timer */				err = pcxhr_hardware_timer(mgr, 1);			mgr->sample_rate = subs->runtime->rate;		}	} while(0);	/* do only once (so we can use break instead of goto) */	up(&mgr->setup_mutex);	return err;}/* *  HW_PARAMS callback for all pcms */static int pcxhr_hw_params(struct snd_pcm_substream *subs,			   struct snd_pcm_hw_params *hw){	struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);	struct pcxhr_mgr *mgr = chip->mgr;	struct pcxhr_stream *stream = subs->runtime->private_data;	snd_pcm_format_t format;	int err;	int channels;	/* set up channels */	channels = params_channels(hw);	/*  set up format for the stream */	format = params_format(hw);	down(&mgr->setup_mutex);	stream->channels = channels;	stream->format = format;	/* set the format to the board */	/*	err = pcxhr_set_format(stream);	if(err) {		up(&mgr->setup_mutex);		return err;	}	*/	/* allocate buffer */	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));	/*	if (err > 0) {		err = pcxhr_update_r_buffer(stream);	}	*/	up(&mgr->setup_mutex);	return err;}static int pcxhr_hw_free(struct snd_pcm_substream *subs){	snd_pcm_lib_free_pages(subs);	return 0;}/* *  CONFIGURATION SPACE for all pcms, mono pcm must update channels_max */static struct snd_pcm_hardware pcxhr_caps ={	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |			      0 /*SNDRV_PCM_INFO_PAUSE*/),	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |			      SNDRV_PCM_FMTBIT_FLOAT_LE ),	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,	.rate_min         = 8000,	.rate_max         = 192000,	.channels_min     = 1,	.channels_max     = 2,	.buffer_bytes_max = (32*1024),	/* 1 byte == 1 frame U8 mono (PCXHR_GRANULARITY is frames!) */	.period_bytes_min = (2*PCXHR_GRANULARITY),	.period_bytes_max = (16*1024),	.periods_min      = 2,	.periods_max      = (32*1024/PCXHR_GRANULARITY),};static int pcxhr_open(struct snd_pcm_substream *subs){	struct snd_pcxhr       *chip = snd_pcm_substream_chip(subs);	struct pcxhr_mgr       *mgr = chip->mgr;	struct snd_pcm_runtime *runtime = subs->runtime;	struct pcxhr_stream    *stream;	int                 is_capture;	down(&mgr->setup_mutex);	/* copy the struct snd_pcm_hardware struct */	runtime->hw = pcxhr_caps;	if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) {		snd_printdd("pcxhr_open playback chip%d subs%d\n",			    chip->chip_idx, subs->number);		is_capture = 0;		stream = &chip->playback_stream[subs->number];	} else {		snd_printdd("pcxhr_open capture chip%d subs%d\n",			    chip->chip_idx, subs->number);		is_capture = 1;		if (mgr->mono_capture)			runtime->hw.channels_max = 1;		else			runtime->hw.channels_min = 2;		stream = &chip->capture_stream[subs->number];	}	if (stream->status != PCXHR_STREAM_STATUS_FREE){		/* streams in use */		snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n",			   chip->chip_idx, subs->number);		up(&mgr->setup_mutex);		return -EBUSY;	}	/* if a sample rate is already used or fixed by external clock,	 * the stream cannot change	 */	if (mgr->sample_rate)		runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;	else {		if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) {			int external_rate;			if (pcxhr_get_external_clock(mgr, mgr->use_clock_type,						     &external_rate) ||			    external_rate == 0) {				/* cannot detect the external clock rate */				up(&mgr->setup_mutex);				return -EBUSY;			}			runtime->hw.rate_min = runtime->hw.rate_max = external_rate;		}	}	stream->status      = PCXHR_STREAM_STATUS_OPEN;	stream->substream   = subs;	stream->channels    = 0; /* not configured yet */	runtime->private_data = stream;	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);	mgr->ref_count_rate++;	up(&mgr->setup_mutex);	return 0;}static int pcxhr_close(struct snd_pcm_substream *subs){

⌨️ 快捷键说明

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