#include #include #include #include #include #ifdef CONFIG_COMPAT struct video_tuner32 { compat_int_t tuner; char name[32]; compat_ulong_t rangelow, rangehigh; u32 flags; /* It is really u32 in videodev.h */ u16 mode, signal; }; static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { int i; if(get_user(kp->tuner, &up->tuner)) return -EFAULT; for(i = 0; i < 32; i++) __get_user(kp->name[i], &up->name[i]); __get_user(kp->rangelow, &up->rangelow); __get_user(kp->rangehigh, &up->rangehigh); __get_user(kp->flags, &up->flags); __get_user(kp->mode, &up->mode); __get_user(kp->signal, &up->signal); return 0; } static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { int i; if(put_user(kp->tuner, &up->tuner)) return -EFAULT; for(i = 0; i < 32; i++) __put_user(kp->name[i], &up->name[i]); __put_user(kp->rangelow, &up->rangelow); __put_user(kp->rangehigh, &up->rangehigh); __put_user(kp->flags, &up->flags); __put_user(kp->mode, &up->mode); __put_user(kp->signal, &up->signal); return 0; } struct video_buffer32 { compat_caddr_t base; compat_int_t height, width, depth, bytesperline; }; static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) { u32 tmp; if (get_user(tmp, &up->base)) return -EFAULT; /* This is actually a physical address stored * as a void pointer. */ kp->base = (void *)(unsigned long) tmp; __get_user(kp->height, &up->height); __get_user(kp->width, &up->width); __get_user(kp->depth, &up->depth); __get_user(kp->bytesperline, &up->bytesperline); return 0; } static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) { u32 tmp = (u32)((unsigned long)kp->base); if(put_user(tmp, &up->base)) return -EFAULT; __put_user(kp->height, &up->height); __put_user(kp->width, &up->width); __put_user(kp->depth, &up->depth); __put_user(kp->bytesperline, &up->bytesperline); return 0; } struct video_clip32 { s32 x, y, width, height; /* Its really s32 in videodev.h */ compat_caddr_t next; }; struct video_window32 { u32 x, y, width, height, chromakey, flags; compat_caddr_t clips; compat_int_t clipcount; }; static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; if (file->f_ops->unlocked_ioctl) ret = file->f_ops->unlocked_ioctl(file, cmd, arg); else if (file->f_ops->ioctl) { lock_kernel(); ret = file->f_ops->ioctl(file->f_dentry->d_inode, file, cmd, arg); unlock_kernel(); } return ret; } /* You get back everything except the clips... */ static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) { if(put_user(kp->x, &up->x)) return -EFAULT; __put_user(kp->y, &up->y); __put_user(kp->width, &up->width); __put_user(kp->height, &up->height); __put_user(kp->chromakey, &up->chromakey); __put_user(kp->flags, &up->flags); __put_user(kp->clipcount, &up->clipcount); return 0; } #define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) #define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) #define VIDIOCGWIN32 _IOR('v',9, struct video_window32) #define VIDIOCSWIN32 _IOW('v',10, struct video_window32) #define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) #define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) #define VIDIOCGFREQ32 _IOR('v',14, u32) #define VIDIOCSFREQ32 _IOW('v',15, u32) enum { MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) }; static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) { struct video_window32 __user *up = compat_ptr(arg); struct video_window __user *vw; struct video_clip __user *p; int nclips; u32 n; if (get_user(nclips, &up->clipcount)) return -EFAULT; /* Peculiar interface... */ if (nclips < 0) nclips = VIDEO_CLIPMAP_SIZE; if (nclips > MaxClips) return -ENOMEM; vw = compat_alloc_user_space(sizeof(struct video_window) + nclips * sizeof(struct video_clip)); p = nclips ? (struct video_clip __user *)(vw + 1) : NULL; if (get_user(n, &up->x) || put_user(n, &vw->x) || get_user(n, &up->y) || put_user(n, &vw->y) || get_user(n, &up->width) || put_user(n, &vw->width) || get_user(n, &up->height) || put_user(n, &vw->height) || get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) || get_user(n, &up->flags) || put_user(n, &vw->flags) || get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) || get_user(n, &up->clips) || put_user(p, &vw->clips)) return -EFAULT; if (nclips) { struct video_clip32 __user *u = compat_ptr(n); int i; if (!u) return -EINVAL; for (i = 0; i < nclips; i++, u++, p++) { s32 v; if (get_user(v, &u->x) || put_user(v, &p->x) || get_user(v, &u->y) || put_user(v, &p->y) || get_user(v, &u->width) || put_user(v, &p->width) || get_user(v, &u->height) || put_user(v, &p->height) || put_user(NULL, &p->next)) return -EFAULT; } } return native_ioctl(file, VIDIOCSWIN, (unsigned long)p); } static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { union { struct video_tuner vt; struct video_buffer vb; struct video_window vw; unsigned long vx; } karg; mm_segment_t old_fs = get_fs(); void __user *up = compat_ptr(arg); int err = 0; /* First, convert the command. */ switch(cmd) { case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; }; switch(cmd) { case VIDIOCSTUNER: case VIDIOCGTUNER: err = get_video_tuner32(&karg.vt, up); break; case VIDIOCSFBUF: err = get_video_buffer32(&karg.vb, up); break; case VIDIOCSFREQ: err = get_user(karg.vx, (u32 __user *)up); break; }; if(err) goto out; set_fs(KERNEL_DS); err = native_ioctl(file, cmd, (unsigned long)&karg); set_fs(old_fs); if(err == 0) { switch(cmd) { case VIDIOCGTUNER: err = put_video_tuner32(&karg.vt, up); break; case VIDIOCGWIN: err = put_video_window32(&karg.vw, up); break; case VIDIOCGFBUF: err = put_video_buffer32(&karg.vb, up); break; case VIDIOCGFREQ: err = put_user(((u32)karg.vx), (u32 __user *)up); break; }; } out: return err; } long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; if (!file->f_ops->ioctl) return ret; switch (cmd) { case VIDIOCSWIN32: ret = do_set_window(file, cmd, arg); break; case VIDIOCGTUNER32: case VIDIOCSTUNER32: case VIDIOCGWIN32: case VIDIOCGFBUF32: case VIDIOCSFBUF32: case VIDIOCGFREQ32: case VIDIOCSFREQ32: ret = do_video_ioctl(file, cmd, arg); break; /* Little v, the video4linux ioctls (conflict?) */ case VIDIOCGCAP: case VIDIOCGCHAN: case VIDIOCSCHAN: case VIDIOCGPICT: case VIDIOCSPICT: case VIDIOCCAPTURE: case VIDIOCKEY: case VIDIOCGAUDIO: case VIDIOCSAUDIO: case VIDIOCSYNC: case VIDIOCMCAPTURE: case VIDIOCGMBUF: case VIDIOCGUNIT: case VIDIOCGCAPTURE: case VIDIOCSCAPTURE: /* BTTV specific... */ case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]): case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]): case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int): case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */ case _IOR('v' , BASE_VIDIOCPRIVATE+4, int): case _IOR('v' , BASE_VIDIOCPRIVATE+5, int): case _IOR('v' , BASE_VIDIOCPRIVATE+6, int): case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); break; } return ret; } #else long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { return -ENOIOCTLCMD; } #endif EXPORT_SYMBOL_GPL(v4l_compat_ioctl32); MODULE_LICENSE("GPL");