📄 rme9652.c
字号:
/* 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 = rme9652->capture_dma_buf.area + (cb_bus - rme9652->capture_dma_buf.addr); rme9652->playback_buffer = rme9652->playback_dma_buf.area + (pb_bus - rme9652->playback_dma_buf.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); unsigned long flags; int result = 0; spin_lock_irqsave(&rme9652->lock, flags); if (!rme9652->running) rme9652_reset_hw_pointer(rme9652); spin_unlock_irqrestore(&rme9652->lock, flags); 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 = RME9652_CHANNEL_BUFFER_BYTES * 26, .period_bytes_min = (64 * 4) * 10, .period_bytes_max = (8192 * 4) * 26, .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_RATE_96000), .rate_min = 44100, .rate_max = 96000, .channels_min = 10, .channels_max = 26, .buffer_bytes_max = RME9652_CHANNEL_BUFFER_BYTES *26, .period_bytes_min = (64 * 4) * 10, .period_bytes_max = (8192 * 4) * 26, .periods_min = 2, .periods_max = 2, .fifo_size = 0,};static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { .count = ARRAY_SIZE(period_sizes), .list = period_sizes, .mask = 0};static int snd_rme9652_hw_rule_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule){ rme9652_t *rme9652 = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); unsigned int list[2] = { rme9652->ds_channels, rme9652->ss_channels }; return snd_interval_list(c, 2, list, 0);}static int snd_rme9652_hw_rule_channels_rate(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule){ rme9652_t *rme9652 = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); if (r->min > 48000) { snd_interval_t t = { .min = rme9652->ds_channels, .max = rme9652->ds_channels, .integer = 1, }; return snd_interval_refine(c, &t); } else if (r->max < 88200) { snd_interval_t t = { .min = rme9652->ss_channels, .max = rme9652->ss_channels, .integer = 1, }; return snd_interval_refine(c, &t); } return 0;}static int snd_rme9652_hw_rule_rate_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule){ rme9652_t *rme9652 = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); if (c->min >= rme9652->ss_channels) { snd
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -