2005-04-17 02:20:36 +04:00
/*
* 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 0213 9 , USA .
*/
/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
2006-03-25 15:19:53 +03:00
/* #define _CPIA_DEBUG_ 1 */
2005-04-17 02:20:36 +04:00
# include <linux/module.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>
2006-02-07 11:49:14 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include "cpia.h"
static int video_nr = - 1 ;
# ifdef MODULE
module_param ( video_nr , int , 0 ) ;
2006-03-21 20:53:22 +03:00
MODULE_AUTHOR ( " Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " V4L-driver for Vision CPiA based cameras " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_SUPPORTED_DEVICE ( " video " ) ;
# endif
2006-03-27 23:18:25 +04:00
static unsigned short colorspace_conv ;
2005-04-17 02:20:36 +04:00
module_param ( colorspace_conv , ushort , 0444 ) ;
MODULE_PARM_DESC ( colorspace_conv ,
2006-04-08 23:06:16 +04:00
" Colorspace conversion: "
" \n 0 = disable, 1 = enable "
" \n Default value is 0 "
) ;
2005-04-17 02:20:36 +04:00
# 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
2006-03-25 15:19:53 +03:00
# define HIGH_COMP_102 160
# define MAX_COMP 239
2005-04-17 02:20:36 +04:00
# 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 ,
2006-03-25 15:19:53 +03:00
int on ) ;
2005-04-17 02:20:36 +04:00
/**********************************************************************
*
* 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 ,
2006-03-25 15:19:53 +03:00
int count , int * eof , void * data )
2005-04-17 02:20:36 +04:00
{
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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . version . firmwareVersion ,
cam - > params . version . firmwareRevision ,
cam - > params . version . vcVersion ,
cam - > params . version . vcRevision ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " CPIA PnP-ID: %04x:%04x:%04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . pnpID . vendor , cam - > params . pnpID . product ,
cam - > params . pnpID . deviceRevision ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " VP-Version: %d.%d %04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . vpVersion . vpVersion ,
cam - > params . vpVersion . vpRevision ,
cam - > params . vpVersion . cameraHeadID ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " system_state: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . systemState ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " grab_state: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . grabState ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " stream_state: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . streamState ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " fatal_error: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . fatalError ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " cmd_error: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . cmdError ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " debug_flags: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . debugFlags ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " vp_status: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . vpStatus ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " error_code: %#04x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . status . errorCode ) ;
2005-04-17 02:20:36 +04:00
/* QX3 specific entries */
if ( cam - > params . qx3 . qx3_detected ) {
out + = sprintf ( out , " button: %4d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . qx3 . button ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " cradled: %4d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . qx3 . cradled ) ;
2005-04-17 02:20:36 +04:00
}
out + = sprintf ( out , " video_size: %s \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . format . videoSize = = VIDEOSIZE_CIF ?
2005-04-17 02:20:36 +04:00
" CIF " : " QCIF " ) ;
out + = sprintf ( out , " roi: (%3d, %3d) to (%3d, %3d) \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . roi . colStart * 8 ,
cam - > params . roi . rowStart * 4 ,
cam - > params . roi . colEnd * 8 ,
cam - > params . roi . rowEnd * 4 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " actual_fps: %3d \n " , cam - > fps ) ;
out + = sprintf ( out , " transfer_rate: %4dkB/s \n " ,
2006-03-25 15:19:53 +03:00
cam - > transfer_rate ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " \n read-write \n " ) ;
out + = sprintf ( out , " ----------------------- current min "
2006-03-25 15:19:53 +03:00
" max default comment \n " ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " brightness: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . colourParams . brightness , 0 , 100 , 50 ) ;
2005-04-17 02:20:36 +04:00
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 "
2006-03-25 15:19:53 +03:00
" steps of 8 \n " ,
cam - > params . colourParams . contrast , 0 , tmp , 48 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " saturation: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . colourParams . saturation , 0 , 100 , 50 ) ;
2005-04-17 02:20:36 +04:00
tmp = ( 25000 + 5000 * cam - > params . sensorFps . baserate ) /
( 1 < < cam - > params . sensorFps . divisor ) ;
out + = sprintf ( out , " sensor_fps: %4d.%03d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
tmp / 1000 , tmp % 1000 , 3 , 30 , 15 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " stream_start_line: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
2 * cam - > params . streamStartLine , 0 ,
2005-04-17 02:20:36 +04:00
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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . format . subSample = = SUBSAMPLE_420 ?
2005-04-17 02:20:36 +04:00
" 420 " : " 422 " , " 420 " , " 422 " , " 422 " ) ;
out + = sprintf ( out , " yuv_order: %8s %8s %8s %8s \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . format . yuvOrder = = YUVORDER_YUYV ?
2005-04-17 02:20:36 +04:00
" YUYV " : " UYVY " , " YUYV " , " UYVY " , " YUYV " ) ;
out + = sprintf ( out , " ecp_timing: %8s %8s %8s %8s \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . ecpTiming ? " slow " : " normal " , " slow " ,
2005-04-17 02:20:36 +04:00
" 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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . colourBalance . redGain , 0 , 212 , 32 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " green_gain: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . colourBalance . greenGain , 0 , 212 , 6 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " blue_gain: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . colourBalance . blueGain , 0 , 212 , 92 ) ;
2005-04-17 02:20:36 +04:00
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 "
2006-03-25 15:19:53 +03:00
" powers of 2 \n " , tmpstr ) ;
2005-04-17 02:20:36 +04:00
else
out + = sprintf ( out , " max_gain: %8d %28s "
" 1,2,4 or 8 \n " ,
2006-03-25 15:19:53 +03:00
1 < < ( cam - > params . exposure . gainMode - 1 ) , tmpstr ) ;
2005-04-17 02:20:36 +04:00
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 " ,
2006-03-25 15:19:53 +03:00
( 2 - cam - > params . exposure . centreWeight ) ? " on " : " off " ,
" off " , " on " , " on " ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " gain: %8d %8d max_gain %8d 1,2,4,8 possible \n " ,
2006-03-25 15:19:53 +03:00
1 < < cam - > params . exposure . gain , 1 , 1 ) ;
2005-04-17 02:20:36 +04:00
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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . exposure . fineExp * 2 , 0 , tmp , 0 ) ;
2005-04-17 02:20:36 +04:00
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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . exposure . redComp , COMP_RED , 255 , COMP_RED ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " green1_comp: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . exposure . green1Comp , COMP_GREEN1 , 255 ,
2005-04-17 02:20:36 +04:00
COMP_GREEN1 ) ;
out + = sprintf ( out , " green2_comp: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . exposure . green2Comp , COMP_GREEN2 , 255 ,
2005-04-17 02:20:36 +04:00
COMP_GREEN2 ) ;
out + = sprintf ( out , " blue_comp: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . exposure . blueComp , COMP_BLUE , 255 , COMP_BLUE ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " apcor_gain1: %#8x %#8x %#8x %#8x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . apcor . gain1 , 0 , 0xff , 0x1c ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " apcor_gain2: %#8x %#8x %#8x %#8x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . apcor . gain2 , 0 , 0xff , 0x1a ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " apcor_gain4: %#8x %#8x %#8x %#8x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . apcor . gain4 , 0 , 0xff , 0x2d ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " apcor_gain8: %#8x %#8x %#8x %#8x \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . apcor . gain8 , 0 , 0xff , 0x2a ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " vl_offset_gain1: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . vlOffset . gain1 , 0 , 255 , 24 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " vl_offset_gain2: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . vlOffset . gain2 , 0 , 255 , 28 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " vl_offset_gain4: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . vlOffset . gain4 , 0 , 255 , 30 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " vl_offset_gain8: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . vlOffset . gain8 , 0 , 255 , 30 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " flicker_control: %8s %8s %8s %8s \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . flickerMode ? " on " : " off " ,
2005-04-17 02:20:36 +04:00
" off " , " on " , " off " ) ;
out + = sprintf ( out , " mains_frequency: %8d %8d %8d %8d "
2006-03-25 15:19:53 +03:00
" only 50/60 \n " ,
cam - > mainsFreq ? 60 : 50 , 50 , 60 , 50 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > params . flickerControl . allowableOverExposure < 0 )
out + = sprintf ( out , " allowable_overexposure: %4dauto auto %8d auto \n " ,
2006-03-25 15:19:53 +03:00
- cam - > params . flickerControl . allowableOverExposure ,
255 ) ;
2005-04-17 02:20:36 +04:00
else
out + = sprintf ( out , " allowable_overexposure: %8d auto %8d auto \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . allowableOverExposure ,
255 ) ;
2005-04-17 02:20:36 +04:00
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 " ,
2006-03-25 15:19:53 +03:00
cam - > params . compression . decimation = =
DECIMATION_ENAB ? " on " : " off " , " off " , " on " ,
2005-04-17 02:20:36 +04:00
" off " ) ;
out + = sprintf ( out , " compression_target: %9s %9s %9s %9s \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionTarget . frTargeting = =
2005-04-17 02:20:36 +04:00
CPIA_COMPRESSION_TARGET_FRAMERATE ?
" framerate " : " quality " ,
" framerate " , " quality " , " quality " ) ;
out + = sprintf ( out , " target_framerate: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionTarget . targetFR , 1 , 30 , 15 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " target_quality: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionTarget . targetQ , 1 , 64 , 5 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " y_threshold: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . yuvThreshold . yThreshold , 0 , 31 , 6 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " uv_threshold: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . yuvThreshold . uvThreshold , 0 , 31 , 6 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " hysteresis: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . hysteresis , 0 , 255 , 3 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " threshold_max: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . threshMax , 0 , 255 , 11 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " small_step: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . smallStep , 0 , 255 , 1 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " large_step: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . largeStep , 0 , 255 , 3 ) ;
2005-04-17 02:20:36 +04:00
out + = sprintf ( out , " decimation_hysteresis: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . decimationHysteresis ,
2005-04-17 02:20:36 +04:00
0 , 255 , 2 ) ;
out + = sprintf ( out , " fr_diff_step_thresh: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . frDiffStepThresh ,
2005-04-17 02:20:36 +04:00
0 , 255 , 5 ) ;
out + = sprintf ( out , " q_diff_step_thresh: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . qDiffStepThresh ,
2005-04-17 02:20:36 +04:00
0 , 255 , 3 ) ;
out + = sprintf ( out , " decimation_thresh_mod: %8d %8d %8d %8d \n " ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionParams . decimationThreshMod ,
2005-04-17 02:20:36 +04:00
0 , 255 , 2 ) ;
/* QX3 specific entries */
if ( cam - > params . qx3 . qx3_detected ) {
2006-03-25 15:19:53 +03:00
out + = sprintf ( out , " toplight: %8s %8s %8s %8s \n " ,
cam - > params . qx3 . toplight ? " on " : " off " ,
2005-04-17 02:20:36 +04:00
" off " , " on " , " off " ) ;
2006-03-25 15:19:53 +03:00
out + = sprintf ( out , " bottomlight: %8s %8s %8s %8s \n " ,
cam - > params . qx3 . bottomlight ? " on " : " off " ,
2005-04-17 02:20:36 +04:00
" off " , " on " , " off " ) ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
int * find_colon , int * err )
2005-04-17 02:20:36 +04:00
{
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 ,
2006-03-25 15:19:53 +03:00
unsigned long count , void * data )
2005-04-17 02:20:36 +04:00
{
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
buffer = page ;
2006-03-25 15:19:53 +03:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & cam - > param_lock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/*
* Skip over leading whitespace
*/
while ( count & & isspace ( * buffer ) ) {
- - count ;
+ + buffer ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
memcpy ( & new_params , & cam - > params , sizeof ( struct cam_params ) ) ;
new_mains = cam - > mainsFreq ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
# 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) && \
2006-03-25 15:19:53 +03:00
new_params . version . firmwareRevision = = ( y ) )
2005-04-17 02:20:36 +04:00
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 )
2006-03-25 15:19:53 +03:00
new_params . flickerControl . allowableOverExposure =
2005-04-17 02:20:36 +04:00
- 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 ;
}
2006-03-25 15:19:53 +03:00
new_params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
new_params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
new_params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
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 " ) ) {
2006-03-25 15:19:53 +03:00
new_params . flickerControl . allowableOverExposure =
2005-04-17 02:20:36 +04:00
- 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 " ) )
2006-03-25 15:19:53 +03:00
new_params . compressionTarget . frTargeting =
2005-04-17 02:20:36 +04:00
CPIA_COMPRESSION_TARGET_QUALITY ;
else if ( ! retval & & MATCH ( " framerate " ) )
2006-03-25 15:19:53 +03:00
new_params . compressionTarget . frTargeting =
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
else
2005-04-17 02:20:36 +04:00
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 " ) ) {
2006-03-25 15:19:53 +03:00
if ( ! retval & & MATCH ( " on " ) )
2005-04-17 02:20:36 +04:00
new_params . qx3 . toplight = 1 ;
else if ( ! retval & & MATCH ( " off " ) )
new_params . qx3 . toplight = 0 ;
2006-03-25 15:19:53 +03:00
else
2005-04-17 02:20:36 +04:00
retval = - EINVAL ;
command_flags | = COMMAND_SETLIGHTS ;
} else if ( MATCH ( " bottomlight " ) ) {
2006-03-25 15:19:53 +03:00
if ( ! retval & & MATCH ( " on " ) )
2005-04-17 02:20:36 +04:00
new_params . qx3 . bottomlight = 1 ;
2006-03-25 15:19:53 +03:00
else if ( ! retval & & MATCH ( " off " ) )
2005-04-17 02:20:36 +04:00
new_params . qx3 . bottomlight = 0 ;
2006-03-25 15:19:53 +03:00
else
2005-04-17 02:20:36 +04:00
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 ;
}
}
}
}
2006-03-25 15:19:53 +03:00
# undef MATCH
2005-04-17 02:20:36 +04:00
# 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 ) ;
2006-03-25 15:19:53 +03:00
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
out :
free_page ( ( unsigned long ) page ) ;
2006-03-25 15:19:53 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
static void create_proc_cpia_cam ( struct cam_data * cam )
{
2007-01-14 21:29:42 +03:00
char name [ 5 + 1 + 10 + 1 ] ;
2005-04-17 02:20:36 +04:00
struct proc_dir_entry * ent ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ! cpia_proc_root | | ! cam )
return ;
2008-10-20 01:54:26 +04:00
snprintf ( name , sizeof ( name ) , " video%d " , cam - > vdev . num ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
ent = create_proc_entry ( name , S_IFREG | S_IRUGO | S_IWUSR , cpia_proc_root ) ;
if ( ! ent )
return ;
ent - > data = cam ;
ent - > read_proc = cpia_read_proc ;
ent - > write_proc = cpia_write_proc ;
2006-03-25 15:19:53 +03:00
/*
2005-04-17 02:20:36 +04:00
size of the proc entry is 3736 bytes for the standard webcam ;
2006-03-25 15:19:53 +03:00
the extra features of the QX3 microscope add 189 bytes .
2005-04-17 02:20:36 +04:00
( 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 )
{
2007-01-14 21:29:42 +03:00
char name [ 5 + 1 + 10 + 1 ] ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ! cam | | ! cam - > proc_entry )
return ;
2006-03-25 15:19:53 +03:00
2008-10-20 01:54:26 +04:00
snprintf ( name , sizeof ( name ) , " video%d " , cam - > vdev . num ) ;
2005-04-17 02:20:36 +04:00
remove_proc_entry ( name , cpia_proc_root ) ;
cam - > proc_entry = NULL ;
}
static void proc_cpia_create ( void )
{
2005-09-29 01:32:57 +04:00
cpia_proc_root = proc_mkdir ( " cpia " , NULL ) ;
2005-04-17 02:20:36 +04:00
2009-03-25 22:48:06 +03:00
if ( ! cpia_proc_root )
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > params . roi . colStart + = cam - > vc . x > > 3 ;
cam - > params . roi . colEnd = cam - > params . roi . colStart +
2006-03-25 15:19:53 +03:00
( cam - > vc . width > > 3 ) ;
2005-04-17 02:20:36 +04:00
cam - > params . roi . rowStart + = cam - > vc . y > > 2 ;
cam - > params . roi . rowEnd = cam - > params . roi . rowStart +
2006-03-25 15:19:53 +03:00
( cam - > vc . height > > 2 ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 :
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
datasize = 8 ;
break ;
2006-03-25 15:19:53 +03:00
case CPIA_COMMAND_ReadMCPorts :
2005-04-17 02:20:36 +04:00
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 )
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
} 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 ] ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
break ;
case CPIA_COMMAND_GetColourBalance :
cam - > params . colourBalance . redGain = data [ 0 ] ;
cam - > params . colourBalance . greenGain = data [ 1 ] ;
cam - > params . colourBalance . blueGain = data [ 2 ] ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
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 ] ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
break ;
2006-03-25 15:19:53 +03:00
case CPIA_COMMAND_ReadMCPorts :
if ( ! cam - > params . qx3 . qx3_detected )
2005-04-17 02:20:36 +04:00
break ;
2006-03-25 15:19:53 +03:00
/* test button press */
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
u8 a , u8 b , u8 c , u8 d ,
u8 e , u8 f , u8 g , u8 h ,
u8 i , u8 j , u8 k , u8 l )
2005-04-17 02:20:36 +04:00
{
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 ,
2006-03-25 15:19:53 +03:00
int linesize , int mmap_kludge )
2005-04-17 02:20:36 +04:00
{
int y , u , v , r , g , b , y1 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ,
2006-03-25 15:19:53 +03:00
int in_uyvy , int mmap_kludge )
2005-04-17 02:20:36 +04:00
{
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 */
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
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 " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
if ( ( ibuf [ 16 ] ! = VIDEOSIZE_QCIF ) & & ( ibuf [ 16 ] ! = VIDEOSIZE_CIF ) ) {
LOG ( " wrong video size \n " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ibuf [ 17 ] ! = SUBSAMPLE_420 & & ibuf [ 17 ] ! = SUBSAMPLE_422 ) {
LOG ( " illegal subtype %d \n " , ibuf [ 17 ] ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
subsample_422 = ibuf [ 17 ] = = SUBSAMPLE_422 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ibuf [ 18 ] ! = YUVORDER_YUYV & & ibuf [ 18 ] ! = YUVORDER_UYVY ) {
LOG ( " illegal yuvorder %d \n " , ibuf [ 18 ] ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
in_uyvy = ibuf [ 18 ] = = YUVORDER_UYVY ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
cols = 8 * ( ibuf [ 25 ] - ibuf [ 24 ] ) ;
rows = 4 * ( ibuf [ 27 ] - ibuf [ 26 ] ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ( ibuf [ 28 ] ! = NOT_COMPRESSED ) & & ( ibuf [ 28 ] ! = COMPRESSED ) ) {
LOG ( " illegal compression %d \n " , ibuf [ 28 ] ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
compressed = ( ibuf [ 28 ] = = COMPRESSED ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ibuf [ 29 ] ! = NO_DECIMATION & & ibuf [ 29 ] ! = DECIMATION_ENAB ) {
LOG ( " illegal decimation %d \n " , ibuf [ 29 ] ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2006-03-25 15:19:53 +03:00
decimation = ( ibuf [ 29 ] = = DECIMATION_ENAB ) ;
2005-04-17 02:20:36 +04:00
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 ] ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
in_uyvy , cam - > mmap_kludge ) ;
2005-04-17 02:20:36 +04:00
ibuf + = 4 ;
ll - = 4 ;
} else {
/* SUBSAMPLE_420 on an odd line */
obuf + = convert420 ( ibuf , obuf ,
2006-03-25 15:19:53 +03:00
out_fmt , linesize ,
cam - > mmap_kludge ) ;
2005-04-17 02:20:36 +04:00
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 ) ) {
2006-03-25 15:19:53 +03:00
size - = 4 ;
2005-04-17 02:20:36 +04:00
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 ;
}
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
0 , cam - > params . streamStartLine , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
/* 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 -
2006-03-25 15:19:53 +03:00
FLICKER_BRIGHTNESS_CONSTANT ;
2005-04-17 02:20:36 +04:00
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 )
{
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue = = COMMAND_NONE ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return ;
}
DEB_BYTE ( cam - > cmd_queue ) ;
DEB_BYTE ( cam - > cmd_queue > > 8 ) ;
if ( cam - > cmd_queue & COMMAND_SETFORMAT ) {
do_command ( cam , CPIA_COMMAND_SetFormat ,
2006-03-25 15:19:53 +03:00
cam - > params . format . videoSize ,
cam - > params . format . subSample ,
cam - > params . format . yuvOrder , 0 ) ;
2005-04-17 02:20:36 +04:00
do_command ( cam , CPIA_COMMAND_SetROI ,
2006-03-25 15:19:53 +03:00
cam - > params . roi . colStart , cam - > params . roi . colEnd ,
cam - > params . roi . rowStart , cam - > params . roi . rowEnd ) ;
2005-04-17 02:20:36 +04:00
cam - > first_frame = 1 ;
}
if ( cam - > cmd_queue & COMMAND_SETCOLOURPARAMS )
do_command ( cam , CPIA_COMMAND_SetColourParams ,
2006-03-25 15:19:53 +03:00
cam - > params . colourParams . brightness ,
cam - > params . colourParams . contrast ,
cam - > params . colourParams . saturation , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETAPCOR )
do_command ( cam , CPIA_COMMAND_SetApcor ,
2006-03-25 15:19:53 +03:00
cam - > params . apcor . gain1 ,
cam - > params . apcor . gain2 ,
cam - > params . apcor . gain4 ,
cam - > params . apcor . gain8 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETVLOFFSET )
do_command ( cam , CPIA_COMMAND_SetVLOffset ,
2006-03-25 15:19:53 +03:00
cam - > params . vlOffset . gain1 ,
cam - > params . vlOffset . gain2 ,
cam - > params . vlOffset . gain4 ,
cam - > params . vlOffset . gain8 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETEXPOSURE ) {
do_command_extended ( cam , CPIA_COMMAND_SetExposure ,
2006-03-25 15:19:53 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > params . exposure . expMode ! = 1 ) {
do_command_extended ( cam , CPIA_COMMAND_SetExposure ,
2006-03-25 15:19:53 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
cam - > params . compressionTarget . frTargeting ,
cam - > params . compressionTarget . targetFR ,
cam - > params . compressionTarget . targetQ , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETYUVTHRESH )
do_command ( cam , CPIA_COMMAND_SetYUVThresh ,
2006-03-25 15:19:53 +03:00
cam - > params . yuvThreshold . yThreshold ,
cam - > params . yuvThreshold . uvThreshold , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETCOMPRESSIONPARAMS )
do_command_extended ( cam , CPIA_COMMAND_SetCompressionParams ,
2006-03-25 15:19:53 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETCOMPRESSION )
do_command ( cam , CPIA_COMMAND_SetCompression ,
2006-03-25 15:19:53 +03:00
cam - > params . compression . mode ,
2005-04-17 02:20:36 +04:00
cam - > params . compression . decimation , 0 , 0 ) ;
if ( cam - > cmd_queue & COMMAND_SETSENSORFPS )
do_command ( cam , CPIA_COMMAND_SetSensorFPS ,
2006-03-25 15:19:53 +03:00
cam - > params . sensorFps . divisor ,
cam - > params . sensorFps . baserate , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETFLICKERCTRL )
do_command ( cam , CPIA_COMMAND_SetFlickerCtrl ,
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . flickerMode ,
cam - > params . flickerControl . coarseJump ,
abs ( cam - > params . flickerControl . allowableOverExposure ) ,
0 ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > cmd_queue & COMMAND_SETECPTIMING )
do_command ( cam , CPIA_COMMAND_SetECPTiming ,
2006-03-25 15:19:53 +03:00
cam - > params . ecpTiming , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
}
cam - > cmd_queue = COMMAND_NONE ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return ;
}
static void set_flicker ( struct cam_params * params , volatile u32 * command_flags ,
2006-03-25 15:19:53 +03:00
int on )
2005-04-17 02:20:36 +04:00
{
/* Everything in here is from the Windows driver */
# define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2006-03-25 15:19:53 +03:00
params - > version . firmwareRevision = = ( y ) )
2005-04-17 02:20:36 +04:00
/* 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
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
else
2005-04-17 02:20:36 +04:00
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) && \
2006-03-25 15:19:53 +03:00
cam - > params . version . firmwareRevision = = ( y ) )
2005-04-17 02:20:36 +04:00
/* 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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ] ;
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
light_exp = cam - > params . colourParams . brightness +
2006-03-25 15:19:53 +03:00
TC - 50 + EXP_ACC_LIGHT ;
2005-04-17 02:20:36 +04:00
if ( light_exp > 255 )
light_exp = 255 ;
dark_exp = cam - > params . colourParams . brightness +
2006-03-25 15:19:53 +03:00
TC - 50 - EXP_ACC_DARK ;
2005-04-17 02:20:36 +04:00
if ( dark_exp < 0 )
dark_exp = 0 ;
very_dark_exp = dark_exp / 2 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
old_exposure = cam - > params . exposure . coarseExpHi * 256 +
2006-03-25 15:19:53 +03:00
cam - > params . exposure . coarseExpLo ;
2005-04-17 02:20:36 +04:00
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 ;
}
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
framerate = cam - > fps ;
if ( framerate > 30 | | framerate < 1 )
framerate = 1 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
flicker_jumps [ cam - > mainsFreq ]
2006-03-25 15:19:53 +03:00
[ cam - > params . sensorFps . baserate ]
[ cam - > params . sensorFps . divisor ] ;
2005-04-17 02:20:36 +04:00
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 */
2006-03-25 15:19:53 +03:00
int max_exp = FIRMWARE_VERSION ( 1 , 2 ) ? MAX_EXP_102 : MAX_EXP ;
2005-04-17 02:20:36 +04:00
- - cam - > params . sensorFps . divisor ;
cam - > cmd_queue | = COMMAND_SETSENSORFPS ;
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
flicker_jumps [ cam - > mainsFreq ]
2006-03-25 15:19:53 +03:00
[ cam - > params . sensorFps . baserate ]
[ cam - > params . sensorFps . divisor ] ;
2005-04-17 02:20:36 +04:00
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 " ) ;
}
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
}
/*-----------------------------------------------------------------*/
/* 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
2006-03-25 15:19:53 +03:00
*/
2005-04-17 02:20:36 +04:00
static void restart_flicker ( struct cam_data * cam )
{
int cam_exposure , old_exp ;
if ( ! FIRMWARE_VERSION ( 1 , 2 ) )
return ;
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > params . flickerControl . flickerMode = = 0 | |
cam - > raw_image [ 39 ] = = 0 ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
return ;
}
cam_exposure = cam - > raw_image [ 39 ] * 2 ;
old_exp = cam - > params . exposure . coarseExpLo +
2006-03-25 15:19:53 +03:00
cam - > params . exposure . coarseExpHi * 256 ;
/*
see how far away camera exposure is from a valid
flicker exposure value
*/
cam_exposure % = cam - > params . flickerControl . coarseJump ;
2005-04-17 02:20:36 +04:00
if ( ! cam - > params . flickerControl . disabled & &
2006-03-25 15:19:53 +03:00
cam_exposure < = cam - > params . flickerControl . coarseJump - 3 ) {
2005-04-17 02:20:36 +04:00
/* Flicker control auto-disabled */
cam - > params . flickerControl . disabled = 1 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( cam - > params . flickerControl . disabled & &
cam - > params . flickerControl . flickerMode & &
old_exp > cam - > params . flickerControl . coarseJump +
2006-03-25 15:19:53 +03:00
ROUND_UP_EXP_FOR_FLICKER ) {
2005-04-17 02:20:36 +04:00
/* 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 ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
}
# undef FIRMWARE_VERSION
static int clear_stall ( struct cam_data * cam )
{
/* FIXME: Does this actually work? */
LOG ( " Clearing stall \n " ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
0 , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* If AEC is enabled, monitor the exposure and
adjust the sensor frame rate if needed */
if ( cam - > params . exposure . expMode = = 2 )
monitor_exposure ( cam ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* camera idle now so dispatch queued commands */
dispatch_commands ( cam ) ;
/* Update our knowledge of the camera state */
2006-03-25 15:19:53 +03:00
do_command ( cam , CPIA_COMMAND_GetColourBalance , 0 , 0 , 0 , 0 ) ;
do_command ( cam , CPIA_COMMAND_GetExposure , 0 , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
CPIA_GRAB_SINGLE , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
/* 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 ,
2006-03-25 15:19:53 +03:00
cam - > params . compression . mode ,
2005-04-17 02:20:36 +04:00
cam - > params . compression . decimation , 0 , 0 ) ;
/* Switch from single-grab to continuous grab */
do_command ( cam , CPIA_COMMAND_SetGrabMode ,
2006-03-25 15:19:53 +03:00
CPIA_GRAB_CONTINUOUS , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > curframe = vm - > frame ;
cam - > frame [ cam - > curframe ] . state = FRAME_READY ;
return fetch_frame ( cam ) ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 |
2006-03-25 15:19:53 +03:00
COMMAND_SETCOMPRESSIONTARGET |
COMMAND_SETCOLOURPARAMS |
COMMAND_SETFORMAT |
COMMAND_SETYUVTHRESH |
COMMAND_SETECPTIMING |
COMMAND_SETCOMPRESSIONPARAMS |
COMMAND_SETEXPOSURE |
COMMAND_SETCOLOURBALANCE |
COMMAND_SETSENSORFPS |
COMMAND_SETAPCOR |
COMMAND_SETFLICKERCTRL |
COMMAND_SETVLOFFSET ;
2005-04-17 02:20:36 +04:00
do_command ( cam , CPIA_COMMAND_SetGrabMode , CPIA_GRAB_SINGLE , 0 , 0 , 0 ) ;
dispatch_commands ( cam ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* procedure described in developer's guide p3-28 */
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ) ;
2006-03-25 15:19:53 +03:00
/* The fatal error checking should be done after
2005-04-17 02:20:36 +04:00
* 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 ,
2006-03-25 15:19:53 +03:00
STREAM_NOT_READY , 0 ) ;
2005-04-17 02:20:36 +04:00
/* 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 ,
2006-03-25 15:19:53 +03:00
FATALERROR , ~ ( COM_FLAG | CPIA_FLAG ) , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* Check the camera status again */
if ( cam - > params . status . fatalError ) {
if ( cam - > params . status . fatalError )
return - EIO ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 )
{
2007-01-07 16:36:24 +03:00
module_put ( ops - > owner ) ;
2005-04-17 02:20:36 +04:00
}
/* ------------------------- V4L interface --------------------- */
2008-12-30 12:58:20 +03:00
static int cpia_open ( struct file * file )
2005-04-17 02:20:36 +04:00
{
struct video_device * dev = video_devdata ( file ) ;
2008-08-23 14:24:07 +04:00
struct cam_data * cam = video_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
err = - ENOMEM ;
if ( ! cam - > raw_image ) {
cam - > raw_image = rvmalloc ( CPIA_MAX_IMAGE_SIZE ) ;
if ( ! cam - > raw_image )
goto oops ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
if ( ! cam - > decompressed_frame . data ) {
cam - > decompressed_frame . data = rvmalloc ( CPIA_MAX_FRAME_SIZE ) ;
if ( ! cam - > decompressed_frame . data )
goto oops ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* open cpia */
err = - ENODEV ;
if ( cam - > ops - > open ( cam - > lowlevel_data ) )
goto oops ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* reset the camera */
if ( ( err = reset_camera ( cam ) ) ! = 0 ) {
cam - > ops - > close ( cam - > lowlevel_data ) ;
goto oops ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
err = - EINTR ;
if ( signal_pending ( current ) )
goto oops ;
/* Set ownership of /proc/cpia/videoX to current user */
if ( cam - > proc_entry )
2008-08-27 17:46:39 +04:00
cam - > proc_entry - > uid = current_uid ( ) ;
2005-04-17 02:20:36 +04:00
/* set mark for loading first frame uncompressed */
cam - > first_frame = 1 ;
/* init it to something */
cam - > mmap_kludge = 0 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
+ + cam - > open_count ;
file - > private_data = dev ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
put_cam ( cam - > ops ) ;
return err ;
}
2008-12-30 12:58:20 +03:00
static int cpia_close ( struct file * file )
2005-04-17 02:20:36 +04:00
{
struct video_device * dev = file - > private_data ;
2008-08-23 14:24:07 +04:00
struct cam_data * cam = video_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( cam - > ops ) {
2006-03-25 15:19:53 +03:00
/* Return ownership of /proc/cpia/videoX to root */
2005-04-17 02:20:36 +04:00
if ( cam - > proc_entry )
cam - > proc_entry - > uid = 0 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ;
2008-08-23 14:24:07 +04:00
struct cam_data * cam = video_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int err ;
/* make this _really_ smp and multithread-safe */
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & cam - > busy_lock ) )
2005-04-17 02:20:36 +04:00
return - EINTR ;
if ( ! buf ) {
DBG ( " buf NULL \n " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( ! count ) {
DBG ( " count 0 \n " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
if ( ! cam - > ops ) {
DBG ( " ops NULL \n " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
if ( copy_to_user ( buf , cam - > decompressed_frame . data ,
2006-03-25 15:19:53 +03:00
cam - > decompressed_frame . count ) ) {
2005-04-17 02:20:36 +04:00
DBG ( " copy_to_user failed \n " ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return cam - > decompressed_frame . count ;
}
2008-12-30 13:04:34 +03:00
static long cpia_do_ioctl ( struct file * file , unsigned int cmd , void * arg )
2005-04-17 02:20:36 +04:00
{
struct video_device * dev = file - > private_data ;
2008-08-23 14:24:07 +04:00
struct cam_data * cam = video_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
if ( ! cam | | ! cam - > ops )
return - ENODEV ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* make this _really_ smp-safe */
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & cam - > busy_lock ) )
2005-04-17 02:20:36 +04:00
return - EINTR ;
2008-11-01 14:25:11 +03:00
/* DBG("cpia_ioctl: %u\n", cmd); */
2005-04-17 02:20:36 +04:00
2008-11-01 14:25:11 +03:00
switch ( cmd ) {
2006-03-08 04:20:23 +03:00
/* query capabilities */
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
}
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
/* 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 )
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . allowableOverExposure =
2005-04-17 02:20:36 +04:00
- find_over_exposure ( cam - > params . colourParams . brightness ) ;
if ( cam - > params . flickerControl . flickerMode ! = 0 )
cam - > cmd_queue | = COMMAND_SETFLICKERCTRL ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* queue command to update camera */
cam - > cmd_queue | = COMMAND_SETCOLOURPARAMS ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ? ? ?
*/
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
break ;
}
cam - > video_size = video_size ;
/* video size is changing, reset the subcapture area */
memset ( & cam - > vc , 0 , sizeof ( cam - > vc ) ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
set_vw_size ( cam ) ;
DBG ( " %d / %d \n " , cam - > vw . width , cam - > vw . height ) ;
cam - > cmd_queue | = COMMAND_SETFORMAT ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
/* 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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ) ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
}
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ) ;
2006-03-25 15:19:53 +03:00
2006-02-07 11:49:14 +03:00
mutex_lock ( & cam - > param_lock ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > vc . x = vc - > x ;
cam - > vc . y = vc - > y ;
cam - > vc . width = vc - > width ;
cam - > vc . height = vc - > height ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
set_vw_size ( cam ) ;
cam - > cmd_queue | = COMMAND_SETFORMAT ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > param_lock ) ;
2005-04-17 02:20:36 +04:00
/* setformat ignored by camera during streaming,
* so stop / dispatch / start */
dispatch_commands ( cam ) ;
break ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return retval ;
2006-03-25 15:19:53 +03:00
}
2005-04-17 02:20:36 +04:00
2008-12-30 13:04:34 +03:00
static long cpia_ioctl ( struct file * file ,
2005-04-17 02:20:36 +04:00
unsigned int cmd , unsigned long arg )
{
2008-11-01 14:25:11 +03:00
return video_usercopy ( file , cmd , arg , cpia_do_ioctl ) ;
2005-04-17 02:20:36 +04:00
}
/* 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 ;
2008-08-23 14:24:07 +04:00
struct cam_data * cam = video_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int retval ;
if ( ! cam | | ! cam - > ops )
return - ENODEV ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
DBG ( " cpia_mmap: %ld \n " , size ) ;
if ( size > FRAME_NUM * CPIA_MAX_FRAME_SIZE )
return - EINVAL ;
if ( ! cam | | ! cam - > ops )
return - ENODEV ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* make this _really_ smp-safe */
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & cam - > busy_lock ) )
2005-04-17 02:20:36 +04:00
return - EINTR ;
if ( ! cam - > frame_buf ) { /* we do lazy allocation */
if ( ( retval = allocate_frame_buf ( cam ) ) ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
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 ) ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return - EAGAIN ;
}
start + = PAGE_SIZE ;
pos + = PAGE_SIZE ;
if ( size > PAGE_SIZE )
size - = PAGE_SIZE ;
else
size = 0 ;
}
DBG ( " cpia_mmap: %ld \n " , size ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-12-30 12:58:20 +03:00
static const struct v4l2_file_operations cpia_fops = {
2005-04-17 02:20:36 +04:00
. 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 ,
2008-08-23 13:23:55 +04:00
. release = video_device_release_empty ,
2005-04-17 02:20:36 +04:00
} ;
/* 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 ;
2006-03-25 15:19:53 +03:00
cam - > params . flickerControl . coarseJump =
2005-04-17 02:20:36 +04:00
flicker_jumps [ cam - > mainsFreq ]
2006-03-25 15:19:53 +03:00
[ cam - > params . sensorFps . baserate ]
[ cam - > params . sensorFps . divisor ] ;
cam - > params . flickerControl . allowableOverExposure =
2005-04-17 02:20:36 +04:00
- 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 */
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > transfer_rate = 0 ;
cam - > exposure_status = EXPOSURE_NORMAL ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* Set Sensor FPS to 15fps. This seems better than 30fps
* for indoor lighting . */
cam - > params . sensorFps . divisor = 1 ;
cam - > params . sensorFps . baserate = 1 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > params . yuvThreshold . yThreshold = 6 ; /* From windows driver */
cam - > params . yuvThreshold . uvThreshold = 6 ; /* From windows driver */
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
cam - > params . format . subSample = SUBSAMPLE_422 ;
cam - > params . format . yuvOrder = YUVORDER_YUYV ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 ,
2006-03-25 15:19:53 +03:00
struct cpia_camera_ops * ops )
2005-04-17 02:20:36 +04:00
{
int i ;
/* Default everything to 0 */
memset ( cam , 0 , sizeof ( struct cam_data ) ) ;
cam - > ops = ops ;
2006-02-07 11:49:14 +03:00
mutex_init ( & cam - > param_lock ) ;
mutex_init ( & cam - > busy_lock ) ;
2005-04-17 02:20:36 +04:00
reset_camera_struct ( cam ) ;
cam - > proc_entry = NULL ;
memcpy ( & cam - > vdev , & cpia_template , sizeof ( cpia_template ) ) ;
2008-08-23 14:24:07 +04:00
video_set_drvdata ( & cam - > vdev , cam ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
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 )
{
2006-03-25 15:19:53 +03:00
struct cam_data * camera ;
2005-04-17 02:20:36 +04:00
if ( ( camera = kmalloc ( sizeof ( struct cam_data ) , GFP_KERNEL ) ) = = NULL )
return NULL ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
init_camera_struct ( camera , ops ) ;
camera - > lowlevel_data = lowlevel ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* register v4l device */
2008-09-04 00:11:58 +04:00
if ( video_register_device ( & camera - > vdev , VFL_TYPE_GRABBER , video_nr ) < 0 ) {
2005-04-17 02:20:36 +04:00
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 ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ;
}
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PROC_FS
2008-10-20 01:54:26 +04:00
DBG ( " destroying /proc/cpia/video%d \n " , cam - > vdev . num ) ;
2005-04-17 02:20:36 +04:00
destroy_proc_cpia_cam ( cam ) ;
2006-03-25 15:19:53 +03:00
# endif
2005-04-17 02:20:36 +04:00
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 "
2006-03-27 23:18:25 +04:00
" parameter to 1 \n " ) ;
2005-04-17 02:20:36 +04:00
# 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 ) ;