?? sa11xx-uda1341.c
字號:
snd_assert(dma_size <= DMA_BUF_SIZE, ); }#ifdef HH_VERSION ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size); if (ret) return; //FIXME#else ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size); if (ret) { printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret); return; }#endif s->period++; s->period %= runtime->periods; s->periods++; }}#ifdef HH_VERSIONstatic void audio_dma_callback(void *data, int size)#elsestatic void audio_dma_callback(void *data)#endif{ struct audio_stream *s = data; /* * If we are getting a callback for an active stream then we inform * the PCM middle layer we've finished a period */ if (s->active) snd_pcm_period_elapsed(s->stream); spin_lock(&s->dma_lock); if (!s->tx_spin && s->periods > 0) s->periods--; audio_process_dma(s); spin_unlock(&s->dma_lock);}/* }}} *//* {{{ PCM setting *//* {{{ trigger & timer */static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd){ struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream); int stream_id = substream->pstr->stream; struct audio_stream *s = &chip->s[stream_id]; struct audio_stream *s1 = &chip->s[stream_id ^ 1]; 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: /* now we need to make sure a record only stream has a clock */ if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { /* we need to force fill the xmit DMA with zeros */ s1->tx_spin = 1; audio_process_dma(s1); } /* this case is when you were recording then you turn on a * playback stream so we stop (also clears it) the dma first, * clear the sync flag and then we let it turned on */ else { s->tx_spin = 0; } /* requested stream startup */ s->active = 1; audio_process_dma(s); break; case SNDRV_PCM_TRIGGER_STOP: /* requested stream shutdown */ audio_stop_dma(s); /* * now we need to make sure a record only stream has a clock * so if we're stopping a playback with an active capture * we need to turn the 0 fill dma on for the xmit side */ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) { /* we need to force fill the xmit DMA with zeros */ s->tx_spin = 1; audio_process_dma(s); } /* * we killed a capture only stream, so we should also kill * the zero fill transmit */ else { if (s1->tx_spin) { s1->tx_spin = 0; audio_stop_dma(s1); } } break; case SNDRV_PCM_TRIGGER_SUSPEND: s->active = 0;#ifdef HH_VERSION sa1100_dma_stop(s->dmach);#else //FIXME - DMA API#endif s->old_offset = audio_get_dma_pos(s) + 1;#ifdef HH_VERSION sa1100_dma_flush_all(s->dmach);#else //FIXME - DMA API#endif s->periods = 0; break; case SNDRV_PCM_TRIGGER_RESUME: s->active = 1; s->tx_spin = 0; audio_process_dma(s); if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { s1->tx_spin = 1; audio_process_dma(s1); } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH:#ifdef HH_VERSION sa1100_dma_stop(s->dmach);#else //FIXME - DMA API#endif s->active = 0; if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { if (s1->active) { s->tx_spin = 1; s->old_offset = audio_get_dma_pos(s) + 1;#ifdef HH_VERSION sa1100_dma_flush_all(s->dmach);#else //FIXME - DMA API#endif audio_process_dma(s); } } else { if (s1->tx_spin) { s1->tx_spin = 0;#ifdef HH_VERSION sa1100_dma_flush_all(s1->dmach);#else //FIXME - DMA API#endif } } break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: s->active = 1; if (s->old_offset) { s->tx_spin = 0; audio_process_dma(s); break; } if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { s1->tx_spin = 1; audio_process_dma(s1); }#ifdef HH_VERSION sa1100_dma_resume(s->dmach);#else //FIXME - DMA API#endif break; default: err = -EINVAL; break; } spin_unlock(&s->dma_lock); return err;}static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream){ struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct audio_stream *s = &chip->s[substream->pstr->stream]; /* set requested samplerate */ sa11xx_uda1341_set_samplerate(chip, runtime->rate); /* set requestd format when available */ /* set FMT here !!! FIXME */ s->period = 0; s->periods = 0; return 0;}static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream){ struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream); return audio_get_dma_pos(&chip->s[substream->pstr->stream]);}/* }}} */static struct snd_pcm_hardware snd_sa11xx_uda1341_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 struct snd_pcm_hardware snd_sa11xx_uda1341_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_sa11xx_uda1341_open(struct snd_pcm_substream *substream){ struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int stream_id = substream->pstr->stream; int err; chip->s[stream_id].stream = substream; if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = snd_sa11xx_uda1341_playback; else runtime->hw = snd_sa11xx_uda1341_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_sa11xx_uda1341_close(struct snd_pcm_substream *substream){ struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream); chip->s[substream->pstr->stream].stream = NULL; return 0;}/* {{{ HW params & free */static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream){ return snd_pcm_lib_free_pages(substream);}/* }}} */static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = { .open = snd_card_sa11xx_uda1341_open, .close = snd_card_sa11xx_uda1341_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sa11xx_uda1341_hw_params, .hw_free = snd_sa11xx_uda1341_hw_free, .prepare = snd_sa11xx_uda1341_prepare, .trigger = snd_sa11xx_uda1341_trigger, .pointer = snd_sa11xx_uda1341_pointer,};static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = { .open = snd_card_sa11xx_uda1341_open, .close = snd_card_sa11xx_uda1341_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sa11xx_uda1341_hw_params, .hw_free = snd_sa11xx_uda1341_hw_free, .prepare = snd_sa11xx_uda1341_prepare, .trigger = snd_sa11xx_uda1341_trigger, .pointer = snd_sa11xx_uda1341_pointer,};static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device){ struct snd_pcm *pcm; int err; if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 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_isa_data(), 64*1024, 64*1024); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops); pcm->private_data = sa11xx_uda1341; pcm->info_flags = 0; strcpy(pcm->name, "UDA1341 PCM"); sa11xx_uda1341_audio_init(sa11xx_uda1341); /* setup DMA controller */ audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback); audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback); sa11xx_uda1341->pcm = pcm; return 0;}/* }}} *//* {{{ module init & exit */#ifdef CONFIG_PMstatic int snd_sa11xx_uda1341_suspend(struct platform_device *devptr, pm_message_t state){ struct snd_card *card = platform_get_drvdata(devptr); struct sa11xx_uda1341 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm);#ifdef HH_VERSION sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach); sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);#else //FIXME#endif l3_command(chip->uda1341, CMD_SUSPEND, NULL); sa11xx_uda1341_audio_shutdown(chip); return 0;}static int snd_sa11xx_uda1341_resume(struct platform_device *devptr){ struct snd_card *card = platform_get_drvdata(devptr); struct sa11xx_uda1341 *chip = card->private_data; sa11xx_uda1341_audio_init(chip); l3_command(chip->uda1341, CMD_RESUME, NULL);#ifdef HH_VERSION sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach); sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);#else //FIXME#endif snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endif /* COMFIG_PM */void snd_sa11xx_uda1341_free(struct snd_card *card){ struct sa11xx_uda1341 *chip = card->private_data; audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]); audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);}static int __init sa11xx_uda1341_probe(struct platform_device *devptr){ int err; struct snd_card *card; struct sa11xx_uda1341 *chip; /* register the soundcard */ card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341)); if (card == NULL) return -ENOMEM; chip = card->private_data; spin_lock_init(&chip->s[0].dma_lock); spin_lock_init(&chip->s[1].dma_lock); card->private_free = snd_sa11xx_uda1341_free; chip->card = card; chip->samplerate = AUDIO_RATE_DEFAULT; // mixer if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341))) goto nodev; // PCM if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0) goto nodev; strcpy(card->driver, "UDA1341"); strcpy(card->shortname, "H3600 UDA1341TS"); sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS"); snd_card_set_dev(card, &devptr->dev); if ((err = snd_card_register(card)) == 0) { printk( KERN_INFO "iPAQ audio support initialized\n" ); platform_set_drvdata(devptr, card); return 0; } nodev: snd_card_free(card); return err;}static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr){ snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); return 0;}#define SA11XX_UDA1341_DRIVER "sa11xx_uda1341"static struct platform_driver sa11xx_uda1341_driver = { .probe = sa11xx_uda1341_probe, .remove = __devexit_p(sa11xx_uda1341_remove),#ifdef CONFIG_PM .suspend = snd_sa11xx_uda1341_suspend, .resume = snd_sa11xx_uda1341_resume,#endif .driver = { .name = SA11XX_UDA1341_DRIVER, },};static int __init sa11xx_uda1341_init(void){ int err; if (!machine_is_h3xxx()) return -ENODEV; if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0) return err; device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0); if (IS_ERR(device)) { platform_driver_unregister(&sa11xx_uda1341_driver); return PTR_ERR(device); } return 0;}static void __exit sa11xx_uda1341_exit(void){ platform_device_unregister(device); platform_driver_unregister(&sa11xx_uda1341_driver);}module_init(sa11xx_uda1341_init);module_exit(sa11xx_uda1341_exit);/* }}} *//* * Local variables: * indent-tabs-mode: t * End: */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -