Esempio n. 1
0
/*
 * xfern ioctl nees to copy (up to) 128 pointers on stack.
 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
 * handler there expands again the same 128 pointers on stack, so it is better
 * to handle the function (calling pcm_readv/writev) directly in this handler.
 */
static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
				      int dir, struct snd_xfern32 __user *data32)
{
	compat_caddr_t buf;
	compat_caddr_t __user *bufptr;
	u32 frames;
	void __user **bufs;
	int err, ch, i;

	if (! substream->runtime)
		return -ENOTTY;
	if (substream->stream != dir)
		return -EINVAL;

	if ((ch = substream->runtime->channels) > 128)
		return -EINVAL;
	if (get_user(buf, &data32->bufs) ||
	    get_user(frames, &data32->frames))
		return -EFAULT;
	bufptr = compat_ptr(buf);
	bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
	if (bufs == NULL)
		return -ENOMEM;
	for (i = 0; i < ch; i++) {
		u32 ptr;
		if (get_user(ptr, bufptr)) {
			kfree(bufs);
			return -EFAULT;
		}
		bufs[i] = compat_ptr(ptr);
		bufptr++;
	}
	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
		err = snd_pcm_lib_writev(substream, bufs, frames);
	else
		err = snd_pcm_lib_readv(substream, bufs, frames);
	if (err >= 0) {
		if (put_user(err, &data32->result))
			err = -EFAULT;
	}
	kfree(bufs);
	return err;
}
Esempio n. 2
0
/*
 * xfern ioctl nees to copy (up to) 128 pointers on stack.
 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
 * handler there expands again the same 128 pointers on stack, so it is better
 * to handle the function (calling pcm_readv/writev) directly in this handler.
 */
static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
{
    snd_pcm_file_t *pcm_file;
    snd_pcm_substream_t *substream;
    struct sndrv_xfern32 __user *srcptr = compat_ptr(arg);
    struct sndrv_xfern32 data32;
    void __user **bufs;
    int err = 0, ch, i;
    u32 __user *bufptr;

    if (sanity_check_pcm(file))
        return -ENOTTY;
    if (! (pcm_file = file->private_data))
        return -ENOTTY;
    if (! (substream = pcm_file->substream))
        return -ENOTTY;
    if (! substream->runtime)
        return -ENOTTY;

    /* check validty of the command */
    switch (native_ctl) {
    case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
        if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
            return -EINVAL;
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
            return -EBADFD;
        break;
    case SNDRV_PCM_IOCTL_READN_FRAMES:
        if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
            return -EINVAL;
        break;
    }
    if ((ch = substream->runtime->channels) > 128)
        return -EINVAL;
    if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
        return -EFAULT;
    bufptr = compat_ptr(data32.bufs);
    bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
    if (bufs == NULL)
        return -ENOMEM;
    for (i = 0; i < ch; i++) {
        u32 ptr;
        if (get_user(ptr, bufptr)) {
            kfree(bufs);
            return -EFAULT;
        }
        bufs[ch] = compat_ptr(ptr);
        bufptr++;
    }
    switch (native_ctl) {
    case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
        err = snd_pcm_lib_writev(substream, bufs, data32.frames);
        break;
    case SNDRV_PCM_IOCTL_READN_FRAMES:
        err = snd_pcm_lib_readv(substream, bufs, data32.frames);
        break;
    }
    if (err >= 0) {
        if (put_user(err, &srcptr->result))
            err = -EFAULT;
    }
    kfree(bufs);
    return err;
}