// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SPCA505 chip based cameras initialization data
*
* V4L2 by Jean - Francis Moine < http : //moinejf.free.fr>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MODULE_NAME "spca505"
#include "gspca.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>" );
MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver" );
MODULE_LICENSE("GPL" );
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
u8 subtype;
#define IntelPCCameraPro 0
#define Nxultra 1
};
static const struct v4l2_pix_format vga_mode[] = {
{160 , 120 , V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 160 ,
.sizeimage = 160 * 120 * 3 / 2 ,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 4 },
{176 , 144 , V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 176 ,
.sizeimage = 176 * 144 * 3 / 2 ,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 3 },
{320 , 240 , V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 320 ,
.sizeimage = 320 * 240 * 3 / 2 ,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2 },
{352 , 288 , V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 352 ,
.sizeimage = 352 * 288 * 3 / 2 ,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1 },
{640 , 480 , V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
.bytesperline = 640 ,
.sizeimage = 640 * 480 * 3 / 2 ,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0 },
};
#define SPCA50X_OFFSET_DATA 10
#define SPCA50X_REG_USB 0 x02 /* spca505 501 */
#define SPCA50X_USB_CTRL 0 x00 /* spca505 */
#define SPCA50X_CUSB_ENABLE 0 x01 /* spca505 */
#define SPCA50X_REG_GLOBAL 0 x03 /* spca505 */
#define SPCA50X_GMISC0_IDSEL 0 x01 /* Global control device ID select spca505 */
#define SPCA50X_GLOBAL_MISC0 0 x00 /* Global control miscellaneous 0 spca505 */
#define SPCA50X_GLOBAL_MISC1 0 x01 /* 505 */
#define SPCA50X_GLOBAL_MISC3 0 x03 /* 505 */
#define SPCA50X_GMISC3_SAA7113RST 0 x20 /* Not sure about this one spca505 */
/* Image format and compression control */
#define SPCA50X_REG_COMPRESS 0 x04
/*
* Data to initialize a SPCA505 . Common to the CCD and external modes
*/
static const u8 spca505_init_data[][3 ] = {
/* bmRequest,value,index */
{SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
/* Sensor reset */
{SPCA50X_REG_GLOBAL, 0 x00, SPCA50X_GLOBAL_MISC3},
{SPCA50X_REG_GLOBAL, 0 x00, SPCA50X_GLOBAL_MISC1},
/* Block USB reset */
{SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0},
{0 x05, 0 x01, 0 x10},
/* Maybe power down some stuff */
{0 x05, 0 x0f, 0 x11},
/* Setup internal CCD ? */
{0 x06, 0 x10, 0 x08},
{0 x06, 0 x00, 0 x09},
{0 x06, 0 x00, 0 x0a},
{0 x06, 0 x00, 0 x0b},
{0 x06, 0 x10, 0 x0c},
{0 x06, 0 x00, 0 x0d},
{0 x06, 0 x00, 0 x0e},
{0 x06, 0 x00, 0 x0f},
{0 x06, 0 x10, 0 x10},
{0 x06, 0 x02, 0 x11},
{0 x06, 0 x00, 0 x12},
{0 x06, 0 x04, 0 x13},
{0 x06, 0 x02, 0 x14},
{0 x06, 0 x8a, 0 x51},
{0 x06, 0 x40, 0 x52},
{0 x06, 0 xb6, 0 x53},
{0 x06, 0 x3d, 0 x54},
{}
};
/*
* Data to initialize the camera using the internal CCD
*/
static const u8 spca505_open_data_ccd[][3 ] = {
/* bmRequest,value,index */
/* Internal CCD data set */
{0 x03, 0 x04, 0 x01},
/* This could be a reset */
{0 x03, 0 x00, 0 x01},
/* Setup compression and image registers. 0x6 and 0x7 seem to be
related to H&V hold, and are resolution mode specific */
{0 x04, 0 x10, 0 x01},
/* DIFF(0x50), was (0x10) */
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x04, 0 x20, 0 x06},
{0 x04, 0 x20, 0 x07},
{0 x08, 0 x0a, 0 x00},
/* DIFF (0x4a), was (0xa) */
{0 x05, 0 x00, 0 x10},
{0 x05, 0 x00, 0 x11},
{0 x05, 0 x00, 0 x00},
/* DIFF not written */
{0 x05, 0 x00, 0 x01},
/* DIFF not written */
{0 x05, 0 x00, 0 x02},
/* DIFF not written */
{0 x05, 0 x00, 0 x03},
/* DIFF not written */
{0 x05, 0 x00, 0 x04},
/* DIFF not written */
{0 x05, 0 x80, 0 x05},
/* DIFF not written */
{0 x05, 0 xe0, 0 x06},
/* DIFF not written */
{0 x05, 0 x20, 0 x07},
/* DIFF not written */
{0 x05, 0 xa0, 0 x08},
/* DIFF not written */
{0 x05, 0 x0, 0 x12},
/* DIFF not written */
{0 x05, 0 x02, 0 x0f},
/* DIFF not written */
{0 x05, 0 x10, 0 x46},
/* DIFF not written */
{0 x05, 0 x8, 0 x4a},
/* DIFF not written */
{0 x03, 0 x08, 0 x03},
/* DIFF (0x3,0x28,0x3) */
{0 x03, 0 x08, 0 x01},
{0 x03, 0 x0c, 0 x03},
/* DIFF not written */
{0 x03, 0 x21, 0 x00},
/* DIFF (0x39) */
/* Extra block copied from init to hopefully ensure CCD is in a sane state */
{0 x06, 0 x10, 0 x08},
{0 x06, 0 x00, 0 x09},
{0 x06, 0 x00, 0 x0a},
{0 x06, 0 x00, 0 x0b},
{0 x06, 0 x10, 0 x0c},
{0 x06, 0 x00, 0 x0d},
{0 x06, 0 x00, 0 x0e},
{0 x06, 0 x00, 0 x0f},
{0 x06, 0 x10, 0 x10},
{0 x06, 0 x02, 0 x11},
{0 x06, 0 x00, 0 x12},
{0 x06, 0 x04, 0 x13},
{0 x06, 0 x02, 0 x14},
{0 x06, 0 x8a, 0 x51},
{0 x06, 0 x40, 0 x52},
{0 x06, 0 xb6, 0 x53},
{0 x06, 0 x3d, 0 x54},
/* End of extra block */
{0 x06, 0 x3f, 0 x1},
/* Block skipped */
{0 x06, 0 x10, 0 x02},
{0 x06, 0 x64, 0 x07},
{0 x06, 0 x10, 0 x08},
{0 x06, 0 x00, 0 x09},
{0 x06, 0 x00, 0 x0a},
{0 x06, 0 x00, 0 x0b},
{0 x06, 0 x10, 0 x0c},
{0 x06, 0 x00, 0 x0d},
{0 x06, 0 x00, 0 x0e},
{0 x06, 0 x00, 0 x0f},
{0 x06, 0 x10, 0 x10},
{0 x06, 0 x02, 0 x11},
{0 x06, 0 x00, 0 x12},
{0 x06, 0 x04, 0 x13},
{0 x06, 0 x02, 0 x14},
{0 x06, 0 x8a, 0 x51},
{0 x06, 0 x40, 0 x52},
{0 x06, 0 xb6, 0 x53},
{0 x06, 0 x3d, 0 x54},
{0 x06, 0 x60, 0 x57},
{0 x06, 0 x20, 0 x58},
{0 x06, 0 x15, 0 x59},
{0 x06, 0 x05, 0 x5a},
{0 x05, 0 x01, 0 xc0},
{0 x05, 0 x10, 0 xcb},
{0 x05, 0 x80, 0 xc1},
/* */
{0 x05, 0 x0, 0 xc2},
/* 4 was 0 */
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x80, 0 xc1},
/* */
{0 x05, 0 x04, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x0, 0 xc1},
/* */
{0 x05, 0 x00, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x40, 0 xc1},
/* */
{0 x05, 0 x17, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x80, 0 xc1},
/* */
{0 x05, 0 x06, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x80, 0 xc1},
/* */
{0 x05, 0 x04, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x03, 0 x4c, 0 x3},
{0 x03, 0 x18, 0 x1},
{0 x06, 0 x70, 0 x51},
{0 x06, 0 xbe, 0 x53},
{0 x06, 0 x71, 0 x57},
{0 x06, 0 x20, 0 x58},
{0 x06, 0 x05, 0 x59},
{0 x06, 0 x15, 0 x5a},
{0 x04, 0 x00, 0 x08},
/* Compress = OFF (0x1 to turn on) */
{0 x04, 0 x12, 0 x09},
{0 x04, 0 x21, 0 x0a},
{0 x04, 0 x10, 0 x0b},
{0 x04, 0 x21, 0 x0c},
{0 x04, 0 x05, 0 x00},
/* was 5 (Image Type ? ) */
{0 x04, 0 x00, 0 x01},
{0 x06, 0 x3f, 0 x01},
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x04, 0 x40, 0 x06},
{0 x04, 0 x40, 0 x07},
{0 x06, 0 x1c, 0 x17},
{0 x06, 0 xe2, 0 x19},
{0 x06, 0 x1c, 0 x1b},
{0 x06, 0 xe2, 0 x1d},
{0 x06, 0 xaa, 0 x1f},
{0 x06, 0 x70, 0 x20},
{0 x05, 0 x01, 0 x10},
{0 x05, 0 x00, 0 x11},
{0 x05, 0 x01, 0 x00},
{0 x05, 0 x05, 0 x01},
{0 x05, 0 x00, 0 xc1},
/* */
{0 x05, 0 x00, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x06, 0 x70, 0 x51},
{0 x06, 0 xbe, 0 x53},
{}
};
/*
* Made by Tomasz Zablocki ( skalamandra @ poczta . onet . pl )
* SPCA505b chip based cameras initialization data
*/
/* jfm */
#define initial_brightness 0 x7f /* 0x0(white)-0xff(black) */
/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */
/*
* Data to initialize a SPCA505 . Common to the CCD and external modes
*/
static const u8 spca505b_init_data[][3 ] = {
/* start */
{0 x02, 0 x00, 0 x00}, /* init */
{0 x02, 0 x00, 0 x01},
{0 x02, 0 x00, 0 x02},
{0 x02, 0 x00, 0 x03},
{0 x02, 0 x00, 0 x04},
{0 x02, 0 x00, 0 x05},
{0 x02, 0 x00, 0 x06},
{0 x02, 0 x00, 0 x07},
{0 x02, 0 x00, 0 x08},
{0 x02, 0 x00, 0 x09},
{0 x03, 0 x00, 0 x00},
{0 x03, 0 x00, 0 x01},
{0 x03, 0 x00, 0 x02},
{0 x03, 0 x00, 0 x03},
{0 x03, 0 x00, 0 x04},
{0 x03, 0 x00, 0 x05},
{0 x03, 0 x00, 0 x06},
{0 x04, 0 x00, 0 x00},
{0 x04, 0 x00, 0 x02},
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x04, 0 x00, 0 x06},
{0 x04, 0 x00, 0 x07},
{0 x04, 0 x00, 0 x08},
{0 x04, 0 x00, 0 x09},
{0 x04, 0 x00, 0 x0a},
{0 x04, 0 x00, 0 x0b},
{0 x04, 0 x00, 0 x0c},
{0 x07, 0 x00, 0 x00},
{0 x07, 0 x00, 0 x03},
{0 x08, 0 x00, 0 x00},
{0 x08, 0 x00, 0 x01},
{0 x08, 0 x00, 0 x02},
{0 x06, 0 x18, 0 x08},
{0 x06, 0 xfc, 0 x09},
{0 x06, 0 xfc, 0 x0a},
{0 x06, 0 xfc, 0 x0b},
{0 x06, 0 x18, 0 x0c},
{0 x06, 0 xfc, 0 x0d},
{0 x06, 0 xfc, 0 x0e},
{0 x06, 0 xfc, 0 x0f},
{0 x06, 0 x18, 0 x10},
{0 x06, 0 xfe, 0 x12},
{0 x06, 0 x00, 0 x11},
{0 x06, 0 x00, 0 x14},
{0 x06, 0 x00, 0 x13},
{0 x06, 0 x28, 0 x51},
{0 x06, 0 xff, 0 x53},
{0 x02, 0 x00, 0 x08},
{0 x03, 0 x00, 0 x03},
{0 x03, 0 x10, 0 x03},
{}
};
/*
* Data to initialize the camera using the internal CCD
*/
static const u8 spca505b_open_data_ccd[][3 ] = {
/* {0x02,0x00,0x00}, */
{0 x03, 0 x04, 0 x01}, /* rst */
{0 x03, 0 x00, 0 x01},
{0 x03, 0 x00, 0 x00},
{0 x03, 0 x21, 0 x00},
{0 x03, 0 x00, 0 x04},
{0 x03, 0 x00, 0 x03},
{0 x03, 0 x18, 0 x03},
{0 x03, 0 x08, 0 x01},
{0 x03, 0 x1c, 0 x03},
{0 x03, 0 x5c, 0 x03},
{0 x03, 0 x5c, 0 x03},
{0 x03, 0 x18, 0 x01},
/* same as 505 */
{0 x04, 0 x10, 0 x01},
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x04, 0 x20, 0 x06},
{0 x04, 0 x20, 0 x07},
{0 x08, 0 x0a, 0 x00},
{0 x05, 0 x00, 0 x10},
{0 x05, 0 x00, 0 x11},
{0 x05, 0 x00, 0 x12},
{0 x05, 0 x6f, 0 x00},
{0 x05, initial_brightness >> 6 , 0 x00},
{0 x05, (initial_brightness << 2 ) & 0 xff, 0 x01},
{0 x05, 0 x00, 0 x02},
{0 x05, 0 x01, 0 x03},
{0 x05, 0 x00, 0 x04},
{0 x05, 0 x03, 0 x05},
{0 x05, 0 xe0, 0 x06},
{0 x05, 0 x20, 0 x07},
{0 x05, 0 xa0, 0 x08},
{0 x05, 0 x00, 0 x12},
{0 x05, 0 x02, 0 x0f},
{0 x05, 0 x80, 0 x14}, /* max exposure off (0=on) */
{0 x05, 0 x01, 0 xb0},
{0 x05, 0 x01, 0 xbf},
{0 x03, 0 x02, 0 x06},
{0 x05, 0 x10, 0 x46},
{0 x05, 0 x08, 0 x4a},
{0 x06, 0 x00, 0 x01},
{0 x06, 0 x10, 0 x02},
{0 x06, 0 x64, 0 x07},
{0 x06, 0 x18, 0 x08},
{0 x06, 0 xfc, 0 x09},
{0 x06, 0 xfc, 0 x0a},
{0 x06, 0 xfc, 0 x0b},
{0 x04, 0 x00, 0 x01},
{0 x06, 0 x18, 0 x0c},
{0 x06, 0 xfc, 0 x0d},
{0 x06, 0 xfc, 0 x0e},
{0 x06, 0 xfc, 0 x0f},
{0 x06, 0 x11, 0 x10}, /* contrast */
{0 x06, 0 x00, 0 x11},
{0 x06, 0 xfe, 0 x12},
{0 x06, 0 x00, 0 x13},
{0 x06, 0 x00, 0 x14},
{0 x06, 0 x9d, 0 x51},
{0 x06, 0 x40, 0 x52},
{0 x06, 0 x7c, 0 x53},
{0 x06, 0 x40, 0 x54},
{0 x06, 0 x02, 0 x57},
{0 x06, 0 x03, 0 x58},
{0 x06, 0 x15, 0 x59},
{0 x06, 0 x05, 0 x5a},
{0 x06, 0 x03, 0 x56},
{0 x06, 0 x02, 0 x3f},
{0 x06, 0 x00, 0 x40},
{0 x06, 0 x39, 0 x41},
{0 x06, 0 x69, 0 x42},
{0 x06, 0 x87, 0 x43},
{0 x06, 0 x9e, 0 x44},
{0 x06, 0 xb1, 0 x45},
{0 x06, 0 xbf, 0 x46},
{0 x06, 0 xcc, 0 x47},
{0 x06, 0 xd5, 0 x48},
{0 x06, 0 xdd, 0 x49},
{0 x06, 0 xe3, 0 x4a},
{0 x06, 0 xe8, 0 x4b},
{0 x06, 0 xed, 0 x4c},
{0 x06, 0 xf2, 0 x4d},
{0 x06, 0 xf7, 0 x4e},
{0 x06, 0 xfc, 0 x4f},
{0 x06, 0 xff, 0 x50},
{0 x05, 0 x01, 0 xc0},
{0 x05, 0 x10, 0 xcb},
{0 x05, 0 x40, 0 xc1},
{0 x05, 0 x04, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x40, 0 xc1},
{0 x05, 0 x09, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 xc0, 0 xc1},
{0 x05, 0 x09, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x40, 0 xc1},
{0 x05, 0 x59, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x04, 0 x00, 0 x01},
{0 x05, 0 x80, 0 xc1},
{0 x05, 0 xec, 0 xc2},
{0 x05, 0 x0, 0 xca},
{0 x06, 0 x02, 0 x57},
{0 x06, 0 x01, 0 x58},
{0 x06, 0 x15, 0 x59},
{0 x06, 0 x0a, 0 x5a},
{0 x06, 0 x01, 0 x57},
{0 x06, 0 x8a, 0 x03},
{0 x06, 0 x0a, 0 x6c},
{0 x06, 0 x30, 0 x01},
{0 x06, 0 x20, 0 x02},
{0 x06, 0 x00, 0 x03},
{0 x05, 0 x8c, 0 x25},
{0 x06, 0 x4d, 0 x51}, /* maybe saturation (4d) */
{0 x06, 0 x84, 0 x53}, /* making green (84) */
{0 x06, 0 x00, 0 x57}, /* sharpness (1) */
{0 x06, 0 x18, 0 x08},
{0 x06, 0 xfc, 0 x09},
{0 x06, 0 xfc, 0 x0a},
{0 x06, 0 xfc, 0 x0b},
{0 x06, 0 x18, 0 x0c}, /* maybe hue (18) */
{0 x06, 0 xfc, 0 x0d},
{0 x06, 0 xfc, 0 x0e},
{0 x06, 0 xfc, 0 x0f},
{0 x06, 0 x18, 0 x10}, /* maybe contrast (18) */
{0 x05, 0 x01, 0 x02},
{0 x04, 0 x00, 0 x08}, /* compression */
{0 x04, 0 x12, 0 x09},
{0 x04, 0 x21, 0 x0a},
{0 x04, 0 x10, 0 x0b},
{0 x04, 0 x21, 0 x0c},
{0 x04, 0 x1d, 0 x00}, /* imagetype (1d) */
{0 x04, 0 x41, 0 x01}, /* hardware snapcontrol */
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x04, 0 x10, 0 x06},
{0 x04, 0 x10, 0 x07},
{0 x04, 0 x40, 0 x06},
{0 x04, 0 x40, 0 x07},
{0 x04, 0 x00, 0 x04},
{0 x04, 0 x00, 0 x05},
{0 x06, 0 x1c, 0 x17},
{0 x06, 0 xe2, 0 x19},
{0 x06, 0 x1c, 0 x1b},
{0 x06, 0 xe2, 0 x1d},
{0 x06, 0 x5f, 0 x1f},
{0 x06, 0 x32, 0 x20},
{0 x05, initial_brightness >> 6 , 0 x00},
{0 x05, (initial_brightness << 2 ) & 0 xff, 0 x01},
{0 x05, 0 x06, 0 xc1},
{0 x05, 0 x58, 0 xc2},
{0 x05, 0 x00, 0 xca},
{0 x05, 0 x00, 0 x11},
{}
};
static int reg_write(struct gspca_dev *gspca_dev,
u16 req, u16 index, u16 value)
{
int ret;
struct usb_device *dev = gspca_dev->dev;
ret = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0 ),
req,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0 , 500 );
gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d\n" ,
req, index, value, ret);
if (ret < 0 )
pr_err("reg write: error %d\n" , ret);
return ret;
}
/* returns: negative is error, pos or zero is data */
static int reg_read(struct gspca_dev *gspca_dev,
u16 req, /* bRequest */
u16 index) /* wIndex */
{
int ret;
ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0 ),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0 , /* value */
index,
gspca_dev->usb_buf, 2 ,
500 ); /* timeout */
if (ret < 0 )
return ret;
return (gspca_dev->usb_buf[1 ] << 8 ) + gspca_dev->usb_buf[0 ];
}
static int write_vector(struct gspca_dev *gspca_dev,
const u8 data[][3 ])
{
int ret, i = 0 ;
while (data[i][0 ] != 0 ) {
ret = reg_write(gspca_dev, data[i][0 ], data[i][2 ],
data[i][1 ]);
if (ret < 0 )
return ret;
i++;
}
return 0 ;
}
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
sd->subtype = id->driver_info;
if (sd->subtype != IntelPCCameraPro)
cam->nmodes = ARRAY_SIZE(vga_mode);
else /* no 640x480 for IntelPCCameraPro */
cam->nmodes = ARRAY_SIZE(vga_mode) - 1 ;
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
if (write_vector(gspca_dev,
sd->subtype == Nxultra
? spca505b_init_data
: spca505_init_data))
return -EIO;
return 0 ;
}
static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
{
reg_write(gspca_dev, 0 x05, 0 x00, (255 - brightness) >> 6 );
reg_write(gspca_dev, 0 x05, 0 x01, (255 - brightness) << 2 );
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int ret, mode;
static u8 mode_tb[][3 ] = {
/* r00 r06 r07 */
{0 x00, 0 x10, 0 x10}, /* 640x480 */
{0 x01, 0 x1a, 0 x1a}, /* 352x288 */
{0 x02, 0 x1c, 0 x1d}, /* 320x240 */
{0 x04, 0 x34, 0 x34}, /* 176x144 */
{0 x05, 0 x40, 0 x40} /* 160x120 */
};
if (sd->subtype == Nxultra)
write_vector(gspca_dev, spca505b_open_data_ccd);
else
write_vector(gspca_dev, spca505_open_data_ccd);
ret = reg_read(gspca_dev, 0 x06, 0 x16);
if (ret < 0 ) {
gspca_err(gspca_dev, "register read failed err: %d\n" , ret);
return ret;
}
if (ret != 0 x0101) {
pr_err("After vector read returns 0x%04x should be 0x0101\n" ,
ret);
}
ret = reg_write(gspca_dev, 0 x06, 0 x16, 0 x0a);
if (ret < 0 )
return ret;
reg_write(gspca_dev, 0 x05, 0 xc2, 0 x12);
/* necessary because without it we can see stream
* only once after loading module */
/* stopping usb registers Tomasz change */
reg_write(gspca_dev, 0 x02, 0 x00, 0 x00);
mode = gspca_dev->cam.cam_mode[(int ) gspca_dev->curr_mode].priv;
reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0 x00, mode_tb[mode][0 ]);
reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0 x06, mode_tb[mode][1 ]);
reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0 x07, mode_tb[mode][2 ]);
return reg_write(gspca_dev, SPCA50X_REG_USB,
SPCA50X_USB_CTRL,
SPCA50X_CUSB_ENABLE);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
/* Disable ISO packet machine */
reg_write(gspca_dev, 0 x02, 0 x00, 0 x00);
}
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
if (!gspca_dev->present)
return ;
/* This maybe reset or power control */
reg_write(gspca_dev, 0 x03, 0 x03, 0 x20);
reg_write(gspca_dev, 0 x03, 0 x01, 0 x00);
reg_write(gspca_dev, 0 x03, 0 x00, 0 x01);
reg_write(gspca_dev, 0 x05, 0 x10, 0 x01);
reg_write(gspca_dev, 0 x05, 0 x11, 0 x0f);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
switch (data[0 ]) {
case 0 : /* start of frame */
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0 );
data += SPCA50X_OFFSET_DATA;
len -= SPCA50X_OFFSET_DATA;
gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
break ;
case 0 xff: /* drop */
break ;
default :
data += 1 ;
len -= 1 ;
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
break ;
}
}
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
gspca_dev->usb_err = 0 ;
if (!gspca_dev->streaming)
return 0 ;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
setbrightness(gspca_dev, ctrl->val);
break ;
}
return gspca_dev->usb_err;
}
static const struct v4l2_ctrl_ops sd_ctrl_ops = {
.s_ctrl = sd_s_ctrl,
};
static int sd_init_controls(struct gspca_dev *gspca_dev)
{
struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
gspca_dev->vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 5 );
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0 , 255 , 1 , 127 );
if (hdl->error) {
pr_err("Could not initialize controls\n" );
return hdl->error;
}
return 0 ;
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.config = sd_config,
.init_controls = sd_init_controls,
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
};
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0 x041e, 0 x401d), .driver_info = Nxultra},
{USB_DEVICE(0 x0733, 0 x0430), .driver_info = IntelPCCameraPro},
/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
{}
};
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,
.reset_resume = gspca_resume,
#endif
};
module_usb_driver(sd_driver);
Messung V0.5 in Prozent C=87 H=99 G=93
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland