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

📄 rme9652.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Tell the card where it is */	rme9652_write(rme9652, RME9652_rec_buffer, cb_bus);	rme9652_write(rme9652, RME9652_play_buffer, pb_bus);	rme9652->capture_buffer = rme9652->capture_dma_buf.area + (cb_bus - rme9652->capture_dma_buf.addr);	rme9652->playback_buffer = rme9652->playback_dma_buf.area + (pb_bus - rme9652->playback_dma_buf.addr);	return 0;}static void snd_rme9652_set_defaults(rme9652_t *rme9652){	unsigned int k;	/* ASSUMPTION: rme9652->lock is either held, or	   there is no need to hold it (e.g. during module	   initalization).	 */	/* set defaults:	   SPDIF Input via Coax 	   autosync clock mode	   maximum latency (7 = 8192 samples, 64Kbyte buffer,	   which implies 2 4096 sample, 32Kbyte periods).	   	   if rev 1.5, initialize the S/PDIF receiver.	 */	rme9652->control_register =	    RME9652_inp_0 | rme9652_encode_latency(7);	rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);	rme9652_reset_hw_pointer(rme9652);	rme9652_compute_period_size(rme9652);	/* default: thru off for all channels */	for (k = 0; k < RME9652_NCHANNELS; ++k)		rme9652_write(rme9652, RME9652_thru_base + k * 4, 0);	rme9652->thru_bits = 0;	rme9652->passthru = 0;	/* set a default rate so that the channel map is set up */	rme9652_set_rate(rme9652, 48000);}static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id, struct pt_regs *regs){	rme9652_t *rme9652 = (rme9652_t *) dev_id;	if (!(rme9652_read(rme9652, RME9652_status_register) & RME9652_IRQ)) {		return IRQ_NONE;	}	rme9652_write(rme9652, RME9652_irq_clear, 0);	if (rme9652->capture_substream) {		snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);	}	if (rme9652->playback_substream) {		snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);	}	return IRQ_HANDLED;}static snd_pcm_uframes_t snd_rme9652_hw_pointer(snd_pcm_substream_t *substream){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	return rme9652_hw_pointer(rme9652);}static char *rme9652_channel_buffer_location(rme9652_t *rme9652,					     int stream,					     int channel){	int mapped_channel;        snd_assert(channel >= 0 || channel < RME9652_NCHANNELS, return NULL);        	if ((mapped_channel = rme9652->channel_map[channel]) < 0) {		return NULL;	}		if (stream == SNDRV_PCM_STREAM_CAPTURE) {		return rme9652->capture_buffer +			(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);	} else {		return rme9652->playback_buffer +			(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);	}}static int snd_rme9652_playback_copy(snd_pcm_substream_t *substream, int channel,				     snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	char *channel_buf;	snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);	channel_buf = rme9652_channel_buffer_location (rme9652,						       substream->pstr->stream,						       channel);	snd_assert(channel_buf != NULL, return -EIO);	if (copy_from_user(channel_buf + pos * 4, src, count * 4))		return -EFAULT;	return count;}static int snd_rme9652_capture_copy(snd_pcm_substream_t *substream, int channel,				    snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	char *channel_buf;	snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL);	channel_buf = rme9652_channel_buffer_location (rme9652,						       substream->pstr->stream,						       channel);	snd_assert(channel_buf != NULL, return -EIO);	if (copy_to_user(dst, channel_buf + pos * 4, count * 4))		return -EFAULT;	return count;}static int snd_rme9652_hw_silence(snd_pcm_substream_t *substream, int channel,				  snd_pcm_uframes_t pos, snd_pcm_uframes_t count){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	char *channel_buf;	channel_buf = rme9652_channel_buffer_location (rme9652,						       substream->pstr->stream,						       channel);	snd_assert(channel_buf != NULL, return -EIO);	memset(channel_buf + pos * 4, 0, count * 4);	return count;}static int snd_rme9652_reset(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	snd_pcm_substream_t *other;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)		other = rme9652->capture_substream;	else		other = rme9652->playback_substream;	if (rme9652->running)		runtime->status->hw_ptr = rme9652_hw_pointer(rme9652);	else		runtime->status->hw_ptr = 0;	if (other) {		struct list_head *pos;		snd_pcm_substream_t *s;		snd_pcm_runtime_t *oruntime = other->runtime;		snd_pcm_group_for_each(pos, substream) {			s = snd_pcm_group_substream_entry(pos);			if (s == other) {				oruntime->status->hw_ptr = runtime->status->hw_ptr;				break;			}		}	}	return 0;}static int snd_rme9652_hw_params(snd_pcm_substream_t *substream,				 snd_pcm_hw_params_t *params){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	int err;	pid_t this_pid;	pid_t other_pid;	spin_lock_irq(&rme9652->lock);	if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {		rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);		rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream);		this_pid = rme9652->playback_pid;		other_pid = rme9652->capture_pid;	} else {		this_pid = rme9652->capture_pid;		other_pid = rme9652->playback_pid;	}	if ((other_pid > 0) && (this_pid != other_pid)) {		/* The other stream is open, and not by the same		   task as this one. Make sure that the parameters		   that matter are the same.		 */		if ((int)params_rate(params) !=		    rme9652_adat_sample_rate(rme9652)) {			spin_unlock_irq(&rme9652->lock);			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);			return -EBUSY;		}		if (params_period_size(params) != rme9652->period_bytes / 4) {			spin_unlock_irq(&rme9652->lock);			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);			return -EBUSY;		}		/* We're fine. */		spin_unlock_irq(&rme9652->lock); 		return 0;	} else {		spin_unlock_irq(&rme9652->lock);	}	/* how to make sure that the rate matches an externally-set one ?	 */	if ((err = rme9652_set_rate(rme9652, params_rate(params))) < 0) {		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);		return err;	}	if ((err = rme9652_set_interrupt_interval(rme9652, params_period_size(params))) < 0) {		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);		return err;	}	return 0;}static int snd_rme9652_channel_info(snd_pcm_substream_t *substream,				    snd_pcm_channel_info_t *info){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	int chn;	snd_assert(info->channel < RME9652_NCHANNELS, return -EINVAL);	if ((chn = rme9652->channel_map[info->channel]) < 0) {		return -EINVAL;	}	info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES;	info->first = 0;	info->step = 32;	return 0;}static int snd_rme9652_ioctl(snd_pcm_substream_t *substream,			     unsigned int cmd, void *arg){	switch (cmd) {	case SNDRV_PCM_IOCTL1_RESET:	{		return snd_rme9652_reset(substream);	}	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:	{		snd_pcm_channel_info_t *info = arg;		return snd_rme9652_channel_info(substream, info);	}	default:		break;	}	return snd_pcm_lib_ioctl(substream, cmd, arg);}static void rme9652_silence_playback(rme9652_t *rme9652){	memset(rme9652->playback_buffer, 0, RME9652_DMA_AREA_BYTES);}static int snd_rme9652_trigger(snd_pcm_substream_t *substream,			       int cmd){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	snd_pcm_substream_t *other;	int running;	spin_lock(&rme9652->lock);	running = rme9652->running;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		running |= 1 << substream->stream;		break;	case SNDRV_PCM_TRIGGER_STOP:		running &= ~(1 << substream->stream);		break;	default:		snd_BUG();		spin_unlock(&rme9652->lock);		return -EINVAL;	}	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)		other = rme9652->capture_substream;	else		other = rme9652->playback_substream;	if (other) {		struct list_head *pos;		snd_pcm_substream_t *s;		snd_pcm_group_for_each(pos, substream) {			s = snd_pcm_group_substream_entry(pos);			if (s == other) {				snd_pcm_trigger_done(s, substream);				if (cmd == SNDRV_PCM_TRIGGER_START)					running |= 1 << s->stream;				else					running &= ~(1 << s->stream);				goto _ok;			}		}		if (cmd == SNDRV_PCM_TRIGGER_START) {			if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&			    substream->stream == SNDRV_PCM_STREAM_CAPTURE)				rme9652_silence_playback(rme9652);		} else {			if (running &&			    substream->stream == SNDRV_PCM_STREAM_PLAYBACK)				rme9652_silence_playback(rme9652);		}	} else {		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 			rme9652_silence_playback(rme9652);	} _ok:	snd_pcm_trigger_done(substream, substream);	if (!rme9652->running && running)		rme9652_start(rme9652);	else if (rme9652->running && !running)		rme9652_stop(rme9652);	rme9652->running = running;	spin_unlock(&rme9652->lock);	return 0;}static int snd_rme9652_prepare(snd_pcm_substream_t *substream){	rme9652_t *rme9652 = snd_pcm_substream_chip(substream);	unsigned long flags;	int result = 0;	spin_lock_irqsave(&rme9652->lock, flags);	if (!rme9652->running)		rme9652_reset_hw_pointer(rme9652);	spin_unlock_irqrestore(&rme9652->lock, flags);	return result;}static snd_pcm_hardware_t snd_rme9652_playback_subinfo ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_NONINTERLEAVED |				 SNDRV_PCM_INFO_SYNC_START |				 SNDRV_PCM_INFO_DOUBLE),	.formats =		SNDRV_PCM_FMTBIT_S32_LE,	.rates =		(SNDRV_PCM_RATE_44100 | 				 SNDRV_PCM_RATE_48000 | 				 SNDRV_PCM_RATE_88200 | 				 SNDRV_PCM_RATE_96000),	.rate_min =		44100,	.rate_max =		96000,	.channels_min =		10,	.channels_max =		26,	.buffer_bytes_max =	RME9652_CHANNEL_BUFFER_BYTES * 26,	.period_bytes_min =	(64 * 4) * 10,	.period_bytes_max =	(8192 * 4) * 26,	.periods_min =		2,	.periods_max =		2,	.fifo_size =		0,};static snd_pcm_hardware_t snd_rme9652_capture_subinfo ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_NONINTERLEAVED |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		SNDRV_PCM_FMTBIT_S32_LE,	.rates =		(SNDRV_PCM_RATE_44100 | 				 SNDRV_PCM_RATE_48000 | 				 SNDRV_PCM_RATE_88200 | 				 SNDRV_PCM_RATE_96000),	.rate_min =		44100,	.rate_max =		96000,	.channels_min =		10,	.channels_max =		26,	.buffer_bytes_max =	RME9652_CHANNEL_BUFFER_BYTES *26,	.period_bytes_min =	(64 * 4) * 10,	.period_bytes_max =	(8192 * 4) * 26,	.periods_min =		2,	.periods_max =		2,	.fifo_size =		0,};static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = {	.count = ARRAY_SIZE(period_sizes),	.list = period_sizes,	.mask = 0};static int snd_rme9652_hw_rule_channels(snd_pcm_hw_params_t *params,					snd_pcm_hw_rule_t *rule){	rme9652_t *rme9652 = rule->private;	snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);	unsigned int list[2] = { rme9652->ds_channels, rme9652->ss_channels };	return snd_interval_list(c, 2, list, 0);}static int snd_rme9652_hw_rule_channels_rate(snd_pcm_hw_params_t *params,					     snd_pcm_hw_rule_t *rule){	rme9652_t *rme9652 = rule->private;	snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);	if (r->min > 48000) {		snd_interval_t t = {			.min = rme9652->ds_channels,			.max = rme9652->ds_channels,			.integer = 1,		};		return snd_interval_refine(c, &t);	} else if (r->max < 88200) {		snd_interval_t t = {			.min = rme9652->ss_channels,			.max = rme9652->ss_channels,			.integer = 1,		};		return snd_interval_refine(c, &t);	}	return 0;}static int snd_rme9652_hw_rule_rate_channels(snd_pcm_hw_params_t *params,					     snd_pcm_hw_rule_t *rule){	rme9652_t *rme9652 = rule->private;	snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);	if (c->min >= rme9652->ss_channels) {		snd

⌨️ 快捷键说明

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