static int minivosc_pcm_prepare(struct snd_pcm_substream *ss) { // copied from aloop-kernel.c // for one, we could get mydev from ss->private_data... // here we try it via ss->runtime->private_data instead. // turns out, this type of call via runtime->private_data // ends up with mydev as null pointer causing SIGSEGV // .. UNLESS runtime->private_data is assigned in _open? struct snd_pcm_runtime *runtime = ss->runtime; struct minivosc_device *mydev = runtime->private_data; unsigned int bps; dbg("%s", __func__); bps = runtime->rate * runtime->channels; // params requested by user app (arecord, audacity) bps *= snd_pcm_format_width(runtime->format); bps /= 8; if (bps <= 0) return -EINVAL; mydev->buf_pos = 0; mydev->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); dbg2(" bps: %u; runtime->buffer_size: %lu; mydev->pcm_buffer_size: %u", bps, runtime->buffer_size, mydev->pcm_buffer_size); if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { /* clear capture buffer */ mydev->silent_size = mydev->pcm_buffer_size; //memset(runtime->dma_area, 0, mydev->pcm_buffer_size); // we're in char land here, so let's mark prepare buffer with value 45 (signature) // this turns out to set everything permanently throughout - not just first buffer, // even though it runs only at start? memset(runtime->dma_area, 45, mydev->pcm_buffer_size); } if (!mydev->running) { mydev->irq_pos = 0; mydev->period_update_pending = 0; } mutex_lock(&mydev->cable_lock); if (!(mydev->valid & ~(1 << ss->stream))) { mydev->pcm_bps = bps; mydev->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); mydev->period_size_frac = frac_pos(mydev->pcm_period_size); } mydev->valid |= 1 << ss->stream; mutex_unlock(&mydev->cable_lock); dbg2(" pcm_period_size: %u; period_size_frac: %u", mydev->pcm_period_size, mydev->period_size_frac); return 0; }
/* call in cable->lock */ static void loopback_timer_start(struct loopback_pcm *dpcm) { unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); if (rate_shift != dpcm->pcm_rate_shift) { dpcm->pcm_rate_shift = rate_shift; dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); } if (dpcm->period_size_frac <= dpcm->irq_pos) { dpcm->irq_pos %= dpcm->period_size_frac; dpcm->period_update_pending = 1; } tick = dpcm->period_size_frac - dpcm->irq_pos; tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; mod_timer(&dpcm->timer, jiffies + tick); }