2009-01-16 05:36:14 -03:00
/*
* Mars MR97310A library
*
2009-10-05 05:11:35 -03:00
* The original mr97310a driver , which supported the Aiptek Pencam VGA + , is
2009-01-16 05:36:14 -03:00
* Copyright ( C ) 2009 Kyle Guinn < elyk03 @ gmail . com >
*
2009-08-14 06:51:52 -03:00
* Support for the MR97310A cameras in addition to the Aiptek Pencam VGA +
* and for the routines for detecting and classifying these various cameras ,
2009-10-05 05:11:35 -03:00
* is Copyright ( C ) 2009 Theodore Kilgore < kilgota @ auburn . edu >
2009-08-14 06:51:52 -03:00
*
2009-10-05 05:11:35 -03:00
* Support for the control settings for the CIF cameras is
2010-09-05 07:06:04 -03:00
* Copyright ( C ) 2009 Hans de Goede < hdegoede @ redhat . com > and
2009-10-05 05:11:35 -03:00
* Thomas Kaiser < thomas @ kaiser - linux . li >
*
* Support for the control settings for the VGA cameras is
2009-08-14 06:51:52 -03:00
* Copyright ( C ) 2009 Theodore Kilgore < kilgota @ auburn . edu >
*
2009-10-05 05:11:35 -03:00
* Several previously unsupported cameras are owned and have been tested by
2010-09-05 07:06:04 -03:00
* Hans de Goede < hdegoede @ redhat . com > and
2009-10-05 05:11:35 -03:00
* Thomas Kaiser < thomas @ kaiser - linux . li > and
2009-10-30 04:29:56 -03:00
* Theodore Kilgore < kilgota @ auburn . edu > and
* Edmond Rodriguez < erodrig_97 @ yahoo . com > and
* Aurelien Jacobs < aurel @ gnuage . org >
2009-08-14 06:51:52 -03:00
*
* The MR97311A support in gspca / mars . c has been helpful in understanding some
* of the registers in these cameras .
*
2009-01-16 05:36:14 -03:00
* 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
* 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 .
*/
2011-08-21 19:56:57 -03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2009-01-16 05:36:14 -03:00
# define MODULE_NAME "mr97310a"
# include "gspca.h"
2009-08-14 06:51:52 -03:00
# define CAM_TYPE_CIF 0
# define CAM_TYPE_VGA 1
# define MR97310A_BRIGHTNESS_DEFAULT 0
2009-10-05 05:11:35 -03:00
# define MR97310A_EXPOSURE_MIN 0
2009-08-14 06:51:52 -03:00
# define MR97310A_EXPOSURE_MAX 4095
# define MR97310A_EXPOSURE_DEFAULT 1000
# define MR97310A_GAIN_MIN 0
# define MR97310A_GAIN_MAX 31
# define MR97310A_GAIN_DEFAULT 25
2010-02-09 18:05:25 -03:00
# define MR97310A_CONTRAST_MIN 0
# define MR97310A_CONTRAST_MAX 31
# define MR97310A_CONTRAST_DEFAULT 23
# define MR97310A_CS_GAIN_MIN 0
# define MR97310A_CS_GAIN_MAX 0x7ff
# define MR97310A_CS_GAIN_DEFAULT 0x110
2012-05-14 09:45:06 -03:00
# define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000)
2009-10-29 07:42:30 -03:00
# define MR97310A_MIN_CLOCKDIV_MIN 3
# define MR97310A_MIN_CLOCKDIV_MAX 8
# define MR97310A_MIN_CLOCKDIV_DEFAULT 3
[media] gspca: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-18 17:44:16 -02:00
MODULE_AUTHOR ( " Kyle Guinn <elyk03@gmail.com>,Theodore Kilgore <kilgota@auburn.edu> " ) ;
2009-01-16 05:36:14 -03:00
MODULE_DESCRIPTION ( " GSPCA/Mars-Semi MR97310A USB Camera Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-09-02 09:55:16 -03:00
/* global parameters */
2009-12-12 06:58:01 -03:00
static int force_sensor_type = - 1 ;
2009-09-02 09:55:16 -03:00
module_param ( force_sensor_type , int , 0644 ) ;
MODULE_PARM_DESC ( force_sensor_type , " Force sensor type (-1 (auto), 0 or 1) " ) ;
2009-01-16 05:36:14 -03:00
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev ; /* !! must be the first item */
2012-05-14 09:45:06 -03:00
struct { /* exposure/min_clockdiv control cluster */
struct v4l2_ctrl * exposure ;
struct v4l2_ctrl * min_clockdiv ;
} ;
2009-01-16 05:36:14 -03:00
u8 sof_read ;
2009-08-14 06:51:52 -03:00
u8 cam_type ; /* 0 is CIF and 1 is VGA */
u8 sensor_type ; /* We use 0 and 1 here, too. */
u8 do_lcd_stop ;
2009-10-30 04:43:39 -03:00
u8 adj_colors ;
2009-01-16 05:36:14 -03:00
} ;
2009-08-14 06:51:52 -03:00
struct sensor_w_data {
u8 reg ;
u8 flags ;
u8 data [ 16 ] ;
int len ;
} ;
2009-10-05 05:11:35 -03:00
static void sd_stopN ( struct gspca_dev * gspca_dev ) ;
2009-01-16 05:36:14 -03:00
static const struct v4l2_pix_format vga_mode [ ] = {
{ 160 , 120 , V4L2_PIX_FMT_MR97310A , V4L2_FIELD_NONE ,
. bytesperline = 160 ,
. sizeimage = 160 * 120 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 4 } ,
{ 176 , 144 , V4L2_PIX_FMT_MR97310A , V4L2_FIELD_NONE ,
. bytesperline = 176 ,
. sizeimage = 176 * 144 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 3 } ,
{ 320 , 240 , V4L2_PIX_FMT_MR97310A , V4L2_FIELD_NONE ,
. bytesperline = 320 ,
. sizeimage = 320 * 240 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 2 } ,
{ 352 , 288 , V4L2_PIX_FMT_MR97310A , V4L2_FIELD_NONE ,
. bytesperline = 352 ,
. sizeimage = 352 * 288 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 1 } ,
{ 640 , 480 , V4L2_PIX_FMT_MR97310A , V4L2_FIELD_NONE ,
. bytesperline = 640 ,
. sizeimage = 640 * 480 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 0 } ,
} ;
/* the bytes to write are in gspca_dev->usb_buf */
2009-08-14 06:51:52 -03:00
static int mr_write ( struct gspca_dev * gspca_dev , int len )
2009-01-16 05:36:14 -03:00
{
int rc ;
rc = usb_bulk_msg ( gspca_dev - > dev ,
usb_sndbulkpipe ( gspca_dev - > dev , 4 ) ,
2009-02-02 16:25:38 -03:00
gspca_dev - > usb_buf , len , NULL , 500 ) ;
2009-01-16 05:36:14 -03:00
if ( rc < 0 )
2011-08-21 19:56:57 -03:00
pr_err ( " reg write [%02x] error %d \n " ,
2009-01-16 05:36:14 -03:00
gspca_dev - > usb_buf [ 0 ] , rc ) ;
return rc ;
}
2009-08-14 06:51:52 -03:00
/* the bytes are read into gspca_dev->usb_buf */
static int mr_read ( struct gspca_dev * gspca_dev , int len )
{
int rc ;
rc = usb_bulk_msg ( gspca_dev - > dev ,
usb_rcvbulkpipe ( gspca_dev - > dev , 3 ) ,
gspca_dev - > usb_buf , len , NULL , 500 ) ;
if ( rc < 0 )
2011-08-21 19:56:57 -03:00
pr_err ( " reg read [%02x] error %d \n " ,
2009-08-14 06:51:52 -03:00
gspca_dev - > usb_buf [ 0 ] , rc ) ;
return rc ;
}
static int sensor_write_reg ( struct gspca_dev * gspca_dev , u8 reg , u8 flags ,
const u8 * data , int len )
{
gspca_dev - > usb_buf [ 0 ] = 0x1f ;
gspca_dev - > usb_buf [ 1 ] = flags ;
gspca_dev - > usb_buf [ 2 ] = reg ;
memcpy ( gspca_dev - > usb_buf + 3 , data , len ) ;
return mr_write ( gspca_dev , len + 3 ) ;
}
static int sensor_write_regs ( struct gspca_dev * gspca_dev ,
const struct sensor_w_data * data , int len )
{
int i , rc ;
for ( i = 0 ; i < len ; i + + ) {
rc = sensor_write_reg ( gspca_dev , data [ i ] . reg , data [ i ] . flags ,
data [ i ] . data , data [ i ] . len ) ;
if ( rc < 0 )
return rc ;
}
return 0 ;
}
static int sensor_write1 ( struct gspca_dev * gspca_dev , u8 reg , u8 data )
{
2009-08-14 17:11:36 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
u8 buf , confirm_reg ;
2009-08-14 06:51:52 -03:00
int rc ;
buf = data ;
2009-10-05 05:11:35 -03:00
if ( sd - > cam_type = = CAM_TYPE_CIF ) {
rc = sensor_write_reg ( gspca_dev , reg , 0x01 , & buf , 1 ) ;
confirm_reg = sd - > sensor_type ? 0x13 : 0x11 ;
} else {
rc = sensor_write_reg ( gspca_dev , reg , 0x00 , & buf , 1 ) ;
confirm_reg = 0x11 ;
}
2009-08-14 06:51:52 -03:00
if ( rc < 0 )
return rc ;
buf = 0x01 ;
2009-08-14 17:11:36 -03:00
rc = sensor_write_reg ( gspca_dev , confirm_reg , 0x00 , & buf , 1 ) ;
2009-08-14 06:51:52 -03:00
if ( rc < 0 )
return rc ;
return 0 ;
}
2009-10-05 05:11:35 -03:00
static int cam_get_response16 ( struct gspca_dev * gspca_dev , u8 reg , int verbose )
2009-08-14 06:51:52 -03:00
{
int err_code ;
2009-10-05 05:11:35 -03:00
gspca_dev - > usb_buf [ 0 ] = reg ;
2009-08-14 06:51:52 -03:00
err_code = mr_write ( gspca_dev , 1 ) ;
if ( err_code < 0 )
return err_code ;
err_code = mr_read ( gspca_dev , 16 ) ;
2009-10-05 05:11:35 -03:00
if ( err_code < 0 )
return err_code ;
if ( verbose )
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " Register: %02x reads %02x%02x%02x \n " ,
reg ,
gspca_dev - > usb_buf [ 0 ] ,
gspca_dev - > usb_buf [ 1 ] ,
gspca_dev - > usb_buf [ 2 ] ) ;
2009-10-05 05:11:35 -03:00
return 0 ;
2009-08-14 06:51:52 -03:00
}
static int zero_the_pointer ( struct gspca_dev * gspca_dev )
{
__u8 * data = gspca_dev - > usb_buf ;
int err_code ;
u8 status = 0 ;
int tries = 0 ;
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
if ( err_code < 0 )
return err_code ;
data [ 0 ] = 0x19 ;
data [ 1 ] = 0x51 ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
if ( err_code < 0 )
return err_code ;
data [ 0 ] = 0x19 ;
data [ 1 ] = 0xba ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
if ( err_code < 0 )
return err_code ;
data [ 0 ] = 0x19 ;
data [ 1 ] = 0x00 ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
if ( err_code < 0 )
return err_code ;
data [ 0 ] = 0x19 ;
data [ 1 ] = 0x00 ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
while ( status ! = 0x0a & & tries < 256 ) {
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
status = data [ 0 ] ;
tries + + ;
if ( err_code < 0 )
return err_code ;
}
2009-08-14 11:05:38 -03:00
if ( status ! = 0x0a )
2017-09-22 14:33:35 -04:00
gspca_err ( gspca_dev , " status is %02x \n " , status ) ;
2009-08-14 06:51:52 -03:00
tries = 0 ;
while ( tries < 4 ) {
data [ 0 ] = 0x19 ;
data [ 1 ] = 0x00 ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
2009-10-05 05:11:35 -03:00
err_code = cam_get_response16 ( gspca_dev , 0x21 , 0 ) ;
2009-08-14 06:51:52 -03:00
status = data [ 0 ] ;
tries + + ;
if ( err_code < 0 )
return err_code ;
}
data [ 0 ] = 0x19 ;
err_code = mr_write ( gspca_dev , 1 ) ;
if ( err_code < 0 )
return err_code ;
err_code = mr_read ( gspca_dev , 16 ) ;
if ( err_code < 0 )
return err_code ;
return 0 ;
}
2009-10-05 05:11:35 -03:00
static int stream_start ( struct gspca_dev * gspca_dev )
2009-08-14 06:51:52 -03:00
{
2009-10-05 05:11:35 -03:00
gspca_dev - > usb_buf [ 0 ] = 0x01 ;
gspca_dev - > usb_buf [ 1 ] = 0x01 ;
return mr_write ( gspca_dev , 2 ) ;
}
2009-08-14 06:51:52 -03:00
2009-10-05 05:11:35 -03:00
static void stream_stop ( struct gspca_dev * gspca_dev )
{
gspca_dev - > usb_buf [ 0 ] = 0x01 ;
gspca_dev - > usb_buf [ 1 ] = 0x00 ;
if ( mr_write ( gspca_dev , 2 ) < 0 )
2017-09-22 14:33:35 -04:00
gspca_err ( gspca_dev , " Stream Stop failed \n " ) ;
2009-10-05 05:11:35 -03:00
}
2009-08-14 06:51:52 -03:00
2009-10-05 05:11:35 -03:00
static void lcd_stop ( struct gspca_dev * gspca_dev )
{
gspca_dev - > usb_buf [ 0 ] = 0x19 ;
gspca_dev - > usb_buf [ 1 ] = 0x54 ;
if ( mr_write ( gspca_dev , 2 ) < 0 )
2017-09-22 14:33:35 -04:00
gspca_err ( gspca_dev , " LCD Stop failed \n " ) ;
2009-10-05 05:11:35 -03:00
}
2009-08-14 06:51:52 -03:00
2009-10-05 05:11:35 -03:00
static int isoc_enable ( struct gspca_dev * gspca_dev )
{
gspca_dev - > usb_buf [ 0 ] = 0x00 ;
2011-03-30 22:57:33 -03:00
gspca_dev - > usb_buf [ 1 ] = 0x4d ; /* ISOC transferring enable... */
2009-10-05 05:11:35 -03:00
return mr_write ( gspca_dev , 2 ) ;
2009-08-14 06:51:52 -03:00
}
2009-10-30 04:29:56 -03:00
/* This function is called at probe time */
2009-01-16 05:36:14 -03:00
static int sd_config ( struct gspca_dev * gspca_dev ,
const struct usb_device_id * id )
{
2009-08-14 06:51:52 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-16 05:36:14 -03:00
struct cam * cam ;
2009-08-14 10:40:26 -03:00
int err_code ;
2009-01-16 05:36:14 -03:00
cam = & gspca_dev - > cam ;
cam - > cam_mode = vga_mode ;
cam - > nmodes = ARRAY_SIZE ( vga_mode ) ;
2009-10-05 05:11:35 -03:00
sd - > do_lcd_stop = 0 ;
2009-10-30 04:29:56 -03:00
/* Several of the supported CIF cameras share the same USB ID but
* require different initializations and different control settings .
* The same is true of the VGA cameras . Therefore , we are forced
* to start the initialization process in order to determine which
* camera is present . Some of the supported cameras require the
2009-10-05 05:11:35 -03:00
* memory pointer to be set to 0 as the very first item of business
* or else they will not stream . So we do that immediately .
*/
err_code = zero_the_pointer ( gspca_dev ) ;
if ( err_code < 0 )
return err_code ;
2009-08-14 10:15:52 -03:00
2009-10-09 03:54:49 -03:00
err_code = stream_start ( gspca_dev ) ;
if ( err_code < 0 )
return err_code ;
2010-01-15 05:54:36 -03:00
/* Now, the query for sensor type. */
err_code = cam_get_response16 ( gspca_dev , 0x07 , 1 ) ;
if ( err_code < 0 )
return err_code ;
2009-10-29 07:45:24 -03:00
if ( id - > idProduct = = 0x0110 | | id - > idProduct = = 0x010e ) {
2009-08-14 06:51:52 -03:00
sd - > cam_type = CAM_TYPE_CIF ;
2009-08-14 10:15:52 -03:00
cam - > nmodes - - ;
2009-08-14 10:40:26 -03:00
/*
2009-10-30 04:29:56 -03:00
* All but one of the known CIF cameras share the same USB ID ,
* but two different init routines are in use , and the control
* settings are different , too . We need to detect which camera
* of the two known varieties is connected !
2009-08-14 10:40:26 -03:00
*
2009-10-05 05:11:35 -03:00
* A list of known CIF cameras follows . They all report either
2010-01-15 05:54:36 -03:00
* 0200 for type 0 or 0300 for type 1.
2009-10-05 05:11:35 -03:00
* If you have another to report , please do
*
* Name sd - > sensor_type reported by
*
2010-02-09 18:05:25 -03:00
* Sakar 56379 Spy - shot 0 T . Kilgore
2009-10-05 05:11:35 -03:00
* Innovage 0 T . Kilgore
* Vivitar Mini 0 H . De Goede
* Vivitar Mini 0 E . Rodriguez
* Vivitar Mini 1 T . Kilgore
* Elta - Media 8212 dc 1 T . Kaiser
* Philips dig . keych . 1 T . Kilgore
2009-10-30 04:29:56 -03:00
* Trust Spyc @ m 100 1 A . Jacobs
2009-08-14 10:40:26 -03:00
*/
2010-01-15 05:54:36 -03:00
switch ( gspca_dev - > usb_buf [ 0 ] ) {
2009-10-05 05:11:35 -03:00
case 2 :
2009-08-14 10:40:26 -03:00
sd - > sensor_type = 0 ;
2009-10-05 05:11:35 -03:00
break ;
case 3 :
sd - > sensor_type = 1 ;
break ;
default :
2011-08-21 19:56:57 -03:00
pr_err ( " Unknown CIF Sensor id : %02x \n " ,
2009-10-05 05:11:35 -03:00
gspca_dev - > usb_buf [ 1 ] ) ;
return - ENODEV ;
}
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " MR97310A CIF camera detected, sensor: %d \n " ,
sd - > sensor_type ) ;
2009-10-05 05:11:35 -03:00
} else {
sd - > cam_type = CAM_TYPE_VGA ;
2009-08-14 10:40:26 -03:00
2009-10-05 05:11:35 -03:00
/*
2010-01-15 05:54:36 -03:00
* Here is a table of the responses to the query for sensor
2010-02-09 18:05:25 -03:00
* type , from the known MR97310A VGA cameras . Six different
* cameras of which five share the same USB ID .
2009-10-05 05:11:35 -03:00
*
* Name gspca_dev - > usb_buf [ ] sd - > sensor_type
2009-10-09 03:54:49 -03:00
* sd - > do_lcd_stop
* Aiptek Pencam VGA + 0300 0 1
2010-02-09 18:05:25 -03:00
* ION digital 0300 0 1
2009-10-09 03:54:49 -03:00
* Argus DC - 1620 0450 1 0
* Argus QuickClix 0420 1 1
2010-02-09 18:05:25 -03:00
* Sakar 77379 Digital 0350 0 1
* Sakar 1638 x CyberPix 0120 0 2
2009-10-05 05:11:35 -03:00
*
2009-10-09 03:54:49 -03:00
* Based upon these results , we assume default settings
* and then correct as necessary , as follows .
2009-10-05 05:11:35 -03:00
*
*/
2009-10-09 03:54:49 -03:00
sd - > sensor_type = 1 ;
sd - > do_lcd_stop = 0 ;
2009-10-30 04:43:39 -03:00
sd - > adj_colors = 0 ;
2010-02-09 18:05:25 -03:00
if ( gspca_dev - > usb_buf [ 0 ] = = 0x01 ) {
sd - > sensor_type = 2 ;
} else if ( ( gspca_dev - > usb_buf [ 0 ] ! = 0x03 ) & &
2009-10-09 03:54:49 -03:00
( gspca_dev - > usb_buf [ 0 ] ! = 0x04 ) ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Unknown VGA Sensor id Byte 0: %02x \n " ,
gspca_dev - > usb_buf [ 0 ] ) ;
pr_err ( " Defaults assumed, may not work \n " ) ;
pr_err ( " Please report this \n " ) ;
2009-10-09 03:54:49 -03:00
}
2009-10-30 04:43:39 -03:00
/* Sakar Digital color needs to be adjusted. */
if ( ( gspca_dev - > usb_buf [ 0 ] = = 0x03 ) & &
( gspca_dev - > usb_buf [ 1 ] = = 0x50 ) )
sd - > adj_colors = 1 ;
2009-10-09 03:54:49 -03:00
if ( gspca_dev - > usb_buf [ 0 ] = = 0x04 ) {
sd - > do_lcd_stop = 1 ;
2009-10-05 05:11:35 -03:00
switch ( gspca_dev - > usb_buf [ 1 ] ) {
case 0x50 :
2009-10-09 03:54:49 -03:00
sd - > sensor_type = 0 ;
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " sensor_type corrected to 0 \n " ) ;
2009-10-05 05:11:35 -03:00
break ;
case 0x20 :
2009-10-09 03:54:49 -03:00
/* Nothing to do here. */
2009-10-05 05:11:35 -03:00
break ;
default :
2011-08-21 19:56:57 -03:00
pr_err ( " Unknown VGA Sensor id Byte 1: %02x \n " ,
gspca_dev - > usb_buf [ 1 ] ) ;
pr_err ( " Defaults assumed, may not work \n " ) ;
pr_err ( " Please report this \n " ) ;
2009-10-05 05:11:35 -03:00
}
2009-09-02 09:55:16 -03:00
}
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " MR97310A VGA camera detected, sensor: %d \n " ,
sd - > sensor_type ) ;
2009-10-05 05:11:35 -03:00
}
2010-01-15 05:54:36 -03:00
/* Stop streaming as we've started it only to probe the sensor type. */
2009-10-05 05:11:35 -03:00
sd_stopN ( gspca_dev ) ;
2009-09-02 09:55:16 -03:00
2009-10-05 05:11:35 -03:00
if ( force_sensor_type ! = - 1 ) {
sd - > sensor_type = ! ! force_sensor_type ;
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " Forcing sensor type to: %d \n " ,
sd - > sensor_type ) ;
2009-10-05 05:11:35 -03:00
}
2009-01-16 05:36:14 -03:00
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init ( struct gspca_dev * gspca_dev )
{
return 0 ;
}
2009-08-14 06:51:52 -03:00
static int start_cif_cam ( struct gspca_dev * gspca_dev )
2009-01-16 05:36:14 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
__u8 * data = gspca_dev - > usb_buf ;
int err_code ;
2010-10-01 07:37:15 -03:00
static const __u8 startup_string [ ] = {
2009-08-14 06:51:52 -03:00
0x00 ,
0x0d ,
0x01 ,
0x00 , /* Hsize/8 for 352 or 320 */
0x00 , /* Vsize/4 for 288 or 240 */
0x13 , /* or 0xbb, depends on sensor */
0x00 , /* Hstart, depends on res. */
0x00 , /* reserved ? */
0x00 , /* Vstart, depends on res. and sensor */
0x50 , /* 0x54 to get 176 or 160 */
0xc0
} ;
/* Note: Some of the above descriptions guessed from MR97113A driver */
2009-01-16 05:36:14 -03:00
2009-08-14 06:51:52 -03:00
memcpy ( data , startup_string , 11 ) ;
if ( sd - > sensor_type )
data [ 5 ] = 0xbb ;
2009-01-16 05:36:14 -03:00
2013-08-30 17:54:23 -03:00
switch ( gspca_dev - > pixfmt . width ) {
2009-01-16 05:36:14 -03:00
case 160 :
2009-08-14 06:51:52 -03:00
data [ 9 ] | = 0x04 ; /* reg 8, 2:1 scale down from 320 */
2009-01-16 05:36:14 -03:00
/* fall thru */
case 320 :
default :
2009-08-14 06:51:52 -03:00
data [ 3 ] = 0x28 ; /* reg 2, H size/8 */
data [ 4 ] = 0x3c ; /* reg 3, V size/4 */
data [ 6 ] = 0x14 ; /* reg 5, H start */
data [ 8 ] = 0x1a + sd - > sensor_type ; /* reg 7, V start */
2009-01-16 05:36:14 -03:00
break ;
case 176 :
2009-08-14 06:51:52 -03:00
data [ 9 ] | = 0x04 ; /* reg 8, 2:1 scale down from 352 */
2009-01-16 05:36:14 -03:00
/* fall thru */
case 352 :
2009-08-14 06:51:52 -03:00
data [ 3 ] = 0x2c ; /* reg 2, H size/8 */
data [ 4 ] = 0x48 ; /* reg 3, V size/4 */
data [ 6 ] = 0x06 ; /* reg 5, H start */
2009-11-01 12:59:42 -03:00
data [ 8 ] = 0x06 - sd - > sensor_type ; /* reg 7, V start */
2009-01-16 05:36:14 -03:00
break ;
}
2009-08-14 06:51:52 -03:00
err_code = mr_write ( gspca_dev , 11 ) ;
2009-01-16 05:36:14 -03:00
if ( err_code < 0 )
return err_code ;
2009-08-14 06:51:52 -03:00
if ( ! sd - > sensor_type ) {
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data cif_sensor0_init_data [ ] = {
2009-08-14 06:51:52 -03:00
{ 0x02 , 0x00 , { 0x03 , 0x5a , 0xb5 , 0x01 ,
0x0f , 0x14 , 0x0f , 0x10 } , 8 } ,
{ 0x0c , 0x00 , { 0x04 , 0x01 , 0x01 , 0x00 , 0x1f } , 5 } ,
{ 0x12 , 0x00 , { 0x07 } , 1 } ,
{ 0x1f , 0x00 , { 0x06 } , 1 } ,
{ 0x27 , 0x00 , { 0x04 } , 1 } ,
{ 0x29 , 0x00 , { 0x0c } , 1 } ,
{ 0x40 , 0x00 , { 0x40 , 0x00 , 0x04 } , 3 } ,
{ 0x50 , 0x00 , { 0x60 } , 1 } ,
{ 0x60 , 0x00 , { 0x06 } , 1 } ,
{ 0x6b , 0x00 , { 0x85 , 0x85 , 0xc8 , 0xc8 , 0xc8 , 0xc8 } , 6 } ,
{ 0x72 , 0x00 , { 0x1e , 0x56 } , 2 } ,
{ 0x75 , 0x00 , { 0x58 , 0x40 , 0xa2 , 0x02 , 0x31 , 0x02 ,
0x31 , 0x80 , 0x00 } , 9 } ,
{ 0x11 , 0x00 , { 0x01 } , 1 } ,
{ 0 , 0 , { 0 } , 0 }
} ;
err_code = sensor_write_regs ( gspca_dev , cif_sensor0_init_data ,
ARRAY_SIZE ( cif_sensor0_init_data ) ) ;
} else { /* sd->sensor_type = 1 */
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data cif_sensor1_init_data [ ] = {
2009-08-14 10:15:52 -03:00
/* Reg 3,4, 7,8 get set by the controls */
2009-08-14 06:51:52 -03:00
{ 0x02 , 0x00 , { 0x10 } , 1 } ,
2009-08-14 10:15:52 -03:00
{ 0x05 , 0x01 , { 0x22 } , 1 } , /* 5/6 also seen as 65h/32h */
{ 0x06 , 0x01 , { 0x00 } , 1 } ,
2009-08-14 06:51:52 -03:00
{ 0x09 , 0x02 , { 0x0e } , 1 } ,
{ 0x0a , 0x02 , { 0x05 } , 1 } ,
{ 0x0b , 0x02 , { 0x05 } , 1 } ,
{ 0x0c , 0x02 , { 0x0f } , 1 } ,
2009-08-14 10:15:52 -03:00
{ 0x0d , 0x02 , { 0x07 } , 1 } ,
2009-08-14 06:51:52 -03:00
{ 0x0e , 0x02 , { 0x0c } , 1 } ,
{ 0x0f , 0x00 , { 0x00 } , 1 } ,
{ 0x10 , 0x00 , { 0x06 } , 1 } ,
{ 0x11 , 0x00 , { 0x07 } , 1 } ,
{ 0x12 , 0x00 , { 0x00 } , 1 } ,
{ 0x13 , 0x00 , { 0x01 } , 1 } ,
{ 0 , 0 , { 0 } , 0 }
} ;
2009-12-25 05:15:10 -03:00
/* Without this command the cam won't work with USB-UHCI */
gspca_dev - > usb_buf [ 0 ] = 0x0a ;
gspca_dev - > usb_buf [ 1 ] = 0x00 ;
err_code = mr_write ( gspca_dev , 2 ) ;
if ( err_code < 0 )
return err_code ;
2009-08-14 06:51:52 -03:00
err_code = sensor_write_regs ( gspca_dev , cif_sensor1_init_data ,
ARRAY_SIZE ( cif_sensor1_init_data ) ) ;
}
2009-10-05 05:11:35 -03:00
return err_code ;
2009-08-14 06:51:52 -03:00
}
2009-01-16 05:36:14 -03:00
2009-08-14 06:51:52 -03:00
static int start_vga_cam ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
__u8 * data = gspca_dev - > usb_buf ;
int err_code ;
2010-10-01 07:37:15 -03:00
static const __u8 startup_string [ ] =
{ 0x00 , 0x0d , 0x01 , 0x00 , 0x00 , 0x2b , 0x00 , 0x00 ,
0x00 , 0x50 , 0xc0 } ;
2009-08-14 06:51:52 -03:00
/* What some of these mean is explained in start_cif_cam(), above */
2009-09-02 09:55:16 -03:00
2009-08-14 06:51:52 -03:00
memcpy ( data , startup_string , 11 ) ;
if ( ! sd - > sensor_type ) {
data [ 5 ] = 0x00 ;
data [ 10 ] = 0x91 ;
}
2010-02-09 18:05:25 -03:00
if ( sd - > sensor_type = = 2 ) {
data [ 5 ] = 0x00 ;
data [ 10 ] = 0x18 ;
}
2009-08-14 06:51:52 -03:00
2013-08-30 17:54:23 -03:00
switch ( gspca_dev - > pixfmt . width ) {
2009-08-14 06:51:52 -03:00
case 160 :
data [ 9 ] | = 0x0c ; /* reg 8, 4:1 scale down */
/* fall thru */
case 320 :
data [ 9 ] | = 0x04 ; /* reg 8, 2:1 scale down */
/* fall thru */
case 640 :
default :
data [ 3 ] = 0x50 ; /* reg 2, H size/8 */
data [ 4 ] = 0x78 ; /* reg 3, V size/4 */
data [ 6 ] = 0x04 ; /* reg 5, H start */
data [ 8 ] = 0x03 ; /* reg 7, V start */
2010-02-09 18:05:25 -03:00
if ( sd - > sensor_type = = 2 ) {
data [ 6 ] = 2 ;
data [ 8 ] = 1 ;
}
2009-08-14 06:51:52 -03:00
if ( sd - > do_lcd_stop )
data [ 8 ] = 0x04 ; /* Bayer tile shifted */
break ;
case 176 :
data [ 9 ] | = 0x04 ; /* reg 8, 2:1 scale down */
/* fall thru */
case 352 :
data [ 3 ] = 0x2c ; /* reg 2, H size */
data [ 4 ] = 0x48 ; /* reg 3, V size */
data [ 6 ] = 0x94 ; /* reg 5, H start */
data [ 8 ] = 0x63 ; /* reg 7, V start */
if ( sd - > do_lcd_stop )
data [ 8 ] = 0x64 ; /* Bayer tile shifted */
break ;
}
err_code = mr_write ( gspca_dev , 11 ) ;
2009-01-16 05:36:14 -03:00
if ( err_code < 0 )
return err_code ;
2009-08-14 06:51:52 -03:00
if ( ! sd - > sensor_type ) {
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data vga_sensor0_init_data [ ] = {
2009-08-14 06:51:52 -03:00
{ 0x01 , 0x00 , { 0x0c , 0x00 , 0x04 } , 3 } ,
{ 0x14 , 0x00 , { 0x01 , 0xe4 , 0x02 , 0x84 } , 4 } ,
{ 0x20 , 0x00 , { 0x00 , 0x80 , 0x00 , 0x08 } , 4 } ,
{ 0x25 , 0x00 , { 0x03 , 0xa9 , 0x80 } , 3 } ,
{ 0x30 , 0x00 , { 0x30 , 0x18 , 0x10 , 0x18 } , 4 } ,
{ 0 , 0 , { 0 } , 0 }
} ;
err_code = sensor_write_regs ( gspca_dev , vga_sensor0_init_data ,
ARRAY_SIZE ( vga_sensor0_init_data ) ) ;
2010-02-09 18:05:25 -03:00
} else if ( sd - > sensor_type = = 1 ) {
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data color_adj [ ] = {
2009-10-30 04:43:39 -03:00
{ 0x02 , 0x00 , { 0x06 , 0x59 , 0x0c , 0x16 , 0x00 ,
/* adjusted blue, green, red gain correct
too much blue from the Sakar Digital */
2009-11-01 13:02:59 -03:00
0x05 , 0x01 , 0x04 } , 8 }
2009-10-30 04:43:39 -03:00
} ;
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data color_no_adj [ ] = {
2009-08-14 06:51:52 -03:00
{ 0x02 , 0x00 , { 0x06 , 0x59 , 0x0c , 0x16 , 0x00 ,
2009-10-30 04:43:39 -03:00
/* default blue, green, red gain settings */
0x07 , 0x00 , 0x01 } , 8 }
} ;
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data vga_sensor1_init_data [ ] = {
2009-08-14 06:51:52 -03:00
{ 0x11 , 0x04 , { 0x01 } , 1 } ,
2009-11-01 13:09:15 -03:00
{ 0x0a , 0x00 , { 0x00 , 0x01 , 0x00 , 0x00 , 0x01 ,
/* These settings may be better for some cameras */
/* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */
2009-08-14 06:51:52 -03:00
0x00 , 0x0a } , 7 } ,
{ 0x11 , 0x04 , { 0x01 } , 1 } ,
{ 0x12 , 0x00 , { 0x00 , 0x63 , 0x00 , 0x70 , 0x00 , 0x00 } , 6 } ,
{ 0x11 , 0x04 , { 0x01 } , 1 } ,
{ 0 , 0 , { 0 } , 0 }
} ;
2009-10-30 04:43:39 -03:00
if ( sd - > adj_colors )
err_code = sensor_write_regs ( gspca_dev , color_adj ,
ARRAY_SIZE ( color_adj ) ) ;
else
err_code = sensor_write_regs ( gspca_dev , color_no_adj ,
ARRAY_SIZE ( color_no_adj ) ) ;
if ( err_code < 0 )
return err_code ;
2009-08-14 06:51:52 -03:00
err_code = sensor_write_regs ( gspca_dev , vga_sensor1_init_data ,
ARRAY_SIZE ( vga_sensor1_init_data ) ) ;
2010-02-09 18:05:25 -03:00
} else { /* sensor type == 2 */
2010-10-01 07:37:15 -03:00
static const struct sensor_w_data vga_sensor2_init_data [ ] = {
2010-02-09 18:05:25 -03:00
{ 0x01 , 0x00 , { 0x48 } , 1 } ,
{ 0x02 , 0x00 , { 0x22 } , 1 } ,
/* Reg 3 msb and 4 is lsb of the exposure setting*/
{ 0x05 , 0x00 , { 0x10 } , 1 } ,
{ 0x06 , 0x00 , { 0x00 } , 1 } ,
{ 0x07 , 0x00 , { 0x00 } , 1 } ,
{ 0x08 , 0x00 , { 0x00 } , 1 } ,
{ 0x09 , 0x00 , { 0x00 } , 1 } ,
/* The following are used in the gain control
* which is BTW completely borked in the OEM driver
* The values for each color go from 0 to 0x7ff
* { 0x0a , 0x00 , { 0x01 } , 1 } , green1 gain msb
* { 0x0b , 0x00 , { 0x10 } , 1 } , green1 gain lsb
* { 0x0c , 0x00 , { 0x01 } , 1 } , red gain msb
* { 0x0d , 0x00 , { 0x10 } , 1 } , red gain lsb
* { 0x0e , 0x00 , { 0x01 } , 1 } , blue gain msb
* { 0x0f , 0x00 , { 0x10 } , 1 } , blue gain lsb
* { 0x10 , 0x00 , { 0x01 } , 1 } , green2 gain msb
* { 0x11 , 0x00 , { 0x10 } , 1 } , green2 gain lsb
*/
{ 0x12 , 0x00 , { 0x00 } , 1 } ,
{ 0x13 , 0x00 , { 0x04 } , 1 } , /* weird effect on colors */
{ 0x14 , 0x00 , { 0x00 } , 1 } ,
{ 0x15 , 0x00 , { 0x06 } , 1 } ,
{ 0x16 , 0x00 , { 0x01 } , 1 } ,
{ 0x17 , 0x00 , { 0xe2 } , 1 } , /* vertical alignment */
{ 0x18 , 0x00 , { 0x02 } , 1 } ,
{ 0x19 , 0x00 , { 0x82 } , 1 } , /* don't mess with */
{ 0x1a , 0x00 , { 0x00 } , 1 } ,
{ 0x1b , 0x00 , { 0x20 } , 1 } ,
/* {0x1c, 0x00, {0x17}, 1}, contrast control */
{ 0x1d , 0x00 , { 0x80 } , 1 } , /* moving causes a mess */
{ 0x1e , 0x00 , { 0x08 } , 1 } , /* moving jams the camera */
{ 0x1f , 0x00 , { 0x0c } , 1 } ,
{ 0x20 , 0x00 , { 0x00 } , 1 } ,
{ 0 , 0 , { 0 } , 0 }
} ;
err_code = sensor_write_regs ( gspca_dev , vga_sensor2_init_data ,
ARRAY_SIZE ( vga_sensor2_init_data ) ) ;
2009-08-14 06:51:52 -03:00
}
return err_code ;
}
static int sd_start ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int err_code ;
sd - > sof_read = 0 ;
2009-10-05 05:11:35 -03:00
/* Some of the VGA cameras require the memory pointer
* to be set to 0 again . We have been forced to start the
2009-11-01 13:07:08 -03:00
* stream in sd_config ( ) to detect the hardware , and closed it .
* Thus , we need here to do a completely fresh and clean start . */
2009-10-05 05:11:35 -03:00
err_code = zero_the_pointer ( gspca_dev ) ;
if ( err_code < 0 )
return err_code ;
err_code = stream_start ( gspca_dev ) ;
if ( err_code < 0 )
return err_code ;
2009-08-14 06:51:52 -03:00
if ( sd - > cam_type = = CAM_TYPE_CIF ) {
err_code = start_cif_cam ( gspca_dev ) ;
} else {
err_code = start_vga_cam ( gspca_dev ) ;
}
2009-10-05 05:11:35 -03:00
if ( err_code < 0 )
return err_code ;
return isoc_enable ( gspca_dev ) ;
2009-01-16 05:36:14 -03:00
}
static void sd_stopN ( struct gspca_dev * gspca_dev )
{
2009-08-14 06:51:52 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-10-05 05:11:35 -03:00
stream_stop ( gspca_dev ) ;
2009-08-14 06:51:52 -03:00
/* Not all the cams need this, but even if not, probably a good idea */
zero_the_pointer ( gspca_dev ) ;
2009-10-05 05:11:35 -03:00
if ( sd - > do_lcd_stop )
lcd_stop ( gspca_dev ) ;
2009-08-14 06:51:52 -03:00
}
2012-05-14 09:45:06 -03:00
static void setbrightness ( struct gspca_dev * gspca_dev , s32 val )
2009-08-14 06:51:52 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-10-05 05:11:35 -03:00
u8 sign_reg = 7 ; /* This reg and the next one used on CIF cams. */
u8 value_reg = 8 ; /* VGA cams seem to use regs 0x0b and 0x0c */
2010-10-01 07:37:15 -03:00
static const u8 quick_clix_table [ ] =
2009-10-05 05:11:35 -03:00
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
{ 0 , 4 , 8 , 12 , 1 , 2 , 3 , 5 , 6 , 9 , 7 , 10 , 13 , 11 , 14 , 15 } ;
if ( sd - > cam_type = = CAM_TYPE_VGA ) {
sign_reg + = 4 ;
value_reg + = 4 ;
}
2009-11-01 13:07:08 -03:00
/* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
2012-05-14 09:45:06 -03:00
if ( val > 0 ) {
2009-10-05 05:11:35 -03:00
sensor_write1 ( gspca_dev , sign_reg , 0x00 ) ;
2009-08-14 06:51:52 -03:00
} else {
2009-10-05 05:11:35 -03:00
sensor_write1 ( gspca_dev , sign_reg , 0x01 ) ;
2012-05-14 09:45:06 -03:00
val = 257 - val ;
2009-08-14 06:51:52 -03:00
}
2009-10-05 05:11:35 -03:00
/* Use lookup table for funky Argus QuickClix brightness */
if ( sd - > do_lcd_stop )
val = quick_clix_table [ val ] ;
sensor_write1 ( gspca_dev , value_reg , val ) ;
2009-08-14 06:51:52 -03:00
}
2012-05-14 09:45:06 -03:00
static void setexposure ( struct gspca_dev * gspca_dev , s32 expo , s32 min_clockdiv )
2009-08-14 06:51:52 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-09 18:05:25 -03:00
int exposure = MR97310A_EXPOSURE_DEFAULT ;
2009-10-29 07:42:30 -03:00
u8 buf [ 2 ] ;
2009-08-14 06:51:52 -03:00
2009-10-05 05:11:35 -03:00
if ( sd - > cam_type = = CAM_TYPE_CIF & & sd - > sensor_type = = 1 ) {
2009-11-01 13:07:08 -03:00
/* This cam does not like exposure settings < 300,
2009-10-11 05:22:29 -03:00
so scale 0 - 4095 to 300 - 4095 */
2012-05-14 09:45:06 -03:00
exposure = ( expo * 9267 ) / 10000 + 300 ;
2009-10-05 05:11:35 -03:00
sensor_write1 ( gspca_dev , 3 , exposure > > 4 ) ;
sensor_write1 ( gspca_dev , 4 , exposure & 0x0f ) ;
2010-02-09 18:05:25 -03:00
} else if ( sd - > sensor_type = = 2 ) {
2012-05-14 09:45:06 -03:00
exposure = expo ;
2010-02-09 18:05:25 -03:00
exposure > > = 3 ;
sensor_write1 ( gspca_dev , 3 , exposure > > 8 ) ;
sensor_write1 ( gspca_dev , 4 , exposure & 0xff ) ;
2009-08-14 17:11:36 -03:00
} else {
/* We have both a clock divider and an exposure register.
We first calculate the clock divider , as that determines
2009-11-01 13:07:08 -03:00
the maximum exposure and then we calculate the exposure
2009-08-14 17:11:36 -03:00
register setting ( which goes from 0 - 511 ) .
Note our 0 - 4095 exposure is mapped to 0 - 511
milliseconds exposure time */
2012-05-14 09:45:06 -03:00
u8 clockdiv = ( 60 * expo + 7999 ) / 8000 ;
2009-08-14 17:11:36 -03:00
/* Limit framerate to not exceed usb bandwidth */
2013-08-30 17:54:23 -03:00
if ( clockdiv < min_clockdiv & & gspca_dev - > pixfmt . width > = 320 )
2012-05-14 09:45:06 -03:00
clockdiv = min_clockdiv ;
2009-08-14 17:11:36 -03:00
else if ( clockdiv < 2 )
clockdiv = 2 ;
2009-10-05 05:11:35 -03:00
if ( sd - > cam_type = = CAM_TYPE_VGA & & clockdiv < 4 )
clockdiv = 4 ;
2009-08-14 17:11:36 -03:00
/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
exposure = ( sd - > exposure / 8 ) * 511 / ( 1000 * clockdiv / 60 ) */
2012-05-14 09:45:06 -03:00
exposure = ( 60 * 511 * expo ) / ( 8000 * clockdiv ) ;
2009-08-14 17:11:36 -03:00
if ( exposure > 511 )
exposure = 511 ;
/* exposure register value is reversed! */
exposure = 511 - exposure ;
2009-10-29 07:42:30 -03:00
buf [ 0 ] = exposure & 0xff ;
buf [ 1 ] = exposure > > 8 ;
sensor_write_reg ( gspca_dev , 0x0e , 0 , buf , 2 ) ;
2009-08-14 17:11:36 -03:00
sensor_write1 ( gspca_dev , 0x02 , clockdiv ) ;
}
2009-08-14 06:51:52 -03:00
}
2012-05-14 09:45:06 -03:00
static void setgain ( struct gspca_dev * gspca_dev , s32 val )
2009-08-14 06:51:52 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-09 18:05:25 -03:00
u8 gainreg ;
2009-08-14 06:51:52 -03:00
2010-02-09 18:05:25 -03:00
if ( sd - > cam_type = = CAM_TYPE_CIF & & sd - > sensor_type = = 1 )
2012-05-14 09:45:06 -03:00
sensor_write1 ( gspca_dev , 0x0e , val ) ;
2010-02-09 18:05:25 -03:00
else if ( sd - > cam_type = = CAM_TYPE_VGA & & sd - > sensor_type = = 2 )
for ( gainreg = 0x0a ; gainreg < 0x11 ; gainreg + = 2 ) {
2012-05-14 09:45:06 -03:00
sensor_write1 ( gspca_dev , gainreg , val > > 8 ) ;
sensor_write1 ( gspca_dev , gainreg + 1 , val & 0xff ) ;
2010-02-09 18:05:25 -03:00
}
else
2012-05-14 09:45:06 -03:00
sensor_write1 ( gspca_dev , 0x10 , val ) ;
2009-08-14 06:51:52 -03:00
}
2012-05-14 09:45:06 -03:00
static void setcontrast ( struct gspca_dev * gspca_dev , s32 val )
2009-08-14 06:51:52 -03:00
{
2012-05-14 09:45:06 -03:00
sensor_write1 ( gspca_dev , 0x1c , val ) ;
2009-08-14 06:51:52 -03:00
}
2012-05-14 09:45:06 -03:00
static int sd_s_ctrl ( struct v4l2_ctrl * ctrl )
2009-08-14 06:51:52 -03:00
{
2012-05-14 09:45:06 -03:00
struct gspca_dev * gspca_dev =
container_of ( ctrl - > handler , struct gspca_dev , ctrl_handler ) ;
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-08-14 06:51:52 -03:00
2012-05-14 09:45:06 -03:00
gspca_dev - > usb_err = 0 ;
2009-08-14 06:51:52 -03:00
2012-05-14 09:45:06 -03:00
if ( ! gspca_dev - > streaming )
return 0 ;
2009-01-16 05:36:14 -03:00
2012-05-14 09:45:06 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
setbrightness ( gspca_dev , ctrl - > val ) ;
break ;
case V4L2_CID_CONTRAST :
setcontrast ( gspca_dev , ctrl - > val ) ;
break ;
case V4L2_CID_EXPOSURE :
setexposure ( gspca_dev , sd - > exposure - > val ,
sd - > min_clockdiv ? sd - > min_clockdiv - > val : 0 ) ;
break ;
case V4L2_CID_GAIN :
setgain ( gspca_dev , ctrl - > val ) ;
break ;
}
return gspca_dev - > usb_err ;
2010-02-09 18:05:25 -03:00
}
2012-05-14 09:45:06 -03:00
static const struct v4l2_ctrl_ops sd_ctrl_ops = {
. s_ctrl = sd_s_ctrl ,
} ;
2010-02-09 18:05:25 -03:00
2012-05-14 09:45:06 -03:00
static int sd_init_controls ( struct gspca_dev * gspca_dev )
2009-10-29 07:42:30 -03:00
{
2012-05-14 09:45:06 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
struct v4l2_ctrl_handler * hdl = & gspca_dev - > ctrl_handler ;
static const struct v4l2_ctrl_config clockdiv = {
. ops = & sd_ctrl_ops ,
. id = MR97310A_CID_CLOCKDIV ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Minimum Clock Divider " ,
. min = MR97310A_MIN_CLOCKDIV_MIN ,
. max = MR97310A_MIN_CLOCKDIV_MAX ,
. step = 1 ,
. def = MR97310A_MIN_CLOCKDIV_DEFAULT ,
} ;
bool has_brightness = false ;
bool has_argus_brightness = false ;
bool has_contrast = false ;
bool has_gain = false ;
bool has_cs_gain = false ;
bool has_exposure = false ;
bool has_clockdiv = false ;
2009-10-29 07:42:30 -03:00
2012-05-14 09:45:06 -03:00
gspca_dev - > vdev . ctrl_handler = hdl ;
v4l2_ctrl_handler_init ( hdl , 4 ) ;
2009-10-29 07:42:30 -03:00
2012-05-14 09:45:06 -03:00
/* Setup controls depending on camera type */
if ( sd - > cam_type = = CAM_TYPE_CIF ) {
/* No brightness for sensor_type 0 */
if ( sd - > sensor_type = = 0 )
has_exposure = has_gain = has_clockdiv = true ;
else
has_exposure = has_gain = has_brightness = true ;
} else {
/* All controls need to be disabled if VGA sensor_type is 0 */
if ( sd - > sensor_type = = 0 )
; /* no controls! */
else if ( sd - > sensor_type = = 2 )
has_exposure = has_cs_gain = has_contrast = true ;
else if ( sd - > do_lcd_stop )
has_exposure = has_gain = has_argus_brightness =
has_clockdiv = true ;
else
has_exposure = has_gain = has_brightness =
has_clockdiv = true ;
}
2009-10-29 07:42:30 -03:00
2012-05-14 09:45:06 -03:00
/* Separate brightness control description for Argus QuickClix as it has
* different limits from the other mr97310a cameras , and separate gain
* control for Sakar CyberPix camera . */
/*
* This control is disabled for CIF type 1 and VGA type 0 cameras .
* It does not quite act linearly for the Argus QuickClix camera ,
* but it does control brightness . The values are 0 - 15 only , and
* the table above makes them act consecutively .
*/
if ( has_brightness )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_BRIGHTNESS , - 254 , 255 , 1 ,
MR97310A_BRIGHTNESS_DEFAULT ) ;
else if ( has_argus_brightness )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_BRIGHTNESS , 0 , 15 , 1 ,
MR97310A_BRIGHTNESS_DEFAULT ) ;
if ( has_contrast )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_CONTRAST , MR97310A_CONTRAST_MIN ,
MR97310A_CONTRAST_MAX , 1 , MR97310A_CONTRAST_DEFAULT ) ;
if ( has_gain )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_GAIN , MR97310A_GAIN_MIN , MR97310A_GAIN_MAX ,
1 , MR97310A_GAIN_DEFAULT ) ;
else if ( has_cs_gain )
v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops , V4L2_CID_GAIN ,
MR97310A_CS_GAIN_MIN , MR97310A_CS_GAIN_MAX ,
1 , MR97310A_CS_GAIN_DEFAULT ) ;
if ( has_exposure )
sd - > exposure = v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_EXPOSURE , MR97310A_EXPOSURE_MIN ,
MR97310A_EXPOSURE_MAX , 1 , MR97310A_EXPOSURE_DEFAULT ) ;
if ( has_clockdiv )
sd - > min_clockdiv = v4l2_ctrl_new_custom ( hdl , & clockdiv , NULL ) ;
if ( hdl - > error ) {
pr_err ( " Could not initialize controls \n " ) ;
return hdl - > error ;
}
if ( has_exposure & & has_clockdiv )
v4l2_ctrl_cluster ( 2 , & sd - > exposure ) ;
2009-10-29 07:42:30 -03:00
return 0 ;
}
2009-01-16 05:36:14 -03:00
/* Include pac common sof detection functions */
# include "pac_common.h"
static void sd_pkt_scan ( struct gspca_dev * gspca_dev ,
2009-11-13 09:21:03 -03:00
u8 * data , /* isoc packet */
int len ) /* iso packet length */
2009-01-16 05:36:14 -03:00
{
2009-11-02 08:05:51 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-16 05:36:14 -03:00
unsigned char * sof ;
2013-02-04 13:17:55 -03:00
sof = pac_find_sof ( gspca_dev , & sd - > sof_read , data , len ) ;
2009-01-16 05:36:14 -03:00
if ( sof ) {
int n ;
/* finish decoding current frame */
n = sof - data ;
if ( n > sizeof pac_sof_marker )
n - = sizeof pac_sof_marker ;
else
n = 0 ;
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , LAST_PACKET ,
2009-01-16 05:36:14 -03:00
data , n ) ;
2009-03-13 13:04:31 -03:00
/* Start next frame. */
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , FIRST_PACKET ,
2009-03-13 13:04:31 -03:00
pac_sof_marker , sizeof pac_sof_marker ) ;
2009-01-16 05:36:14 -03:00
len - = sof - data ;
data = sof ;
}
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , INTER_PACKET , data , len ) ;
2009-01-16 05:36:14 -03:00
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
. name = MODULE_NAME ,
. config = sd_config ,
. init = sd_init ,
2012-05-14 09:45:06 -03:00
. init_controls = sd_init_controls ,
2009-01-16 05:36:14 -03:00
. start = sd_start ,
. stopN = sd_stopN ,
. pkt_scan = sd_pkt_scan ,
} ;
/* -- module initialisation -- */
2011-01-13 05:20:29 -03:00
static const struct usb_device_id device_table [ ] = {
2009-10-29 07:45:24 -03:00
{ USB_DEVICE ( 0x08ca , 0x0110 ) } , /* Trust Spyc@m 100 */
2009-08-14 06:51:52 -03:00
{ USB_DEVICE ( 0x08ca , 0x0111 ) } , /* Aiptek Pencam VGA+ */
{ USB_DEVICE ( 0x093a , 0x010f ) } , /* All other known MR97310A VGA cams */
{ USB_DEVICE ( 0x093a , 0x010e ) } , /* All known MR97310A CIF cams */
2009-01-16 05:36:14 -03:00
{ }
} ;
MODULE_DEVICE_TABLE ( usb , device_table ) ;
/* -- device connect -- */
static int sd_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
return gspca_dev_probe ( intf , id , & sd_desc , sizeof ( struct sd ) ,
THIS_MODULE ) ;
}
static struct usb_driver sd_driver = {
. name = MODULE_NAME ,
. id_table = device_table ,
. probe = sd_probe ,
. disconnect = gspca_disconnect ,
# ifdef CONFIG_PM
. suspend = gspca_suspend ,
. resume = gspca_resume ,
2012-06-30 06:44:47 -03:00
. reset_resume = gspca_resume ,
2009-01-16 05:36:14 -03:00
# endif
} ;
2011-11-18 09:46:12 -08:00
module_usb_driver ( sd_driver ) ;