aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 09:35:11 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 09:35:11 -0700
commit0851668fdd97e526b2a41f794b785c204dd3d3e0 (patch)
tree4ef7c20a8be8393006c6fe9627eb29dd30877d61 /drivers/staging
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc (diff)
parent[media] af9015: Fix max I2C message size when used with tda18271 (diff)
downloadlinux-dev-0851668fdd97e526b2a41f794b785c204dd3d3e0.tar.xz
linux-dev-0851668fdd97e526b2a41f794b785c204dd3d3e0.zip
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (505 commits) [media] af9015: Fix max I2C message size when used with tda18271 [media] IR: initialize ir_raw_event in few more drivers [media] Guard a divide in v4l1 compat layer [media] imon: fix nomouse modprobe option [media] imon: remove redundant change_protocol call [media] imon: fix my egregious brown paper bag w/rdev/idev split [media] cafe_ccic: Configure ov7670 correctly [media] ov7670: allow configuration of image size, clock speed, and I/O method [media] af9015: support for DigitalNow TinyTwin v3 [1f4d:9016] [media] af9015: map DigitalNow TinyTwin v2 remote [media] DigitalNow TinyTwin remote controller [media] af9015: RC fixes and improvements videodev2.h.xml: Update to reflect the latest changes at videodev2.h [media] v4l: document new Bayer and monochrome pixel formats [media] DocBook/v4l: Add missing formats used on gspca cpia1 and sn9c2028 [media] firedtv: add parameter to fake ca_system_ids in CA_INFO [media] tm6000: fix a macro coding style issue tm6000: Remove some ugly debug code [media] Nova-S-Plus audio line input [media] [RFC,1/1] V4L2: Use new CAP bits in existing RDS capable drivers ...
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile2
-rw-r--r--drivers/staging/cpia/Kconfig39
-rw-r--r--drivers/staging/cpia/Makefile5
-rw-r--r--drivers/staging/cpia/TODO8
-rw-r--r--drivers/staging/cpia/cpia.c4032
-rw-r--r--drivers/staging/cpia/cpia.h432
-rw-r--r--drivers/staging/cpia/cpia_pp.c869
-rw-r--r--drivers/staging/cpia/cpia_usb.c640
-rw-r--r--drivers/staging/cx25821/Kconfig2
-rw-r--r--drivers/staging/cx25821/cx25821-alsa.c2
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.c13
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.h4
-rw-r--r--drivers/staging/cx25821/cx25821-audio.h10
-rw-r--r--drivers/staging/cx25821/cx25821-core.c64
-rw-r--r--drivers/staging/cx25821/cx25821-i2c.c2
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-reg.h10
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c8
-rw-r--r--drivers/staging/cx25821/cx25821-reg.h4
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.c135
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.h14
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.c28
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.h10
-rw-r--r--drivers/staging/cx25821/cx25821-video.c6
-rw-r--r--drivers/staging/cx25821/cx25821.h51
-rw-r--r--drivers/staging/dt3155v4l/dt3155v4l.c8
-rw-r--r--drivers/staging/go7007/Kconfig2
-rw-r--r--drivers/staging/go7007/go7007-driver.c55
-rw-r--r--drivers/staging/go7007/go7007-usb.c2
-rw-r--r--drivers/staging/go7007/go7007-v4l2.c19
-rw-r--r--drivers/staging/go7007/s2250-board.c34
-rw-r--r--drivers/staging/go7007/wis-ov7640.c1
-rw-r--r--drivers/staging/go7007/wis-saa7113.c1
-rw-r--r--drivers/staging/go7007/wis-saa7115.c1
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c1
-rw-r--r--drivers/staging/go7007/wis-tw2804.c1
-rw-r--r--drivers/staging/go7007/wis-tw9903.c1
-rw-r--r--drivers/staging/go7007/wis-uda1342.c1
-rw-r--r--drivers/staging/lirc/Kconfig2
-rw-r--r--drivers/staging/lirc/lirc_igorplugusb.c190
-rw-r--r--drivers/staging/lirc/lirc_it87.c23
-rw-r--r--drivers/staging/lirc/lirc_ite8709.c6
-rw-r--r--drivers/staging/lirc/lirc_parallel.c61
-rw-r--r--drivers/staging/lirc/lirc_serial.c24
-rw-r--r--drivers/staging/lirc/lirc_sir.c24
-rw-r--r--drivers/staging/lirc/lirc_zilog.c3
-rw-r--r--drivers/staging/stradis/Kconfig7
-rw-r--r--drivers/staging/stradis/Makefile3
-rw-r--r--drivers/staging/stradis/TODO6
-rw-r--r--drivers/staging/stradis/stradis.c2213
-rw-r--r--drivers/staging/tm6000/TODO6
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c102
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c41
-rw-r--r--drivers/staging/tm6000/tm6000-core.c157
-rw-r--r--drivers/staging/tm6000/tm6000-dvb.c32
-rw-r--r--drivers/staging/tm6000/tm6000-i2c.c43
-rw-r--r--drivers/staging/tm6000/tm6000-input.c34
-rw-r--r--drivers/staging/tm6000/tm6000-regs.h32
-rw-r--r--drivers/staging/tm6000/tm6000-stds.c350
-rw-r--r--drivers/staging/tm6000/tm6000-usb-isoc.h32
-rw-r--r--drivers/staging/tm6000/tm6000-video.c442
-rw-r--r--drivers/staging/tm6000/tm6000.h54
62 files changed, 9519 insertions, 889 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 8e03e7600239..2ea91e049255 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -51,6 +51,10 @@ source "drivers/staging/cx25821/Kconfig"
source "drivers/staging/tm6000/Kconfig"
+source "drivers/staging/cpia/Kconfig"
+
+source "drivers/staging/stradis/Kconfig"
+
source "drivers/staging/usbip/Kconfig"
source "drivers/staging/winbond/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 0e7d7559d379..c359fbb0e04a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
+obj-$(CONFIG_VIDEO_CPIA) += cpia/
+obj-$(CONFIG_VIDEO_STRADIS) += stradis/
obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
diff --git a/drivers/staging/cpia/Kconfig b/drivers/staging/cpia/Kconfig
new file mode 100644
index 000000000000..205d247ad373
--- /dev/null
+++ b/drivers/staging/cpia/Kconfig
@@ -0,0 +1,39 @@
+config VIDEO_CPIA
+ tristate "CPiA Video For Linux (DEPRECATED)"
+ depends on VIDEO_V4L1
+ default n
+ ---help---
+ This driver is DEPRECATED please use the gspca cpia1 module
+ instead. Note that you need atleast version 0.6.4 of libv4l for
+ the cpia1 gspca module.
+
+ This is the video4linux driver for cameras based on Vision's CPiA
+ (Colour Processor Interface ASIC), such as the Creative Labs Video
+ Blaster Webcam II. If you have one of these cameras, say Y here
+ and select parallel port and/or USB lowlevel support below,
+ otherwise say N. This will not work with the Creative Webcam III.
+
+ Please read <file:Documentation/video4linux/README.cpia> for more
+ information.
+
+ This driver is also available as a module (cpia).
+
+config VIDEO_CPIA_PP
+ tristate "CPiA Parallel Port Lowlevel Support"
+ depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
+ help
+ This is the lowlevel parallel port support for cameras based on
+ Vision's CPiA (Colour Processor Interface ASIC), such as the
+ Creative Webcam II. If you have the parallel port version of one
+ of these cameras, say Y here, otherwise say N. It is also available
+ as a module (cpia_pp).
+
+config VIDEO_CPIA_USB
+ tristate "CPiA USB Lowlevel Support"
+ depends on VIDEO_CPIA && USB
+ help
+ This is the lowlevel USB support for cameras based on Vision's CPiA
+ (Colour Processor Interface ASIC), such as the Creative Webcam II.
+ If you have the USB version of one of these cameras, say Y here,
+ otherwise say N. This will not work with the Creative Webcam III.
+ It is also available as a module (cpia_usb).
diff --git a/drivers/staging/cpia/Makefile b/drivers/staging/cpia/Makefile
new file mode 100644
index 000000000000..89e52f10d739
--- /dev/null
+++ b/drivers/staging/cpia/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/cpia/TODO b/drivers/staging/cpia/TODO
new file mode 100644
index 000000000000..ccb1c0775eec
--- /dev/null
+++ b/drivers/staging/cpia/TODO
@@ -0,0 +1,8 @@
+This is an obsolete driver for some cpia-based webcams that use the parallel port.
+We couldn't find anyone with this hardware in order to port it to use V4L2.
+
+Also, parallel-port webcams are obsolete nowadays.
+
+If nobody take care on it, the driver will be removed for 2.6.38.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/cpia/cpia.c b/drivers/staging/cpia/cpia.c
new file mode 100644
index 000000000000..933ae4c8cb9a
--- /dev/null
+++ b/drivers/staging/cpia/cpia.c
@@ -0,0 +1,4032 @@
+/*
+ * cpia CPiA driver
+ *
+ * Supports CPiA based Video Camera's.
+ *
+ * (C) Copyright 1999-2000 Peter Pregler
+ * (C) Copyright 1999-2000 Scott J. Bertin
+ * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
+ * (C) Copyright 2000 STMicroelectronics
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_ 1 */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/mutex.h>
+
+#include "cpia.h"
+
+static int video_nr = -1;
+
+#ifdef MODULE
+module_param(video_nr, int, 0);
+MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
+MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
+#endif
+
+static unsigned short colorspace_conv;
+module_param(colorspace_conv, ushort, 0444);
+MODULE_PARM_DESC(colorspace_conv,
+ " Colorspace conversion:"
+ "\n 0 = disable, 1 = enable"
+ "\n Default value is 0"
+ );
+
+#define ABOUT "V4L-Driver for Vision CPiA based cameras"
+
+#define CPIA_MODULE_CPIA (0<<5)
+#define CPIA_MODULE_SYSTEM (1<<5)
+#define CPIA_MODULE_VP_CTRL (5<<5)
+#define CPIA_MODULE_CAPTURE (6<<5)
+#define CPIA_MODULE_DEBUG (7<<5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
+#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
+#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
+
+#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
+#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
+
+enum {
+ FRAME_READY, /* Ready to grab into */
+ FRAME_GRABBING, /* In the process of being grabbed into */
+ FRAME_DONE, /* Finished grabbing, but not been synced yet */
+ FRAME_UNUSED, /* Unused (no MCAPTURE) */
+};
+
+#define COMMAND_NONE 0x0000
+#define COMMAND_SETCOMPRESSION 0x0001
+#define COMMAND_SETCOMPRESSIONTARGET 0x0002
+#define COMMAND_SETCOLOURPARAMS 0x0004
+#define COMMAND_SETFORMAT 0x0008
+#define COMMAND_PAUSE 0x0010
+#define COMMAND_RESUME 0x0020
+#define COMMAND_SETYUVTHRESH 0x0040
+#define COMMAND_SETECPTIMING 0x0080
+#define COMMAND_SETCOMPRESSIONPARAMS 0x0100
+#define COMMAND_SETEXPOSURE 0x0200
+#define COMMAND_SETCOLOURBALANCE 0x0400
+#define COMMAND_SETSENSORFPS 0x0800
+#define COMMAND_SETAPCOR 0x1000
+#define COMMAND_SETFLICKERCTRL 0x2000
+#define COMMAND_SETVLOFFSET 0x4000
+#define COMMAND_SETLIGHTS 0x8000
+
+#define ROUND_UP_EXP_FOR_FLICKER 15
+
+/* Constants for automatic frame rate adjustment */
+#define MAX_EXP 302
+#define MAX_EXP_102 255
+#define LOW_EXP 140
+#define VERY_LOW_EXP 70
+#define TC 94
+#define EXP_ACC_DARK 50
+#define EXP_ACC_LIGHT 90
+#define HIGH_COMP_102 160
+#define MAX_COMP 239
+#define DARK_TIME 3
+#define LIGHT_TIME 3
+
+/* Maximum number of 10ms loops to wait for the stream to become ready */
+#define READY_TIMEOUT 100
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+ { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+/* forward declaration of local function */
+static void reset_camera_struct(struct cam_data *cam);
+static int find_over_exposure(int brightness);
+static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
+ int on);
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ **********************************************************************/
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+ size = PAGE_ALIGN(size);
+ mem = vmalloc_32(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ adr = (unsigned long) mem;
+ while ((long) size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * /proc interface
+ *
+ **********************************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *cpia_proc_root=NULL;
+
+static int cpia_proc_show(struct seq_file *m, void *v)
+{
+ struct cam_data *cam = m->private;
+ int tmp;
+ char tmpstr[29];
+
+ seq_printf(m, "read-only\n-----------------------\n");
+ seq_printf(m, "V4L Driver version: %d.%d.%d\n",
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+ seq_printf(m, "CPIA Version: %d.%02d (%d.%d)\n",
+ cam->params.version.firmwareVersion,
+ cam->params.version.firmwareRevision,
+ cam->params.version.vcVersion,
+ cam->params.version.vcRevision);
+ seq_printf(m, "CPIA PnP-ID: %04x:%04x:%04x\n",
+ cam->params.pnpID.vendor, cam->params.pnpID.product,
+ cam->params.pnpID.deviceRevision);
+ seq_printf(m, "VP-Version: %d.%d %04x\n",
+ cam->params.vpVersion.vpVersion,
+ cam->params.vpVersion.vpRevision,
+ cam->params.vpVersion.cameraHeadID);
+
+ seq_printf(m, "system_state: %#04x\n",
+ cam->params.status.systemState);
+ seq_printf(m, "grab_state: %#04x\n",
+ cam->params.status.grabState);
+ seq_printf(m, "stream_state: %#04x\n",
+ cam->params.status.streamState);
+ seq_printf(m, "fatal_error: %#04x\n",
+ cam->params.status.fatalError);
+ seq_printf(m, "cmd_error: %#04x\n",
+ cam->params.status.cmdError);
+ seq_printf(m, "debug_flags: %#04x\n",
+ cam->params.status.debugFlags);
+ seq_printf(m, "vp_status: %#04x\n",
+ cam->params.status.vpStatus);
+ seq_printf(m, "error_code: %#04x\n",
+ cam->params.status.errorCode);
+ /* QX3 specific entries */
+ if (cam->params.qx3.qx3_detected) {
+ seq_printf(m, "button: %4d\n",
+ cam->params.qx3.button);
+ seq_printf(m, "cradled: %4d\n",
+ cam->params.qx3.cradled);
+ }
+ seq_printf(m, "video_size: %s\n",
+ cam->params.format.videoSize == VIDEOSIZE_CIF ?
+ "CIF " : "QCIF");
+ seq_printf(m, "roi: (%3d, %3d) to (%3d, %3d)\n",
+ cam->params.roi.colStart*8,
+ cam->params.roi.rowStart*4,
+ cam->params.roi.colEnd*8,
+ cam->params.roi.rowEnd*4);
+ seq_printf(m, "actual_fps: %3d\n", cam->fps);
+ seq_printf(m, "transfer_rate: %4dkB/s\n",
+ cam->transfer_rate);
+
+ seq_printf(m, "\nread-write\n");
+ seq_printf(m, "----------------------- current min"
+ " max default comment\n");
+ seq_printf(m, "brightness: %8d %8d %8d %8d\n",
+ cam->params.colourParams.brightness, 0, 100, 50);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits contrast to 80 */
+ tmp = 80;
+ else
+ tmp = 96;
+
+ seq_printf(m, "contrast: %8d %8d %8d %8d"
+ " steps of 8\n",
+ cam->params.colourParams.contrast, 0, tmp, 48);
+ seq_printf(m, "saturation: %8d %8d %8d %8d\n",
+ cam->params.colourParams.saturation, 0, 100, 50);
+ tmp = (25000+5000*cam->params.sensorFps.baserate)/
+ (1<<cam->params.sensorFps.divisor);
+ seq_printf(m, "sensor_fps: %4d.%03d %8d %8d %8d\n",
+ tmp/1000, tmp%1000, 3, 30, 15);
+ seq_printf(m, "stream_start_line: %8d %8d %8d %8d\n",
+ 2*cam->params.streamStartLine, 0,
+ cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
+ cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
+ seq_printf(m, "sub_sample: %8s %8s %8s %8s\n",
+ cam->params.format.subSample == SUBSAMPLE_420 ?
+ "420" : "422", "420", "422", "422");
+ seq_printf(m, "yuv_order: %8s %8s %8s %8s\n",
+ cam->params.format.yuvOrder == YUVORDER_YUYV ?
+ "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
+ seq_printf(m, "ecp_timing: %8s %8s %8s %8s\n",
+ cam->params.ecpTiming ? "slow" : "normal", "slow",
+ "normal", "normal");
+
+ if (cam->params.colourBalance.balanceMode == 2) {
+ sprintf(tmpstr, "auto");
+ } else {
+ sprintf(tmpstr, "manual");
+ }
+ seq_printf(m, "color_balance_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ seq_printf(m, "red_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.redGain, 0, 212, 32);
+ seq_printf(m, "green_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.greenGain, 0, 212, 6);
+ seq_printf(m, "blue_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.blueGain, 0, 212, 92);
+
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits gain to 2 */
+ sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
+ else
+ sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
+
+ if (cam->params.exposure.gainMode == 0)
+ seq_printf(m, "max_gain: unknown %28s"
+ " powers of 2\n", tmpstr);
+ else
+ seq_printf(m, "max_gain: %8d %28s"
+ " 1,2,4 or 8 \n",
+ 1<<(cam->params.exposure.gainMode-1), tmpstr);
+
+ switch(cam->params.exposure.expMode) {
+ case 1:
+ case 3:
+ sprintf(tmpstr, "manual");
+ break;
+ case 2:
+ sprintf(tmpstr, "auto");
+ break;
+ default:
+ sprintf(tmpstr, "unknown");
+ break;
+ }
+ seq_printf(m, "exposure_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ seq_printf(m, "centre_weight: %8s %8s %8s %8s\n",
+ (2-cam->params.exposure.centreWeight) ? "on" : "off",
+ "off", "on", "on");
+ seq_printf(m, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
+ 1<<cam->params.exposure.gain, 1, 1);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits fineExp/2 to 127 */
+ tmp = 254;
+ else
+ tmp = 510;
+
+ seq_printf(m, "fine_exp: %8d %8d %8d %8d\n",
+ cam->params.exposure.fineExp*2, 0, tmp, 0);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits coarseExpHi to 0 */
+ tmp = MAX_EXP_102;
+ else
+ tmp = MAX_EXP;
+
+ seq_printf(m, "coarse_exp: %8d %8d %8d"
+ " %8d\n", cam->params.exposure.coarseExpLo+
+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
+ seq_printf(m, "red_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
+ seq_printf(m, "green1_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green1Comp, COMP_GREEN1, 255,
+ COMP_GREEN1);
+ seq_printf(m, "green2_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green2Comp, COMP_GREEN2, 255,
+ COMP_GREEN2);
+ seq_printf(m, "blue_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
+
+ seq_printf(m, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain1, 0, 0xff, 0x1c);
+ seq_printf(m, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain2, 0, 0xff, 0x1a);
+ seq_printf(m, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain4, 0, 0xff, 0x2d);
+ seq_printf(m, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain8, 0, 0xff, 0x2a);
+ seq_printf(m, "vl_offset_gain1: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain1, 0, 255, 24);
+ seq_printf(m, "vl_offset_gain2: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain2, 0, 255, 28);
+ seq_printf(m, "vl_offset_gain4: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain4, 0, 255, 30);
+ seq_printf(m, "vl_offset_gain8: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain8, 0, 255, 30);
+ seq_printf(m, "flicker_control: %8s %8s %8s %8s\n",
+ cam->params.flickerControl.flickerMode ? "on" : "off",
+ "off", "on", "off");
+ seq_printf(m, "mains_frequency: %8d %8d %8d %8d"
+ " only 50/60\n",
+ cam->mainsFreq ? 60 : 50, 50, 60, 50);
+ if(cam->params.flickerControl.allowableOverExposure < 0)
+ seq_printf(m, "allowable_overexposure: %4dauto auto %8d auto\n",
+ -cam->params.flickerControl.allowableOverExposure,
+ 255);
+ else
+ seq_printf(m, "allowable_overexposure: %8d auto %8d auto\n",
+ cam->params.flickerControl.allowableOverExposure,
+ 255);
+ seq_printf(m, "compression_mode: ");
+ switch(cam->params.compression.mode) {
+ case CPIA_COMPRESSION_NONE:
+ seq_printf(m, "%8s", "none");
+ break;
+ case CPIA_COMPRESSION_AUTO:
+ seq_printf(m, "%8s", "auto");
+ break;
+ case CPIA_COMPRESSION_MANUAL:
+ seq_printf(m, "%8s", "manual");
+ break;
+ default:
+ seq_printf(m, "%8s", "unknown");
+ break;
+ }
+ seq_printf(m, " none,auto,manual auto\n");
+ seq_printf(m, "decimation_enable: %8s %8s %8s %8s\n",
+ cam->params.compression.decimation ==
+ DECIMATION_ENAB ? "on":"off", "off", "on",
+ "off");
+ seq_printf(m, "compression_target: %9s %9s %9s %9s\n",
+ cam->params.compressionTarget.frTargeting ==
+ CPIA_COMPRESSION_TARGET_FRAMERATE ?
+ "framerate":"quality",
+ "framerate", "quality", "quality");
+ seq_printf(m, "target_framerate: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetFR, 1, 30, 15);
+ seq_printf(m, "target_quality: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetQ, 1, 64, 5);
+ seq_printf(m, "y_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.yThreshold, 0, 31, 6);
+ seq_printf(m, "uv_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
+ seq_printf(m, "hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.hysteresis, 0, 255, 3);
+ seq_printf(m, "threshold_max: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.threshMax, 0, 255, 11);
+ seq_printf(m, "small_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.smallStep, 0, 255, 1);
+ seq_printf(m, "large_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.largeStep, 0, 255, 3);
+ seq_printf(m, "decimation_hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationHysteresis,
+ 0, 255, 2);
+ seq_printf(m, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.frDiffStepThresh,
+ 0, 255, 5);
+ seq_printf(m, "q_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.qDiffStepThresh,
+ 0, 255, 3);
+ seq_printf(m, "decimation_thresh_mod: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationThreshMod,
+ 0, 255, 2);
+ /* QX3 specific entries */
+ if (cam->params.qx3.qx3_detected) {
+ seq_printf(m, "toplight: %8s %8s %8s %8s\n",
+ cam->params.qx3.toplight ? "on" : "off",
+ "off", "on", "off");
+ seq_printf(m, "bottomlight: %8s %8s %8s %8s\n",
+ cam->params.qx3.bottomlight ? "on" : "off",
+ "off", "on", "off");
+ }
+
+ return 0;
+}
+
+static int cpia_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cpia_proc_show, PDE(inode)->data);
+}
+
+static int match(char *checkstr, char **buffer, size_t *count,
+ int *find_colon, int *err)
+{
+ int ret, colon_found = 1;
+ int len = strlen(checkstr);
+ ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
+ if (ret) {
+ *buffer += len;
+ *count -= len;
+ if (*find_colon) {
+ colon_found = 0;
+ while (*count && (**buffer == ' ' || **buffer == '\t' ||
+ (!colon_found && **buffer == ':'))) {
+ if (**buffer == ':')
+ colon_found = 1;
+ --*count;
+ ++*buffer;
+ }
+ if (!*count || !colon_found)
+ *err = -EINVAL;
+ *find_colon = 0;
+ }
+ }
+ return ret;
+}
+
+static unsigned long int value(char **buffer, size_t *count, int *err)
+{
+ char *p;
+ unsigned long int ret;
+ ret = simple_strtoul(*buffer, &p, 0);
+ if (p == *buffer)
+ *err = -EINVAL;
+ else {
+ *count -= p - *buffer;
+ *buffer = p;
+ }
+ return ret;
+}
+
+static ssize_t cpia_proc_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data;
+ struct cam_params new_params;
+ char *page, *buffer;
+ int retval, find_colon;
+ int size = count;
+ unsigned long val = 0;
+ u32 command_flags = 0;
+ u8 new_mains;
+
+ /*
+ * This code to copy from buf to page is shamelessly copied
+ * from the comx driver
+ */
+ if (count > PAGE_SIZE) {
+ printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE);
+ return -ENOSPC;
+ }
+
+ if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+ if(copy_from_user(page, buf, count))
+ {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ if (page[count-1] == '\n')
+ page[count-1] = '\0';
+ else if (count < PAGE_SIZE)
+ page[count] = '\0';
+ else if (page[count]) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ buffer = page;
+
+ if (mutex_lock_interruptible(&cam->param_lock))
+ return -ERESTARTSYS;
+
+ /*
+ * Skip over leading whitespace
+ */
+ while (count && isspace(*buffer)) {
+ --count;
+ ++buffer;
+ }
+
+ memcpy(&new_params, &cam->params, sizeof(struct cam_params));
+ new_mains = cam->mainsFreq;
+
+#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
+#define VALUE (value(&buffer,&count, &retval))
+#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
+ new_params.version.firmwareRevision == (y))
+
+ retval = 0;
+ while (count && !retval) {
+ find_colon = 1;
+ if (MATCH("brightness")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100)
+ new_params.colourParams.brightness = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ if(new_params.flickerControl.allowableOverExposure < 0)
+ new_params.flickerControl.allowableOverExposure =
+ -find_over_exposure(new_params.colourParams.brightness);
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+
+ } else if (MATCH("contrast")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100) {
+ /* contrast is in steps of 8, so round*/
+ val = ((val + 3) / 8) * 8;
+ /* 1-02 firmware limits contrast to 80*/
+ if (FIRMWARE_VERSION(1,2) && val > 80)
+ val = 80;
+
+ new_params.colourParams.contrast = val;
+ } else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ } else if (MATCH("saturation")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100)
+ new_params.colourParams.saturation = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ } else if (MATCH("sensor_fps")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ /* find values so that sensorFPS is minimized,
+ * but >= val */
+ if (val > 30)
+ retval = -EINVAL;
+ else if (val > 25) {
+ new_params.sensorFps.divisor = 0;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 15) {
+ new_params.sensorFps.divisor = 0;
+ new_params.sensorFps.baserate = 0;
+ } else if (val > 12) {
+ new_params.sensorFps.divisor = 1;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 7) {
+ new_params.sensorFps.divisor = 1;
+ new_params.sensorFps.baserate = 0;
+ } else if (val > 6) {
+ new_params.sensorFps.divisor = 2;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 3) {
+ new_params.sensorFps.divisor = 2;
+ new_params.sensorFps.baserate = 0;
+ } else {
+ new_params.sensorFps.divisor = 3;
+ /* Either base rate would work here */
+ new_params.sensorFps.baserate = 1;
+ }
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ }
+ command_flags |= COMMAND_SETSENSORFPS;
+ cam->exposure_status = EXPOSURE_NORMAL;
+ } else if (MATCH("stream_start_line")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ int max_line = 288;
+
+ if (new_params.format.videoSize == VIDEOSIZE_QCIF)
+ max_line = 144;
+ if (val <= max_line)
+ new_params.streamStartLine = val/2;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("sub_sample")) {
+ if (!retval && MATCH("420"))
+ new_params.format.subSample = SUBSAMPLE_420;
+ else if (!retval && MATCH("422"))
+ new_params.format.subSample = SUBSAMPLE_422;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETFORMAT;
+ } else if (MATCH("yuv_order")) {
+ if (!retval && MATCH("YUYV"))
+ new_params.format.yuvOrder = YUVORDER_YUYV;
+ else if (!retval && MATCH("UYVY"))
+ new_params.format.yuvOrder = YUVORDER_UYVY;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETFORMAT;
+ } else if (MATCH("ecp_timing")) {
+ if (!retval && MATCH("normal"))
+ new_params.ecpTiming = 0;
+ else if (!retval && MATCH("slow"))
+ new_params.ecpTiming = 1;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETECPTIMING;
+ } else if (MATCH("color_balance_mode")) {
+ if (!retval && MATCH("manual"))
+ new_params.colourBalance.balanceMode = 3;
+ else if (!retval && MATCH("auto"))
+ new_params.colourBalance.balanceMode = 2;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("red_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212) {
+ new_params.colourBalance.redGain = val;
+ new_params.colourBalance.balanceMode = 1;
+ } else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("green_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212) {
+ new_params.colourBalance.greenGain = val;
+ new_params.colourBalance.balanceMode = 1;
+ } else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("blue_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212) {
+ new_params.colourBalance.blueGain = val;
+ new_params.colourBalance.balanceMode = 1;
+ } else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("max_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ /* 1-02 firmware limits gain to 2 */
+ if (FIRMWARE_VERSION(1,2) && val > 2)
+ val = 2;
+ switch(val) {
+ case 1:
+ new_params.exposure.gainMode = 1;
+ break;
+ case 2:
+ new_params.exposure.gainMode = 2;
+ break;
+ case 4:
+ new_params.exposure.gainMode = 3;
+ break;
+ case 8:
+ new_params.exposure.gainMode = 4;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ }
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("exposure_mode")) {
+ if (!retval && MATCH("auto"))
+ new_params.exposure.expMode = 2;
+ else if (!retval && MATCH("manual")) {
+ if (new_params.exposure.expMode == 2)
+ new_params.exposure.expMode = 3;
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ new_params.flickerControl.flickerMode = 0;
+ } else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("centre_weight")) {
+ if (!retval && MATCH("on"))
+ new_params.exposure.centreWeight = 1;
+ else if (!retval && MATCH("off"))
+ new_params.exposure.centreWeight = 2;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ switch(val) {
+ case 1:
+ new_params.exposure.gain = 0;
+ break;
+ case 2:
+ new_params.exposure.gain = 1;
+ break;
+ case 4:
+ new_params.exposure.gain = 2;
+ break;
+ case 8:
+ new_params.exposure.gain = 3;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ new_params.exposure.expMode = 1;
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETEXPOSURE;
+ if (new_params.exposure.gain >
+ new_params.exposure.gainMode-1)
+ retval = -EINVAL;
+ }
+ } else if (MATCH("fine_exp")) {
+ if (!retval)
+ val = VALUE/2;
+
+ if (!retval) {
+ if (val < 256) {
+ /* 1-02 firmware limits fineExp/2 to 127*/
+ if (FIRMWARE_VERSION(1,2) && val > 127)
+ val = 127;
+ new_params.exposure.fineExp = val;
+ new_params.exposure.expMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("coarse_exp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= MAX_EXP) {
+ if (FIRMWARE_VERSION(1,2) &&
+ val > MAX_EXP_102)
+ val = MAX_EXP_102;
+ new_params.exposure.coarseExpLo =
+ val & 0xff;
+ new_params.exposure.coarseExpHi =
+ val >> 8;
+ new_params.exposure.expMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("red_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= COMP_RED && val <= 255) {
+ new_params.exposure.redComp = val;
+ new_params.exposure.compMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("green1_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= COMP_GREEN1 && val <= 255) {
+ new_params.exposure.green1Comp = val;
+ new_params.exposure.compMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("green2_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= COMP_GREEN2 && val <= 255) {
+ new_params.exposure.green2Comp = val;
+ new_params.exposure.compMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("blue_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= COMP_BLUE && val <= 255) {
+ new_params.exposure.blueComp = val;
+ new_params.exposure.compMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain1")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain1 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain2")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain2 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain4")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain4 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain8")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain8 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("vl_offset_gain1")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain1 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain2")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain2 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain4")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain4 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain8")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain8 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("flicker_control")) {
+ if (!retval && MATCH("on")) {
+ set_flicker(&new_params, &command_flags, 1);
+ } else if (!retval && MATCH("off")) {
+ set_flicker(&new_params, &command_flags, 0);
+ } else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else if (MATCH("mains_frequency")) {
+ if (!retval && MATCH("50")) {
+ new_mains = 0;
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else if (!retval && MATCH("60")) {
+ new_mains = 1;
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ } else if (MATCH("allowable_overexposure")) {
+ if (!retval && MATCH("auto")) {
+ new_params.flickerControl.allowableOverExposure =
+ -find_over_exposure(new_params.colourParams.brightness);
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff) {
+ new_params.flickerControl.
+ allowableOverExposure = val;
+ if(new_params.flickerControl.flickerMode != 0)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ }
+ } else if (MATCH("compression_mode")) {
+ if (!retval && MATCH("none"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_NONE;
+ else if (!retval && MATCH("auto"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_AUTO;
+ else if (!retval && MATCH("manual"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_MANUAL;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSION;
+ } else if (MATCH("decimation_enable")) {
+ if (!retval && MATCH("off"))
+ new_params.compression.decimation = 0;
+ else if (!retval && MATCH("on"))
+ new_params.compression.decimation = 1;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSION;
+ } else if (MATCH("compression_target")) {
+ if (!retval && MATCH("quality"))
+ new_params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_QUALITY;
+ else if (!retval && MATCH("framerate"))
+ new_params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_FRAMERATE;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("target_framerate")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if(val > 0 && val <= 30)
+ new_params.compressionTarget.targetFR = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("target_quality")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if(val > 0 && val <= 64)
+ new_params.compressionTarget.targetQ = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("y_threshold")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 32)
+ new_params.yuvThreshold.yThreshold = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETYUVTHRESH;
+ } else if (MATCH("uv_threshold")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 32)
+ new_params.yuvThreshold.uvThreshold = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETYUVTHRESH;
+ } else if (MATCH("hysteresis")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.hysteresis = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("threshold_max")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.threshMax = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("small_step")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.smallStep = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("large_step")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.largeStep = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("decimation_hysteresis")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.decimationHysteresis = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("fr_diff_step_thresh")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.frDiffStepThresh = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("q_diff_step_thresh")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.qDiffStepThresh = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("decimation_thresh_mod")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.decimationThreshMod = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("toplight")) {
+ if (!retval && MATCH("on"))
+ new_params.qx3.toplight = 1;
+ else if (!retval && MATCH("off"))
+ new_params.qx3.toplight = 0;
+ else
+ retval = -EINVAL;
+ command_flags |= COMMAND_SETLIGHTS;
+ } else if (MATCH("bottomlight")) {
+ if (!retval && MATCH("on"))
+ new_params.qx3.bottomlight = 1;
+ else if (!retval && MATCH("off"))
+ new_params.qx3.bottomlight = 0;
+ else
+ retval = -EINVAL;
+ command_flags |= COMMAND_SETLIGHTS;
+ } else {
+ DBG("No match found\n");
+ retval = -EINVAL;
+ }
+
+ if (!retval) {
+ while (count && isspace(*buffer) && *buffer != '\n') {
+ --count;
+ ++buffer;
+ }
+ if (count) {
+ if (*buffer == '\0' && count != 1)
+ retval = -EINVAL;
+ else if (*buffer != '\n' && *buffer != ';' &&
+ *buffer != '\0')
+ retval = -EINVAL;
+ else {
+ --count;
+ ++buffer;
+ }
+ }
+ }
+ }
+#undef MATCH
+#undef VALUE
+#undef FIRMWARE_VERSION
+ if (!retval) {
+ if (command_flags & COMMAND_SETCOLOURPARAMS) {
+ /* Adjust cam->vp to reflect these changes */
+ cam->vp.brightness =
+ new_params.colourParams.brightness*65535/100;
+ cam->vp.contrast =
+ new_params.colourParams.contrast*65535/100;
+ cam->vp.colour =
+ new_params.colourParams.saturation*65535/100;
+ }
+ if((command_flags & COMMAND_SETEXPOSURE) &&
+ new_params.exposure.expMode == 2)
+ cam->exposure_status = EXPOSURE_NORMAL;
+
+ memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+ cam->mainsFreq = new_mains;
+ cam->cmd_queue |= command_flags;
+ retval = size;
+ } else
+ DBG("error: %d\n", retval);
+
+ mutex_unlock(&cam->param_lock);
+
+out:
+ free_page((unsigned long)page);
+ return retval;
+}
+
+static const struct file_operations cpia_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cpia_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cpia_proc_write,
+};
+
+static void create_proc_cpia_cam(struct cam_data *cam)
+{
+ struct proc_dir_entry *ent;
+
+ if (!cpia_proc_root || !cam)
+ return;
+
+ ent = proc_create_data(video_device_node_name(&cam->vdev),
+ S_IRUGO|S_IWUSR, cpia_proc_root,
+ &cpia_proc_fops, cam);
+ if (!ent)
+ return;
+
+ /*
+ size of the proc entry is 3736 bytes for the standard webcam;
+ the extra features of the QX3 microscope add 189 bytes.
+ (we have not yet probed the camera to see which type it is).
+ */
+ ent->size = 3736 + 189;
+ cam->proc_entry = ent;
+}
+
+static void destroy_proc_cpia_cam(struct cam_data *cam)
+{
+ if (!cam || !cam->proc_entry)
+ return;
+
+ remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root);
+ cam->proc_entry = NULL;
+}
+
+static void proc_cpia_create(void)
+{
+ cpia_proc_root = proc_mkdir("cpia", NULL);
+
+ if (!cpia_proc_root)
+ LOG("Unable to initialise /proc/cpia\n");
+}
+
+static void __exit proc_cpia_destroy(void)
+{
+ remove_proc_entry("cpia", NULL);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* ----------------------- debug functions ---------------------- */
+
+#define printstatus(cam) \
+ DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
+ cam->params.status.systemState, cam->params.status.grabState, \
+ cam->params.status.streamState, cam->params.status.fatalError, \
+ cam->params.status.cmdError, cam->params.status.debugFlags, \
+ cam->params.status.vpStatus, cam->params.status.errorCode);
+
+/* ----------------------- v4l helpers -------------------------- */
+
+/* supported frame palettes and depths */
+static inline int valid_mode(u16 palette, u16 depth)
+{
+ if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
+ (palette == VIDEO_PALETTE_YUYV && depth == 16))
+ return 1;
+
+ if (colorspace_conv)
+ return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
+ (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
+ (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
+ (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
+ (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
+ (palette == VIDEO_PALETTE_UYVY && depth == 16);
+
+ return 0;
+}
+
+static int match_videosize( int width, int height )
+{
+ /* return the best match, where 'best' is as always
+ * the largest that is not bigger than what is requested. */
+ if (width>=352 && height>=288)
+ return VIDEOSIZE_352_288; /* CIF */
+
+ if (width>=320 && height>=240)
+ return VIDEOSIZE_320_240; /* SIF */
+
+ if (width>=288 && height>=216)
+ return VIDEOSIZE_288_216;
+
+ if (width>=256 && height>=192)
+ return VIDEOSIZE_256_192;
+
+ if (width>=224 && height>=168)
+ return VIDEOSIZE_224_168;
+
+ if (width>=192 && height>=144)
+ return VIDEOSIZE_192_144;
+
+ if (width>=176 && height>=144)
+ return VIDEOSIZE_176_144; /* QCIF */
+
+ if (width>=160 && height>=120)
+ return VIDEOSIZE_160_120; /* QSIF */
+
+ if (width>=128 && height>=96)
+ return VIDEOSIZE_128_96;
+
+ if (width>=88 && height>=72)
+ return VIDEOSIZE_88_72;
+
+ if (width>=64 && height>=48)
+ return VIDEOSIZE_64_48;
+
+ if (width>=48 && height>=48)
+ return VIDEOSIZE_48_48;
+
+ return -1;
+}
+
+/* these are the capture sizes we support */
+static void set_vw_size(struct cam_data *cam)
+{
+ /* the col/row/start/end values are the result of simple math */
+ /* study the SetROI-command in cpia developers guide p 2-22 */
+ /* streamStartLine is set to the recommended value in the cpia */
+ /* developers guide p 3-37 */
+ switch(cam->video_size) {
+ case VIDEOSIZE_CIF:
+ cam->vw.width = 352;
+ cam->vw.height = 288;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=0;
+ cam->params.roi.rowStart=0;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_SIF:
+ cam->vw.width = 320;
+ cam->vw.height = 240;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=2;
+ cam->params.roi.rowStart=6;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_288_216:
+ cam->vw.width = 288;
+ cam->vw.height = 216;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=4;
+ cam->params.roi.rowStart=9;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_256_192:
+ cam->vw.width = 256;
+ cam->vw.height = 192;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=6;
+ cam->params.roi.rowStart=12;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_224_168:
+ cam->vw.width = 224;
+ cam->vw.height = 168;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=8;
+ cam->params.roi.rowStart=15;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_192_144:
+ cam->vw.width = 192;
+ cam->vw.height = 144;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=10;
+ cam->params.roi.rowStart=18;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_QCIF:
+ cam->vw.width = 176;
+ cam->vw.height = 144;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=0;
+ cam->params.roi.rowStart=0;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_QSIF:
+ cam->vw.width = 160;
+ cam->vw.height = 120;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=1;
+ cam->params.roi.rowStart=3;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_128_96:
+ cam->vw.width = 128;
+ cam->vw.height = 96;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=3;
+ cam->params.roi.rowStart=6;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_88_72:
+ cam->vw.width = 88;
+ cam->vw.height = 72;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=5;
+ cam->params.roi.rowStart=9;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_64_48:
+ cam->vw.width = 64;
+ cam->vw.height = 48;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=7;
+ cam->params.roi.rowStart=12;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_48_48:
+ cam->vw.width = 48;
+ cam->vw.height = 48;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=8;
+ cam->params.roi.rowStart=6;
+ cam->params.streamStartLine = 60;
+ break;
+ default:
+ LOG("bad videosize value: %d\n", cam->video_size);
+ return;
+ }
+
+ if(cam->vc.width == 0)
+ cam->vc.width = cam->vw.width;
+ if(cam->vc.height == 0)
+ cam->vc.height = cam->vw.height;
+
+ cam->params.roi.colStart += cam->vc.x >> 3;
+ cam->params.roi.colEnd = cam->params.roi.colStart +
+ (cam->vc.width >> 3);
+ cam->params.roi.rowStart += cam->vc.y >> 2;
+ cam->params.roi.rowEnd = cam->params.roi.rowStart +
+ (cam->vc.height >> 2);
+
+ return;
+}
+
+static int allocate_frame_buf(struct cam_data *cam)
+{
+ int i;
+
+ cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
+ if (!cam->frame_buf)
+ return -ENOBUFS;
+
+ for (i = 0; i < FRAME_NUM; i++)
+ cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
+
+ return 0;
+}
+
+static int free_frame_buf(struct cam_data *cam)
+{
+ int i;
+
+ rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
+ cam->frame_buf = NULL;
+ for (i=0; i < FRAME_NUM; i++)
+ cam->frame[i].data = NULL;
+
+ return 0;
+}
+
+
+static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
+{
+ int i;
+
+ for (i=0; i < FRAME_NUM; i++)
+ frame[i].state = FRAME_UNUSED;
+ return;
+}
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+/* send an arbitrary command to the camera */
+static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
+{
+ int retval, datasize;
+ u8 cmd[8], data[8];
+
+ switch(command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ case CPIA_COMMAND_GetPnPID:
+ case CPIA_COMMAND_GetCameraStatus:
+ case CPIA_COMMAND_GetVPVersion:
+ datasize=8;
+ break;
+ case CPIA_COMMAND_GetColourParams:
+ case CPIA_COMMAND_GetColourBalance:
+ case CPIA_COMMAND_GetExposure:
+ mutex_lock(&cam->param_lock);
+ datasize=8;
+ break;
+ case CPIA_COMMAND_ReadMCPorts:
+ case CPIA_COMMAND_ReadVCRegs:
+ datasize = 4;
+ break;
+ default:
+ datasize=0;
+ break;
+ }
+
+ cmd[0] = command>>8;
+ cmd[1] = command&0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = datasize;
+ cmd[7] = 0;
+
+ retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+ if (retval) {
+ DBG("%x - failed, retval=%d\n", command, retval);
+ if (command == CPIA_COMMAND_GetColourParams ||
+ command == CPIA_COMMAND_GetColourBalance ||
+ command == CPIA_COMMAND_GetExposure)
+ mutex_unlock(&cam->param_lock);
+ } else {
+ switch(command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ cam->params.version.firmwareVersion = data[0];
+ cam->params.version.firmwareRevision = data[1];
+ cam->params.version.vcVersion = data[2];
+ cam->params.version.vcRevision = data[3];
+ break;
+ case CPIA_COMMAND_GetPnPID:
+ cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
+ cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
+ cam->params.pnpID.deviceRevision =
+ data[4]+(((u16)data[5])<<8);
+ break;
+ case CPIA_COMMAND_GetCameraStatus:
+ cam->params.status.systemState = data[0];
+ cam->params.status.grabState = data[1];
+ cam->params.status.streamState = data[2];
+ cam->params.status.fatalError = data[3];
+ cam->params.status.cmdError = data[4];
+ cam->params.status.debugFlags = data[5];
+ cam->params.status.vpStatus = data[6];
+ cam->params.status.errorCode = data[7];
+ break;
+ case CPIA_COMMAND_GetVPVersion:
+ cam->params.vpVersion.vpVersion = data[0];
+ cam->params.vpVersion.vpRevision = data[1];
+ cam->params.vpVersion.cameraHeadID =
+ data[2]+(((u16)data[3])<<8);
+ break;
+ case CPIA_COMMAND_GetColourParams:
+ cam->params.colourParams.brightness = data[0];
+ cam->params.colourParams.contrast = data[1];
+ cam->params.colourParams.saturation = data[2];
+ mutex_unlock(&cam->param_lock);
+ break;
+ case CPIA_COMMAND_GetColourBalance:
+ cam->params.colourBalance.redGain = data[0];
+ cam->params.colourBalance.greenGain = data[1];
+ cam->params.colourBalance.blueGain = data[2];
+ mutex_unlock(&cam->param_lock);
+ break;
+ case CPIA_COMMAND_GetExposure:
+ cam->params.exposure.gain = data[0];
+ cam->params.exposure.fineExp = data[1];
+ cam->params.exposure.coarseExpLo = data[2];
+ cam->params.exposure.coarseExpHi = data[3];
+ cam->params.exposure.redComp = data[4];
+ cam->params.exposure.green1Comp = data[5];
+ cam->params.exposure.green2Comp = data[6];
+ cam->params.exposure.blueComp = data[7];
+ mutex_unlock(&cam->param_lock);
+ break;
+
+ case CPIA_COMMAND_ReadMCPorts:
+ if (!cam->params.qx3.qx3_detected)
+ break;
+ /* test button press */
+ cam->params.qx3.button = ((data[1] & 0x02) == 0);
+ if (cam->params.qx3.button) {
+ /* button pressed - unlock the latch */
+ do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+ do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+ }
+
+ /* test whether microscope is cradled */
+ cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return retval;
+}
+
+/* send a command to the camera with an additional data transaction */
+static int do_command_extended(struct cam_data *cam, u16 command,
+ u8 a, u8 b, u8 c, u8 d,
+ u8 e, u8 f, u8 g, u8 h,
+ u8 i, u8 j, u8 k, u8 l)
+{
+ int retval;
+ u8 cmd[8], data[8];
+
+ cmd[0] = command>>8;
+ cmd[1] = command&0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = 8;
+ cmd[7] = 0;
+ data[0] = e;
+ data[1] = f;
+ data[2] = g;
+ data[3] = h;
+ data[4] = i;
+ data[5] = j;
+ data[6] = k;
+ data[7] = l;
+
+ retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+ if (retval)
+ DBG("%x - failed\n", command);
+
+ return retval;
+}
+
+/**********************************************************************
+ *
+ * Colorspace conversion
+ *
+ **********************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+ int linesize, int mmap_kludge)
+{
+ int y, u, v, r, g, b, y1;
+
+ /* Odd lines use the same u and v as the previous line.
+ * Because of compression, it is necessary to get this
+ * information from the decoded image. */
+ switch(out_fmt) {
+ case VIDEO_PALETTE_RGB555:
+ y = (*yuv++ - 16) * 76310;
+ y1 = (*yuv - 16) * 76310;
+ r = ((*(rgb+1-linesize)) & 0x7c) << 1;
+ g = ((*(rgb-linesize)) & 0xe0) >> 4 |
+ ((*(rgb+1-linesize)) & 0x03) << 6;
+ b = ((*(rgb-linesize)) & 0x1f) << 3;
+ u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+ v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+ r = 104635 * v;
+ g = -25690 * u - 53294 * v;
+ b = 132278 * u;
+ *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+ *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+ *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+ *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+ return 4;
+ case VIDEO_PALETTE_RGB565:
+ y = (*yuv++ - 16) * 76310;
+ y1 = (*yuv - 16) * 76310;
+ r = (*(rgb+1-linesize)) & 0xf8;
+ g = ((*(rgb-linesize)) & 0xe0) >> 3 |
+ ((*(rgb+1-linesize)) & 0x07) << 5;
+ b = ((*(rgb-linesize)) & 0x1f) << 3;
+ u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+ v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+ r = 104635 * v;
+ g = -25690 * u - 53294 * v;
+ b = 132278 * u;
+ *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+ *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+ *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+ *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+ return 4;
+ break;
+ case VIDEO_PALETTE_RGB24:
+ case VIDEO_PALETTE_RGB32:
+ y = (*yuv++ - 16) * 76310;
+ y1 = (*yuv - 16) * 76310;
+ if (mmap_kludge) {
+ r = *(rgb+2-linesize);
+ g = *(rgb+1-linesize);
+ b = *(rgb-linesize);
+ } else {
+ r = *(rgb-linesize);
+ g = *(rgb+1-linesize);
+ b = *(rgb+2-linesize);
+ }
+ u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+ v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+ r = 104635 * v;
+ g = -25690 * u + -53294 * v;
+ b = 132278 * u;
+ if (mmap_kludge) {
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(r+y);
+ if(out_fmt == VIDEO_PALETTE_RGB32)
+ rgb++;
+ *rgb++ = LIMIT(b+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(r+y1);
+ } else {
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(b+y);
+ if(out_fmt == VIDEO_PALETTE_RGB32)
+ rgb++;
+ *rgb++ = LIMIT(r+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(b+y1);
+ }
+ if(out_fmt == VIDEO_PALETTE_RGB32)
+ return 8;
+ return 6;
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ y = *yuv++;
+ u = *(rgb+1-linesize);
+ y1 = *yuv;
+ v = *(rgb+3-linesize);
+ *rgb++ = y;
+ *rgb++ = u;
+ *rgb++ = y1;
+ *rgb = v;
+ return 4;
+ case VIDEO_PALETTE_UYVY:
+ u = *(rgb-linesize);
+ y = *yuv++;
+ v = *(rgb+2-linesize);
+ y1 = *yuv;
+ *rgb++ = u;
+ *rgb++ = y;
+ *rgb++ = v;
+ *rgb = y1;
+ return 4;
+ case VIDEO_PALETTE_GREY:
+ *rgb++ = *yuv++;
+ *rgb = *yuv;
+ return 2;
+ default:
+ DBG("Empty: %d\n", out_fmt);
+ return 0;
+ }
+}
+
+
+static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+ int in_uyvy, int mmap_kludge)
+{
+ int y, u, v, r, g, b, y1;
+
+ switch(out_fmt) {
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_RGB24:
+ case VIDEO_PALETTE_RGB32:
+ if (in_uyvy) {
+ u = *yuv++ - 128;
+ y = (*yuv++ - 16) * 76310;
+ v = *yuv++ - 128;
+ y1 = (*yuv - 16) * 76310;
+ } else {
+ y = (*yuv++ - 16) * 76310;
+ u = *yuv++ - 128;
+ y1 = (*yuv++ - 16) * 76310;
+ v = *yuv - 128;
+ }
+ r = 104635 * v;
+ g = -25690 * u + -53294 * v;
+ b = 132278 * u;
+ break;
+ default:
+ y = *yuv++;
+ u = *yuv++;
+ y1 = *yuv++;
+ v = *yuv;
+ /* Just to avoid compiler warnings */
+ r = 0;
+ g = 0;
+ b = 0;
+ break;
+ }
+ switch(out_fmt) {
+ case VIDEO_PALETTE_RGB555:
+ *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+ *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+ *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+ *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+ return 4;
+ case VIDEO_PALETTE_RGB565:
+ *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+ *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+ *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+ *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+ return 4;
+ case VIDEO_PALETTE_RGB24:
+ if (mmap_kludge) {
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(b+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(r+y1);
+ } else {
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(r+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(b+y1);
+ }
+ return 6;
+ case VIDEO_PALETTE_RGB32:
+ if (mmap_kludge) {
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(r+y);
+ rgb++;
+ *rgb++ = LIMIT(b+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(r+y1);
+ } else {
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(b+y);
+ rgb++;
+ *rgb++ = LIMIT(r+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(b+y1);
+ }
+ return 8;
+ case VIDEO_PALETTE_GREY:
+ *rgb++ = y;
+ *rgb = y1;
+ return 2;
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ *rgb++ = y;
+ *rgb++ = u;
+ *rgb++ = y1;
+ *rgb = v;
+ return 4;
+ case VIDEO_PALETTE_UYVY:
+ *rgb++ = u;
+ *rgb++ = y;
+ *rgb++ = v;
+ *rgb = y1;
+ return 4;
+ default:
+ DBG("Empty: %d\n", out_fmt);
+ return 0;
+ }
+}
+
+static int skipcount(int count, int fmt)
+{
+ switch(fmt) {
+ case VIDEO_PALETTE_GREY:
+ return count;
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ case VIDEO_PALETTE_UYVY:
+ return 2*count;
+ case VIDEO_PALETTE_RGB24:
+ return 3*count;
+ case VIDEO_PALETTE_RGB32:
+ return 4*count;
+ default:
+ return 0;
+ }
+}
+
+static int parse_picture(struct cam_data *cam, int size)
+{
+ u8 *obuf, *ibuf, *end_obuf;
+ int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
+ int rows, cols, linesize, subsample_422;
+
+ /* make sure params don't change while we are decoding */
+ mutex_lock(&cam->param_lock);
+
+ obuf = cam->decompressed_frame.data;
+ end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
+ ibuf = cam->raw_image;
+ origsize = size;
+ out_fmt = cam->vp.palette;
+
+ if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
+ LOG("header not found\n");
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+
+ if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
+ LOG("wrong video size\n");
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+
+ if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
+ LOG("illegal subtype %d\n",ibuf[17]);
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+ subsample_422 = ibuf[17] == SUBSAMPLE_422;
+
+ if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
+ LOG("illegal yuvorder %d\n",ibuf[18]);
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+ in_uyvy = ibuf[18] == YUVORDER_UYVY;
+
+ if ((ibuf[24] != cam->params.roi.colStart) ||
+ (ibuf[25] != cam->params.roi.colEnd) ||
+ (ibuf[26] != cam->params.roi.rowStart) ||
+ (ibuf[27] != cam->params.roi.rowEnd)) {
+ LOG("ROI mismatch\n");
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+ cols = 8*(ibuf[25] - ibuf[24]);
+ rows = 4*(ibuf[27] - ibuf[26]);
+
+
+ if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
+ LOG("illegal compression %d\n",ibuf[28]);
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+ compressed = (ibuf[28] == COMPRESSED);
+
+ if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
+ LOG("illegal decimation %d\n",ibuf[29]);
+ mutex_unlock(&cam->param_lock);
+ return -1;
+ }
+ decimation = (ibuf[29] == DECIMATION_ENAB);
+
+ cam->params.yuvThreshold.yThreshold = ibuf[30];
+ cam->params.yuvThreshold.uvThreshold = ibuf[31];
+ cam->params.status.systemState = ibuf[32];
+ cam->params.status.grabState = ibuf[33];
+ cam->params.status.streamState = ibuf[34];
+ cam->params.status.fatalError = ibuf[35];
+ cam->params.status.cmdError = ibuf[36];
+ cam->params.status.debugFlags = ibuf[37];
+ cam->params.status.vpStatus = ibuf[38];
+ cam->params.status.errorCode = ibuf[39];
+ cam->fps = ibuf[41];
+ mutex_unlock(&cam->param_lock);
+
+ linesize = skipcount(cols, out_fmt);
+ ibuf += FRAME_HEADER_SIZE;
+ size -= FRAME_HEADER_SIZE;
+ ll = ibuf[0] | (ibuf[1] << 8);
+ ibuf += 2;
+ even_line = 1;
+
+ while (size > 0) {
+ size -= (ll+2);
+ if (size < 0) {
+ LOG("Insufficient data in buffer\n");
+ return -1;
+ }
+
+ while (ll > 1) {
+ if (!compressed || (compressed && !(*ibuf & 1))) {
+ if(subsample_422 || even_line) {
+ obuf += yuvconvert(ibuf, obuf, out_fmt,
+ in_uyvy, cam->mmap_kludge);
+ ibuf += 4;
+ ll -= 4;
+ } else {
+ /* SUBSAMPLE_420 on an odd line */
+ obuf += convert420(ibuf, obuf,
+ out_fmt, linesize,
+ cam->mmap_kludge);
+ ibuf += 2;
+ ll -= 2;
+ }
+ } else {
+ /*skip compressed interval from previous frame*/
+ obuf += skipcount(*ibuf >> 1, out_fmt);
+ if (obuf > end_obuf) {
+ LOG("Insufficient buffer size\n");
+ return -1;
+ }
+ ++ibuf;
+ ll--;
+ }
+ }
+ if (ll == 1) {
+ if (*ibuf != EOL) {
+ DBG("EOL not found giving up after %d/%d"
+ " bytes\n", origsize-size, origsize);
+ return -1;
+ }
+
+ ++ibuf; /* skip over EOL */
+
+ if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
+ (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
+ size -= 4;
+ break;
+ }
+
+ if(decimation) {
+ /* skip the odd lines for now */
+ obuf += linesize;
+ }
+
+ if (size > 1) {
+ ll = ibuf[0] | (ibuf[1] << 8);
+ ibuf += 2; /* skip over line length */
+ }
+ if(!decimation)
+ even_line = !even_line;
+ } else {
+ LOG("line length was not 1 but %d after %d/%d bytes\n",
+ ll, origsize-size, origsize);
+ return -1;
+ }
+ }
+
+ if(decimation) {
+ /* interpolate odd rows */
+ int i, j;
+ u8 *prev, *next;
+ prev = cam->decompressed_frame.data;
+ obuf = prev+linesize;
+ next = obuf+linesize;
+ for(i=1; i<rows-1; i+=2) {
+ for(j=0; j<linesize; ++j) {
+ *obuf++ = ((int)*prev++ + *next++) / 2;
+ }
+ prev += linesize;
+ obuf += linesize;
+ next += linesize;
+ }
+ /* last row is odd, just copy previous row */
+ memcpy(obuf, prev, linesize);
+ }
+
+ cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
+
+ return cam->decompressed_frame.count;
+}
+
+/* InitStreamCap wrapper to select correct start line */
+static inline int init_stream_cap(struct cam_data *cam)
+{
+ return do_command(cam, CPIA_COMMAND_InitStreamCap,
+ 0, cam->params.streamStartLine, 0, 0);
+}
+
+
+/* find_over_exposure
+ * Finds a suitable value of OverExposure for use with SetFlickerCtrl
+ * Some calculation is required because this value changes with the brightness
+ * set with SetColourParameters
+ *
+ * Parameters: Brightness - last brightness value set with SetColourParameters
+ *
+ * Returns: OverExposure value to use with SetFlickerCtrl
+ */
+#define FLICKER_MAX_EXPOSURE 250
+#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
+#define FLICKER_BRIGHTNESS_CONSTANT 59
+static int find_over_exposure(int brightness)
+{
+ int MaxAllowableOverExposure, OverExposure;
+
+ MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
+ FLICKER_BRIGHTNESS_CONSTANT;
+
+ if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
+ OverExposure = MaxAllowableOverExposure;
+ } else {
+ OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
+ }
+
+ return OverExposure;
+}
+#undef FLICKER_MAX_EXPOSURE
+#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
+#undef FLICKER_BRIGHTNESS_CONSTANT
+
+/* update various camera modes and settings */
+static void dispatch_commands(struct cam_data *cam)
+{
+ mutex_lock(&cam->param_lock);
+ if (cam->cmd_queue==COMMAND_NONE) {
+ mutex_unlock(&cam->param_lock);
+ return;
+ }
+ DEB_BYTE(cam->cmd_queue);
+ DEB_BYTE(cam->cmd_queue>>8);
+ if (cam->cmd_queue & COMMAND_SETFORMAT) {
+ do_command(cam, CPIA_COMMAND_SetFormat,
+ cam->params.format.videoSize,
+ cam->params.format.subSample,
+ cam->params.format.yuvOrder, 0);
+ do_command(cam, CPIA_COMMAND_SetROI,
+ cam->params.roi.colStart, cam->params.roi.colEnd,
+ cam->params.roi.rowStart, cam->params.roi.rowEnd);
+ cam->first_frame = 1;
+ }
+
+ if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
+ do_command(cam, CPIA_COMMAND_SetColourParams,
+ cam->params.colourParams.brightness,
+ cam->params.colourParams.contrast,
+ cam->params.colourParams.saturation, 0);
+
+ if (cam->cmd_queue & COMMAND_SETAPCOR)
+ do_command(cam, CPIA_COMMAND_SetApcor,
+ cam->params.apcor.gain1,
+ cam->params.apcor.gain2,
+ cam->params.apcor.gain4,
+ cam->params.apcor.gain8);
+
+ if (cam->cmd_queue & COMMAND_SETVLOFFSET)
+ do_command(cam, CPIA_COMMAND_SetVLOffset,
+ cam->params.vlOffset.gain1,
+ cam->params.vlOffset.gain2,
+ cam->params.vlOffset.gain4,
+ cam->params.vlOffset.gain8);
+
+ if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
+ do_command_extended(cam, CPIA_COMMAND_SetExposure,
+ cam->params.exposure.gainMode,
+ 1,
+ cam->params.exposure.compMode,
+ cam->params.exposure.centreWeight,
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+ if(cam->params.exposure.expMode != 1) {
+ do_command_extended(cam, CPIA_COMMAND_SetExposure,
+ 0,
+ cam->params.exposure.expMode,
+ 0, 0,
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ 0, 0, 0, 0);
+ }
+ }
+
+ if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
+ if (cam->params.colourBalance.balanceMode == 1) {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 1,
+ cam->params.colourBalance.redGain,
+ cam->params.colourBalance.greenGain,
+ cam->params.colourBalance.blueGain);
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+ if (cam->params.colourBalance.balanceMode == 2) {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 2, 0, 0, 0);
+ }
+ if (cam->params.colourBalance.balanceMode == 3) {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+ }
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
+ do_command(cam, CPIA_COMMAND_SetCompressionTarget,
+ cam->params.compressionTarget.frTargeting,
+ cam->params.compressionTarget.targetFR,
+ cam->params.compressionTarget.targetQ, 0);
+
+ if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
+ do_command(cam, CPIA_COMMAND_SetYUVThresh,
+ cam->params.yuvThreshold.yThreshold,
+ cam->params.yuvThreshold.uvThreshold, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
+ do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
+ 0, 0, 0, 0,
+ cam->params.compressionParams.hysteresis,
+ cam->params.compressionParams.threshMax,
+ cam->params.compressionParams.smallStep,
+ cam->params.compressionParams.largeStep,
+ cam->params.compressionParams.decimationHysteresis,
+ cam->params.compressionParams.frDiffStepThresh,
+ cam->params.compressionParams.qDiffStepThresh,
+ cam->params.compressionParams.decimationThreshMod);
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
+ do_command(cam, CPIA_COMMAND_SetCompression,
+ cam->params.compression.mode,
+ cam->params.compression.decimation, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETSENSORFPS)
+ do_command(cam, CPIA_COMMAND_SetSensorFPS,
+ cam->params.sensorFps.divisor,
+ cam->params.sensorFps.baserate, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
+ do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
+ cam->params.flickerControl.flickerMode,
+ cam->params.flickerControl.coarseJump,
+ abs(cam->params.flickerControl.allowableOverExposure),
+ 0);
+
+ if (cam->cmd_queue & COMMAND_SETECPTIMING)
+ do_command(cam, CPIA_COMMAND_SetECPTiming,
+ cam->params.ecpTiming, 0, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_PAUSE)
+ do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_RESUME)
+ init_stream_cap(cam);
+
+ if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
+ {
+ int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+ int p2 = (cam->params.qx3.toplight == 0) << 3;
+ do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
+ do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+ }
+
+ cam->cmd_queue = COMMAND_NONE;
+ mutex_unlock(&cam->param_lock);
+ return;
+}
+
+
+
+static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
+ int on)
+{
+ /* Everything in here is from the Windows driver */
+#define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
+ params->version.firmwareRevision == (y))
+/* define for compgain calculation */
+#if 0
+#define COMPGAIN(base, curexp, newexp) \
+ (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+ (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
+#else
+ /* equivalent functions without floating point math */
+#define COMPGAIN(base, curexp, newexp) \
+ (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+ (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
+#endif
+
+
+ int currentexp = params->exposure.coarseExpLo +
+ params->exposure.coarseExpHi*256;
+ int startexp;
+ if (on) {
+ int cj = params->flickerControl.coarseJump;
+ params->flickerControl.flickerMode = 1;
+ params->flickerControl.disabled = 0;
+ if(params->exposure.expMode != 2)
+ *command_flags |= COMMAND_SETEXPOSURE;
+ params->exposure.expMode = 2;
+ currentexp = currentexp << params->exposure.gain;
+ params->exposure.gain = 0;
+ /* round down current exposure to nearest value */
+ startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
+ if(startexp < 1)
+ startexp = 1;
+ startexp = (startexp * cj) - 1;
+ if(FIRMWARE_VERSION(1,2))
+ while(startexp > MAX_EXP_102)
+ startexp -= cj;
+ else
+ while(startexp > MAX_EXP)
+ startexp -= cj;
+ params->exposure.coarseExpLo = startexp & 0xff;
+ params->exposure.coarseExpHi = startexp >> 8;
+ if (currentexp > startexp) {
+ if (currentexp > (2 * startexp))
+ currentexp = 2 * startexp;
+ params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
+ params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
+ params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
+ params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
+ } else {
+ params->exposure.redComp = COMP_RED;
+ params->exposure.green1Comp = COMP_GREEN1;
+ params->exposure.green2Comp = COMP_GREEN2;
+ params->exposure.blueComp = COMP_BLUE;
+ }
+ if(FIRMWARE_VERSION(1,2))
+ params->exposure.compMode = 0;
+ else
+ params->exposure.compMode = 1;
+
+ params->apcor.gain1 = 0x18;
+ params->apcor.gain2 = 0x18;
+ params->apcor.gain4 = 0x16;
+ params->apcor.gain8 = 0x14;
+ *command_flags |= COMMAND_SETAPCOR;
+ } else {
+ params->flickerControl.flickerMode = 0;
+ params->flickerControl.disabled = 1;
+ /* Coarse = average of equivalent coarse for each comp channel */
+ startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
+ startexp = startexp >> 2;
+ while(startexp > MAX_EXP &&
+ params->exposure.gain < params->exposure.gainMode-1) {
+ startexp = startexp >> 1;
+ ++params->exposure.gain;
+ }
+ if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
+ startexp = MAX_EXP_102;
+ if(startexp > MAX_EXP)
+ startexp = MAX_EXP;
+ params->exposure.coarseExpLo = startexp&0xff;
+ params->exposure.coarseExpHi = startexp >> 8;
+ params->exposure.redComp = COMP_RED;
+ params->exposure.green1Comp = COMP_GREEN1;
+ params->exposure.green2Comp = COMP_GREEN2;
+ params->exposure.blueComp = COMP_BLUE;
+ params->exposure.compMode = 1;
+ *command_flags |= COMMAND_SETEXPOSURE;
+ params->apcor.gain1 = 0x18;
+ params->apcor.gain2 = 0x16;
+ params->apcor.gain4 = 0x24;
+ params->apcor.gain8 = 0x34;
+ *command_flags |= COMMAND_SETAPCOR;
+ }
+ params->vlOffset.gain1 = 20;
+ params->vlOffset.gain2 = 24;
+ params->vlOffset.gain4 = 26;
+ params->vlOffset.gain8 = 26;
+ *command_flags |= COMMAND_SETVLOFFSET;
+#undef FIRMWARE_VERSION
+#undef EXP_FROM_COMP
+#undef COMPGAIN
+}
+
+#define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
+ cam->params.version.firmwareRevision == (y))
+/* monitor the exposure and adjust the sensor frame rate if needed */
+static void monitor_exposure(struct cam_data *cam)
+{
+ u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
+ int retval, light_exp, dark_exp, very_dark_exp;
+ int old_exposure, new_exposure, framerate;
+
+ /* get necessary stats and register settings from camera */
+ /* do_command can't handle this, so do it ourselves */
+ cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
+ cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
+ cmd[2] = 30;
+ cmd[3] = 4;
+ cmd[4] = 9;
+ cmd[5] = 8;
+ cmd[6] = 8;
+ cmd[7] = 0;
+ retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+ if (retval) {
+ LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
+ retval);
+ return;
+ }
+ exp_acc = data[0];
+ bcomp = data[1];
+ gain = data[2];
+ coarseL = data[3];
+
+ mutex_lock(&cam->param_lock);
+ light_exp = cam->params.colourParams.brightness +
+ TC - 50 + EXP_ACC_LIGHT;
+ if(light_exp > 255)
+ light_exp = 255;
+ dark_exp = cam->params.colourParams.brightness +
+ TC - 50 - EXP_ACC_DARK;
+ if(dark_exp < 0)
+ dark_exp = 0;
+ very_dark_exp = dark_exp/2;
+
+ old_exposure = cam->params.exposure.coarseExpHi * 256 +
+ cam->params.exposure.coarseExpLo;
+
+ if(!cam->params.flickerControl.disabled) {
+ /* Flicker control on */
+ int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
+ bcomp += 128; /* decode */
+ if(bcomp >= max_comp && exp_acc < dark_exp) {
+ /* dark */
+ if(exp_acc < very_dark_exp) {
+ /* very dark */
+ if(cam->exposure_status == EXPOSURE_VERY_DARK)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_VERY_DARK;
+ cam->exposure_count = 1;
+ }
+ } else {
+ /* just dark */
+ if(cam->exposure_status == EXPOSURE_DARK)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_DARK;
+ cam->exposure_count = 1;
+ }
+ }
+ } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
+ /* light */
+ if(old_exposure <= VERY_LOW_EXP) {
+ /* very light */
+ if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_VERY_LIGHT;
+ cam->exposure_count = 1;
+ }
+ } else {
+ /* just light */
+ if(cam->exposure_status == EXPOSURE_LIGHT)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_LIGHT;
+ cam->exposure_count = 1;
+ }
+ }
+ } else {
+ /* not dark or light */
+ cam->exposure_status = EXPOSURE_NORMAL;
+ }
+ } else {
+ /* Flicker control off */
+ if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
+ /* dark */
+ if(exp_acc < very_dark_exp) {
+ /* very dark */
+ if(cam->exposure_status == EXPOSURE_VERY_DARK)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_VERY_DARK;
+ cam->exposure_count = 1;
+ }
+ } else {
+ /* just dark */
+ if(cam->exposure_status == EXPOSURE_DARK)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_DARK;
+ cam->exposure_count = 1;
+ }
+ }
+ } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
+ /* light */
+ if(old_exposure <= VERY_LOW_EXP) {
+ /* very light */
+ if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_VERY_LIGHT;
+ cam->exposure_count = 1;
+ }
+ } else {
+ /* just light */
+ if(cam->exposure_status == EXPOSURE_LIGHT)
+ ++cam->exposure_count;
+ else {
+ cam->exposure_status = EXPOSURE_LIGHT;
+ cam->exposure_count = 1;
+ }
+ }
+ } else {
+ /* not dark or light */
+ cam->exposure_status = EXPOSURE_NORMAL;
+ }
+ }
+
+ framerate = cam->fps;
+ if(framerate > 30 || framerate < 1)
+ framerate = 1;
+
+ if(!cam->params.flickerControl.disabled) {
+ /* Flicker control on */
+ if((cam->exposure_status == EXPOSURE_VERY_DARK ||
+ cam->exposure_status == EXPOSURE_DARK) &&
+ cam->exposure_count >= DARK_TIME*framerate &&
+ cam->params.sensorFps.divisor < 3) {
+
+ /* dark for too long */
+ ++cam->params.sensorFps.divisor;
+ cam->cmd_queue |= COMMAND_SETSENSORFPS;
+
+ cam->params.flickerControl.coarseJump =
+ flicker_jumps[cam->mainsFreq]
+ [cam->params.sensorFps.baserate]
+ [cam->params.sensorFps.divisor];
+ cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
+
+ new_exposure = cam->params.flickerControl.coarseJump-1;
+ while(new_exposure < old_exposure/2)
+ new_exposure += cam->params.flickerControl.coarseJump;
+ cam->params.exposure.coarseExpLo = new_exposure & 0xff;
+ cam->params.exposure.coarseExpHi = new_exposure >> 8;
+ cam->cmd_queue |= COMMAND_SETEXPOSURE;
+ cam->exposure_status = EXPOSURE_NORMAL;
+ LOG("Automatically decreasing sensor_fps\n");
+
+ } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
+ cam->exposure_status == EXPOSURE_LIGHT) &&
+ cam->exposure_count >= LIGHT_TIME*framerate &&
+ cam->params.sensorFps.divisor > 0) {
+
+ /* light for too long */
+ int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
+
+ --cam->params.sensorFps.divisor;
+ cam->cmd_queue |= COMMAND_SETSENSORFPS;
+
+ cam->params.flickerControl.coarseJump =
+ flicker_jumps[cam->mainsFreq]
+ [cam->params.sensorFps.baserate]
+ [cam->params.sensorFps.divisor];
+ cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
+
+ new_exposure = cam->params.flickerControl.coarseJump-1;
+ while(new_exposure < 2*old_exposure &&
+ new_exposure+
+ cam->params.flickerControl.coarseJump < max_exp)
+ new_exposure += cam->params.flickerControl.coarseJump;
+ cam->params.exposure.coarseExpLo = new_exposure & 0xff;
+ cam->params.exposure.coarseExpHi = new_exposure >> 8;
+ cam->cmd_queue |= COMMAND_SETEXPOSURE;
+ cam->exposure_status = EXPOSURE_NORMAL;
+ LOG("Automatically increasing sensor_fps\n");
+ }
+ } else {
+ /* Flicker control off */
+ if((cam->exposure_status == EXPOSURE_VERY_DARK ||
+ cam->exposure_status == EXPOSURE_DARK) &&
+ cam->exposure_count >= DARK_TIME*framerate &&
+ cam->params.sensorFps.divisor < 3) {
+
+ /* dark for too long */
+ ++cam->params.sensorFps.divisor;
+ cam->cmd_queue |= COMMAND_SETSENSORFPS;
+
+ if(cam->params.exposure.gain > 0) {
+ --cam->params.exposure.gain;
+ cam->cmd_queue |= COMMAND_SETEXPOSURE;
+ }
+ cam->exposure_status = EXPOSURE_NORMAL;
+ LOG("Automatically decreasing sensor_fps\n");
+
+ } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
+ cam->exposure_status == EXPOSURE_LIGHT) &&
+ cam->exposure_count >= LIGHT_TIME*framerate &&
+ cam->params.sensorFps.divisor > 0) {
+
+ /* light for too long */
+ --cam->params.sensorFps.divisor;
+ cam->cmd_queue |= COMMAND_SETSENSORFPS;
+
+ if(cam->params.exposure.gain <
+ cam->params.exposure.gainMode-1) {
+ ++cam->params.exposure.gain;
+ cam->cmd_queue |= COMMAND_SETEXPOSURE;
+ }
+ cam->exposure_status = EXPOSURE_NORMAL;
+ LOG("Automatically increasing sensor_fps\n");
+ }
+ }
+ mutex_unlock(&cam->param_lock);
+}
+
+/*-----------------------------------------------------------------*/
+/* if flicker is switched off, this function switches it back on.It checks,
+ however, that conditions are suitable before restarting it.
+ This should only be called for firmware version 1.2.
+
+ It also adjust the colour balance when an exposure step is detected - as
+ long as flicker is running
+*/
+static void restart_flicker(struct cam_data *cam)
+{
+ int cam_exposure, old_exp;
+ if(!FIRMWARE_VERSION(1,2))
+ return;
+ mutex_lock(&cam->param_lock);
+ if(cam->params.flickerControl.flickerMode == 0 ||
+ cam->raw_image[39] == 0) {
+ mutex_unlock(&cam->param_lock);
+ return;
+ }
+ cam_exposure = cam->raw_image[39]*2;
+ old_exp = cam->params.exposure.coarseExpLo +
+ cam->params.exposure.coarseExpHi*256;
+ /*
+ see how far away camera exposure is from a valid
+ flicker exposure value
+ */
+ cam_exposure %= cam->params.flickerControl.coarseJump;
+ if(!cam->params.flickerControl.disabled &&
+ cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
+ /* Flicker control auto-disabled */
+ cam->params.flickerControl.disabled = 1;
+ }
+
+ if(cam->params.flickerControl.disabled &&
+ cam->params.flickerControl.flickerMode &&
+ old_exp > cam->params.flickerControl.coarseJump +
+ ROUND_UP_EXP_FOR_FLICKER) {
+ /* exposure is now high enough to switch
+ flicker control back on */
+ set_flicker(&cam->params, &cam->cmd_queue, 1);
+ if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
+ cam->params.exposure.expMode == 2)
+ cam->exposure_status = EXPOSURE_NORMAL;
+
+ }
+ mutex_unlock(&cam->param_lock);
+}
+#undef FIRMWARE_VERSION
+
+static int clear_stall(struct cam_data *cam)
+{
+ /* FIXME: Does this actually work? */
+ LOG("Clearing stall\n");
+
+ cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
+ do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+ return cam->params.status.streamState != STREAM_PAUSED;
+}
+
+/* kernel thread function to read image from camera */
+static int fetch_frame(void *data)
+{
+ int image_size, retry;
+ struct cam_data *cam = (struct cam_data *)data;
+ unsigned long oldjif, rate, diff;
+
+ /* Allow up to two bad images in a row to be read and
+ * ignored before an error is reported */
+ for (retry = 0; retry < 3; ++retry) {
+ if (retry)
+ DBG("retry=%d\n", retry);
+
+ if (!cam->ops)
+ continue;
+
+ /* load first frame always uncompressed */
+ if (cam->first_frame &&
+ cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
+ do_command(cam, CPIA_COMMAND_SetCompression,
+ CPIA_COMPRESSION_NONE,
+ NO_DECIMATION, 0, 0);
+ /* Trial & error - Discarding a frame prevents the
+ first frame from having an error in the data. */
+ do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
+ }
+
+ /* init camera upload */
+ if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
+ cam->params.streamStartLine, 0, 0))
+ continue;
+
+ if (cam->ops->wait_for_stream_ready) {
+ /* loop until image ready */
+ int count = 0;
+ do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+ while (cam->params.status.streamState != STREAM_READY) {
+ if(++count > READY_TIMEOUT)
+ break;
+ if(cam->params.status.streamState ==
+ STREAM_PAUSED) {
+ /* Bad news */
+ if(!clear_stall(cam))
+ return -EIO;
+ }
+
+ cond_resched();
+
+ /* sleep for 10 ms, hopefully ;) */
+ msleep_interruptible(10);
+ if (signal_pending(current))
+ return -EINTR;
+
+ do_command(cam, CPIA_COMMAND_GetCameraStatus,
+ 0, 0, 0, 0);
+ }
+ if(cam->params.status.streamState != STREAM_READY) {
+ continue;
+ }
+ }
+
+ cond_resched();
+
+ /* grab image from camera */
+ oldjif = jiffies;
+ image_size = cam->ops->streamRead(cam->lowlevel_data,
+ cam->raw_image, 0);
+ if (image_size <= 0) {
+ DBG("streamRead failed: %d\n", image_size);
+ continue;
+ }
+
+ rate = image_size * HZ / 1024;
+ diff = jiffies-oldjif;
+ cam->transfer_rate = diff==0 ? rate : rate/diff;
+ /* diff==0 ? unlikely but possible */
+
+ /* Switch flicker control back on if it got turned off */
+ restart_flicker(cam);
+
+ /* If AEC is enabled, monitor the exposure and
+ adjust the sensor frame rate if needed */
+ if(cam->params.exposure.expMode == 2)
+ monitor_exposure(cam);
+
+ /* camera idle now so dispatch queued commands */
+ dispatch_commands(cam);
+
+ /* Update our knowledge of the camera state */
+ do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+ do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
+
+ /* decompress and convert image to by copying it from
+ * raw_image to decompressed_frame
+ */
+
+ cond_resched();
+
+ cam->image_size = parse_picture(cam, image_size);
+ if (cam->image_size <= 0) {
+ DBG("parse_picture failed %d\n", cam->image_size);
+ if(cam->params.compression.mode !=
+ CPIA_COMPRESSION_NONE) {
+ /* Compression may not work right if we
+ had a bad frame, get the next one
+ uncompressed. */
+ cam->first_frame = 1;
+ do_command(cam, CPIA_COMMAND_SetGrabMode,
+ CPIA_GRAB_SINGLE, 0, 0, 0);
+ /* FIXME: Trial & error - need up to 70ms for
+ the grab mode change to complete ? */
+ msleep_interruptible(70);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ } else
+ break;
+ }
+
+ if (retry < 3) {
+ /* FIXME: this only works for double buffering */
+ if (cam->frame[cam->curframe].state == FRAME_READY) {
+ memcpy(cam->frame[cam->curframe].data,
+ cam->decompressed_frame.data,
+ cam->decompressed_frame.count);
+ cam->frame[cam->curframe].state = FRAME_DONE;
+ } else
+ cam->decompressed_frame.state = FRAME_DONE;
+
+ if (cam->first_frame) {
+ cam->first_frame = 0;
+ do_command(cam, CPIA_COMMAND_SetCompression,
+ cam->params.compression.mode,
+ cam->params.compression.decimation, 0, 0);
+
+ /* Switch from single-grab to continuous grab */
+ do_command(cam, CPIA_COMMAND_SetGrabMode,
+ CPIA_GRAB_CONTINUOUS, 0, 0, 0);
+ }
+ return 0;
+ }
+ return -EIO;
+}
+
+static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
+{
+ if (!cam->frame_buf) {
+ /* we do lazy allocation */
+ int err;
+ if ((err = allocate_frame_buf(cam)))
+ return err;
+ }
+
+ cam->curframe = vm->frame;
+ cam->frame[cam->curframe].state = FRAME_READY;
+ return fetch_frame(cam);
+}
+
+static int goto_high_power(struct cam_data *cam)
+{
+ if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
+ return -EIO;
+ msleep_interruptible(40); /* windows driver does it too */
+ if(signal_pending(current))
+ return -EINTR;
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -EIO;
+ if (cam->params.status.systemState == HI_POWER_STATE) {
+ DBG("camera now in HIGH power state\n");
+ return 0;
+ }
+ printstatus(cam);
+ return -EIO;
+}
+
+static int goto_low_power(struct cam_data *cam)
+{
+ if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
+ return -1;
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -1;
+ if (cam->params.status.systemState == LO_POWER_STATE) {
+ DBG("camera now in LOW power state\n");
+ return 0;
+ }
+ printstatus(cam);
+ return -1;
+}
+
+static void save_camera_state(struct cam_data *cam)
+{
+ if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
+ do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
+ do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+ DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+ DBG("%d/%d/%d\n",
+ cam->params.colourBalance.redGain,
+ cam->params.colourBalance.greenGain,
+ cam->params.colourBalance.blueGain);
+}
+
+static int set_camera_state(struct cam_data *cam)
+{
+ cam->cmd_queue = COMMAND_SETCOMPRESSION |
+ COMMAND_SETCOMPRESSIONTARGET |
+ COMMAND_SETCOLOURPARAMS |
+ COMMAND_SETFORMAT |
+ COMMAND_SETYUVTHRESH |
+ COMMAND_SETECPTIMING |
+ COMMAND_SETCOMPRESSIONPARAMS |
+ COMMAND_SETEXPOSURE |
+ COMMAND_SETCOLOURBALANCE |
+ COMMAND_SETSENSORFPS |
+ COMMAND_SETAPCOR |
+ COMMAND_SETFLICKERCTRL |
+ COMMAND_SETVLOFFSET;
+
+ do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
+ dispatch_commands(cam);
+
+ /* Wait 6 frames for the sensor to get all settings and
+ AEC/ACB to settle */
+ msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
+ (1 << cam->params.sensorFps.divisor) + 10);
+
+ if(signal_pending(current))
+ return -EINTR;
+
+ save_camera_state(cam);
+
+ return 0;
+}
+
+static void get_version_information(struct cam_data *cam)
+{
+ /* GetCPIAVersion */
+ do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+
+ /* GetPnPID */
+ do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+/* initialize camera */
+static int reset_camera(struct cam_data *cam)
+{
+ int err;
+ /* Start the camera in low power mode */
+ if (goto_low_power(cam)) {
+ if (cam->params.status.systemState != WARM_BOOT_STATE)
+ return -ENODEV;
+
+ /* FIXME: this is just dirty trial and error */
+ err = goto_high_power(cam);
+ if(err)
+ return err;
+ do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
+ if (goto_low_power(cam))
+ return -ENODEV;
+ }
+
+ /* procedure described in developer's guide p3-28 */
+
+ /* Check the firmware version. */
+ cam->params.version.firmwareVersion = 0;
+ get_version_information(cam);
+ if (cam->params.version.firmwareVersion != 1)
+ return -ENODEV;
+
+ /* A bug in firmware 1-02 limits gainMode to 2 */
+ if(cam->params.version.firmwareRevision <= 2 &&
+ cam->params.exposure.gainMode > 2) {
+ cam->params.exposure.gainMode = 2;
+ }
+
+ /* set QX3 detected flag */
+ cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+ cam->params.pnpID.product == 0x0001);
+
+ /* The fatal error checking should be done after
+ * the camera powers up (developer's guide p 3-38) */
+
+ /* Set streamState before transition to high power to avoid bug
+ * in firmware 1-02 */
+ do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
+ STREAM_NOT_READY, 0);
+
+ /* GotoHiPower */
+ err = goto_high_power(cam);
+ if (err)
+ return err;
+
+ /* Check the camera status */
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -EIO;
+
+ if (cam->params.status.fatalError) {
+ DBG("fatal_error: %#04x\n",
+ cam->params.status.fatalError);
+ DBG("vp_status: %#04x\n",
+ cam->params.status.vpStatus);
+ if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
+ /* Fatal error in camera */
+ return -EIO;
+ } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
+ /* Firmware 1-02 may do this for parallel port cameras,
+ * just clear the flags (developer's guide p 3-38) */
+ do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
+ FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
+ }
+ }
+
+ /* Check the camera status again */
+ if (cam->params.status.fatalError) {
+ if (cam->params.status.fatalError)
+ return -EIO;
+ }
+
+ /* VPVersion can't be retrieved before the camera is in HiPower,
+ * so get it here instead of in get_version_information. */
+ do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+
+ /* set camera to a known state */
+ return set_camera_state(cam);
+}
+
+static void put_cam(struct cpia_camera_ops* ops)
+{
+ module_put(ops->owner);
+}
+
+/* ------------------------- V4L interface --------------------- */
+static int cpia_open(struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct cam_data *cam = video_get_drvdata(dev);
+ int err;
+
+ if (!cam) {
+ DBG("Internal error, cam_data not found!\n");
+ return -ENODEV;
+ }
+
+ if (cam->open_count > 0) {
+ DBG("Camera already open\n");
+ return -EBUSY;
+ }
+
+ if (!try_module_get(cam->ops->owner))
+ return -ENODEV;
+
+ mutex_lock(&cam->busy_lock);
+ err = -ENOMEM;
+ if (!cam->raw_image) {
+ cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
+ if (!cam->raw_image)
+ goto oops;
+ }
+
+ if (!cam->decompressed_frame.data) {
+ cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
+ if (!cam->decompressed_frame.data)
+ goto oops;
+ }
+
+ /* open cpia */
+ err = -ENODEV;
+ if (cam->ops->open(cam->lowlevel_data))
+ goto oops;
+
+ /* reset the camera */
+ if ((err = reset_camera(cam)) != 0) {
+ cam->ops->close(cam->lowlevel_data);
+ goto oops;
+ }
+
+ err = -EINTR;
+ if(signal_pending(current))
+ goto oops;
+
+ /* Set ownership of /proc/cpia/videoX to current user */
+ if(cam->proc_entry)
+ cam->proc_entry->uid = current_uid();
+
+ /* set mark for loading first frame uncompressed */
+ cam->first_frame = 1;
+
+ /* init it to something */
+ cam->mmap_kludge = 0;
+
+ ++cam->open_count;
+ file->private_data = dev;
+ mutex_unlock(&cam->busy_lock);
+ return 0;
+
+ oops:
+ if (cam->decompressed_frame.data) {
+ rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+ cam->decompressed_frame.data = NULL;
+ }
+ if (cam->raw_image) {
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ }
+ mutex_unlock(&cam->busy_lock);
+ put_cam(cam->ops);
+ return err;
+}
+
+static int cpia_close(struct file *file)
+{
+ struct video_device *dev = file->private_data;
+ struct cam_data *cam = video_get_drvdata(dev);
+
+ if (cam->ops) {
+ /* Return ownership of /proc/cpia/videoX to root */
+ if(cam->proc_entry)
+ cam->proc_entry->uid = 0;
+
+ /* save camera state for later open (developers guide ch 3.5.3) */
+ save_camera_state(cam);
+
+ /* GotoLoPower */
+ goto_low_power(cam);
+
+ /* Update the camera status */
+ do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+ /* cleanup internal state stuff */
+ free_frames(cam->frame);
+
+ /* close cpia */
+ cam->ops->close(cam->lowlevel_data);
+
+ put_cam(cam->ops);
+ }
+
+ if (--cam->open_count == 0) {
+ /* clean up capture-buffers */
+ if (cam->raw_image) {
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ }
+
+ if (cam->decompressed_frame.data) {
+ rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+ cam->decompressed_frame.data = NULL;
+ }
+
+ if (cam->frame_buf)
+ free_frame_buf(cam);
+
+ if (!cam->ops)
+ kfree(cam);
+ }
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static ssize_t cpia_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *dev = file->private_data;
+ struct cam_data *cam = video_get_drvdata(dev);
+ int err;
+
+ /* make this _really_ smp and multithread-safe */
+ if (mutex_lock_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ if (!buf) {
+ DBG("buf NULL\n");
+ mutex_unlock(&cam->busy_lock);
+ return -EINVAL;
+ }
+
+ if (!count) {
+ DBG("count 0\n");
+ mutex_unlock(&cam->busy_lock);
+ return 0;
+ }
+
+ if (!cam->ops) {
+ DBG("ops NULL\n");
+ mutex_unlock(&cam->busy_lock);
+ return -ENODEV;
+ }
+
+ /* upload frame */
+ cam->decompressed_frame.state = FRAME_READY;
+ cam->mmap_kludge=0;
+ if((err = fetch_frame(cam)) != 0) {
+ DBG("ERROR from fetch_frame: %d\n", err);
+ mutex_unlock(&cam->busy_lock);
+ return err;
+ }
+ cam->decompressed_frame.state = FRAME_UNUSED;
+
+ /* copy data to user space */
+ if (cam->decompressed_frame.count > count) {
+ DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
+ (unsigned long) count);
+ mutex_unlock(&cam->busy_lock);
+ return -EFAULT;
+ }
+ if (copy_to_user(buf, cam->decompressed_frame.data,
+ cam->decompressed_frame.count)) {
+ DBG("copy_to_user failed\n");
+ mutex_unlock(&cam->busy_lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&cam->busy_lock);
+ return cam->decompressed_frame.count;
+}
+
+static long cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+ struct video_device *dev = file->private_data;
+ struct cam_data *cam = video_get_drvdata(dev);
+ int retval = 0;
+
+ if (!cam || !cam->ops)
+ return -ENODEV;
+
+ /* make this _really_ smp-safe */
+ if (mutex_lock_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ /* DBG("cpia_ioctl: %u\n", cmd); */
+
+ switch (cmd) {
+ /* query capabilities */
+ case VIDIOCGCAP:
+ {
+ struct video_capability *b = arg;
+
+ DBG("VIDIOCGCAP\n");
+ strcpy(b->name, "CPiA Camera");
+ b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+ b->channels = 1;
+ b->audios = 0;
+ b->maxwidth = 352; /* VIDEOSIZE_CIF */
+ b->maxheight = 288;
+ b->minwidth = 48; /* VIDEOSIZE_48_48 */
+ b->minheight = 48;
+ break;
+ }
+
+ /* get/set video source - we are a camera and nothing else */
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
+
+ DBG("VIDIOCGCHAN\n");
+ if (v->channel != 0) {
+ retval = -EINVAL;
+ break;
+ }
+
+ v->channel = 0;
+ strcpy(v->name, "Camera");
+ v->tuners = 0;
+ v->flags = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ v->norm = 0;
+ break;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *v = arg;
+
+ DBG("VIDIOCSCHAN\n");
+ if (v->channel != 0)
+ retval = -EINVAL;
+ break;
+ }
+
+ /* image properties */
+ case VIDIOCGPICT:
+ {
+ struct video_picture *pic = arg;
+ DBG("VIDIOCGPICT\n");
+ *pic = cam->vp;
+ break;
+ }
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *vp = arg;
+
+ DBG("VIDIOCSPICT\n");
+
+ /* check validity */
+ DBG("palette: %d\n", vp->palette);
+ DBG("depth: %d\n", vp->depth);
+ if (!valid_mode(vp->palette, vp->depth)) {
+ retval = -EINVAL;
+ break;
+ }
+
+ mutex_lock(&cam->param_lock);
+ /* brightness, colour, contrast need no check 0-65535 */
+ cam->vp = *vp;
+ /* update cam->params.colourParams */
+ cam->params.colourParams.brightness = vp->brightness*100/65535;
+ cam->params.colourParams.contrast = vp->contrast*100/65535;
+ cam->params.colourParams.saturation = vp->colour*100/65535;
+ /* contrast is in steps of 8, so round */
+ cam->params.colourParams.contrast =
+ ((cam->params.colourParams.contrast + 3) / 8) * 8;
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2 &&
+ cam->params.colourParams.contrast > 80) {
+ /* 1-02 firmware limits contrast to 80 */
+ cam->params.colourParams.contrast = 80;
+ }
+
+ /* Adjust flicker control if necessary */
+ if(cam->params.flickerControl.allowableOverExposure < 0)
+ cam->params.flickerControl.allowableOverExposure =
+ -find_over_exposure(cam->params.colourParams.brightness);
+ if(cam->params.flickerControl.flickerMode != 0)
+ cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
+
+
+ /* queue command to update camera */
+ cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
+ mutex_unlock(&cam->param_lock);
+ DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
+ vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
+ vp->contrast);
+ break;
+ }
+
+ /* get/set capture window */
+ case VIDIOCGWIN:
+ {
+ struct video_window *vw = arg;
+ DBG("VIDIOCGWIN\n");
+
+ *vw = cam->vw;
+ break;
+ }
+
+ case VIDIOCSWIN:
+ {
+ /* copy_from_user, check validity, copy to internal structure */
+ struct video_window *vw = arg;
+ DBG("VIDIOCSWIN\n");
+
+ if (vw->clipcount != 0) { /* clipping not supported */
+ retval = -EINVAL;
+ break;
+ }
+ if (vw->clips != NULL) { /* clipping not supported */
+ retval = -EINVAL;
+ break;
+ }
+
+ /* we set the video window to something smaller or equal to what
+ * is requested by the user???
+ */
+ mutex_lock(&cam->param_lock);
+ if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+ int video_size = match_videosize(vw->width, vw->height);
+
+ if (video_size < 0) {
+ retval = -EINVAL;
+ mutex_unlock(&cam->param_lock);
+ break;
+ }
+ cam->video_size = video_size;
+
+ /* video size is changing, reset the subcapture area */
+ memset(&cam->vc, 0, sizeof(cam->vc));
+
+ set_vw_size(cam);
+ DBG("%d / %d\n", cam->vw.width, cam->vw.height);
+ cam->cmd_queue |= COMMAND_SETFORMAT;
+ }
+
+ mutex_unlock(&cam->param_lock);
+
+ /* setformat ignored by camera during streaming,
+ * so stop/dispatch/start */
+ if (cam->cmd_queue & COMMAND_SETFORMAT) {
+ DBG("\n");
+ dispatch_commands(cam);
+ }
+ DBG("%d/%d:%d\n", cam->video_size,
+ cam->vw.width, cam->vw.height);
+ break;
+ }
+
+ /* mmap interface */
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf *vm = arg;
+ int i;
+
+ DBG("VIDIOCGMBUF\n");
+ memset(vm, 0, sizeof(*vm));
+ vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+ vm->frames = FRAME_NUM;
+ for (i = 0; i < FRAME_NUM; i++)
+ vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
+ break;
+ }
+
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap *vm = arg;
+ int video_size;
+
+ DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
+ vm->width, vm->height);
+ if (vm->frame<0||vm->frame>=FRAME_NUM) {
+ retval = -EINVAL;
+ break;
+ }
+
+ /* set video format */
+ cam->vp.palette = vm->format;
+ switch(vm->format) {
+ case VIDEO_PALETTE_GREY:
+ cam->vp.depth=8;
+ break;
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ case VIDEO_PALETTE_UYVY:
+ cam->vp.depth = 16;
+ break;
+ case VIDEO_PALETTE_RGB24:
+ cam->vp.depth = 24;
+ break;
+ case VIDEO_PALETTE_RGB32:
+ cam->vp.depth = 32;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ if (retval)
+ break;
+
+ /* set video size */
+ video_size = match_videosize(vm->width, vm->height);
+ if (video_size < 0) {
+ retval = -EINVAL;
+ break;
+ }
+ if (video_size != cam->video_size) {
+ cam->video_size = video_size;
+
+ /* video size is changing, reset the subcapture area */
+ memset(&cam->vc, 0, sizeof(cam->vc));
+
+ set_vw_size(cam);
+ cam->cmd_queue |= COMMAND_SETFORMAT;
+ dispatch_commands(cam);
+ }
+ /* according to v4l-spec we must start streaming here */
+ cam->mmap_kludge = 1;
+ retval = capture_frame(cam, vm);
+
+ break;
+ }
+
+ case VIDIOCSYNC:
+ {
+ int *frame = arg;
+
+ //DBG("VIDIOCSYNC: %d\n", *frame);
+
+ if (*frame<0 || *frame >= FRAME_NUM) {
+ retval = -EINVAL;
+ break;
+ }
+
+ switch (cam->frame[*frame].state) {
+ case FRAME_UNUSED:
+ case FRAME_READY:
+ case FRAME_GRABBING:
+ DBG("sync to unused frame %d\n", *frame);
+ retval = -EINVAL;
+ break;
+
+ case FRAME_DONE:
+ cam->frame[*frame].state = FRAME_UNUSED;
+ //DBG("VIDIOCSYNC: %d synced\n", *frame);
+ break;
+ }
+ if (retval == -EINTR) {
+ /* FIXME - xawtv does not handle this nice */
+ retval = 0;
+ }
+ break;
+ }
+
+ case VIDIOCGCAPTURE:
+ {
+ struct video_capture *vc = arg;
+
+ DBG("VIDIOCGCAPTURE\n");
+
+ *vc = cam->vc;
+
+ break;
+ }
+
+ case VIDIOCSCAPTURE:
+ {
+ struct video_capture *vc = arg;
+
+ DBG("VIDIOCSCAPTURE\n");
+
+ if (vc->decimation != 0) { /* How should this be used? */
+ retval = -EINVAL;
+ break;
+ }
+ if (vc->flags != 0) { /* Even/odd grab not supported */
+ retval = -EINVAL;
+ break;
+ }
+
+ /* Clip to the resolution we can set for the ROI
+ (every 8 columns and 4 rows) */
+ vc->x = vc->x & ~(__u32)7;
+ vc->y = vc->y & ~(__u32)3;
+ vc->width = vc->width & ~(__u32)7;
+ vc->height = vc->height & ~(__u32)3;
+
+ if(vc->width == 0 || vc->height == 0 ||
+ vc->x + vc->width > cam->vw.width ||
+ vc->y + vc->height > cam->vw.height) {
+ retval = -EINVAL;
+ break;
+ }
+
+ DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
+
+ mutex_lock(&cam->param_lock);
+
+ cam->vc.x = vc->x;
+ cam->vc.y = vc->y;
+ cam->vc.width = vc->width;
+ cam->vc.height = vc->height;
+
+ set_vw_size(cam);
+ cam->cmd_queue |= COMMAND_SETFORMAT;
+
+ mutex_unlock(&cam->param_lock);
+
+ /* setformat ignored by camera during streaming,
+ * so stop/dispatch/start */
+ dispatch_commands(cam);
+ break;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit *vu = arg;
+
+ DBG("VIDIOCGUNIT\n");
+
+ vu->video = cam->vdev.minor;
+ vu->vbi = VIDEO_NO_UNIT;
+ vu->radio = VIDEO_NO_UNIT;
+ vu->audio = VIDEO_NO_UNIT;
+ vu->teletext = VIDEO_NO_UNIT;
+
+ break;
+ }
+
+
+ /* pointless to implement overlay with this camera */
+ case VIDIOCCAPTURE:
+ case VIDIOCGFBUF:
+ case VIDIOCSFBUF:
+ case VIDIOCKEY:
+ /* tuner interface - we have none */
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ /* audio interface - we have none */
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ retval = -EINVAL;
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+
+ mutex_unlock(&cam->busy_lock);
+ return retval;
+}
+
+static long cpia_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, cpia_do_ioctl);
+}
+
+
+/* FIXME */
+static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *dev = file->private_data;
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long page, pos;
+ struct cam_data *cam = video_get_drvdata(dev);
+ int retval;
+
+ if (!cam || !cam->ops)
+ return -ENODEV;
+
+ DBG("cpia_mmap: %ld\n", size);
+
+ if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
+ return -EINVAL;
+
+ /* make this _really_ smp-safe */
+ if (mutex_lock_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ if (!cam->frame_buf) { /* we do lazy allocation */
+ if ((retval = allocate_frame_buf(cam))) {
+ mutex_unlock(&cam->busy_lock);
+ return retval;
+ }
+ }
+
+ pos = (unsigned long)(cam->frame_buf);
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+ mutex_unlock(&cam->busy_lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ DBG("cpia_mmap: %ld\n", size);
+ mutex_unlock(&cam->busy_lock);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations cpia_fops = {
+ .owner = THIS_MODULE,
+ .open = cpia_open,
+ .release = cpia_close,
+ .read = cpia_read,
+ .mmap = cpia_mmap,
+ .ioctl = cpia_ioctl,
+};
+
+static struct video_device cpia_template = {
+ .name = "CPiA Camera",
+ .fops = &cpia_fops,
+ .release = video_device_release_empty,
+};
+
+/* initialise cam_data structure */
+static void reset_camera_struct(struct cam_data *cam)
+{
+ /* The following parameter values are the defaults from
+ * "Software Developer's Guide for CPiA Cameras". Any changes
+ * to the defaults are noted in comments. */
+ cam->params.colourParams.brightness = 50;
+ cam->params.colourParams.contrast = 48;
+ cam->params.colourParams.saturation = 50;
+ cam->params.exposure.gainMode = 4;
+ cam->params.exposure.expMode = 2; /* AEC */
+ cam->params.exposure.compMode = 1;
+ cam->params.exposure.centreWeight = 1;
+ cam->params.exposure.gain = 0;
+ cam->params.exposure.fineExp = 0;
+ cam->params.exposure.coarseExpLo = 185;
+ cam->params.exposure.coarseExpHi = 0;
+ cam->params.exposure.redComp = COMP_RED;
+ cam->params.exposure.green1Comp = COMP_GREEN1;
+ cam->params.exposure.green2Comp = COMP_GREEN2;
+ cam->params.exposure.blueComp = COMP_BLUE;
+ cam->params.colourBalance.balanceMode = 2; /* ACB */
+ cam->params.colourBalance.redGain = 32;
+ cam->params.colourBalance.greenGain = 6;
+ cam->params.colourBalance.blueGain = 92;
+ cam->params.apcor.gain1 = 0x18;
+ cam->params.apcor.gain2 = 0x16;
+ cam->params.apcor.gain4 = 0x24;
+ cam->params.apcor.gain8 = 0x34;
+ cam->params.flickerControl.flickerMode = 0;
+ cam->params.flickerControl.disabled = 1;
+
+ cam->params.flickerControl.coarseJump =
+ flicker_jumps[cam->mainsFreq]
+ [cam->params.sensorFps.baserate]
+ [cam->params.sensorFps.divisor];
+ cam->params.flickerControl.allowableOverExposure =
+ -find_over_exposure(cam->params.colourParams.brightness);
+ cam->params.vlOffset.gain1 = 20;
+ cam->params.vlOffset.gain2 = 24;
+ cam->params.vlOffset.gain4 = 26;
+ cam->params.vlOffset.gain8 = 26;
+ cam->params.compressionParams.hysteresis = 3;
+ cam->params.compressionParams.threshMax = 11;
+ cam->params.compressionParams.smallStep = 1;
+ cam->params.compressionParams.largeStep = 3;
+ cam->params.compressionParams.decimationHysteresis = 2;
+ cam->params.compressionParams.frDiffStepThresh = 5;
+ cam->params.compressionParams.qDiffStepThresh = 3;
+ cam->params.compressionParams.decimationThreshMod = 2;
+ /* End of default values from Software Developer's Guide */
+
+ cam->transfer_rate = 0;
+ cam->exposure_status = EXPOSURE_NORMAL;
+
+ /* Set Sensor FPS to 15fps. This seems better than 30fps
+ * for indoor lighting. */
+ cam->params.sensorFps.divisor = 1;
+ cam->params.sensorFps.baserate = 1;
+
+ cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+ cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
+
+ cam->params.format.subSample = SUBSAMPLE_422;
+ cam->params.format.yuvOrder = YUVORDER_YUYV;
+
+ cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
+ cam->params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_QUALITY;
+ cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+ cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+
+ cam->params.qx3.qx3_detected = 0;
+ cam->params.qx3.toplight = 0;
+ cam->params.qx3.bottomlight = 0;
+ cam->params.qx3.button = 0;
+ cam->params.qx3.cradled = 0;
+
+ cam->video_size = VIDEOSIZE_CIF;
+
+ cam->vp.colour = 32768; /* 50% */
+ cam->vp.hue = 32768; /* 50% */
+ cam->vp.brightness = 32768; /* 50% */
+ cam->vp.contrast = 32768; /* 50% */
+ cam->vp.whiteness = 0; /* not used -> grayscale only */
+ cam->vp.depth = 24; /* to be set by user */
+ cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
+
+ cam->vc.x = 0;
+ cam->vc.y = 0;
+ cam->vc.width = 0;
+ cam->vc.height = 0;
+
+ cam->vw.x = 0;
+ cam->vw.y = 0;
+ set_vw_size(cam);
+ cam->vw.chromakey = 0;
+ cam->vw.flags = 0;
+ cam->vw.clipcount = 0;
+ cam->vw.clips = NULL;
+
+ cam->cmd_queue = COMMAND_NONE;
+ cam->first_frame = 1;
+
+ return;
+}
+
+/* initialize cam_data structure */
+static void init_camera_struct(struct cam_data *cam,
+ struct cpia_camera_ops *ops )
+{
+ int i;
+
+ /* Default everything to 0 */
+ memset(cam, 0, sizeof(struct cam_data));
+
+ cam->ops = ops;
+ mutex_init(&cam->param_lock);
+ mutex_init(&cam->busy_lock);
+
+ reset_camera_struct(cam);
+
+ cam->proc_entry = NULL;
+
+ memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
+ video_set_drvdata(&cam->vdev, cam);
+
+ cam->curframe = 0;
+ for (i = 0; i < FRAME_NUM; i++) {
+ cam->frame[i].width = 0;
+ cam->frame[i].height = 0;
+ cam->frame[i].state = FRAME_UNUSED;
+ cam->frame[i].data = NULL;
+ }
+ cam->decompressed_frame.width = 0;
+ cam->decompressed_frame.height = 0;
+ cam->decompressed_frame.state = FRAME_UNUSED;
+ cam->decompressed_frame.data = NULL;
+}
+
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
+{
+ struct cam_data *camera;
+
+ if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
+ return NULL;
+
+
+ init_camera_struct( camera, ops );
+ camera->lowlevel_data = lowlevel;
+
+ /* register v4l device */
+ if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+ kfree(camera);
+ printk(KERN_DEBUG "video_register_device failed\n");
+ return NULL;
+ }
+
+ /* get version information from camera: open/reset/close */
+
+ /* open cpia */
+ if (camera->ops->open(camera->lowlevel_data))
+ return camera;
+
+ /* reset the camera */
+ if (reset_camera(camera) != 0) {
+ camera->ops->close(camera->lowlevel_data);
+ return camera;
+ }
+
+ /* close cpia */
+ camera->ops->close(camera->lowlevel_data);
+
+#ifdef CONFIG_PROC_FS
+ create_proc_cpia_cam(camera);
+#endif
+
+ printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
+ camera->params.version.firmwareVersion,
+ camera->params.version.firmwareRevision,
+ camera->params.version.vcVersion,
+ camera->params.version.vcRevision);
+ printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
+ camera->params.pnpID.vendor,
+ camera->params.pnpID.product,
+ camera->params.pnpID.deviceRevision);
+ printk(KERN_INFO " VP-Version: %d.%d %04x\n",
+ camera->params.vpVersion.vpVersion,
+ camera->params.vpVersion.vpRevision,
+ camera->params.vpVersion.cameraHeadID);
+
+ return camera;
+}
+
+void cpia_unregister_camera(struct cam_data *cam)
+{
+ DBG("unregistering video\n");
+ video_unregister_device(&cam->vdev);
+ if (cam->open_count) {
+ put_cam(cam->ops);
+ DBG("camera open -- setting ops to NULL\n");
+ cam->ops = NULL;
+ }
+
+#ifdef CONFIG_PROC_FS
+ DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev));
+ destroy_proc_cpia_cam(cam);
+#endif
+ if (!cam->open_count) {
+ DBG("freeing camera\n");
+ kfree(cam);
+ }
+}
+
+static int __init cpia_init(void)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+
+ printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
+ "allowed, it is disabled by default now. Users should fix the "
+ "applications in case they don't work without conversion "
+ "reenabled by setting the 'colorspace_conv' module "
+ "parameter to 1\n");
+
+#ifdef CONFIG_PROC_FS
+ proc_cpia_create();
+#endif
+
+ return 0;
+}
+
+static void __exit cpia_exit(void)
+{
+#ifdef CONFIG_PROC_FS
+ proc_cpia_destroy();
+#endif
+}
+
+module_init(cpia_init);
+module_exit(cpia_exit);
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(cpia_register_camera);
+EXPORT_SYMBOL(cpia_unregister_camera);
diff --git a/drivers/staging/cpia/cpia.h b/drivers/staging/cpia/cpia.h
new file mode 100644
index 000000000000..8f0cfee4b8a1
--- /dev/null
+++ b/drivers/staging/cpia/cpia.h
@@ -0,0 +1,432 @@
+#ifndef cpia_h
+#define cpia_h
+
+/*
+ * CPiA Parallel Port Video4Linux driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman,
+ * Peter Pregler,
+ * Scott J. Bertin,
+ * VLSI Vision Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define CPIA_MAJ_VER 1
+#define CPIA_MIN_VER 2
+#define CPIA_PATCH_VER 3
+
+#define CPIA_PP_MAJ_VER CPIA_MAJ_VER
+#define CPIA_PP_MIN_VER CPIA_MIN_VER
+#define CPIA_PP_PATCH_VER CPIA_PATCH_VER
+
+#define CPIA_USB_MAJ_VER CPIA_MAJ_VER
+#define CPIA_USB_MIN_VER CPIA_MIN_VER
+#define CPIA_USB_PATCH_VER CPIA_PATCH_VER
+
+#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
+#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
+
+#ifdef __KERNEL__
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+struct cpia_camera_ops
+{
+ /* open sets privdata to point to structure for this camera.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*open)(void *privdata);
+
+ /* Registers callback function cb to be called with cbdata
+ * when an image is ready. If cb is NULL, only single image grabs
+ * should be used. cb should immediately call streamRead to read
+ * the data or data may be lost. Returns negative value on error,
+ * otherwise 0.
+ */
+ int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
+ void *cbdata);
+
+ /* transferCmd sends commands to the camera. command MUST point to
+ * an 8 byte buffer in kernel space. data can be NULL if no extra
+ * data is needed. The size of the data is given by the last 2
+ * bytes of command. data must also point to memory in kernel space.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*transferCmd)(void *privdata, u8 *command, u8 *data);
+
+ /* streamStart initiates stream capture mode.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*streamStart)(void *privdata);
+
+ /* streamStop terminates stream capture mode.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*streamStop)(void *privdata);
+
+ /* streamRead reads a frame from the camera. buffer points to a
+ * buffer large enough to hold a complete frame in kernel space.
+ * noblock indicates if this should be a non blocking read.
+ * Returns the number of bytes read, or negative value on error.
+ */
+ int (*streamRead)(void *privdata, u8 *buffer, int noblock);
+
+ /* close disables the device until open() is called again.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*close)(void *privdata);
+
+ /* If wait_for_stream_ready is non-zero, wait until the streamState
+ * is STREAM_READY before calling streamRead.
+ */
+ int wait_for_stream_ready;
+
+ /*
+ * Used to maintain lowlevel module usage counts
+ */
+ struct module *owner;
+};
+
+struct cpia_frame {
+ u8 *data;
+ int count;
+ int width;
+ int height;
+ volatile int state;
+};
+
+struct cam_params {
+ struct {
+ u8 firmwareVersion;
+ u8 firmwareRevision;
+ u8 vcVersion;
+ u8 vcRevision;
+ } version;
+ struct {
+ u16 vendor;
+ u16 product;
+ u16 deviceRevision;
+ } pnpID;
+ struct {
+ u8 vpVersion;
+ u8 vpRevision;
+ u16 cameraHeadID;
+ } vpVersion;
+ struct {
+ u8 systemState;
+ u8 grabState;
+ u8 streamState;
+ u8 fatalError;
+ u8 cmdError;
+ u8 debugFlags;
+ u8 vpStatus;
+ u8 errorCode;
+ } status;
+ struct {
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ } colourParams;
+ struct {
+ u8 gainMode;
+ u8 expMode;
+ u8 compMode;
+ u8 centreWeight;
+ u8 gain;
+ u8 fineExp;
+ u8 coarseExpLo;
+ u8 coarseExpHi;
+ u8 redComp;
+ u8 green1Comp;
+ u8 green2Comp;
+ u8 blueComp;
+ } exposure;
+ struct {
+ u8 balanceMode;
+ u8 redGain;
+ u8 greenGain;
+ u8 blueGain;
+ } colourBalance;
+ struct {
+ u8 divisor;
+ u8 baserate;
+ } sensorFps;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } apcor;
+ struct {
+ u8 disabled;
+ u8 flickerMode;
+ u8 coarseJump;
+ int allowableOverExposure;
+ } flickerControl;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } vlOffset;
+ struct {
+ u8 mode;
+ u8 decimation;
+ } compression;
+ struct {
+ u8 frTargeting;
+ u8 targetFR;
+ u8 targetQ;
+ } compressionTarget;
+ struct {
+ u8 yThreshold;
+ u8 uvThreshold;
+ } yuvThreshold;
+ struct {
+ u8 hysteresis;
+ u8 threshMax;
+ u8 smallStep;
+ u8 largeStep;
+ u8 decimationHysteresis;
+ u8 frDiffStepThresh;
+ u8 qDiffStepThresh;
+ u8 decimationThreshMod;
+ } compressionParams;
+ struct {
+ u8 videoSize; /* CIF/QCIF */
+ u8 subSample;
+ u8 yuvOrder;
+ } format;
+ struct { /* Intel QX3 specific data */
+ u8 qx3_detected; /* a QX3 is present */
+ u8 toplight; /* top light lit , R/W */
+ u8 bottomlight; /* bottom light lit, R/W */
+ u8 button; /* snapshot button pressed (R/O) */
+ u8 cradled; /* microscope is in cradle (R/O) */
+ } qx3;
+ struct {
+ u8 colStart; /* skip first 8*colStart pixels */
+ u8 colEnd; /* finish at 8*colEnd pixels */
+ u8 rowStart; /* skip first 4*rowStart lines */
+ u8 rowEnd; /* finish at 4*rowEnd lines */
+ } roi;
+ u8 ecpTiming;
+ u8 streamStartLine;
+};
+
+enum v4l_camstates {
+ CPIA_V4L_IDLE = 0,
+ CPIA_V4L_ERROR,
+ CPIA_V4L_COMMAND,
+ CPIA_V4L_GRABBING,
+ CPIA_V4L_STREAMING,
+ CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM 2 /* double buffering for now */
+
+struct cam_data {
+ struct list_head cam_data_list;
+
+ struct mutex busy_lock; /* guard against SMP multithreading */
+ struct cpia_camera_ops *ops; /* lowlevel driver operations */
+ void *lowlevel_data; /* private data for lowlevel driver */
+ u8 *raw_image; /* buffer for raw image data */
+ struct cpia_frame decompressed_frame;
+ /* buffer to hold decompressed frame */
+ int image_size; /* sizeof last decompressed image */
+ int open_count; /* # of process that have camera open */
+
+ /* camera status */
+ int fps; /* actual fps reported by the camera */
+ int transfer_rate; /* transfer rate from camera in kB/s */
+ u8 mainsFreq; /* for flicker control */
+
+ /* proc interface */
+ struct mutex param_lock; /* params lock for this camera */
+ struct cam_params params; /* camera settings */
+ struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
+
+ /* v4l */
+ int video_size; /* VIDEO_SIZE_ */
+ volatile enum v4l_camstates camstate; /* v4l layer status */
+ struct video_device vdev; /* v4l videodev */
+ struct video_picture vp; /* v4l camera settings */
+ struct video_window vw; /* v4l capture area */
+ struct video_capture vc; /* v4l subcapture area */
+
+ /* mmap interface */
+ int curframe; /* the current frame to grab into */
+ u8 *frame_buf; /* frame buffer data */
+ struct cpia_frame frame[FRAME_NUM];
+ /* FRAME_NUM-buffering, so we need a array */
+
+ int first_frame;
+ int mmap_kludge; /* 'wrong' byte order for mmap */
+ volatile u32 cmd_queue; /* queued commands */
+ int exposure_status; /* EXPOSURE_* */
+ int exposure_count; /* number of frames at this status */
+};
+
+/* cpia_register_camera is called by low level driver for each camera.
+ * A unique camera number is returned, or a negative value on error */
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
+
+/* cpia_unregister_camera is called by low level driver when a camera
+ * is removed. This must not fail. */
+void cpia_unregister_camera(struct cam_data *cam);
+
+/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
+ * one byte 16bit DMA alignment
+ */
+#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
+
+/* constant value's */
+#define MAGIC_0 0x19
+#define MAGIC_1 0x68
+#define DATA_IN 0xC0
+#define DATA_OUT 0x40
+#define VIDEOSIZE_QCIF 0 /* 176x144 */
+#define VIDEOSIZE_CIF 1 /* 352x288 */
+#define VIDEOSIZE_SIF 2 /* 320x240 */
+#define VIDEOSIZE_QSIF 3 /* 160x120 */
+#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */
+#define VIDEOSIZE_64_48 5
+#define VIDEOSIZE_128_96 6
+#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF
+#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF
+#define VIDEOSIZE_192_144 7
+#define VIDEOSIZE_224_168 8
+#define VIDEOSIZE_256_192 9
+#define VIDEOSIZE_288_216 10
+#define VIDEOSIZE_320_240 VIDEOSIZE_SIF
+#define VIDEOSIZE_352_288 VIDEOSIZE_CIF
+#define VIDEOSIZE_88_72 11 /* quarter CIF */
+#define SUBSAMPLE_420 0
+#define SUBSAMPLE_422 1
+#define YUVORDER_YUYV 0
+#define YUVORDER_UYVY 1
+#define NOT_COMPRESSED 0
+#define COMPRESSED 1
+#define NO_DECIMATION 0
+#define DECIMATION_ENAB 1
+#define EOI 0xff /* End Of Image */
+#define EOL 0xfd /* End Of Line */
+#define FRAME_HEADER_SIZE 64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE 0
+#define CPIA_GRAB_CONTINUOUS 1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE 0
+#define CPIA_COMPRESSION_AUTO 1
+#define CPIA_COMPRESSION_MANUAL 2
+#define CPIA_COMPRESSION_TARGET_QUALITY 0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE 0
+#define GRABSTATE 1
+#define STREAMSTATE 2
+#define FATALERROR 3
+#define CMDERROR 4
+#define DEBUGFLAGS 5
+#define VPSTATUS 6
+#define ERRORCODE 7
+
+/* SystemState */
+#define UNINITIALISED_STATE 0
+#define PASS_THROUGH_STATE 1
+#define LO_POWER_STATE 2
+#define HI_POWER_STATE 3
+#define WARM_BOOT_STATE 4
+
+/* GrabState */
+#define GRAB_IDLE 0
+#define GRAB_ACTIVE 1
+#define GRAB_DONE 2
+
+/* StreamState */
+#define STREAM_NOT_READY 0
+#define STREAM_READY 1
+#define STREAM_OPEN 2
+#define STREAM_PAUSED 3
+#define STREAM_FINISHED 4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG 1
+#define SYSTEM_FLAG 2
+#define INT_CTRL_FLAG 4
+#define PROCESS_FLAG 8
+#define COM_FLAG 16
+#define VP_CTRL_FLAG 32
+#define CAPTURE_FLAG 64
+#define DEBUG_FLAG 128
+
+/* VPStatus */
+#define VP_STATE_OK 0x00
+
+#define VP_STATE_FAILED_VIDEOINIT 0x01
+#define VP_STATE_FAILED_AECACBINIT 0x02
+#define VP_STATE_AEC_MAX 0x04
+#define VP_STATE_ACB_BMAX 0x08
+
+#define VP_STATE_ACB_RMIN 0x10
+#define VP_STATE_ACB_GMIN 0x20
+#define VP_STATE_ACB_RMAX 0x40
+#define VP_STATE_ACB_GMAX 0x80
+
+/* default (minimum) compensation values */
+#define COMP_RED 220
+#define COMP_GREEN1 214
+#define COMP_GREEN2 COMP_GREEN1
+#define COMP_BLUE 230
+
+/* exposure status */
+#define EXPOSURE_VERY_LIGHT 0
+#define EXPOSURE_LIGHT 1
+#define EXPOSURE_NORMAL 2
+#define EXPOSURE_DARK 3
+#define EXPOSURE_VERY_DARK 4
+
+/* ErrorCode */
+#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
+#define ALOG(fmt,args...) printk(fmt, ##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
+
+#ifdef _CPIA_DEBUG_
+#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
+#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DEB_BYTE(p)\
+ DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
+ (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
+ (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#endif /* __KERNEL__ */
+
+#endif /* cpia_h */
diff --git a/drivers/staging/cpia/cpia_pp.c b/drivers/staging/cpia/cpia_pp.c
new file mode 100644
index 000000000000..f5604c16a092
--- /dev/null
+++ b/drivers/staging/cpia/cpia_pp.c
@@ -0,0 +1,869 @@
+/*
+ * cpia_pp CPiA Parallel Port driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
+ * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_ 1 */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/kmod.h>
+
+/* #define _CPIA_DEBUG_ define for verbose debug output */
+#include "cpia.h"
+
+static int cpia_pp_open(void *privdata);
+static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata);
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_pp_streamStart(void *privdata);
+static int cpia_pp_streamStop(void *privdata);
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
+static int cpia_pp_close(void *privdata);
+
+
+#define ABOUT "Parallel port driver for Vision CPiA based cameras"
+
+#define PACKET_LENGTH 8
+
+/* Magic numbers for defining port-device mappings */
+#define PPCPIA_PARPORT_UNSPEC -4
+#define PPCPIA_PARPORT_AUTO -3
+#define PPCPIA_PARPORT_OFF -2
+#define PPCPIA_PARPORT_NONE -1
+
+static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static char *parport[PARPORT_MAX] = {NULL,};
+
+MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
+MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
+MODULE_LICENSE("GPL");
+
+module_param_array(parport, charp, NULL, 0);
+MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
+
+struct pp_cam_entry {
+ struct pardevice *pdev;
+ struct parport *port;
+ struct work_struct cb_task;
+ void (*cb_func)(void *cbdata);
+ void *cb_data;
+ int open_count;
+ wait_queue_head_t wq_stream;
+ /* image state flags */
+ int image_ready; /* we got an interrupt */
+ int image_complete; /* we have seen 4 EOI */
+
+ int streaming; /* we are in streaming mode */
+ int stream_irq;
+};
+
+static struct cpia_camera_ops cpia_pp_ops =
+{
+ cpia_pp_open,
+ cpia_pp_registerCallback,
+ cpia_pp_transferCmd,
+ cpia_pp_streamStart,
+ cpia_pp_streamStop,
+ cpia_pp_streamRead,
+ cpia_pp_close,
+ 1,
+ THIS_MODULE
+};
+
+static LIST_HEAD(cam_list);
+static spinlock_t cam_list_lock_pp;
+
+/* FIXME */
+static void cpia_parport_enable_irq( struct parport *port ) {
+ parport_enable_irq(port);
+ mdelay(10);
+ return;
+}
+
+static void cpia_parport_disable_irq( struct parport *port ) {
+ parport_disable_irq(port);
+ mdelay(10);
+ return;
+}
+
+/* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility
+ * Link Flag during negotiation */
+#define UPLOAD_FLAG 0x08
+#define NIBBLE_TRANSFER 0x01
+#define ECP_TRANSFER 0x03
+
+#define PARPORT_CHUNK_SIZE PAGE_SIZE
+
+
+static void cpia_pp_run_callback(struct work_struct *work)
+{
+ void (*cb_func)(void *cbdata);
+ void *cb_data;
+ struct pp_cam_entry *cam;
+
+ cam = container_of(work, struct pp_cam_entry, cb_task);
+ cb_func = cam->cb_func;
+ cb_data = cam->cb_data;
+
+ cb_func(cb_data);
+}
+
+/****************************************************************************
+ *
+ * CPiA-specific low-level parport functions for nibble uploads
+ *
+ ***************************************************************************/
+/* CPiA nonstandard "Nibble" mode (no nDataAvail signal after each byte). */
+/* The standard kernel parport_ieee1284_read_nibble() fails with the CPiA... */
+
+static size_t cpia_read_nibble (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ /* adapted verbatim, with one change, from
+ parport_ieee1284_read_nibble() in drivers/parport/ieee1284-ops.c */
+
+ unsigned char *buf = buffer;
+ int i;
+ unsigned char byte = 0;
+
+ len *= 2; /* in nibbles */
+ for (i=0; i < len; i++) {
+ unsigned char nibble;
+
+ /* The CPiA firmware suppresses the use of nDataAvail (nFault LO)
+ * after every second nibble to signal that more
+ * data is available. (the total number of Bytes that
+ * should be sent is known; if too few are received, an error
+ * will be recorded after a timeout).
+ * This is incompatible with parport_ieee1284_read_nibble(),
+ * which expects to find nFault LO after every second nibble.
+ */
+
+ /* Solution: modify cpia_read_nibble to only check for
+ * nDataAvail before the first nibble is sent.
+ */
+
+ /* Does the error line indicate end of data? */
+ if (((i /*& 1*/) == 0) &&
+ (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+ DBG("%s: No more nibble data (%d bytes)\n",
+ port->name, i/2);
+ goto end_of_data;
+ }
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK, 0)) {
+ /* Timeout -- no more data? */
+ DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
+ port->name, i/2);
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ break;
+ }
+
+
+ /* Read a nibble. */
+ nibble = parport_read_status (port) >> 3;
+ nibble &= ~8;
+ if ((nibble & 0x10) == 0)
+ nibble |= 8;
+ nibble &= 0xf;
+
+ /* Event 10: Set nAutoFd high. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DBG("%s: Nibble timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ if (i & 1) {
+ /* Second nibble */
+ byte |= nibble << 4;
+ *buf++ = byte;
+ } else
+ byte = nibble;
+ }
+
+ if (i == len) {
+ /* Read the last nibble without checking data avail. */
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+ end_of_data:
+ /* Go to reverse idle phase. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ }
+ else
+ port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ }
+
+ return i/2;
+}
+
+/* CPiA nonstandard "Nibble Stream" mode (2 nibbles per cycle, instead of 1)
+ * (See CPiA Data sheet p. 31)
+ *
+ * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a
+ * nonstandard variant of nibble mode which allows the same (mediocre)
+ * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable
+ * parallel ports, but works also for non-TRISTATE-capable ports.
+ * (Standard nibble mode only send 4 bits per cycle)
+ *
+ */
+
+static size_t cpia_read_nibble_stream(struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ int i;
+ unsigned char *buf = buffer;
+ int endseen = 0;
+
+ for (i=0; i < len; i++) {
+ unsigned char nibble[2], byte = 0;
+ int j;
+
+ /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */
+ if (endseen > 3 )
+ break;
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK, 0)) {
+ /* Timeout -- no more data? */
+ DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
+ port->name, i/2);
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ break;
+ }
+
+ /* Read lower nibble */
+ nibble[0] = parport_read_status (port) >>3;
+
+ /* Event 10: Set nAutoFd high. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DBG("%s: Nibble timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ /* Read upper nibble */
+ nibble[1] = parport_read_status (port) >>3;
+
+ /* reassemble the byte */
+ for (j = 0; j < 2 ; j++ ) {
+ nibble[j] &= ~8;
+ if ((nibble[j] & 0x10) == 0)
+ nibble[j] |= 8;
+ nibble[j] &= 0xf;
+ }
+ byte = (nibble[0] |(nibble[1] << 4));
+ *buf++ = byte;
+
+ if(byte == EOI)
+ endseen++;
+ else
+ endseen = 0;
+ }
+ return i;
+}
+
+/****************************************************************************
+ *
+ * EndTransferMode
+ *
+ ***************************************************************************/
+static void EndTransferMode(struct pp_cam_entry *cam)
+{
+ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+}
+
+/****************************************************************************
+ *
+ * ForwardSetup
+ *
+ ***************************************************************************/
+static int ForwardSetup(struct pp_cam_entry *cam)
+{
+ int retry;
+
+ /* The CPiA uses ECP protocol for Downloads from the Host to the camera.
+ * This will be software-emulated if ECP hardware is not present
+ */
+
+ /* the usual camera maximum response time is 10ms, but after receiving
+ * some commands, it needs up to 40ms. (Data Sheet p. 32)*/
+
+ for(retry = 0; retry < 4; ++retry) {
+ if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
+ break;
+ }
+ mdelay(10);
+ }
+ if(retry == 4) {
+ DBG("Unable to negotiate IEEE1284 ECP Download mode\n");
+ return -1;
+ }
+ return 0;
+}
+/****************************************************************************
+ *
+ * ReverseSetup
+ *
+ ***************************************************************************/
+static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
+{
+ int retry;
+ int upload_mode, mode = IEEE1284_MODE_ECP;
+ int transfer_mode = ECP_TRANSFER;
+
+ if (!(cam->port->modes & PARPORT_MODE_ECP) &&
+ !(cam->port->modes & PARPORT_MODE_TRISTATE)) {
+ mode = IEEE1284_MODE_NIBBLE;
+ transfer_mode = NIBBLE_TRANSFER;
+ }
+
+ upload_mode = mode;
+ if(extensibility) mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK;
+
+ /* the usual camera maximum response time is 10ms, but after
+ * receiving some commands, it needs up to 40ms. */
+
+ for(retry = 0; retry < 4; ++retry) {
+ if(!parport_negotiate(cam->port, mode)) {
+ break;
+ }
+ mdelay(10);
+ }
+ if(retry == 4) {
+ if(extensibility)
+ DBG("Unable to negotiate upload extensibility mode\n");
+ else
+ DBG("Unable to negotiate upload mode\n");
+ return -1;
+ }
+ if(extensibility) cam->port->ieee1284.mode = upload_mode;
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
+{
+ int retval=0;
+ int size_written;
+
+ if (packet == NULL) {
+ return -EINVAL;
+ }
+ if (ForwardSetup(cam)) {
+ DBG("Write failed in setup\n");
+ return -EIO;
+ }
+ size_written = parport_write(cam->port, packet, size);
+ if(size_written != size) {
+ DBG("Write failed, wrote %d/%d\n", size_written, size);
+ retval = -EIO;
+ }
+ EndTransferMode(cam);
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
+{
+ int retval=0;
+
+ if (packet == NULL) {
+ return -EINVAL;
+ }
+ if (ReverseSetup(cam, 0)) {
+ return -EIO;
+ }
+
+ /* support for CPiA variant nibble reads */
+ if(cam->port->ieee1284.mode == IEEE1284_MODE_NIBBLE) {
+ if(cpia_read_nibble(cam->port, packet, size, 0) != size)
+ retval = -EIO;
+ } else {
+ if(parport_read(cam->port, packet, size) != size)
+ retval = -EIO;
+ }
+ EndTransferMode(cam);
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamStart
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStart(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+ DBG("\n");
+ cam->streaming=1;
+ cam->image_ready=0;
+ //if (ReverseSetup(cam,1)) return -EIO;
+ if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamStop
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStop(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+
+ DBG("\n");
+ cam->streaming=0;
+ cpia_parport_disable_irq(cam->port);
+ //EndTransferMode(cam);
+
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamRead
+ *
+ ***************************************************************************/
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+ int bytes_read;
+
+ /* support for CPiA variant "nibble stream" reads */
+ if(port->ieee1284.mode == IEEE1284_MODE_NIBBLE)
+ bytes_read = cpia_read_nibble_stream(port,buffer,len,0);
+ else {
+ int new_bytes;
+ for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+ new_bytes = parport_read(port, buffer+bytes_read,
+ len-bytes_read);
+ if(new_bytes < 0) break;
+ }
+ }
+ return bytes_read;
+}
+
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
+{
+ struct pp_cam_entry *cam = privdata;
+ int read_bytes = 0;
+ int i, endseen, block_size, new_bytes;
+
+ if(cam == NULL) {
+ DBG("Internal driver error: cam is NULL\n");
+ return -EINVAL;
+ }
+ if(buffer == NULL) {
+ DBG("Internal driver error: buffer is NULL\n");
+ return -EINVAL;
+ }
+ //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
+ if( cam->stream_irq ) {
+ DBG("%d\n", cam->image_ready);
+ cam->image_ready--;
+ }
+ cam->image_complete=0;
+ if (0/*cam->streaming*/) {
+ if(!cam->image_ready) {
+ if(noblock) return -EWOULDBLOCK;
+ interruptible_sleep_on(&cam->wq_stream);
+ if( signal_pending(current) ) return -EINTR;
+ DBG("%d\n", cam->image_ready);
+ }
+ } else {
+ if (ReverseSetup(cam, 1)) {
+ DBG("unable to ReverseSetup\n");
+ return -EIO;
+ }
+ }
+ endseen = 0;
+ block_size = PARPORT_CHUNK_SIZE;
+ while( !cam->image_complete ) {
+ cond_resched();
+
+ new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+ if( new_bytes <= 0 ) {
+ break;
+ }
+ i=-1;
+ while(++i<new_bytes && endseen<4) {
+ if(*buffer==EOI) {
+ endseen++;
+ } else {
+ endseen=0;
+ }
+ buffer++;
+ }
+ read_bytes += i;
+ if( endseen==4 ) {
+ cam->image_complete=1;
+ break;
+ }
+ if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+ block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+ }
+ }
+ EndTransferMode(cam);
+ return cam->image_complete ? read_bytes : -EIO;
+}
+/****************************************************************************
+ *
+ * cpia_pp_transferCmd
+ *
+ ***************************************************************************/
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+ int err;
+ int retval=0;
+ int databytes;
+ struct pp_cam_entry *cam = privdata;
+
+ if(cam == NULL) {
+ DBG("Internal driver error: cam is NULL\n");
+ return -EINVAL;
+ }
+ if(command == NULL) {
+ DBG("Internal driver error: command is NULL\n");
+ return -EINVAL;
+ }
+ databytes = (((int)command[7])<<8) | command[6];
+ if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
+ DBG("Error writing command\n");
+ return err;
+ }
+ if(command[0] == DATA_IN) {
+ u8 buffer[8];
+ if(data == NULL) {
+ DBG("Internal driver error: data is NULL\n");
+ return -EINVAL;
+ }
+ if((err = ReadPacket(cam, buffer, 8)) < 0) {
+ DBG("Error reading command result\n");
+ return err;
+ }
+ memcpy(data, buffer, databytes);
+ } else if(command[0] == DATA_OUT) {
+ if(databytes > 0) {
+ if(data == NULL) {
+ DBG("Internal driver error: data is NULL\n");
+ retval = -EINVAL;
+ } else {
+ if((err=WritePacket(cam, data, databytes)) < 0){
+ DBG("Error writing command data\n");
+ return err;
+ }
+ }
+ }
+ } else {
+ DBG("Unexpected first byte of command: %x\n", command[0]);
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_open
+ *
+ ***************************************************************************/
+static int cpia_pp_open(void *privdata)
+{
+ struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
+
+ if (cam == NULL)
+ return -EINVAL;
+
+ if(cam->open_count == 0) {
+ if (parport_claim(cam->pdev)) {
+ DBG("failed to claim the port\n");
+ return -EBUSY;
+ }
+ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+ parport_data_forward(cam->port);
+ parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
+ udelay(50);
+ parport_write_control(cam->port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
+ }
+
+ ++cam->open_count;
+
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_registerCallback
+ *
+ ***************************************************************************/
+static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
+{
+ struct pp_cam_entry *cam = privdata;
+ int retval = 0;
+
+ if(cam->port->irq != PARPORT_IRQ_NONE) {
+ cam->cb_func = cb;
+ cam->cb_data = cbdata;
+ INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
+ } else {
+ retval = -1;
+ }
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_close
+ *
+ ***************************************************************************/
+static int cpia_pp_close(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+ if (--cam->open_count == 0) {
+ parport_release(cam->pdev);
+ }
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_register
+ *
+ ***************************************************************************/
+static int cpia_pp_register(struct parport *port)
+{
+ struct pardevice *pdev = NULL;
+ struct pp_cam_entry *cam;
+ struct cam_data *cpia;
+
+ if (!(port->modes & PARPORT_MODE_PCSPP)) {
+ LOG("port is not supported by CPiA driver\n");
+ return -ENXIO;
+ }
+
+ cam = kzalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
+ if (cam == NULL) {
+ LOG("failed to allocate camera structure\n");
+ return -ENOMEM;
+ }
+
+ pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
+ NULL, 0, cam);
+
+ if (!pdev) {
+ LOG("failed to parport_register_device\n");
+ kfree(cam);
+ return -ENXIO;
+ }
+
+ cam->pdev = pdev;
+ cam->port = port;
+ init_waitqueue_head(&cam->wq_stream);
+
+ cam->streaming = 0;
+ cam->stream_irq = 0;
+
+ if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
+ LOG("failed to cpia_register_camera\n");
+ parport_unregister_device(pdev);
+ kfree(cam);
+ return -ENXIO;
+ }
+ spin_lock( &cam_list_lock_pp );
+ list_add( &cpia->cam_data_list, &cam_list );
+ spin_unlock( &cam_list_lock_pp );
+
+ return 0;
+}
+
+static void cpia_pp_detach (struct parport *port)
+{
+ struct list_head *tmp;
+ struct cam_data *cpia = NULL;
+ struct pp_cam_entry *cam;
+
+ spin_lock( &cam_list_lock_pp );
+ list_for_each (tmp, &cam_list) {
+ cpia = list_entry(tmp, struct cam_data, cam_data_list);
+ cam = (struct pp_cam_entry *) cpia->lowlevel_data;
+ if (cam && cam->port->number == port->number) {
+ list_del(&cpia->cam_data_list);
+ break;
+ }
+ cpia = NULL;
+ }
+ spin_unlock( &cam_list_lock_pp );
+
+ if (!cpia) {
+ DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
+ return;
+ }
+
+ cam = (struct pp_cam_entry *) cpia->lowlevel_data;
+ cpia_unregister_camera(cpia);
+ if(cam->open_count > 0)
+ cpia_pp_close(cam);
+ parport_unregister_device(cam->pdev);
+ cpia->lowlevel_data = NULL;
+ kfree(cam);
+}
+
+static void cpia_pp_attach (struct parport *port)
+{
+ unsigned int i;
+
+ switch (parport_nr[0])
+ {
+ case PPCPIA_PARPORT_UNSPEC:
+ case PPCPIA_PARPORT_AUTO:
+ if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
+ port->probe_info[0].cmdset == NULL ||
+ strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
+ return;
+
+ cpia_pp_register(port);
+
+ break;
+
+ default:
+ for (i = 0; i < PARPORT_MAX; ++i) {
+ if (port->number == parport_nr[i]) {
+ cpia_pp_register(port);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+static struct parport_driver cpia_pp_driver = {
+ .name = "cpia_pp",
+ .attach = cpia_pp_attach,
+ .detach = cpia_pp_detach,
+};
+
+static int __init cpia_pp_init(void)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
+ CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
+
+ if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
+ printk(" disabled\n");
+ return 0;
+ }
+
+ spin_lock_init( &cam_list_lock_pp );
+
+ if (parport_register_driver (&cpia_pp_driver)) {
+ LOG ("unable to register with parport\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int __init cpia_init(void)
+{
+ if (parport[0]) {
+ /* The user gave some parameters. Let's see what they were. */
+ if (!strncmp(parport[0], "auto", 4)) {
+ parport_nr[0] = PPCPIA_PARPORT_AUTO;
+ } else {
+ int n;
+ for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
+ if (!strncmp(parport[n], "none", 4)) {
+ parport_nr[n] = PPCPIA_PARPORT_NONE;
+ } else {
+ char *ep;
+ unsigned long r = simple_strtoul(parport[n], &ep, 0);
+ if (ep != parport[n]) {
+ parport_nr[n] = r;
+ } else {
+ LOG("bad port specifier `%s'\n", parport[n]);
+ return -ENODEV;
+ }
+ }
+ }
+ }
+ }
+ return cpia_pp_init();
+}
+
+static void __exit cpia_cleanup(void)
+{
+ parport_unregister_driver(&cpia_pp_driver);
+ return;
+}
+
+module_init(cpia_init);
+module_exit(cpia_cleanup);
diff --git a/drivers/staging/cpia/cpia_usb.c b/drivers/staging/cpia/cpia_usb.c
new file mode 100644
index 000000000000..58d193ff591c
--- /dev/null
+++ b/drivers/staging/cpia/cpia_usb.c
@@ -0,0 +1,640 @@
+/*
+ * cpia_usb CPiA USB driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * Copyright (C) 1999 Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
+ * Copyright (C) 1999, 2000 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_ 1 */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#include "cpia.h"
+
+#define USB_REQ_CPIA_GRAB_FRAME 0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
+#define WAIT_FOR_NEXT_FRAME 0
+#define FORCE_FRAME_UPLOAD 1
+
+#define FRAMES_PER_DESC 10
+#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
+#define CPIA_NUMSBUF 2
+#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
+#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+
+struct cpia_sbuf {
+ char *data;
+ struct urb *urb;
+};
+
+#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
+enum framebuf_status {
+ FRAME_EMPTY,
+ FRAME_READING,
+ FRAME_READY,
+ FRAME_ERROR,
+};
+
+struct framebuf {
+ int length;
+ enum framebuf_status status;
+ u8 data[FRAMEBUF_LEN];
+ struct framebuf *next;
+};
+
+struct usb_cpia {
+ /* Device structure */
+ struct usb_device *dev;
+
+ unsigned char iface;
+ wait_queue_head_t wq_stream;
+
+ int cursbuf; /* Current receiving sbuf */
+ struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
+
+ int streaming;
+ int open;
+ int present;
+ struct framebuf *buffers[3];
+ struct framebuf *curbuff, *workbuff;
+};
+
+static int cpia_usb_open(void *privdata);
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata);
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_usb_streamStart(void *privdata);
+static int cpia_usb_streamStop(void *privdata);
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
+static int cpia_usb_close(void *privdata);
+
+#define ABOUT "USB driver for Vision CPiA based cameras"
+
+static struct cpia_camera_ops cpia_usb_ops = {
+ cpia_usb_open,
+ cpia_usb_registerCallback,
+ cpia_usb_transferCmd,
+ cpia_usb_streamStart,
+ cpia_usb_streamStop,
+ cpia_usb_streamRead,
+ cpia_usb_close,
+ 0,
+ THIS_MODULE
+};
+
+static LIST_HEAD(cam_list);
+static spinlock_t cam_list_lock_usb;
+
+static void cpia_usb_complete(struct urb *urb)
+{
+ int i;
+ char *cdata;
+ struct usb_cpia *ucpia;
+
+ if (!urb || !urb->context)
+ return;
+
+ ucpia = (struct usb_cpia *) urb->context;
+
+ if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
+ return;
+
+ if (ucpia->workbuff->status == FRAME_EMPTY) {
+ ucpia->workbuff->status = FRAME_READING;
+ ucpia->workbuff->length = 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int n = urb->iso_frame_desc[i].actual_length;
+ int st = urb->iso_frame_desc[i].status;
+
+ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ if (st)
+ printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
+
+ if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
+ printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
+ return;
+ }
+
+ if (n) {
+ if ((ucpia->workbuff->length > 0) ||
+ (0x19 == cdata[0] && 0x68 == cdata[1])) {
+ memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
+ ucpia->workbuff->length += n;
+ } else
+ DBG("Ignoring packet!\n");
+ } else {
+ if (ucpia->workbuff->length > 4 &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
+ ucpia->workbuff->status = FRAME_READY;
+ ucpia->curbuff = ucpia->workbuff;
+ ucpia->workbuff = ucpia->workbuff->next;
+ ucpia->workbuff->status = FRAME_EMPTY;
+ ucpia->workbuff->length = 0;
+
+ if (waitqueue_active(&ucpia->wq_stream))
+ wake_up_interruptible(&ucpia->wq_stream);
+ }
+ }
+ }
+
+ /* resubmit */
+ urb->dev = ucpia->dev;
+ if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+ printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
+}
+
+static int cpia_usb_open(void *privdata)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+ struct urb *urb;
+ int ret, retval = 0, fx, err;
+
+ if (!ucpia)
+ return -EINVAL;
+
+ ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!ucpia->sbuf[0].data)
+ return -EINVAL;
+
+ ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!ucpia->sbuf[1].data) {
+ retval = -EINVAL;
+ goto error_0;
+ }
+
+ ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
+ if (ret < 0) {
+ printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
+ retval = -EBUSY;
+ goto error_1;
+ }
+
+ ucpia->buffers[0]->status = FRAME_EMPTY;
+ ucpia->buffers[0]->length = 0;
+ ucpia->buffers[1]->status = FRAME_EMPTY;
+ ucpia->buffers[1]->length = 0;
+ ucpia->buffers[2]->status = FRAME_EMPTY;
+ ucpia->buffers[2]->length = 0;
+ ucpia->curbuff = ucpia->buffers[0];
+ ucpia->workbuff = ucpia->buffers[1];
+
+ /* We double buffer the Iso lists, and also know the polling
+ * interval is every frame (1 == (1 << (bInterval -1))).
+ */
+ urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+ if (!urb) {
+ printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+ retval = -ENOMEM;
+ goto error_1;
+ }
+
+ ucpia->sbuf[0].urb = urb;
+ urb->dev = ucpia->dev;
+ urb->context = ucpia;
+ urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = ucpia->sbuf[0].data;
+ urb->complete = cpia_usb_complete;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->interval = 1;
+ urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+ urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+ urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ }
+
+ urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+ if (!urb) {
+ printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 1\n");
+ retval = -ENOMEM;
+ goto error_urb0;
+ }
+
+ ucpia->sbuf[1].urb = urb;
+ urb->dev = ucpia->dev;
+ urb->context = ucpia;
+ urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = ucpia->sbuf[1].data;
+ urb->complete = cpia_usb_complete;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->interval = 1;
+ urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+ urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+ urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ }
+
+ /* queue the ISO urbs, and resubmit in the completion handler */
+ err = usb_submit_urb(ucpia->sbuf[0].urb, GFP_KERNEL);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
+ err);
+ goto error_urb1;
+ }
+ err = usb_submit_urb(ucpia->sbuf[1].urb, GFP_KERNEL);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
+ err);
+ goto error_urb1;
+ }
+
+ ucpia->streaming = 1;
+ ucpia->open = 1;
+
+ return 0;
+
+error_urb1: /* free urb 1 */
+ usb_free_urb(ucpia->sbuf[1].urb);
+ ucpia->sbuf[1].urb = NULL;
+error_urb0: /* free urb 0 */
+ usb_free_urb(ucpia->sbuf[0].urb);
+ ucpia->sbuf[0].urb = NULL;
+error_1:
+ kfree (ucpia->sbuf[1].data);
+ ucpia->sbuf[1].data = NULL;
+error_0:
+ kfree (ucpia->sbuf[0].data);
+ ucpia->sbuf[0].data = NULL;
+
+ return retval;
+}
+
+//
+// convenience functions
+//
+
+/****************************************************************************
+ *
+ * WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
+{
+ if (!packet)
+ return -EINVAL;
+
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ packet[1] + (packet[0] << 8),
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ packet[2] + (packet[3] << 8),
+ packet[4] + (packet[5] << 8), buf, size, 1000);
+}
+
+/****************************************************************************
+ *
+ * ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
+{
+ if (!packet || size <= 0)
+ return -EINVAL;
+
+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ packet[1] + (packet[0] << 8),
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ packet[2] + (packet[3] << 8),
+ packet[4] + (packet[5] << 8), buf, size, 1000);
+}
+
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+ int err = 0;
+ int databytes;
+ struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
+ struct usb_device *udev = ucpia->dev;
+
+ if (!udev) {
+ DBG("Internal driver error: udev is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!command) {
+ DBG("Internal driver error: command is NULL\n");
+ return -EINVAL;
+ }
+
+ databytes = (((int)command[7])<<8) | command[6];
+
+ if (command[0] == DATA_IN) {
+ u8 buffer[8];
+
+ if (!data) {
+ DBG("Internal driver error: data is NULL\n");
+ return -EINVAL;
+ }
+
+ err = ReadPacket(udev, command, buffer, 8);
+ if (err < 0)
+ return err;
+
+ memcpy(data, buffer, databytes);
+ } else if(command[0] == DATA_OUT)
+ WritePacket(udev, command, data, databytes);
+ else {
+ DBG("Unexpected first byte of command: %x\n", command[0]);
+ err = -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamStart(void *privdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamStop(void *privdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+ struct framebuf *mybuff;
+
+ if (!ucpia || !ucpia->present)
+ return -1;
+
+ if (ucpia->curbuff->status != FRAME_READY)
+ interruptible_sleep_on(&ucpia->wq_stream);
+ else
+ DBG("Frame already waiting!\n");
+
+ mybuff = ucpia->curbuff;
+
+ if (!mybuff)
+ return -1;
+
+ if (mybuff->status != FRAME_READY || mybuff->length < 4) {
+ DBG("Something went wrong!\n");
+ return -1;
+ }
+
+ memcpy(frame, mybuff->data, mybuff->length);
+ mybuff->status = FRAME_EMPTY;
+
+/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
+/* mybuff->length, frame[0], frame[1], */
+/* frame[mybuff->length-4], frame[mybuff->length-3], */
+/* frame[mybuff->length-2], frame[mybuff->length-1]); */
+
+ return mybuff->length;
+}
+
+static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
+{
+ if (!ucpia->streaming)
+ return;
+
+ ucpia->streaming = 0;
+
+ /* Set packet size to 0 */
+ if (try) {
+ int ret;
+
+ ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
+ return;
+ }
+ }
+
+ /* Unschedule all of the iso td's */
+ if (ucpia->sbuf[1].urb) {
+ usb_kill_urb(ucpia->sbuf[1].urb);
+ usb_free_urb(ucpia->sbuf[1].urb);
+ ucpia->sbuf[1].urb = NULL;
+ }
+
+ kfree(ucpia->sbuf[1].data);
+ ucpia->sbuf[1].data = NULL;
+
+ if (ucpia->sbuf[0].urb) {
+ usb_kill_urb(ucpia->sbuf[0].urb);
+ usb_free_urb(ucpia->sbuf[0].urb);
+ ucpia->sbuf[0].urb = NULL;
+ }
+
+ kfree(ucpia->sbuf[0].data);
+ ucpia->sbuf[0].data = NULL;
+}
+
+static int cpia_usb_close(void *privdata)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+
+ if(!ucpia)
+ return -ENODEV;
+
+ ucpia->open = 0;
+
+ /* ucpia->present = 0 protects against trying to reset the
+ * alt setting if camera is physically disconnected while open */
+ cpia_usb_free_resources(ucpia, ucpia->present);
+
+ return 0;
+}
+
+/* Probing and initializing */
+
+static int cpia_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *interface;
+ struct usb_cpia *ucpia;
+ struct cam_data *cam;
+ int ret;
+
+ /* A multi-config CPiA camera? */
+ if (udev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ interface = intf->cur_altsetting;
+
+ printk(KERN_INFO "USB CPiA camera found\n");
+
+ ucpia = kzalloc(sizeof(*ucpia), GFP_KERNEL);
+ if (!ucpia) {
+ printk(KERN_ERR "couldn't kmalloc cpia struct\n");
+ return -ENOMEM;
+ }
+
+ ucpia->dev = udev;
+ ucpia->iface = interface->desc.bInterfaceNumber;
+ init_waitqueue_head(&ucpia->wq_stream);
+
+ ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
+ if (!ucpia->buffers[0]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
+ goto fail_alloc_0;
+ }
+
+ ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
+ if (!ucpia->buffers[1]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
+ goto fail_alloc_1;
+ }
+
+ ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
+ if (!ucpia->buffers[2]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
+ goto fail_alloc_2;
+ }
+
+ ucpia->buffers[0]->next = ucpia->buffers[1];
+ ucpia->buffers[1]->next = ucpia->buffers[2];
+ ucpia->buffers[2]->next = ucpia->buffers[0];
+
+ ret = usb_set_interface(udev, ucpia->iface, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
+ /* goto fail_all; */
+ }
+
+ /* Before register_camera, important */
+ ucpia->present = 1;
+
+ cam = cpia_register_camera(&cpia_usb_ops, ucpia);
+ if (!cam) {
+ LOG("failed to cpia_register_camera\n");
+ goto fail_all;
+ }
+
+ spin_lock( &cam_list_lock_usb );
+ list_add( &cam->cam_data_list, &cam_list );
+ spin_unlock( &cam_list_lock_usb );
+
+ usb_set_intfdata(intf, cam);
+ return 0;
+
+fail_all:
+ vfree(ucpia->buffers[2]);
+ ucpia->buffers[2] = NULL;
+fail_alloc_2:
+ vfree(ucpia->buffers[1]);
+ ucpia->buffers[1] = NULL;
+fail_alloc_1:
+ vfree(ucpia->buffers[0]);
+ ucpia->buffers[0] = NULL;
+fail_alloc_0:
+ kfree(ucpia);
+ return -EIO;
+}
+
+static void cpia_disconnect(struct usb_interface *intf);
+
+static struct usb_device_id cpia_id_table [] = {
+ { USB_DEVICE(0x0553, 0x0002) },
+ { USB_DEVICE(0x0813, 0x0001) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, cpia_id_table);
+MODULE_LICENSE("GPL");
+
+
+static struct usb_driver cpia_driver = {
+ .name = "cpia",
+ .probe = cpia_probe,
+ .disconnect = cpia_disconnect,
+ .id_table = cpia_id_table,
+};
+
+static void cpia_disconnect(struct usb_interface *intf)
+{
+ struct cam_data *cam = usb_get_intfdata(intf);
+ struct usb_cpia *ucpia;
+
+ usb_set_intfdata(intf, NULL);
+ if (!cam)
+ return;
+
+ ucpia = (struct usb_cpia *) cam->lowlevel_data;
+ spin_lock( &cam_list_lock_usb );
+ list_del(&cam->cam_data_list);
+ spin_unlock( &cam_list_lock_usb );
+
+ ucpia->present = 0;
+
+ cpia_unregister_camera(cam);
+ if(ucpia->open)
+ cpia_usb_close(cam->lowlevel_data);
+
+ ucpia->curbuff->status = FRAME_ERROR;
+
+ if (waitqueue_active(&ucpia->wq_stream))
+ wake_up_interruptible(&ucpia->wq_stream);
+
+ ucpia->curbuff = ucpia->workbuff = NULL;
+
+ vfree(ucpia->buffers[2]);
+ ucpia->buffers[2] = NULL;
+
+ vfree(ucpia->buffers[1]);
+ ucpia->buffers[1] = NULL;
+
+ vfree(ucpia->buffers[0]);
+ ucpia->buffers[0] = NULL;
+
+ cam->lowlevel_data = NULL;
+ kfree(ucpia);
+}
+
+static int __init usb_cpia_init(void)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
+ CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
+
+ spin_lock_init(&cam_list_lock_usb);
+ return usb_register(&cpia_driver);
+}
+
+static void __exit usb_cpia_cleanup(void)
+{
+ usb_deregister(&cpia_driver);
+}
+
+
+module_init (usb_cpia_init);
+module_exit (usb_cpia_cleanup);
+
diff --git a/drivers/staging/cx25821/Kconfig b/drivers/staging/cx25821/Kconfig
index 813cb355ac01..1d73334d2a44 100644
--- a/drivers/staging/cx25821/Kconfig
+++ b/drivers/staging/cx25821/Kconfig
@@ -5,7 +5,7 @@ config VIDEO_CX25821
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEO_TVEEPROM
- select VIDEO_IR
+ depends on VIDEO_IR
select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
select VIDEO_CX25840
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c
index bbe36437ac16..2a01dc057b2c 100644
--- a/drivers/staging/cx25821/cx25821-alsa.c
+++ b/drivers/staging/cx25821/cx25821-alsa.c
@@ -629,7 +629,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
* Only boards with eeprom and byte 1 at eeprom=1 have it
*/
-static struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = {
+static const struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = {
{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/staging/cx25821/cx25821-audio-upstream.c
index cdff49f409f2..6f3200666c93 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.c
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.c
@@ -40,8 +40,8 @@ MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
MODULE_LICENSE("GPL");
static int _intr_msk =
- FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | FLD_AUD_SRC_SYNC |
- FLD_AUD_SRC_OPC_ERR;
+ FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | FLD_AUD_SRC_SYNC |
+ FLD_AUD_SRC_OPC_ERR;
int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev,
struct sram_channel *ch,
@@ -506,7 +506,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
{
int i = 0;
u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
dma_addr_t risc_phys_jump_addr;
__le32 *rp;
@@ -608,7 +608,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
if (!dev)
return -1;
- sram_ch = dev->channels[dev->_audio_upstream_channel_select].
+ sram_ch = dev->channels[dev->_audio_upstream_channel_select].
sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
@@ -733,7 +733,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
}
dev->_audio_upstream_channel_select = channel_select;
- sram_ch = dev->channels[channel_select].sram_channels;
+ sram_ch = dev->channels[channel_select].sram_channels;
/* Work queue */
INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
@@ -764,9 +764,8 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
str_length + 1);
/* Default if filename is empty string */
- if (strcmp(dev->input_audiofilename, "") == 0) {
+ if (strcmp(dev->input_audiofilename, "") == 0)
dev->_audiofilename = "/root/audioGOOD.wav";
- }
} else {
str_length = strlen(_defaultAudioName);
dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.h b/drivers/staging/cx25821/cx25821-audio-upstream.h
index ca987addf815..668a4f11e80b 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.h
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.h
@@ -46,11 +46,11 @@
#define USE_RISC_NOOP_AUDIO 1
#ifdef USE_RISC_NOOP_AUDIO
-#define AUDIO_RISC_DMA_BUF_SIZE ( LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
+#define AUDIO_RISC_DMA_BUF_SIZE (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
#endif
#ifndef USE_RISC_NOOP_AUDIO
-#define AUDIO_RISC_DMA_BUF_SIZE ( LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
+#define AUDIO_RISC_DMA_BUF_SIZE (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
#endif
static int _line_size;
diff --git a/drivers/staging/cx25821/cx25821-audio.h b/drivers/staging/cx25821/cx25821-audio.h
index 434b2a312a80..a702a0db21d3 100644
--- a/drivers/staging/cx25821/cx25821-audio.h
+++ b/drivers/staging/cx25821/cx25821-audio.h
@@ -31,18 +31,18 @@
#define NUMBER_OF_PROGRAMS 8
/*
- Max size of the RISC program for a buffer. - worst case is 2 writes per line
- Space is also added for the 4 no-op instructions added on the end.
-*/
+ * Max size of the RISC program for a buffer. - worst case is 2 writes per line
+ * Space is also added for the 4 no-op instructions added on the end.
+ */
#ifndef USE_RISC_NOOP
#define MAX_BUFFER_PROGRAM_SIZE \
- (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4)
+ (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4)
#endif
/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
#ifdef USE_RISC_NOOP
#define MAX_BUFFER_PROGRAM_SIZE \
- (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
+ (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
#endif
/* Sizes of various instructions in bytes. Used when adding instructions. */
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c
index c487c19256b9..ca1eece3df0d 100644
--- a/drivers/staging/cx25821/cx25821-core.c
+++ b/drivers/staging/cx25821/cx25821-core.c
@@ -42,7 +42,7 @@ static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
-static unsigned int cx25821_devcount = 0;
+static unsigned int cx25821_devcount;
static DEFINE_MUTEX(devlist);
LIST_HEAD(cx25821_devlist);
@@ -781,14 +781,14 @@ static void cx25821_shutdown(struct cx25821_dev *dev)
/* Disable Video A/B activity */
for (i = 0; i < VID_CHANNEL_NUM; i++) {
- cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
- cx_write(dev->channels[i].sram_channels->int_msk, 0);
+ cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+ cx_write(dev->channels[i].sram_channels->int_msk, 0);
}
- for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
- i++) {
- cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
- cx_write(dev->channels[i].sram_channels->int_msk, 0);
+ for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+ i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+ cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+ cx_write(dev->channels[i].sram_channels->int_msk, 0);
}
/* Disable Audio activity */
@@ -806,9 +806,9 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
u32 format)
{
if (channel_select <= 7 && channel_select >= 0) {
- cx_write(dev->channels[channel_select].
- sram_channels->pix_frmt, format);
- dev->channels[channel_select].pixel_formats = format;
+ cx_write(dev->channels[channel_select].
+ sram_channels->pix_frmt, format);
+ dev->channels[channel_select].pixel_formats = format;
}
}
@@ -829,7 +829,7 @@ static void cx25821_initialize(struct cx25821_dev *dev)
cx_write(PCI_INT_STAT, 0xffffffff);
for (i = 0; i < VID_CHANNEL_NUM; i++)
- cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
+ cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
cx_write(AUD_A_INT_STAT, 0xffffffff);
cx_write(AUD_B_INT_STAT, 0xffffffff);
@@ -843,22 +843,22 @@ static void cx25821_initialize(struct cx25821_dev *dev)
mdelay(100);
for (i = 0; i < VID_CHANNEL_NUM; i++) {
- cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
- cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
- 1440, 0);
- dev->channels[i].pixel_formats = PIXEL_FRMT_422;
- dev->channels[i].use_cif_resolution = FALSE;
+ cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+ cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
+ 1440, 0);
+ dev->channels[i].pixel_formats = PIXEL_FRMT_422;
+ dev->channels[i].use_cif_resolution = FALSE;
}
/* Probably only affect Downstream */
- for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
- i++) {
- cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+ for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+ i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+ cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
}
- cx25821_sram_channel_setup_audio(dev,
- dev->channels[SRAM_CH08].sram_channels,
- 128, 0);
+ cx25821_sram_channel_setup_audio(dev,
+ dev->channels[SRAM_CH08].sram_channels,
+ 128, 0);
cx25821_gpio_init(dev);
}
@@ -931,8 +931,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
- for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
- dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+ for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+ dev->channels[i].sram_channels = &cx25821_sram_channels[i];
if (dev->nr > 1)
CX25821_INFO("dev->nr > 1!");
@@ -1003,11 +1003,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
cx25821_card_setup(dev);
- if (medusa_video_init(dev) < 0)
- CX25821_ERR("%s() Failed to initialize medusa!\n"
- , __func__);
+ if (medusa_video_init(dev) < 0)
+ CX25821_ERR("%s() Failed to initialize medusa!\n"
+ , __func__);
- cx25821_video_register(dev);
+ cx25821_video_register(dev);
/* register IOCTL device */
dev->ioctl_dev =
@@ -1319,7 +1319,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb, 0, 0);
+ videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
@@ -1342,12 +1342,12 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
for (i = 0; i < VID_CHANNEL_NUM; i++) {
if (pci_status & mask[i]) {
- vid_status = cx_read(dev->channels[i].
- sram_channels->int_stat);
+ vid_status = cx_read(dev->channels[i].
+ sram_channels->int_stat);
if (vid_status)
handled +=
- cx25821_video_irq(dev, i, vid_status);
+ cx25821_video_irq(dev, i, vid_status);
cx_write(PCI_INT_STAT, mask[i]);
}
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/staging/cx25821/cx25821-i2c.c
index e43572e61ece..2b14bcca6897 100644
--- a/drivers/staging/cx25821/cx25821-i2c.c
+++ b/drivers/staging/cx25821/cx25821-i2c.c
@@ -283,7 +283,7 @@ static struct i2c_algorithm cx25821_i2c_algo_template = {
.master_xfer = i2c_xfer,
.functionality = cx25821_functionality,
#ifdef NEED_ALGO_CONTROL
- .algo_control = dummy_algo_control,
+ .algo_control = dummy_algo_control,
#endif
};
diff --git a/drivers/staging/cx25821/cx25821-medusa-reg.h b/drivers/staging/cx25821/cx25821-medusa-reg.h
index f7f33b3e7058..1c1c228352d1 100644
--- a/drivers/staging/cx25821/cx25821-medusa-reg.h
+++ b/drivers/staging/cx25821/cx25821-medusa-reg.h
@@ -443,13 +443,13 @@
/*****************************************************************************/
/* LUMA_CTRL register fields */
#define VDEC_A_BRITE_CTRL 0x1014
-#define VDEC_A_CNTRST_CTRL 0x1015
-#define VDEC_A_PEAK_SEL 0x1016
+#define VDEC_A_CNTRST_CTRL 0x1015
+#define VDEC_A_PEAK_SEL 0x1016
/*****************************************************************************/
/* CHROMA_CTRL register fields */
-#define VDEC_A_USAT_CTRL 0x1018
-#define VDEC_A_VSAT_CTRL 0x1019
-#define VDEC_A_HUE_CTRL 0x101A
+#define VDEC_A_USAT_CTRL 0x1018
+#define VDEC_A_VSAT_CTRL 0x1019
+#define VDEC_A_HUE_CTRL 0x101A
#endif
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index ef9f2b82a860..1e11e0ce2d0a 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -778,9 +778,9 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
int medusa_video_init(struct cx25821_dev *dev)
{
- u32 value = 0, tmp = 0;
- int ret_val = 0;
- int i = 0;
+ u32 value = 0, tmp = 0;
+ int ret_val = 0;
+ int i = 0;
mutex_lock(&dev->lock);
@@ -829,7 +829,7 @@ int medusa_video_init(struct cx25821_dev *dev)
/* select AFE clock to output mode */
value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
value &= 0x83FFFFFF;
- ret_val =
+ ret_val =
cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
value | 0x10000000);
diff --git a/drivers/staging/cx25821/cx25821-reg.h b/drivers/staging/cx25821/cx25821-reg.h
index cfe0f32db377..a3fc25a4dc0b 100644
--- a/drivers/staging/cx25821/cx25821-reg.h
+++ b/drivers/staging/cx25821/cx25821-reg.h
@@ -163,8 +163,8 @@
#define FLD_VID_DST_RISC2 0x00000010
#define FLD_VID_SRC_RISC1 0x00000002
#define FLD_VID_DST_RISC1 0x00000001
-#define FLD_VID_SRC_ERRORS FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF
-#define FLD_VID_DST_ERRORS FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF
+#define FLD_VID_SRC_ERRORS (FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF)
+#define FLD_VID_DST_ERRORS (FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF)
/* ***************************************************************************** */
#define AUD_A_INT_MSK 0x0400C0 /* Audio Int interrupt mask */
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
index d12dbb572e8b..405e2db72b0f 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
@@ -32,17 +32,17 @@
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
MODULE_LICENSE("GPL");
static int _intr_msk =
- FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
+ FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
- __le32 * rp, unsigned int offset,
+ __le32 *rp, unsigned int offset,
unsigned int bpl, u32 sync_line,
unsigned int lines,
int fifo_enable, int field_type)
@@ -53,9 +53,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
if (USE_RISC_NOOP_VIDEO) {
- for (i = 0; i < NUM_NO_OPS; i++) {
+ for (i = 0; i < NUM_NO_OPS; i++)
*(rp++) = cpu_to_le32(RISC_NOOP);
- }
}
/* scan lines */
@@ -75,7 +74,7 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
}
static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
- __le32 * rp,
+ __le32 *rp,
dma_addr_t databuf_phys_addr,
unsigned int offset,
u32 sync_line, unsigned int bpl,
@@ -88,14 +87,12 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
int dist_betwn_starts = bpl * 2;
/* sync instruction */
- if (sync_line != NO_SYNC_LINE) {
+ if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
- }
if (USE_RISC_NOOP_VIDEO) {
- for (i = 0; i < NUM_NO_OPS; i++) {
+ for (i = 0; i < NUM_NO_OPS; i++)
*(rp++) = cpu_to_le32(RISC_NOOP);
- }
}
/* scan lines */
@@ -133,7 +130,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
{
__le32 *rp;
int fifo_enable = 0;
- int singlefield_lines = lines >> 1; /*get line count for single field */
+ int singlefield_lines = lines >> 1; /*get line count for single field */
int odd_num_lines = singlefield_lines;
int frame = 0;
int frame_size = 0;
@@ -218,15 +215,15 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
("cx25821: No video file is currently running so return!\n");
return;
}
- /* Disable RISC interrupts */
+ /* Disable RISC interrupts */
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
- /* Turn OFF risc and fifo */
+ /* Turn OFF risc and fifo */
tmp = cx_read(sram_ch->dma_ctl);
cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
- /* Clear data buffer memory */
+ /* Clear data buffer memory */
if (dev->_data_buf_virt_addr_ch2)
memset(dev->_data_buf_virt_addr_ch2, 0,
dev->_data_buf_size_ch2);
@@ -250,9 +247,8 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev)
{
- if (dev->_is_running_ch2) {
+ if (dev->_is_running_ch2)
cx25821_stop_upstream_video_ch2(dev);
- }
if (dev->_dma_virt_addr_ch2) {
pci_free_consistent(dev->pci, dev->_risc_size_ch2,
@@ -303,11 +299,10 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
file_offset = dev->_frame_count_ch2 * frame_size;
myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
-
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk("%s(): ERROR opening file(%s) with errno = %d! \n",
- __func__, dev->_filename_ch2, open_errno);
+ printk("%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename_ch2, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
@@ -371,8 +366,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
container_of(work, struct cx25821_dev, _irq_work_entry_ch2);
if (!dev) {
- printk("ERROR %s(): since container_of(work_struct) FAILED! \n",
- __func__);
+ printk("ERROR %s(): since container_of(work_struct) FAILED!\n",
+ __func__);
return;
}
@@ -398,8 +393,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk("%s(): ERROR opening file(%s) with errno = %d! \n",
- __func__, dev->_filename_ch2, open_errno);
+ printk("%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename_ch2, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
@@ -450,9 +445,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (i > 0)
dev->_frame_count_ch2++;
- if (vfs_read_retval < line_size) {
+ if (vfs_read_retval < line_size)
break;
- }
}
dev->_file_status_ch2 =
@@ -494,7 +488,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
return -ENOMEM;
}
- /* Iniitize at this address until n bytes to 0 */
+ /* Iniitize at this address until n bytes to 0 */
memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
if (dev->_data_buf_virt_addr_ch2 != NULL) {
@@ -502,7 +496,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_data_buf_virt_addr_ch2,
dev->_data_buf_phys_addr_ch2);
}
- /* For Video Data buffer allocation */
+ /* For Video Data buffer allocation */
dev->_data_buf_virt_addr_ch2 =
pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
&data_dma_addr);
@@ -515,26 +509,26 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
return -ENOMEM;
}
- /* Initialize at this address until n bytes to 0 */
+ /* Initialize at this address until n bytes to 0 */
memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
ret = cx25821_openfile_ch2(dev, sram_ch);
if (ret < 0)
return ret;
- /* Creating RISC programs */
+ /* Creating RISC programs */
ret =
cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
dev->_lines_count_ch2);
if (ret < 0) {
printk(KERN_INFO
- "cx25821: Failed creating Video Upstream Risc programs! \n");
+ "cx25821: Failed creating Video Upstream Risc programs!\n");
goto error;
}
return 0;
- error:
+ error:
return ret;
}
@@ -542,7 +536,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
u32 status)
{
u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
int singlefield_lines = NTSC_FIELD_HEIGHT;
int line_size_in_bytes = Y422_LINE_SZ;
int odd_risc_prog_size = 0;
@@ -550,13 +544,13 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
__le32 *rp;
if (status & FLD_VID_SRC_RISC1) {
- /* We should only process one program per call */
+ /* We should only process one program per call */
u32 prog_cnt = cx_read(channel->gpcnt);
- /*
- Since we've identified our IRQ, clear our bits from the
- interrupt mask and interrupt status registers
- */
+ /*
+ * Since we've identified our IRQ, clear our bits from the
+ * interrupt mask and interrupt status registers
+ */
int_msk_tmp = cx_read(channel->int_msk);
cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
cx_write(channel->int_stat, _intr_msk);
@@ -612,7 +606,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
dev->_frame_count_ch2);
return -1;
}
- /* ElSE, set the interrupt mask register, re-enable irq. */
+ /* ElSE, set the interrupt mask register, re-enable irq. */
int_msk_tmp = cx_read(channel->int_msk);
cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
@@ -631,24 +625,22 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
return -1;
channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
-
- sram_ch = dev->channels[channel_num].sram_channels;
+ sram_ch = dev->channels[channel_num].sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
- /* Only deal with our interrupt */
+ /* Only deal with our interrupt */
if (vid_status) {
handled =
cx25821_video_upstream_irq_ch2(dev, channel_num,
vid_status);
}
- if (handled < 0) {
+ if (handled < 0)
cx25821_stop_upstream_video_ch2(dev);
- } else {
+ else
handled += handled;
- }
return IRQ_RETVAL(handled);
}
@@ -667,22 +659,21 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
value |= dev->_isNTSC_ch2 ? 0 : 0x10;
cx_write(ch->vid_fmt_ctl, value);
- /*
- set number of active pixels in each line. Default is 720
- pixels in both NTSC and PAL format
- */
+ /*
+ * set number of active pixels in each line. Default is 720
+ * pixels in both NTSC and PAL format
+ */
cx_write(ch->vid_active_ctl1, width);
num_lines = (height / 2) & 0x3FF;
odd_num_lines = num_lines;
- if (dev->_isNTSC_ch2) {
+ if (dev->_isNTSC_ch2)
odd_num_lines += 1;
- }
value = (num_lines << 16) | odd_num_lines;
- /* set number of active lines in field 0 (top) and field 1 (bottom) */
+ /* set number of active lines in field 0 (top) and field 1 (bottom) */
cx_write(ch->vid_active_ctl2, value);
cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
@@ -694,27 +685,27 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
u32 tmp = 0;
int err = 0;
- /*
- 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
- for channel A-C
- */
+ /*
+ * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
+ * for channel A-C
+ */
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
- /*
- Set the physical start address of the RISC program in the initial
- program counter(IPC) member of the cmds.
- */
+ /*
+ * Set the physical start address of the RISC program in the initial
+ * program counter(IPC) member of the cmds.
+ */
cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
- cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
+ cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
/* reset counter */
cx_write(sram_ch->gpcnt_ctl, 3);
- /* Clear our bits from the interrupt status register. */
+ /* Clear our bits from the interrupt status register. */
cx_write(sram_ch->int_stat, _intr_msk);
- /* Set the interrupt mask register, enable irq. */
+ /* Set the interrupt mask register, enable irq. */
cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -727,7 +718,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
dev->pci->irq);
goto fail_irq;
}
- /* Start the DMA engine */
+ /* Start the DMA engine */
tmp = cx_read(sram_ch->dma_ctl);
cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
@@ -736,7 +727,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
return 0;
- fail_irq:
+ fail_irq:
cx25821_dev_unregister(dev);
return err;
}
@@ -758,7 +749,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
}
dev->_channel2_upstream_select = channel_select;
- sram_ch = dev->channels[channel_select].sram_channels;
+ sram_ch = dev->channels[channel_select].sram_channels;
INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
dev->_irq_queues_ch2 =
@@ -769,10 +760,10 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
return -ENOMEM;
}
- /*
- 656/VIP SRC Upstream Channel I & J and 7 -
- Host Bus Interface for channel A-C
- */
+ /*
+ * 656/VIP SRC Upstream Channel I & J and 7 -
+ * Host Bus Interface for channel A-C
+ */
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
@@ -808,7 +799,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
str_length + 1);
}
- /* Default if filename is empty string */
+ /* Default if filename is empty string */
if (strcmp(dev->input_filename_ch2, "") == 0) {
if (dev->_isNTSC_ch2) {
dev->_filename_ch2 =
@@ -833,7 +824,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
dev->upstream_databuf_size_ch2 = data_frame_size * 2;
- /* Allocating buffers and prepare RISC program */
+ /* Allocating buffers and prepare RISC program */
retval =
cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
dev->_line_size_ch2);
@@ -848,7 +839,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
return 0;
- error:
+ error:
cx25821_dev_unregister(dev);
return err;
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
index 62340636c916..029e8305724b 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
@@ -88,14 +88,14 @@
#endif
#ifndef USE_RISC_NOOP_VIDEO
-#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define PAL_RISC_BUF_SIZE ( 2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE) )
+#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define PAL_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE))
#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
-#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
+ RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
+#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE) )
+#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+ RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
#endif
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/staging/cx25821/cx25821-video-upstream.c
index 756a820a76cb..16bf74d65912 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream.c
@@ -39,7 +39,7 @@ MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
MODULE_LICENSE("GPL");
static int _intr_msk =
- FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
+ FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR;
int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
struct sram_channel *ch,
@@ -346,13 +346,13 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR
+ printk(KERN_ERR
"%s(): ERROR opening file(%s) with errno = %d!\n",
__func__, dev->_filename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR
+ printk(KERN_ERR
"%s: File has no file operations registered!",
__func__);
filp_close(myfile, NULL);
@@ -360,7 +360,7 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
}
if (!myfile->f_op->read) {
- printk(KERN_ERR
+ printk(KERN_ERR
"%s: File has no READ operations registered!",
__func__);
filp_close(myfile, NULL);
@@ -415,7 +415,7 @@ static void cx25821_vidups_handler(struct work_struct *work)
container_of(work, struct cx25821_dev, _irq_work_entry);
if (!dev) {
- printk(KERN_ERR
+ printk(KERN_ERR
"ERROR %s(): since container_of(work_struct) FAILED!\n",
__func__);
return;
@@ -448,7 +448,7 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR
+ printk(KERN_ERR
"%s: File has no file operations registered!",
__func__);
filp_close(myfile, NULL);
@@ -456,7 +456,7 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
}
if (!myfile->f_op->read) {
- printk(KERN_ERR
+ printk(KERN_ERR
"%s: File has no READ operations registered! \
Returning.",
__func__);
@@ -589,7 +589,7 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
u32 status)
{
u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
int singlefield_lines = NTSC_FIELD_HEIGHT;
int line_size_in_bytes = Y422_LINE_SZ;
int odd_risc_prog_size = 0;
@@ -657,12 +657,12 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
Interrupt!\n", __func__);
if (status & FLD_VID_SRC_SYNC)
- printk(KERN_ERR "%s: Video Received Sync Error \
- Interrupt!\n", __func__);
+ printk(KERN_ERR "%s: Video Received Sync Error \
+ Interrupt!\n", __func__);
if (status & FLD_VID_SRC_OPC_ERR)
- printk(KERN_ERR "%s: Video Received OpCode Error \
- Interrupt!\n", __func__);
+ printk(KERN_ERR "%s: Video Received OpCode Error \
+ Interrupt!\n", __func__);
}
if (dev->_file_status == END_OF_FILE) {
@@ -690,7 +690,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
- sram_ch = dev->channels[channel_num].sram_channels;
+ sram_ch = dev->channels[channel_num].sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
@@ -811,7 +811,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
}
dev->_channel_upstream_select = channel_select;
- sram_ch = dev->channels[channel_select].sram_channels;
+ sram_ch = dev->channels[channel_select].sram_channels;
INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.h b/drivers/staging/cx25821/cx25821-video-upstream.h
index 10dee5c24a81..f0b3ac0880ad 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream.h
@@ -97,13 +97,13 @@
#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE)
#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+ RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
-#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE )
+#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-#define NTSC_RISC_BUF_SIZE ( 2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE) )
+#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE )
+ RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
#endif
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index 1d5e8796d383..e7f1d5778cec 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -856,7 +856,7 @@ static int video_open(struct file *file)
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
+ sizeof(struct cx25821_buffer), fh, NULL);
dprintk(1, "post videobuf_queue_init()\n");
unlock_kernel();
@@ -993,6 +993,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct cx25821_fh *fh = priv;
struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ struct v4l2_mbus_framefmt mbus_fmt;
int err;
int pix_format = PIXEL_FRMT_422;
@@ -1039,7 +1040,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
return 0;
}
diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h
index 1b628f61578a..c94000125782 100644
--- a/drivers/staging/cx25821/cx25821.h
+++ b/drivers/staging/cx25821/cx25821.h
@@ -91,10 +91,10 @@
/* Currently supported by the driver */
#define CX25821_NORMS (\
- V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \
- V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
- V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_H | \
- V4L2_STD_PAL_Nc )
+ V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \
+ V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_H | \
+ V4L2_STD_PAL_Nc)
#define CX25821_BOARD_CONEXANT_ATHENA10 1
#define MAX_VID_CHANNEL_NUM 12
@@ -139,7 +139,7 @@ struct cx25821_fh {
/* video capture */
struct cx25821_fmt *fmt;
unsigned int width, height;
- int channel_id;
+ int channel_id;
/* vbi capture */
struct videobuf_queue vidq;
@@ -238,26 +238,25 @@ struct cx25821_data {
};
struct cx25821_channel {
- struct v4l2_prio_state prio;
+ struct v4l2_prio_state prio;
- int ctl_bright;
- int ctl_contrast;
- int ctl_hue;
- int ctl_saturation;
+ int ctl_bright;
+ int ctl_contrast;
+ int ctl_hue;
+ int ctl_saturation;
+ struct cx25821_data timeout_data;
- struct cx25821_data timeout_data;
+ struct video_device *video_dev;
+ struct cx25821_dmaqueue vidq;
- struct video_device *video_dev;
- struct cx25821_dmaqueue vidq;
+ struct sram_channel *sram_channels;
- struct sram_channel *sram_channels;
-
- struct mutex lock;
- int resources;
+ struct mutex lock;
+ int resources;
- int pixel_formats;
- int use_cif_resolution;
- int cif_width;
+ int pixel_formats;
+ int use_cif_resolution;
+ int cif_width;
};
struct cx25821_dev {
@@ -283,7 +282,7 @@ struct cx25821_dev {
int nr;
struct mutex lock;
- struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+ struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
/* board details */
unsigned int board;
@@ -311,7 +310,7 @@ struct cx25821_dev {
int _audio_lines_count;
int _audioframe_count;
int _audio_upstream_channel_select;
- int _last_index_irq; /* The last interrupt index processed. */
+ int _last_index_irq; /* The last interrupt index processed. */
__le32 *_risc_audio_jmp_addr;
__le32 *_risc_virt_start_addr;
@@ -443,7 +442,7 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
}
#define cx25821_call_all(dev, o, f, args...) \
- v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
+ v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
extern struct list_head cx25821_devlist;
extern struct cx25821_board cx25821_boards[];
@@ -491,7 +490,7 @@ struct sram_channel {
u32 fld_aud_fifo_en;
u32 fld_aud_risc_en;
- /* For Upstream Video */
+ /* For Upstream Video */
u32 vid_fmt_ctl;
u32 vid_active_ctl1;
u32 vid_active_ctl2;
@@ -511,8 +510,8 @@ extern struct sram_channel cx25821_sram_channels[];
#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2))
#define cx_andor(reg, mask, value) \
- writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
- ((value) & (mask)), dev->lmmio+((reg)>>2))
+ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+((reg)>>2))
#define cx_set(reg, bit) cx_andor((reg), (bit), (bit))
#define cx_clear(reg, bit) cx_andor((reg), (bit), 0)
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c
index fd48b38e797c..b996697e7eb2 100644
--- a/drivers/staging/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/dt3155v4l/dt3155v4l.c
@@ -293,7 +293,7 @@ static void
dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
if (vb->state == VIDEOBUF_ACTIVE)
- videobuf_waiton(vb, 0, 0); /* FIXME: cannot be interrupted */
+ videobuf_waiton(q, vb, 0, 0); /* FIXME: cannot be interrupted */
videobuf_dma_contig_free(q, vb);
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -440,7 +440,7 @@ dt3155_open(struct file *filp)
videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops,
&pd->pdev->dev, &pd->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), pd);
+ sizeof(struct videobuf_buffer), pd, NULL);
/* disable all irqs, clear all irq flags */
iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
pd->regs + INT_CSR);
@@ -494,7 +494,7 @@ dt3155_release(struct file *filp)
tmp = pd->curr_buf;
spin_unlock_irqrestore(&pd->lock, flags);
if (tmp)
- videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+ videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
dt3155_stop_acq(pd);
videobuf_stop(pd->vidq);
pd->acq_fp = NULL;
@@ -603,7 +603,7 @@ dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
tmp = pd->curr_buf;
spin_unlock_irqrestore(&pd->lock, flags);
if (tmp)
- videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+ videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
return ret;
}
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
index 75fa46805527..3aecd30f0d1e 100644
--- a/drivers/staging/go7007/Kconfig
+++ b/drivers/staging/go7007/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_GO7007
depends on BKL # please fix
depends on SND
select VIDEOBUF_DMA_SG
- select VIDEO_IR
+ depends on VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
select SND_PCM
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index 372a7c6791ca..b3f42f37a313 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -194,51 +194,15 @@ int go7007_reset_encoder(struct go7007 *go)
* Attempt to instantiate an I2C client by ID, probably loading a module.
*/
static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
- int id, int addr)
+ int addr)
{
struct go7007 *go = i2c_get_adapdata(adapter);
struct v4l2_device *v4l2_dev = &go->v4l2_dev;
- char *modname;
- switch (id) {
- case I2C_DRIVERID_WIS_SAA7115:
- modname = "wis-saa7115";
- break;
- case I2C_DRIVERID_WIS_SAA7113:
- modname = "wis-saa7113";
- break;
- case I2C_DRIVERID_WIS_UDA1342:
- modname = "wis-uda1342";
- break;
- case I2C_DRIVERID_WIS_SONY_TUNER:
- modname = "wis-sony-tuner";
- break;
- case I2C_DRIVERID_WIS_TW9903:
- modname = "wis-tw9903";
- break;
- case I2C_DRIVERID_WIS_TW2804:
- modname = "wis-tw2804";
- break;
- case I2C_DRIVERID_WIS_OV7640:
- modname = "wis-ov7640";
- break;
- case I2C_DRIVERID_S2250:
- modname = "s2250";
- break;
- default:
- modname = NULL;
- break;
- }
-
- if (v4l2_i2c_new_subdev(v4l2_dev, adapter, modname, type, addr, NULL))
+ if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL))
return 0;
- if (modname != NULL)
- printk(KERN_INFO
- "go7007: probing for module %s failed\n", modname);
- else
- printk(KERN_INFO
- "go7007: sensor %u seems to be unsupported!\n", id);
+ printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
return -1;
}
@@ -277,7 +241,6 @@ int go7007_register_encoder(struct go7007 *go)
for (i = 0; i < go->board_info->num_i2c_devs; ++i)
init_i2c_module(&go->i2c_adapter,
go->board_info->i2c_devs[i].type,
- go->board_info->i2c_devs[i].id,
go->board_info->i2c_devs[i].addr);
if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
i2c_clients_command(&go->i2c_adapter,
@@ -393,7 +356,8 @@ static void write_bitmap_word(struct go7007 *go)
for (i = 0; i < 16; ++i) {
y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
- go->active_map[stride * y + (x >> 3)] |=
+ if (stride * y + (x >> 3) < sizeof(go->active_map))
+ go->active_map[stride * y + (x >> 3)] |=
(go->modet_word & 1) << (x & 0x7);
go->modet_word >>= 1;
}
@@ -485,6 +449,15 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
}
break;
case STATE_00_00_01:
+ if (buf[i] == 0xF8 && go->modet_enable == 0) {
+ /* MODET start code, but MODET not enabled */
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x01);
+ store_byte(go->active_buf, 0xF8);
+ go->state = STATE_DATA;
+ break;
+ }
/* If this is the start of a new MPEG frame,
* get a new buffer */
if ((go->format == GO7007_FORMAT_MPEG1 ||
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
index 20ed930b588c..bea9f4d5bc3c 100644
--- a/drivers/staging/go7007/go7007-usb.c
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -394,7 +394,7 @@ static struct go7007_usb_board board_adlink_mpg24 = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_twTW2804",
+ .type = "wis_tw2804",
.id = I2C_DRIVERID_WIS_TW2804,
.addr = 0x00, /* yes, really */
},
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
index 46b4b9f6855b..2b27d8da70a2 100644
--- a/drivers/staging/go7007/go7007-v4l2.c
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -252,23 +252,22 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
go->modet_map[i] = 0;
if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
- struct v4l2_format res;
+ struct v4l2_mbus_framefmt mbus_fmt;
- if (fmt != NULL) {
- res = *fmt;
- } else {
- res.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- res.fmt.pix.width = width;
- }
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ if (fmt != NULL)
+ mbus_fmt.width = fmt->fmt.pix.width;
+ else
+ mbus_fmt.width = width;
if (height > sensor_height / 2) {
- res.fmt.pix.height = height / 2;
+ mbus_fmt.height = height / 2;
go->encoder_v_halve = 0;
} else {
- res.fmt.pix.height = height;
+ mbus_fmt.height = height;
go->encoder_v_halve = 1;
}
- call_all(&go->v4l2_dev, video, s_fmt, &res);
+ call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt);
} else {
if (width <= sensor_width / 4) {
go->encoder_h_halve = 1;
diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/go7007/s2250-board.c
index 93f26048e3b4..e7736a915530 100644
--- a/drivers/staging/go7007/s2250-board.c
+++ b/drivers/staging/go7007/s2250-board.c
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/v4l2-subdev.h>
#include "go7007-priv.h"
@@ -479,12 +478,13 @@ static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return 0;
}
-static int s2250_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int s2250_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
{
struct s2250 *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (fmt->fmt.pix.height < 640) {
+ if (fmt->height < 640) {
write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);
write_reg_fp(client, 0x140, 0x060);
} else {
@@ -555,7 +555,7 @@ static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
static const struct v4l2_subdev_video_ops s2250_video_ops = {
.s_routing = s2250_s_video_routing,
- .s_fmt = s2250_s_fmt,
+ .s_mbus_fmt = s2250_s_mbus_fmt,
};
static const struct v4l2_subdev_ops s2250_ops = {
@@ -674,9 +674,25 @@ static const struct i2c_device_id s2250_id[] = {
};
MODULE_DEVICE_TABLE(i2c, s2250_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "s2250",
- .probe = s2250_probe,
- .remove = s2250_remove,
- .id_table = s2250_id,
+static struct i2c_driver s2250_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s2250",
+ },
+ .probe = s2250_probe,
+ .remove = s2250_remove,
+ .id_table = s2250_id,
};
+
+static __init int init_s2250(void)
+{
+ return i2c_add_driver(&s2250_driver);
+}
+
+static __exit void exit_s2250(void)
+{
+ i2c_del_driver(&s2250_driver);
+}
+
+module_init(init_s2250);
+module_exit(exit_s2250);
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
index 4f0cbdde2765..6bc9470fecb6 100644
--- a/drivers/staging/go7007/wis-ov7640.c
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -81,6 +81,7 @@ static const struct i2c_device_id wis_ov7640_id[] = {
{ "wis_ov7640", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);
static struct i2c_driver wis_ov7640_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index 72f5c1f56d19..05e0e1083864 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -308,6 +308,7 @@ static const struct i2c_device_id wis_saa7113_id[] = {
{ "wis_saa7113", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
static struct i2c_driver wis_saa7113_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index cd950b61cf70..46cff59e28b7 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -441,6 +441,7 @@ static const struct i2c_device_id wis_saa7115_id[] = {
{ "wis_saa7115", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
static struct i2c_driver wis_saa7115_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 981c9b311b8b..8f1b7d4f6a2e 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -692,6 +692,7 @@ static const struct i2c_device_id wis_sony_tuner_id[] = {
{ "wis_sony_tuner", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
static struct i2c_driver wis_sony_tuner_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index ee28a99dc388..5b218c55842a 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -331,6 +331,7 @@ static const struct i2c_device_id wis_tw2804_id[] = {
{ "wis_tw2804", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
static struct i2c_driver wis_tw2804_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index 80d47269b1c0..9230f4a80529 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -313,6 +313,7 @@ static const struct i2c_device_id wis_tw9903_id[] = {
{ "wis_tw9903", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);
static struct i2c_driver wis_tw9903_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
index 5c4eb49d7357..0127be2f3be0 100644
--- a/drivers/staging/go7007/wis-uda1342.c
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -86,6 +86,7 @@ static const struct i2c_device_id wis_uda1342_id[] = {
{ "wis_uda1342", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);
static struct i2c_driver wis_uda1342_driver = {
.driver = {
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
index 100c4d4b8125..fa790db75d7e 100644
--- a/drivers/staging/lirc/Kconfig
+++ b/drivers/staging/lirc/Kconfig
@@ -53,7 +53,7 @@ config LIRC_ITE8709
config LIRC_PARALLEL
tristate "Homebrew Parallel Port Receiver"
- depends on LIRC_STAGING && PARPORT && !SMP
+ depends on LIRC_STAGING && PARPORT
help
Driver for Homebrew Parallel Port Receivers
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c
index bce600ede263..0dc2c2b22c2b 100644
--- a/drivers/staging/lirc/lirc_igorplugusb.c
+++ b/drivers/staging/lirc/lirc_igorplugusb.c
@@ -54,10 +54,10 @@
/* module identification */
-#define DRIVER_VERSION "0.1"
+#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR \
"Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
-#define DRIVER_DESC "USB remote driver for LIRC"
+#define DRIVER_DESC "Igorplug USB remote driver for LIRC"
#define DRIVER_NAME "lirc_igorplugusb"
/* debugging support */
@@ -201,7 +201,6 @@ struct igorplug {
/* usb */
struct usb_device *usbdev;
- struct urb *urb_in;
int devnum;
unsigned char *buf_in;
@@ -216,28 +215,36 @@ struct igorplug {
/* handle sending (init strings) */
int send_flags;
- wait_queue_head_t wait_out;
};
static int unregister_from_lirc(struct igorplug *ir)
{
- struct lirc_driver *d = ir->d;
+ struct lirc_driver *d;
int devnum;
- if (!ir->d)
+ if (!ir) {
+ printk(KERN_ERR "%s: called with NULL device struct!\n",
+ __func__);
return -EINVAL;
+ }
devnum = ir->devnum;
- dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+ d = ir->d;
- lirc_unregister_driver(d->minor);
+ if (!d) {
+ printk(KERN_ERR "%s: called with NULL lirc driver struct!\n",
+ __func__);
+ return -EINVAL;
+ }
- printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+ dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
+ lirc_unregister_driver(d->minor);
kfree(d);
ir->d = NULL;
kfree(ir);
- return 0;
+
+ return devnum;
}
static int set_use_inc(void *data)
@@ -248,6 +255,7 @@ static int set_use_inc(void *data)
printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
return -EIO;
}
+
dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
if (!ir->usbdev)
@@ -264,9 +272,29 @@ static void set_use_dec(void *data)
printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
return;
}
+
dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
}
+static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
+ int i, int max)
+{
+ int code;
+
+ /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+ while (i < max) {
+ /* 1 Igor-tick = 85.333333 us */
+ code = (unsigned int)ir->buf_in[i] * 85 +
+ (unsigned int)ir->buf_in[i] / 3;
+ ir->last_time.tv_usec += code;
+ if (ir->in_space)
+ code |= PULSE_BIT;
+ lirc_buffer_write(buf, (unsigned char *)&code);
+ /* 1 chunk = CODE_LENGTH bytes */
+ ir->in_space ^= 1;
+ ++i;
+ }
+}
/**
* Called in user context.
@@ -274,41 +302,32 @@ static void set_use_dec(void *data)
* -ENODATA if none was available. This should add some number of bits
* evenly divisible by code_length to the buffer
*/
-static int usb_remote_poll(void *data, struct lirc_buffer *buf)
+static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
{
int ret;
struct igorplug *ir = (struct igorplug *)data;
- if (!ir->usbdev) /* Has the device been removed? */
+ if (!ir || !ir->usbdev) /* Has the device been removed? */
return -ENODEV;
memset(ir->buf_in, 0, ir->len_in);
- ret = usb_control_msg(
- ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
- GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,
- 0/* offset */, /*unused*/0,
- ir->buf_in, ir->len_in,
- /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,
+ 0/* offset */, /*unused*/0,
+ ir->buf_in, ir->len_in,
+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
if (ret > 0) {
- int i = DEVICE_HEADERLEN;
int code, timediff;
struct timeval now;
- if (ret <= 1) /* ACK packet has 1 byte --> ignore */
+ /* ACK packet has 1 byte --> ignore */
+ if (ret < DEVICE_HEADERLEN)
return -ENODATA;
dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
- if (ir->buf_in[2] != 0) {
- printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
- ir->devnum);
- /* start at earliest byte */
- i = DEVICE_HEADERLEN + ir->buf_in[2];
- /* where are we now? space, gap or pulse? */
- }
-
do_gettimeofday(&now);
timediff = now.tv_sec - ir->last_time.tv_sec;
if (timediff + 1 > PULSE_MASK / 1000000)
@@ -325,18 +344,20 @@ static int usb_remote_poll(void *data, struct lirc_buffer *buf)
lirc_buffer_write(buf, (unsigned char *)&code);
ir->in_space = 1; /* next comes a pulse */
- /* MODE2: pulse/space (PULSE_BIT) in 1us units */
-
- while (i < ret) {
- /* 1 Igor-tick = 85.333333 us */
- code = (unsigned int)ir->buf_in[i] * 85
- + (unsigned int)ir->buf_in[i] / 3;
- if (ir->in_space)
- code |= PULSE_BIT;
- lirc_buffer_write(buf, (unsigned char *)&code);
- /* 1 chunk = CODE_LENGTH bytes */
- ir->in_space ^= 1;
- ++i;
+ if (ir->buf_in[2] == 0)
+ send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
+ else {
+ printk(KERN_WARNING DRIVER_NAME
+ "[%d]: Device buffer overrun.\n", ir->devnum);
+ /* HHHNNNNNNNNNNNOOOOOOOO H = header
+ <---[2]---> N = newer
+ <---------ret--------> O = older */
+ ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
+ /* keep even-ness to not desync pulse/pause */
+ send_fragment(ir, buf, DEVICE_HEADERLEN +
+ ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
+ send_fragment(ir, buf, DEVICE_HEADERLEN,
+ DEVICE_HEADERLEN + ir->buf_in[2]);
}
ret = usb_control_msg(
@@ -358,12 +379,12 @@ static int usb_remote_poll(void *data, struct lirc_buffer *buf)
-static int usb_remote_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+static int igorplugusb_remote_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
struct usb_device *dev = NULL;
struct usb_host_interface *idesc = NULL;
- struct usb_host_endpoint *ep_ctl2;
+ struct usb_endpoint_descriptor *ep;
struct igorplug *ir = NULL;
struct lirc_driver *driver = NULL;
int devnum, pipe, maxp;
@@ -380,20 +401,21 @@ static int usb_remote_probe(struct usb_interface *intf,
if (idesc->desc.bNumEndpoints != 1)
return -ENODEV;
- ep_ctl2 = idesc->endpoint;
- if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+
+ ep = &idesc->endpoint->desc;
+ if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
!= USB_DIR_IN)
- || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
return -ENODEV;
- pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+
+ pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
devnum = dev->devnum;
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n",
+ dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
devnum, CODE_LENGTH, maxp);
-
mem_failure = 0;
ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
if (!ir) {
@@ -406,9 +428,8 @@ static int usb_remote_probe(struct usb_interface *intf,
goto mem_failure_switch;
}
- ir->buf_in = usb_alloc_coherent(dev,
- DEVICE_BUFLEN+DEVICE_HEADERLEN,
- GFP_ATOMIC, &ir->dma_in);
+ ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
+ GFP_ATOMIC, &ir->dma_in);
if (!ir->buf_in) {
mem_failure = 3;
goto mem_failure_switch;
@@ -424,12 +445,10 @@ static int usb_remote_probe(struct usb_interface *intf,
driver->set_use_inc = &set_use_inc;
driver->set_use_dec = &set_use_dec;
driver->sample_rate = sample_rate; /* per second */
- driver->add_to_buf = &usb_remote_poll;
+ driver->add_to_buf = &igorplugusb_remote_poll;
driver->dev = &intf->dev;
driver->owner = THIS_MODULE;
- init_waitqueue_head(&ir->wait_out);
-
minor = lirc_register_driver(driver);
if (minor < 0)
mem_failure = 9;
@@ -438,7 +457,7 @@ mem_failure_switch:
switch (mem_failure) {
case 9:
- usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+ usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
ir->buf_in, ir->dma_in);
case 3:
kfree(driver);
@@ -454,7 +473,7 @@ mem_failure_switch:
ir->d = driver;
ir->devnum = devnum;
ir->usbdev = dev;
- ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+ ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
ir->in_space = 1; /* First mode2 event is a space. */
do_gettimeofday(&ir->last_time);
@@ -484,63 +503,64 @@ mem_failure_switch:
}
-static void usb_remote_disconnect(struct usb_interface *intf)
+static void igorplugusb_remote_disconnect(struct usb_interface *intf)
{
- struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_device *usbdev = interface_to_usbdev(intf);
struct igorplug *ir = usb_get_intfdata(intf);
+ struct device *dev = &intf->dev;
+ int devnum;
+
usb_set_intfdata(intf, NULL);
if (!ir || !ir->d)
return;
ir->usbdev = NULL;
- wake_up_all(&ir->wait_out);
- usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+ usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
+
+ devnum = unregister_from_lirc(ir);
- unregister_from_lirc(ir);
+ dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
}
-static struct usb_device_id usb_remote_id_table[] = {
+static struct usb_device_id igorplugusb_remote_id_table[] = {
/* Igor Plug USB (Atmel's Manufact. ID) */
{ USB_DEVICE(0x03eb, 0x0002) },
+ /* Fit PC2 Infrared Adapter */
+ { USB_DEVICE(0x03eb, 0x21fe) },
/* Terminating entry */
{ }
};
-static struct usb_driver usb_remote_driver = {
+static struct usb_driver igorplugusb_remote_driver = {
.name = DRIVER_NAME,
- .probe = usb_remote_probe,
- .disconnect = usb_remote_disconnect,
- .id_table = usb_remote_id_table
+ .probe = igorplugusb_remote_probe,
+ .disconnect = igorplugusb_remote_disconnect,
+ .id_table = igorplugusb_remote_id_table
};
-static int __init usb_remote_init(void)
+static int __init igorplugusb_remote_init(void)
{
- int i;
+ int ret = 0;
- printk(KERN_INFO "\n"
- DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n");
- printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n");
- dprintk(DRIVER_NAME ": debug mode enabled\n");
+ dprintk(DRIVER_NAME ": loaded, debug mode enabled\n");
- i = usb_register(&usb_remote_driver);
- if (i < 0) {
- printk(DRIVER_NAME ": usb register failed, result = %d\n", i);
- return -ENODEV;
- }
+ ret = usb_register(&igorplugusb_remote_driver);
+ if (ret)
+ printk(KERN_ERR DRIVER_NAME ": usb register failed!\n");
- return 0;
+ return ret;
}
-static void __exit usb_remote_exit(void)
+static void __exit igorplugusb_remote_exit(void)
{
- usb_deregister(&usb_remote_driver);
+ usb_deregister(&igorplugusb_remote_driver);
}
-module_init(usb_remote_init);
-module_exit(usb_remote_exit);
+module_init(igorplugusb_remote_init);
+module_exit(igorplugusb_remote_exit);
#include <linux/vermagic.h>
MODULE_INFO(vermagic, VERMAGIC_STRING);
@@ -548,8 +568,10 @@ MODULE_INFO(vermagic, VERMAGIC_STRING);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, usb_remote_id_table);
+MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
module_param(sample_rate, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
index 543c5c3bf907..929ae5795467 100644
--- a/drivers/staging/lirc/lirc_it87.c
+++ b/drivers/staging/lirc/lirc_it87.c
@@ -239,8 +239,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int retval = 0;
- unsigned long value = 0;
- unsigned int ivalue;
+ __u32 value = 0;
unsigned long hw_flags;
if (cmd == LIRC_GET_FEATURES)
@@ -256,24 +255,24 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
case LIRC_GET_FEATURES:
case LIRC_GET_SEND_MODE:
case LIRC_GET_REC_MODE:
- retval = put_user(value, (unsigned long *) arg);
+ retval = put_user(value, (__u32 *) arg);
break;
case LIRC_SET_SEND_MODE:
case LIRC_SET_REC_MODE:
- retval = get_user(value, (unsigned long *) arg);
+ retval = get_user(value, (__u32 *) arg);
break;
case LIRC_SET_SEND_CARRIER:
- retval = get_user(ivalue, (unsigned int *) arg);
+ retval = get_user(value, (__u32 *) arg);
if (retval)
return retval;
- ivalue /= 1000;
- if (ivalue > IT87_CIR_FREQ_MAX ||
- ivalue < IT87_CIR_FREQ_MIN)
+ value /= 1000;
+ if (value > IT87_CIR_FREQ_MAX ||
+ value < IT87_CIR_FREQ_MIN)
return -EINVAL;
- it87_freq = ivalue;
+ it87_freq = value;
spin_lock_irqsave(&hardware_lock, hw_flags);
outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) |
@@ -340,6 +339,9 @@ static const struct file_operations lirc_fops = {
.write = lirc_write,
.poll = lirc_poll,
.unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_ioctl,
+#endif
.open = lirc_open,
.release = lirc_close,
.llseek = noop_llseek,
@@ -964,10 +966,11 @@ static void __exit lirc_it87_exit(void)
printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
}
-/* SECTION: PNP for ITE8704/18 */
+/* SECTION: PNP for ITE8704/13/18 */
static const struct pnp_device_id pnp_dev_table[] = {
{"ITE8704", 0},
+ {"ITE8713", 0},
{}
};
diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c
index 9352f45bbece..cb20cfdcfadd 100644
--- a/drivers/staging/lirc/lirc_ite8709.c
+++ b/drivers/staging/lirc/lirc_ite8709.c
@@ -102,8 +102,8 @@ struct ite8709_device {
int io;
int irq;
spinlock_t hardware_lock;
- unsigned long long acc_pulse;
- unsigned long long acc_space;
+ __u64 acc_pulse;
+ __u64 acc_space;
char lastbit;
struct timeval last_tv;
struct lirc_driver driver;
@@ -220,7 +220,7 @@ static void ite8709_set_use_dec(void *data)
}
static void ite8709_add_read_queue(struct ite8709_device *dev, int flag,
- unsigned long long val)
+ __u64 val)
{
int value;
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
index 6da4a8c6ebc3..884904c782d1 100644
--- a/drivers/staging/lirc/lirc_parallel.c
+++ b/drivers/staging/lirc/lirc_parallel.c
@@ -24,10 +24,6 @@
/*** Includes ***/
-#ifdef CONFIG_SMP
-#error "--- Sorry, this driver is not SMP safe. ---"
-#endif
-
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -301,9 +297,9 @@ static void irq_handler(void *blah)
if (signal != 0) {
/* ajust value to usecs */
- unsigned long long helper;
+ __u64 helper;
- helper = ((unsigned long long) signal)*1000000;
+ helper = ((__u64) signal)*1000000;
do_div(helper, timer);
signal = (long) helper;
@@ -404,9 +400,9 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
/* adjust values from usecs */
for (i = 0; i < count; i++) {
- unsigned long long helper;
+ __u64 helper;
- helper = ((unsigned long long) wbuf[i])*timer;
+ helper = ((__u64) wbuf[i])*timer;
do_div(helper, 1000000);
wbuf[i] = (int) helper;
}
@@ -464,48 +460,48 @@ static unsigned int lirc_poll(struct file *file, poll_table *wait)
static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int result;
- unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK |
- LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
- unsigned long mode;
- unsigned int ivalue;
+ __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+ __u32 mode;
+ __u32 value;
switch (cmd) {
case LIRC_GET_FEATURES:
- result = put_user(features, (unsigned long *) arg);
+ result = put_user(features, (__u32 *) arg);
if (result)
return result;
break;
case LIRC_GET_SEND_MODE:
- result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+ result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
if (result)
return result;
break;
case LIRC_GET_REC_MODE:
- result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg);
+ result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
if (result)
return result;
break;
case LIRC_SET_SEND_MODE:
- result = get_user(mode, (unsigned long *) arg);
+ result = get_user(mode, (__u32 *) arg);
if (result)
return result;
if (mode != LIRC_MODE_PULSE)
return -EINVAL;
break;
case LIRC_SET_REC_MODE:
- result = get_user(mode, (unsigned long *) arg);
+ result = get_user(mode, (__u32 *) arg);
if (result)
return result;
if (mode != LIRC_MODE_MODE2)
return -ENOSYS;
break;
case LIRC_SET_TRANSMITTER_MASK:
- result = get_user(ivalue, (unsigned int *) arg);
+ result = get_user(value, (__u32 *) arg);
if (result)
return result;
- if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue)
+ if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
return LIRC_PARALLEL_MAX_TRANSMITTERS;
- tx_mask = ivalue;
+ tx_mask = value;
break;
default:
return -ENOIOCTLCMD;
@@ -546,6 +542,9 @@ static const struct file_operations lirc_fops = {
.write = lirc_write,
.poll = lirc_poll,
.unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_ioctl,
+#endif
.open = lirc_open,
.release = lirc_close
};
@@ -576,28 +575,6 @@ static struct lirc_driver driver = {
static int pf(void *handle);
static void kf(void *handle);
-static struct timer_list poll_timer;
-static void poll_state(unsigned long ignored);
-
-static void poll_state(unsigned long ignored)
-{
- printk(KERN_NOTICE "%s: time\n",
- LIRC_DRIVER_NAME);
- del_timer(&poll_timer);
- if (is_claimed)
- return;
- kf(NULL);
- if (!is_claimed) {
- printk(KERN_NOTICE "%s: could not claim port, giving up\n",
- LIRC_DRIVER_NAME);
- init_timer(&poll_timer);
- poll_timer.expires = jiffies + HZ;
- poll_timer.data = (unsigned long)current;
- poll_timer.function = poll_state;
- add_timer(&poll_timer);
- }
-}
-
static int pf(void *handle)
{
parport_disable_irq(pport);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
index 8da382492612..971844bbee28 100644
--- a/drivers/staging/lirc/lirc_serial.c
+++ b/drivers/staging/lirc/lirc_serial.c
@@ -372,7 +372,7 @@ static unsigned long conv_us_to_clocks;
static int init_timing_params(unsigned int new_duty_cycle,
unsigned int new_freq)
{
- unsigned long long loops_per_sec, work;
+ __u64 loops_per_sec, work;
duty_cycle = new_duty_cycle;
freq = new_freq;
@@ -987,8 +987,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int result;
- unsigned long value;
- unsigned int ivalue;
+ __u32 value;
switch (cmd) {
case LIRC_GET_SEND_MODE:
@@ -997,7 +996,7 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
result = put_user(LIRC_SEND2MODE
(hardware[type].features&LIRC_CAN_SEND_MASK),
- (unsigned long *) arg);
+ (__u32 *) arg);
if (result)
return result;
break;
@@ -1006,7 +1005,7 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
return -ENOIOCTLCMD;
- result = get_user(value, (unsigned long *) arg);
+ result = get_user(value, (__u32 *) arg);
if (result)
return result;
/* only LIRC_MODE_PULSE supported */
@@ -1023,12 +1022,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
return -ENOIOCTLCMD;
- result = get_user(ivalue, (unsigned int *) arg);
+ result = get_user(value, (__u32 *) arg);
if (result)
return result;
- if (ivalue <= 0 || ivalue > 100)
+ if (value <= 0 || value > 100)
return -EINVAL;
- return init_timing_params(ivalue, freq);
+ return init_timing_params(value, freq);
break;
case LIRC_SET_SEND_CARRIER:
@@ -1036,12 +1035,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
return -ENOIOCTLCMD;
- result = get_user(ivalue, (unsigned int *) arg);
+ result = get_user(value, (__u32 *) arg);
if (result)
return result;
- if (ivalue > 500000 || ivalue < 20000)
+ if (value > 500000 || value < 20000)
return -EINVAL;
- return init_timing_params(duty_cycle, ivalue);
+ return init_timing_params(duty_cycle, value);
break;
default:
@@ -1054,6 +1053,9 @@ static const struct file_operations lirc_fops = {
.owner = THIS_MODULE,
.write = lirc_write,
.unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_ioctl,
+#endif
.read = lirc_dev_fop_read,
.poll = lirc_dev_fop_poll,
.open = lirc_dev_fop_open,
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
index 2478871bd95e..c553ab626238 100644
--- a/drivers/staging/lirc/lirc_sir.c
+++ b/drivers/staging/lirc/lirc_sir.c
@@ -336,9 +336,8 @@ static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int retval = 0;
- unsigned long value = 0;
+ __u32 value = 0;
#ifdef LIRC_ON_SA1100
- unsigned int ivalue;
if (cmd == LIRC_GET_FEATURES)
value = LIRC_CAN_SEND_PULSE |
@@ -362,22 +361,22 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
case LIRC_GET_FEATURES:
case LIRC_GET_SEND_MODE:
case LIRC_GET_REC_MODE:
- retval = put_user(value, (unsigned long *) arg);
+ retval = put_user(value, (__u32 *) arg);
break;
case LIRC_SET_SEND_MODE:
case LIRC_SET_REC_MODE:
- retval = get_user(value, (unsigned long *) arg);
+ retval = get_user(value, (__u32 *) arg);
break;
#ifdef LIRC_ON_SA1100
case LIRC_SET_SEND_DUTY_CYCLE:
- retval = get_user(ivalue, (unsigned int *) arg);
+ retval = get_user(value, (__u32 *) arg);
if (retval)
return retval;
- if (ivalue <= 0 || ivalue > 100)
+ if (value <= 0 || value > 100)
return -EINVAL;
- /* (ivalue/100)*(1000000/freq) */
- duty_cycle = ivalue;
+ /* (value/100)*(1000000/freq) */
+ duty_cycle = value;
pulse_width = (unsigned long) duty_cycle*10000/freq;
space_width = (unsigned long) 1000000L/freq-pulse_width;
if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
@@ -386,12 +385,12 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
break;
case LIRC_SET_SEND_CARRIER:
- retval = get_user(ivalue, (unsigned int *) arg);
+ retval = get_user(value, (__u32 *) arg);
if (retval)
return retval;
- if (ivalue > 500000 || ivalue < 20000)
+ if (value > 500000 || value < 20000)
return -EINVAL;
- freq = ivalue;
+ freq = value;
pulse_width = (unsigned long) duty_cycle*10000/freq;
space_width = (unsigned long) 1000000L/freq-pulse_width;
if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
@@ -457,6 +456,9 @@ static const struct file_operations lirc_fops = {
.write = lirc_write,
.poll = lirc_poll,
.unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_ioctl,
+#endif
.open = lirc_dev_fop_open,
.release = lirc_dev_fop_close,
.llseek = no_llseek,
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
index 100caab10451..d92064498523 100644
--- a/drivers/staging/lirc/lirc_zilog.c
+++ b/drivers/staging/lirc/lirc_zilog.c
@@ -1139,6 +1139,9 @@ static const struct file_operations lirc_fops = {
.write = write,
.poll = poll,
.unlocked_ioctl = ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ioctl,
+#endif
.open = open,
.release = close
};
diff --git a/drivers/staging/stradis/Kconfig b/drivers/staging/stradis/Kconfig
new file mode 100644
index 000000000000..92e891141896
--- /dev/null
+++ b/drivers/staging/stradis/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_STRADIS
+ tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
+ depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
+ help
+ Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
+ driver for PCI. There is a product page at
+ <http://www.stradis.com/>.
diff --git a/drivers/staging/stradis/Makefile b/drivers/staging/stradis/Makefile
new file mode 100644
index 000000000000..0f1feab59e39
--- /dev/null
+++ b/drivers/staging/stradis/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/stradis/TODO b/drivers/staging/stradis/TODO
new file mode 100644
index 000000000000..f48150fe2fa9
--- /dev/null
+++ b/drivers/staging/stradis/TODO
@@ -0,0 +1,6 @@
+This is an obsolete driver for ancient stradis hardware.
+We couldn't find anyone with this hardware in order to port it to use V4L2.
+
+If nobody take care on it, the driver will be removed for 2.6.38.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/stradis/stradis.c b/drivers/staging/stradis/stradis.c
new file mode 100644
index 000000000000..a057824e7ebc
--- /dev/null
+++ b/drivers/staging/stradis/stradis.c
@@ -0,0 +1,2213 @@
+/*
+ * stradis.c - stradis 4:2:2 mpeg decoder driver
+ *
+ * Stradis 4:2:2 MPEG-2 Decoder Driver
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "saa7146.h"
+#include "saa7146reg.h"
+#include "ibmmpeg2.h"
+#include "saa7121.h"
+#include "cs8420.h"
+
+#define DEBUG(x) /* debug driver */
+#undef IDEBUG /* debug irq handler */
+#undef MDEBUG /* debug memory management */
+
+#define SAA7146_MAX 6
+
+static struct saa7146 saa7146s[SAA7146_MAX];
+
+static int saa_num; /* number of SAA7146s in use */
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_LICENSE("GPL");
+
+#define nDebNormal 0x00480000
+#define nDebNoInc 0x00480000
+#define nDebVideo 0xd0480000
+#define nDebAudio 0xd0400000
+#define nDebDMA 0x02c80000
+
+#define oDebNormal 0x13c80000
+#define oDebNoInc 0x13c80000
+#define oDebVideo 0xd1080000
+#define oDebAudio 0xd1080000
+#define oDebDMA 0x03080000
+
+#define NewCard (saa->boardcfg[3])
+#define ChipControl (saa->boardcfg[1])
+#define NTSCFirstActive (saa->boardcfg[4])
+#define PALFirstActive (saa->boardcfg[5])
+#define NTSCLastActive (saa->boardcfg[54])
+#define PALLastActive (saa->boardcfg[55])
+#define Have2MB (saa->boardcfg[18] & 0x40)
+#define HaveCS8420 (saa->boardcfg[18] & 0x04)
+#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20)
+#define HaveCS3310 (saa->boardcfg[18] & 0x01)
+#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31])
+#define HaveCS4341 (saa->boardcfg[40] == 2)
+#define SDIType (saa->boardcfg[27])
+#define CurrentMode (saa->boardcfg[2])
+
+#define debNormal (NewCard ? nDebNormal : oDebNormal)
+#define debNoInc (NewCard ? nDebNoInc : oDebNoInc)
+#define debVideo (NewCard ? nDebVideo : oDebVideo)
+#define debAudio (NewCard ? nDebAudio : oDebAudio)
+#define debDMA (NewCard ? nDebDMA : oDebDMA)
+
+#ifdef USE_RESCUE_EEPROM_SDM275
+static unsigned char rescue_eeprom[64] = {
+ 0x00, 0x01, 0x04, 0x13, 0x26, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x43, 0x63,
+ 0x22, 0x01, 0x29, 0x15, 0x73, 0x00, 0x1f, 'd', 'e', 'c', 'x', 'l',
+ 'd', 'v', 'a', 0x02, 0x00, 0x01, 0x00, 0xcc, 0xa4, 0x63, 0x09, 0xe2,
+ 0x10, 0x00, 0x0a, 0x00, 0x02, 0x02, 'd', 'e', 'c', 'x', 'l', 'a',
+ 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Hardware I2C functions */
+static void I2CWipe(struct saa7146 *saa)
+{
+ int i;
+ /* set i2c to ~=100kHz, abort transfer, clear busy */
+ saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ saawrite(0x600, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ saawrite(0x600, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+}
+
+/* read I2C */
+static int I2CRead(struct saa7146 *saa, unsigned char addr,
+ unsigned char subaddr, int dosub)
+{
+ int i;
+
+ if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+ I2CWipe(saa);
+ for (i = 0;
+ i < 1000 && (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY);
+ i++)
+ schedule();
+ if (i == 1000)
+ I2CWipe(saa);
+ if (dosub)
+ saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
+ ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
+ else
+ saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
+ 0xf1, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ /* wait for valid data */
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
+ return -1;
+ if (i == 1000)
+ printk("i2c setup read timeout\n");
+ saawrite(0x41, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ /* wait for valid data */
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
+ return -1;
+ if (i == 1000)
+ printk("i2c read timeout\n");
+ return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
+}
+
+/* set both to write both bytes, reset it to write only b1 */
+
+static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
+ unsigned char b2, int both)
+{
+ int i;
+ u32 data;
+
+ if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+ I2CWipe(saa);
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (i == 1000)
+ I2CWipe(saa);
+ data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
+ if (both)
+ data |= ((b2 & 0xff) << 8) | 0xe5;
+ else
+ data |= 0xd1;
+ saawrite(data, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
+ SAA7146_MC2);
+ return 0;
+}
+
+static void attach_inform(struct saa7146 *saa, int id)
+{
+ int i;
+
+ DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr,
+ id));
+ if (id == 0xa0) { /* we have rev2 or later board, fill in info */
+ for (i = 0; i < 64; i++)
+ saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
+#ifdef USE_RESCUE_EEPROM_SDM275
+ if (saa->boardcfg[0] != 0) {
+ printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE "
+ "BEEN IGNORED\n", saa->nr);
+ for (i = 0; i < 64; i++)
+ saa->boardcfg[i] = rescue_eeprom[i];
+ }
+#endif
+ printk("stradis%d: config =", saa->nr);
+ for (i = 0; i < 51; i++) {
+ printk(" %02x", saa->boardcfg[i]);
+ }
+ printk("\n");
+ }
+}
+
+static void I2CBusScan(struct saa7146 *saa)
+{
+ int i;
+ for (i = 0; i < 0xff; i += 2)
+ if ((I2CRead(saa, i, 0, 0)) >= 0)
+ attach_inform(saa, i);
+}
+
+static int debiwait_maxwait;
+
+static int wait_for_debi_done(struct saa7146 *saa)
+{
+ int i;
+
+ /* wait for registers to be programmed */
+ for (i = 0; i < 100000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
+ saaread(SAA7146_MC2);
+ /* wait for transfer to complete */
+ for (i = 0; i < 500000 &&
+ (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
+ saaread(SAA7146_MC2);
+
+ if (i > debiwait_maxwait)
+ printk("wait-for-debi-done maxwait: %d\n",
+ debiwait_maxwait = i);
+
+ if (i == 500000)
+ return -1;
+
+ return 0;
+}
+
+static int debiwrite(struct saa7146 *saa, u32 config, int addr,
+ u32 val, int count)
+{
+ u32 cmd;
+ if (count <= 0 || count > 32764)
+ return -1;
+ if (wait_for_debi_done(saa) < 0)
+ return -1;
+ saawrite(config, SAA7146_DEBI_CONFIG);
+ if (count <= 4) /* immediate transfer */
+ saawrite(val, SAA7146_DEBI_AD);
+ else /* block transfer */
+ saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+ saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
+ saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+ SAA7146_MC2);
+ return 0;
+}
+
+static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
+{
+ u32 result = 0;
+
+ if (count > 32764 || count <= 0)
+ return 0;
+ if (wait_for_debi_done(saa) < 0)
+ return 0;
+ saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+ saawrite((count << 17) | 0x10000 | (addr & 0xffff),
+ SAA7146_DEBI_COMMAND);
+ saawrite(config, SAA7146_DEBI_CONFIG);
+ saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+ SAA7146_MC2);
+ if (count > 4) /* not an immediate transfer */
+ return count;
+ wait_for_debi_done(saa);
+ result = saaread(SAA7146_DEBI_AD);
+ if (count == 1)
+ result &= 0xff;
+ if (count == 2)
+ result &= 0xffff;
+ if (count == 3)
+ result &= 0xffffff;
+ return result;
+}
+
+static void do_irq_send_data(struct saa7146 *saa)
+{
+ int split, audbytes, vidbytes;
+
+ saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
+ /* if special feature mode in effect, disable audio sending */
+ if (saa->playmode != VID_PLAY_NORMAL)
+ saa->audtail = saa->audhead = 0;
+ if (saa->audhead <= saa->audtail)
+ audbytes = saa->audtail - saa->audhead;
+ else
+ audbytes = 65536 - (saa->audhead - saa->audtail);
+ if (saa->vidhead <= saa->vidtail)
+ vidbytes = saa->vidtail - saa->vidhead;
+ else
+ vidbytes = 524288 - (saa->vidhead - saa->vidtail);
+ if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
+ saawrite(0, SAA7146_IER);
+ return;
+ }
+ /* if at least 1 block audio waiting and audio fifo isn't full */
+ if (audbytes >= 2048 && (debiread(saa, debNormal, IBM_MP2_AUD_FIFO, 2)
+ & 0xff) < 60) {
+ if (saa->audhead > saa->audtail)
+ split = 65536 - saa->audhead;
+ else
+ split = 0;
+ audbytes = 2048;
+ if (split > 0 && split < 2048) {
+ memcpy(saa->dmadebi, saa->audbuf + saa->audhead, split);
+ saa->audhead = 0;
+ audbytes -= split;
+ } else
+ split = 0;
+ memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
+ audbytes);
+ saa->audhead += audbytes;
+ saa->audhead &= 0xffff;
+ debiwrite(saa, debAudio, (NewCard ? IBM_MP2_AUD_FIFO :
+ IBM_MP2_AUD_FIFOW), 0, 2048);
+ wake_up_interruptible(&saa->audq);
+ /* if at least 1 block video waiting and video fifo isn't full */
+ } else if (vidbytes >= 30720 && (debiread(saa, debNormal,
+ IBM_MP2_FIFO, 2)) < 16384) {
+ if (saa->vidhead > saa->vidtail)
+ split = 524288 - saa->vidhead;
+ else
+ split = 0;
+ vidbytes = 30720;
+ if (split > 0 && split < 30720) {
+ memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, split);
+ saa->vidhead = 0;
+ vidbytes -= split;
+ } else
+ split = 0;
+ memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
+ vidbytes);
+ saa->vidhead += vidbytes;
+ saa->vidhead &= 0x7ffff;
+ debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
+ IBM_MP2_FIFOW), 0, 30720);
+ wake_up_interruptible(&saa->vidq);
+ }
+ saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
+}
+
+static void send_osd_data(struct saa7146 *saa)
+{
+ int size = saa->osdtail - saa->osdhead;
+ if (size > 30720)
+ size = 30720;
+ /* ensure some multiple of 8 bytes is transferred */
+ size = 8 * ((size + 8) >> 3);
+ if (size) {
+ debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
+ (saa->osdhead >> 3), 2);
+ memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
+ saa->osdhead += size;
+ /* block transfer of next 8 bytes to ~32k bytes */
+ debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
+ }
+ if (saa->osdhead >= saa->osdtail) {
+ saa->osdhead = saa->osdtail = 0;
+ debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+ }
+}
+
+static irqreturn_t saa7146_irq(int irq, void *dev_id)
+{
+ struct saa7146 *saa = dev_id;
+ u32 stat, astat;
+ int count;
+ int handled = 0;
+
+ count = 0;
+ while (1) {
+ /* get/clear interrupt status bits */
+ stat = saaread(SAA7146_ISR);
+ astat = stat & saaread(SAA7146_IER);
+ if (!astat)
+ break;
+ handled = 1;
+ saawrite(astat, SAA7146_ISR);
+ if (astat & SAA7146_PSR_DEBI_S) {
+ do_irq_send_data(saa);
+ }
+ if (astat & SAA7146_PSR_PIN1) {
+ int istat;
+ /* the following read will trigger DEBI_S */
+ istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+ if (istat & 1) {
+ saawrite(0, SAA7146_IER);
+ send_osd_data(saa);
+ saawrite(SAA7146_PSR_DEBI_S |
+ SAA7146_PSR_PIN1, SAA7146_IER);
+ }
+ if (istat & 0x20) { /* Video Start */
+ saa->vidinfo.frame_count++;
+ }
+ if (istat & 0x400) { /* Picture Start */
+ /* update temporal reference */
+ }
+ if (istat & 0x200) { /* Picture Resolution Change */
+ /* read new resolution */
+ }
+ if (istat & 0x100) { /* New User Data found */
+ /* read new user data */
+ }
+ if (istat & 0x1000) { /* new GOP/SMPTE */
+ /* read new SMPTE */
+ }
+ if (istat & 0x8000) { /* Sequence Start Code */
+ /* reset frame counter, load sizes */
+ saa->vidinfo.frame_count = 0;
+ saa->vidinfo.h_size = 704;
+ saa->vidinfo.v_size = 480;
+#if 0
+ if (saa->endmarkhead != saa->endmarktail) {
+ saa->audhead =
+ saa->endmark[saa->endmarkhead];
+ saa->endmarkhead++;
+ if (saa->endmarkhead >= MAX_MARKS)
+ saa->endmarkhead = 0;
+ }
+#endif
+ }
+ if (istat & 0x4000) { /* Sequence Error Code */
+ if (saa->endmarkhead != saa->endmarktail) {
+ saa->audhead =
+ saa->endmark[saa->endmarkhead];
+ saa->endmarkhead++;
+ if (saa->endmarkhead >= MAX_MARKS)
+ saa->endmarkhead = 0;
+ }
+ }
+ }
+#ifdef IDEBUG
+ if (astat & SAA7146_PSR_PPEF) {
+ IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PABO) {
+ IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PPED) {
+ IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_I1) {
+ IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_I0) {
+ IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_LATE1) {
+ IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_LATE0) {
+ IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_E1) {
+ IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_E0) {
+ IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_TO1) {
+ IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_TO0) {
+ IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_UPLD) {
+ IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_DEBI_E) {
+ IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_I2C_S) {
+ IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_I2C_E) {
+ IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A2_IN) {
+ IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A2_OUT) {
+ IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A1_IN) {
+ IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A1_OUT) {
+ IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_AFOU) {
+ IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_V_PE) {
+ IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_VFOU) {
+ IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_FIDA) {
+ IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_FIDB) {
+ IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN3) {
+ IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN2) {
+ IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN0) {
+ IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_ECS) {
+ IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_EC3S) {
+ IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_EC0S) {
+ IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
+ }
+#endif
+ count++;
+ if (count > 15)
+ printk(KERN_WARNING "stradis%d: irq loop %d\n",
+ saa->nr, count);
+ if (count > 20) {
+ saawrite(0, SAA7146_IER);
+ printk(KERN_ERR
+ "stradis%d: IRQ loop cleared\n", saa->nr);
+ }
+ }
+ return IRQ_RETVAL(handled);
+}
+
+static int ibm_send_command(struct saa7146 *saa,
+ int command, int data, int chain)
+{
+ int i;
+
+ if (chain)
+ debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1)| 1,2);
+ else
+ debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
+ for (i = 0; i < 100 &&
+ (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
+ schedule();
+ if (i == 100)
+ return -1;
+ return 0;
+}
+
+static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
+{
+ I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
+ I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
+}
+
+static void initialize_cs4341(struct saa7146 *saa)
+{
+ int i;
+ for (i = 0; i < 200; i++) {
+ /* auto mute off, power on, no de-emphasis */
+ /* I2S data up to 24-bit 64xFs internal SCLK */
+ I2CWrite(saa, 0x22, 0x01, 0x11, 2);
+ /* ATAPI mixer settings */
+ I2CWrite(saa, 0x22, 0x02, 0x49, 2);
+ /* attenuation left 3db */
+ I2CWrite(saa, 0x22, 0x03, 0x00, 2);
+ /* attenuation right 3db */
+ I2CWrite(saa, 0x22, 0x04, 0x00, 2);
+ I2CWrite(saa, 0x22, 0x01, 0x10, 2);
+ if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
+ break;
+ schedule();
+ }
+ printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
+ return;
+}
+
+static void initialize_cs8420(struct saa7146 *saa, int pro)
+{
+ int i;
+ u8 *sequence;
+ if (pro)
+ sequence = mode8420pro;
+ else
+ sequence = mode8420con;
+ for (i = 0; i < INIT8420LEN; i++)
+ I2CWrite(saa, 0x20, init8420[i * 2], init8420[i * 2 + 1], 2);
+ for (i = 0; i < MODE8420LEN; i++)
+ I2CWrite(saa, 0x20, sequence[i * 2], sequence[i * 2 + 1], 2);
+ printk("stradis%d: CS8420 initialized\n", saa->nr);
+}
+
+static void initialize_saa7121(struct saa7146 *saa, int dopal)
+{
+ int i, mod;
+ u8 *sequence;
+ if (dopal)
+ sequence = init7121pal;
+ else
+ sequence = init7121ntsc;
+ mod = saaread(SAA7146_PSR) & 0x08;
+ /* initialize PAL/NTSC video encoder */
+ for (i = 0; i < INIT7121LEN; i++) {
+ if (NewCard) { /* handle new card encoder differences */
+ if (sequence[i * 2] == 0x3a)
+ I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
+ else if (sequence[i * 2] == 0x6b)
+ I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
+ else if (sequence[i * 2] == 0x6c)
+ I2CWrite(saa, 0x88, 0x6c,
+ dopal ? 0x09 : 0xf5, 2);
+ else if (sequence[i * 2] == 0x6d)
+ I2CWrite(saa, 0x88, 0x6d,
+ dopal ? 0x20 : 0x00, 2);
+ else if (sequence[i * 2] == 0x7a)
+ I2CWrite(saa, 0x88, 0x7a,
+ dopal ? (PALFirstActive - 1) :
+ (NTSCFirstActive - 4), 2);
+ else if (sequence[i * 2] == 0x7b)
+ I2CWrite(saa, 0x88, 0x7b,
+ dopal ? PALLastActive :
+ NTSCLastActive, 2);
+ else
+ I2CWrite(saa, 0x88, sequence[i * 2],
+ sequence[i * 2 + 1], 2);
+ } else {
+ if (sequence[i * 2] == 0x6b && mod)
+ I2CWrite(saa, 0x88, 0x6b,
+ (sequence[i * 2 + 1] ^ 0x09), 2);
+ else if (sequence[i * 2] == 0x7a)
+ I2CWrite(saa, 0x88, 0x7a,
+ dopal ? (PALFirstActive - 1) :
+ (NTSCFirstActive - 4), 2);
+ else if (sequence[i * 2] == 0x7b)
+ I2CWrite(saa, 0x88, 0x7b,
+ dopal ? PALLastActive :
+ NTSCLastActive, 2);
+ else
+ I2CWrite(saa, 0x88, sequence[i * 2],
+ sequence[i * 2 + 1], 2);
+ }
+ }
+}
+
+static void set_genlock_offset(struct saa7146 *saa, int noffset)
+{
+ int nCode;
+ int PixelsPerLine = 858;
+ if (CurrentMode == VIDEO_MODE_PAL)
+ PixelsPerLine = 864;
+ if (noffset > 500)
+ noffset = 500;
+ else if (noffset < -500)
+ noffset = -500;
+ nCode = noffset + 0x100;
+ if (nCode == 1)
+ nCode = 0x401;
+ else if (nCode < 1)
+ nCode = 0x400 + PixelsPerLine + nCode;
+ debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
+}
+
+static void set_out_format(struct saa7146 *saa, int mode)
+{
+ initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
+ saa->boardcfg[2] = mode;
+ /* do not adjust analog video parameters here, use saa7121 init */
+ /* you will affect the SDI output on the new card */
+ if (mode == VIDEO_MODE_PAL) { /* PAL */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
+ mdelay(50);
+ saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
+ if (NewCard) {
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, 0xe100, 2);
+ mdelay(50);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ NewCard ? 0xe500 : 0x6500, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+ (1 << 8) |
+ (NewCard ? PALFirstActive : PALFirstActive - 6), 2);
+ } else { /* NTSC */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
+ mdelay(50);
+ saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ NewCard ? 0xe100 : 0x6100, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+ (1 << 8) |
+ (NewCard ? NTSCFirstActive : NTSCFirstActive - 6), 2);
+ }
+}
+
+/* Intialize bitmangler to map from a byte value to the mangled word that
+ * must be output to program the Xilinx part through the DEBI port.
+ * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
+ * transfer FPGA code, init IBM chip, transfer IBM microcode
+ * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
+ */
+static u16 bitmangler[256];
+
+static int initialize_fpga(struct video_code *bitdata)
+{
+ int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
+ u16 *dmabuf;
+ u8 *newdma;
+ struct saa7146 *saa;
+
+ /* verify fpga code */
+ for (startindex = 0; startindex < bitdata->datasize; startindex++)
+ if (bitdata->data[startindex] == 255)
+ break;
+ if (startindex == bitdata->datasize) {
+ printk(KERN_INFO "stradis: bad fpga code\n");
+ return -1;
+ }
+ /* initialize all detected cards */
+ for (num = 0; num < saa_num; num++) {
+ saa = &saa7146s[num];
+ if (saa->boardcfg[0] > 20)
+ continue; /* card was programmed */
+ loadtwo = (saa->boardcfg[18] & 0x10);
+ if (!NewCard) /* we have an old board */
+ for (i = 0; i < 256; i++)
+ bitmangler[i] = ((i & 0x01) << 15) |
+ ((i & 0x02) << 6) | ((i & 0x04) << 4) |
+ ((i & 0x08) << 9) | ((i & 0x10) << 7) |
+ ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+ ((i & 0x80) >> 7);
+ else /* else we have a new board */
+ for (i = 0; i < 256; i++)
+ bitmangler[i] = ((i & 0x01) << 7) |
+ ((i & 0x02) << 5) | ((i & 0x04) << 3) |
+ ((i & 0x08) << 1) | ((i & 0x10) >> 1) |
+ ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+ ((i & 0x80) >> 7);
+
+ dmabuf = (u16 *) saa->dmadebi;
+ newdma = (u8 *) saa->dmadebi;
+ if (NewCard) { /* SDM2xxx */
+ if (!strncmp(bitdata->loadwhat, "decoder2", 8))
+ continue; /* fpga not for this card */
+ if (!strncmp(&saa->boardcfg[42], bitdata->loadwhat, 8))
+ loadfile = 1;
+ else if (loadtwo && !strncmp(&saa->boardcfg[19],
+ bitdata->loadwhat, 8))
+ loadfile = 2;
+ else if (!saa->boardcfg[42] && !strncmp("decxl",
+ bitdata->loadwhat, 8))
+ loadfile = 1; /* special */
+ else
+ continue; /* fpga not for this card */
+ if (loadfile != 1 && loadfile != 2)
+ continue; /* skip to next card */
+ if (saa->boardcfg[0] && loadfile == 1)
+ continue; /* skip to next card */
+ if (saa->boardcfg[0] != 1 && loadfile == 2)
+ continue; /* skip to next card */
+ saa->boardcfg[0]++; /* mark fpga handled */
+ printk("stradis%d: loading %s\n", saa->nr,
+ bitdata->loadwhat);
+ if (loadtwo && loadfile == 2)
+ goto send_fpga_stuff;
+ /* turn on the Audio interface to set PROG low */
+ saawrite(0x00400040, SAA7146_GPIO_CTRL);
+ saaread(SAA7146_PSR); /* ensure posted write */
+ /* wait for everyone to reset */
+ mdelay(10);
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ } else { /* original card */
+ if (strncmp(bitdata->loadwhat, "decoder2", 8))
+ continue; /* fpga not for this card */
+ /* Pull the Xilinx PROG signal WS3 low */
+ saawrite(0x02000200, SAA7146_MC1);
+ /* Turn on the Audio interface so can set PROG low */
+ saawrite(0x000000c0, SAA7146_ACON1);
+ /* Pull the Xilinx INIT signal (GPIO2) low */
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ /* Make sure everybody resets */
+ saaread(SAA7146_PSR); /* ensure posted write */
+ mdelay(10);
+ /* Release the Xilinx PROG signal */
+ saawrite(0x00000000, SAA7146_ACON1);
+ /* Turn off the Audio interface */
+ saawrite(0x02000000, SAA7146_MC1);
+ }
+ /* Release Xilinx INIT signal (WS2) */
+ saawrite(0x00000000, SAA7146_GPIO_CTRL);
+ /* Wait for the INIT to go High */
+ for (i = 0;
+ i < 10000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
+ i++)
+ schedule();
+ if (i == 1000) {
+ printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
+ return -1;
+ }
+send_fpga_stuff:
+ if (NewCard) {
+ for (i = startindex; i < bitdata->datasize; i++)
+ newdma[i - startindex] =
+ bitmangler[bitdata->data[i]];
+ debiwrite(saa, 0x01420000, 0, 0,
+ ((bitdata->datasize - startindex) + 5));
+ if (loadtwo && loadfile == 1) {
+ printk("stradis%d: awaiting 2nd FPGA bitfile\n",
+ saa->nr);
+ continue; /* skip to next card */
+ }
+ } else {
+ for (i = startindex; i < bitdata->datasize; i++)
+ dmabuf[i - startindex] =
+ bitmangler[bitdata->data[i]];
+ debiwrite(saa, 0x014a0000, 0, 0,
+ ((bitdata->datasize - startindex) + 5) * 2);
+ }
+ for (i = 0;
+ i < 1000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
+ i++)
+ schedule();
+ if (i == 1000) {
+ printk(KERN_INFO "stradis%d: FPGA load failed\n",
+ saa->nr);
+ failure++;
+ continue;
+ }
+ if (!NewCard) {
+ /* Pull the Xilinx INIT signal (GPIO2) low */
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ saaread(SAA7146_PSR); /* ensure posted write */
+ mdelay(2);
+ saawrite(0x00000000, SAA7146_GPIO_CTRL);
+ mdelay(2);
+ }
+ printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
+ saa->boardcfg[0] = 26; /* mark fpga programmed */
+ /* set VXCO to its lowest frequency */
+ debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
+ if (NewCard) {
+ /* mute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+ 0, 2);
+ /* set VXCO to PWM mode, release reset, blank on */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
+ mdelay(10);
+ /* unmute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CTL0,
+ 0x2020, 2);
+ }
+ /* set source Black */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+ saa->boardcfg[4] = 22; /* set NTSC First Active Line */
+ saa->boardcfg[5] = 23; /* set PAL First Active Line */
+ saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */
+ saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */
+ set_out_format(saa, VIDEO_MODE_NTSC);
+ mdelay(50);
+ /* begin IBM chip init */
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+ saaread(SAA7146_PSR); /* wait for reset */
+ mdelay(5);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+ debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+ if (NewCard) {
+ mdelay(5);
+ /* set i2s rate converter to 48KHz */
+ debiwrite(saa, debNormal, 0x80c0, 6, 2);
+ /* we must init CS8420 first since rev b pulls i2s */
+ /* master clock low and CS4341 needs i2s master to */
+ /* run the i2c port. */
+ if (HaveCS8420)
+ /* 0=consumer, 1=pro */
+ initialize_cs8420(saa, 0);
+
+ mdelay(5);
+ if (HaveCS4341)
+ initialize_cs4341(saa);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+ debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+ if (NewCard)
+ set_genlock_offset(saa, 0);
+ debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+#if 0
+ /* enable genlock */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
+#else
+ /* disable genlock */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
+#endif
+ }
+
+ return failure;
+}
+
+static int do_ibm_reset(struct saa7146 *saa)
+{
+ /* failure if decoder not previously programmed */
+ if (saa->boardcfg[0] < 37)
+ return -EIO;
+ /* mute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
+ /* disable interrupts */
+ saawrite(0, SAA7146_IER);
+ saa->audhead = saa->audtail = 0;
+ saa->vidhead = saa->vidtail = 0;
+ /* tristate debi bus, disable debi transfers */
+ saawrite(0x00880000, SAA7146_MC1);
+ /* ensure posted write */
+ saaread(SAA7146_MC1);
+ mdelay(50);
+ /* re-enable debi transfers */
+ saawrite(0x00880088, SAA7146_MC1);
+ /* set source Black */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+ /* begin IBM chip init */
+ set_out_format(saa, CurrentMode);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+ saaread(SAA7146_PSR); /* wait for reset */
+ mdelay(5);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+ debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+ if (NewCard) {
+ mdelay(5);
+ /* set i2s rate converter to 48KHz */
+ debiwrite(saa, debNormal, 0x80c0, 6, 2);
+ /* we must init CS8420 first since rev b pulls i2s */
+ /* master clock low and CS4341 needs i2s master to */
+ /* run the i2c port. */
+ if (HaveCS8420)
+ /* 0=consumer, 1=pro */
+ initialize_cs8420(saa, 1);
+
+ mdelay(5);
+ if (HaveCS4341)
+ initialize_cs4341(saa);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+ debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+ if (NewCard)
+ set_genlock_offset(saa, 0);
+ debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+ if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+ (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
+ printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
+ }
+ if (HaveCS3310) {
+ int i = CS3310MaxLvl;
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i << 8)| i),2);
+ }
+ /* start video decoder */
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ /* 256k vid, 3520 bytes aud */
+ debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+ ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+ /* enable buffer threshold irq */
+ debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+ /* clear pending interrupts */
+ debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+
+ return 0;
+}
+
+/* load the decoder microcode */
+static int initialize_ibmmpeg2(struct video_code *microcode)
+{
+ int i, num;
+ struct saa7146 *saa;
+
+ for (num = 0; num < saa_num; num++) {
+ saa = &saa7146s[num];
+ /* check that FPGA is loaded */
+ debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
+ i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2);
+ if (i != 0xa55a) {
+ printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
+ saa->nr, i);
+#if 0
+ return -1;
+#endif
+ }
+ if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
+ if (saa->boardcfg[0] > 27)
+ continue; /* skip to next card */
+ /* load video control store */
+ saa->boardcfg[1] = 0x13; /* no-sync default */
+ debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+ debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+ for (i = 0; i < microcode->datasize / 2; i++)
+ debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
+ (microcode->data[i * 2] << 8) |
+ microcode->data[i * 2 + 1], 2);
+ debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+ ChipControl, 2);
+ saa->boardcfg[0] = 28;
+ }
+ if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
+ if (saa->boardcfg[0] > 35)
+ continue; /* skip to next card */
+ /* load audio control store */
+ debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+ for (i = 0; i < microcode->datasize; i++)
+ debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
+ microcode->data[i], 1);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+ if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+ 0xe000, 1)) {
+ printk(KERN_ERR "stradis%d: IBM config "
+ "failed\n", saa->nr);
+ return -1;
+ }
+ /* set PWM to center value */
+ if (NewCard) {
+ debiwrite(saa, debNormal, XILINX_PWM,
+ saa->boardcfg[14] +
+ (saa->boardcfg[13] << 8), 2);
+ } else
+ debiwrite(saa, debNormal, XILINX_PWM, 0x46, 2);
+
+ if (HaveCS3310) {
+ i = CS3310MaxLvl;
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+ (i << 8) | i, 2);
+ }
+ printk(KERN_INFO "stradis%d: IBM MPEGCD%d Inited\n",
+ saa->nr, 18 + (debiread(saa, debNormal,
+ IBM_MP2_CHIP_CONTROL, 2) >> 12));
+ /* start video decoder */
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+ ChipControl, 2);
+ debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037,
+ 2); /* 256k vid, 3520 bytes aud */
+ debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+ ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+ /* enable buffer threshold irq */
+ debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+ debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+ /* enable gpio irq */
+ saawrite(0x00002000, SAA7146_GPIO_CTRL);
+ /* enable decoder output to HPS */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+ saa->boardcfg[0] = 37;
+ }
+ }
+
+ return 0;
+}
+
+static u32 palette2fmt[] = { /* some of these YUV translations are wrong */
+ 0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
+ 0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
+ 0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
+};
+static int bpp2fmt[4] = {
+ VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
+ VIDEO_PALETTE_RGB32
+};
+
+/* I wish I could find a formula to calculate these... */
+static u32 h_prescale[64] = {
+ 0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
+ 0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
+ 0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
+ 0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
+ 0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
+ 0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
+ 0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
+ 0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
+ 0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
+ 0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
+ 0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
+};
+static u32 v_gain[64] = {
+ 0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
+ 0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
+ 0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+ 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+};
+
+static void saa7146_set_winsize(struct saa7146 *saa)
+{
+ u32 format;
+ int offset, yacl, ysci;
+ saa->win.color_fmt = format =
+ (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
+ palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
+ offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
+ saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
+ saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
+ saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
+ saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
+ SAA7146_PROT_ADDR1);
+ saawrite(0, SAA7146_PAGE1);
+ saawrite(format | 0x60, SAA7146_CLIP_FORMAT_CTRL);
+ offset = (704 / (saa->win.width - 1)) & 0x3f;
+ saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
+ offset = (720896 / saa->win.width) / (offset + 1);
+ saawrite((offset << 12) | 0x0c, SAA7146_HPS_H_SCALE);
+ if (CurrentMode == VIDEO_MODE_NTSC) {
+ yacl = /*(480 / saa->win.height - 1) & 0x3f */ 0;
+ ysci = 1024 - (saa->win.height * 1024 / 480);
+ } else {
+ yacl = /*(576 / saa->win.height - 1) & 0x3f */ 0;
+ ysci = 1024 - (saa->win.height * 1024 / 576);
+ }
+ saawrite((1 << 31) | (ysci << 21) | (yacl << 15), SAA7146_HPS_V_SCALE);
+ saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
+ saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
+ SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
+ SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), SAA7146_MC2);
+}
+
+/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
+ * bitmap is fixed width, 128 bytes (1024 pixels represented)
+ * arranged most-sigificant-bit-left in 32-bit words
+ * based on saa7146 clipping hardware, it swaps bytes if LE
+ * much of this makes up for egcs brain damage -- so if you
+ * are wondering "why did he do this?" it is because the C
+ * was adjusted to generate the optimal asm output without
+ * writing non-portable __asm__ directives.
+ */
+
+static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
+{
+ register int startword, endword;
+ register u32 bitsleft, bitsright;
+ u32 *temp;
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+ if (w <= 0 || h <= 0 || x > 1023 || y > 639)
+ return; /* throw away bad clips */
+ if (x + w > 1024)
+ w = 1024 - x;
+ if (y + h > 640)
+ h = 640 - y;
+ startword = (x >> 5);
+ endword = ((x + w) >> 5);
+ bitsleft = (0xffffffff >> (x & 31));
+ bitsright = (0xffffffff << (~((x + w) - (endword << 5))));
+ temp = &clipmap[(y << 5) + startword];
+ w = endword - startword;
+ if (!w) {
+ bitsleft |= bitsright;
+ for (y = 0; y < h; y++) {
+ *temp |= bitsleft;
+ temp += 32;
+ }
+ } else {
+ for (y = 0; y < h; y++) {
+ *temp++ |= bitsleft;
+ for (x = 1; x < w; x++)
+ *temp++ = 0xffffffff;
+ *temp |= bitsright;
+ temp += (32 - w);
+ }
+ }
+}
+
+static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
+{
+ int i, width, height;
+ u32 *clipmap;
+
+ clipmap = saa->dmavid2;
+ if ((width = saa->win.width) > 1023)
+ width = 1023; /* sanity check */
+ if ((height = saa->win.height) > 640)
+ height = 639; /* sanity check */
+ if (ncr > 0) { /* rectangles pased */
+ /* convert rectangular clips to a bitmap */
+ memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
+ for (i = 0; i < ncr; i++)
+ clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
+ cr[i].width, cr[i].height);
+ }
+ /* clip against viewing window AND screen
+ so we do not have to rely on the user program
+ */
+ clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
+ (saa->win.swidth - saa->win.x) : width, 0, 1024, 768);
+ clip_draw_rectangle(clipmap, 0,
+ (saa->win.y + height > saa->win.sheight) ?
+ (saa->win.sheight - saa->win.y) : height, 1024, 768);
+ if (saa->win.x < 0)
+ clip_draw_rectangle(clipmap, 0, 0, -saa->win.x, 768);
+ if (saa->win.y < 0)
+ clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
+}
+
+static long saa_ioctl(struct file *file,
+ unsigned int cmd, unsigned long argl)
+{
+ struct saa7146 *saa = file->private_data;
+ void __user *arg = (void __user *)argl;
+
+ switch (cmd) {
+ case VIDIOCGCAP:
+ {
+ struct video_capability b;
+ strcpy(b.name, saa->video_dev.name);
+ b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
+ VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+ VID_TYPE_SCALES;
+ b.channels = 1;
+ b.audios = 1;
+ b.maxwidth = 768;
+ b.maxheight = 576;
+ b.minwidth = 32;
+ b.minheight = 32;
+ if (copy_to_user(arg, &b, sizeof(b)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCGPICT:
+ {
+ struct video_picture p = saa->picture;
+ if (saa->win.depth == 8)
+ p.palette = VIDEO_PALETTE_HI240;
+ if (saa->win.depth == 15)
+ p.palette = VIDEO_PALETTE_RGB555;
+ if (saa->win.depth == 16)
+ p.palette = VIDEO_PALETTE_RGB565;
+ if (saa->win.depth == 24)
+ p.palette = VIDEO_PALETTE_RGB24;
+ if (saa->win.depth == 32)
+ p.palette = VIDEO_PALETTE_RGB32;
+ if (copy_to_user(arg, &p, sizeof(p)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSPICT:
+ {
+ struct video_picture p;
+ u32 format;
+ if (copy_from_user(&p, arg, sizeof(p)))
+ return -EFAULT;
+ if (p.palette < ARRAY_SIZE(palette2fmt)) {
+ format = palette2fmt[p.palette];
+ saa->win.color_fmt = format;
+ saawrite(format | 0x60,
+ SAA7146_CLIP_FORMAT_CTRL);
+ }
+ saawrite(((p.brightness & 0xff00) << 16) |
+ ((p.contrast & 0xfe00) << 7) |
+ ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
+ saa->picture = p;
+ /* upload changed registers */
+ saawrite(((SAA7146_MC2_UPLD_HPS_H |
+ SAA7146_MC2_UPLD_HPS_V) << 16) |
+ SAA7146_MC2_UPLD_HPS_H |
+ SAA7146_MC2_UPLD_HPS_V, SAA7146_MC2);
+ return 0;
+ }
+ case VIDIOCSWIN:
+ {
+ struct video_window vw;
+ struct video_clip *vcp = NULL;
+
+ if (copy_from_user(&vw, arg, sizeof(vw)))
+ return -EFAULT;
+
+ /* stop capture */
+ if (vw.flags || vw.width < 16 || vw.height < 16) {
+ saawrite((SAA7146_MC1_TR_E_1 << 16),
+ SAA7146_MC1);
+ return -EINVAL;
+ }
+ /* 32-bit align start and adjust width */
+ if (saa->win.bpp < 4) {
+ int i = vw.x;
+ vw.x = (vw.x + 3) & ~3;
+ i = vw.x - i;
+ vw.width -= i;
+ }
+ saa->win.x = vw.x;
+ saa->win.y = vw.y;
+ saa->win.width = vw.width;
+ if (saa->win.width > 768)
+ saa->win.width = 768;
+ saa->win.height = vw.height;
+ if (CurrentMode == VIDEO_MODE_NTSC) {
+ if (saa->win.height > 480)
+ saa->win.height = 480;
+ } else {
+ if (saa->win.height > 576)
+ saa->win.height = 576;
+ }
+
+ /* stop capture */
+ saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
+ saa7146_set_winsize(saa);
+
+ /*
+ * Do any clips.
+ */
+ if (vw.clipcount < 0) {
+ if (copy_from_user(saa->dmavid2, vw.clips,
+ VIDEO_CLIPMAP_SIZE))
+ return -EFAULT;
+ } else if (vw.clipcount > 16384) {
+ return -EINVAL;
+ } else if (vw.clipcount > 0) {
+ vcp = vmalloc(sizeof(struct video_clip) *
+ vw.clipcount);
+ if (vcp == NULL)
+ return -ENOMEM;
+ if (copy_from_user(vcp, vw.clips,
+ sizeof(struct video_clip) *
+ vw.clipcount)) {
+ vfree(vcp);
+ return -EFAULT;
+ }
+ } else /* nothing clipped */
+ memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
+
+ make_clip_tab(saa, vcp, vw.clipcount);
+ if (vw.clipcount > 0)
+ vfree(vcp);
+
+ /* start capture & clip dma if we have an address */
+ if ((saa->cap & 3) && saa->win.vidadr != 0)
+ saawrite(((SAA7146_MC1_TR_E_1 |
+ SAA7146_MC1_TR_E_2) << 16) | 0xffff,
+ SAA7146_MC1);
+ return 0;
+ }
+ case VIDIOCGWIN:
+ {
+ struct video_window vw;
+ vw.x = saa->win.x;
+ vw.y = saa->win.y;
+ vw.width = saa->win.width;
+ vw.height = saa->win.height;
+ vw.chromakey = 0;
+ vw.flags = 0;
+ if (copy_to_user(arg, &vw, sizeof(vw)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCCAPTURE:
+ {
+ int v;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ if (v == 0) {
+ saa->cap &= ~1;
+ saawrite((SAA7146_MC1_TR_E_1 << 16),
+ SAA7146_MC1);
+ } else {
+ if (saa->win.vidadr == 0 || saa->win.width == 0
+ || saa->win.height == 0)
+ return -EINVAL;
+ saa->cap |= 1;
+ saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
+ SAA7146_MC1);
+ }
+ return 0;
+ }
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer v;
+ v.base = (void *)saa->win.vidadr;
+ v.height = saa->win.sheight;
+ v.width = saa->win.swidth;
+ v.depth = saa->win.depth;
+ v.bytesperline = saa->win.bpl;
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+
+ }
+ case VIDIOCSFBUF:
+ {
+ struct video_buffer v;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
+ v.depth != 24 && v.depth != 32 && v.width > 16 &&
+ v.height > 16 && v.bytesperline > 16)
+ return -EINVAL;
+ if (v.base)
+ saa->win.vidadr = (unsigned long)v.base;
+ saa->win.sheight = v.height;
+ saa->win.swidth = v.width;
+ saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
+ saa->win.depth = v.depth;
+ saa->win.bpl = v.bytesperline;
+
+ DEBUG(printk("Display at %p is %d by %d, bytedepth %d, "
+ "bpl %d\n", v.base, v.width, v.height,
+ saa->win.bpp, saa->win.bpl));
+ saa7146_set_winsize(saa);
+ return 0;
+ }
+ case VIDIOCKEY:
+ {
+ /* Will be handled higher up .. */
+ return 0;
+ }
+
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ v = saa->audio_dev;
+ v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
+ v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
+ strcpy(v.name, "MPEG");
+ v.mode = VIDEO_SOUND_STEREO;
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio v;
+ int i;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ i = (~(v.volume >> 8)) & 0xff;
+ if (!HaveCS4341) {
+ if (v.flags & VIDEO_AUDIO_MUTE)
+ debiwrite(saa, debNormal,
+ IBM_MP2_FRNT_ATTEN, 0xffff, 2);
+ if (!(v.flags & VIDEO_AUDIO_MUTE))
+ debiwrite(saa, debNormal,
+ IBM_MP2_FRNT_ATTEN, 0x0000, 2);
+ if (v.flags & VIDEO_AUDIO_VOLUME)
+ debiwrite(saa, debNormal,
+ IBM_MP2_FRNT_ATTEN,
+ (i << 8) | i, 2);
+ } else {
+ if (v.flags & VIDEO_AUDIO_MUTE)
+ cs4341_setlevel(saa, 0xff, 0xff);
+ if (!(v.flags & VIDEO_AUDIO_MUTE))
+ cs4341_setlevel(saa, 0, 0);
+ if (v.flags & VIDEO_AUDIO_VOLUME)
+ cs4341_setlevel(saa, i, i);
+ }
+ saa->audio_dev = v;
+ return 0;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit vu;
+ vu.video = saa->video_dev.minor;
+ vu.vbi = VIDEO_NO_UNIT;
+ vu.radio = VIDEO_NO_UNIT;
+ vu.audio = VIDEO_NO_UNIT;
+ vu.teletext = VIDEO_NO_UNIT;
+ if (copy_to_user(arg, &vu, sizeof(vu)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSPLAYMODE:
+ {
+ struct video_play_mode pmode;
+ if (copy_from_user((void *)&pmode, arg,
+ sizeof(struct video_play_mode)))
+ return -EFAULT;
+ switch (pmode.mode) {
+ case VID_PLAY_VID_OUT_MODE:
+ if (pmode.p1 != VIDEO_MODE_NTSC &&
+ pmode.p1 != VIDEO_MODE_PAL)
+ return -EINVAL;
+ set_out_format(saa, pmode.p1);
+ return 0;
+ case VID_PLAY_GENLOCK:
+ debiwrite(saa, debNormal, XILINX_CTL0,
+ pmode.p1 ? 0x8000 : 0x8080, 2);
+ if (NewCard)
+ set_genlock_offset(saa, pmode.p2);
+ return 0;
+ case VID_PLAY_NORMAL:
+ debiwrite(saa, debNormal,
+ IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_PAUSE:
+ /* IBM removed the PAUSE command */
+ /* they say use SINGLE_FRAME now */
+ case VID_PLAY_SINGLE_FRAME:
+ ibm_send_command(saa, IBM_MP2_SINGLE_FRAME,0,0);
+ if (saa->playmode == pmode.mode) {
+ debiwrite(saa, debNormal,
+ IBM_MP2_CHIP_CONTROL,
+ ChipControl, 2);
+ }
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_FAST_FORWARD:
+ ibm_send_command(saa, IBM_MP2_FAST_FORWARD,0,0);
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_SLOW_MOTION:
+ ibm_send_command(saa, IBM_MP2_SLOW_MOTION,
+ pmode.p1, 0);
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_IMMEDIATE_NORMAL:
+ /* ensure transfers resume */
+ debiwrite(saa, debNormal,
+ IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ ibm_send_command(saa, IBM_MP2_IMED_NORM_PLAY,
+ 0, 0);
+ saa->playmode = VID_PLAY_NORMAL;
+ return 0;
+ case VID_PLAY_SWITCH_CHANNELS:
+ saa->audhead = saa->audtail = 0;
+ saa->vidhead = saa->vidtail = 0;
+ ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,1);
+ ibm_send_command(saa, IBM_MP2_RESET_AUD_RATE,
+ 0, 1);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+ 0, 2);
+ ibm_send_command(saa, IBM_MP2_CHANNEL_SWITCH,
+ 0, 1);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+ ChipControl, 2);
+ ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+ saa->playmode = VID_PLAY_NORMAL;
+ return 0;
+ case VID_PLAY_FREEZE_FRAME:
+ ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,0);
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_STILL_MODE:
+ ibm_send_command(saa, IBM_MP2_SET_STILL_MODE,
+ 0, 0);
+ saa->playmode = pmode.mode;
+ return 0;
+ case VID_PLAY_MASTER_MODE:
+ if (pmode.p1 == VID_PLAY_MASTER_NONE)
+ saa->boardcfg[1] = 0x13;
+ else if (pmode.p1 == VID_PLAY_MASTER_VIDEO)
+ saa->boardcfg[1] = 0x23;
+ else if (pmode.p1 == VID_PLAY_MASTER_AUDIO)
+ saa->boardcfg[1] = 0x43;
+ else
+ return -EINVAL;
+ debiwrite(saa, debNormal,
+ IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ return 0;
+ case VID_PLAY_ACTIVE_SCANLINES:
+ if (CurrentMode == VIDEO_MODE_PAL) {
+ if (pmode.p1 < 1 || pmode.p2 > 625)
+ return -EINVAL;
+ saa->boardcfg[5] = pmode.p1;
+ saa->boardcfg[55] = (pmode.p1 +
+ (pmode.p2 / 2) - 1) & 0xff;
+ } else {
+ if (pmode.p1 < 4 || pmode.p2 > 525)
+ return -EINVAL;
+ saa->boardcfg[4] = pmode.p1;
+ saa->boardcfg[54] = (pmode.p1 +
+ (pmode.p2 / 2) - 4) & 0xff;
+ }
+ set_out_format(saa, CurrentMode);
+ case VID_PLAY_RESET:
+ return do_ibm_reset(saa);
+ case VID_PLAY_END_MARK:
+ if (saa->endmarktail < saa->endmarkhead) {
+ if (saa->endmarkhead -
+ saa->endmarktail < 2)
+ return -ENOSPC;
+ } else if (saa->endmarkhead <=saa->endmarktail){
+ if (saa->endmarktail - saa->endmarkhead
+ > (MAX_MARKS - 2))
+ return -ENOSPC;
+ } else
+ return -ENOSPC;
+ saa->endmark[saa->endmarktail] = saa->audtail;
+ saa->endmarktail++;
+ if (saa->endmarktail >= MAX_MARKS)
+ saa->endmarktail = 0;
+ }
+ return -EINVAL;
+ }
+ case VIDIOCSWRITEMODE:
+ {
+ int mode;
+ if (copy_from_user((void *)&mode, arg, sizeof(int)))
+ return -EFAULT;
+ if (mode == VID_WRITE_MPEG_AUD ||
+ mode == VID_WRITE_MPEG_VID ||
+ mode == VID_WRITE_CC ||
+ mode == VID_WRITE_TTX ||
+ mode == VID_WRITE_OSD) {
+ saa->writemode = mode;
+ return 0;
+ }
+ return -EINVAL;
+ }
+ case VIDIOCSMICROCODE:
+ {
+ struct video_code ucode;
+ __u8 *udata;
+ int i;
+ if (copy_from_user(&ucode, arg, sizeof(ucode)))
+ return -EFAULT;
+ if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
+ strncmp(ucode.loadwhat, "dec", 3))
+ return -EINVAL;
+ if ((udata = vmalloc(ucode.datasize)) == NULL)
+ return -ENOMEM;
+ if (copy_from_user(udata, ucode.data, ucode.datasize)) {
+ vfree(udata);
+ return -EFAULT;
+ }
+ ucode.data = udata;
+ if (!strncmp(ucode.loadwhat, "decoder.aud", 11) ||
+ !strncmp(ucode.loadwhat, "decoder.vid", 11))
+ i = initialize_ibmmpeg2(&ucode);
+ else
+ i = initialize_fpga(&ucode);
+ vfree(udata);
+ if (i)
+ return -EINVAL;
+ return 0;
+
+ }
+ case VIDIOCGCHAN: /* this makes xawtv happy */
+ {
+ struct video_channel v;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ v.flags = VIDEO_VC_AUDIO;
+ v.tuners = 0;
+ v.type = VID_TYPE_MPEG_DECODER;
+ v.norm = CurrentMode;
+ strcpy(v.name, "MPEG2");
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSCHAN: /* this makes xawtv happy */
+ {
+ struct video_channel v;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ /* do nothing */
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int saa_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct saa7146 *saa = file->private_data;
+ printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
+ return -EINVAL;
+}
+
+static ssize_t saa_read(struct file *file, char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t saa_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ struct saa7146 *saa = file->private_data;
+ unsigned long todo = count;
+ int blocksize, split;
+ unsigned long flags;
+
+ while (todo > 0) {
+ if (saa->writemode == VID_WRITE_MPEG_AUD) {
+ spin_lock_irqsave(&saa->lock, flags);
+ if (saa->audhead <= saa->audtail)
+ blocksize = 65536 -
+ (saa->audtail - saa->audhead);
+ else
+ blocksize = saa->audhead - saa->audtail;
+ spin_unlock_irqrestore(&saa->lock, flags);
+ if (blocksize < 16384) {
+ saawrite(SAA7146_PSR_DEBI_S |
+ SAA7146_PSR_PIN1, SAA7146_IER);
+ saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+ /* wait for buffer space to open */
+ interruptible_sleep_on(&saa->audq);
+ }
+ spin_lock_irqsave(&saa->lock, flags);
+ if (saa->audhead <= saa->audtail) {
+ blocksize = 65536 -
+ (saa->audtail - saa->audhead);
+ split = 65536 - saa->audtail;
+ } else {
+ blocksize = saa->audhead - saa->audtail;
+ split = 65536;
+ }
+ spin_unlock_irqrestore(&saa->lock, flags);
+ blocksize--;
+ if (blocksize > todo)
+ blocksize = todo;
+ /* double check that we really have space */
+ if (!blocksize)
+ return -ENOSPC;
+ if (split < blocksize) {
+ if (copy_from_user(saa->audbuf +
+ saa->audtail, buf, split))
+ return -EFAULT;
+ buf += split;
+ todo -= split;
+ blocksize -= split;
+ saa->audtail = 0;
+ }
+ if (copy_from_user(saa->audbuf + saa->audtail, buf,
+ blocksize))
+ return -EFAULT;
+ saa->audtail += blocksize;
+ todo -= blocksize;
+ buf += blocksize;
+ saa->audtail &= 0xffff;
+ } else if (saa->writemode == VID_WRITE_MPEG_VID) {
+ spin_lock_irqsave(&saa->lock, flags);
+ if (saa->vidhead <= saa->vidtail)
+ blocksize = 524288 -
+ (saa->vidtail - saa->vidhead);
+ else
+ blocksize = saa->vidhead - saa->vidtail;
+ spin_unlock_irqrestore(&saa->lock, flags);
+ if (blocksize < 65536) {
+ saawrite(SAA7146_PSR_DEBI_S |
+ SAA7146_PSR_PIN1, SAA7146_IER);
+ saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+ /* wait for buffer space to open */
+ interruptible_sleep_on(&saa->vidq);
+ }
+ spin_lock_irqsave(&saa->lock, flags);
+ if (saa->vidhead <= saa->vidtail) {
+ blocksize = 524288 -
+ (saa->vidtail - saa->vidhead);
+ split = 524288 - saa->vidtail;
+ } else {
+ blocksize = saa->vidhead - saa->vidtail;
+ split = 524288;
+ }
+ spin_unlock_irqrestore(&saa->lock, flags);
+ blocksize--;
+ if (blocksize > todo)
+ blocksize = todo;
+ /* double check that we really have space */
+ if (!blocksize)
+ return -ENOSPC;
+ if (split < blocksize) {
+ if (copy_from_user(saa->vidbuf +
+ saa->vidtail, buf, split))
+ return -EFAULT;
+ buf += split;
+ todo -= split;
+ blocksize -= split;
+ saa->vidtail = 0;
+ }
+ if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
+ blocksize))
+ return -EFAULT;
+ saa->vidtail += blocksize;
+ todo -= blocksize;
+ buf += blocksize;
+ saa->vidtail &= 0x7ffff;
+ } else if (saa->writemode == VID_WRITE_OSD) {
+ if (count > 131072)
+ return -ENOSPC;
+ if (copy_from_user(saa->osdbuf, buf, count))
+ return -EFAULT;
+ buf += count;
+ saa->osdhead = 0;
+ saa->osdtail = count;
+ debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ debiread(saa, debNormal,
+ IBM_MP2_DISP_MODE, 2) | 1, 2);
+ /* trigger osd data transfer */
+ saawrite(SAA7146_PSR_DEBI_S |
+ SAA7146_PSR_PIN1, SAA7146_IER);
+ saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+ }
+ }
+ return count;
+}
+
+static int saa_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
+
+ lock_kernel();
+ file->private_data = saa;
+
+ saa->user++;
+ if (saa->user > 1) {
+ unlock_kernel();
+ return 0; /* device open already, don't reset */
+ }
+ saa->writemode = VID_WRITE_MPEG_VID; /* default to video */
+ unlock_kernel();
+ return 0;
+}
+
+static int saa_release(struct file *file)
+{
+ struct saa7146 *saa = file->private_data;
+ saa->user--;
+
+ if (saa->user > 0) /* still someone using device */
+ return 0;
+ saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */
+ return 0;
+}
+
+static const struct v4l2_file_operations saa_fops = {
+ .owner = THIS_MODULE,
+ .open = saa_open,
+ .release = saa_release,
+ .ioctl = saa_ioctl,
+ .read = saa_read,
+ .write = saa_write,
+ .mmap = saa_mmap,
+};
+
+/* template for video_device-structure */
+static struct video_device saa_template = {
+ .name = "SAA7146A",
+ .fops = &saa_fops,
+ .release = video_device_release_empty,
+};
+
+static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
+{
+ int retval;
+ struct saa7146 *saa = pci_get_drvdata(pdev);
+
+ saa->endmarkhead = saa->endmarktail = 0;
+ saa->win.x = saa->win.y = 0;
+ saa->win.width = saa->win.cropwidth = 720;
+ saa->win.height = saa->win.cropheight = 480;
+ saa->win.cropx = saa->win.cropy = 0;
+ saa->win.bpp = 2;
+ saa->win.depth = 16;
+ saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
+ saa->win.bpl = 1024 * saa->win.bpp;
+ saa->win.swidth = 1024;
+ saa->win.sheight = 768;
+ saa->picture.brightness = 32768;
+ saa->picture.contrast = 38768;
+ saa->picture.colour = 32768;
+ saa->cap = 0;
+ saa->nr = num;
+ saa->playmode = VID_PLAY_NORMAL;
+ memset(saa->boardcfg, 0, 64); /* clear board config area */
+ saa->saa7146_mem = NULL;
+ saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
+ saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
+ saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
+ saa->pagea1out = saa->pagea2in = saa->pagea2out =
+ saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
+ saa->pageRPS2 = NULL;
+ saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
+ saa->audhead = saa->vidtail = 0;
+
+ init_waitqueue_head(&saa->i2cq);
+ init_waitqueue_head(&saa->audq);
+ init_waitqueue_head(&saa->debiq);
+ init_waitqueue_head(&saa->vidq);
+ spin_lock_init(&saa->lock);
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "%d: pci_enable_device failed!\n", num);
+ goto err;
+ }
+
+ saa->id = pdev->device;
+ saa->irq = pdev->irq;
+ saa->saa7146_adr = pci_resource_start(pdev, 0);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision);
+
+ saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
+ if (saa->saa7146_mem == NULL) {
+ dev_err(&pdev->dev, "%d: ioremap failed!\n", num);
+ retval = -EIO;
+ goto err;
+ }
+
+ memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
+ saawrite(0, SAA7146_IER); /* turn off all interrupts */
+
+ retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
+ "stradis", saa);
+ if (retval == -EINVAL)
+ dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
+ else if (retval == -EBUSY)
+ dev_err(&pdev->dev, "%d: IRQ %ld busy, change your PnP config "
+ "in BIOS\n", num, saa->irq);
+ if (retval < 0)
+ goto errio;
+
+ pci_set_master(pdev);
+ retval = video_register_device(&saa->video_dev, VFL_TYPE_GRABBER,
+ video_nr);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "%d: error in registering video device!\n",
+ num);
+ goto errio;
+ }
+
+ return 0;
+errio:
+ iounmap(saa->saa7146_mem);
+err:
+ return retval;
+}
+
+static int __devinit init_saa7146(struct pci_dev *pdev)
+{
+ struct saa7146 *saa = pci_get_drvdata(pdev);
+
+ saa->user = 0;
+ /* reset the saa7146 */
+ saawrite(0xffff0000, SAA7146_MC1);
+ mdelay(5);
+ /* enable debi and i2c transfers and pins */
+ saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
+ SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
+ /* ensure proper state of chip */
+ saawrite(0x00000000, SAA7146_PAGE1);
+ saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
+ saawrite(0x00000000, SAA7146_PAGE2);
+ saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
+ saawrite(0x00000000, SAA7146_DD1_INIT);
+ saawrite(0x00000000, SAA7146_DD1_STREAM_B);
+ saawrite(0x00000000, SAA7146_DD1_STREAM_A);
+ saawrite(0x00000000, SAA7146_BRS_CTRL);
+ saawrite(0x80400040, SAA7146_BCS_CTRL);
+ saawrite(0x0000e000 /*| (1<<29) */ , SAA7146_HPS_CTRL);
+ saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
+ saawrite(0x00000000, SAA7146_ACON1);
+ saawrite(0x00000000, SAA7146_ACON2);
+ saawrite(0x00000600, SAA7146_I2C_STATUS);
+ saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
+ SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
+ SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
+ SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
+ SAA7146_MC2);
+ /* setup arbitration control registers */
+ saawrite(0x1412121a, SAA7146_PCI_BT_V1);
+
+ /* allocate 32k dma buffer + 4k for page table */
+ if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
+ dev_err(&pdev->dev, "%d: debi kmalloc failed\n", saa->nr);
+ goto err;
+ }
+#if 0
+ saa->pagedebi = saa->dmadebi + 32768; /* top 4k is for mmu */
+ saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
+ for (i = 0; i < 12; i++) /* setup mmu page table */
+ saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
+#endif
+ saa->audhead = saa->vidhead = saa->osdhead = 0;
+ saa->audtail = saa->vidtail = saa->osdtail = 0;
+ if (saa->vidbuf == NULL && (saa->vidbuf = vmalloc(524288)) == NULL) {
+ dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+ goto err;
+ }
+ if (saa->audbuf == NULL && (saa->audbuf = vmalloc(65536)) == NULL) {
+ dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+ goto errfree;
+ }
+ if (saa->osdbuf == NULL && (saa->osdbuf = vmalloc(131072)) == NULL) {
+ dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+ goto errfree;
+ }
+ /* allocate 81920 byte buffer for clipping */
+ if ((saa->dmavid2 = kzalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
+ dev_err(&pdev->dev, "%d: clip kmalloc failed\n", saa->nr);
+ goto errfree;
+ }
+ /* setup clipping registers */
+ saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
+ saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
+ saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
+ SAA7146_PROT_ADDR2);
+ saawrite(256, SAA7146_PITCH2);
+ saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */
+ saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
+ SAA7146_MC2);
+ I2CBusScan(saa);
+
+ return 0;
+errfree:
+ vfree(saa->osdbuf);
+ vfree(saa->audbuf);
+ vfree(saa->vidbuf);
+ saa->audbuf = saa->osdbuf = saa->vidbuf = NULL;
+err:
+ return -ENOMEM;
+}
+
+static void stradis_release_saa(struct pci_dev *pdev)
+{
+ u8 command;
+ struct saa7146 *saa = pci_get_drvdata(pdev);
+
+ /* turn off all capturing, DMA and IRQs */
+ saawrite(0xffff0000, SAA7146_MC1); /* reset chip */
+ saawrite(0, SAA7146_MC2);
+ saawrite(0, SAA7146_IER);
+ saawrite(0xffffffffUL, SAA7146_ISR);
+
+ /* disable PCI bus-mastering */
+ pci_read_config_byte(pdev, PCI_COMMAND, &command);
+ command &= ~PCI_COMMAND_MASTER;
+ pci_write_config_byte(pdev, PCI_COMMAND, command);
+
+ /* unmap and free memory */
+ saa->audhead = saa->audtail = saa->osdhead = 0;
+ saa->vidhead = saa->vidtail = saa->osdtail = 0;
+ vfree(saa->vidbuf);
+ vfree(saa->audbuf);
+ vfree(saa->osdbuf);
+ kfree(saa->dmavid2);
+ saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
+ saa->dmavid2 = NULL;
+ kfree(saa->dmadebi);
+ kfree(saa->dmavid1);
+ kfree(saa->dmavid3);
+ kfree(saa->dmaa1in);
+ kfree(saa->dmaa1out);
+ kfree(saa->dmaa2in);
+ kfree(saa->dmaa2out);
+ kfree(saa->dmaRPS1);
+ kfree(saa->dmaRPS2);
+ free_irq(saa->irq, saa);
+ if (saa->saa7146_mem)
+ iounmap(saa->saa7146_mem);
+ if (video_is_registered(&saa->video_dev))
+ video_unregister_device(&saa->video_dev);
+}
+
+static int __devinit stradis_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int retval = -EINVAL;
+
+ if (saa_num >= SAA7146_MAX)
+ goto err;
+
+ if (!pdev->subsystem_vendor)
+ dev_info(&pdev->dev, "%d: rev1 decoder\n", saa_num);
+ else
+ dev_info(&pdev->dev, "%d: SDM2xx found\n", saa_num);
+
+ pci_set_drvdata(pdev, &saa7146s[saa_num]);
+
+ retval = configure_saa7146(pdev, saa_num);
+ if (retval) {
+ dev_err(&pdev->dev, "%d: error in configuring\n", saa_num);
+ goto err;
+ }
+
+ if (init_saa7146(pdev) < 0) {
+ dev_err(&pdev->dev, "%d: error in initialization\n", saa_num);
+ retval = -EIO;
+ goto errrel;
+ }
+
+ saa_num++;
+
+ return 0;
+errrel:
+ stradis_release_saa(pdev);
+err:
+ return retval;
+}
+
+static void __devexit stradis_remove(struct pci_dev *pdev)
+{
+ stradis_release_saa(pdev);
+}
+
+static struct pci_device_id stradis_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146) },
+ { 0 }
+};
+
+
+static struct pci_driver stradis_driver = {
+ .name = "stradis",
+ .id_table = stradis_pci_tbl,
+ .probe = stradis_probe,
+ .remove = __devexit_p(stradis_remove)
+};
+
+static int __init stradis_init(void)
+{
+ int retval;
+
+ saa_num = 0;
+
+ retval = pci_register_driver(&stradis_driver);
+ if (retval)
+ printk(KERN_ERR "stradis: Unable to register pci driver.\n");
+
+ return retval;
+}
+
+static void __exit stradis_exit(void)
+{
+ pci_unregister_driver(&stradis_driver);
+ printk(KERN_INFO "stradis: module cleanup complete\n");
+}
+
+module_init(stradis_init);
+module_exit(stradis_exit);
diff --git a/drivers/staging/tm6000/TODO b/drivers/staging/tm6000/TODO
new file mode 100644
index 000000000000..34780fc17b16
--- /dev/null
+++ b/drivers/staging/tm6000/TODO
@@ -0,0 +1,6 @@
+There a few things to do before putting this driver in production:
+ - CodingStyle;
+ - Fix audio;
+ - Fix some panic/OOPS conditions.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index 087137d9164d..e379e3ec4442 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -160,15 +160,15 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
- .period_bytes_min = 62720,
- .period_bytes_max = 62720,
+ .period_bytes_min = 64,
+ .period_bytes_max = 12544,
.periods_min = 1,
- .periods_max = 1024,
+ .periods_max = 98,
.buffer_bytes_max = 62720 * 8,
};
@@ -201,6 +201,14 @@ _error:
*/
static int snd_tm6000_close(struct snd_pcm_substream *substream)
{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
+
return 0;
}
@@ -211,38 +219,67 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
struct snd_pcm_runtime *runtime;
int period_elapsed = 0;
unsigned int stride, buf_pos;
+ int length;
+
+ if (atomic_read(&core->stream_started) == 0)
+ return 0;
- if (!size || !substream)
+ if (!size || !substream) {
+ dprintk(1, "substream was NULL\n");
return -EINVAL;
+ }
runtime = substream->runtime;
- if (!runtime || !runtime->dma_area)
+ if (!runtime || !runtime->dma_area) {
+ dprintk(1, "runtime was NULL\n");
return -EINVAL;
+ }
buf_pos = chip->buf_pos;
stride = runtime->frame_bits >> 3;
+ if (stride == 0) {
+ dprintk(1, "stride is zero\n");
+ return -EINVAL;
+ }
+
+ length = size / stride;
+ if (length == 0) {
+ dprintk(1, "%s: length was zero\n", __func__);
+ return -EINVAL;
+ }
+
dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
runtime->dma_area, buf_pos,
(unsigned int)runtime->buffer_size, stride);
- if (buf_pos + size >= runtime->buffer_size * stride) {
- unsigned int cnt = runtime->buffer_size * stride - buf_pos;
- memcpy(runtime->dma_area + buf_pos, buf, cnt);
- memcpy(runtime->dma_area, buf + cnt, size - cnt);
+ if (buf_pos + length >= runtime->buffer_size) {
+ unsigned int cnt = runtime->buffer_size - buf_pos;
+ memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
+ memcpy(runtime->dma_area, buf + cnt * stride,
+ length * stride - cnt * stride);
} else
- memcpy(runtime->dma_area + buf_pos, buf, size);
+ memcpy(runtime->dma_area + buf_pos * stride, buf,
+ length * stride);
- chip->buf_pos += size;
- if (chip->buf_pos >= runtime->buffer_size * stride)
- chip->buf_pos -= runtime->buffer_size * stride;
+#ifndef NO_PCM_LOCK
+ snd_pcm_stream_lock(substream);
+#endif
- chip->period_pos += size;
+ chip->buf_pos += length;
+ if (chip->buf_pos >= runtime->buffer_size)
+ chip->buf_pos -= runtime->buffer_size;
+
+ chip->period_pos += length;
if (chip->period_pos >= runtime->period_size) {
chip->period_pos -= runtime->period_size;
period_elapsed = 1;
}
+#ifndef NO_PCM_LOCK
+ snd_pcm_stream_unlock(substream);
+#endif
+
if (period_elapsed)
snd_pcm_period_elapsed(substream);
@@ -272,8 +309,12 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
{
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
- _tm6000_stop_audio_dma(chip);
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
return 0;
}
@@ -295,30 +336,42 @@ static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
/*
* trigger callback
*/
+static void audio_trigger(struct work_struct *work)
+{
+ struct tm6000_core *core = container_of(work, struct tm6000_core,
+ wq_trigger);
+ struct snd_tm6000_card *chip = core->adev;
+
+ if (atomic_read(&core->stream_started)) {
+ dprintk(1, "starting capture");
+ _tm6000_start_audio_dma(chip);
+ } else {
+ dprintk(1, "stopping capture");
+ _tm6000_stop_audio_dma(chip);
+ }
+}
+
static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- int err;
-
- spin_lock(&chip->reg_lock);
+ struct tm6000_core *core = chip->core;
+ int err = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- err = _tm6000_start_audio_dma(chip);
+ atomic_set(&core->stream_started, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
- err = _tm6000_stop_audio_dma(chip);
+ atomic_set(&core->stream_started, 0);
break;
default:
err = -EINVAL;
break;
}
-
- spin_unlock(&chip->reg_lock);
+ schedule_work(&core->wq_trigger);
return err;
}
-
/*
* pointer callback
*/
@@ -411,6 +464,7 @@ int tm6000_audio_init(struct tm6000_core *dev)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
rc = snd_card_register(card);
if (rc < 0)
goto error;
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 9d091c34991b..664e6038090d 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -1,20 +1,20 @@
/*
- tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -349,7 +349,7 @@ int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
dev->gpio.tuner_reset, 0x01);
break;
}
- return (rc);
+ return rc;
}
EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
@@ -545,7 +545,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
/* Load tuner module */
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ NULL, "tuner", dev->tuner_addr, NULL);
memset(&tun_setup, 0, sizeof(tun_setup));
tun_setup.type = dev->tuner_type;
@@ -683,7 +683,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
if (dev->caps.has_tda9874)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL);
+ NULL, "tvaudio", I2C_ADDR_TDA9874, NULL);
/* register and initialize V4L2 */
rc = tm6000_v4l2_register(dev);
@@ -909,8 +909,6 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
- mutex_lock(&dev->lock);
-
tm6000_ir_fini(dev);
if (dev->gpio.power_led) {
@@ -945,7 +943,6 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
tm6000_close_extension(dev);
tm6000_remove_from_devlist(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
}
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index cded411d8bba..df3f187959b9 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -1,23 +1,23 @@
/*
- tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- - DVB-T support
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ * - DVB-T support
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -30,14 +30,13 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
-#define USB_TIMEOUT 5*HZ /* ms */
+#define USB_TIMEOUT (5 * HZ) /* ms */
int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
u16 value, u16 index, u8 *buf, u16 len)
{
int ret, i;
unsigned int pipe;
- static int ini = 0, last = 0, n = 0;
u8 *data = NULL;
if (len)
@@ -52,19 +51,12 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
}
if (tm6000_debug & V4L2_DEBUG_I2C) {
- if (!ini)
- last = ini = jiffies;
-
- printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
+ printk("(dev %p, pipe %08x): ", dev->udev, pipe);
- printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+ printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
(req_type & USB_DIR_IN) ? " IN" : "OUT",
- jiffies_to_msecs(jiffies-last),
- jiffies_to_msecs(jiffies-ini),
req_type, req, value&0xff, value>>8, index&0xff,
index>>8, len&0xff, len>>8);
- last = jiffies;
- n++;
if (!(req_type & USB_DIR_IN)) {
printk(">>> ");
@@ -186,21 +178,17 @@ void tm6000_set_fourcc_format(struct tm6000_core *dev)
}
}
-int tm6000_init_analog_mode(struct tm6000_core *dev)
+static void tm6000_set_vbi(struct tm6000_core *dev)
{
- if (dev->dev_type == TM6010) {
- int val;
+ /*
+ * FIXME:
+ * VBI lines and start/end are different between 60Hz and 50Hz
+ * So, it is very likely that we need to change the config to
+ * something that takes it into account, doing something different
+ * if (dev->norm & V4L2_STD_525_60)
+ */
- /* Enable video */
- val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
- val |= 0x60;
- tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
- val = tm6000_get_reg(dev,
- TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
- val &= ~0x40;
- tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
-
- /* Init teletext */
+ if (dev->dev_type == TM6010) {
tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
@@ -249,44 +237,26 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
+ }
+}
+int tm6000_init_analog_mode(struct tm6000_core *dev)
+{
+ struct v4l2_frequency f;
+
+ if (dev->dev_type == TM6010) {
+ int val;
+
+ /* Enable video */
+ val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
+ val |= 0x60;
+ tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+ val = tm6000_get_reg(dev,
+ TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
+ val &= ~0x40;
+ tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
- /* Init audio */
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
- tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
- tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x05);
- tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x06);
- tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
- tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
- tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
- tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
- tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
- tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
- tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
- tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
- tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
- tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
- tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
- tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
- tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
- tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
- tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
- tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
- tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
- tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
- tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
- tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+ tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
} else {
/* Enables soft reset */
@@ -325,15 +295,22 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
/* Tuner firmware can now be loaded */
- /*FIXME: Hack!!! */
- struct v4l2_frequency f;
- mutex_lock(&dev->lock);
+ /*
+ * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
+ * for more than a few seconds. Not sure why, as this behavior does
+ * not happen on other devices with xc3028. So, I suspect that it
+ * is yet another bug at tm6000. After start sleeping, decoding
+ * doesn't start automatically. Instead, it requires some
+ * I2C commands to wake it up. As we want to have image at the
+ * beginning, we needed to add this hack. The better would be to
+ * discover some way to make tm6000 to wake up without this hack.
+ */
f.frequency = dev->freq;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
- mutex_unlock(&dev->lock);
msleep(100);
tm6000_set_standard(dev, &dev->norm);
+ tm6000_set_vbi(dev);
tm6000_set_audio_bitrate(dev, 48000);
/* switch dvb led off */
@@ -361,7 +338,6 @@ int tm6000_init_digital_mode(struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
- tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]);
} else {
@@ -660,7 +636,6 @@ void tm6000_add_into_devlist(struct tm6000_core *dev)
*/
static LIST_HEAD(tm6000_extension_devlist);
-static DEFINE_MUTEX(tm6000_extension_devlist_lock);
int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
char *buf, int size)
@@ -684,14 +659,12 @@ int tm6000_register_extension(struct tm6000_ops *ops)
struct tm6000_core *dev = NULL;
mutex_lock(&tm6000_devlist_mutex);
- mutex_lock(&tm6000_extension_devlist_lock);
list_add_tail(&ops->next, &tm6000_extension_devlist);
list_for_each_entry(dev, &tm6000_devlist, devlist) {
ops->init(dev);
printk(KERN_INFO "%s: Initialized (%s) extension\n",
dev->name, ops->name);
}
- mutex_unlock(&tm6000_extension_devlist_lock);
mutex_unlock(&tm6000_devlist_mutex);
return 0;
}
@@ -707,10 +680,8 @@ void tm6000_unregister_extension(struct tm6000_ops *ops)
ops->fini(dev);
}
- mutex_lock(&tm6000_extension_devlist_lock);
printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
list_del(&ops->next);
- mutex_unlock(&tm6000_extension_devlist_lock);
mutex_unlock(&tm6000_devlist_mutex);
}
EXPORT_SYMBOL(tm6000_unregister_extension);
@@ -719,26 +690,26 @@ void tm6000_init_extension(struct tm6000_core *dev)
{
struct tm6000_ops *ops = NULL;
- mutex_lock(&tm6000_extension_devlist_lock);
+ mutex_lock(&tm6000_devlist_mutex);
if (!list_empty(&tm6000_extension_devlist)) {
list_for_each_entry(ops, &tm6000_extension_devlist, next) {
if (ops->init)
ops->init(dev);
}
}
- mutex_unlock(&tm6000_extension_devlist_lock);
+ mutex_unlock(&tm6000_devlist_mutex);
}
void tm6000_close_extension(struct tm6000_core *dev)
{
struct tm6000_ops *ops = NULL;
- mutex_lock(&tm6000_extension_devlist_lock);
+ mutex_lock(&tm6000_devlist_mutex);
if (!list_empty(&tm6000_extension_devlist)) {
list_for_each_entry(ops, &tm6000_extension_devlist, next) {
if (ops->fini)
ops->fini(dev);
}
}
- mutex_unlock(&tm6000_extension_devlist_lock);
+ mutex_lock(&tm6000_devlist_mutex);
}
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
index f501edccf9c4..ff04c89e45a3 100644
--- a/drivers/staging/tm6000/tm6000-dvb.c
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -1,20 +1,20 @@
/*
- tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
index 79bc67f0311f..3e46866dd279 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -1,23 +1,23 @@
/*
- tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- - Fix SMBus Read Byte command
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ * - Fix SMBus Read Byte command
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -32,11 +32,9 @@
#include "tuner-xc2028.h"
-/*FIXME: Hack to avoid needing to patch i2c-id.h */
-#define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
/* ----------------------------------------------------------- */
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
@@ -324,7 +322,6 @@ static struct i2c_adapter tm6000_adap_template = {
.owner = THIS_MODULE,
.class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
.name = "tm6000",
- .id = I2C_HW_B_TM6000,
.algo = &tm6000_algo,
};
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
index 54f7667cc706..6022caaa739b 100644
--- a/drivers/staging/tm6000/tm6000-input.c
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -1,20 +1,20 @@
/*
- tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
static unsigned int enable_ir = 1;
module_param(enable_ir, int, 0644);
-MODULE_PARM_DESC(enable_ir, "enable ir (default is enable");
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
#undef dprintk
diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h
index 1c5289c971fa..1f0ced8fa20f 100644
--- a/drivers/staging/tm6000/tm6000-regs.h
+++ b/drivers/staging/tm6000/tm6000-regs.h
@@ -1,20 +1,20 @@
/*
- tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
index 6bf4a73b320d..cc7b8664fc20 100644
--- a/drivers/staging/tm6000/tm6000-stds.c
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -1,20 +1,20 @@
/*
- tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -28,21 +28,37 @@ struct tm6000_reg_settings {
unsigned char value;
};
+enum tm6000_audio_std {
+ BG_NICAM,
+ BTSC,
+ BG_A2,
+ DK_NICAM,
+ EIAJ,
+ FM_RADIO,
+ I_NICAM,
+ KOREA_A2,
+ L_NICAM,
+};
+
struct tm6000_std_tv_settings {
v4l2_std_id id;
+ enum tm6000_audio_std audio_default_std;
+
struct tm6000_reg_settings sif[12];
struct tm6000_reg_settings nosif[12];
- struct tm6000_reg_settings common[25];
+ struct tm6000_reg_settings common[26];
};
struct tm6000_std_settings {
v4l2_std_id id;
+ enum tm6000_audio_std audio_default_std;
struct tm6000_reg_settings common[37];
};
static struct tm6000_std_tv_settings tv_stds[] = {
{
.id = V4L2_STD_PAL_M,
+ .audio_default_std = BTSC,
.sif = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -96,11 +112,14 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
{TM6010_REQ07_R3F_RESET, 0x00},
+
{0, 0, 0},
},
}, {
.id = V4L2_STD_PAL_Nc,
+ .audio_default_std = BTSC,
.sif = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -154,11 +173,14 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
{TM6010_REQ07_R3F_RESET, 0x00},
+
{0, 0, 0},
},
}, {
.id = V4L2_STD_PAL,
+ .audio_default_std = BG_A2,
.sif = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -212,11 +234,73 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc},
{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
{TM6010_REQ07_R3F_RESET, 0x00},
+
{0, 0, 0},
},
}, {
- .id = V4L2_STD_SECAM,
+ .id = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+ .audio_default_std = BG_NICAM,
+ .sif = {
+ {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
+ {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+ {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+ {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08},
+ {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+ {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+ {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+ {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+ {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62},
+ {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe},
+ {TM6010_REQ07_RFE_POWER_DOWN, 0xcb},
+ {0, 0, 0},
+ },
+ .nosif = {
+ {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+ {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
+ {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+ {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+ {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+ {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+ {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+ {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+ {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60},
+ {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+ {TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {TM6010_REQ07_R3F_RESET, 0x01},
+ {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+ {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+ {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+ {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
+ {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+ {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+ {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+ {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+ {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+ {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+ {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+ {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+ {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+ {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+ {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+ {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+ {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+ {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+ {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+ {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
+ {TM6010_REQ07_R3F_RESET, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM_DK,
+ .audio_default_std = DK_NICAM,
.sif = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -269,11 +353,13 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
{TM6010_REQ07_R3F_RESET, 0x00},
{0, 0, 0},
},
}, {
.id = V4L2_STD_NTSC,
+ .audio_default_std = BTSC,
.sif = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8},
@@ -327,7 +413,9 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd},
{TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+
{TM6010_REQ07_R3F_RESET, 0x00},
+
{0, 0, 0},
},
},
@@ -336,6 +424,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
static struct tm6000_std_settings composite_stds[] = {
{
.id = V4L2_STD_PAL_M,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -378,6 +467,7 @@ static struct tm6000_std_settings composite_stds[] = {
},
}, {
.id = V4L2_STD_PAL_Nc,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -420,6 +510,7 @@ static struct tm6000_std_settings composite_stds[] = {
},
}, {
.id = V4L2_STD_PAL,
+ .audio_default_std = BG_A2,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -462,6 +553,49 @@ static struct tm6000_std_settings composite_stds[] = {
},
}, {
.id = V4L2_STD_SECAM,
+ .audio_default_std = BG_NICAM,
+ .common = {
+ {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+ {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
+ {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3},
+ {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f},
+ {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1},
+ {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0},
+ {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+ {TM6010_REQ08_RED_GAIN_SEL, 0xe8},
+ {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+ {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+ {TM6010_REQ07_RFE_POWER_DOWN, 0x8b},
+
+ {TM6010_REQ07_R3F_RESET, 0x01},
+ {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38},
+ {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+ {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+ {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
+ {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+ {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+ {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+ {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+ {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+ {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+ {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+ {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+ {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+ {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c},
+ {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+ {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+ {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+ {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+ {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+ {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+ {TM6010_REQ07_R3F_RESET, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM_DK,
+ .audio_default_std = DK_NICAM,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -503,6 +637,7 @@ static struct tm6000_std_settings composite_stds[] = {
},
}, {
.id = V4L2_STD_NTSC,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4},
@@ -549,6 +684,7 @@ static struct tm6000_std_settings composite_stds[] = {
static struct tm6000_std_settings svideo_stds[] = {
{
.id = V4L2_STD_PAL_M,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -591,6 +727,7 @@ static struct tm6000_std_settings svideo_stds[] = {
},
}, {
.id = V4L2_STD_PAL_Nc,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -633,6 +770,7 @@ static struct tm6000_std_settings svideo_stds[] = {
},
}, {
.id = V4L2_STD_PAL,
+ .audio_default_std = BG_A2,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -675,6 +813,49 @@ static struct tm6000_std_settings svideo_stds[] = {
},
}, {
.id = V4L2_STD_SECAM,
+ .audio_default_std = BG_NICAM,
+ .common = {
+ {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
+ {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
+ {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8},
+ {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00},
+ {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2},
+ {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0},
+ {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2},
+ {TM6010_REQ08_RED_GAIN_SEL, 0xe0},
+ {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68},
+ {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc},
+ {TM6010_REQ07_RFE_POWER_DOWN, 0x8a},
+
+ {TM6010_REQ07_R3F_RESET, 0x01},
+ {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39},
+ {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
+ {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
+ {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
+ {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
+ {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
+ {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
+ {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed},
+ {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c},
+ {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc},
+ {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc},
+ {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd},
+ {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c},
+ {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a},
+ {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1},
+ {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c},
+ {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18},
+ {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42},
+ {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF},
+
+ {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07},
+ {TM6010_REQ07_R3F_RESET, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM_DK,
+ .audio_default_std = DK_NICAM,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -716,6 +897,7 @@ static struct tm6000_std_settings svideo_stds[] = {
},
}, {
.id = V4L2_STD_NTSC,
+ .audio_default_std = BTSC,
.common = {
{TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0},
{TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc},
@@ -760,6 +942,133 @@ static struct tm6000_std_settings svideo_stds[] = {
},
};
+
+static int tm6000_set_audio_std(struct tm6000_core *dev,
+ enum tm6000_audio_std std)
+{
+ uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
+ uint8_t areg_05 = 0x09; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
+ uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
+ uint8_t mono_flag = 0; /* No mono */
+ uint8_t nicam_flag = 0; /* No NICAM */
+
+ switch (std) {
+#if 0
+ case DK_MONO:
+ mono_flag = 1;
+ break;
+ case DK_A2_1:
+ break;
+ case DK_A2_3:
+ areg_05 = 0x0b;
+ break;
+ case BG_MONO:
+ mono_flag = 1;
+ areg_05 = 0x05;
+ break;
+#endif
+ case BG_NICAM:
+ areg_05 = 0x07;
+ nicam_flag = 1;
+ break;
+ case BTSC:
+ areg_05 = 0x02;
+ break;
+ case BG_A2:
+ areg_05 = 0x05;
+ break;
+ case DK_NICAM:
+ areg_05 = 0x06;
+ nicam_flag = 1;
+ break;
+ case EIAJ:
+ areg_05 = 0x02;
+ break;
+ case FM_RADIO:
+ tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
+ tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
+ tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
+ tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+ tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+ tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+ tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+ tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+ return 0;
+ break;
+ case I_NICAM:
+ areg_05 = 0x08;
+ nicam_flag = 1;
+ break;
+ case KOREA_A2:
+ areg_05 = 0x04;
+ break;
+ case L_NICAM:
+ areg_02 = 0x02; /* GC1 Fixed gain +12dB */
+ areg_05 = 0x0a;
+ nicam_flag = 1;
+ break;
+ }
+
+#if 0
+ switch (tv_audio_mode) {
+ case TV_MONO:
+ areg_06 = (nicam_flag) ? 0x03 : 0x00;
+ break;
+ case TV_LANG_A:
+ areg_06 = 0x00;
+ break;
+ case TV_LANG_B:
+ areg_06 = 0x01;
+ break;
+ }
+#endif
+
+ if (mono_flag)
+ areg_06 = 0x00;
+
+ tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
+ tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
+ tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
+ tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
+ tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
+ tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
+ tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
+ tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
+ tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
+ tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
+ tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
+ tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
+ tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
+ tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
+ tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
+ tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
+ tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
+ tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
+ tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
+ tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
+ tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
+ tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
+ tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
+ tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
+ tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+ tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
+ tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+ tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
+ tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+
+ return 0;
+}
+
void tm6000_get_std_res(struct tm6000_core *dev)
{
/* Currently, those are the only supported resoltions */
@@ -820,6 +1129,8 @@ static int tm6000_set_tv(struct tm6000_core *dev, int pos)
rc = tm6000_load_std(dev, tv_stds[pos].common,
sizeof(tv_stds[pos].common));
+ tm6000_set_audio_std(dev, tv_stds[pos].audio_default_std);
+
return rc;
}
@@ -845,6 +1156,8 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
rc = tm6000_load_std(dev, svideo_stds[i].common,
sizeof(svideo_stds[i].
common));
+ tm6000_set_audio_std(dev, svideo_stds[i].audio_default_std);
+
goto ret;
}
}
@@ -856,6 +1169,7 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
composite_stds[i].common,
sizeof(composite_stds[i].
common));
+ tm6000_set_audio_std(dev, composite_stds[i].audio_default_std);
goto ret;
}
}
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
index 138716a8f056..a9e61d95a9b2 100644
--- a/drivers/staging/tm6000/tm6000-usb-isoc.h
+++ b/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -1,20 +1,20 @@
/*
- tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/videodev2.h>
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index ce0a089a0771..9ec82796634e 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -1,23 +1,23 @@
/*
- tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- - Fixed module load/unload
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ * - Fixed module load/unload
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/delay.h>
@@ -118,8 +118,9 @@ static struct tm6000_fmt format[] = {
};
/* ------------------------------------------------------------------
- DMA and thread functions
- ------------------------------------------------------------------*/
+ * DMA and thread functions
+ * ------------------------------------------------------------------
+ */
#define norm_maxw(a) 720
#define norm_maxh(a) 576
@@ -189,17 +190,17 @@ static int copy_streams(u8 *data, unsigned long len,
struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
- u8 *ptr=data, *endp=data+len, c;
- unsigned long header=0;
- int rc=0;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ u8 *ptr = data, *endp = data+len, c;
+ unsigned long header = 0;
+ int rc = 0;
unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
struct tm6000_buffer *vbuf;
char *voutp = NULL;
unsigned int linewidth;
/* get video buffer */
- get_next_buf (dma_q, &vbuf);
+ get_next_buf(dma_q, &vbuf);
if (!vbuf)
return rc;
voutp = videobuf_to_vmalloc(&vbuf->vb);
@@ -213,7 +214,7 @@ static int copy_streams(u8 *data, unsigned long len,
/* from last urb or packet */
header = dev->isoc_ctl.tmp_buf;
if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
- memcpy ((u8 *)&header +
+ memcpy((u8 *)&header +
dev->isoc_ctl.tmp_buf_len,
ptr,
4 - dev->isoc_ctl.tmp_buf_len);
@@ -224,7 +225,7 @@ static int copy_streams(u8 *data, unsigned long len,
if (ptr + 3 >= endp) {
/* have incomplete header */
dev->isoc_ctl.tmp_buf_len = endp - ptr;
- memcpy (&dev->isoc_ctl.tmp_buf, ptr,
+ memcpy(&dev->isoc_ctl.tmp_buf, ptr,
dev->isoc_ctl.tmp_buf_len);
return rc;
}
@@ -261,13 +262,13 @@ static int copy_streams(u8 *data, unsigned long len,
/* Announces that a new buffer
* were filled
*/
- buffer_filled (dev, dma_q, vbuf);
- dprintk (dev, V4L2_DEBUG_ISOC,
+ buffer_filled(dev, dma_q, vbuf);
+ dprintk(dev, V4L2_DEBUG_ISOC,
"new buffer filled\n");
- get_next_buf (dma_q, &vbuf);
+ get_next_buf(dma_q, &vbuf);
if (!vbuf)
return rc;
- voutp = videobuf_to_vmalloc (&vbuf->vb);
+ voutp = videobuf_to_vmalloc(&vbuf->vb);
if (!voutp)
return rc;
memset(voutp, 0, vbuf->vb.size);
@@ -301,9 +302,17 @@ static int copy_streams(u8 *data, unsigned long len,
case TM6000_URB_MSG_VIDEO:
/* Fills video buffer */
if (vbuf)
- memcpy (&voutp[pos], ptr, cpysize);
+ memcpy(&voutp[pos], ptr, cpysize);
break;
case TM6000_URB_MSG_AUDIO:
+ /* Need some code to copy audio buffer */
+ if (dev->fourcc == V4L2_PIX_FMT_YUYV) {
+ /* Swap word bytes */
+ int i;
+
+ for (i = 0; i < cpysize; i += 2)
+ swab16s((u16 *)(ptr + i));
+ }
tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
break;
case TM6000_URB_MSG_VBI:
@@ -338,9 +347,9 @@ static int copy_multiplexed(u8 *ptr, unsigned long len,
struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
- unsigned int pos=dev->isoc_ctl.pos,cpysize;
- int rc=1;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ unsigned int pos = dev->isoc_ctl.pos, cpysize;
+ int rc = 1;
struct tm6000_buffer *buf;
char *outp = NULL;
@@ -351,19 +360,18 @@ static int copy_multiplexed(u8 *ptr, unsigned long len,
if (!outp)
return 0;
- while (len>0) {
- cpysize=min(len,buf->vb.size-pos);
- //printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
+ while (len > 0) {
+ cpysize = min(len, buf->vb.size-pos);
memcpy(&outp[pos], ptr, cpysize);
- pos+=cpysize;
- ptr+=cpysize;
- len-=cpysize;
+ pos += cpysize;
+ ptr += cpysize;
+ len -= cpysize;
if (pos >= buf->vb.size) {
- pos=0;
+ pos = 0;
/* Announces that a new buffer were filled */
- buffer_filled (dev, dma_q, buf);
+ buffer_filled(dev, dma_q, buf);
dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
- get_next_buf (dma_q, &buf);
+ get_next_buf(dma_q, &buf);
if (!buf)
break;
outp = videobuf_to_vmalloc(&(buf->vb));
@@ -373,16 +381,16 @@ static int copy_multiplexed(u8 *ptr, unsigned long len,
}
}
- dev->isoc_ctl.pos=pos;
+ dev->isoc_ctl.pos = pos;
return rc;
}
-static void inline print_err_status (struct tm6000_core *dev,
+static inline void print_err_status(struct tm6000_core *dev,
int packet, int status)
{
char *errmsg = "Unknown";
- switch(status) {
+ switch (status) {
case -ENOENT:
errmsg = "unlinked synchronuously";
break;
@@ -408,7 +416,7 @@ static void inline print_err_status (struct tm6000_core *dev,
errmsg = "Device does not respond";
break;
}
- if (packet<0) {
+ if (packet < 0) {
dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
status, errmsg);
} else {
@@ -424,20 +432,20 @@ static void inline print_err_status (struct tm6000_core *dev,
static inline int tm6000_isoc_copy(struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
- int i, len=0, rc=1, status;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ int i, len = 0, rc = 1, status;
char *p;
if (urb->status < 0) {
- print_err_status (dev, -1, urb->status);
+ print_err_status(dev, -1, urb->status);
return 0;
}
for (i = 0; i < urb->number_of_packets; i++) {
status = urb->iso_frame_desc[i].status;
- if (status<0) {
- print_err_status (dev,i,status);
+ if (status < 0) {
+ print_err_status(dev, i, status);
continue;
}
@@ -446,9 +454,9 @@ static inline int tm6000_isoc_copy(struct urb *urb)
if (len > 0) {
p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (!urb->iso_frame_desc[i].status) {
- if ((dev->fourcc)==V4L2_PIX_FMT_TM6000) {
- rc=copy_multiplexed(p, len, urb);
- if (rc<=0)
+ if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
+ rc = copy_multiplexed(p, len, urb);
+ if (rc <= 0)
return rc;
} else {
copy_streams(p, len, urb);
@@ -460,8 +468,9 @@ static inline int tm6000_isoc_copy(struct urb *urb)
}
/* ------------------------------------------------------------------
- URB control
- ------------------------------------------------------------------*/
+ * URB control
+ * ------------------------------------------------------------------
+ */
/*
* IRQ callback, called by URB callback
@@ -501,7 +510,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
dev->isoc_ctl.buf = NULL;
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb=dev->isoc_ctl.urb[i];
+ urb = dev->isoc_ctl.urb[i];
if (urb) {
usb_kill_urb(urb);
usb_unlink_urb(urb);
@@ -517,11 +526,11 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
dev->isoc_ctl.transfer_buffer[i] = NULL;
}
- kfree (dev->isoc_ctl.urb);
- kfree (dev->isoc_ctl.transfer_buffer);
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
- dev->isoc_ctl.urb=NULL;
- dev->isoc_ctl.transfer_buffer=NULL;
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
dev->isoc_ctl.num_bufs = 0;
}
@@ -552,7 +561,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
dev->isoc_ctl.max_pkt_size = size;
- max_packets = ( framesize + size - 1) / size;
+ max_packets = (framesize + size - 1) / size;
if (max_packets > TM6000_MAX_ISO_PACKETS)
max_packets = TM6000_MAX_ISO_PACKETS;
@@ -594,10 +603,10 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
sb_size, GFP_KERNEL, &urb->transfer_dma);
if (!dev->isoc_ctl.transfer_buffer[i]) {
- tm6000_err ("unable to allocate %i bytes for transfer"
+ tm6000_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n",
sb_size, i,
- in_interrupt()?" while in int":"");
+ in_interrupt() ? " while in int" : "");
tm6000_uninit_isoc(dev);
return -ENOMEM;
}
@@ -619,13 +628,13 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
return 0;
}
-static int tm6000_start_thread( struct tm6000_core *dev)
+static int tm6000_start_thread(struct tm6000_core *dev)
{
struct tm6000_dmaqueue *dma_q = &dev->vidq;
int i;
- dma_q->frame=0;
- dma_q->ini_jiffies=jiffies;
+ dma_q->frame = 0;
+ dma_q->ini_jiffies = jiffies;
init_waitqueue_head(&dma_q->wq);
@@ -644,8 +653,9 @@ static int tm6000_start_thread( struct tm6000_core *dev)
}
/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
+ * Videobuf operations
+ * ------------------------------------------------------------------
+ */
static int
buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
@@ -656,9 +666,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (0 == *count)
*count = TM6000_DEF_BUF;
- if (*count < TM6000_MIN_BUF) {
- *count=TM6000_MIN_BUF;
- }
+ if (*count < TM6000_MIN_BUF)
+ *count = TM6000_MIN_BUF;
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
@@ -698,7 +707,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
struct tm6000_core *dev = fh->dev;
int rc = 0, urb_init = 0;
@@ -753,7 +762,7 @@ fail:
static void
buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
- struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
struct tm6000_fh *fh = vq->priv_data;
struct tm6000_core *dev = fh->dev;
struct tm6000_dmaqueue *vidq = &dev->vidq;
@@ -764,9 +773,9 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
- struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
- free_buffer(vq,buf);
+ free_buffer(vq, buf);
}
static struct videobuf_queue_ops tm6000_video_qops = {
@@ -777,49 +786,66 @@ static struct videobuf_queue_ops tm6000_video_qops = {
};
/* ------------------------------------------------------------------
- IOCTL handling
- ------------------------------------------------------------------*/
+ * IOCTL handling
+ * ------------------------------------------------------------------
+ */
-static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
+static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
{
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
- mutex_unlock(&dev->lock);
- return 1;
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh && dev->is_res_read)
+ return true;
+
+ return false;
+}
+
+static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh)
+ return true;
+
+ return false;
}
-static int res_locked(struct tm6000_core *dev)
+static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
+ bool is_res_read)
{
- return (dev->resources);
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh && dev->is_res_read == is_res_read)
+ return true;
+
+ /* is it free? */
+ if (dev->resources)
+ return false;
+
+ /* grab it */
+ dev->resources = fh;
+ dev->is_res_read = is_res_read;
+ dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+ return true;
}
static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
{
- mutex_lock(&dev->lock);
- dev->resources = 0;
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources != fh)
+ return;
+
+ dev->resources = NULL;
dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
- mutex_unlock(&dev->lock);
}
/* ------------------------------------------------------------------
- IOCTL vidioc handling
- ------------------------------------------------------------------*/
-static int vidioc_querycap (struct file *file, void *priv,
+ * IOCTL vidioc handling
+ * ------------------------------------------------------------------
+ */
+static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- // struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
- strlcpy(cap->card,"Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
- // strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+ strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
cap->version = TM6000_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
@@ -828,21 +854,21 @@ static int vidioc_querycap (struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- strlcpy(f->description,format[f->index].name,sizeof(f->description));
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
}
-static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
f->fmt.pix.width = fh->width;
f->fmt.pix.height = fh->height;
@@ -853,10 +879,10 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
- return (0);
+ return 0;
}
-static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
+static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
@@ -866,7 +892,7 @@ static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
return NULL;
}
-static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
@@ -882,15 +908,14 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
field = f->fmt.pix.field;
- if (field == V4L2_FIELD_ANY) {
-// field=V4L2_FIELD_INTERLACED;
- field=V4L2_FIELD_SEQ_TB;
- } else if (V4L2_FIELD_INTERLACED != field) {
+ if (field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_SEQ_TB;
+ else if (V4L2_FIELD_INTERLACED != field) {
dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
return -EINVAL;
}
- tm6000_get_std_res (dev);
+ tm6000_get_std_res(dev);
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
@@ -908,14 +933,14 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
}
/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- int ret = vidioc_try_fmt_vid_cap(file,fh,f);
+ int ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
- return (ret);
+ return ret;
fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
fh->width = f->fmt.pix.width;
@@ -927,52 +952,52 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
tm6000_set_fourcc_format(dev);
- return (0);
+ return 0;
}
-static int vidioc_reqbufs (struct file *file, void *priv,
+static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
- return (videobuf_reqbufs(&fh->vb_vidq, p));
+ return videobuf_reqbufs(&fh->vb_vidq, p);
}
-static int vidioc_querybuf (struct file *file, void *priv,
+static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
- return (videobuf_querybuf(&fh->vb_vidq, p));
+ return videobuf_querybuf(&fh->vb_vidq, p);
}
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
- return (videobuf_qbuf(&fh->vb_vidq, p));
+ return videobuf_qbuf(&fh->vb_vidq, p);
}
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
- return (videobuf_dqbuf(&fh->vb_vidq, p,
- file->f_flags & O_NONBLOCK));
+ return videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK);
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
- return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
}
#endif
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -980,7 +1005,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
if (i != fh->type)
return -EINVAL;
- if (!res_get(dev,fh))
+ if (!res_get(dev, fh, false))
return -EBUSY;
return (videobuf_streamon(&fh->vb_vidq));
}
@@ -1007,7 +1032,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
struct tm6000_fh *fh=priv;
struct tm6000_core *dev = fh->dev;
- rc=tm6000_set_standard (dev, norm);
+ rc = tm6000_init_analog_mode(dev);
fh->width = dev->width;
fh->height = dev->height;
@@ -1020,21 +1045,21 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
return 0;
}
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
switch (inp->index) {
case TM6000_INPUT_TV:
inp->type = V4L2_INPUT_TYPE_TUNER;
- strcpy(inp->name,"Television");
+ strcpy(inp->name, "Television");
break;
case TM6000_INPUT_COMPOSITE:
inp->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(inp->name,"Composite");
+ strcpy(inp->name, "Composite");
break;
case TM6000_INPUT_SVIDEO:
inp->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(inp->name,"S-Video");
+ strcpy(inp->name, "S-Video");
break;
default:
return -EINVAL;
@@ -1044,48 +1069,48 @@ static int vidioc_enum_input (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- *i=dev->input;
+ *i = dev->input;
return 0;
}
-static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- int rc=0;
+ int rc = 0;
char buf[1];
switch (i) {
case TM6000_INPUT_TV:
- dev->input=i;
- *buf=0;
+ dev->input = i;
+ *buf = 0;
break;
case TM6000_INPUT_COMPOSITE:
case TM6000_INPUT_SVIDEO:
- dev->input=i;
- *buf=1;
+ dev->input = i;
+ *buf = 1;
break;
default:
return -EINVAL;
}
- rc=tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+ rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1);
if (!rc) {
- dev->input=i;
- rc=vidioc_s_std (file, priv, &dev->vfd->current_norm);
+ dev->input = i;
+ rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
}
- return (rc);
+ return rc;
}
/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
int i;
@@ -1094,16 +1119,16 @@ static int vidioc_queryctrl (struct file *file, void *priv,
if (qc->id && qc->id == tm6000_qctrl[i].id) {
memcpy(qc, &(tm6000_qctrl[i]),
sizeof(*qc));
- return (0);
+ return 0;
}
return -EINVAL;
}
-static int vidioc_g_ctrl (struct file *file, void *priv,
+static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct tm6000_fh *fh=priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
int val;
@@ -1125,41 +1150,41 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
return -EINVAL;
}
- if (val<0)
+ if (val < 0)
return val;
- ctrl->value=val;
+ ctrl->value = val;
return 0;
}
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct tm6000_fh *fh =priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- u8 val=ctrl->value;
+ u8 val = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_CONTRAST:
- tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+ tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
return 0;
case V4L2_CID_BRIGHTNESS:
- tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
+ tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
return 0;
case V4L2_CID_SATURATION:
- tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
+ tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
return 0;
case V4L2_CID_HUE:
- tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
+ tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
return 0;
}
return -EINVAL;
}
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct tm6000_fh *fh =priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
if (unlikely(UNSET == dev->tuner_type))
@@ -1176,10 +1201,10 @@ static int vidioc_g_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct tm6000_fh *fh =priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
if (UNSET == dev->tuner_type)
@@ -1190,10 +1215,10 @@ static int vidioc_s_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct tm6000_fh *fh =priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
if (unlikely(UNSET == dev->tuner_type))
@@ -1207,10 +1232,10 @@ static int vidioc_g_frequency (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct tm6000_fh *fh =priv;
+ struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
@@ -1221,10 +1246,8 @@ static int vidioc_s_frequency (struct file *file, void *priv,
if (unlikely(f->tuner != 0))
return -EINVAL;
-// mutex_lock(&dev->lock);
dev->freq = f->frequency;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-// mutex_unlock(&dev->lock);
return 0;
}
@@ -1239,7 +1262,7 @@ static int tm6000_open(struct file *file)
struct tm6000_core *dev = video_drvdata(file);
struct tm6000_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int i,rc;
+ int i, rc;
printk(KERN_INFO "tm6000: open called (dev=%s)\n",
video_device_node_name(vdev));
@@ -1256,7 +1279,7 @@ static int tm6000_open(struct file *file)
dev->users);
/* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh) {
dev->users--;
return -ENOMEM;
@@ -1284,23 +1307,23 @@ static int tm6000_open(struct file *file)
"active=%d\n",list_empty(&dev->vidq.active));
/* initialize hardware on analog mode */
- if (dev->mode!=TM6000_MODE_ANALOG) {
- rc=tm6000_init_analog_mode (dev);
- if (rc<0)
- return rc;
+ rc = tm6000_init_analog_mode(dev);
+ if (rc < 0)
+ return rc;
+ if (dev->mode != TM6000_MODE_ANALOG) {
/* Put all controls at a sane state */
for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
- qctl_regs[i] =tm6000_qctrl[i].default_value;
+ qctl_regs[i] = tm6000_qctrl[i].default_value;
- dev->mode=TM6000_MODE_ANALOG;
+ dev->mode = TM6000_MODE_ANALOG;
}
videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
NULL, &dev->slock,
fh->type,
V4L2_FIELD_INTERLACED,
- sizeof(struct tm6000_buffer),fh);
+ sizeof(struct tm6000_buffer), fh, &dev->lock);
return 0;
}
@@ -1311,7 +1334,7 @@ tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
struct tm6000_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(fh->dev))
+ if (!res_get(fh->dev, fh, true))
return -EBUSY;
return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
@@ -1329,7 +1352,10 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
- if (res_get(fh->dev,fh)) {
+ if (!!is_res_streaming(fh->dev, fh))
+ return POLLERR;
+
+ if (!is_res_read(fh->dev, fh)) {
/* streaming capture */
if (list_empty(&fh->vb_vidq.stream))
return POLLERR;
@@ -1342,7 +1368,7 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN|POLLRDNORM;
+ return POLLIN | POLLRDNORM;
return 0;
}
@@ -1357,12 +1383,13 @@ static int tm6000_release(struct file *file)
dev->users--;
+ res_free(dev, fh);
if (!dev->users) {
tm6000_uninit_isoc(dev);
videobuf_mmap_free(&fh->vb_vidq);
}
- kfree (fh);
+ kfree(fh);
return 0;
}
@@ -1372,7 +1399,7 @@ static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
struct tm6000_fh *fh = file->private_data;
int ret;
- ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
return ret;
}
@@ -1381,7 +1408,7 @@ static struct v4l2_file_operations tm6000_fops = {
.owner = THIS_MODULE,
.open = tm6000_open,
.release = tm6000_release,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.read = tm6000_read,
.poll = tm6000_poll,
.mmap = tm6000_mmap,
@@ -1425,8 +1452,9 @@ static struct video_device tm6000_template = {
};
/* -----------------------------------------------------------------
- Initialization and module stuff
- ------------------------------------------------------------------*/
+ * Initialization and module stuff
+ * ------------------------------------------------------------------
+ */
int tm6000_v4l2_register(struct tm6000_core *dev)
{
@@ -1443,8 +1471,10 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
- memcpy (dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
- dev->vfd->debug=tm6000_debug;
+ memcpy(dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
+ dev->vfd->debug = tm6000_debug;
+ dev->vfd->lock = &dev->lock;
+
vfd->v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(vfd, dev);
@@ -1466,11 +1496,11 @@ int tm6000_v4l2_exit(void)
}
module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,"Allow changing video device number");
+MODULE_PARM_DESC(video_nr, "Allow changing video device number");
-module_param_named (debug, tm6000_debug, int, 0444);
-MODULE_PARM_DESC(debug,"activates debug info");
+module_param_named(debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 1ec1bff9b294..46017b603190 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -1,23 +1,23 @@
/*
- tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
-
- Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- - DVB-T support
-
- 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 version 2
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ * - DVB-T support
+ *
+ * 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 version 2
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Use the tm6000-hack, instead of the proper initialization code i*/
@@ -54,8 +54,9 @@ enum tm6000_devtype {
};
/* ------------------------------------------------------------------
- Basic structures
- ------------------------------------------------------------------*/
+ * Basic structures
+ * ------------------------------------------------------------------
+ */
struct tm6000_fmt {
char *name;
@@ -189,7 +190,9 @@ struct tm6000_core {
int users;
/* various device info */
- unsigned int resources;
+ struct tm6000_fh *resources; /* Points to fh that is streaming */
+ bool is_res_read;
+
struct video_device *vfd;
struct tm6000_dmaqueue vidq;
struct v4l2_device v4l2_dev;
@@ -205,6 +208,9 @@ struct tm6000_core {
/* audio support */
struct snd_tm6000_card *adev;
+ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
+ atomic_t stream_started; /* stream should be running if true */
+
struct tm6000_IR *ir;
@@ -251,9 +257,9 @@ struct tm6000_fh {
enum v4l2_buf_type type;
};
-#define TM6000_STD V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \
+#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \
V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
- V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
+ V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
/* In tm6000-cards.c */