📄 rme9652.c
字号:
snd_rme9652_free_buffer(rme9652->dev, rme9652->playback_buffer_unaligned);#endif }}static int snd_rme9652_free(rme9652_t *rme9652){ if (rme9652->irq >= 0) rme9652_stop(rme9652); snd_rme9652_proc_done(rme9652); snd_rme9652_free_buffers(rme9652); if (rme9652->iobase) iounmap((void *) rme9652->iobase); if (rme9652->res_port) { release_resource(rme9652->res_port); kfree_nocheck(rme9652->res_port); } if (rme9652->irq >= 0) free_irq(rme9652->irq, (void *)rme9652); return 0;}static int __init snd_rme9652_initialize_memory(rme9652_t *rme9652){ void *pb, *cb; dma_addr_t pb_addr, cb_addr; unsigned long pb_bus, cb_bus;#ifndef RME9652_PREALLOCATE_MEMORY cb = snd_malloc_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, &cb_addr); pb = snd_malloc_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, &pb_addr);#else cb = snd_rme9652_get_buffer(rme9652->dev, &cb_addr); pb = snd_rme9652_get_buffer(rme9652->dev, &pb_addr);#endif if (cb == 0 || pb == 0) { if (cb) {#ifdef RME9652_PREALLOCATE_MEMORY snd_rme9652_free_buffer(rme9652->dev, cb);#else snd_free_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, cb, cb_addr);#endif } if (pb) {#ifdef RME9652_PREALLOCATE_MEMORY snd_rme9652_free_buffer(rme9652->dev, pb);#else snd_free_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, pb, pb_addr);#endif } printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name); return -ENOMEM; } /* save raw addresses for use when freeing memory later */ rme9652->capture_buffer_unaligned = cb; rme9652->playback_buffer_unaligned = pb; rme9652->capture_buffer_addr = cb_addr; rme9652->playback_buffer_addr = pb_addr; /* Align to bus-space 64K boundary */ cb_bus = (cb_addr + 0xFFFF) & ~0xFFFFl; pb_bus = (pb_addr + 0xFFFF) & ~0xFFFFl; /* 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 = cb + (cb_bus - cb_addr); rme9652->playback_buffer = pb + (pb_bus - pb_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);}void 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; } 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); }}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 *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); copy_from_user(channel_buf + pos * 4, src, count * 4); return count;}static int snd_rme9652_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void *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); copy_to_user(dst, channel_buf + pos * 4, count * 4); 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) { snd_pcm_substream_t *s = substream; snd_pcm_runtime_t *oruntime = other->runtime; do { s = s->link_next; if (s == other) { oruntime->status->hw_ptr = runtime->status->hw_ptr; break; } } while (s != substream); } 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 (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) { snd_pcm_substream_t *s = substream; do { s = s->link_next; 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; } } while (s != substream); 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); } } _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); int result = 0; spin_lock_irq(&rme9652->lock); if (!rme9652->running) rme9652_reset_hw_pointer(rme9652); spin_unlock_irq(&rme9652->lock); 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: 1024*1024, period_bytes_min: 1, period_bytes_max: 1024*1024, 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_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -