summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cpia.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/video/cpia.c
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/media/video/cpia.c')
-rw-r--r--drivers/media/video/cpia.c4073
1 files changed, 4073 insertions, 0 deletions
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
new file mode 100644
index 000000000000..8c08b7f1ad23
--- /dev/null
+++ b/drivers/media/video/cpia.c
@@ -0,0 +1,4073 @@
+/*
+ * 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/config.h>
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.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 <asm/semaphore.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "cpia.h"
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+extern int cpia_pp_init(void);
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB
+extern int cpia_usb_init(void);
+#endif
+
+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@erdfeld.com>");
+MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
+#endif
+
+static unsigned short colorspace_conv = 0;
+module_param(colorspace_conv, ushort, 0444);
+MODULE_PARM_DESC(colorspace_conv,
+ "\n<n> Colorspace conversion:"
+ "\n0 = disable"
+ "\n1 = enable"
+ "\nDefault value is 0"
+ "\n");
+
+#define ABOUT "V4L-Driver for Vision CPiA based cameras"
+
+#ifndef VID_HARDWARE_CPIA
+#define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
+#endif
+
+#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_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *out = page;
+ int len, tmp;
+ struct cam_data *cam = data;
+ char tmpstr[29];
+
+ /* IMPORTANT: This output MUST be kept under PAGE_SIZE
+ * or we need to get more sophisticated. */
+
+ out += sprintf(out, "read-only\n-----------------------\n");
+ out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+ out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
+ cam->params.version.firmwareVersion,
+ cam->params.version.firmwareRevision,
+ cam->params.version.vcVersion,
+ cam->params.version.vcRevision);
+ out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
+ cam->params.pnpID.vendor, cam->params.pnpID.product,
+ cam->params.pnpID.deviceRevision);
+ out += sprintf(out, "VP-Version: %d.%d %04x\n",
+ cam->params.vpVersion.vpVersion,
+ cam->params.vpVersion.vpRevision,
+ cam->params.vpVersion.cameraHeadID);
+
+ out += sprintf(out, "system_state: %#04x\n",
+ cam->params.status.systemState);
+ out += sprintf(out, "grab_state: %#04x\n",
+ cam->params.status.grabState);
+ out += sprintf(out, "stream_state: %#04x\n",
+ cam->params.status.streamState);
+ out += sprintf(out, "fatal_error: %#04x\n",
+ cam->params.status.fatalError);
+ out += sprintf(out, "cmd_error: %#04x\n",
+ cam->params.status.cmdError);
+ out += sprintf(out, "debug_flags: %#04x\n",
+ cam->params.status.debugFlags);
+ out += sprintf(out, "vp_status: %#04x\n",
+ cam->params.status.vpStatus);
+ out += sprintf(out, "error_code: %#04x\n",
+ cam->params.status.errorCode);
+ /* QX3 specific entries */
+ if (cam->params.qx3.qx3_detected) {
+ out += sprintf(out, "button: %4d\n",
+ cam->params.qx3.button);
+ out += sprintf(out, "cradled: %4d\n",
+ cam->params.qx3.cradled);
+ }
+ out += sprintf(out, "video_size: %s\n",
+ cam->params.format.videoSize == VIDEOSIZE_CIF ?
+ "CIF " : "QCIF");
+ out += sprintf(out, "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);
+ out += sprintf(out, "actual_fps: %3d\n", cam->fps);
+ out += sprintf(out, "transfer_rate: %4dkB/s\n",
+ cam->transfer_rate);
+
+ out += sprintf(out, "\nread-write\n");
+ out += sprintf(out, "----------------------- current min"
+ " max default comment\n");
+ out += sprintf(out, "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;
+
+ out += sprintf(out, "contrast: %8d %8d %8d %8d"
+ " steps of 8\n",
+ cam->params.colourParams.contrast, 0, tmp, 48);
+ out += sprintf(out, "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);
+ out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
+ tmp/1000, tmp%1000, 3, 30, 15);
+ out += sprintf(out, "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);
+ out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
+ cam->params.format.subSample == SUBSAMPLE_420 ?
+ "420" : "422", "420", "422", "422");
+ out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
+ cam->params.format.yuvOrder == YUVORDER_YUYV ?
+ "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
+ out += sprintf(out, "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");
+ }
+ out += sprintf(out, "color_balance_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.redGain, 0, 212, 32);
+ out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.greenGain, 0, 212, 6);
+ out += sprintf(out, "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)
+ out += sprintf(out, "max_gain: unknown %28s"
+ " powers of 2\n", tmpstr);
+ else
+ out += sprintf(out, "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;
+ }
+ out += sprintf(out, "exposure_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
+ (2-cam->params.exposure.centreWeight) ? "on" : "off",
+ "off", "on", "on");
+ out += sprintf(out, "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;
+
+ out += sprintf(out, "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;
+
+ out += sprintf(out, "coarse_exp: %8d %8d %8d"
+ " %8d\n", cam->params.exposure.coarseExpLo+
+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
+ out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
+ out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green1Comp, COMP_GREEN1, 255,
+ COMP_GREEN1);
+ out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green2Comp, COMP_GREEN2, 255,
+ COMP_GREEN2);
+ out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
+
+ out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain1, 0, 0xff, 0x1c);
+ out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain2, 0, 0xff, 0x1a);
+ out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain4, 0, 0xff, 0x2d);
+ out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain8, 0, 0xff, 0x2a);
+ out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain1, 0, 255, 24);
+ out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain2, 0, 255, 28);
+ out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain4, 0, 255, 30);
+ out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain8, 0, 255, 30);
+ out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
+ cam->params.flickerControl.flickerMode ? "on" : "off",
+ "off", "on", "off");
+ out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
+ " only 50/60\n",
+ cam->mainsFreq ? 60 : 50, 50, 60, 50);
+ if(cam->params.flickerControl.allowableOverExposure < 0)
+ out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
+ -cam->params.flickerControl.allowableOverExposure,
+ 255);
+ else
+ out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
+ cam->params.flickerControl.allowableOverExposure,
+ 255);
+ out += sprintf(out, "compression_mode: ");
+ switch(cam->params.compression.mode) {
+ case CPIA_COMPRESSION_NONE:
+ out += sprintf(out, "%8s", "none");
+ break;
+ case CPIA_COMPRESSION_AUTO:
+ out += sprintf(out, "%8s", "auto");
+ break;
+ case CPIA_COMPRESSION_MANUAL:
+ out += sprintf(out, "%8s", "manual");
+ break;
+ default:
+ out += sprintf(out, "%8s", "unknown");
+ break;
+ }
+ out += sprintf(out, " none,auto,manual auto\n");
+ out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
+ cam->params.compression.decimation ==
+ DECIMATION_ENAB ? "on":"off", "off", "on",
+ "off");
+ out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
+ cam->params.compressionTarget.frTargeting ==
+ CPIA_COMPRESSION_TARGET_FRAMERATE ?
+ "framerate":"quality",
+ "framerate", "quality", "quality");
+ out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetFR, 1, 30, 15);
+ out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetQ, 1, 64, 5);
+ out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.yThreshold, 0, 31, 6);
+ out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
+ out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.hysteresis, 0, 255, 3);
+ out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.threshMax, 0, 255, 11);
+ out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.smallStep, 0, 255, 1);
+ out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.largeStep, 0, 255, 3);
+ out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationHysteresis,
+ 0, 255, 2);
+ out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.frDiffStepThresh,
+ 0, 255, 5);
+ out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.qDiffStepThresh,
+ 0, 255, 3);
+ out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationThreshMod,
+ 0, 255, 2);
+ /* QX3 specific entries */
+ if (cam->params.qx3.qx3_detected) {
+ out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
+ cam->params.qx3.toplight ? "on" : "off",
+ "off", "on", "off");
+ out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
+ cam->params.qx3.bottomlight ? "on" : "off",
+ "off", "on", "off");
+ }
+
+ len = out - page;
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0) return 0;
+ } else
+ len = count;
+
+ *start = page + off;
+ return len;
+}
+
+
+static int match(char *checkstr, char **buffer, unsigned long *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, unsigned long *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 int cpia_write_proc(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ struct cam_data *cam = 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 %lu > %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 (down_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;