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

📄 x900-wm8976.c

📁 这个代码是基于JADE X90+ wm8976 的 ALSA标准接口的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
			return;}static void audio_dma_capture_done(void *data){	audio_stream_t *s = data;	snd_pcm_substream_t * substream = s->substream;		//snd_pcm_runtime_t *runtime=substream->runtime;	//unsigned int dma_size,offset;			spin_lock(&s->dma_lock);	if (!s->tx_spin && s->periods > 0)		s->periods--;			snd_pcm_period_elapsed(s->substream);		audio_dma_start(s,audio_dma_capture_done,1);			spin_unlock(&s->dma_lock);			spin_unlock(&s->dma_lock);}/* }}} *//* {{{ PCM setting *//* {{{ trigger & timer */static int snd_x900_wm8976_playback_trigger(snd_pcm_substream_t * substream, int cmd){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	int stream_id = substream->pstr->stream;	audio_stream_t *s = &chip->s[stream_id];	int err = 0;		/* note local interrupts are already disabled in the midlevel code */	spin_lock(&s->dma_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		case SNDRV_PCM_TRIGGER_RESUME: 		if(s->dma_done) wait_for_completion(s->dma_done);		audio_dma_start(s,audio_dma_play_done,stream_id);				break;	case SNDRV_PCM_TRIGGER_STOP:			case SNDRV_PCM_TRIGGER_SUSPEND: 		audio_stop_dma(s);						break;	 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 				break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:				break;	}	spin_unlock(&s->dma_lock);		return err;}static int snd_x900_wm8976_capture_trigger(snd_pcm_substream_t * substream, int cmd){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	int stream_id = substream->pstr->stream;	audio_stream_t *s = &chip->s[stream_id];	int err = 0;		/* note local interrupts are already disabled in the midlevel code */	spin_lock(&s->dma_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		case SNDRV_PCM_TRIGGER_RESUME:		if(s->dma_done) wait_for_completion(s->dma_done);		audio_dma_start(s,audio_dma_capture_done,stream_id);				break;	case SNDRV_PCM_TRIGGER_STOP:			case SNDRV_PCM_TRIGGER_SUSPEND:		audio_stop_dma(s);						break;	 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 				break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:				break;	}	spin_unlock(&s->dma_lock);		return err;}static int snd_x900_wm8976_prepare(snd_pcm_substream_t * substream){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	audio_stream_t *s = &chip->s[substream->pstr->stream];        	/* set requested samplerate */	x900_wm8976_set_samplerate(chip, runtime->rate);		s->period = 0;	s->periods = 0;        	return 0;}static snd_pcm_uframes_t snd_x900_wm8976_pointer(snd_pcm_substream_t * substream){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int stream = substream->stream;		 int bytes = chip->s[stream].pa.tsize;	 return bytes_to_frames(runtime, bytes);}/* }}} */static snd_pcm_hardware_t snd_x900_wm8976_capture ={	.info			= (SNDRV_PCM_INFO_INTERLEAVED |				   SNDRV_PCM_INFO_BLOCK_TRANSFER |				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),	.formats		= SNDRV_PCM_FMTBIT_S16_LE,	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\				   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\				   SNDRV_PCM_RATE_KNOT),	.rate_min		= 8000,	.rate_max		= 48000,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 64,	.period_bytes_max	= DMA_BUF_SIZE,	.periods_min		= 2,	.periods_max		= 255,	.fifo_size		= 0,};static snd_pcm_hardware_t snd_x900_wm8976_playback ={	.info			= (SNDRV_PCM_INFO_INTERLEAVED |				   SNDRV_PCM_INFO_BLOCK_TRANSFER |				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),	.formats		= SNDRV_PCM_FMTBIT_S16_LE,	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\                                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\				   SNDRV_PCM_RATE_KNOT),	.rate_min		= 8000,	.rate_max		= 48000,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 64,	.period_bytes_max	= DMA_BUF_SIZE,	.periods_min		= 2,	.periods_max		= 255,	.fifo_size		= 0,};static int snd_card_x900_wm8976_open(snd_pcm_substream_t * substream){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int stream_id = substream->pstr->stream;	int err;	//	struct snd_dma_buffer *dma_buffer = substream->dma_buffer;	chip->s[stream_id].substream = substream;	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)		runtime->hw = snd_x900_wm8976_playback;	else		runtime->hw = snd_x900_wm8976_capture;		if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;		if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)		return err;			return 0;}static int snd_card_x900_wm8976_close(snd_pcm_substream_t * substream){	x900_wm8976_t *chip = snd_pcm_substream_chip(substream);	chip->s[substream->pstr->stream].substream = NULL;	return 0;}/* {{{ HW params & free */static int snd_x900_wm8976_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_x900_wm8976_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}/* }}} */static snd_pcm_ops_t snd_card_x900_wm8976_playback_ops = {	.open			= snd_card_x900_wm8976_open,	.close			= snd_card_x900_wm8976_close,	.ioctl			= snd_pcm_lib_ioctl,	.hw_params	        = snd_x900_wm8976_hw_params,	.hw_free	        = snd_x900_wm8976_hw_free,	.prepare		= snd_x900_wm8976_prepare,	.trigger		= snd_x900_wm8976_playback_trigger,	.pointer		= snd_x900_wm8976_pointer,};static snd_pcm_ops_t snd_card_x900_wm8976_capture_ops = {	.open			= snd_card_x900_wm8976_open,	.close			= snd_card_x900_wm8976_close,	.ioctl			= snd_pcm_lib_ioctl,		.hw_params	        = snd_x900_wm8976_hw_params,	.hw_free	        = snd_x900_wm8976_hw_free,	.prepare		= snd_x900_wm8976_prepare,	.trigger		= snd_x900_wm8976_capture_trigger,	.pointer		= snd_x900_wm8976_pointer,};static int __init snd_card_x900_wm8976_pcm(x900_wm8976_t *x900_wm8976, int device){	snd_pcm_t *pcm;	int err;	if ((err = snd_pcm_new(x900_wm8976->card, "WM8976 PCM", device, 1, 1, &pcm)) < 0)		return err;	/*	 * this sets up our initial buffers and sets the dma_type to isa.	 * isa works but I'm not sure why (or if) it's the right choice	 * this may be too large, trying it for now	 */	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 					      snd_dma_continuous_data(0),					     64*1024, 64*1024);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_x900_wm8976_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_x900_wm8976_capture_ops);	pcm->private_data = x900_wm8976;	pcm->info_flags = 0;	strcpy(pcm->name, "WM8976 PCM");	x900_wm8976_audio_init(x900_wm8976);		/* setup DMA controller */	audio_dma_request(&x900_wm8976->s[SNDRV_PCM_STREAM_PLAYBACK], 1);	audio_dma_request(&x900_wm8976->s[SNDRV_PCM_STREAM_CAPTURE], 0);	x900_wm8976->pcm = pcm;	return 0;}/* }}} *//* {{{ module init & exit */#ifdef CONFIG_PMstatic int snd_x900_wm8976_suspend(snd_card_t *card, pm_message_t state){	x900_wm8976_t *chip = card->pm_private_data;		unsigned char wm8976_for_suspend[]={0x43,0x0e,0x00};		snd_pcm_suspend_all(chip->pcm);	jade_command(chip->wm8976, wm8976_for_suspend);	x900_wm8976_audio_shutdown(chip);	return 0;}static int snd_x900_wm8976_resume(snd_card_t *card){	x900_wm8976_t *chip = card->pm_private_data;	unsigned char wm8976_for_resume[]={0x43,0x0e,0x00};		x900_wm8976_audio_init(chip);	jade_command(chip->wm8976, wm8976_for_resume);	/* we have a bug on suspend,so we must deal with carefully*/	audio_dma_request(&x900_wm8976->s[SNDRV_PCM_STREAM_PLAYBACK], 1);	audio_dma_request(&x900_wm8976->s[SNDRV_PCM_STREAM_CAPTURE], 0);	return 0;}#endif /* COMFIG_PM */void snd_x900_wm8976_free(snd_card_t *card){	x900_wm8976_t *chip = card->private_data;	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);	x900_wm8976 = NULL;	card->private_data = NULL;	kfree(chip);}static int __init x900_wm8976_init(){	int err;	snd_card_t *card;		if (!machine_is_x900())			return -ENODEV;	IIS_BASE = ioremap(IIS_BASE_HW, 0x1000);	if(IIS_BASE == 0){		printk("SOUND: i2s remap failed\n");		return -1;	}	/* register the soundcard */	card = snd_card_new(-1, id, THIS_MODULE, sizeof(x900_wm8976_t));	if (card == NULL)		return -ENOMEM;	x900_wm8976 = kcalloc(1, sizeof(*x900_wm8976), GFP_KERNEL);			if (x900_wm8976 == NULL)			return -ENOMEM;		//	x900_wm8976->s[0].dma_done=NULL;//	x900_wm8976->s[1].dma_done=NULL;	spin_lock_init(&x900_wm8976->s[0].dma_lock);	spin_lock_init(&x900_wm8976->s[1].dma_lock);         	card->private_data = (void *)x900_wm8976;	card->private_free = snd_x900_wm8976_free;	x900_wm8976->card = card;	x900_wm8976->samplerate = AUDIO_RATE_DEFAULT;	// mixer 		if ((err = snd_chip_wm8976_mixer_new(x900_wm8976->card, &x900_wm8976->wm8976))<0)		goto nodev;			// PCM	if ((err = snd_card_x900_wm8976_pcm(x900_wm8976, 0)) < 0)		goto nodev;        	snd_card_set_generic_pm_callback(card,				     snd_x900_wm8976_suspend, snd_x900_wm8976_resume,				     x900_wm8976);	strcpy(card->driver, "WM8976");	strcpy(card->shortname, "IIS WM8976");	sprintf(card->longname, "JADE-X900 IIS with Philips wm8976");	        	if ((err = snd_card_register(card)) == 0) {		printk( KERN_INFO "x900 audio support initialized\n" );				return 0;	}         nodev:	snd_card_free(card);	return err;}static void __exit x900_wm8976_exit(void){//	platform_device_unregister(device);//	platform_driver_unregister(&x900_wm8976_driver);	snd_card_free(x900_wm8976->card);}module_init(x900_wm8976_init);module_exit(x900_wm8976_exit);/* }}} */

⌨️ 快捷键说明

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