2008-11-22 05:23:39 -03:00
/*
2010-01-07 05:18:16 -03:00
* ov534 - ov772x gspca driver
2009-11-11 07:46:28 -03:00
*
2008-11-22 05:23:39 -03:00
* Copyright ( C ) 2008 Antonio Ospite < ospite @ studenti . unina . it >
2008-12-10 05:45:14 -03:00
* Copyright ( C ) 2008 Jim Paris < jim @ jtan . com >
2009-03-19 06:15:21 -03:00
* Copyright ( C ) 2009 Jean - Francois Moine http : //moinejf.free.fr
2008-11-22 05:23:39 -03:00
*
* Based on a prototype written by Mark Ferrell < majortrips @ gmail . com >
* USB protocol reverse engineered by Jim Paris < jim @ jtan . com >
* https : //jim.sh/svn/jim/devl/playstation/ps3/eye/test/
*
2009-11-11 07:46:28 -03:00
* PS3 Eye camera enhanced by Richard Kaswy http : //kaswy.free.fr
2009-11-11 14:28:53 -03:00
* PS3 Eye camera , brightness , contrast , hue , AWB control added
* by Max Thrun < bear24rw @ gmail . com >
2009-11-11 07:46:28 -03:00
*
2008-11-22 05:23:39 -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 .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# define MODULE_NAME "ov534"
# include "gspca.h"
2009-03-19 06:15:21 -03:00
# define OV534_REG_ADDRESS 0xf1 /* sensor address */
2008-11-22 05:23:39 -03:00
# define OV534_REG_SUBADDR 0xf2
# define OV534_REG_WRITE 0xf3
# define OV534_REG_READ 0xf4
# define OV534_REG_OPERATION 0xf5
# define OV534_REG_STATUS 0xf6
# define OV534_OP_WRITE_3 0x37
# define OV534_OP_WRITE_2 0x33
# define OV534_OP_READ_2 0xf9
# define CTRL_TIMEOUT 500
MODULE_AUTHOR ( " Antonio Ospite <ospite@studenti.unina.it> " ) ;
MODULE_DESCRIPTION ( " GSPCA/OV534 USB Camera Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev ; /* !! must be the first item */
2008-12-04 05:06:08 -03:00
__u32 last_pts ;
2009-03-19 06:12:59 -03:00
u16 last_fid ;
u8 frame_rate ;
2009-11-11 14:28:53 -03:00
u8 brightness ;
u8 contrast ;
2009-11-11 07:46:28 -03:00
u8 gain ;
u8 exposure ;
2010-02-27 17:20:20 -03:00
u8 agc ;
2009-11-11 14:28:53 -03:00
u8 awb ;
2010-02-27 17:20:21 -03:00
u8 aec ;
2009-11-24 05:22:05 -03:00
s8 sharpness ;
2009-11-11 07:46:28 -03:00
u8 hflip ;
u8 vflip ;
2009-03-19 06:15:21 -03:00
2008-11-22 05:23:39 -03:00
} ;
/* V4L2 controls supported by the driver */
2009-11-11 07:46:28 -03:00
static int sd_setgain ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getgain ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int sd_setexposure ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getexposure ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2010-02-27 17:20:20 -03:00
static int sd_setagc ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getagc ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2009-11-11 07:46:28 -03:00
static int sd_setsharpness ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getsharpness ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int sd_sethflip ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_gethflip ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int sd_setvflip ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getvflip ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2009-11-11 14:28:53 -03:00
static int sd_setawb ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getawb ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2010-02-27 17:20:21 -03:00
static int sd_setaec ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getaec ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2009-11-11 14:28:53 -03:00
static int sd_setbrightness ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getbrightness ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int sd_setcontrast ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int sd_getcontrast ( struct gspca_dev * gspca_dev , __s32 * val ) ;
2009-11-11 07:46:28 -03:00
2010-01-07 05:18:16 -03:00
static const struct ctrl sd_ctrls [ ] = {
2010-03-01 08:54:33 -03:00
{ /* 0 */
{
. id = V4L2_CID_BRIGHTNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Brightness " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
2010-02-27 17:20:20 -03:00
# define BRIGHTNESS_DEF 0
2010-03-01 08:54:33 -03:00
. default_value = BRIGHTNESS_DEF ,
} ,
. set = sd_setbrightness ,
. get = sd_getbrightness ,
2009-11-11 14:28:53 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 1 */
{
. id = V4L2_CID_CONTRAST ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Contrast " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
2010-02-27 17:20:20 -03:00
# define CONTRAST_DEF 32
2010-03-01 08:54:33 -03:00
. default_value = CONTRAST_DEF ,
} ,
. set = sd_setcontrast ,
. get = sd_getcontrast ,
2009-11-11 14:28:53 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 2 */
{
. id = V4L2_CID_GAIN ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Main Gain " ,
. minimum = 0 ,
. maximum = 63 ,
. step = 1 ,
2009-11-11 07:46:28 -03:00
# define GAIN_DEF 20
2010-03-01 08:54:33 -03:00
. default_value = GAIN_DEF ,
} ,
. set = sd_setgain ,
. get = sd_getgain ,
2009-11-11 07:46:28 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 3 */
{
. id = V4L2_CID_EXPOSURE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Exposure " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
2010-01-07 05:18:16 -03:00
# define EXPO_DEF 120
2010-03-01 08:54:33 -03:00
. default_value = EXPO_DEF ,
} ,
. set = sd_setexposure ,
. get = sd_getexposure ,
2009-11-11 07:46:28 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 4 */
{
. id = V4L2_CID_AUTOGAIN ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " Auto Gain " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
2010-02-27 17:20:20 -03:00
# define AGC_DEF 1
2010-03-01 08:54:33 -03:00
. default_value = AGC_DEF ,
} ,
. set = sd_setagc ,
. get = sd_getagc ,
2009-11-11 07:46:28 -03:00
} ,
2010-02-27 17:20:19 -03:00
# define AWB_IDX 5
2010-03-01 08:54:33 -03:00
{ /* 5 */
{
. id = V4L2_CID_AUTO_WHITE_BALANCE ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " Auto White Balance " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
2010-02-27 17:20:23 -03:00
# define AWB_DEF 1
2010-03-01 08:54:33 -03:00
. default_value = AWB_DEF ,
} ,
. set = sd_setawb ,
. get = sd_getawb ,
2009-11-11 14:28:53 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 6 */
{
. id = V4L2_CID_EXPOSURE_AUTO ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " Auto Exposure " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
2010-02-27 17:20:21 -03:00
# define AEC_DEF 1
2010-03-01 08:54:33 -03:00
. default_value = AEC_DEF ,
} ,
. set = sd_setaec ,
. get = sd_getaec ,
2010-02-27 17:20:21 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 7 */
{
. id = V4L2_CID_SHARPNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Sharpness " ,
. minimum = 0 ,
. maximum = 63 ,
. step = 1 ,
2010-01-07 05:18:16 -03:00
# define SHARPNESS_DEF 0
2010-03-01 08:54:33 -03:00
. default_value = SHARPNESS_DEF ,
} ,
. set = sd_setsharpness ,
. get = sd_getsharpness ,
2009-11-11 07:46:28 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 8 */
{
. id = V4L2_CID_HFLIP ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " HFlip " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
2009-11-11 07:46:28 -03:00
# define HFLIP_DEF 0
2010-03-01 08:54:33 -03:00
. default_value = HFLIP_DEF ,
} ,
. set = sd_sethflip ,
. get = sd_gethflip ,
2009-11-11 07:46:28 -03:00
} ,
2010-03-01 08:54:33 -03:00
{ /* 9 */
{
. id = V4L2_CID_VFLIP ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " VFlip " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
2009-11-11 07:46:28 -03:00
# define VFLIP_DEF 0
2010-03-01 08:54:33 -03:00
. default_value = VFLIP_DEF ,
} ,
. set = sd_setvflip ,
. get = sd_getvflip ,
2009-11-11 07:46:28 -03:00
} ,
} ;
2008-11-22 05:23:39 -03:00
2009-11-14 09:45:38 -03:00
static const struct v4l2_pix_format ov772x_mode [ ] = {
2009-11-11 07:46:28 -03:00
{ 320 , 240 , V4L2_PIX_FMT_YUYV , V4L2_FIELD_NONE ,
. bytesperline = 320 * 2 ,
. sizeimage = 320 * 240 * 2 ,
2009-11-11 14:28:53 -03:00
. colorspace = V4L2_COLORSPACE_SRGB ,
2009-11-11 07:46:28 -03:00
. priv = 1 } ,
2008-11-22 05:23:39 -03:00
{ 640 , 480 , V4L2_PIX_FMT_YUYV , V4L2_FIELD_NONE ,
. bytesperline = 640 * 2 ,
. sizeimage = 640 * 480 * 2 ,
2009-05-22 04:16:42 -03:00
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 0 } ,
} ;
2010-01-17 03:27:04 -03:00
static const u8 qvga_rates [ ] = { 125 , 100 , 75 , 60 , 50 , 40 , 30 } ;
static const u8 vga_rates [ ] = { 60 , 50 , 40 , 30 , 15 } ;
static const struct framerates ov772x_framerates [ ] = {
{ /* 320x240 */
. rates = qvga_rates ,
. nrates = ARRAY_SIZE ( qvga_rates ) ,
} ,
{ /* 640x480 */
. rates = vga_rates ,
. nrates = ARRAY_SIZE ( vga_rates ) ,
} ,
} ;
2010-01-07 05:18:16 -03:00
static const u8 bridge_init [ ] [ 2 ] = {
2008-12-04 04:28:27 -03:00
{ 0xc2 , 0x0c } ,
{ 0x88 , 0xf8 } ,
{ 0xc3 , 0x69 } ,
{ 0x89 , 0xff } ,
{ 0x76 , 0x03 } ,
{ 0x92 , 0x01 } ,
{ 0x93 , 0x18 } ,
{ 0x94 , 0x10 } ,
{ 0x95 , 0x10 } ,
{ 0xe2 , 0x00 } ,
{ 0xe7 , 0x3e } ,
{ 0x96 , 0x00 } ,
{ 0x97 , 0x20 } ,
{ 0x97 , 0x20 } ,
{ 0x97 , 0x20 } ,
{ 0x97 , 0x0a } ,
{ 0x97 , 0x3f } ,
{ 0x97 , 0x4a } ,
{ 0x97 , 0x20 } ,
{ 0x97 , 0x15 } ,
{ 0x97 , 0x0b } ,
{ 0x8e , 0x40 } ,
{ 0x1f , 0x81 } ,
{ 0x34 , 0x05 } ,
{ 0xe3 , 0x04 } ,
{ 0x88 , 0x00 } ,
{ 0x89 , 0x00 } ,
{ 0x76 , 0x00 } ,
{ 0xe7 , 0x2e } ,
{ 0x31 , 0xf9 } ,
{ 0x25 , 0x42 } ,
{ 0x21 , 0xf0 } ,
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
2008-12-10 05:45:14 -03:00
{ 0x1d , 0x02 } , /* payload size 0x0200 * 4 = 2048 bytes */
{ 0x1d , 0x00 } , /* payload size */
2009-11-11 07:46:28 -03:00
2008-12-04 04:36:14 -03:00
{ 0x1d , 0x02 } , /* frame size 0x025800 * 4 = 614400 */
{ 0x1d , 0x58 } , /* frame size */
{ 0x1d , 0x00 } , /* frame size */
2008-12-04 04:28:27 -03:00
2008-12-10 05:47:44 -03:00
{ 0x1c , 0x0a } ,
{ 0x1d , 0x08 } , /* turn on UVC header */
{ 0x1d , 0x0e } , /* .. */
2008-12-04 04:28:27 -03:00
{ 0x8d , 0x1c } ,
{ 0x8e , 0x80 } ,
{ 0xe5 , 0x04 } ,
{ 0xc0 , 0x50 } ,
{ 0xc1 , 0x3c } ,
{ 0xc2 , 0x0c } ,
} ;
2010-01-07 05:18:16 -03:00
static const u8 sensor_init [ ] [ 2 ] = {
2008-12-04 04:28:27 -03:00
{ 0x12 , 0x80 } ,
{ 0x11 , 0x01 } ,
2009-11-11 07:46:28 -03:00
/*fixme: better have a delay?*/
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
{ 0x11 , 0x01 } ,
2008-12-04 04:28:27 -03:00
{ 0x3d , 0x03 } ,
{ 0x17 , 0x26 } ,
{ 0x18 , 0xa0 } ,
{ 0x19 , 0x07 } ,
{ 0x1a , 0xf0 } ,
{ 0x32 , 0x00 } ,
{ 0x29 , 0xa0 } ,
{ 0x2c , 0xf0 } ,
{ 0x65 , 0x20 } ,
{ 0x11 , 0x01 } ,
{ 0x42 , 0x7f } ,
2009-11-11 14:28:53 -03:00
{ 0x63 , 0xaa } , /* AWB - was e0 */
2008-12-04 04:28:27 -03:00
{ 0x64 , 0xff } ,
{ 0x66 , 0x00 } ,
2009-11-11 14:28:53 -03:00
{ 0x13 , 0xf0 } , /* com8 */
2008-12-04 04:28:27 -03:00
{ 0x0d , 0x41 } ,
{ 0x0f , 0xc5 } ,
{ 0x14 , 0x11 } ,
{ 0x22 , 0x7f } ,
{ 0x23 , 0x03 } ,
{ 0x24 , 0x40 } ,
{ 0x25 , 0x30 } ,
{ 0x26 , 0xa1 } ,
{ 0x2a , 0x00 } ,
{ 0x2b , 0x00 } ,
{ 0x6b , 0xaa } ,
2009-11-11 14:28:53 -03:00
{ 0x13 , 0xff } , /* AWB */
2008-12-04 04:28:27 -03:00
{ 0x90 , 0x05 } ,
{ 0x91 , 0x01 } ,
{ 0x92 , 0x03 } ,
{ 0x93 , 0x00 } ,
{ 0x94 , 0x60 } ,
{ 0x95 , 0x3c } ,
{ 0x96 , 0x24 } ,
{ 0x97 , 0x1e } ,
{ 0x98 , 0x62 } ,
{ 0x99 , 0x80 } ,
{ 0x9a , 0x1e } ,
{ 0x9b , 0x08 } ,
{ 0x9c , 0x20 } ,
{ 0x9e , 0x81 } ,
{ 0xa6 , 0x04 } ,
{ 0x7e , 0x0c } ,
{ 0x7f , 0x16 } ,
{ 0x80 , 0x2a } ,
{ 0x81 , 0x4e } ,
{ 0x82 , 0x61 } ,
{ 0x83 , 0x6f } ,
{ 0x84 , 0x7b } ,
{ 0x85 , 0x86 } ,
{ 0x86 , 0x8e } ,
{ 0x87 , 0x97 } ,
{ 0x88 , 0xa4 } ,
{ 0x89 , 0xaf } ,
{ 0x8a , 0xc5 } ,
{ 0x8b , 0xd7 } ,
{ 0x8c , 0xe8 } ,
{ 0x8d , 0x20 } ,
{ 0x0c , 0x90 } ,
{ 0x2b , 0x00 } ,
{ 0x22 , 0x7f } ,
{ 0x23 , 0x03 } ,
{ 0x11 , 0x01 } ,
{ 0x0c , 0xd0 } ,
{ 0x64 , 0xff } ,
{ 0x0d , 0x41 } ,
{ 0x14 , 0x41 } ,
{ 0x0e , 0xcd } ,
{ 0xac , 0xbf } ,
2009-11-11 14:28:53 -03:00
{ 0x8e , 0x00 } , /* De-noise threshold */
2008-12-04 04:28:27 -03:00
{ 0x0c , 0xd0 }
} ;
2010-01-07 05:18:16 -03:00
static const u8 bridge_start_vga [ ] [ 2 ] = {
2009-11-11 07:46:28 -03:00
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
{ 0x1d , 0x02 } ,
{ 0x1d , 0x00 } ,
{ 0x1d , 0x02 } ,
{ 0x1d , 0x58 } ,
{ 0x1d , 0x00 } ,
{ 0xc0 , 0x50 } ,
{ 0xc1 , 0x3c } ,
} ;
2010-01-07 05:18:16 -03:00
static const u8 sensor_start_vga [ ] [ 2 ] = {
2009-11-11 07:46:28 -03:00
{ 0x12 , 0x00 } ,
{ 0x17 , 0x26 } ,
{ 0x18 , 0xa0 } ,
{ 0x19 , 0x07 } ,
{ 0x1a , 0xf0 } ,
{ 0x29 , 0xa0 } ,
{ 0x2c , 0xf0 } ,
2009-11-11 14:28:53 -03:00
{ 0x65 , 0x20 } ,
2009-11-11 07:46:28 -03:00
} ;
2010-01-07 05:18:16 -03:00
static const u8 bridge_start_qvga [ ] [ 2 ] = {
2009-11-11 07:46:28 -03:00
{ 0x1c , 0x00 } ,
{ 0x1d , 0x40 } ,
{ 0x1d , 0x02 } ,
{ 0x1d , 0x00 } ,
{ 0x1d , 0x01 } ,
{ 0x1d , 0x4b } ,
{ 0x1d , 0x00 } ,
{ 0xc0 , 0x28 } ,
{ 0xc1 , 0x1e } ,
} ;
2010-01-07 05:18:16 -03:00
static const u8 sensor_start_qvga [ ] [ 2 ] = {
2009-11-11 07:46:28 -03:00
{ 0x12 , 0x40 } ,
{ 0x17 , 0x3f } ,
{ 0x18 , 0x50 } ,
{ 0x19 , 0x03 } ,
{ 0x1a , 0x78 } ,
{ 0x29 , 0x50 } ,
{ 0x2c , 0x78 } ,
2009-11-11 14:28:53 -03:00
{ 0x65 , 0x2f } ,
2009-11-11 07:46:28 -03:00
} ;
2008-11-22 05:23:39 -03:00
2009-03-19 06:15:21 -03:00
static void ov534_reg_write ( struct gspca_dev * gspca_dev , u16 reg , u8 val )
{
struct usb_device * udev = gspca_dev - > dev ;
int ret ;
PDEBUG ( D_USBO , " reg=0x%04x, val=0%02x " , reg , val ) ;
gspca_dev - > usb_buf [ 0 ] = val ;
ret = usb_control_msg ( udev ,
usb_sndctrlpipe ( udev , 0 ) ,
0x01 ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
0x00 , reg , gspca_dev - > usb_buf , 1 , CTRL_TIMEOUT ) ;
if ( ret < 0 )
PDEBUG ( D_ERR , " write failed " ) ;
}
static u8 ov534_reg_read ( struct gspca_dev * gspca_dev , u16 reg )
{
struct usb_device * udev = gspca_dev - > dev ;
int ret ;
ret = usb_control_msg ( udev ,
usb_rcvctrlpipe ( udev , 0 ) ,
0x01 ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
0x00 , reg , gspca_dev - > usb_buf , 1 , CTRL_TIMEOUT ) ;
PDEBUG ( D_USBI , " reg=0x%04x, data=0x%02x " , reg , gspca_dev - > usb_buf [ 0 ] ) ;
if ( ret < 0 )
PDEBUG ( D_ERR , " read failed " ) ;
return gspca_dev - > usb_buf [ 0 ] ;
}
/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
* ( direction and output ) ? */
static void ov534_set_led ( struct gspca_dev * gspca_dev , int status )
{
u8 data ;
PDEBUG ( D_CONF , " led status: %d " , status ) ;
data = ov534_reg_read ( gspca_dev , 0x21 ) ;
data | = 0x80 ;
ov534_reg_write ( gspca_dev , 0x21 , data ) ;
data = ov534_reg_read ( gspca_dev , 0x23 ) ;
if ( status )
data | = 0x80 ;
else
data & = ~ 0x80 ;
ov534_reg_write ( gspca_dev , 0x23 , data ) ;
if ( ! status ) {
data = ov534_reg_read ( gspca_dev , 0x21 ) ;
data & = ~ 0x80 ;
ov534_reg_write ( gspca_dev , 0x21 , data ) ;
}
}
static int sccb_check_status ( struct gspca_dev * gspca_dev )
{
u8 data ;
int i ;
for ( i = 0 ; i < 5 ; i + + ) {
data = ov534_reg_read ( gspca_dev , OV534_REG_STATUS ) ;
switch ( data ) {
case 0x00 :
return 1 ;
case 0x04 :
return 0 ;
case 0x03 :
break ;
default :
PDEBUG ( D_ERR , " sccb status 0x%02x, attempt %d/5 " ,
data , i + 1 ) ;
}
}
return 0 ;
}
static void sccb_reg_write ( struct gspca_dev * gspca_dev , u8 reg , u8 val )
{
PDEBUG ( D_USBO , " reg: 0x%02x, val: 0x%02x " , reg , val ) ;
ov534_reg_write ( gspca_dev , OV534_REG_SUBADDR , reg ) ;
ov534_reg_write ( gspca_dev , OV534_REG_WRITE , val ) ;
ov534_reg_write ( gspca_dev , OV534_REG_OPERATION , OV534_OP_WRITE_3 ) ;
if ( ! sccb_check_status ( gspca_dev ) )
PDEBUG ( D_ERR , " sccb_reg_write failed " ) ;
}
static u8 sccb_reg_read ( struct gspca_dev * gspca_dev , u16 reg )
{
ov534_reg_write ( gspca_dev , OV534_REG_SUBADDR , reg ) ;
ov534_reg_write ( gspca_dev , OV534_REG_OPERATION , OV534_OP_WRITE_2 ) ;
if ( ! sccb_check_status ( gspca_dev ) )
PDEBUG ( D_ERR , " sccb_reg_read failed 1 " ) ;
ov534_reg_write ( gspca_dev , OV534_REG_OPERATION , OV534_OP_READ_2 ) ;
if ( ! sccb_check_status ( gspca_dev ) )
PDEBUG ( D_ERR , " sccb_reg_read failed 2 " ) ;
return ov534_reg_read ( gspca_dev , OV534_REG_READ ) ;
}
/* output a bridge sequence (reg - val) */
static void reg_w_array ( struct gspca_dev * gspca_dev ,
const u8 ( * data ) [ 2 ] , int len )
{
while ( - - len > = 0 ) {
ov534_reg_write ( gspca_dev , ( * data ) [ 0 ] , ( * data ) [ 1 ] ) ;
data + + ;
}
}
/* output a sensor sequence (reg - val) */
static void sccb_w_array ( struct gspca_dev * gspca_dev ,
const u8 ( * data ) [ 2 ] , int len )
{
while ( - - len > = 0 ) {
if ( ( * data ) [ 0 ] ! = 0xff ) {
sccb_reg_write ( gspca_dev , ( * data ) [ 0 ] , ( * data ) [ 1 ] ) ;
} else {
sccb_reg_read ( gspca_dev , ( * data ) [ 1 ] ) ;
sccb_reg_write ( gspca_dev , 0xff , 0x00 ) ;
}
data + + ;
}
}
2009-11-12 06:10:36 -03:00
/* ov772x specific controls */
static void set_frame_rate ( struct gspca_dev * gspca_dev )
2008-12-10 06:06:20 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-11-11 07:46:28 -03:00
int i ;
struct rate_s {
u8 fps ;
u8 r11 ;
u8 r0d ;
u8 re5 ;
} ;
const struct rate_s * r ;
static const struct rate_s rate_0 [ ] = { /* 640x480 */
{ 60 , 0x01 , 0xc1 , 0x04 } ,
{ 50 , 0x01 , 0x41 , 0x02 } ,
{ 40 , 0x02 , 0xc1 , 0x04 } ,
{ 30 , 0x04 , 0x81 , 0x02 } ,
{ 15 , 0x03 , 0x41 , 0x04 } ,
} ;
static const struct rate_s rate_1 [ ] = { /* 320x240 */
{ 125 , 0x02 , 0x81 , 0x02 } ,
{ 100 , 0x02 , 0xc1 , 0x04 } ,
{ 75 , 0x03 , 0xc1 , 0x04 } ,
{ 60 , 0x04 , 0xc1 , 0x04 } ,
{ 50 , 0x02 , 0x41 , 0x04 } ,
{ 40 , 0x03 , 0x41 , 0x04 } ,
{ 30 , 0x04 , 0x41 , 0x04 } ,
} ;
if ( gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv = = 0 ) {
r = rate_0 ;
i = ARRAY_SIZE ( rate_0 ) ;
} else {
r = rate_1 ;
i = ARRAY_SIZE ( rate_1 ) ;
}
while ( - - i > 0 ) {
if ( sd - > frame_rate > = r - > fps )
break ;
r + + ;
}
sccb_reg_write ( gspca_dev , 0x11 , r - > r11 ) ;
sccb_reg_write ( gspca_dev , 0x0d , r - > r0d ) ;
ov534_reg_write ( gspca_dev , 0xe5 , r - > re5 ) ;
PDEBUG ( D_PROBE , " frame_rate: %d " , r - > fps ) ;
}
2010-01-07 05:18:16 -03:00
static void setbrightness ( struct gspca_dev * gspca_dev )
2009-11-11 14:28:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-03-01 08:54:33 -03:00
sccb_reg_write ( gspca_dev , 0x9b , sd - > brightness ) ;
2009-11-11 14:28:53 -03:00
}
2010-01-07 05:18:16 -03:00
static void setcontrast ( struct gspca_dev * gspca_dev )
2009-11-11 14:28:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-03-01 08:54:33 -03:00
sccb_reg_write ( gspca_dev , 0x9c , sd - > contrast ) ;
2009-11-11 14:28:53 -03:00
}
2009-11-11 07:46:28 -03:00
static void setgain ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
u8 val ;
2008-12-10 06:06:20 -03:00
2010-02-27 17:20:20 -03:00
if ( sd - > agc )
return ;
2009-11-11 07:46:28 -03:00
val = sd - > gain ;
switch ( val & 0x30 ) {
case 0x00 :
val & = 0x0f ;
2008-12-10 06:06:20 -03:00
break ;
2009-11-11 07:46:28 -03:00
case 0x10 :
val & = 0x0f ;
val | = 0x30 ;
2008-12-10 06:06:20 -03:00
break ;
2009-11-11 07:46:28 -03:00
case 0x20 :
val & = 0x0f ;
val | = 0x70 ;
2008-12-10 06:06:20 -03:00
break ;
2009-11-11 07:46:28 -03:00
default :
/* case 0x30: */
val & = 0x0f ;
val | = 0xf0 ;
2008-12-10 06:06:20 -03:00
break ;
}
2009-11-11 07:46:28 -03:00
sccb_reg_write ( gspca_dev , 0x00 , val ) ;
}
2010-01-07 05:18:16 -03:00
static void setexposure ( struct gspca_dev * gspca_dev )
2009-11-11 07:46:28 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
u8 val ;
2010-03-01 08:53:34 -03:00
if ( sd - > aec )
return ;
/* 'val' is one byte and represents half of the exposure value we are
* going to set into registers , a two bytes value :
*
* MSB : ( ( u16 ) val < < 1 ) > > 8 = = val > > 7
* LSB : ( ( u16 ) val < < 1 ) & 0xff = = val < < 1
*/
2009-11-11 07:46:28 -03:00
val = sd - > exposure ;
sccb_reg_write ( gspca_dev , 0x08 , val > > 7 ) ;
sccb_reg_write ( gspca_dev , 0x10 , val < < 1 ) ;
}
2010-02-27 17:20:20 -03:00
static void setagc ( struct gspca_dev * gspca_dev )
2009-11-11 07:46:28 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-27 17:20:20 -03:00
if ( sd - > agc ) {
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) | 0x04 ) ;
2009-11-11 07:46:28 -03:00
sccb_reg_write ( gspca_dev , 0x64 ,
sccb_reg_read ( gspca_dev , 0x64 ) | 0x03 ) ;
} else {
2010-02-27 17:20:20 -03:00
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) & ~ 0x04 ) ;
2009-11-11 07:46:28 -03:00
sccb_reg_write ( gspca_dev , 0x64 ,
2010-02-27 17:20:20 -03:00
sccb_reg_read ( gspca_dev , 0x64 ) & ~ 0x03 ) ;
setgain ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
}
}
2009-11-11 14:28:53 -03:00
static void setawb ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-27 17:20:23 -03:00
if ( sd - > awb ) {
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) | 0x02 ) ;
sccb_reg_write ( gspca_dev , 0x63 ,
sccb_reg_read ( gspca_dev , 0x63 ) | 0xc0 ) ;
} else {
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) & ~ 0x02 ) ;
sccb_reg_write ( gspca_dev , 0x63 ,
sccb_reg_read ( gspca_dev , 0x63 ) & ~ 0xc0 ) ;
}
2009-11-11 14:28:53 -03:00
}
2010-02-27 17:20:21 -03:00
static void setaec ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( sd - > aec )
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) | 0x01 ) ;
else {
sccb_reg_write ( gspca_dev , 0x13 ,
sccb_reg_read ( gspca_dev , 0x13 ) & ~ 0x01 ) ;
setexposure ( gspca_dev ) ;
}
}
2010-01-07 05:18:16 -03:00
static void setsharpness ( struct gspca_dev * gspca_dev )
2009-11-11 07:46:28 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
u8 val ;
val = sd - > sharpness ;
2010-02-27 17:20:24 -03:00
sccb_reg_write ( gspca_dev , 0x91 , val ) ; /* Auto de-noise threshold */
sccb_reg_write ( gspca_dev , 0x8e , val ) ; /* De-noise threshold */
2009-11-11 07:46:28 -03:00
}
static void sethflip ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( sd - > hflip = = 0 )
sccb_reg_write ( gspca_dev , 0x0c ,
sccb_reg_read ( gspca_dev , 0x0c ) | 0x40 ) ;
else
sccb_reg_write ( gspca_dev , 0x0c ,
2010-02-27 17:20:25 -03:00
sccb_reg_read ( gspca_dev , 0x0c ) & ~ 0x40 ) ;
2009-11-11 07:46:28 -03:00
}
static void setvflip ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( sd - > vflip = = 0 )
sccb_reg_write ( gspca_dev , 0x0c ,
sccb_reg_read ( gspca_dev , 0x0c ) | 0x80 ) ;
else
sccb_reg_write ( gspca_dev , 0x0c ,
2010-02-27 17:20:25 -03:00
sccb_reg_read ( gspca_dev , 0x0c ) & ~ 0x80 ) ;
2008-12-10 06:06:20 -03:00
}
2008-11-22 05:23:39 -03:00
/* this function is called at probe time */
static int sd_config ( struct gspca_dev * gspca_dev ,
const struct usb_device_id * id )
{
2009-03-19 06:15:21 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2008-11-22 05:23:39 -03:00
struct cam * cam ;
cam = & gspca_dev - > cam ;
2010-01-07 05:18:16 -03:00
cam - > cam_mode = ov772x_mode ;
cam - > nmodes = ARRAY_SIZE ( ov772x_mode ) ;
2010-01-17 03:27:04 -03:00
cam - > mode_framerates = ov772x_framerates ;
2009-05-22 04:16:42 -03:00
2010-01-07 05:18:16 -03:00
cam - > bulk = 1 ;
cam - > bulk_size = 16384 ;
cam - > bulk_nurbs = 2 ;
2008-11-22 05:23:39 -03:00
2009-11-11 07:46:28 -03:00
sd - > frame_rate = 30 ;
2009-11-11 14:28:53 -03:00
2010-01-07 05:18:16 -03:00
sd - > brightness = BRIGHTNESS_DEF ;
sd - > contrast = CONTRAST_DEF ;
sd - > gain = GAIN_DEF ;
sd - > exposure = EXPO_DEF ;
2010-02-27 17:20:20 -03:00
# if AGC_DEF != 0
sd - > agc = AGC_DEF ;
2009-11-12 16:15:44 -03:00
# else
2010-01-07 05:18:16 -03:00
gspca_dev - > ctrl_inac | = ( 1 < < AWB_IDX ) ;
2009-11-11 14:28:53 -03:00
# endif
2010-02-27 17:20:23 -03:00
sd - > awb = AWB_DEF ;
2010-02-27 17:20:21 -03:00
sd - > aec = AEC_DEF ;
2010-01-07 05:18:16 -03:00
sd - > sharpness = SHARPNESS_DEF ;
sd - > hflip = HFLIP_DEF ;
sd - > vflip = VFLIP_DEF ;
2008-11-22 05:23:39 -03:00
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init ( struct gspca_dev * gspca_dev )
{
2009-03-19 06:15:21 -03:00
u16 sensor_id ;
/* reset bridge */
ov534_reg_write ( gspca_dev , 0xe7 , 0x3a ) ;
ov534_reg_write ( gspca_dev , 0xe0 , 0x08 ) ;
msleep ( 100 ) ;
/* initialize the sensor address */
2010-01-07 05:18:16 -03:00
ov534_reg_write ( gspca_dev , OV534_REG_ADDRESS , 0x42 ) ;
2009-03-19 06:15:21 -03:00
/* reset sensor */
sccb_reg_write ( gspca_dev , 0x12 , 0x80 ) ;
msleep ( 10 ) ;
/* probe the sensor */
sccb_reg_read ( gspca_dev , 0x0a ) ;
sensor_id = sccb_reg_read ( gspca_dev , 0x0a ) < < 8 ;
sccb_reg_read ( gspca_dev , 0x0b ) ;
sensor_id | = sccb_reg_read ( gspca_dev , 0x0b ) ;
PDEBUG ( D_PROBE , " Sensor ID: %04x " , sensor_id ) ;
/* initialize */
2010-01-07 05:18:16 -03:00
reg_w_array ( gspca_dev , bridge_init ,
ARRAY_SIZE ( bridge_init ) ) ;
ov534_set_led ( gspca_dev , 1 ) ;
sccb_w_array ( gspca_dev , sensor_init ,
ARRAY_SIZE ( sensor_init ) ) ;
ov534_reg_write ( gspca_dev , 0xe0 , 0x09 ) ;
ov534_set_led ( gspca_dev , 0 ) ;
set_frame_rate ( gspca_dev ) ;
2008-11-22 05:23:39 -03:00
return 0 ;
}
2010-01-07 05:18:16 -03:00
static int sd_start ( struct gspca_dev * gspca_dev )
2008-11-22 05:23:39 -03:00
{
2009-05-22 04:16:42 -03:00
int mode ;
2008-11-22 05:23:39 -03:00
2009-11-11 07:46:28 -03:00
mode = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv ;
if ( mode ! = 0 ) { /* 320x240 */
2010-01-07 05:18:16 -03:00
reg_w_array ( gspca_dev , bridge_start_qvga ,
ARRAY_SIZE ( bridge_start_qvga ) ) ;
sccb_w_array ( gspca_dev , sensor_start_qvga ,
ARRAY_SIZE ( sensor_start_qvga ) ) ;
2009-11-11 07:46:28 -03:00
} else { /* 640x480 */
2010-01-07 05:18:16 -03:00
reg_w_array ( gspca_dev , bridge_start_vga ,
ARRAY_SIZE ( bridge_start_vga ) ) ;
sccb_w_array ( gspca_dev , sensor_start_vga ,
ARRAY_SIZE ( sensor_start_vga ) ) ;
2009-03-19 06:15:21 -03:00
}
2009-11-12 06:10:36 -03:00
set_frame_rate ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
2010-02-27 17:20:20 -03:00
setagc ( gspca_dev ) ;
2009-11-11 14:28:53 -03:00
setawb ( gspca_dev ) ;
2010-02-27 17:20:21 -03:00
setaec ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
setgain ( gspca_dev ) ;
2010-01-07 05:18:16 -03:00
setexposure ( gspca_dev ) ;
setbrightness ( gspca_dev ) ;
setcontrast ( gspca_dev ) ;
setsharpness ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
setvflip ( gspca_dev ) ;
sethflip ( gspca_dev ) ;
ov534_set_led ( gspca_dev , 1 ) ;
ov534_reg_write ( gspca_dev , 0xe0 , 0x00 ) ;
2008-11-22 05:23:39 -03:00
return 0 ;
}
2010-01-07 05:18:16 -03:00
static void sd_stopN ( struct gspca_dev * gspca_dev )
2009-11-11 07:46:28 -03:00
{
ov534_reg_write ( gspca_dev , 0xe0 , 0x09 ) ;
ov534_set_led ( gspca_dev , 0 ) ;
}
2008-12-04 04:52:40 -03:00
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
# define UVC_STREAM_EOH (1 << 7)
# define UVC_STREAM_ERR (1 << 6)
# define UVC_STREAM_STI (1 << 5)
# define UVC_STREAM_RES (1 << 4)
# define UVC_STREAM_SCR (1 << 3)
# define UVC_STREAM_PTS (1 << 2)
# define UVC_STREAM_EOF (1 << 1)
# define UVC_STREAM_FID (1 << 0)
2009-11-13 09:21:03 -03:00
static void sd_pkt_scan ( struct gspca_dev * gspca_dev ,
u8 * data , int len )
2008-11-22 05:23:39 -03:00
{
2008-12-04 05:06:08 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2008-12-04 04:52:40 -03:00
__u32 this_pts ;
2009-03-19 06:12:59 -03:00
u16 this_fid ;
2008-12-10 05:45:14 -03:00
int remaining_len = len ;
2009-03-19 06:12:59 -03:00
do {
2010-01-07 05:18:16 -03:00
len = min ( remaining_len , 2048 ) ;
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* Payloads are prefixed with a UVC-style header. We
consider a frame to start when the FID toggles , or the PTS
changes . A frame ends when EOF is set , and we ' ve received
the correct number of bytes . */
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* Verify UVC header. Header length is always 12 */
if ( data [ 0 ] ! = 12 | | len < 12 ) {
PDEBUG ( D_PACK , " bad header " ) ;
goto discard ;
}
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* Check errors */
if ( data [ 1 ] & UVC_STREAM_ERR ) {
PDEBUG ( D_PACK , " payload error " ) ;
goto discard ;
}
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* Extract PTS and FID */
if ( ! ( data [ 1 ] & UVC_STREAM_PTS ) ) {
PDEBUG ( D_PACK , " PTS not present " ) ;
2008-12-04 04:52:40 -03:00
goto discard ;
}
2009-03-19 06:12:59 -03:00
this_pts = ( data [ 5 ] < < 24 ) | ( data [ 4 ] < < 16 )
| ( data [ 3 ] < < 8 ) | data [ 2 ] ;
this_fid = ( data [ 1 ] & UVC_STREAM_FID ) ? 1 : 0 ;
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* If PTS or FID has changed, start a new frame. */
if ( this_pts ! = sd - > last_pts | | this_fid ! = sd - > last_fid ) {
2009-04-23 13:52:27 -03:00
if ( gspca_dev - > last_packet_type = = INTER_PACKET )
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , LAST_PACKET ,
NULL , 0 ) ;
2009-03-19 06:12:59 -03:00
sd - > last_pts = this_pts ;
sd - > last_fid = this_fid ;
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , FIRST_PACKET ,
2009-03-19 06:12:59 -03:00
data + 12 , len - 12 ) ;
/* If this packet is marked as EOF, end the frame */
2009-04-23 13:52:27 -03:00
} else if ( data [ 1 ] & UVC_STREAM_EOF ) {
2010-01-07 05:18:16 -03:00
struct gspca_frame * frame ;
2009-03-19 06:12:59 -03:00
sd - > last_pts = 0 ;
2010-01-07 05:18:16 -03:00
frame = gspca_get_i_frame ( gspca_dev ) ;
if ( frame = = NULL )
goto discard ;
2010-01-17 03:42:14 -03:00
if ( frame - > data_end - frame - > data + ( len - 12 ) ! =
2010-01-07 05:18:16 -03:00
gspca_dev - > width * gspca_dev - > height * 2 ) {
2010-01-17 03:42:14 -03:00
PDEBUG ( D_PACK , " wrong sized frame " ) ;
2010-01-07 05:18:16 -03:00
goto discard ;
}
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , LAST_PACKET ,
data + 12 , len - 12 ) ;
2009-04-23 13:52:27 -03:00
} else {
/* Add the data from this payload */
2009-11-13 09:21:03 -03:00
gspca_frame_add ( gspca_dev , INTER_PACKET ,
data + 12 , len - 12 ) ;
2009-03-19 06:05:06 -03:00
}
2008-12-04 04:52:40 -03:00
2009-03-19 06:12:59 -03:00
/* Done this payload */
goto scan_next ;
2008-12-04 04:52:40 -03:00
discard :
2009-03-19 06:12:59 -03:00
/* Discard data until a new frame starts. */
2009-11-13 09:21:03 -03:00
gspca_dev - > last_packet_type = DISCARD_PACKET ;
2009-03-19 06:12:59 -03:00
scan_next :
remaining_len - = len ;
data + = len ;
} while ( remaining_len > 0 ) ;
2008-11-22 05:23:39 -03:00
}
2009-11-24 05:22:05 -03:00
/* controls */
2009-11-11 07:46:28 -03:00
static int sd_setgain ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > gain = val ;
if ( gspca_dev - > streaming )
setgain ( gspca_dev ) ;
return 0 ;
}
static int sd_getgain ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > gain ;
return 0 ;
}
static int sd_setexposure ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > exposure = val ;
2010-01-07 05:18:16 -03:00
if ( gspca_dev - > streaming )
setexposure ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
return 0 ;
}
static int sd_getexposure ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > exposure ;
return 0 ;
}
2009-11-11 14:28:53 -03:00
static int sd_setbrightness ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > brightness = val ;
2010-01-07 05:18:16 -03:00
if ( gspca_dev - > streaming )
setbrightness ( gspca_dev ) ;
2009-11-11 14:28:53 -03:00
return 0 ;
}
static int sd_getbrightness ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > brightness ;
return 0 ;
}
static int sd_setcontrast ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > contrast = val ;
2010-01-07 05:18:16 -03:00
if ( gspca_dev - > streaming )
setcontrast ( gspca_dev ) ;
2009-11-11 14:28:53 -03:00
return 0 ;
}
static int sd_getcontrast ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > contrast ;
return 0 ;
}
2010-02-27 17:20:20 -03:00
static int sd_setagc ( struct gspca_dev * gspca_dev , __s32 val )
2009-11-11 07:46:28 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-27 17:20:20 -03:00
sd - > agc = val ;
2009-11-12 16:15:44 -03:00
2009-11-24 05:22:05 -03:00
if ( gspca_dev - > streaming ) {
2010-01-07 05:18:16 -03:00
/* the auto white balance control works only
* when auto gain is set */
if ( val )
gspca_dev - > ctrl_inac & = ~ ( 1 < < AWB_IDX ) ;
else
gspca_dev - > ctrl_inac | = ( 1 < < AWB_IDX ) ;
2010-02-27 17:20:20 -03:00
setagc ( gspca_dev ) ;
2009-11-24 05:22:05 -03:00
}
2009-11-11 07:46:28 -03:00
return 0 ;
}
2010-02-27 17:20:20 -03:00
static int sd_getagc ( struct gspca_dev * gspca_dev , __s32 * val )
2009-11-11 07:46:28 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-02-27 17:20:20 -03:00
* val = sd - > agc ;
2009-11-11 07:46:28 -03:00
return 0 ;
}
2009-11-11 14:28:53 -03:00
static int sd_setawb ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > awb = val ;
if ( gspca_dev - > streaming )
setawb ( gspca_dev ) ;
return 0 ;
}
static int sd_getawb ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > awb ;
return 0 ;
}
2010-02-27 17:20:21 -03:00
static int sd_setaec ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > aec = val ;
if ( gspca_dev - > streaming )
setaec ( gspca_dev ) ;
return 0 ;
}
static int sd_getaec ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > aec ;
return 0 ;
}
2009-11-11 07:46:28 -03:00
static int sd_setsharpness ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > sharpness = val ;
2010-01-07 05:18:16 -03:00
if ( gspca_dev - > streaming )
setsharpness ( gspca_dev ) ;
2009-11-11 07:46:28 -03:00
return 0 ;
}
static int sd_getsharpness ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > sharpness ;
return 0 ;
}
static int sd_sethflip ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > hflip = val ;
if ( gspca_dev - > streaming )
sethflip ( gspca_dev ) ;
return 0 ;
}
static int sd_gethflip ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > hflip ;
return 0 ;
}
static int sd_setvflip ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > vflip = val ;
if ( gspca_dev - > streaming )
setvflip ( gspca_dev ) ;
return 0 ;
}
static int sd_getvflip ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
* val = sd - > vflip ;
return 0 ;
}
2008-12-10 06:06:20 -03:00
/* get stream parameters (framerate) */
2008-12-21 15:02:54 -03:00
static int sd_get_streamparm ( struct gspca_dev * gspca_dev ,
struct v4l2_streamparm * parm )
2008-12-10 06:06:20 -03:00
{
struct v4l2_captureparm * cp = & parm - > parm . capture ;
struct v4l2_fract * tpf = & cp - > timeperframe ;
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( parm - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
cp - > capability | = V4L2_CAP_TIMEPERFRAME ;
tpf - > numerator = 1 ;
tpf - > denominator = sd - > frame_rate ;
return 0 ;
}
/* set stream parameters (framerate) */
2008-12-21 15:02:54 -03:00
static int sd_set_streamparm ( struct gspca_dev * gspca_dev ,
struct v4l2_streamparm * parm )
2008-12-10 06:06:20 -03:00
{
struct v4l2_captureparm * cp = & parm - > parm . capture ;
struct v4l2_fract * tpf = & cp - > timeperframe ;
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( parm - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
return - EINVAL ;
/* Set requested framerate */
sd - > frame_rate = tpf - > denominator / tpf - > numerator ;
2010-01-07 05:18:16 -03:00
if ( gspca_dev - > streaming )
2009-11-12 06:10:36 -03:00
set_frame_rate ( gspca_dev ) ;
2008-12-10 06:06:20 -03:00
/* Return the actual framerate */
tpf - > numerator = 1 ;
tpf - > denominator = sd - > frame_rate ;
return 0 ;
}
2008-11-22 05:23:39 -03:00
/* sub-driver description */
2010-01-07 05:18:16 -03:00
static const struct sd_desc sd_desc = {
2008-11-22 05:23:39 -03:00
. name = MODULE_NAME ,
2010-01-07 05:18:16 -03:00
. ctrls = sd_ctrls ,
. nctrls = ARRAY_SIZE ( sd_ctrls ) ,
2008-11-22 05:23:39 -03:00
. config = sd_config ,
. init = sd_init ,
2010-01-07 05:18:16 -03:00
. start = sd_start ,
. stopN = sd_stopN ,
2009-11-11 07:46:28 -03:00
. pkt_scan = sd_pkt_scan ,
. get_streamparm = sd_get_streamparm ,
. set_streamparm = sd_set_streamparm ,
} ;
2008-11-22 05:23:39 -03:00
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table [ ] = {
2010-01-07 05:18:16 -03:00
{ USB_DEVICE ( 0x1415 , 0x2000 ) } ,
2008-11-22 05:23:39 -03:00
{ }
} ;
MODULE_DEVICE_TABLE ( usb , device_table ) ;
/* -- device connect -- */
static int sd_probe ( struct usb_interface * intf , const struct usb_device_id * id )
{
2010-01-07 05:18:16 -03:00
return gspca_dev_probe ( intf , id , & sd_desc , sizeof ( struct sd ) ,
2009-11-11 07:46:28 -03:00
THIS_MODULE ) ;
2008-11-22 05:23:39 -03:00
}
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 ,
# endif
} ;
/* -- module insert / remove -- */
static int __init sd_mod_init ( void )
{
2009-01-01 13:02:07 -03:00
int ret ;
2009-11-11 07:46:28 -03:00
2009-01-01 13:02:07 -03:00
ret = usb_register ( & sd_driver ) ;
if ( ret < 0 )
2009-01-01 13:04:58 -03:00
return ret ;
2008-11-22 05:23:39 -03:00
PDEBUG ( D_PROBE , " registered " ) ;
return 0 ;
}
static void __exit sd_mod_exit ( void )
{
usb_deregister ( & sd_driver ) ;
PDEBUG ( D_PROBE , " deregistered " ) ;
}
module_init ( sd_mod_init ) ;
module_exit ( sd_mod_exit ) ;