summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
commit5c72acfc65bcea784244f6c8412b6c6c22bcd05d (patch)
treeb5c60b347b82109d8105b4ac1e4b2e590d6dd263
Initial revisionXORG-STABLE
-rw-r--r--README37
-rw-r--r--man/v4l.man39
-rw-r--r--src/v4l.c1023
-rw-r--r--src/videodev.h255
4 files changed, 1354 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..a21e915
--- /dev/null
+++ b/README
@@ -0,0 +1,37 @@
+
+ Video 4 Linux adaptor driver for XFree86 v4.0
+
+ Developed by Gerd Knorr <kraxel@goldbach.in-berlin.de> and
+ David Woodhouse <David.Woodhouse@mvhi.com>
+
+----------------------------------------------------------------------------
+
+ This chipset driver does not provide a graphics adaptor driver, but instead
+ registers a number of generic Xv adaptors which can be used with any graphics
+ chipset driver.
+
+ In order to use v4l adaptors with your favourite graphics driver, the
+ graphics driver must do two things:
+
+ 1. Correctly set pScrn->memPhysBase and pScrn->fbOffset for the screens that
+ it provides, to the physical address of the frame buffer memory, and
+ the offset within that memory that the current mode starts,
+ respectively.
+
+ 2. Use the xf86XVListGenericAdaptors() routine to list all available Xv
+ adaptors which are usable with any target device, and initialise
+ them on its screens with xf86XVScreenInit() as follows...
+
+ {
+ XF86VideoAdaptorPtr *ptr;
+
+ int xvexts = xf86XVListGenericAdaptors(&ptr);
+
+ if (xvexts) {
+ xf86XVScreenInit(pScreen, ptr, xvexts);
+ }
+ }
+
+
+
+$XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/README,v 1.2 2001/05/07 21:59:07 tsi Exp $
diff --git a/man/v4l.man b/man/v4l.man
new file mode 100644
index 0000000..5337112
--- /dev/null
+++ b/man/v4l.man
@@ -0,0 +1,39 @@
+.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.man,v 1.3 2001/05/29 22:24:06 dawes Exp $
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH V4L __drivermansuffix__ __vendorversion__
+.SH NAME
+v4l \- video4linux driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qModule\*q"
+\ \ ...
+.B " Load \*qv4l\*q"
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B v4l
+is an XFree86 driver for video4linux cards. It provides a Xvideo
+extention port for video overlay. Just add the driver to the module
+list within the module section of your XF86Config file if you want
+to use it. There are no config options.
+.P
+Note that the the extmod module is also required for the Xvideo
+support (and lots of other extentions too).
+.SH SUPPORTED HARDWARE
+The
+.B v4l
+driver works with every piece of hardware which is supported by a
+video4linux (kernel-) device driver and is able to handle video
+overlay.
+.P
+bt848/bt878-based TV cards are the most popular hardware these
+days.
+.SH CONFIGURATION DETAILS
+Please refer to XF86Config(__filemansuffix__) for general configuration
+details. This section only covers configuration details specific to this
+driver.
+.SH "SEE ALSO"
+XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__)
+.SH AUTHORS
+Authors include: Gerd Knorr <kraxel@bytesex.org>
diff --git a/src/v4l.c b/src/v4l.c
new file mode 100644
index 0000000..156d63c
--- /dev/null
+++ b/src/v4l.c
@@ -0,0 +1,1023 @@
+/*
+ * video4linux Xv Driver
+ * based on Michael Schimek's permedia 2 driver.
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c,v 1.30 2002/05/14 20:19:53 alanh Exp $ */
+
+#include "videodev.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86_ansic.h"
+#include "xf86Pci.h"
+#include "xf86PciInfo.h"
+#include "xf86fbman.h"
+#include "xf86xv.h"
+#include "Xv.h"
+#include "miscstruct.h"
+#include "dgaproc.h"
+#include "xf86str.h"
+
+#include <asm/ioctl.h> /* _IORW(xxx) #defines are here */
+
+#if 0
+# define DEBUG(x) (x)
+#else
+# define DEBUG(x)
+#endif
+
+static void V4LIdentify(int flags);
+static Bool V4LProbe(DriverPtr drv, int flags);
+static const OptionInfoRec * V4LAvailableOptions(int chipid, int busid);
+
+DriverRec V4L = {
+ 40000,
+ "v4l",
+ V4LIdentify, /* Identify*/
+ V4LProbe, /* Probe */
+ V4LAvailableOptions,
+ NULL,
+ 0
+};
+
+
+#ifdef XFree86LOADER
+
+static MODULESETUPPROTO(v4lSetup);
+
+static XF86ModuleVersionInfo v4lVersRec =
+{
+ "v4l",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ 0, 0, 1,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ {0,0,0,0}
+};
+
+XF86ModuleData v4lModuleData = { &v4lVersRec, v4lSetup, NULL };
+
+static pointer
+v4lSetup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+ const char *osname;
+ static Bool setupDone = FALSE;
+
+ if (setupDone) {
+ if (errmaj)
+ *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+
+ setupDone = TRUE;
+
+ /* Check that we're being loaded on a Linux system */
+ LoaderGetOS(&osname, NULL, NULL, NULL);
+ if (!osname || strcmp(osname, "linux") != 0) {
+ if (errmaj)
+ *errmaj = LDR_BADOS;
+ if (errmin)
+ *errmin = 0;
+ return NULL;
+ } else {
+ /* OK */
+
+ xf86AddDriver (&V4L, module, 0);
+
+ return (pointer)1;
+ }
+}
+
+#else
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#endif
+
+#define VIDEO_OFF 0 /* really off */
+#define VIDEO_RGB 1 /* rgb overlay (directly to fb) */
+#define VIDEO_YUV 2 /* yuv overlay (to offscreen memory + hw scaling) */
+#define VIDEO_RECLIP 3 /* temporarly off, window clipping changes */
+
+typedef struct _PortPrivRec {
+ ScrnInfoPtr pScrn;
+ FBAreaPtr pFBArea[2];
+ int VideoOn;
+ Bool StreamOn;
+
+ /* file handle */
+ int nr;
+ struct video_capability cap;
+
+ /* RGB overlay */
+ struct video_buffer rgb_fbuf;
+ struct video_window rgb_win;
+ int rgbpalette;
+ int rgbdepth;
+
+ /* attributes */
+ struct video_picture pict;
+ struct video_audio audio;
+
+ XF86VideoEncodingPtr enc;
+ int *input;
+ int *norm;
+ int nenc,cenc;
+
+ /* yuv to offscreen */
+ XF86OffscreenImagePtr format; /* list */
+ int nformat; /* # if list entries */
+ XF86OffscreenImagePtr myfmt; /* which one is YUY2 (packed) */
+ int yuv_format;
+
+ int yuv_width,yuv_height;
+ XF86SurfacePtr surface;
+ struct video_buffer yuv_fbuf;
+ struct video_window yuv_win;
+} PortPrivRec, *PortPrivPtr;
+
+#define XV_ENCODING "XV_ENCODING"
+#define XV_BRIGHTNESS "XV_BRIGHTNESS"
+#define XV_CONTRAST "XV_CONTRAST"
+#define XV_SATURATION "XV_SATURATION"
+#define XV_HUE "XV_HUE"
+
+#define XV_FREQ "XV_FREQ"
+#define XV_MUTE "XV_MUTE"
+#define XV_VOLUME "XV_VOLUME"
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvEncoding, xvBrightness, xvContrast, xvSaturation, xvHue;
+static Atom xvFreq, xvMute, xvVolume;
+
+static XF86VideoFormatRec
+InputVideoFormats[] = {
+ { 15, TrueColor },
+ { 16, TrueColor },
+ { 24, TrueColor },
+ { 32, TrueColor },
+};
+
+#define V4L_ATTR (sizeof(Attributes) / sizeof(XF86AttributeRec))
+
+static const XF86AttributeRec Attributes[] = {
+ {XvSettable | XvGettable, -1000, 1000, XV_ENCODING},
+ {XvSettable | XvGettable, -1000, 1000, XV_BRIGHTNESS},
+ {XvSettable | XvGettable, -1000, 1000, XV_CONTRAST},
+ {XvSettable | XvGettable, -1000, 1000, XV_SATURATION},
+ {XvSettable | XvGettable, -1000, 1000, XV_HUE},
+};
+static const XF86AttributeRec VolumeAttr =
+ {XvSettable | XvGettable, -1000, 1000, XV_VOLUME};
+static const XF86AttributeRec MuteAttr =
+ {XvSettable | XvGettable, 0, 1, XV_MUTE};
+static const XF86AttributeRec FreqAttr =
+ {XvSettable | XvGettable, 0, 16*1000, XV_FREQ};
+
+
+#define MAX_V4L_DEVICES 4
+#define V4L_FD (v4l_devices[pPPriv->nr].fd)
+#define V4L_REF (v4l_devices[pPPriv->nr].useCount)
+#define V4L_NAME (v4l_devices[pPPriv->nr].devName)
+
+static struct V4L_DEVICE {
+ int fd;
+ int useCount;
+ char devName[16];
+} v4l_devices[MAX_V4L_DEVICES] = {
+ { -1 },
+ { -1 },
+ { -1 },
+ { -1 },
+};
+
+/* ---------------------------------------------------------------------- */
+/* forward decl */
+
+static void V4lQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h, pointer data);
+
+/* ---------------------------------------------------------------------- */
+
+static int V4lOpenDevice(PortPrivPtr pPPriv, ScrnInfoPtr pScrn)
+{
+ static int first = 1;
+
+ if (-1 == V4L_FD) {
+ V4L_FD = open(V4L_NAME, O_RDWR, 0);
+
+ pPPriv->rgb_fbuf.width = pScrn->virtualX;
+ pPPriv->rgb_fbuf.height = pScrn->virtualY;
+ pPPriv->rgb_fbuf.depth = pScrn->bitsPerPixel;
+ pPPriv->rgb_fbuf.bytesperline = pScrn->displayWidth * ((pScrn->bitsPerPixel + 7)/8);
+ pPPriv->rgb_fbuf.base = (pointer)(pScrn->memPhysBase + pScrn->fbOffset);
+ if (first) {
+ first = 0;
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
+ "v4l: memPhysBase=%p\n", pScrn->memPhysBase);
+ }
+
+ switch (pScrn->bitsPerPixel) {
+ case 16:
+ if (pScrn->weight.green == 5) {
+ pPPriv->rgbpalette = VIDEO_PALETTE_RGB555;
+ pPPriv->rgbdepth = 16;
+ } else {
+ pPPriv->rgbpalette = VIDEO_PALETTE_RGB565;
+ pPPriv->rgbdepth = 16;
+ }
+ break;
+ case 24:
+ pPPriv->rgbpalette = VIDEO_PALETTE_RGB24;
+ pPPriv->rgbdepth = 24;
+ break;
+ case 32:
+ pPPriv->rgbpalette = VIDEO_PALETTE_RGB32;
+ pPPriv->rgbdepth = 32;
+ break;
+ }
+ }
+
+ if (-1 == V4L_FD)
+ return errno;
+
+ V4L_REF++;
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
+ "Xv/open: refcount=%d\n",V4L_REF));
+
+ return 0;
+}
+
+static void V4lCloseDevice(PortPrivPtr pPPriv, ScrnInfoPtr pScrn)
+{
+ V4L_REF--;
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
+ "Xv/close: refcount=%d\n",V4L_REF));
+ if (0 == V4L_REF && -1 != V4L_FD) {
+ close(V4L_FD);
+ V4L_FD = -1;
+ }
+}
+
+static int
+V4lPutVideo(ScrnInfoPtr pScrn,
+ short vid_x, short vid_y, short drw_x, short drw_y,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ RegionPtr clipBoxes, pointer data)
+{
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+ struct video_clip *clip;
+ BoxPtr pBox;
+ RegionRec newReg;
+ BoxRec newBox;
+ unsigned int i,dx,dy,dw,dh;
+ int width,height;
+ int one=1;
+
+ /* Open a file handle to the device */
+ if (VIDEO_OFF == pPPriv->VideoOn) {
+ if (V4lOpenDevice(pPPriv, pScrn))
+ return Success;
+ }
+
+ if (0 != pPPriv->yuv_format) {
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PV yuv\n"));
+ width = pPPriv->enc[pPPriv->cenc].width;
+ height = pPPriv->enc[pPPriv->cenc].height/2; /* no interlace */
+ if (drw_w < width)
+ width = drw_w;
+ if (drw_h < height)
+ height = drw_h;
+ if ((height != pPPriv->yuv_height) || (width != pPPriv->yuv_width)) {
+ /* new size -- free old surface */
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " surface resize\n"));
+ if (pPPriv->surface) {
+ pPPriv->VideoOn = VIDEO_OFF;
+ pPPriv->myfmt->stop(pPPriv->surface);
+ pPPriv->myfmt->free_surface(pPPriv->surface);
+ xfree(pPPriv->surface);
+ pPPriv->surface = NULL;
+ }
+ pPPriv->yuv_width = width;
+ pPPriv->yuv_height = height;
+ }
+ if (!pPPriv->surface) {
+ /* allocate + setup offscreen surface */
+ if (NULL == (pPPriv->surface = xalloc(sizeof(XF86SurfaceRec))))
+ return FALSE;
+ if (Success != pPPriv->myfmt->alloc_surface
+ (pScrn,pPPriv->myfmt->image->id,
+ pPPriv->yuv_width,pPPriv->yuv_height,pPPriv->surface)) {
+ xfree(pPPriv->surface);
+ pPPriv->surface = NULL;
+ goto fallback_to_rgb;
+ }
+ pPPriv->yuv_fbuf.width = pPPriv->surface->width;
+ pPPriv->yuv_fbuf.height = pPPriv->surface->height;
+ pPPriv->yuv_fbuf.depth = 16;
+ pPPriv->yuv_fbuf.bytesperline = pPPriv->surface->pitches[0];
+ pPPriv->yuv_fbuf.base =
+ (pointer)(pScrn->memPhysBase + pPPriv->surface->offsets[0]);
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " surface: %p+%d = %p, %dx%d, pitch %d\n",
+ pScrn->memPhysBase,pPPriv->surface->offsets[0],
+ pScrn->memPhysBase+pPPriv->surface->offsets[0],
+ pPPriv->surface->width,pPPriv->surface->height,
+ pPPriv->surface->pitches[0]));
+ pPPriv->yuv_win.width = pPPriv->surface->width;
+ pPPriv->yuv_win.height = pPPriv->surface->height;
+ }
+
+ /* program driver */
+ if (-1 == ioctl(V4L_FD,VIDIOCSFBUF,&(pPPriv->yuv_fbuf)))
+ perror("ioctl VIDIOCSFBUF");
+ if (-1 == ioctl(V4L_FD,VIDIOCGPICT,&pPPriv->pict))
+ perror("ioctl VIDIOCGPICT");
+ pPPriv->pict.palette = pPPriv->yuv_format;
+ pPPriv->pict.depth = 16;
+ if (-1 == ioctl(V4L_FD,VIDIOCSPICT,&pPPriv->pict))
+ perror("ioctl VIDIOCSPICT");
+ if (-1 == ioctl(V4L_FD,VIDIOCSWIN,&(pPPriv->yuv_win)))
+ perror("ioctl VIDIOCSWIN");
+ if (-1 == ioctl(V4L_FD, VIDIOCCAPTURE, &one))
+ perror("ioctl VIDIOCCAPTURE(1)");
+
+ if (0 == (pPPriv->myfmt->flags & VIDEO_INVERT_CLIPLIST)) {
+ /* invert cliplist */
+ newBox.x1 = drw_x;
+ newBox.y1 = drw_y;
+ newBox.x2 = drw_x + drw_w;
+ newBox.y2 = drw_y + drw_h;
+
+ if (pPPriv->myfmt->flags & VIDEO_CLIP_TO_VIEWPORT) {
+ /* trim to the viewport */
+ if(newBox.x1 < pScrn->frameX0)
+ newBox.x1 = pScrn->frameX0;
+ if(newBox.x2 > pScrn->frameX1)
+ newBox.x2 = pScrn->frameX1;
+
+ if(newBox.y1 < pScrn->frameY0)
+ newBox.y1 = pScrn->frameY0;
+ if(newBox.y2 > pScrn->frameY1)
+ newBox.y2 = pScrn->frameY1;
+ }
+
+ REGION_INIT(pScrn->pScreen, &newReg, &newBox, 1);
+ REGION_SUBTRACT(pScrn->pScreen, &newReg, &newReg, clipBoxes);
+ clipBoxes = &newReg;
+ }
+
+ /* start overlay */
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
+ "over: - %d,%d -> %d,%d (%dx%d) (yuv=%dx%d)\n",
+ drw_x, drw_y,
+ drw_x+drw_w, drw_y+drw_h,
+ drw_w, drw_h,
+ pPPriv->surface->width,pPPriv->surface->height));
+ pPPriv->myfmt->display(pPPriv->surface,
+ 0, 0, drw_x, drw_y,
+ pPPriv->surface->width,
+ pPPriv->surface->height,
+ drw_w, drw_h,
+ clipBoxes);
+ if (0 == (pPPriv->myfmt->flags & VIDEO_INVERT_CLIPLIST)) {
+ REGION_UNINIT(pScrn->pScreen, &newReg);
+ }
+ pPPriv->VideoOn = VIDEO_YUV;
+ return Success;
+ }
+
+ fallback_to_rgb:
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PV rgb\n"));
+ /* FIXME: vid-* is ignored for now, not supported by v4l */
+
+ dw = (drw_w < pPPriv->enc[pPPriv->cenc].width) ?
+ drw_w : pPPriv->enc[pPPriv->cenc].width;
+ dh = (drw_h < pPPriv->enc[pPPriv->cenc].height) ?
+ drw_h : pPPriv->enc[pPPriv->cenc].height;
+ /* if the window is too big, center the video */
+ dx = drw_x + (drw_w - dw)/2;
+ dy = drw_y + (drw_h - dh)/2;
+ /* bttv prefeares aligned addresses */
+ dx &= ~3;
+ if (dx < drw_x) dx += 4;
+ if (dx+dw > drw_x+drw_w) dw -= 4;
+
+ /* window */
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " win: %dx%d+%d+%d\n",
+ drw_w,drw_h,drw_x,drw_y));
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " use: %dx%d+%d+%d\n",
+ dw,dh,dx,dy));
+ pPPriv->rgb_win.x = dx;
+ pPPriv->rgb_win.y = dy;
+ pPPriv->rgb_win.width = dw;
+ pPPriv->rgb_win.height = dh;
+ pPPriv->rgb_win.flags = 0;
+
+ /* clipping */
+ if (pPPriv->rgb_win.clips) {
+ xfree(pPPriv->rgb_win.clips);
+ pPPriv->rgb_win.clips = NULL;
+ }
+ pPPriv->rgb_win.clipcount = REGION_NUM_RECTS(clipBoxes);
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2," clip: have #%d\n",
+ pPPriv->rgb_win.clipcount));
+ if (0 != pPPriv->rgb_win.clipcount) {
+ pPPriv->rgb_win.clips = xalloc(pPPriv->rgb_win.clipcount*sizeof(struct video_clip));
+ if (NULL != pPPriv->rgb_win.clips) {
+ memset(pPPriv->rgb_win.clips,0,pPPriv->rgb_win.clipcount*sizeof(struct video_clip));
+ pBox = REGION_RECTS(clipBoxes);
+ clip = pPPriv->rgb_win.clips;
+ for (i = 0; i < REGION_NUM_RECTS(clipBoxes); i++, pBox++, clip++) {
+ clip->x = pBox->x1 - dx;
+ clip->y = pBox->y1 - dy;
+ clip->width = pBox->x2 - pBox->x1;
+ clip->height = pBox->y2 - pBox->y1;
+ }
+ }
+ }
+
+ /* start */
+ if (-1 == ioctl(V4L_FD,VIDIOCSFBUF,&(pPPriv->rgb_fbuf)))
+ perror("ioctl VIDIOCSFBUF");
+ if (-1 == ioctl(V4L_FD,VIDIOCGPICT,&pPPriv->pict))
+ perror("ioctl VIDIOCGPICT");
+ pPPriv->pict.palette = pPPriv->rgbpalette;
+ pPPriv->pict.depth = pPPriv->rgbdepth;
+ if (-1 == ioctl(V4L_FD,VIDIOCSPICT,&pPPriv->pict))
+ perror("ioctl VIDIOCSPICT");
+ if (-1 == ioctl(V4L_FD,VIDIOCSWIN,&(pPPriv->rgb_win)))
+ perror("ioctl VIDIOCSWIN");
+ if (-1 == ioctl(V4L_FD, VIDIOCCAPTURE, &one))
+ perror("ioctl VIDIOCCAPTURE(1)");
+ pPPriv->VideoOn = VIDEO_RGB;
+
+ return Success;
+}
+
+static int
+V4lPutStill(ScrnInfoPtr pScrn,
+ short vid_x, short vid_y, short drw_x, short drw_y,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ RegionPtr clipBoxes, pointer data)
+{
+#if 0
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+#endif
+
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PS\n"));
+
+ /* FIXME */
+ return Success;
+}
+
+static void
+V4lStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+ int zero=0;
+
+ if (VIDEO_OFF == pPPriv->VideoOn) {
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
+ "Xv/StopVideo called with video already off\n"));
+ return;
+ }
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/StopVideo shutdown=%d\n",shutdown));
+
+ if (!shutdown) {
+ /* just reclipping, we have to stop DMA transfers to the visible screen */
+ if (VIDEO_RGB == pPPriv->VideoOn) {
+ if (-1 == ioctl(V4L_FD, VIDIOCCAPTURE, &zero))
+ perror("ioctl VIDIOCCAPTURE(0)");
+ pPPriv->VideoOn = VIDEO_RECLIP;
+ }
+ } else {
+ /* video stop - turn off and free everything */
+ if (VIDEO_YUV == pPPriv->VideoOn) {
+ pPPriv->myfmt->stop(pPPriv->surface);
+ pPPriv->myfmt->free_surface(pPPriv->surface);
+ xfree(pPPriv->surface);
+ pPPriv->surface = NULL;
+ }
+ if (-1 == ioctl(V4L_FD, VIDIOCCAPTURE, &zero))
+ perror("ioctl VIDIOCCAPTURE(0)");
+
+ V4lCloseDevice(pPPriv,pScrn);
+ pPPriv->VideoOn = VIDEO_OFF;
+ }
+}
+
+/* v4l uses range 0 - 65535; Xv uses -1000 - 1000 */
+static int
+v4l_to_xv(int val) {
+ val = val * 2000 / 65536 - 1000;
+ if (val < -1000) val = -1000;
+ if (val > 1000) val = 1000;
+ return val;
+}
+static int
+xv_to_v4l(int val) {
+ val = val * 65536 / 2000 + 32768;
+ if (val < -0) val = 0;
+ if (val > 65535) val = 65535;
+ return val;
+}
+
+static int
+V4lSetPortAttribute(ScrnInfoPtr pScrn,
+ Atom attribute, INT32 value, pointer data)
+{
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+ struct video_channel chan;
+ int ret = Success;
+
+ if (V4lOpenDevice(pPPriv, pScrn))
+ return Success;
+
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/SPA %d, %d\n",
+ attribute, value));
+
+ if (-1 == V4L_FD) {
+ ret = Success;
+ } else if (attribute == xvEncoding) {
+ if (value >= 0 && value < pPPriv->nenc) {
+ pPPriv->cenc = value;
+ chan.channel = pPPriv->input[value];
+ chan.norm = pPPriv->norm[value];
+ if (-1 == ioctl(V4L_FD,VIDIOCSCHAN,&chan))
+ perror("ioctl VIDIOCSCHAN");
+ } else {
+ ret = BadValue;
+ }
+ } else if (attribute == xvBrightness ||
+ attribute == xvContrast ||
+ attribute == xvSaturation ||
+ attribute == xvHue) {
+ ioctl(V4L_FD,VIDIOCGPICT,&pPPriv->pict);
+ if (attribute == xvBrightness) pPPriv->pict.brightness = xv_to_v4l(value);
+ if (attribute == xvContrast) pPPriv->pict.contrast = xv_to_v4l(value);
+ if (attribute == xvSaturation) pPPriv->pict.colour = xv_to_v4l(value);
+ if (attribute == xvHue) pPPriv->pict.hue = xv_to_v4l(value);
+ if (-1 == ioctl(V4L_FD,VIDIOCSPICT,&pPPriv->pict))
+ perror("ioctl VIDIOCSPICT");
+ } else if (attribute == xvMute ||
+ attribute == xvVolume) {
+ ioctl(V4L_FD,VIDIOCGAUDIO,&pPPriv->audio);
+ if (attribute == xvMute) {
+ if (value)
+ pPPriv->audio.flags |= VIDEO_AUDIO_MUTE;
+ else
+ pPPriv->audio.flags &= ~VIDEO_AUDIO_MUTE;
+ } else if (attribute == xvVolume) {
+ if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME)
+ pPPriv->audio.volume = xv_to_v4l(value);
+ } else {
+ ret = BadValue;
+ }
+ if (ret != BadValue)
+ if (-1 == ioctl(V4L_FD,VIDIOCSAUDIO,&pPPriv->audio))
+ perror("ioctl VIDIOCSAUDIO");
+ } else if (attribute == xvFreq) {
+ if (-1 == ioctl(V4L_FD,VIDIOCSFREQ,&value))
+ perror("ioctl VIDIOCSFREQ");
+ } else if (0 != pPPriv->yuv_format &&
+ pPPriv->myfmt->setAttribute) {
+ /* not mine -> pass to yuv scaler driver */
+ ret = pPPriv->myfmt->setAttribute(pScrn, attribute, value);
+ } else {
+ ret = BadValue;
+ }
+
+ V4lCloseDevice(pPPriv,pScrn);
+ return ret;
+}
+
+static int
+V4lGetPortAttribute(ScrnInfoPtr pScrn,
+ Atom attribute, INT32 *value, pointer data)
+{
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+ int ret = Success;
+
+ if (V4lOpenDevice(pPPriv, pScrn))
+ return Success;
+
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/GPA %d\n",
+ attribute));
+
+ if (-1 == V4L_FD) {
+ ret = Success;
+ } else if (attribute == xvEncoding) {
+ *value = pPPriv->cenc;
+ } else if (attribute == xvBrightness ||
+ attribute == xvContrast ||
+ attribute == xvSaturation ||
+ attribute == xvHue) {
+ ioctl(V4L_FD,VIDIOCGPICT,&pPPriv->pict);
+ if (attribute == xvBrightness) *value = v4l_to_xv(pPPriv->pict.brightness);
+ if (attribute == xvContrast) *value = v4l_to_xv(pPPriv->pict.contrast);
+ if (attribute == xvSaturation) *value = v4l_to_xv(pPPriv->pict.colour);
+ if (attribute == xvHue) *value = v4l_to_xv(pPPriv->pict.hue);
+ } else if (attribute == xvMute ||
+ attribute == xvVolume) {
+ ioctl(V4L_FD,VIDIOCGAUDIO,&pPPriv->audio);
+ if (attribute == xvMute) {
+ *value = (pPPriv->audio.flags & VIDEO_AUDIO_MUTE) ? 1 : 0;
+ } else if (attribute == xvVolume) {
+ if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME)
+ *value = v4l_to_xv(pPPriv->audio.volume);
+ } else {
+ ret = BadValue;
+ }
+ } else if (attribute == xvFreq) {
+ ioctl(V4L_FD,VIDIOCGFREQ,value);
+ } else if (0 != pPPriv->yuv_format &&
+ pPPriv->myfmt->getAttribute) {
+ /* not mine -> pass to yuv scaler driver */
+ ret = pPPriv->myfmt->getAttribute(pScrn, attribute, value);
+ } else {
+ ret = BadValue;
+ }
+
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/GPA %d, %d\n",
+ attribute, *value));
+
+ V4lCloseDevice(pPPriv,pScrn);
+ return ret;
+}
+
+static void
+V4lQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h, pointer data)
+{
+ PortPrivPtr pPPriv = (PortPrivPtr) data;
+ int maxx = pPPriv->enc[pPPriv->cenc].width;
+ int maxy = pPPriv->enc[pPPriv->cenc].height;
+
+ if (0 != pPPriv->yuv_format) {
+ *p_w = pPPriv->myfmt->max_width;
+ *p_h = pPPriv->myfmt->max_height;
+ } else {
+ *p_w = (drw_w < maxx) ? drw_w : maxx;
+ *p_h = (drw_h < maxy) ? drw_h : maxy;
+ }
+
+ DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/BS %d %dx%d %dx%d\n",
+ pPPriv->cenc,drw_w,drw_h,*p_w,*p_h));
+}
+
+static const OptionInfoRec *
+V4LAvailableOptions(int chipid, int busid)
+{
+ return NULL;
+}
+
+static void
+V4LIdentify(int flags)
+{
+ xf86Msg(X_INFO, "v4l driver for Video4Linux\n");
+}
+
+static char*
+fixname(char *str)
+{
+ int s,d;
+ for (s=0, d=0;; s++) {
+ if (str[s] == '-')
+ continue;
+ str[d++] = tolower(str[s]);
+ if (0 == str[s])
+ break;
+ }
+ return str;
+}
+
+static int
+v4l_add_enc(XF86VideoEncodingPtr enc, int i,
+ char *norm, char *input, int width, int height, int n, int d)
+{
+ enc[i].id = i;
+ enc[i].name = xalloc(strlen(norm)+strlen(input)+2);
+ if (NULL == enc[i].name)
+ return -1;
+ enc[i].width = width;
+ enc[i].height = height;
+ enc[i].rate.numerator = n;
+ enc[i].rate.denominator = d;
+ sprintf(enc[i].name,"%s-%s",norm,fixname(input));
+ return 0;
+}
+
+static void
+V4LBuildEncodings(PortPrivPtr p, int fd, int channels)
+{
+ static struct video_channel channel;
+ int i,entries,have_bttv;
+
+#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+ have_bttv = 0;
+ if (-1 != ioctl(fd,BTTV_VERSION,NULL))
+ have_bttv = 1;
+
+ entries = (have_bttv ? 7 : 3) * channels;
+ p->enc = xalloc(sizeof(XF86VideoEncodingRec) * entries);
+ if (NULL == p->enc)
+ goto fail;
+ memset(p->enc,0,sizeof(XF86VideoEncodingRec) * entries);
+ p->norm = xalloc(sizeof(int) * entries);
+ if (NULL == p->norm)
+ goto fail;
+ memset(p->norm,0,sizeof(int) * entries);
+ p->input = xalloc(sizeof(int) * entries);
+ if (NULL == p->input)
+ goto fail;
+ memset(p->input,0,sizeof(int) * entries);
+
+ p->nenc = 0;
+ for (i = 0; i < channels; i++) {
+ channel.channel = i;
+ if (-1 == ioctl(fd,VIDIOCGCHAN,&channel)) {
+ perror("ioctl VIDIOCGCHAN");
+ continue;
+ }
+
+ v4l_add_enc(p->enc, p->nenc,"pal", channel.name, 768,576, 1,50);
+ p->norm[p->nenc] = VIDEO_MODE_PAL;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ v4l_add_enc(p->enc,p->nenc,"ntsc", channel.name, 640,480, 1001,60000);
+ p->norm[p->nenc] = VIDEO_MODE_NTSC;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ v4l_add_enc(p->enc,p->nenc,"secam",channel.name, 768,576, 1,50);
+ p->norm[p->nenc] = VIDEO_MODE_SECAM;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ if (have_bttv) {
+ /* workaround for a v4l design flaw: The v4l API knows just pal,
+ ntsc and secam. But there are a few more norms (pal versions
+ with a different timings used in south america for example).
+ The bttv driver can handle these too. */
+ if (0 != v4l_add_enc(p->enc,p->nenc,"palnc",channel.name,
+ 640, 576, 1,50))
+ goto fail;
+ p->norm[p->nenc] = 3;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ if (0 != v4l_add_enc(p->enc,p->nenc,"palm",channel.name,
+ 640, 576, 1,50))
+ goto fail;
+ p->norm[p->nenc] = 4;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ if (0 != v4l_add_enc(p->enc, p->nenc,"paln", channel.name,
+ 768,576, 1,50))
+ goto fail;
+ p->norm[p->nenc] = 5;
+ p->input[p->nenc] = i;
+ p->nenc++;
+
+ if (0 != v4l_add_enc(p->enc,p->nenc,"ntscjp", channel.name,
+ 640,480, 1001,60000))
+ goto fail;
+ p->norm[p->nenc] = 6;
+ p->input[p->nenc] = i;
+ p->nenc++;
+ }
+ }
+ return;
+
+ fail:
+ if (p->input)
+ xfree(p->input);
+ p->input = NULL;
+ if (p->norm)
+ xfree(p->norm);
+ p->norm = NULL;
+ if (p->enc)
+ xfree(p->enc);
+ p->enc = NULL;
+ p->nenc = 0;
+}
+
+/* add a attribute a list */
+static void
+v4l_add_attr(XF86AttributeRec **list, int *count,
+ const XF86AttributeRec *attr)
+{
+ XF86AttributeRec *oldlist = *list;
+ int i;
+
+ for (i = 0; i < *count; i++) {
+ if (0 == strcmp((*list)[i].name,attr->name)) {
+ DEBUG(xf86Msg(X_INFO, "v4l: skip dup attr %s\n",attr->name));
+ return;
+ }
+ }
+
+ DEBUG(xf86Msg(X_INFO, "v4l: add attr %s\n",attr->name));
+ *list = xalloc((*count + 1) * sizeof(XF86AttributeRec));
+ if (NULL == *list) {
+ *count = 0;
+ return;
+ }
+ if (*count)
+ memcpy(*list, oldlist, *count * sizeof(XF86AttributeRec));
+ memcpy(*list + *count, attr, sizeof(XF86AttributeRec));
+ (*count)++;
+}
+
+/* setup yuv overlay + hw scaling: look if we find some common video
+ format which both v4l driver and the X-Server can handle */
+static void v4l_check_yuv(ScrnInfoPtr pScrn, PortPrivPtr pPPriv,
+ char *dev, int fd)
+{
+ static const struct {
+ unsigned int v4l_palette;
+ unsigned int v4l_depth;
+ unsigned int xv_id;
+ unsigned int xv_format;
+ } yuvlist[] = {
+ { VIDEO_PALETTE_YUV422, 16, 0x32595559, XvPacked },
+ { VIDEO_PALETTE_UYVY, 16, 0x59565955, XvPacked },
+ { 0 /* end of list */ },
+ };
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ int fmt,i;
+
+ pPPriv->format = xf86XVQueryOffscreenImages(pScreen,&pPPriv->nformat);
+ for (fmt = 0; yuvlist[fmt].v4l_palette != 0; fmt++) {
+ /* check v4l ... */
+ ioctl(fd,VIDIOCGPICT,&pPPriv->pict);
+ pPPriv->pict.palette = yuvlist[fmt].v4l_palette;
+ pPPriv->pict.depth = yuvlist[fmt].v4l_depth;
+ if (-1 == ioctl(fd,VIDIOCSPICT,&pPPriv->pict))
+ continue;
+ ioctl(fd,VIDIOCGPICT,&pPPriv->pict);
+ if (pPPriv->pict.palette != yuvlist[fmt].v4l_palette)
+ continue;
+ /* ... works, check available offscreen image formats now ... */
+ for (i = 0; i < pPPriv->nformat; i++) {
+ if (pPPriv->format[i].image->id == yuvlist[fmt].xv_id &&
+ pPPriv->format[i].image->format == yuvlist[fmt].xv_format) {
+ /* ... match found, good. */
+ pPPriv->yuv_format = yuvlist[fmt].v4l_palette;
+ pPPriv->myfmt = pPPriv->format+i;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "v4l[%s]: using hw video scaling [%4.4s].\n",
+ dev,(char*)&(pPPriv->format[i].image->id));
+ return;
+ }
+ }
+ }
+}
+
+static int
+V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors)
+{
+ PortPrivPtr pPPriv;
+ DevUnion *Private;
+ XF86VideoAdaptorPtr *VAR = NULL;
+ char dev[18];
+ int fd,i,j,d;
+
+ DEBUG(xf86Msg(X_INFO, "v4l: init start\n"));
+
+ for (i = 0, d = 0; d < MAX_V4L_DEVICES; d++) {
+ sprintf(dev, "/dev/video%d", d);
+ fd = open(dev, O_RDWR, 0);
+ if (fd == -1) {
+ sprintf(dev, "/dev/v4l/video%d", d);
+ fd = open(dev, O_RDWR, 0);
+ if (fd == -1)
+ break;
+ }
+ DEBUG(xf86Msg(X_INFO, "v4l: %s open ok\n",dev));
+
+ /* our private data */
+ pPPriv = xalloc(sizeof(PortPrivRec));
+ if (!pPPriv)
+ return FALSE;
+ memset(pPPriv,0,sizeof(PortPrivRec));
+ pPPriv->nr = d;
+
+ /* check device */
+ if (-1 == ioctl(fd,VIDIOCGCAP,&pPPriv->cap) ||
+ 0 == (pPPriv->cap.type & VID_TYPE_OVERLAY)) {
+ DEBUG(xf86Msg(X_INFO, "v4l: %s: no overlay support\n",dev));
+ xfree(pPPriv);
+ close(fd);
+ continue;
+ }
+ strncpy(V4L_NAME, dev, 16);
+ V4LBuildEncodings(pPPriv,fd,pPPriv->cap.channels);
+ if (NULL == pPPriv->enc)
+ return FALSE;
+ v4l_check_yuv(pScrn,pPPriv,dev,fd);
+
+ /* alloc VideoAdaptorRec */
+ VAR = xrealloc(VAR,sizeof(XF86VideoAdaptorPtr)*(i+1));
+ VAR[i] = xalloc(sizeof(XF86VideoAdaptorRec));
+ if (!VAR[i])
+ return FALSE;
+ memset(VAR[i],0,sizeof(XF86VideoAdaptorRec));
+
+
+ /* build attribute list */
+ for (j = 0; j < V4L_ATTR; j++) {
+ /* video attributes */
+ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,
+ &Attributes[j]);
+ }
+ if (0 == ioctl(fd,VIDIOCGAUDIO,&pPPriv->audio)) {
+ /* audio attributes */
+ if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME)
+ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,
+ &VolumeAttr);
+ if (pPPriv->audio.flags & VIDEO_AUDIO_MUTABLE)
+ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,
+ &MuteAttr);
+ }
+ if (pPPriv->cap.type & VID_TYPE_TUNER) {
+ /* tuner attributes */
+ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,
+ &FreqAttr);
+ }
+ if (0 != pPPriv->yuv_format) {
+ /* pass throuth scaler attributes */
+ for (j = 0; j < pPPriv->myfmt->num_attributes; j++) {
+ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,
+ pPPriv->myfmt->attributes+j);
+ }
+ }
+
+
+ /* hook in private data */
+ Private = xalloc(sizeof(DevUnion));
+ if (!Private)
+ return FALSE;
+ memset(Private,0,sizeof(DevUnion));
+ Private->ptr = (pointer)pPPriv;
+ VAR[i]->pPortPrivates = Private;
+ VAR[i]->nPorts = 1;
+
+ /* init VideoAdaptorRec */
+ VAR[i]->type = XvInputMask | XvWindowMask | XvVideoMask;
+ VAR[i]->name = "video4linux";
+ VAR[i]->flags = VIDEO_INVERT_CLIPLIST;
+
+ VAR[i]->PutVideo = V4lPutVideo;
+ VAR[i]->PutStill = V4lPutStill;
+ VAR[i]->StopVideo = V4lStopVideo;
+ VAR[i]->SetPortAttribute = V4lSetPortAttribute;
+ VAR[i]->GetPortAttribute = V4lGetPortAttribute;
+ VAR[i]->QueryBestSize = V4lQueryBestSize;
+
+ VAR[i]->nEncodings = pPPriv->nenc;
+ VAR[i]->pEncodings = pPPriv->enc;
+ VAR[i]->nFormats =
+ sizeof(InputVideoFormats) / sizeof(InputVideoFormats[0]);
+ VAR[i]->pFormats = InputVideoFormats;
+
+ if (fd != -1)
+ close(fd);
+ i++;
+ }
+
+ xvEncoding = MAKE_ATOM(XV_ENCODING);
+ xvHue = MAKE_ATOM(XV_HUE);
+ xvSaturation = MAKE_ATOM(XV_SATURATION);
+ xvBrightness = MAKE_ATOM(XV_BRIGHTNESS);
+ xvContrast = MAKE_ATOM(XV_CONTRAST);
+
+ xvFreq = MAKE_ATOM(XV_FREQ);
+ xvMute = MAKE_ATOM(XV_MUTE);
+ xvVolume = MAKE_ATOM(XV_VOLUME);
+
+ DEBUG(xf86Msg(X_INFO, "v4l: init done, %d device(s) found\n",i));
+
+ *adaptors = VAR;
+ return i;
+}
+
+static Bool
+V4LProbe(DriverPtr drv, int flags)
+{
+ if (flags & PROBE_DETECT)
+ return TRUE;
+
+ xf86XVRegisterGenericAdaptorDriver(V4LInit);
+ drv->refCount++;
+ return TRUE;
+}
diff --git a/src/videodev.h b/src/videodev.h
new file mode 100644
index 0000000..77b592e
--- /dev/null
+++ b/src/videodev.h
@@ -0,0 +1,255 @@
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+/* Linux V4L API, Version 1
+ * videodev.h from v4l driver in Linux 2.2.3
+ *
+ * Used here with the explicit permission of the original author, Alan Cox.
+ * <alan@lxorguk.ukuu.org.uk>
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/videodev.h,v 1.8 2001/03/03 22:46:31 tsi Exp $ */
+
+#include "Xmd.h"
+
+#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 */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ CARD32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ CARD16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+ CARD16 norm; /* Norm set by channel */
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ unsigned long rangelow, rangehigh; /* Tuner range */
+ CARD32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+ CARD16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ CARD16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ CARD16 brightness;
+ CARD16 hue;
+ CARD16 colour;
+ CARD16 contrast;
+ CARD16 whiteness; /* Black and white only */
+ CARD16 depth; /* Capture depth */
+ CARD16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ CARD16 volume; /* If settable */
+ CARD16 bass, treble;
+ CARD32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 4
+#define VIDEO_SOUND_LANG2 8
+ CARD16 mode;
+ CARD16 balance; /* Stereo balance */
+ CARD16 step; /* Step actual volume uses */
+};
+
+struct video_clip
+{
+ INT32 x,y;
+ INT32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ CARD32 x,y; /* Position of window */
+ CARD32 width,height; /* Its size */
+ CARD32 chromakey;
+ CARD32 flags;
+ struct video_clip *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
+};
+
+struct video_capture
+{
+ CARD32 x,y; /* Offsets into image */
+ CARD32 width, height; /* Area to capture */
+ CARD16 decimation; /* Decimation divder */
+ CARD16 flags; /* Flags for capture */
+#define VIDEO_CAPTURE_ODD 0 /* Temporal */
+#define VIDEO_CAPTURE_EVEN 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 - n) for double buffer */
+ int height,width;
+ unsigned int format; /* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+ CARD8 key[8];
+ CARD32 flags;
+};
+
+
+#define VIDEO_MAX_FRAME 32
+
+struct video_mbuf
+{
+ int size; /* Total memory to map */
+ int frames; /* Frames */
+ int offsets[VIDEO_MAX_FRAME];
+};
+
+
+#define VIDEO_NO_UNIT (-1)
+
+
+struct video_unit
+{
+ int video; /* Video minor */
+ int vbi; /* VBI minor */
+ int radio; /* Radio minor */
+ int audio; /* Audio minor */
+ int teletext; /* Teletext minor */
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+#define VIDIOCGMBUF _IOR('v', 20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v', 21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get frame buffer */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set frame buffer - root only */
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+
+#define VID_HARDWARE_BT848 1
+#define VID_HARDWARE_QCAM_BW 2
+#define VID_HARDWARE_PMS 3
+#define VID_HARDWARE_QCAM_C 4
+#define VID_HARDWARE_PSEUDO 5
+#define VID_HARDWARE_SAA5249 6
+#define VID_HARDWARE_AZTECH 7
+#define VID_HARDWARE_SF16MI 8
+#define VID_HARDWARE_RTRACK 9
+#define VID_HARDWARE_ZOLTRIX 10
+#define VID_HARDWARE_SAA7146 11
+#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */
+#define VID_HARDWARE_RTRACK2 13
+#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */
+#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */
+#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */
+#define VID_HARDWARE_BROADWAY 17 /* Broadway project */
+#define VID_HARDWARE_GEMTEK 18
+#define VID_HARDWARE_TYPHOON 19
+#define VID_HARDWARE_VINO 20 /* Reserved for SGI Indy Vino */
+
+/*
+ * Initialiser list
+ */
+
+struct video_init
+{
+ char *name;
+ int (*init)(struct video_init *);
+};
+
+#endif