📄 pcm_compat.c
字号:
/* * 32bit -> 64bit ioctl wrapper for PCM API * Copyright (c) by Takashi Iwai <tiwai@suse.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* This file included from pcm_native.c */#include <linux/compat.h>static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, s32 __user *src){ snd_pcm_sframes_t delay; mm_segment_t fs; int err; fs = snd_enter_user(); err = snd_pcm_delay(substream, &delay); snd_leave_user(fs); if (err < 0) return err; if (put_user(delay, src)) return -EFAULT; return err;}static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, u32 __user *src){ snd_pcm_uframes_t frames; int err; if (get_user(frames, src)) return -EFAULT; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = snd_pcm_playback_rewind(substream, frames); else err = snd_pcm_capture_rewind(substream, frames); if (put_user(err, src)) return -EFAULT; return err < 0 ? err : 0;}static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream, u32 __user *src){ snd_pcm_uframes_t frames; int err; if (get_user(frames, src)) return -EFAULT; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = snd_pcm_playback_forward(substream, frames); else err = snd_pcm_capture_forward(substream, frames); if (put_user(err, src)) return -EFAULT; return err < 0 ? err : 0;}struct snd_pcm_hw_params32 { u32 flags; struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */ struct snd_mask mres[5]; /* reserved masks */ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; struct snd_interval ires[9]; /* reserved intervals */ u32 rmask; u32 cmask; u32 info; u32 msbits; u32 rate_num; u32 rate_den; u32 fifo_size; unsigned char reserved[64];};struct snd_pcm_sw_params32 { s32 tstamp_mode; u32 period_step; u32 sleep_min; u32 avail_min; u32 xfer_align; u32 start_threshold; u32 stop_threshold; u32 silence_threshold; u32 silence_size; u32 boundary; unsigned char reserved[64];};/* recalcuate the boundary within 32bit */static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime){ snd_pcm_uframes_t boundary; if (! runtime->buffer_size) return 0; boundary = runtime->buffer_size; while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) boundary *= 2; return boundary;}static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, struct snd_pcm_sw_params32 __user *src){ struct snd_pcm_sw_params params; snd_pcm_uframes_t boundary; int err; memset(¶ms, 0, sizeof(params)); if (get_user(params.tstamp_mode, &src->tstamp_mode) || get_user(params.period_step, &src->period_step) || get_user(params.sleep_min, &src->sleep_min) || get_user(params.avail_min, &src->avail_min) || get_user(params.xfer_align, &src->xfer_align) || get_user(params.start_threshold, &src->start_threshold) || get_user(params.stop_threshold, &src->stop_threshold) || get_user(params.silence_threshold, &src->silence_threshold) || get_user(params.silence_size, &src->silence_size)) return -EFAULT; /* * Check silent_size parameter. Since we have 64bit boundary, * silence_size must be compared with the 32bit boundary. */ boundary = recalculate_boundary(substream->runtime); if (boundary && params.silence_size >= boundary) params.silence_size = substream->runtime->boundary; err = snd_pcm_sw_params(substream, ¶ms); if (err < 0) return err; if (boundary && put_user(boundary, &src->boundary)) return -EFAULT; return err;}struct snd_pcm_channel_info32 { u32 channel; u32 offset; u32 first; u32 step;};static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream, struct snd_pcm_channel_info32 __user *src){ struct snd_pcm_channel_info info; int err; if (get_user(info.channel, &src->channel) || get_user(info.offset, &src->offset) || get_user(info.first, &src->first) || get_user(info.step, &src->step)) return -EFAULT; err = snd_pcm_channel_info(substream, &info); if (err < 0) return err; if (put_user(info.channel, &src->channel) || put_user(info.offset, &src->offset) || put_user(info.first, &src->first) || put_user(info.step, &src->step)) return -EFAULT; return err;}struct snd_pcm_status32 { s32 state; struct compat_timespec trigger_tstamp; struct compat_timespec tstamp; u32 appl_ptr; u32 hw_ptr; s32 delay; u32 avail; u32 avail_max; u32 overrange; s32 suspended_state; unsigned char reserved[60];} __attribute__((packed));static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, struct snd_pcm_status32 __user *src){ struct snd_pcm_status status; int err; err = snd_pcm_status(substream, &status); if (err < 0) return err; if (put_user(status.state, &src->state) || put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) || put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) || put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) || put_user(status.appl_ptr, &src->appl_ptr) || put_user(status.hw_ptr, &src->hw_ptr) || put_user(status.delay, &src->delay) || put_user(status.avail, &src->avail) || put_user(status.avail_max, &src->avail_max) || put_user(status.overrange, &src->overrange) || put_user(status.suspended_state, &src->suspended_state)) return -EFAULT; return err;}/* both for HW_PARAMS and HW_REFINE */static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, int refine, struct snd_pcm_hw_params32 __user *data32){ struct snd_pcm_hw_params *data; struct snd_pcm_runtime *runtime; int err; if (! (runtime = substream->runtime)) return -ENOTTY; data = kmalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; /* only fifo_size is different, so just copy all */ if (copy_from_user(data, data32, sizeof(*data32))) { err = -EFAULT; goto error; } if (refine) err = snd_pcm_hw_refine(substream, data); else err = snd_pcm_hw_params(substream, data); if (err < 0) goto error; if (copy_to_user(data32, data, sizeof(*data32)) || put_user(data->fifo_size, &data32->fifo_size)) { err = -EFAULT; goto error; } if (! refine) { unsigned int new_boundary = recalculate_boundary(runtime); if (new_boundary) runtime->boundary = new_boundary; } error: kfree(data); return err;}/* */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -