📄 nm256.c
字号:
runtime->rate = samplerates[rate_index]; switch (substream->stream) { case SNDRV_PCM_STREAM_PLAYBACK: snd_nm256_load_coefficient(chip, 0, rate_index); /* 0 = playback */ snd_nm256_writeb(chip, NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET, ratebits); break; case SNDRV_PCM_STREAM_CAPTURE: snd_nm256_load_coefficient(chip, 1, rate_index); /* 1 = record */ snd_nm256_writeb(chip, NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET, ratebits); break; }}/* acquire interrupt */static int snd_nm256_acquire_irq(struct nm256 *chip){ mutex_lock(&chip->irq_mutex); if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, chip->card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); mutex_unlock(&chip->irq_mutex); return -EBUSY; } chip->irq = chip->pci->irq; } chip->irq_acks++; mutex_unlock(&chip->irq_mutex); return 0;}/* release interrupt */static void snd_nm256_release_irq(struct nm256 *chip){ mutex_lock(&chip->irq_mutex); if (chip->irq_acks > 0) chip->irq_acks--; if (chip->irq_acks == 0 && chip->irq >= 0) { free_irq(chip->irq, chip); chip->irq = -1; } mutex_unlock(&chip->irq_mutex);}/* * start / stop *//* update the watermark (current period) */static void snd_nm256_pcm_mark(struct nm256 *chip, struct nm256_stream *s, int reg){ s->cur_period++; s->cur_period %= s->periods; snd_nm256_writel(chip, reg, s->buf + s->cur_period * s->period_size);}#define snd_nm256_playback_mark(chip, s) snd_nm256_pcm_mark(chip, s, NM_PBUFFER_WMARK)#define snd_nm256_capture_mark(chip, s) snd_nm256_pcm_mark(chip, s, NM_RBUFFER_WMARK)static voidsnd_nm256_playback_start(struct nm256 *chip, struct nm256_stream *s, struct snd_pcm_substream *substream){ /* program buffer pointers */ snd_nm256_writel(chip, NM_PBUFFER_START, s->buf); snd_nm256_writel(chip, NM_PBUFFER_END, s->buf + s->dma_size - (1 << s->shift)); snd_nm256_writel(chip, NM_PBUFFER_CURRP, s->buf); snd_nm256_playback_mark(chip, s); /* Enable playback engine and interrupts. */ snd_nm256_writeb(chip, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN); /* Enable both channels. */ snd_nm256_writew(chip, NM_AUDIO_MUTE_REG, 0x0);}static voidsnd_nm256_capture_start(struct nm256 *chip, struct nm256_stream *s, struct snd_pcm_substream *substream){ /* program buffer pointers */ snd_nm256_writel(chip, NM_RBUFFER_START, s->buf); snd_nm256_writel(chip, NM_RBUFFER_END, s->buf + s->dma_size); snd_nm256_writel(chip, NM_RBUFFER_CURRP, s->buf); snd_nm256_capture_mark(chip, s); /* Enable playback engine and interrupts. */ snd_nm256_writeb(chip, NM_RECORD_ENABLE_REG, NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN);}/* Stop the play engine. */static voidsnd_nm256_playback_stop(struct nm256 *chip){ /* Shut off sound from both channels. */ snd_nm256_writew(chip, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT); /* Disable play engine. */ snd_nm256_writeb(chip, NM_PLAYBACK_ENABLE_REG, 0);}static voidsnd_nm256_capture_stop(struct nm256 *chip){ /* Disable recording engine. */ snd_nm256_writeb(chip, NM_RECORD_ENABLE_REG, 0);}static intsnd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd){ struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; int err = 0; snd_assert(s != NULL, return -ENXIO); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: s->suspended = 0; /* fallthru */ case SNDRV_PCM_TRIGGER_START: if (! s->running) { snd_nm256_playback_start(chip, s, substream); s->running = 1; } break; case SNDRV_PCM_TRIGGER_SUSPEND: s->suspended = 1; /* fallthru */ case SNDRV_PCM_TRIGGER_STOP: if (s->running) { snd_nm256_playback_stop(chip); s->running = 0; } break; default: err = -EINVAL; break; } spin_unlock(&chip->reg_lock); return err;}static intsnd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd){ struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; int err = 0; snd_assert(s != NULL, return -ENXIO); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (! s->running) { snd_nm256_capture_start(chip, s, substream); s->running = 1; } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (s->running) { snd_nm256_capture_stop(chip); s->running = 0; } break; default: err = -EINVAL; break; } spin_unlock(&chip->reg_lock); return err;}/* * prepare playback/capture channel */static int snd_nm256_pcm_prepare(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; snd_assert(s, return -ENXIO); s->dma_size = frames_to_bytes(runtime, substream->runtime->buffer_size); s->period_size = frames_to_bytes(runtime, substream->runtime->period_size); s->periods = substream->runtime->periods; s->cur_period = 0; spin_lock_irq(&chip->reg_lock); s->running = 0; snd_nm256_set_format(chip, s, substream); spin_unlock_irq(&chip->reg_lock); return 0;}/* * get the current pointer */static snd_pcm_uframes_tsnd_nm256_playback_pointer(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; unsigned long curp; snd_assert(s, return 0); curp = snd_nm256_readl(chip, NM_PBUFFER_CURRP) - (unsigned long)s->buf; curp %= s->dma_size; return bytes_to_frames(substream->runtime, curp);}static snd_pcm_uframes_tsnd_nm256_capture_pointer(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; unsigned long curp; snd_assert(s != NULL, return 0); curp = snd_nm256_readl(chip, NM_RBUFFER_CURRP) - (unsigned long)s->buf; curp %= s->dma_size; return bytes_to_frames(substream->runtime, curp);}/* Remapped I/O space can be accessible as pointer on i386 *//* This might be changed in the future */#ifndef __i386__/* * silence / copy for playback */static intsnd_nm256_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, snd_pcm_uframes_t count){ struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); memset_io(s->bufptr + pos, 0, count); return 0;}static intsnd_nm256_playback_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count){ struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); if (copy_from_user_toio(s->bufptr + pos, src, count)) return -EFAULT; return 0;}/* * copy to user */static intsnd_nm256_capture_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){ struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); if (copy_to_user_fromio(dst, s->bufptr + pos, count)) return -EFAULT; return 0;}#endif /* !__i386__ *//* * update playback/capture watermarks *//* spinlock held! */static voidsnd_nm256_playback_update(struct nm256 *chip){ struct nm256_stream *s; s = &chip->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (s->running && s->substream) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(s->substream); spin_lock(&chip->reg_lock); snd_nm256_playback_mark(chip, s); }}/* spinlock held! */static voidsnd_nm256_capture_update(struct nm256 *chip){ struct nm256_stream *s; s = &chip->streams[SNDRV_PCM_STREAM_CAPTURE]; if (s->running && s->substream) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(s->substream); spin_lock(&chip->reg_lock); snd_nm256_capture_mark(chip, s); }}/* * hardware info */static struct snd_pcm_hardware snd_nm256_playback ={ .info = SNDRV_PCM_INFO_MMAP_IOMEM |SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .periods_min = 2, .periods_max = 1024, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 256, .period_bytes_max = 128 * 1024,};static struct snd_pcm_hardware snd_nm256_capture ={ .info = SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .periods_min = 2, .periods_max = 1024, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 256, .period_bytes_max = 128 * 1024,};/* set dma transfer size */static int snd_nm256_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ /* area and addr are already set and unchanged */ substream->runtime->dma_bytes = params_buffer_bytes(hw_params); return 0;}/* * open */static void snd_nm256_setup_stream(struct nm256 *chip, struct nm256_stream *s, struct snd_pcm_substream *substream, struct snd_pcm_hardware *hw_ptr){ struct snd_pcm_runtime *runtime = substream->runtime; s->running = 0; runtime->hw = *hw_ptr; runtime->hw.buffer_bytes_max = s->bufsize; runtime->hw.period_bytes_max = s->bufsize / 2; runtime->dma_area = (void __force *) s->bufptr; runtime->dma_addr = s->bufptr_addr; runtime->dma_bytes = s->bufsize; runtime->private_data = s; s->substream = substream; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);}static intsnd_nm256_playback_open(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); if (snd_nm256_acquire_irq(chip) < 0) return -EBUSY; snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK], substream, &snd_nm256_playback); return 0;}static intsnd_nm256_capture_open(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); if (snd_nm256_acquire_irq(chip) < 0) return -EBUSY; snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE], substream, &snd_nm256_capture); return 0;}/* * close - we don't have to do special.. */static intsnd_nm256_playback_close(struct snd_pcm_substream *substream){ struct nm256 *chip = snd_pcm_substream_chip(substream); snd_nm256_release_irq(chip); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -