Date: Fri, 4 Dec 2009 21:06:55 +0000 (UTC) From: Alexander Leidinger <netchild@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r200110 - head/sys/compat/linux Message-ID: <200912042106.nB4L6tsr065541@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: netchild Date: Fri Dec 4 21:06:54 2009 New Revision: 200110 URL: http://svn.freebsd.org/changeset/base/200110 Log: This is v4l support for the linuxulator. This allows to access FreeBSD native devices which support the v4l API from processes running within the linuxulator, e.g. skype or flash can access the multimedia/pwcbsd driver. Not tested is firmware upload, framebuffer stuff and video tuner stuff due to lack of hardware. The clipping part (VIDIOCSWIN) needs a little bit of further work (partly in progress, but can not be tested due to lack of a suitable device). The submitter tested this sucessfully with Skype and flash apps on amd64 and i386 with the multimedia/pwcbsd driver. Submitted by: J.R. Oldroyd <fbsd@opal.com> Added: head/sys/compat/linux/linux_videodev_compat.h (contents, props changed) Modified: head/sys/compat/linux/linux_ioctl.c head/sys/compat/linux/linux_ioctl.h head/sys/compat/linux/linux_videodev.h (contents, props changed) Modified: head/sys/compat/linux/linux_ioctl.c ============================================================================== --- head/sys/compat/linux/linux_ioctl.c Fri Dec 4 20:46:45 2009 (r200109) +++ head/sys/compat/linux/linux_ioctl.c Fri Dec 4 21:06:54 2009 (r200110) @@ -78,6 +78,9 @@ __FBSDID("$FreeBSD$"); #include <compat/linux/linux_socket.h> #include <compat/linux/linux_util.h> +#include <compat/linux/linux_videodev.h> +#include <compat/linux/linux_videodev_compat.h> + CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ); static linux_ioctl_function_t linux_ioctl_cdrom; @@ -91,6 +94,7 @@ static linux_ioctl_function_t linux_ioct static linux_ioctl_function_t linux_ioctl_private; static linux_ioctl_function_t linux_ioctl_drm; static linux_ioctl_function_t linux_ioctl_sg; +static linux_ioctl_function_t linux_ioctl_v4l; static linux_ioctl_function_t linux_ioctl_special; static struct linux_ioctl_handler cdrom_handler = @@ -115,6 +119,8 @@ static struct linux_ioctl_handler drm_ha { linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX }; static struct linux_ioctl_handler sg_handler = { linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX }; +static struct linux_ioctl_handler video_handler = +{ linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX }; DATA_SET(linux_ioctl_handler_set, cdrom_handler); DATA_SET(linux_ioctl_handler_set, vfat_handler); @@ -127,6 +133,7 @@ DATA_SET(linux_ioctl_handler_set, termio DATA_SET(linux_ioctl_handler_set, private_handler); DATA_SET(linux_ioctl_handler_set, drm_handler); DATA_SET(linux_ioctl_handler_set, sg_handler); +DATA_SET(linux_ioctl_handler_set, video_handler); struct handler_element { @@ -2589,6 +2596,295 @@ linux_ioctl_sg(struct thread *td, struct } /* + * Video4Linux (V4L) ioctl handler + */ +static int +linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt) +{ + vt->tuner = lvt->tuner; + strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE); + vt->rangelow = lvt->rangelow; /* possible long size conversion */ + vt->rangehigh = lvt->rangehigh; /* possible long size conversion */ + vt->flags = lvt->flags; + vt->mode = lvt->mode; + vt->signal = lvt->signal; + return (0); +} + +static int +bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt) +{ + lvt->tuner = vt->tuner; + strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE); + lvt->rangelow = vt->rangelow; /* possible long size conversion */ + lvt->rangehigh = vt->rangehigh; /* possible long size conversion */ + lvt->flags = vt->flags; + lvt->mode = vt->mode; + lvt->signal = vt->signal; + return (0); +} + +#if 0 +static int +linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc) +{ + vc->x = lvc->x; + vc->y = lvc->y; + vc->width = lvc->width; + vc->height = lvc->height; + vc->next = PTRIN(lvc->next); /* possible pointer size conversion */ + return (0); +} +#endif + +static int +linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw) +{ + vw->x = lvw->x; + vw->y = lvw->y; + vw->width = lvw->width; + vw->height = lvw->height; + vw->chromakey = lvw->chromakey; + vw->flags = lvw->flags; + vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */ + vw->clipcount = lvw->clipcount; + return (0); +} + +static int +bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw) +{ + lvw->x = vw->x; + lvw->y = vw->y; + lvw->width = vw->width; + lvw->height = vw->height; + lvw->chromakey = vw->chromakey; + lvw->flags = vw->flags; + lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */ + lvw->clipcount = vw->clipcount; + return (0); +} + +static int +linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb) +{ + vb->base = PTRIN(lvb->base); /* possible pointer size conversion */ + vb->height = lvb->height; + vb->width = lvb->width; + vb->depth = lvb->depth; + vb->bytesperline = lvb->bytesperline; + return (0); +} + +static int +bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb) +{ + lvb->base = PTROUT(vb->base); /* possible pointer size conversion */ + lvb->height = vb->height; + lvb->width = vb->width; + lvb->depth = vb->depth; + lvb->bytesperline = vb->bytesperline; + return (0); +} + +static int +linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc) +{ + strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE); + vc->datasize = lvc->datasize; + vc->data = PTRIN(lvc->data); /* possible pointer size conversion */ + return (0); +} + +#if 0 +static int +linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw) +{ + struct video_clip vclip; + struct l_video_clip l_vclip; + struct video_clip **ppvc; + struct l_video_clip *plvc; + int error; + + ppvc = &(vw->clips); + for (plvc = (struct l_video_clip *) PTRIN(lvw->clips); + plvc != NULL; + plvc = (struct l_video_clip *) PTRIN(plvc->next)) { + error = copyin((void *) plvc, &l_vclip, sizeof(l_vclip)); + if (error) return (error); + linux_to_bsd_v4l_clip(&l_vclip, &vclip); + /* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */ + if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL) + return (ENOMEM); /* XXX: linux has no ENOMEM here */ + memcpy(&vclip, *ppvc, sizeof(vclip)); + ppvc = &((*ppvc)->next); + } + return (0); +} + +static int +linux_v4l_cliplist_free(struct video_window *vw) +{ + struct video_clip **ppvc; + struct video_clip **ppvc_next; + + for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) { + ppvc_next = &((*ppvc)->next); + free(*ppvc, M_LINUX); + } + return (0); +} +#endif + +static int +linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + struct video_tuner vtun; + struct video_window vwin; + struct video_buffer vbuf; + struct video_code vcode; + struct l_video_tuner l_vtun; + struct l_video_window l_vwin; + struct l_video_buffer l_vbuf; + struct l_video_code l_vcode; + + switch (args->cmd & 0xffff) { + case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break; + case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break; + case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; + + case LINUX_VIDIOCGTUNER: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_tuner(&vtun, &l_vtun); + error = copyout(&l_vtun, (void *) args->arg, + sizeof(l_vtun)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSTUNER: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_tuner(&l_vtun, &vtun); + error = fo_ioctl(fp, VIDIOCSMICROCODE, &vtun, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break; + case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break; + case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; + + case LINUX_VIDIOCGWIN: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_window(&vwin, &l_vwin); + error = copyout(&l_vwin, (void *) args->arg, + sizeof(l_vwin)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSWIN: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_window(&l_vwin, &vwin); +#if 0 + /* + * XXX: some Linux apps call SWIN but do not store valid + * values in clipcount or in the clips pointer. Until + * we have someone calling to support this, the code + * to handle the list of video_clip structures is removed. + */ + error = linux_v4l_cliplist_copy(&l_vwin, &vwin); +#endif + if (!error) + error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td); + fdrop(fp, td); +#if 0 + linux_v4l_cliplist_free(&vwin); +#endif + return (error); + + case LINUX_VIDIOCGFBUF: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf); + error = copyout(&l_vbuf, (void *) args->arg, + sizeof(l_vbuf)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSFBUF: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf); + error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break; + case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break; + case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break; + case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break; + case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break; + case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break; + case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break; + case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break; + case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break; + case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break; + case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break; + case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break; + case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break; + case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; + + case LINUX_VIDIOCSMICROCODE: + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_code(&l_vcode, &vcode); + error = fo_ioctl(fp, VIDIOCSTUNER, &vcode, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break; + case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break; + default: return (ENOIOCTL); + } + + error = ioctl(td, (struct ioctl_args *)args); + return (error); +} + +/* * Special ioctl handler */ static int Modified: head/sys/compat/linux/linux_ioctl.h ============================================================================== --- head/sys/compat/linux/linux_ioctl.h Fri Dec 4 20:46:45 2009 (r200109) +++ head/sys/compat/linux/linux_ioctl.h Fri Dec 4 21:06:54 2009 (r200110) @@ -575,4 +575,40 @@ struct ifnet; int linux_ifname(struct ifnet *, char *, size_t); +/* + * video + */ +#define LINUX_VIDIOCGCAP 0x7601 +#define LINUX_VIDIOCGCHAN 0x7602 +#define LINUX_VIDIOCSCHAN 0x7603 +#define LINUX_VIDIOCGTUNER 0x7604 +#define LINUX_VIDIOCSTUNER 0x7605 +#define LINUX_VIDIOCGPICT 0x7606 +#define LINUX_VIDIOCSPICT 0x7607 +#define LINUX_VIDIOCCAPTURE 0x7608 +#define LINUX_VIDIOCGWIN 0x7609 +#define LINUX_VIDIOCSWIN 0x760a +#define LINUX_VIDIOCGFBUF 0x760b +#define LINUX_VIDIOCSFBUF 0x760c +#define LINUX_VIDIOCKEY 0x760d +#define LINUX_VIDIOCGFREQ 0x760e +#define LINUX_VIDIOCSFREQ 0x760f +#define LINUX_VIDIOCGAUDIO 0x7610 +#define LINUX_VIDIOCSAUDIO 0x7611 +#define LINUX_VIDIOCSYNC 0x7623 +#define LINUX_VIDIOCMCAPTURE 0x7613 +#define LINUX_VIDIOCGMBUF 0x7614 +#define LINUX_VIDIOCGUNIT 0x7615 +#define LINUX_VIDIOCGCAPTURE 0x7616 +#define LINUX_VIDIOCSCAPTURE 0x7617 +#define LINUX_VIDIOCSPLAYMODE 0x7618 +#define LINUX_VIDIOCSWRITEMODE 0x7619 +#define LINUX_VIDIOCGPLAYINFO 0x761a +#define LINUX_VIDIOCSMICROCODE 0x761b +#define LINUX_VIDIOCGVBIFMT 0x761c +#define LINUX_VIDIOCSVBIFMT 0x761d + +#define LINUX_IOCTL_VIDEO_MIN LINUX_VIDIOCGCAP +#define LINUX_IOCTL_VIDEO_MAX LINUX_VIDIOCSVBIFMT + #endif /* !_LINUX_IOCTL_H_ */ Modified: head/sys/compat/linux/linux_videodev.h ============================================================================== --- head/sys/compat/linux/linux_videodev.h Fri Dec 4 20:46:45 2009 (r200109) +++ head/sys/compat/linux/linux_videodev.h Fri Dec 4 21:06:54 2009 (r200110) @@ -1,48 +1,41 @@ +/* + * This header comes from linux, but it has no license. The author + * (Alan Cox @ Redhat) gave explicit permissions to use it in FreeBSD. + * The freeBSD vendor branch for v4l gives a more detailed description + * about this. + * + * $FreeBSD$ + */ + #ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H -#include <linux/types.h> +#include <sys/types.h> +typedef int32_t __s32; +typedef uint32_t __u32; +typedef uint16_t __u16; +typedef uint8_t __u8; +#if 0 #define HAVE_V4L1 1 #include <linux/videodev2.h> +#endif -#ifdef __KERNEL__ - -#include <linux/mm.h> - -extern struct video_device* video_devdata(struct file*); - -#define to_video_device(cd) container_of(cd, struct video_device, class_dev) -static inline void -video_device_create_file(struct video_device *vfd, - struct class_device_attribute *attr) -{ - class_device_create_file(&vfd->class_dev, attr); -} -static inline void -video_device_remove_file(struct video_device *vfd, - struct class_device_attribute *attr) -{ - class_device_remove_file(&vfd->class_dev, attr); -} - -#if OBSOLETE_OWNER /* to be removed in 2.6.15 */ -/* helper functions to access driver private data. */ -static inline void *video_get_drvdata(struct video_device *dev) -{ - return dev->priv; -} - -static inline void video_set_drvdata(struct video_device *dev, void *data) -{ - dev->priv = data; -} -#endif - -extern int video_exclusive_open(struct inode *inode, struct file *file); -extern int video_exclusive_release(struct inode *inode, struct file *file); -#endif /* __KERNEL__ */ +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ +#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ +#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ +#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ +#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ struct video_capability { @@ -157,7 +150,7 @@ struct video_window __u32 width,height; /* Its size */ __u32 chromakey; __u32 flags; - struct video_clip __user *clips; /* Set only */ + struct video_clip *clips; /* Set only */ int clipcount; #define VIDEO_WINDOW_INTERLACE 1 #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ @@ -197,6 +190,8 @@ struct video_key __u32 flags; }; +#define VIDEO_MAX_FRAME 32 + struct video_mbuf { int size; /* Total memory to map */ Added: head/sys/compat/linux/linux_videodev_compat.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/compat/linux/linux_videodev_compat.h Fri Dec 4 21:06:54 2009 (r200110) @@ -0,0 +1,59 @@ +/* + * $FreeBSD$ + */ + +/* + * This file defines compatibility versions of several video structures + * defined in the Linux videodev.h header (linux_videodev.h). The + * structures defined in this file are the ones that have been determined + * to have 32- to 64-bit size dependencies. + */ + +#ifndef _LINUX_VIDEODEV_COMPAT_H_ +#define _LINUX_VIDEODEV_COMPAT_H_ + +struct l_video_tuner +{ + l_int tuner; +#define LINUX_VIDEO_TUNER_NAME_SIZE 32 + char name[LINUX_VIDEO_TUNER_NAME_SIZE]; + l_ulong rangelow, rangehigh; + uint32_t flags; + uint16_t mode; + uint16_t signal; +}; + +struct l_video_clip +{ + int32_t x, y; + int32_t width, height; + l_uintptr_t next; +}; + +struct l_video_window +{ + uint32_t x, y; + uint32_t width, height; + uint32_t chromakey; + uint32_t flags; + l_uintptr_t clips; + l_int clipcount; +}; + +struct l_video_buffer +{ + l_uintptr_t base; + l_int height, width; + l_int depth; + l_int bytesperline; +}; + +struct l_video_code +{ +#define LINUX_VIDEO_CODE_LOADWHAT_SIZE 16 + char loadwhat[LINUX_VIDEO_CODE_LOADWHAT_SIZE]; + l_int datasize; + l_uintptr_t data; +}; + +#endif /* !_LINUX_VIDEODEV_COMPAT_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912042106.nB4L6tsr065541>