📄 x900-wm8976.c
字号:
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 + -