static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream, int dir, struct snd_xferi32 __user *data32) { compat_caddr_t buf; u32 frames; int err; if (! substream->runtime) return -ENOTTY; if (substream->stream != dir) return -EINVAL; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (get_user(buf, &data32->buf) || get_user(frames, &data32->frames)) return -EFAULT; if (dir == SNDRV_PCM_STREAM_PLAYBACK) err = snd_pcm_lib_write(substream, compat_ptr(buf), frames); else err = snd_pcm_lib_read(substream, compat_ptr(buf), frames); if (err < 0) return err; /* copy the result */ if (put_user(err, &data32->result)) return -EFAULT; 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; }
/** * 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; }