Path: blob/master/drivers/media/video/gspca/ov534_9.c
17705 views
/*1* ov534-ov965x gspca driver2*3* Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr4* Copyright (C) 2008 Antonio Ospite <[email protected]>5* Copyright (C) 2008 Jim Paris <[email protected]>6*7* Based on a prototype written by Mark Ferrell <[email protected]>8* USB protocol reverse engineered by Jim Paris <[email protected]>9* https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/10*11* This program is free software; you can redistribute it and/or modify12* it under the terms of the GNU General Public License as published by13* the Free Software Foundation; either version 2 of the License, or14* any later version.15*16* This program is distributed in the hope that it will be useful,17* but WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the19* GNU General Public License for more details.20*21* You should have received a copy of the GNU General Public License22* along with this program; if not, write to the Free Software23* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA24*/2526#define MODULE_NAME "ov534_9"2728#include "gspca.h"2930#define OV534_REG_ADDRESS 0xf1 /* sensor address */31#define OV534_REG_SUBADDR 0xf232#define OV534_REG_WRITE 0xf333#define OV534_REG_READ 0xf434#define OV534_REG_OPERATION 0xf535#define OV534_REG_STATUS 0xf63637#define OV534_OP_WRITE_3 0x3738#define OV534_OP_WRITE_2 0x3339#define OV534_OP_READ_2 0xf94041#define CTRL_TIMEOUT 5004243MODULE_AUTHOR("Jean-Francois Moine <[email protected]>");44MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver");45MODULE_LICENSE("GPL");4647/* specific webcam descriptor */48struct sd {49struct gspca_dev gspca_dev; /* !! must be the first item */50__u32 last_pts;51u8 last_fid;5253u8 brightness;54u8 contrast;55u8 autogain;56u8 exposure;57s8 sharpness;58u8 satur;59u8 freq;60};6162/* V4L2 controls supported by the driver */63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);67static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);68static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);69static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);70static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);71static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);72static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);73static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val);74static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val);75static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);76static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);7778static const struct ctrl sd_ctrls[] = {79{ /* 0 */80{81.id = V4L2_CID_BRIGHTNESS,82.type = V4L2_CTRL_TYPE_INTEGER,83.name = "Brightness",84.minimum = 0,85.maximum = 15,86.step = 1,87#define BRIGHTNESS_DEF 788.default_value = BRIGHTNESS_DEF,89},90.set = sd_setbrightness,91.get = sd_getbrightness,92},93{ /* 1 */94{95.id = V4L2_CID_CONTRAST,96.type = V4L2_CTRL_TYPE_INTEGER,97.name = "Contrast",98.minimum = 0,99.maximum = 15,100.step = 1,101#define CONTRAST_DEF 3102.default_value = CONTRAST_DEF,103},104.set = sd_setcontrast,105.get = sd_getcontrast,106},107{ /* 2 */108{109.id = V4L2_CID_AUTOGAIN,110.type = V4L2_CTRL_TYPE_BOOLEAN,111.name = "Autogain",112.minimum = 0,113.maximum = 1,114.step = 1,115#define AUTOGAIN_DEF 1116.default_value = AUTOGAIN_DEF,117},118.set = sd_setautogain,119.get = sd_getautogain,120},121#define EXPO_IDX 3122{ /* 3 */123{124.id = V4L2_CID_EXPOSURE,125.type = V4L2_CTRL_TYPE_INTEGER,126.name = "Exposure",127.minimum = 0,128.maximum = 3,129.step = 1,130#define EXPO_DEF 0131.default_value = EXPO_DEF,132},133.set = sd_setexposure,134.get = sd_getexposure,135},136{ /* 4 */137{138.id = V4L2_CID_SHARPNESS,139.type = V4L2_CTRL_TYPE_INTEGER,140.name = "Sharpness",141.minimum = -1, /* -1 = auto */142.maximum = 4,143.step = 1,144#define SHARPNESS_DEF -1145.default_value = SHARPNESS_DEF,146},147.set = sd_setsharpness,148.get = sd_getsharpness,149},150{ /* 5 */151{152.id = V4L2_CID_SATURATION,153.type = V4L2_CTRL_TYPE_INTEGER,154.name = "Saturation",155.minimum = 0,156.maximum = 4,157.step = 1,158#define SATUR_DEF 2159.default_value = SATUR_DEF,160},161.set = sd_setsatur,162.get = sd_getsatur,163},164{165{166.id = V4L2_CID_POWER_LINE_FREQUENCY,167.type = V4L2_CTRL_TYPE_MENU,168.name = "Light frequency filter",169.minimum = 0,170.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */171.step = 1,172#define FREQ_DEF 0173.default_value = FREQ_DEF,174},175.set = sd_setfreq,176.get = sd_getfreq,177},178};179180static const struct v4l2_pix_format ov965x_mode[] = {181#define QVGA_MODE 0182{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,183.bytesperline = 320,184.sizeimage = 320 * 240 * 3 / 8 + 590,185.colorspace = V4L2_COLORSPACE_JPEG},186#define VGA_MODE 1187{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,188.bytesperline = 640,189.sizeimage = 640 * 480 * 3 / 8 + 590,190.colorspace = V4L2_COLORSPACE_JPEG},191#define SVGA_MODE 2192{800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,193.bytesperline = 800,194.sizeimage = 800 * 600 * 3 / 8 + 590,195.colorspace = V4L2_COLORSPACE_JPEG},196#define XGA_MODE 3197{1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,198.bytesperline = 1024,199.sizeimage = 1024 * 768 * 3 / 8 + 590,200.colorspace = V4L2_COLORSPACE_JPEG},201#define SXGA_MODE 4202{1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,203.bytesperline = 1280,204.sizeimage = 1280 * 1024 * 3 / 8 + 590,205.colorspace = V4L2_COLORSPACE_JPEG},206};207208static const u8 bridge_init[][2] = {209{0x88, 0xf8},210{0x89, 0xff},211{0x76, 0x03},212{0x92, 0x03},213{0x95, 0x10},214{0xe2, 0x00},215{0xe7, 0x3e},216{0x8d, 0x1c},217{0x8e, 0x00},218{0x8f, 0x00},219{0x1f, 0x00},220{0xc3, 0xf9},221{0x89, 0xff},222{0x88, 0xf8},223{0x76, 0x03},224{0x92, 0x01},225{0x93, 0x18},226{0x1c, 0x0a},227{0x1d, 0x48},228{0xc0, 0x50},229{0xc1, 0x3c},230{0x34, 0x05},231{0xc2, 0x0c},232{0xc3, 0xf9},233{0x34, 0x05},234{0xe7, 0x2e},235{0x31, 0xf9},236{0x35, 0x02},237{0xd9, 0x10},238{0x25, 0x42},239{0x94, 0x11},240};241242static const u8 sensor_init[][2] = {243{0x12, 0x80}, /* com7 - SSCB reset */244{0x00, 0x00}, /* gain */245{0x01, 0x80}, /* blue */246{0x02, 0x80}, /* red */247{0x03, 0x1b}, /* vref */248{0x04, 0x03}, /* com1 - exposure low bits */249{0x0b, 0x57}, /* ver */250{0x0e, 0x61}, /* com5 */251{0x0f, 0x42}, /* com6 */252{0x11, 0x00}, /* clkrc */253{0x12, 0x02}, /* com7 - 15fps VGA YUYV */254{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */255{0x14, 0x28}, /* com9 */256{0x16, 0x24}, /* reg16 */257{0x17, 0x1d}, /* hstart*/258{0x18, 0xbd}, /* hstop */259{0x19, 0x01}, /* vstrt */260{0x1a, 0x81}, /* vstop*/261{0x1e, 0x04}, /* mvfp */262{0x24, 0x3c}, /* aew */263{0x25, 0x36}, /* aeb */264{0x26, 0x71}, /* vpt */265{0x27, 0x08}, /* bbias */266{0x28, 0x08}, /* gbbias */267{0x29, 0x15}, /* gr com */268{0x2a, 0x00}, /* exhch */269{0x2b, 0x00}, /* exhcl */270{0x2c, 0x08}, /* rbias */271{0x32, 0xff}, /* href */272{0x33, 0x00}, /* chlf */273{0x34, 0x3f}, /* aref1 */274{0x35, 0x00}, /* aref2 */275{0x36, 0xf8}, /* aref3 */276{0x38, 0x72}, /* adc2 */277{0x39, 0x57}, /* aref4 */278{0x3a, 0x80}, /* tslb - yuyv */279{0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */280{0x3d, 0x99}, /* com13 */281{0x3f, 0xc1}, /* edge */282{0x40, 0xc0}, /* com15 */283{0x41, 0x40}, /* com16 */284{0x42, 0xc0}, /* com17 */285{0x43, 0x0a}, /* rsvd */286{0x44, 0xf0},287{0x45, 0x46},288{0x46, 0x62},289{0x47, 0x2a},290{0x48, 0x3c},291{0x4a, 0xfc},292{0x4b, 0xfc},293{0x4c, 0x7f},294{0x4d, 0x7f},295{0x4e, 0x7f},296{0x4f, 0x98}, /* matrix */297{0x50, 0x98},298{0x51, 0x00},299{0x52, 0x28},300{0x53, 0x70},301{0x54, 0x98},302{0x58, 0x1a}, /* matrix coef sign */303{0x59, 0x85}, /* AWB control */304{0x5a, 0xa9},305{0x5b, 0x64},306{0x5c, 0x84},307{0x5d, 0x53},308{0x5e, 0x0e},309{0x5f, 0xf0}, /* AWB blue limit */310{0x60, 0xf0}, /* AWB red limit */311{0x61, 0xf0}, /* AWB green limit */312{0x62, 0x00}, /* lcc1 */313{0x63, 0x00}, /* lcc2 */314{0x64, 0x02}, /* lcc3 */315{0x65, 0x16}, /* lcc4 */316{0x66, 0x01}, /* lcc5 */317{0x69, 0x02}, /* hv */318{0x6b, 0x5a}, /* dbvl */319{0x6c, 0x04},320{0x6d, 0x55},321{0x6e, 0x00},322{0x6f, 0x9d},323{0x70, 0x21}, /* dnsth */324{0x71, 0x78},325{0x72, 0x00}, /* poidx */326{0x73, 0x01}, /* pckdv */327{0x74, 0x3a}, /* xindx */328{0x75, 0x35}, /* yindx */329{0x76, 0x01},330{0x77, 0x02},331{0x7a, 0x12}, /* gamma curve */332{0x7b, 0x08},333{0x7c, 0x16},334{0x7d, 0x30},335{0x7e, 0x5e},336{0x7f, 0x72},337{0x80, 0x82},338{0x81, 0x8e},339{0x82, 0x9a},340{0x83, 0xa4},341{0x84, 0xac},342{0x85, 0xb8},343{0x86, 0xc3},344{0x87, 0xd6},345{0x88, 0xe6},346{0x89, 0xf2},347{0x8a, 0x03},348{0x8c, 0x89}, /* com19 */349{0x14, 0x28}, /* com9 */350{0x90, 0x7d},351{0x91, 0x7b},352{0x9d, 0x03}, /* lcc6 */353{0x9e, 0x04}, /* lcc7 */354{0x9f, 0x7a},355{0xa0, 0x79},356{0xa1, 0x40}, /* aechm */357{0xa4, 0x50}, /* com21 */358{0xa5, 0x68}, /* com26 */359{0xa6, 0x4a}, /* AWB green */360{0xa8, 0xc1}, /* refa8 */361{0xa9, 0xef}, /* refa9 */362{0xaa, 0x92},363{0xab, 0x04},364{0xac, 0x80}, /* black level control */365{0xad, 0x80},366{0xae, 0x80},367{0xaf, 0x80},368{0xb2, 0xf2},369{0xb3, 0x20},370{0xb4, 0x20}, /* ctrlb4 */371{0xb5, 0x00},372{0xb6, 0xaf},373{0xbb, 0xae},374{0xbc, 0x7f}, /* ADC channel offsets */375{0xdb, 0x7f},376{0xbe, 0x7f},377{0xbf, 0x7f},378{0xc0, 0xe2},379{0xc1, 0xc0},380{0xc2, 0x01},381{0xc3, 0x4e},382{0xc6, 0x85},383{0xc7, 0x80}, /* com24 */384{0xc9, 0xe0},385{0xca, 0xe8},386{0xcb, 0xf0},387{0xcc, 0xd8},388{0xcd, 0xf1},389{0x4f, 0x98}, /* matrix */390{0x50, 0x98},391{0x51, 0x00},392{0x52, 0x28},393{0x53, 0x70},394{0x54, 0x98},395{0x58, 0x1a},396{0xff, 0x41}, /* read 41, write ff 00 */397{0x41, 0x40}, /* com16 */398399{0xc5, 0x03}, /* 60 Hz banding filter */400{0x6a, 0x02}, /* 50 Hz banding filter */401402{0x12, 0x62}, /* com7 - 30fps VGA YUV */403{0x36, 0xfa}, /* aref3 */404{0x69, 0x0a}, /* hv */405{0x8c, 0x89}, /* com22 */406{0x14, 0x28}, /* com9 */407{0x3e, 0x0c},408{0x41, 0x40}, /* com16 */409{0x72, 0x00},410{0x73, 0x00},411{0x74, 0x3a},412{0x75, 0x35},413{0x76, 0x01},414{0xc7, 0x80},415{0x03, 0x12}, /* vref */416{0x17, 0x16}, /* hstart */417{0x18, 0x02}, /* hstop */418{0x19, 0x01}, /* vstrt */419{0x1a, 0x3d}, /* vstop */420{0x32, 0xff}, /* href */421{0xc0, 0xaa},422};423424static const u8 bridge_init_2[][2] = {425{0x94, 0xaa},426{0xf1, 0x60},427{0xe5, 0x04},428{0xc0, 0x50},429{0xc1, 0x3c},430{0x8c, 0x00},431{0x8d, 0x1c},432{0x34, 0x05},433434{0xc2, 0x0c},435{0xc3, 0xf9},436{0xda, 0x01},437{0x50, 0x00},438{0x51, 0xa0},439{0x52, 0x3c},440{0x53, 0x00},441{0x54, 0x00},442{0x55, 0x00},443{0x57, 0x00},444{0x5c, 0x00},445{0x5a, 0xa0},446{0x5b, 0x78},447{0x35, 0x02},448{0xd9, 0x10},449{0x94, 0x11},450};451452static const u8 sensor_init_2[][2] = {453{0x3b, 0xc4},454{0x1e, 0x04}, /* mvfp */455{0x13, 0xe0}, /* com8 */456{0x00, 0x00}, /* gain */457{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */458{0x11, 0x03}, /* clkrc */459{0x6b, 0x5a}, /* dblv */460{0x6a, 0x05},461{0xc5, 0x07},462{0xa2, 0x4b},463{0xa3, 0x3e},464{0x2d, 0x00},465{0xff, 0x42}, /* read 42, write ff 00 */466{0x42, 0xc0}, /* com17 */467{0x2d, 0x00},468{0xff, 0x42}, /* read 42, write ff 00 */469{0x42, 0xc1}, /* com17 */470/* sharpness */471{0x3f, 0x01},472{0xff, 0x42}, /* read 42, write ff 00 */473{0x42, 0xc1}, /* com17 */474/* saturation */475{0x4f, 0x98}, /* matrix */476{0x50, 0x98},477{0x51, 0x00},478{0x52, 0x28},479{0x53, 0x70},480{0x54, 0x98},481{0x58, 0x1a},482{0xff, 0x41}, /* read 41, write ff 00 */483{0x41, 0x40}, /* com16 */484/* contrast */485{0x56, 0x40},486/* brightness */487{0x55, 0x8f},488/* expo */489{0x10, 0x25}, /* aech - exposure high bits */490{0xff, 0x13}, /* read 13, write ff 00 */491{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */492};493494static const u8 sensor_start_1_vga[][2] = { /* same for qvga */495{0x12, 0x62}, /* com7 - 30fps VGA YUV */496{0x36, 0xfa}, /* aref3 */497{0x69, 0x0a}, /* hv */498{0x8c, 0x89}, /* com22 */499{0x14, 0x28}, /* com9 */500{0x3e, 0x0c}, /* com14 */501{0x41, 0x40}, /* com16 */502{0x72, 0x00},503{0x73, 0x00},504{0x74, 0x3a},505{0x75, 0x35},506{0x76, 0x01},507{0xc7, 0x80}, /* com24 */508{0x03, 0x12}, /* vref */509{0x17, 0x16}, /* hstart */510{0x18, 0x02}, /* hstop */511{0x19, 0x01}, /* vstrt */512{0x1a, 0x3d}, /* vstop */513{0x32, 0xff}, /* href */514{0xc0, 0xaa},515};516517static const u8 sensor_start_1_svga[][2] = {518{0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */519{0x36, 0xf8}, /* aref3 */520{0x69, 0x02}, /* hv */521{0x8c, 0x0d}, /* com22 */522{0x3e, 0x0c}, /* com14 */523{0x41, 0x40}, /* com16 */524{0x72, 0x00},525{0x73, 0x01},526{0x74, 0x3a},527{0x75, 0x35},528{0x76, 0x01},529{0xc7, 0x80}, /* com24 */530{0x03, 0x1b}, /* vref */531{0x17, 0x1d}, /* hstart */532{0x18, 0xbd}, /* hstop */533{0x19, 0x01}, /* vstrt */534{0x1a, 0x81}, /* vstop */535{0x32, 0xff}, /* href */536{0xc0, 0xe2},537};538539static const u8 sensor_start_1_xga[][2] = {540{0x12, 0x02}, /* com7 */541{0x36, 0xf8}, /* aref3 */542{0x69, 0x02}, /* hv */543{0x8c, 0x89}, /* com22 */544{0x14, 0x28}, /* com9 */545{0x3e, 0x0c}, /* com14 */546{0x41, 0x40}, /* com16 */547{0x72, 0x00},548{0x73, 0x01},549{0x74, 0x3a},550{0x75, 0x35},551{0x76, 0x01},552{0xc7, 0x80}, /* com24 */553{0x03, 0x1b}, /* vref */554{0x17, 0x1d}, /* hstart */555{0x18, 0xbd}, /* hstop */556{0x19, 0x01}, /* vstrt */557{0x1a, 0x81}, /* vstop */558{0x32, 0xff}, /* href */559{0xc0, 0xe2},560};561562static const u8 sensor_start_1_sxga[][2] = {563{0x12, 0x02}, /* com7 */564{0x36, 0xf8}, /* aref3 */565{0x69, 0x02}, /* hv */566{0x8c, 0x89}, /* com22 */567{0x14, 0x28}, /* com9 */568{0x3e, 0x0c}, /* com14 */569{0x41, 0x40}, /* com16 */570{0x72, 0x00},571{0x73, 0x01},572{0x74, 0x3a},573{0x75, 0x35},574{0x76, 0x01},575{0xc7, 0x80}, /* com24 */576{0x03, 0x1b}, /* vref */577{0x17, 0x1d}, /* hstart */578{0x18, 0x02}, /* hstop */579{0x19, 0x01}, /* vstrt */580{0x1a, 0x81}, /* vstop */581{0x32, 0xff}, /* href */582{0xc0, 0xe2},583};584585static const u8 bridge_start_qvga[][2] = {586{0x94, 0xaa},587{0xf1, 0x60},588{0xe5, 0x04},589{0xc0, 0x50},590{0xc1, 0x3c},591{0x8c, 0x00},592{0x8d, 0x1c},593{0x34, 0x05},594595{0xc2, 0x4c},596{0xc3, 0xf9},597{0xda, 0x00},598{0x50, 0x00},599{0x51, 0xa0},600{0x52, 0x78},601{0x53, 0x00},602{0x54, 0x00},603{0x55, 0x00},604{0x57, 0x00},605{0x5c, 0x00},606{0x5a, 0x50},607{0x5b, 0x3c},608{0x35, 0x02},609{0xd9, 0x10},610{0x94, 0x11},611};612613static const u8 bridge_start_vga[][2] = {614{0x94, 0xaa},615{0xf1, 0x60},616{0xe5, 0x04},617{0xc0, 0x50},618{0xc1, 0x3c},619{0x8c, 0x00},620{0x8d, 0x1c},621{0x34, 0x05},622{0xc2, 0x0c},623{0xc3, 0xf9},624{0xda, 0x01},625{0x50, 0x00},626{0x51, 0xa0},627{0x52, 0x3c},628{0x53, 0x00},629{0x54, 0x00},630{0x55, 0x00},631{0x57, 0x00},632{0x5c, 0x00},633{0x5a, 0xa0},634{0x5b, 0x78},635{0x35, 0x02},636{0xd9, 0x10},637{0x94, 0x11},638};639640static const u8 bridge_start_svga[][2] = {641{0x94, 0xaa},642{0xf1, 0x60},643{0xe5, 0x04},644{0xc0, 0xa0},645{0xc1, 0x80},646{0x8c, 0x00},647{0x8d, 0x1c},648{0x34, 0x05},649{0xc2, 0x4c},650{0xc3, 0xf9},651{0x50, 0x00},652{0x51, 0x40},653{0x52, 0x00},654{0x53, 0x00},655{0x54, 0x00},656{0x55, 0x88},657{0x57, 0x00},658{0x5c, 0x00},659{0x5a, 0xc8},660{0x5b, 0x96},661{0x35, 0x02},662{0xd9, 0x10},663{0xda, 0x00},664{0x94, 0x11},665};666667static const u8 bridge_start_xga[][2] = {668{0x94, 0xaa},669{0xf1, 0x60},670{0xe5, 0x04},671{0xc0, 0xa0},672{0xc1, 0x80},673{0x8c, 0x00},674{0x8d, 0x1c},675{0x34, 0x05},676{0xc2, 0x4c},677{0xc3, 0xf9},678{0x50, 0x00},679{0x51, 0x40},680{0x52, 0x00},681{0x53, 0x00},682{0x54, 0x00},683{0x55, 0x88},684{0x57, 0x00},685{0x5c, 0x01},686{0x5a, 0x00},687{0x5b, 0xc0},688{0x35, 0x02},689{0xd9, 0x10},690{0xda, 0x01},691{0x94, 0x11},692};693694static const u8 bridge_start_sxga[][2] = {695{0x94, 0xaa},696{0xf1, 0x60},697{0xe5, 0x04},698{0xc0, 0xa0},699{0xc1, 0x80},700{0x8c, 0x00},701{0x8d, 0x1c},702{0x34, 0x05},703{0xc2, 0x0c},704{0xc3, 0xf9},705{0xda, 0x00},706{0x35, 0x02},707{0xd9, 0x10},708{0x94, 0x11},709};710711static const u8 sensor_start_2_qvga[][2] = {712{0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */713{0x1e, 0x04}, /* mvfp */714{0x13, 0xe0}, /* com8 */715{0x00, 0x00},716{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */717{0x11, 0x01}, /* clkrc */718{0x6b, 0x5a}, /* dblv */719{0x6a, 0x02}, /* 50 Hz banding filter */720{0xc5, 0x03}, /* 60 Hz banding filter */721{0xa2, 0x96}, /* bd50 */722{0xa3, 0x7d}, /* bd60 */723724{0xff, 0x13}, /* read 13, write ff 00 */725{0x13, 0xe7},726{0x3a, 0x80}, /* tslb - yuyv */727};728729static const u8 sensor_start_2_vga[][2] = {730{0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */731{0x1e, 0x04}, /* mvfp */732{0x13, 0xe0}, /* com8 */733{0x00, 0x00},734{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */735{0x11, 0x03}, /* clkrc */736{0x6b, 0x5a}, /* dblv */737{0x6a, 0x05}, /* 50 Hz banding filter */738{0xc5, 0x07}, /* 60 Hz banding filter */739{0xa2, 0x4b}, /* bd50 */740{0xa3, 0x3e}, /* bd60 */741742{0x2d, 0x00}, /* advfl */743};744745static const u8 sensor_start_2_svga[][2] = { /* same for xga */746{0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */747{0x1e, 0x04}, /* mvfp */748{0x13, 0xe0}, /* com8 */749{0x00, 0x00},750{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */751{0x11, 0x01}, /* clkrc */752{0x6b, 0x5a}, /* dblv */753{0x6a, 0x0c}, /* 50 Hz banding filter */754{0xc5, 0x0f}, /* 60 Hz banding filter */755{0xa2, 0x4e}, /* bd50 */756{0xa3, 0x41}, /* bd60 */757};758759static const u8 sensor_start_2_sxga[][2] = {760{0x13, 0xe0}, /* com8 */761{0x00, 0x00},762{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */763{0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */764{0x1e, 0x04}, /* mvfp */765{0x11, 0x01}, /* clkrc */766{0x6b, 0x5a}, /* dblv */767{0x6a, 0x0c}, /* 50 Hz banding filter */768{0xc5, 0x0f}, /* 60 Hz banding filter */769{0xa2, 0x4e}, /* bd50 */770{0xa3, 0x41}, /* bd60 */771};772773static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)774{775struct usb_device *udev = gspca_dev->dev;776int ret;777778if (gspca_dev->usb_err < 0)779return;780gspca_dev->usb_buf[0] = val;781ret = usb_control_msg(udev,782usb_sndctrlpipe(udev, 0),7830x01,784USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,7850x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);786if (ret < 0) {787err("reg_w failed %d", ret);788gspca_dev->usb_err = ret;789}790}791792static void reg_w(struct gspca_dev *gspca_dev, u16 reg, u8 val)793{794PDEBUG(D_USBO, "reg_w [%04x] = %02x", reg, val);795reg_w_i(gspca_dev, reg, val);796}797798static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)799{800struct usb_device *udev = gspca_dev->dev;801int ret;802803if (gspca_dev->usb_err < 0)804return 0;805ret = usb_control_msg(udev,806usb_rcvctrlpipe(udev, 0),8070x01,808USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,8090x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);810PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]);811if (ret < 0) {812err("reg_r err %d", ret);813gspca_dev->usb_err = ret;814}815return gspca_dev->usb_buf[0];816}817818static int sccb_check_status(struct gspca_dev *gspca_dev)819{820u8 data;821int i;822823for (i = 0; i < 5; i++) {824data = reg_r(gspca_dev, OV534_REG_STATUS);825826switch (data) {827case 0x00:828return 1;829case 0x04:830return 0;831case 0x03:832break;833default:834PDEBUG(D_USBI|D_USBO,835"sccb status 0x%02x, attempt %d/5",836data, i + 1);837}838}839return 0;840}841842static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)843{844PDEBUG(D_USBO, "sccb_write [%02x] = %02x", reg, val);845reg_w_i(gspca_dev, OV534_REG_SUBADDR, reg);846reg_w_i(gspca_dev, OV534_REG_WRITE, val);847reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);848849if (!sccb_check_status(gspca_dev))850err("sccb_write failed");851}852853static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)854{855reg_w(gspca_dev, OV534_REG_SUBADDR, reg);856reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);857if (!sccb_check_status(gspca_dev))858err("sccb_read failed 1");859860reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);861if (!sccb_check_status(gspca_dev))862err("sccb_read failed 2");863864return reg_r(gspca_dev, OV534_REG_READ);865}866867/* output a bridge sequence (reg - val) */868static void reg_w_array(struct gspca_dev *gspca_dev,869const u8 (*data)[2], int len)870{871while (--len >= 0) {872reg_w(gspca_dev, (*data)[0], (*data)[1]);873data++;874}875}876877/* output a sensor sequence (reg - val) */878static void sccb_w_array(struct gspca_dev *gspca_dev,879const u8 (*data)[2], int len)880{881while (--len >= 0) {882if ((*data)[0] != 0xff) {883sccb_write(gspca_dev, (*data)[0], (*data)[1]);884} else {885sccb_read(gspca_dev, (*data)[1]);886sccb_write(gspca_dev, 0xff, 0x00);887}888data++;889}890}891892/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.893* (direction and output)? */894static void set_led(struct gspca_dev *gspca_dev, int status)895{896u8 data;897898PDEBUG(D_CONF, "led status: %d", status);899900data = reg_r(gspca_dev, 0x21);901data |= 0x80;902reg_w(gspca_dev, 0x21, data);903904data = reg_r(gspca_dev, 0x23);905if (status)906data |= 0x80;907else908data &= ~0x80;909910reg_w(gspca_dev, 0x23, data);911912if (!status) {913data = reg_r(gspca_dev, 0x21);914data &= ~0x80;915reg_w(gspca_dev, 0x21, data);916}917}918919static void setbrightness(struct gspca_dev *gspca_dev)920{921struct sd *sd = (struct sd *) gspca_dev;922u8 val;923924val = sd->brightness;925if (val < 8)926val = 15 - val; /* f .. 8 */927else928val = val - 8; /* 0 .. 7 */929sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */9300x0f | (val << 4));931}932933static void setcontrast(struct gspca_dev *gspca_dev)934{935struct sd *sd = (struct sd *) gspca_dev;936937sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */938sd->contrast << 4);939}940941static void setautogain(struct gspca_dev *gspca_dev)942{943struct sd *sd = (struct sd *) gspca_dev;944u8 val;945946/*fixme: should adjust agc/awb/aec by different controls */947val = sccb_read(gspca_dev, 0x13); /* com8 */948sccb_write(gspca_dev, 0xff, 0x00);949if (sd->autogain)950val |= 0x05; /* agc & aec */951else952val &= 0xfa;953sccb_write(gspca_dev, 0x13, val);954}955956static void setexposure(struct gspca_dev *gspca_dev)957{958struct sd *sd = (struct sd *) gspca_dev;959u8 val;960static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e};961962sccb_write(gspca_dev, 0x10, /* aec[9:2] */963expo[sd->exposure]);964965val = sccb_read(gspca_dev, 0x13); /* com8 */966sccb_write(gspca_dev, 0xff, 0x00);967sccb_write(gspca_dev, 0x13, val);968969val = sccb_read(gspca_dev, 0xa1); /* aech */970sccb_write(gspca_dev, 0xff, 0x00);971sccb_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */972}973974static void setsharpness(struct gspca_dev *gspca_dev)975{976struct sd *sd = (struct sd *) gspca_dev;977s8 val;978979val = sd->sharpness;980if (val < 0) { /* auto */981val = sccb_read(gspca_dev, 0x42); /* com17 */982sccb_write(gspca_dev, 0xff, 0x00);983sccb_write(gspca_dev, 0x42, val | 0x40);984/* Edge enhancement strength auto adjust */985return;986}987if (val != 0)988val = 1 << (val - 1);989sccb_write(gspca_dev, 0x3f, /* edge - edge enhance. factor */990val);991val = sccb_read(gspca_dev, 0x42); /* com17 */992sccb_write(gspca_dev, 0xff, 0x00);993sccb_write(gspca_dev, 0x42, val & 0xbf);994}995996static void setsatur(struct gspca_dev *gspca_dev)997{998struct sd *sd = (struct sd *) gspca_dev;999u8 val1, val2, val3;1000static const u8 matrix[5][2] = {1001{0x14, 0x38},1002{0x1e, 0x54},1003{0x28, 0x70},1004{0x32, 0x8c},1005{0x48, 0x90}1006};10071008val1 = matrix[sd->satur][0];1009val2 = matrix[sd->satur][1];1010val3 = val1 + val2;1011sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */1012sccb_write(gspca_dev, 0x50, val3);1013sccb_write(gspca_dev, 0x51, 0x00);1014sccb_write(gspca_dev, 0x52, val1);1015sccb_write(gspca_dev, 0x53, val2);1016sccb_write(gspca_dev, 0x54, val3);1017sccb_write(gspca_dev, 0x58, 0x1a); /* mtxs - coeff signs */10181019val1 = sccb_read(gspca_dev, 0x41); /* com16 */1020sccb_write(gspca_dev, 0xff, 0x00);1021sccb_write(gspca_dev, 0x41, val1);1022}10231024static void setfreq(struct gspca_dev *gspca_dev)1025{1026struct sd *sd = (struct sd *) gspca_dev;1027u8 val;10281029val = sccb_read(gspca_dev, 0x13); /* com8 */1030sccb_write(gspca_dev, 0xff, 0x00);1031if (sd->freq == 0) {1032sccb_write(gspca_dev, 0x13, val & 0xdf);1033return;1034}1035sccb_write(gspca_dev, 0x13, val | 0x20);10361037val = sccb_read(gspca_dev, 0x42); /* com17 */1038sccb_write(gspca_dev, 0xff, 0x00);1039if (sd->freq == 1)1040val |= 0x01;1041else1042val &= 0xfe;1043sccb_write(gspca_dev, 0x42, val);1044}10451046/* this function is called at probe time */1047static int sd_config(struct gspca_dev *gspca_dev,1048const struct usb_device_id *id)1049{1050struct sd *sd = (struct sd *) gspca_dev;1051struct cam *cam;10521053cam = &gspca_dev->cam;10541055cam->cam_mode = ov965x_mode;1056cam->nmodes = ARRAY_SIZE(ov965x_mode);10571058sd->brightness = BRIGHTNESS_DEF;1059sd->contrast = CONTRAST_DEF;1060#if AUTOGAIN_DEF != 01061sd->autogain = AUTOGAIN_DEF;1062gspca_dev->ctrl_inac |= (1 << EXPO_IDX);1063#endif1064#if EXPO_DEF != 01065sd->exposure = EXPO_DEF;1066#endif1067#if SHARPNESS_DEF != 01068sd->sharpness = SHARPNESS_DEF;1069#endif1070sd->satur = SATUR_DEF;1071sd->freq = FREQ_DEF;10721073return 0;1074}10751076/* this function is called at probe and resume time */1077static int sd_init(struct gspca_dev *gspca_dev)1078{1079u16 sensor_id;10801081/* reset bridge */1082reg_w(gspca_dev, 0xe7, 0x3a);1083reg_w(gspca_dev, 0xe0, 0x08);1084msleep(100);10851086/* initialize the sensor address */1087reg_w(gspca_dev, OV534_REG_ADDRESS, 0x60);10881089/* reset sensor */1090sccb_write(gspca_dev, 0x12, 0x80);1091msleep(10);10921093/* probe the sensor */1094sccb_read(gspca_dev, 0x0a);1095sensor_id = sccb_read(gspca_dev, 0x0a) << 8;1096sccb_read(gspca_dev, 0x0b);1097sensor_id |= sccb_read(gspca_dev, 0x0b);1098PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);10991100/* initialize */1101reg_w_array(gspca_dev, bridge_init,1102ARRAY_SIZE(bridge_init));1103sccb_w_array(gspca_dev, sensor_init,1104ARRAY_SIZE(sensor_init));1105reg_w_array(gspca_dev, bridge_init_2,1106ARRAY_SIZE(bridge_init_2));1107sccb_w_array(gspca_dev, sensor_init_2,1108ARRAY_SIZE(sensor_init_2));1109reg_w(gspca_dev, 0xe0, 0x00);1110reg_w(gspca_dev, 0xe0, 0x01);1111set_led(gspca_dev, 0);1112reg_w(gspca_dev, 0xe0, 0x00);11131114return gspca_dev->usb_err;1115}11161117static int sd_start(struct gspca_dev *gspca_dev)1118{1119switch (gspca_dev->curr_mode) {1120case QVGA_MODE: /* 320x240 */1121sccb_w_array(gspca_dev, sensor_start_1_vga,1122ARRAY_SIZE(sensor_start_1_vga));1123reg_w_array(gspca_dev, bridge_start_qvga,1124ARRAY_SIZE(bridge_start_qvga));1125sccb_w_array(gspca_dev, sensor_start_2_qvga,1126ARRAY_SIZE(sensor_start_2_qvga));1127break;1128case VGA_MODE: /* 640x480 */1129sccb_w_array(gspca_dev, sensor_start_1_vga,1130ARRAY_SIZE(sensor_start_1_vga));1131reg_w_array(gspca_dev, bridge_start_vga,1132ARRAY_SIZE(bridge_start_vga));1133sccb_w_array(gspca_dev, sensor_start_2_vga,1134ARRAY_SIZE(sensor_start_2_vga));1135break;1136case SVGA_MODE: /* 800x600 */1137sccb_w_array(gspca_dev, sensor_start_1_svga,1138ARRAY_SIZE(sensor_start_1_svga));1139reg_w_array(gspca_dev, bridge_start_svga,1140ARRAY_SIZE(bridge_start_svga));1141sccb_w_array(gspca_dev, sensor_start_2_svga,1142ARRAY_SIZE(sensor_start_2_svga));1143break;1144case XGA_MODE: /* 1024x768 */1145sccb_w_array(gspca_dev, sensor_start_1_xga,1146ARRAY_SIZE(sensor_start_1_xga));1147reg_w_array(gspca_dev, bridge_start_xga,1148ARRAY_SIZE(bridge_start_xga));1149sccb_w_array(gspca_dev, sensor_start_2_svga,1150ARRAY_SIZE(sensor_start_2_svga));1151break;1152default:1153/* case SXGA_MODE: * 1280x1024 */1154sccb_w_array(gspca_dev, sensor_start_1_sxga,1155ARRAY_SIZE(sensor_start_1_sxga));1156reg_w_array(gspca_dev, bridge_start_sxga,1157ARRAY_SIZE(bridge_start_sxga));1158sccb_w_array(gspca_dev, sensor_start_2_sxga,1159ARRAY_SIZE(sensor_start_2_sxga));1160break;1161}1162setfreq(gspca_dev);1163setautogain(gspca_dev);1164setbrightness(gspca_dev);1165setcontrast(gspca_dev);1166setexposure(gspca_dev);1167setsharpness(gspca_dev);1168setsatur(gspca_dev);11691170reg_w(gspca_dev, 0xe0, 0x00);1171reg_w(gspca_dev, 0xe0, 0x00);1172set_led(gspca_dev, 1);1173return gspca_dev->usb_err;1174}11751176static void sd_stopN(struct gspca_dev *gspca_dev)1177{1178reg_w(gspca_dev, 0xe0, 0x01);1179set_led(gspca_dev, 0);1180reg_w(gspca_dev, 0xe0, 0x00);1181}11821183/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */1184#define UVC_STREAM_EOH (1 << 7)1185#define UVC_STREAM_ERR (1 << 6)1186#define UVC_STREAM_STI (1 << 5)1187#define UVC_STREAM_RES (1 << 4)1188#define UVC_STREAM_SCR (1 << 3)1189#define UVC_STREAM_PTS (1 << 2)1190#define UVC_STREAM_EOF (1 << 1)1191#define UVC_STREAM_FID (1 << 0)11921193static void sd_pkt_scan(struct gspca_dev *gspca_dev,1194u8 *data, int len)1195{1196struct sd *sd = (struct sd *) gspca_dev;1197__u32 this_pts;1198u8 this_fid;1199int remaining_len = len;12001201do {1202len = min(remaining_len, 2040);12031204/* Payloads are prefixed with a UVC-style header. We1205consider a frame to start when the FID toggles, or the PTS1206changes. A frame ends when EOF is set, and we've received1207the correct number of bytes. */12081209/* Verify UVC header. Header length is always 12 */1210if (data[0] != 12 || len < 12) {1211PDEBUG(D_PACK, "bad header");1212goto discard;1213}12141215/* Check errors */1216if (data[1] & UVC_STREAM_ERR) {1217PDEBUG(D_PACK, "payload error");1218goto discard;1219}12201221/* Extract PTS and FID */1222if (!(data[1] & UVC_STREAM_PTS)) {1223PDEBUG(D_PACK, "PTS not present");1224goto discard;1225}1226this_pts = (data[5] << 24) | (data[4] << 16)1227| (data[3] << 8) | data[2];1228this_fid = data[1] & UVC_STREAM_FID;12291230/* If PTS or FID has changed, start a new frame. */1231if (this_pts != sd->last_pts || this_fid != sd->last_fid) {1232if (gspca_dev->last_packet_type == INTER_PACKET)1233gspca_frame_add(gspca_dev, LAST_PACKET,1234NULL, 0);1235sd->last_pts = this_pts;1236sd->last_fid = this_fid;1237gspca_frame_add(gspca_dev, FIRST_PACKET,1238data + 12, len - 12);1239/* If this packet is marked as EOF, end the frame */1240} else if (data[1] & UVC_STREAM_EOF) {1241sd->last_pts = 0;1242gspca_frame_add(gspca_dev, LAST_PACKET,1243data + 12, len - 12);1244} else {12451246/* Add the data from this payload */1247gspca_frame_add(gspca_dev, INTER_PACKET,1248data + 12, len - 12);1249}12501251/* Done this payload */1252goto scan_next;12531254discard:1255/* Discard data until a new frame starts. */1256gspca_dev->last_packet_type = DISCARD_PACKET;12571258scan_next:1259remaining_len -= len;1260data += len;1261} while (remaining_len > 0);1262}12631264/* controls */1265static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)1266{1267struct sd *sd = (struct sd *) gspca_dev;12681269sd->brightness = val;1270if (gspca_dev->streaming)1271setbrightness(gspca_dev);1272return gspca_dev->usb_err;1273}12741275static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)1276{1277struct sd *sd = (struct sd *) gspca_dev;12781279*val = sd->brightness;1280return 0;1281}12821283static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)1284{1285struct sd *sd = (struct sd *) gspca_dev;12861287sd->contrast = val;1288if (gspca_dev->streaming)1289setcontrast(gspca_dev);1290return gspca_dev->usb_err;1291}12921293static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)1294{1295struct sd *sd = (struct sd *) gspca_dev;12961297*val = sd->contrast;1298return 0;1299}13001301static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)1302{1303struct sd *sd = (struct sd *) gspca_dev;13041305sd->autogain = val;13061307if (gspca_dev->streaming) {1308if (val)1309gspca_dev->ctrl_inac |= (1 << EXPO_IDX);1310else1311gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX);1312setautogain(gspca_dev);1313}1314return gspca_dev->usb_err;1315}13161317static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)1318{1319struct sd *sd = (struct sd *) gspca_dev;13201321*val = sd->autogain;1322return 0;1323}13241325static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)1326{1327struct sd *sd = (struct sd *) gspca_dev;13281329sd->exposure = val;1330if (gspca_dev->streaming)1331setexposure(gspca_dev);1332return gspca_dev->usb_err;1333}13341335static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)1336{1337struct sd *sd = (struct sd *) gspca_dev;13381339*val = sd->exposure;1340return 0;1341}13421343static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)1344{1345struct sd *sd = (struct sd *) gspca_dev;13461347sd->sharpness = val;1348if (gspca_dev->streaming)1349setsharpness(gspca_dev);1350return gspca_dev->usb_err;1351}13521353static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)1354{1355struct sd *sd = (struct sd *) gspca_dev;13561357*val = sd->sharpness;1358return 0;1359}13601361static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val)1362{1363struct sd *sd = (struct sd *) gspca_dev;13641365sd->satur = val;1366if (gspca_dev->streaming)1367setsatur(gspca_dev);1368return gspca_dev->usb_err;1369}13701371static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val)1372{1373struct sd *sd = (struct sd *) gspca_dev;13741375*val = sd->satur;1376return 0;1377}1378static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)1379{1380struct sd *sd = (struct sd *) gspca_dev;13811382sd->freq = val;1383if (gspca_dev->streaming)1384setfreq(gspca_dev);1385return gspca_dev->usb_err;1386}13871388static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)1389{1390struct sd *sd = (struct sd *) gspca_dev;13911392*val = sd->freq;1393return 0;1394}13951396static int sd_querymenu(struct gspca_dev *gspca_dev,1397struct v4l2_querymenu *menu)1398{1399switch (menu->id) {1400case V4L2_CID_POWER_LINE_FREQUENCY:1401switch (menu->index) {1402case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */1403strcpy((char *) menu->name, "NoFliker");1404return 0;1405case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */1406strcpy((char *) menu->name, "50 Hz");1407return 0;1408case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */1409strcpy((char *) menu->name, "60 Hz");1410return 0;1411}1412break;1413}1414return -EINVAL;1415}14161417/* sub-driver description */1418static const struct sd_desc sd_desc = {1419.name = MODULE_NAME,1420.ctrls = sd_ctrls,1421.nctrls = ARRAY_SIZE(sd_ctrls),1422.config = sd_config,1423.init = sd_init,1424.start = sd_start,1425.stopN = sd_stopN,1426.pkt_scan = sd_pkt_scan,1427.querymenu = sd_querymenu,1428};14291430/* -- module initialisation -- */1431static const struct usb_device_id device_table[] = {1432{USB_DEVICE(0x06f8, 0x3003)},1433{}1434};14351436MODULE_DEVICE_TABLE(usb, device_table);14371438/* -- device connect -- */1439static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)1440{1441return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),1442THIS_MODULE);1443}14441445static struct usb_driver sd_driver = {1446.name = MODULE_NAME,1447.id_table = device_table,1448.probe = sd_probe,1449.disconnect = gspca_disconnect,1450#ifdef CONFIG_PM1451.suspend = gspca_suspend,1452.resume = gspca_resume,1453#endif1454};14551456/* -- module insert / remove -- */1457static int __init sd_mod_init(void)1458{1459return usb_register(&sd_driver);1460}14611462static void __exit sd_mod_exit(void)1463{1464usb_deregister(&sd_driver);1465}14661467module_init(sd_mod_init);1468module_exit(sd_mod_exit);146914701471