/** * Set default hardware params */ static int playback_default_hw_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_hw_params *params; snd_pcm_sframes_t result; /* * SNDRV_PCM_ACCESS_RW_INTERLEAVED, * SNDRV_PCM_FORMAT_S16_LE * CHANNELS: 2 * RATE: 48000 */ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 2; snd->rate = 48000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) { ERROR(snd->card, "Preparing sound card failed: %d\n", (int)result); kfree(params); return result; } /* Store the hardware parameters */ snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); kfree(params); INFO(snd->card, "Hardware params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return 0; }
static int playback_prepare_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_hw_params *params; snd_pcm_sframes_t result; snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 2; snd->rate = 8000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (result < 0) pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (result < 0) { pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result); kfree(params); return result; } result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) pr_err("Preparing playback failed: %d\n", (int)result); snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); kfree(params); pr_debug("playback params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return 0; }
static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) { struct gaudio_snd_dev *snd = &card->playback; struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; mm_segment_t old_fs; ssize_t result; snd_pcm_sframes_t frames; int err = 0; if (!count) { pr_err("Buffer is empty, no data to play"); return 0; } if (!audio_reinit) { err = gaudio_open_streams(); if (err) { pr_err("Failed to init audio streams"); return 0; } audio_reinit = 1; } try_again: if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED || runtime->status->state == SNDRV_PCM_STATE_SETUP) { result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) { pr_err("Preparing playback failed: %d\n", (int)result); return result; } } if (!runtime->frame_bits) { pr_err("SND failure - runtime->frame_bits == 0"); return 0; } frames = bytes_to_frames(runtime, count); pr_debug("runtime->frame_bits = %d, count = %d, frames = %d", runtime->frame_bits, (int)count, (int)frames); old_fs = get_fs(); set_fs(KERNEL_DS); result = snd_pcm_lib_write(snd->substream, buf, frames); if (result != frames) { pr_err("snd_pcm_lib_write failed with err %d\n", (int)result); set_fs(old_fs); goto try_again; } set_fs(old_fs); pr_debug("Done. Sent %d frames", (int)frames); return 0; }
int ksnd_pcm_start(ksnd_pcm_t *kpcm) { snd_pcm_substream_t *substream = kpcm->substream; if (substream != NULL) snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL); return 0; }
/** * Playback audio buffer data by ALSA PCM device */ static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) { struct gaudio_snd_dev *snd = &card->playback; struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; mm_segment_t old_fs; ssize_t result; snd_pcm_sframes_t frames; try_again: if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) { ERROR(card, "Preparing sound card failed: %d\n", (int)result); return result; } } frames = bytes_to_frames(runtime, count); old_fs = get_fs(); set_fs(KERNEL_DS); result = snd_pcm_lib_write(snd->substream, buf, frames); if (result != frames) { ERROR(card, "Playback error: %d\n", (int)result); set_fs(old_fs); goto try_again; } set_fs(old_fs); return 0; }
int ksnd_pcm_prepare(ksnd_pcm_t *kpcm) { int err; snd_pcm_substream_t *substream = kpcm->substream; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { snd_printd("alsa_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n"); return err; } return 0; }
int ksnd_pcm_hw_params(ksnd_pcm_t *kpcm, ksnd_pcm_hw_params_t *params) { snd_pcm_substream_t *substream = kpcm->substream; int err; if (substream == NULL) return -EFAULT; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (0 != err) return err; kpcm->actual_hwparams = *params; return 0; }
int ksnd_pcm_delay(ksnd_pcm_t *pcm, snd_pcm_sframes_t *delay) { snd_pcm_substream_t *substream = pcm->substream; snd_pcm_sframes_t frames; int err; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &frames); if (err < 0) { return err; } *delay = frames; return 0; }
static size_t u_audio_capture(struct gaudio *card, void *buf, size_t count) { ssize_t result; mm_segment_t old_fs; snd_pcm_sframes_t frames; int err = 0; struct gaudio_snd_dev *snd = &card->capture; struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; if (!audio_reinit) { err = gaudio_open_streams(); if (err) { pr_err("Failed to init audio streams: err %d", err); return 0; } audio_reinit = 1; } try_again: if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED || runtime->status->state == SNDRV_PCM_STATE_SETUP) { result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) { pr_err("Preparing capture failed: %d\n", (int)result); return result; } } frames = bytes_to_frames(runtime, count); old_fs = get_fs(); set_fs(KERNEL_DS); pr_debug("frames = %d, count = %d", (int)frames, count); result = snd_pcm_lib_read(substream, buf, frames); if (result != frames) { pr_err("Capture error: %d\n", (int)result); set_fs(old_fs); goto try_again; } set_fs(old_fs); return 0; }
static int capture_prepare_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params; struct snd_pcm_sw_params *swparams; unsigned long period_size; unsigned long buffer_size; snd_pcm_sframes_t result = 0; snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 1; snd->rate = 8000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { pr_err("Failed to allocate hw params"); return -ENOMEM; } _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (result < 0) pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (result < 0) { pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result); kfree(params); return result; } result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) pr_err("Preparing capture failed: %d\n", (int)result); snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); runtime->frame_bits = snd_pcm_format_physical_width(runtime->format); swparams = kzalloc(sizeof(*swparams), GFP_KERNEL); if (!swparams) { pr_err("Failed to allocate sw params"); kfree(params); return -ENOMEM; } buffer_size = pcm_buffer_size(params); period_size = pcm_period_size(params); swparams->avail_min = period_size/2; swparams->xfer_align = period_size/2; kfree(params); swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; swparams->period_step = 1; swparams->start_threshold = 1; swparams->stop_threshold = INT_MAX; swparams->silence_size = 0; swparams->silence_threshold = 0; result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, swparams); if (result < 0) pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result); kfree(swparams); pr_debug("capture params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return result; }
int ksnd_pcm_set_params(ksnd_pcm_t *pcm, int nrchannels, int sampledepth, int samplerate, int periodsize, int buffersize) { snd_pcm_substream_t *substream = pcm->substream; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_hw_params_t *hw_params = NULL; snd_pcm_sw_params_t *sw_params = NULL; int err; int format; snd_mask_t mask; int i; void *hwbuf; err = ksnd_pcm_hw_params_malloc(&hw_params); if (0 != err) goto failure; sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); if (!sw_params) { err = -ENOMEM; goto failure; } switch (sampledepth) { case 16: format = SNDRV_PCM_FORMAT_S16_LE; break; case 24: sampledepth = 32; /*FALLTHRU*/ case 32: format = SNDRV_PCM_FORMAT_S32_LE; break; default: snd_printd("%s Unsupported sampledepth %d\n", __FUNCTION__, sampledepth); err = -EINVAL; goto failure; } err = ksnd_pcm_hw_params_any(pcm, hw_params); if (snd_BUG_ON(err < 0)) goto failure; _snd_pcm_hw_param_setinteger(hw_params, SNDRV_PCM_HW_PARAM_PERIODS); _snd_pcm_hw_param_min(hw_params, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); snd_mask_none(&mask); snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); err = snd_pcm_hw_param_mask(substream, hw_params, SNDRV_PCM_HW_PARAM_ACCESS, &mask); if (err < 0) { err = -EINVAL; goto failure; } err = snd_pcm_hw_param_set(substream, hw_params, SNDRV_PCM_HW_PARAM_RATE, samplerate, 0); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_CHANNELS, nrchannels, NULL); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_FORMAT, format, 0); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, periodsize, NULL); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, buffersize, NULL); if (snd_BUG_ON(err < 0)) goto failure; _ksnd_pcm_drop(substream); /*now we re-use the 61937 control to enable the HW sync mechanism */ if (0 != (err = ksnd_pcm_hw_params(pcm, hw_params) < 0)) { snd_printd("HW_PARAMS failed: for %d:%d code is %i\n", substream->pcm->card->number, substream->pcm->device, err); goto failure; } memset(sw_params, 0, sizeof(*sw_params)); sw_params->start_threshold = (runtime->buffer_size - (runtime->period_size * 2)); sw_params->stop_threshold = runtime->buffer_size; sw_params->period_step = 1; sw_params->sleep_min = 0; sw_params->avail_min = runtime->period_size; sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sw_params->silence_threshold = runtime->period_size; sw_params->silence_size = runtime->period_size; if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { snd_printd("SW_PARAMS failed: for %d:%d code is %i\n", substream->pcm->card->number, substream->pcm->device, err); goto failure; } if ((err = ksnd_pcm_prepare(pcm)) < 0) goto failure; if (pcm->hwareas[0].addr) iounmap(pcm->hwareas[0].addr); hwbuf = ioremap_nocache(runtime->dma_addr, runtime->dma_bytes); for (i = 0; i < nrchannels; i++) { pcm->hwareas[i].addr = hwbuf; pcm->hwareas[i].first = i * sampledepth; pcm->hwareas[i].step = nrchannels * sampledepth; } nrchannels = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS, 0); samplerate = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_RATE, 0); periodsize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 0); buffersize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0); printk(KERN_DEBUG "ksound: Set parameters for hw:%d,%d to %d x %dhz with period %d (of %d)\n", substream->pcm->card->number, substream->pcm->device, nrchannels, samplerate, periodsize, buffersize); err = 0; failure: if (hw_params) ksnd_pcm_hw_params_free(hw_params); if (sw_params) kfree(sw_params); return err; }
static inline int _ksnd_pcm_pause(snd_pcm_substream_t *substream, unsigned int push) { snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PAUSE, (void *) push); return 0; }
static inline int _ksnd_pcm_drain(snd_pcm_substream_t *substream) { snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); return 0; }