📄 rme9652.c
字号:
snd_iprintf(buffer, "%2d: off ", i + 1); } if (((i + 1) % 8) == 0) { snd_iprintf(buffer, "\n"); } } snd_iprintf(buffer, "\n");}static void __devinit snd_rme9652_proc_init(rme9652_t *rme9652){ snd_info_entry_t *entry; if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read);}static void snd_rme9652_free_buffers(rme9652_t *rme9652){ if (rme9652->capture_buffer_unaligned) { snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, rme9652->capture_buffer_unaligned, rme9652->capture_buffer_addr, 1); } if (rme9652->playback_buffer_unaligned) { snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, rme9652->playback_buffer_unaligned, rme9652->playback_buffer_addr, 0); }}static int snd_rme9652_free(rme9652_t *rme9652){ if (rme9652->irq >= 0) rme9652_stop(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 __devinit snd_rme9652_initialize_memory(rme9652_t *rme9652){ void *pb, *cb; dma_addr_t pb_addr, cb_addr; unsigned long pb_bus, cb_bus; cb = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, &cb_addr, 1); pb = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, &pb_addr, 0); if (cb == 0 || pb == 0) { if (cb) { snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, cb, cb_addr, 1); } if (pb) { snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, pb, pb_addr, 0); } 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);}static irqreturn_t 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 IRQ_NONE; } 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); } return IRQ_HANDLED;}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 __user *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); if (copy_from_user(channel_buf + pos * 4, src, count * 4)) return -EFAULT; return count;}static int snd_rme9652_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *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); if (copy_to_user(dst, channel_buf + pos * 4, count * 4)) return -EFAULT; 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) { struct list_head *pos; snd_pcm_substream_t *s; snd_pcm_runtime_t *oruntime = other->runtime; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if (s == other) { oruntime->status->hw_ptr = runtime->status->hw_ptr; break; } } } 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 ((int)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) { struct list_head *pos; snd_pcm_substream_t *s; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); 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; } } 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); } } else { if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 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(&rme9652->lock); if (!rme9652->running) rme9652_reset_hw_pointer(rme9652); spin_unlock(&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), .ra
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -