Path: blob/master/drivers/media/video/gspca/t613.c
17602 views
/*1* T613 subdriver2*3* Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*19*Notes: * t613 + tas5130A20* * Focus to light do not balance well as in win.21* Quality in win is not good, but its kinda better.22* * Fix some "extraneous bytes", most of apps will show the image anyway23* * Gamma table, is there, but its really doing something?24* * 7~8 Fps, its ok, max on win its 10.25* Costantino Leandro26*/2728#define MODULE_NAME "t613"2930#include <linux/slab.h>31#include "gspca.h"3233#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)3435MODULE_AUTHOR("Leandro Costantino <[email protected]>");36MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");37MODULE_LICENSE("GPL");3839struct sd {40struct gspca_dev gspca_dev; /* !! must be the first item */4142u8 brightness;43u8 contrast;44u8 colors;45u8 autogain;46u8 gamma;47u8 sharpness;48u8 freq;49u8 red_gain;50u8 blue_gain;51u8 green_gain;52u8 awb; /* set default r/g/b and activate */53u8 mirror;54u8 effect;5556u8 sensor;57};58enum sensors {59SENSOR_OM6802,60SENSOR_OTHER,61SENSOR_TAS5130A,62SENSOR_LT168G, /* must verify if this is the actual model */63};6465/* V4L2 controls supported by the driver */66static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);67static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);68static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);69static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);70static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);71static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);72static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);73static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);74static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);75static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);76static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);77static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);78static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);79static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);8081static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);82static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);83static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);84static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);85static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);86static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);87static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);88static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);8990static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);91static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);92static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);93static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);9495static const struct ctrl sd_ctrls[] = {96{97{98.id = V4L2_CID_BRIGHTNESS,99.type = V4L2_CTRL_TYPE_INTEGER,100.name = "Brightness",101.minimum = 0,102.maximum = 14,103.step = 1,104#define BRIGHTNESS_DEF 8105.default_value = BRIGHTNESS_DEF,106},107.set = sd_setbrightness,108.get = sd_getbrightness,109},110{111{112.id = V4L2_CID_CONTRAST,113.type = V4L2_CTRL_TYPE_INTEGER,114.name = "Contrast",115.minimum = 0,116.maximum = 0x0d,117.step = 1,118#define CONTRAST_DEF 0x07119.default_value = CONTRAST_DEF,120},121.set = sd_setcontrast,122.get = sd_getcontrast,123},124{125{126.id = V4L2_CID_SATURATION,127.type = V4L2_CTRL_TYPE_INTEGER,128.name = "Color",129.minimum = 0,130.maximum = 0x0f,131.step = 1,132#define COLORS_DEF 0x05133.default_value = COLORS_DEF,134},135.set = sd_setcolors,136.get = sd_getcolors,137},138#define GAMMA_MAX 16139#define GAMMA_DEF 10140{141{142.id = V4L2_CID_GAMMA, /* (gamma on win) */143.type = V4L2_CTRL_TYPE_INTEGER,144.name = "Gamma",145.minimum = 0,146.maximum = GAMMA_MAX - 1,147.step = 1,148.default_value = GAMMA_DEF,149},150.set = sd_setgamma,151.get = sd_getgamma,152},153{154{155.id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,156* some apps dont bring up the157* backligth_compensation control) */158.type = V4L2_CTRL_TYPE_INTEGER,159.name = "Low Light",160.minimum = 0,161.maximum = 1,162.step = 1,163#define AUTOGAIN_DEF 0x01164.default_value = AUTOGAIN_DEF,165},166.set = sd_setlowlight,167.get = sd_getlowlight,168},169{170{171.id = V4L2_CID_HFLIP,172.type = V4L2_CTRL_TYPE_BOOLEAN,173.name = "Mirror Image",174.minimum = 0,175.maximum = 1,176.step = 1,177#define MIRROR_DEF 0178.default_value = MIRROR_DEF,179},180.set = sd_setmirror,181.get = sd_getmirror182},183{184{185.id = V4L2_CID_POWER_LINE_FREQUENCY,186.type = V4L2_CTRL_TYPE_MENU,187.name = "Light Frequency Filter",188.minimum = 1, /* 1 -> 0x50, 2->0x60 */189.maximum = 2,190.step = 1,191#define FREQ_DEF 1192.default_value = FREQ_DEF,193},194.set = sd_setfreq,195.get = sd_getfreq},196197{198{199.id = V4L2_CID_AUTO_WHITE_BALANCE,200.type = V4L2_CTRL_TYPE_INTEGER,201.name = "Auto White Balance",202.minimum = 0,203.maximum = 1,204.step = 1,205#define AWB_DEF 0206.default_value = AWB_DEF,207},208.set = sd_setawb,209.get = sd_getawb210},211{212{213.id = V4L2_CID_SHARPNESS,214.type = V4L2_CTRL_TYPE_INTEGER,215.name = "Sharpness",216.minimum = 0,217.maximum = 15,218.step = 1,219#define SHARPNESS_DEF 0x06220.default_value = SHARPNESS_DEF,221},222.set = sd_setsharpness,223.get = sd_getsharpness,224},225{226{227.id = V4L2_CID_EFFECTS,228.type = V4L2_CTRL_TYPE_MENU,229.name = "Webcam Effects",230.minimum = 0,231.maximum = 4,232.step = 1,233#define EFFECTS_DEF 0234.default_value = EFFECTS_DEF,235},236.set = sd_seteffect,237.get = sd_geteffect238},239{240{241.id = V4L2_CID_BLUE_BALANCE,242.type = V4L2_CTRL_TYPE_INTEGER,243.name = "Blue Balance",244.minimum = 0x10,245.maximum = 0x40,246.step = 1,247#define BLUE_GAIN_DEF 0x20248.default_value = BLUE_GAIN_DEF,249},250.set = sd_setblue_gain,251.get = sd_getblue_gain,252},253{254{255.id = V4L2_CID_RED_BALANCE,256.type = V4L2_CTRL_TYPE_INTEGER,257.name = "Red Balance",258.minimum = 0x10,259.maximum = 0x40,260.step = 1,261#define RED_GAIN_DEF 0x20262.default_value = RED_GAIN_DEF,263},264.set = sd_setred_gain,265.get = sd_getred_gain,266},267{268{269.id = V4L2_CID_GAIN,270.type = V4L2_CTRL_TYPE_INTEGER,271.name = "Gain",272.minimum = 0x10,273.maximum = 0x40,274.step = 1,275#define GAIN_DEF 0x20276.default_value = GAIN_DEF,277},278.set = sd_setgain,279.get = sd_getgain,280},281};282283static const struct v4l2_pix_format vga_mode_t16[] = {284{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,285.bytesperline = 160,286.sizeimage = 160 * 120 * 4 / 8 + 590,287.colorspace = V4L2_COLORSPACE_JPEG,288.priv = 4},289{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,290.bytesperline = 176,291.sizeimage = 176 * 144 * 3 / 8 + 590,292.colorspace = V4L2_COLORSPACE_JPEG,293.priv = 3},294{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,295.bytesperline = 320,296.sizeimage = 320 * 240 * 3 / 8 + 590,297.colorspace = V4L2_COLORSPACE_JPEG,298.priv = 2},299{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,300.bytesperline = 352,301.sizeimage = 352 * 288 * 3 / 8 + 590,302.colorspace = V4L2_COLORSPACE_JPEG,303.priv = 1},304{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,305.bytesperline = 640,306.sizeimage = 640 * 480 * 3 / 8 + 590,307.colorspace = V4L2_COLORSPACE_JPEG,308.priv = 0},309};310311/* sensor specific data */312struct additional_sensor_data {313const u8 n3[6];314const u8 *n4, n4sz;315const u8 reg80, reg8e;316const u8 nset8[6];317const u8 data1[10];318const u8 data2[9];319const u8 data3[9];320const u8 data5[6];321const u8 stream[4];322};323324static const u8 n4_om6802[] = {3250x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,3260x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,3270x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,3280xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,3290xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,3300xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,3310x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,3320x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,3330xac, 0x84, 0xad, 0x86, 0xaf, 0x46334};335static const u8 n4_other[] = {3360x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,3370x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,3380x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,3390x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,3400xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,3410xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,3420xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,3430xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00344};345static const u8 n4_tas5130a[] = {3460x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,3470x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,3480x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,3490xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,3500xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,3510xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,3520xc6, 0xda353};354static const u8 n4_lt168g[] = {3550x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,3560x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,3570x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,3580x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,3590xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,3600xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,3610xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,3620xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,3630xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80364};365366static const struct additional_sensor_data sensor_data[] = {367[SENSOR_OM6802] = {368.n3 =369{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},370.n4 = n4_om6802,371.n4sz = sizeof n4_om6802,372.reg80 = 0x3c,373.reg8e = 0x33,374.nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},375.data1 =376{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,3770xb3, 0xfc},378.data2 =379{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,3800xff},381.data3 =382{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,3830xff},384.data5 = /* this could be removed later */385{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},386.stream =387{0x0b, 0x04, 0x0a, 0x78},388},389[SENSOR_OTHER] = {390.n3 =391{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},392.n4 = n4_other,393.n4sz = sizeof n4_other,394.reg80 = 0xac,395.reg8e = 0xb8,396.nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},397.data1 =398{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,3990xe8, 0xfc},400.data2 =401{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,4020xd9},403.data3 =404{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,4050xd9},406.data5 =407{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},408.stream =409{0x0b, 0x04, 0x0a, 0x00},410},411[SENSOR_TAS5130A] = {412.n3 =413{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},414.n4 = n4_tas5130a,415.n4sz = sizeof n4_tas5130a,416.reg80 = 0x3c,417.reg8e = 0xb4,418.nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},419.data1 =420{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,4210xc8, 0xfc},422.data2 =423{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,4240xe0},425.data3 =426{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,4270xe0},428.data5 =429{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},430.stream =431{0x0b, 0x04, 0x0a, 0x40},432},433[SENSOR_LT168G] = {434.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},435.n4 = n4_lt168g,436.n4sz = sizeof n4_lt168g,437.reg80 = 0x7c,438.reg8e = 0xb3,439.nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},440.data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,4410xb0, 0xf4},442.data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,4430xff},444.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,4450xff},446.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},447.stream = {0x0b, 0x04, 0x0a, 0x28},448},449};450451#define MAX_EFFECTS 7452/* easily done by soft, this table could be removed,453* i keep it here just in case */454static char *effects_control[MAX_EFFECTS] = {455"Normal",456"Emboss", /* disabled */457"Monochrome",458"Sepia",459"Sketch",460"Sun Effect", /* disabled */461"Negative",462};463static const u8 effects_table[MAX_EFFECTS][6] = {464{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */465{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */466{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */467{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */468{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */469{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */470{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */471};472473static const u8 gamma_table[GAMMA_MAX][17] = {474/* gamma table from cam1690.ini */475{0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */4760x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,4770xff},478{0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */4790x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,4800xff},481{0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */4820x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,4830xff},484{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */4850x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,4860xff},487{0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */4880x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,4890xff},490{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */4910x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,4920xff},493{0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */4940x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,4950xff},496{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */4970x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,4980xff},499{0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */5000x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,5010xff},502{0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */5030x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,5040xff},505{0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */5060x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,5070xff},508{0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */5090xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,5100xff},511{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */5120xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,5130xff},514{0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */5150xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,5160xff},517{0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */5180xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,5190xff},520{0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */5210xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,5220xff}523};524525static const u8 tas5130a_sensor_init[][8] = {526{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},527{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},528{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},529};530531static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};532533/* read 1 byte */534static u8 reg_r(struct gspca_dev *gspca_dev,535u16 index)536{537usb_control_msg(gspca_dev->dev,538usb_rcvctrlpipe(gspca_dev->dev, 0),5390, /* request */540USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,5410, /* value */542index,543gspca_dev->usb_buf, 1, 500);544return gspca_dev->usb_buf[0];545}546547static void reg_w(struct gspca_dev *gspca_dev,548u16 index)549{550usb_control_msg(gspca_dev->dev,551usb_sndctrlpipe(gspca_dev->dev, 0),5520,553USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,5540, index,555NULL, 0, 500);556}557558static void reg_w_buf(struct gspca_dev *gspca_dev,559const u8 *buffer, u16 len)560{561if (len <= USB_BUF_SZ) {562memcpy(gspca_dev->usb_buf, buffer, len);563usb_control_msg(gspca_dev->dev,564usb_sndctrlpipe(gspca_dev->dev, 0),5650,566USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,5670x01, 0,568gspca_dev->usb_buf, len, 500);569} else {570u8 *tmpbuf;571572tmpbuf = kmemdup(buffer, len, GFP_KERNEL);573if (!tmpbuf) {574err("Out of memory");575return;576}577usb_control_msg(gspca_dev->dev,578usb_sndctrlpipe(gspca_dev->dev, 0),5790,580USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,5810x01, 0,582tmpbuf, len, 500);583kfree(tmpbuf);584}585}586587/* write values to consecutive registers */588static void reg_w_ixbuf(struct gspca_dev *gspca_dev,589u8 reg,590const u8 *buffer, u16 len)591{592int i;593u8 *p, *tmpbuf;594595if (len * 2 <= USB_BUF_SZ) {596p = tmpbuf = gspca_dev->usb_buf;597} else {598p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);599if (!tmpbuf) {600err("Out of memory");601return;602}603}604i = len;605while (--i >= 0) {606*p++ = reg++;607*p++ = *buffer++;608}609usb_control_msg(gspca_dev->dev,610usb_sndctrlpipe(gspca_dev->dev, 0),6110,612USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,6130x01, 0,614tmpbuf, len * 2, 500);615if (len * 2 > USB_BUF_SZ)616kfree(tmpbuf);617}618619static void om6802_sensor_init(struct gspca_dev *gspca_dev)620{621int i;622const u8 *p;623u8 byte;624u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};625static const u8 sensor_init[] = {6260xdf, 0x6d,6270xdd, 0x18,6280x5a, 0xe0,6290x5c, 0x07,6300x5d, 0xb0,6310x5e, 0x1e,6320x60, 0x71,6330xef, 0x00,6340xe9, 0x00,6350xea, 0x00,6360x90, 0x24,6370x91, 0xb2,6380x82, 0x32,6390xfd, 0x41,6400x00 /* table end */641};642643reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);644msleep(100);645i = 4;646while (--i > 0) {647byte = reg_r(gspca_dev, 0x0060);648if (!(byte & 0x01))649break;650msleep(100);651}652byte = reg_r(gspca_dev, 0x0063);653if (byte != 0x17) {654err("Bad sensor reset %02x", byte);655/* continue? */656}657658p = sensor_init;659while (*p != 0) {660val[1] = *p++;661val[3] = *p++;662if (*p == 0)663reg_w(gspca_dev, 0x3c80);664reg_w_buf(gspca_dev, val, sizeof val);665i = 4;666while (--i >= 0) {667msleep(15);668byte = reg_r(gspca_dev, 0x60);669if (!(byte & 0x01))670break;671}672}673msleep(15);674reg_w(gspca_dev, 0x3c80);675}676677/* this function is called at probe time */678static int sd_config(struct gspca_dev *gspca_dev,679const struct usb_device_id *id)680{681struct sd *sd = (struct sd *) gspca_dev;682struct cam *cam;683684cam = &gspca_dev->cam;685686cam->cam_mode = vga_mode_t16;687cam->nmodes = ARRAY_SIZE(vga_mode_t16);688689sd->brightness = BRIGHTNESS_DEF;690sd->contrast = CONTRAST_DEF;691sd->colors = COLORS_DEF;692sd->gamma = GAMMA_DEF;693sd->autogain = AUTOGAIN_DEF;694sd->mirror = MIRROR_DEF;695sd->freq = FREQ_DEF;696sd->awb = AWB_DEF;697sd->sharpness = SHARPNESS_DEF;698sd->effect = EFFECTS_DEF;699sd->red_gain = RED_GAIN_DEF;700sd->blue_gain = BLUE_GAIN_DEF;701sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;702703return 0;704}705706static void setbrightness(struct gspca_dev *gspca_dev)707{708struct sd *sd = (struct sd *) gspca_dev;709unsigned int brightness;710u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };711712brightness = sd->brightness;713if (brightness < 7) {714set6[1] = 0x26;715set6[3] = 0x70 - brightness * 0x10;716} else {717set6[3] = 0x00 + ((brightness - 7) * 0x10);718}719720reg_w_buf(gspca_dev, set6, sizeof set6);721}722723static void setcontrast(struct gspca_dev *gspca_dev)724{725struct sd *sd = (struct sd *) gspca_dev;726unsigned int contrast = sd->contrast;727u16 reg_to_write;728729if (contrast < 7)730reg_to_write = 0x8ea9 - contrast * 0x200;731else732reg_to_write = 0x00a9 + (contrast - 7) * 0x200;733734reg_w(gspca_dev, reg_to_write);735}736737static void setcolors(struct gspca_dev *gspca_dev)738{739struct sd *sd = (struct sd *) gspca_dev;740u16 reg_to_write;741742reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */743reg_w(gspca_dev, reg_to_write);744}745746static void setgamma(struct gspca_dev *gspca_dev)747{748struct sd *sd = (struct sd *) gspca_dev;749750PDEBUG(D_CONF, "Gamma: %d", sd->gamma);751reg_w_ixbuf(gspca_dev, 0x90,752gamma_table[sd->gamma], sizeof gamma_table[0]);753}754755static void setRGB(struct gspca_dev *gspca_dev)756{757struct sd *sd = (struct sd *) gspca_dev;758u8 all_gain_reg[6] =759{0x87, 0x00, 0x88, 0x00, 0x89, 0x00};760761all_gain_reg[1] = sd->red_gain;762all_gain_reg[3] = sd->blue_gain;763all_gain_reg[5] = sd->green_gain;764reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);765}766767/* Generic fnc for r/b balance, exposure and awb */768static void setawb(struct gspca_dev *gspca_dev)769{770struct sd *sd = (struct sd *) gspca_dev;771u16 reg80;772773reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;774775/* on awb leave defaults values */776if (!sd->awb) {777/* shoud we wait here.. */778/* update and reset RGB gains with webcam values */779sd->red_gain = reg_r(gspca_dev, 0x0087);780sd->blue_gain = reg_r(gspca_dev, 0x0088);781sd->green_gain = reg_r(gspca_dev, 0x0089);782reg80 &= ~0x0400; /* AWB off */783}784reg_w(gspca_dev, reg80);785reg_w(gspca_dev, reg80);786}787788static void init_gains(struct gspca_dev *gspca_dev)789{790struct sd *sd = (struct sd *) gspca_dev;791u16 reg80;792u8 all_gain_reg[8] =793{0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};794795all_gain_reg[1] = sd->red_gain;796all_gain_reg[3] = sd->blue_gain;797all_gain_reg[5] = sd->green_gain;798reg80 = sensor_data[sd->sensor].reg80;799if (!sd->awb)800reg80 &= ~0x04;801all_gain_reg[7] = reg80;802reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);803804reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);805reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);806reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);807}808809static void setsharpness(struct gspca_dev *gspca_dev)810{811struct sd *sd = (struct sd *) gspca_dev;812u16 reg_to_write;813814reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;815816reg_w(gspca_dev, reg_to_write);817}818819static void setfreq(struct gspca_dev *gspca_dev)820{821struct sd *sd = (struct sd *) gspca_dev;822u8 reg66;823u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };824825switch (sd->sensor) {826case SENSOR_LT168G:827if (sd->freq != 0)828freq[3] = 0xa8;829reg66 = 0x41;830break;831case SENSOR_OM6802:832reg66 = 0xca;833break;834default:835reg66 = 0x40;836break;837}838switch (sd->freq) {839case 0: /* no flicker */840freq[3] = 0xf0;841break;842case 2: /* 60Hz */843reg66 &= ~0x40;844break;845}846freq[1] = reg66;847848reg_w_buf(gspca_dev, freq, sizeof freq);849}850851/* this function is called at probe and resume time */852static int sd_init(struct gspca_dev *gspca_dev)853{854/* some of this registers are not really neded, because855* they are overriden by setbrigthness, setcontrast, etc,856* but wont hurt anyway, and can help someone with similar webcam857* to see the initial parameters.*/858struct sd *sd = (struct sd *) gspca_dev;859const struct additional_sensor_data *sensor;860int i;861u16 sensor_id;862u8 test_byte = 0;863864static const u8 read_indexs[] =865{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,8660xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };867static const u8 n1[] =868{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};869static const u8 n2[] =870{0x08, 0x00};871872sensor_id = (reg_r(gspca_dev, 0x06) << 8)873| reg_r(gspca_dev, 0x07);874switch (sensor_id & 0xff0f) {875case 0x0801:876PDEBUG(D_PROBE, "sensor tas5130a");877sd->sensor = SENSOR_TAS5130A;878break;879case 0x0802:880PDEBUG(D_PROBE, "sensor lt168g");881sd->sensor = SENSOR_LT168G;882break;883case 0x0803:884PDEBUG(D_PROBE, "sensor 'other'");885sd->sensor = SENSOR_OTHER;886break;887case 0x0807:888PDEBUG(D_PROBE, "sensor om6802");889sd->sensor = SENSOR_OM6802;890break;891default:892err("unknown sensor %04x", sensor_id);893return -EINVAL;894}895896if (sd->sensor == SENSOR_OM6802) {897reg_w_buf(gspca_dev, n1, sizeof n1);898i = 5;899while (--i >= 0) {900reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);901test_byte = reg_r(gspca_dev, 0x0063);902msleep(100);903if (test_byte == 0x17)904break; /* OK */905}906if (i < 0) {907err("Bad sensor reset %02x", test_byte);908return -EIO;909}910reg_w_buf(gspca_dev, n2, sizeof n2);911}912913i = 0;914while (read_indexs[i] != 0x00) {915test_byte = reg_r(gspca_dev, read_indexs[i]);916PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],917test_byte);918i++;919}920921sensor = &sensor_data[sd->sensor];922reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);923reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);924925if (sd->sensor == SENSOR_LT168G) {926test_byte = reg_r(gspca_dev, 0x80);927PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,928test_byte);929reg_w(gspca_dev, 0x6c80);930}931932reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);933reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);934reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);935936reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);937reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);938reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);939940setbrightness(gspca_dev);941setcontrast(gspca_dev);942setgamma(gspca_dev);943setcolors(gspca_dev);944setsharpness(gspca_dev);945init_gains(gspca_dev);946setfreq(gspca_dev);947948reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);949reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);950reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);951952if (sd->sensor == SENSOR_LT168G) {953test_byte = reg_r(gspca_dev, 0x80);954PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,955test_byte);956reg_w(gspca_dev, 0x6c80);957}958959reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);960reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);961reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);962963return 0;964}965966static void setmirror(struct gspca_dev *gspca_dev)967{968struct sd *sd = (struct sd *) gspca_dev;969u8 hflipcmd[8] =970{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};971972if (sd->mirror)973hflipcmd[3] = 0x01;974975reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);976}977978static void seteffect(struct gspca_dev *gspca_dev)979{980struct sd *sd = (struct sd *) gspca_dev;981982reg_w_buf(gspca_dev, effects_table[sd->effect],983sizeof effects_table[0]);984if (sd->effect == 1 || sd->effect == 5) {985PDEBUG(D_CONF,986"This effect have been disabled for webcam \"safety\"");987return;988}989990if (sd->effect == 1 || sd->effect == 4)991reg_w(gspca_dev, 0x4aa6);992else993reg_w(gspca_dev, 0xfaa6);994}995996/* Is this really needed?997* i added some module parameters for test with some users */998static void poll_sensor(struct gspca_dev *gspca_dev)999{1000static const u8 poll1[] =1001{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,10020x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,10030x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,10040x60, 0x14};1005static const u8 poll2[] =1006{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,10070x73, 0x02, 0x73, 0x02, 0x60, 0x14};1008static const u8 noise03[] = /* (some differences / ms-drv) */1009{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,10100xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,10110xc2, 0x80, 0xc3, 0x10};10121013PDEBUG(D_STREAM, "[Sensor requires polling]");1014reg_w_buf(gspca_dev, poll1, sizeof poll1);1015reg_w_buf(gspca_dev, poll2, sizeof poll2);1016reg_w_buf(gspca_dev, noise03, sizeof noise03);1017}10181019static int sd_start(struct gspca_dev *gspca_dev)1020{1021struct sd *sd = (struct sd *) gspca_dev;1022const struct additional_sensor_data *sensor;1023int i, mode;1024u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };1025static const u8 t3[] =1026{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };10271028mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;1029switch (mode) {1030case 0: /* 640x480 (0x00) */1031break;1032case 1: /* 352x288 */1033t2[1] = 0x40;1034break;1035case 2: /* 320x240 */1036t2[1] = 0x10;1037break;1038case 3: /* 176x144 */1039t2[1] = 0x50;1040break;1041default:1042/* case 4: * 160x120 */1043t2[1] = 0x20;1044break;1045}10461047switch (sd->sensor) {1048case SENSOR_OM6802:1049om6802_sensor_init(gspca_dev);1050break;1051case SENSOR_TAS5130A:1052i = 0;1053for (;;) {1054reg_w_buf(gspca_dev, tas5130a_sensor_init[i],1055sizeof tas5130a_sensor_init[0]);1056if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)1057break;1058i++;1059}1060reg_w(gspca_dev, 0x3c80);1061/* just in case and to keep sync with logs (for mine) */1062reg_w_buf(gspca_dev, tas5130a_sensor_init[i],1063sizeof tas5130a_sensor_init[0]);1064reg_w(gspca_dev, 0x3c80);1065break;1066}1067sensor = &sensor_data[sd->sensor];1068setfreq(gspca_dev);1069reg_r(gspca_dev, 0x0012);1070reg_w_buf(gspca_dev, t2, sizeof t2);1071reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);1072reg_w(gspca_dev, 0x0013);1073msleep(15);1074reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);1075reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);10761077if (sd->sensor == SENSOR_OM6802)1078poll_sensor(gspca_dev);10791080return 0;1081}10821083static void sd_stopN(struct gspca_dev *gspca_dev)1084{1085struct sd *sd = (struct sd *) gspca_dev;10861087reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,1088sizeof sensor_data[sd->sensor].stream);1089reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,1090sizeof sensor_data[sd->sensor].stream);1091if (sd->sensor == SENSOR_OM6802) {1092msleep(20);1093reg_w(gspca_dev, 0x0309);1094}1095}10961097static void sd_pkt_scan(struct gspca_dev *gspca_dev,1098u8 *data, /* isoc packet */1099int len) /* iso packet length */1100{1101int pkt_type;11021103if (data[0] == 0x5a) {1104/* Control Packet, after this came the header again,1105* but extra bytes came in the packet before this,1106* sometimes an EOF arrives, sometimes not... */1107return;1108}1109data += 2;1110len -= 2;1111if (data[0] == 0xff && data[1] == 0xd8)1112pkt_type = FIRST_PACKET;1113else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)1114pkt_type = LAST_PACKET;1115else1116pkt_type = INTER_PACKET;1117gspca_frame_add(gspca_dev, pkt_type, data, len);1118}11191120static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)1121{1122struct sd *sd = (struct sd *) gspca_dev;11231124sd->blue_gain = val;1125if (gspca_dev->streaming)1126reg_w(gspca_dev, (val << 8) + 0x88);1127return 0;1128}11291130static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)1131{1132struct sd *sd = (struct sd *) gspca_dev;11331134*val = sd->blue_gain;1135return 0;1136}11371138static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)1139{1140struct sd *sd = (struct sd *) gspca_dev;11411142sd->red_gain = val;1143if (gspca_dev->streaming)1144reg_w(gspca_dev, (val << 8) + 0x87);11451146return 0;1147}11481149static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)1150{1151struct sd *sd = (struct sd *) gspca_dev;11521153*val = sd->red_gain;1154return 0;1155}11561157static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)1158{1159struct sd *sd = (struct sd *) gspca_dev;1160u16 psg, nsg;11611162psg = sd->red_gain + sd->blue_gain + sd->green_gain;1163nsg = val * 3;1164sd->red_gain = sd->red_gain * nsg / psg;1165if (sd->red_gain > 0x40)1166sd->red_gain = 0x40;1167else if (sd->red_gain < 0x10)1168sd->red_gain = 0x10;1169sd->blue_gain = sd->blue_gain * nsg / psg;1170if (sd->blue_gain > 0x40)1171sd->blue_gain = 0x40;1172else if (sd->blue_gain < 0x10)1173sd->blue_gain = 0x10;1174sd->green_gain = sd->green_gain * nsg / psg;1175if (sd->green_gain > 0x40)1176sd->green_gain = 0x40;1177else if (sd->green_gain < 0x10)1178sd->green_gain = 0x10;11791180if (gspca_dev->streaming)1181setRGB(gspca_dev);1182return 0;1183}11841185static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)1186{1187struct sd *sd = (struct sd *) gspca_dev;11881189*val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;1190return 0;1191}11921193static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)1194{1195struct sd *sd = (struct sd *) gspca_dev;11961197sd->brightness = val;1198if (gspca_dev->streaming)1199setbrightness(gspca_dev);1200return 0;1201}12021203static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)1204{1205struct sd *sd = (struct sd *) gspca_dev;12061207*val = sd->brightness;1208return *val;1209}12101211static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)1212{1213struct sd *sd = (struct sd *) gspca_dev;12141215sd->awb = val;1216if (gspca_dev->streaming)1217setawb(gspca_dev);1218return 0;1219}12201221static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)1222{1223struct sd *sd = (struct sd *) gspca_dev;12241225*val = sd->awb;1226return *val;1227}12281229static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)1230{1231struct sd *sd = (struct sd *) gspca_dev;12321233sd->mirror = val;1234if (gspca_dev->streaming)1235setmirror(gspca_dev);1236return 0;1237}12381239static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)1240{1241struct sd *sd = (struct sd *) gspca_dev;12421243*val = sd->mirror;1244return *val;1245}12461247static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)1248{1249struct sd *sd = (struct sd *) gspca_dev;12501251sd->effect = val;1252if (gspca_dev->streaming)1253seteffect(gspca_dev);1254return 0;1255}12561257static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)1258{1259struct sd *sd = (struct sd *) gspca_dev;12601261*val = sd->effect;1262return *val;1263}12641265static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)1266{1267struct sd *sd = (struct sd *) gspca_dev;12681269sd->contrast = val;1270if (gspca_dev->streaming)1271setcontrast(gspca_dev);1272return 0;1273}12741275static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)1276{1277struct sd *sd = (struct sd *) gspca_dev;12781279*val = sd->contrast;1280return *val;1281}12821283static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)1284{1285struct sd *sd = (struct sd *) gspca_dev;12861287sd->colors = val;1288if (gspca_dev->streaming)1289setcolors(gspca_dev);1290return 0;1291}12921293static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)1294{1295struct sd *sd = (struct sd *) gspca_dev;12961297*val = sd->colors;1298return 0;1299}13001301static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)1302{1303struct sd *sd = (struct sd *) gspca_dev;13041305sd->gamma = val;1306if (gspca_dev->streaming)1307setgamma(gspca_dev);1308return 0;1309}13101311static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)1312{1313struct sd *sd = (struct sd *) gspca_dev;13141315*val = sd->gamma;1316return 0;1317}13181319static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)1320{1321struct sd *sd = (struct sd *) gspca_dev;13221323sd->freq = val;1324if (gspca_dev->streaming)1325setfreq(gspca_dev);1326return 0;1327}13281329static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)1330{1331struct sd *sd = (struct sd *) gspca_dev;13321333*val = sd->freq;1334return 0;1335}13361337static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)1338{1339struct sd *sd = (struct sd *) gspca_dev;13401341sd->sharpness = val;1342if (gspca_dev->streaming)1343setsharpness(gspca_dev);1344return 0;1345}13461347static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)1348{1349struct sd *sd = (struct sd *) gspca_dev;13501351*val = sd->sharpness;1352return 0;1353}13541355/* Low Light set here......*/1356static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)1357{1358struct sd *sd = (struct sd *) gspca_dev;13591360sd->autogain = val;1361if (val != 0)1362reg_w(gspca_dev, 0xf48e);1363else1364reg_w(gspca_dev, 0xb48e);1365return 0;1366}13671368static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)1369{1370struct sd *sd = (struct sd *) gspca_dev;13711372*val = sd->autogain;1373return 0;1374}13751376static int sd_querymenu(struct gspca_dev *gspca_dev,1377struct v4l2_querymenu *menu)1378{1379static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};13801381switch (menu->id) {1382case V4L2_CID_POWER_LINE_FREQUENCY:1383if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))1384break;1385strcpy((char *) menu->name, freq_nm[menu->index]);1386return 0;1387case V4L2_CID_EFFECTS:1388if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {1389strncpy((char *) menu->name,1390effects_control[menu->index],1391sizeof menu->name);1392return 0;1393}1394break;1395}1396return -EINVAL;1397}13981399/* sub-driver description */1400static const struct sd_desc sd_desc = {1401.name = MODULE_NAME,1402.ctrls = sd_ctrls,1403.nctrls = ARRAY_SIZE(sd_ctrls),1404.config = sd_config,1405.init = sd_init,1406.start = sd_start,1407.stopN = sd_stopN,1408.pkt_scan = sd_pkt_scan,1409.querymenu = sd_querymenu,1410};14111412/* -- module initialisation -- */1413static const struct usb_device_id device_table[] = {1414{USB_DEVICE(0x17a1, 0x0128)},1415{}1416};1417MODULE_DEVICE_TABLE(usb, device_table);14181419/* -- device connect -- */1420static int sd_probe(struct usb_interface *intf,1421const struct usb_device_id *id)1422{1423return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),1424THIS_MODULE);1425}14261427static struct usb_driver sd_driver = {1428.name = MODULE_NAME,1429.id_table = device_table,1430.probe = sd_probe,1431.disconnect = gspca_disconnect,1432#ifdef CONFIG_PM1433.suspend = gspca_suspend,1434.resume = gspca_resume,1435#endif1436};14371438/* -- module insert / remove -- */1439static int __init sd_mod_init(void)1440{1441return usb_register(&sd_driver);1442}1443static void __exit sd_mod_exit(void)1444{1445usb_deregister(&sd_driver);1446}14471448module_init(sd_mod_init);1449module_exit(sd_mod_exit);145014511452