t613.c 35.5 KB
Newer Older
1
/*
2 3 4
 * T613 subdriver
 *
 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19 20 21 22 23 24 25 26
 *
 *Notes: * t613  + tas5130A
 *	* Focus to light do not balance well as in win.
 *	  Quality in win is not good, but its kinda better.
 *	 * Fix some "extraneous bytes", most of apps will show the image anyway
 *	 * Gamma table, is there, but its really doing something?
 *	 * 7~8 Fps, its ok, max on win its 10.
 *			Costantino Leandro
27 28 29
 */

#define MODULE_NAME "t613"
30

31 32
#include "gspca.h"

33
#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
34 35 36 37 38 39 40 41

MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
MODULE_LICENSE("GPL");

struct sd {
	struct gspca_dev gspca_dev;	/* !! must be the first item */

42 43 44 45 46 47 48
	u8 brightness;
	u8 contrast;
	u8 colors;
	u8 autogain;
	u8 gamma;
	u8 sharpness;
	u8 freq;
49 50 51
	u8 red_gain;
	u8 blue_gain;
	u8 green_gain;
52
	u8 awb; /* set default r/g/b and activate */
53 54 55 56
	u8 mirror;
	u8 effect;

	u8 sensor;
57 58 59 60 61 62
enum {
	SENSOR_OM6802,
	SENSOR_OTHER,
	SENSOR_TAS5130A,
	SENSOR_LT168G,		/* must verify if this is the actual model */
} sensors;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
};

/* V4L2 controls supported by the driver */
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);
static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
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_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
80

81 82
static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
83 84 85 86 87 88
static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
89

90 91
static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
92 93 94 95 96
static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_querymenu(struct gspca_dev *gspca_dev,
			struct v4l2_querymenu *menu);

97
static const struct ctrl sd_ctrls[] = {
98 99 100 101 102 103
	{
	 {
	  .id = V4L2_CID_BRIGHTNESS,
	  .type = V4L2_CTRL_TYPE_INTEGER,
	  .name = "Brightness",
	  .minimum = 0,
104
	  .maximum = 14,
105
	  .step = 1,
106 107
#define BRIGHTNESS_DEF 8
	  .default_value = BRIGHTNESS_DEF,
108 109 110 111 112 113 114 115 116 117 118 119
	  },
	 .set = sd_setbrightness,
	 .get = sd_getbrightness,
	 },
	{
	 {
	  .id = V4L2_CID_CONTRAST,
	  .type = V4L2_CTRL_TYPE_INTEGER,
	  .name = "Contrast",
	  .minimum = 0,
	  .maximum = 0x0d,
	  .step = 1,
120 121
#define CONTRAST_DEF 0x07
	  .default_value = CONTRAST_DEF,
122 123 124 125 126 127 128 129 130 131 132 133
	  },
	 .set = sd_setcontrast,
	 .get = sd_getcontrast,
	 },
	{
	 {
	  .id = V4L2_CID_SATURATION,
	  .type = V4L2_CTRL_TYPE_INTEGER,
	  .name = "Color",
	  .minimum = 0,
	  .maximum = 0x0f,
	  .step = 1,
134 135
#define COLORS_DEF 0x05
	  .default_value = COLORS_DEF,
136 137 138 139
	  },
	 .set = sd_setcolors,
	 .get = sd_getcolors,
	 },
140 141
#define GAMMA_MAX 16
#define GAMMA_DEF 10
142 143 144 145
	{
	 {
	  .id = V4L2_CID_GAMMA,	/* (gamma on win) */
	  .type = V4L2_CTRL_TYPE_INTEGER,
146
	  .name = "Gamma",
147
	  .minimum = 0,
148
	  .maximum = GAMMA_MAX - 1,
149
	  .step = 1,
150
	  .default_value = GAMMA_DEF,
151 152 153 154 155 156
	  },
	 .set = sd_setgamma,
	 .get = sd_getgamma,
	 },
	{
	 {
157
	  .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,
158 159 160 161 162 163 164
				 * some apps dont bring up the
				 * backligth_compensation control) */
	  .type = V4L2_CTRL_TYPE_INTEGER,
	  .name = "Low Light",
	  .minimum = 0,
	  .maximum = 1,
	  .step = 1,
165 166
#define AUTOGAIN_DEF 0x01
	  .default_value = AUTOGAIN_DEF,
167 168 169 170 171 172 173 174 175 176 177 178
	  },
	 .set = sd_setlowlight,
	 .get = sd_getlowlight,
	 },
	{
	 {
	  .id = V4L2_CID_HFLIP,
	  .type = V4L2_CTRL_TYPE_BOOLEAN,
	  .name = "Mirror Image",
	  .minimum = 0,
	  .maximum = 1,
	  .step = 1,
179 180
#define MIRROR_DEF 0
	  .default_value = MIRROR_DEF,
181
	  },
182 183
	 .set = sd_setmirror,
	 .get = sd_getmirror
184 185 186 187 188 189 190 191 192
	},
	{
	 {
	  .id = V4L2_CID_POWER_LINE_FREQUENCY,
	  .type = V4L2_CTRL_TYPE_MENU,
	  .name = "Light Frequency Filter",
	  .minimum = 1,		/* 1 -> 0x50, 2->0x60 */
	  .maximum = 2,
	  .step = 1,
193 194
#define FREQ_DEF 1
	  .default_value = FREQ_DEF,
195 196 197 198 199 200
	  },
	 .set = sd_setfreq,
	 .get = sd_getfreq},

	{
	 {
201
	  .id =  V4L2_CID_AUTO_WHITE_BALANCE,
202
	  .type = V4L2_CTRL_TYPE_INTEGER,
203
	  .name = "Auto White Balance",
204 205 206
	  .minimum = 0,
	  .maximum = 1,
	  .step = 1,
207 208
#define AWB_DEF 0
	  .default_value = AWB_DEF,
209
	  },
210 211
	 .set = sd_setawb,
	 .get = sd_getawb
212 213 214 215 216 217 218
	},
	{
	 {
	  .id = V4L2_CID_SHARPNESS,
	  .type = V4L2_CTRL_TYPE_INTEGER,
	  .name = "Sharpness",
	  .minimum = 0,
219
	  .maximum = 15,
220
	  .step = 1,
221 222
#define SHARPNESS_DEF 0x06
	  .default_value = SHARPNESS_DEF,
223 224 225 226 227 228 229 230 231 232 233 234
	  },
	 .set = sd_setsharpness,
	 .get = sd_getsharpness,
	 },
	{
	 {
	  .id = V4L2_CID_EFFECTS,
	  .type = V4L2_CTRL_TYPE_MENU,
	  .name = "Webcam Effects",
	  .minimum = 0,
	  .maximum = 4,
	  .step = 1,
235 236
#define EFFECTS_DEF 0
	  .default_value = EFFECTS_DEF,
237 238 239 240
	  },
	 .set = sd_seteffect,
	 .get = sd_geteffect
	},
241 242 243 244 245 246 247 248
	{
	 {
	    .id      = V4L2_CID_BLUE_BALANCE,
	    .type    = V4L2_CTRL_TYPE_INTEGER,
	    .name    = "Blue Balance",
	    .minimum = 0x10,
	    .maximum = 0x40,
	    .step    = 1,
249 250
#define BLUE_GAIN_DEF 0x20
	    .default_value = BLUE_GAIN_DEF,
251
	 },
252 253
	.set = sd_setblue_gain,
	.get = sd_getblue_gain,
254 255 256 257 258 259 260 261 262
	},
	{
	 {
	    .id      = V4L2_CID_RED_BALANCE,
	    .type    = V4L2_CTRL_TYPE_INTEGER,
	    .name    = "Red Balance",
	    .minimum = 0x10,
	    .maximum = 0x40,
	    .step    = 1,
263 264
#define RED_GAIN_DEF 0x20
	    .default_value = RED_GAIN_DEF,
265
	 },
266 267
	.set = sd_setred_gain,
	.get = sd_getred_gain,
268 269 270 271 272 273 274 275 276
	},
	{
	 {
	    .id      = V4L2_CID_GAIN,
	    .type    = V4L2_CTRL_TYPE_INTEGER,
	    .name    = "Gain",
	    .minimum = 0x10,
	    .maximum = 0x40,
	    .step    = 1,
277 278
#define GAIN_DEF  0x20
	    .default_value = GAIN_DEF,
279
	 },
280 281
	.set = sd_setgain,
	.get = sd_getgain,
282
	},
283 284
};

285
static const struct v4l2_pix_format vga_mode_t16[] = {
286 287
	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 160,
288
		.sizeimage = 160 * 120 * 4 / 8 + 590,
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
		.colorspace = V4L2_COLORSPACE_JPEG,
		.priv = 4},
	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 176,
		.sizeimage = 176 * 144 * 3 / 8 + 590,
		.colorspace = V4L2_COLORSPACE_JPEG,
		.priv = 3},
	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 320,
		.sizeimage = 320 * 240 * 3 / 8 + 590,
		.colorspace = V4L2_COLORSPACE_JPEG,
		.priv = 2},
	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 352,
		.sizeimage = 352 * 288 * 3 / 8 + 590,
		.colorspace = V4L2_COLORSPACE_JPEG,
		.priv = 1},
	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 640,
		.sizeimage = 640 * 480 * 3 / 8 + 590,
		.colorspace = V4L2_COLORSPACE_JPEG,
		.priv = 0},
311 312
};

313 314
/* sensor specific data */
struct additional_sensor_data {
315 316 317 318
	const u8 n3[6];
	const u8 *n4, n4sz;
	const u8 reg80, reg8e;
	const u8 nset8[6];
319 320 321 322 323
	const u8 data1[10];
	const u8 data2[9];
	const u8 data3[9];
	const u8 data5[6];
	const u8 stream[4];
324 325
};

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
static const u8 n4_om6802[] = {
	0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
	0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
	0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
	0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
	0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
	0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
	0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
	0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
	0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
};
static const u8 n4_other[] = {
	0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
	0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
	0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
	0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
	0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
	0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
	0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
};
static const u8 n4_tas5130a[] = {
	0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
	0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
	0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
	0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
	0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
	0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
	0xc6, 0xda
};
356 357 358 359 360 361 362 363 364 365 366
static const u8 n4_lt168g[] = {
	0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
	0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
	0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
	0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
	0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
	0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
	0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
	0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
};
367

368
static const struct additional_sensor_data sensor_data[] = {
369
[SENSOR_OM6802] = {
370 371 372 373 374 375 376
	.n3 =
		{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
	.n4 = n4_om6802,
	.n4sz = sizeof n4_om6802,
	.reg80 = 0x3c,
	.reg8e = 0x33,
	.nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
377 378 379 380 381 382
	.data1 =
		{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
		 0xb3, 0xfc},
	.data2 =
		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
		 0xff},
383 384 385
	.data3 =
		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
		 0xff},
386 387 388 389 390
	.data5 =	/* this could be removed later */
		{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
	.stream =
		{0x0b, 0x04, 0x0a, 0x78},
    },
391
[SENSOR_OTHER] = {
392 393 394 395 396 397 398
	.n3 =
		{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
	.n4 = n4_other,
	.n4sz = sizeof n4_other,
	.reg80 = 0xac,
	.reg8e = 0xb8,
	.nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
399 400 401 402 403 404
	.data1 =
		{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
		 0xe8, 0xfc},
	.data2 =
		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
		 0xd9},
405 406 407
	.data3 =
		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
		 0xd9},
408 409 410 411 412
	.data5 =
		{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
	.stream =
		{0x0b, 0x04, 0x0a, 0x00},
    },
413
[SENSOR_TAS5130A] = {
414 415 416 417 418 419 420
	.n3 =
		{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
	.n4 = n4_tas5130a,
	.n4sz = sizeof n4_tas5130a,
	.reg80 = 0x3c,
	.reg8e = 0xb4,
	.nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
421
	.data1 =
422 423
		{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
		 0xc8, 0xfc},
424
	.data2 =
425 426
		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
		 0xe0},
427 428 429
	.data3 =
		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
		 0xe0},
430 431 432 433 434
	.data5 =
		{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
	.stream =
		{0x0b, 0x04, 0x0a, 0x40},
    },
435
[SENSOR_LT168G] = {
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
	.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
	.n4 = n4_lt168g,
	.n4sz = sizeof n4_lt168g,
	.reg80 = 0x7c,
	.reg8e = 0xb3,
	.nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
	.data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
		 0xb0, 0xf4},
	.data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
		 0xff},
	.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
		 0xff},
	.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
	.stream = {0x0b, 0x04, 0x0a, 0x28},
    },
451 452
};

453 454 455
#define MAX_EFFECTS 7
/* easily done by soft, this table could be removed,
 * i keep it here just in case */
456 457 458 459 460 461 462 463 464
static char *effects_control[MAX_EFFECTS] = {
	"Normal",
	"Emboss",		/* disabled */
	"Monochrome",
	"Sepia",
	"Sketch",
	"Sun Effect",		/* disabled */
	"Negative",
};
465
static const u8 effects_table[MAX_EFFECTS][6] = {
466 467 468 469 470 471 472 473 474
	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},	/* Monochrome */
	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},	/* Sepia */
	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},	/* Croquis */
	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},	/* Sun Effect */
	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
};

475
static const u8 gamma_table[GAMMA_MAX][17] = {
476 477 478
/* gamma table from cam1690.ini */
	{0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,	/* 0 */
	 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
479
	 0xff},
480 481
	{0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,	/* 1 */
	 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
482
	 0xff},
483 484
	{0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,	/* 2 */
	 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
485
	 0xff},
486 487
	{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,	/* 3 */
	 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
488
	 0xff},
489 490
	{0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a,	/* 4 */
	 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
491
	 0xff},
492 493
	{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,	/* 5 */
	 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
494
	 0xff},
495
	{0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,	/* 6 */
496 497
	 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
	 0xff},
498
	{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,	/* 7 */
499 500
	 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
	 0xff},
501 502
	{0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,	/* 8 */
	 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
503
	 0xff},
504 505
	{0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,	/* 9 */
	 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
506
	 0xff},
507 508
	{0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,	/* 10 */
	 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
509
	 0xff},
510
	{0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,	/* 11 */
511 512 513 514 515 516 517 518 519 520 521 522 523 524
	 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
	 0xff},
	{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,	/* 12 */
	 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
	 0xff},
	{0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,	/* 13 */
	 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
	 0xff},
	{0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,	/* 14 */
	 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
	 0xff},
	{0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,	/* 15 */
	 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
	 0xff}
525 526
};

527
static const u8 tas5130a_sensor_init[][8] = {
528 529 530 531 532
	{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
	{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
};

533
static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
534

535
/* read 1 byte */
536 537
static u8 reg_r(struct gspca_dev *gspca_dev,
		   u16 index)
538
{
539 540
	usb_control_msg(gspca_dev->dev,
			usb_rcvctrlpipe(gspca_dev->dev, 0),
541 542 543
			0,		/* request */
			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			0,		/* value */
544 545 546
			index,
			gspca_dev->usb_buf, 1, 500);
	return gspca_dev->usb_buf[0];
547 548
}

549
static void reg_w(struct gspca_dev *gspca_dev,
550
		  u16 index)
551 552 553 554
{
	usb_control_msg(gspca_dev->dev,
			usb_sndctrlpipe(gspca_dev->dev, 0),
			0,
555
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
556 557 558 559
			0, index,
			NULL, 0, 500);
}

560
static void reg_w_buf(struct gspca_dev *gspca_dev,
561
		  const u8 *buffer, u16 len)
562
{
563
	if (len <= USB_BUF_SZ) {
564 565 566
		memcpy(gspca_dev->usb_buf, buffer, len);
		usb_control_msg(gspca_dev->dev,
				usb_sndctrlpipe(gspca_dev->dev, 0),
567
				0,
568
			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
569
				0x01, 0,
570
				gspca_dev->usb_buf, len, 500);
571
	} else {
572
		u8 *tmpbuf;
573 574

		tmpbuf = kmalloc(len, GFP_KERNEL);
575 576 577 578
		if (!tmpbuf) {
			err("Out of memory");
			return;
		}
579
		memcpy(tmpbuf, buffer, len);
580 581
		usb_control_msg(gspca_dev->dev,
				usb_sndctrlpipe(gspca_dev->dev, 0),
582
				0,
583
			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
584
				0x01, 0,
585 586 587
				tmpbuf, len, 500);
		kfree(tmpbuf);
	}
588 589
}

590 591 592 593 594 595 596 597
/* write values to consecutive registers */
static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
			u8 reg,
			const u8 *buffer, u16 len)
{
	int i;
	u8 *p, *tmpbuf;

598
	if (len * 2 <= USB_BUF_SZ) {
599
		p = tmpbuf = gspca_dev->usb_buf;
600
	} else {
601
		p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
602 603 604 605 606
		if (!tmpbuf) {
			err("Out of memory");
			return;
		}
	}
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
	i = len;
	while (--i >= 0) {
		*p++ = reg++;
		*p++ = *buffer++;
	}
	usb_control_msg(gspca_dev->dev,
			usb_sndctrlpipe(gspca_dev->dev, 0),
			0,
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			0x01, 0,
			tmpbuf, len * 2, 500);
	if (len * 2 > USB_BUF_SZ)
		kfree(tmpbuf);
}

622
static void om6802_sensor_init(struct gspca_dev *gspca_dev)
623 624
{
	int i;
625 626 627 628
	const u8 *p;
	u8 byte;
	u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
	static const u8 sensor_init[] = {
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
		0xdf, 0x6d,
		0xdd, 0x18,
		0x5a, 0xe0,
		0x5c, 0x07,
		0x5d, 0xb0,
		0x5e, 0x1e,
		0x60, 0x71,
		0xef, 0x00,
		0xe9, 0x00,
		0xea, 0x00,
		0x90, 0x24,
		0x91, 0xb2,
		0x82, 0x32,
		0xfd, 0x41,
		0x00			/* table end */
	};

646
	reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
647
	msleep(100);
648
	i = 4;
649
	while (--i > 0) {
650 651 652 653 654 655 656 657 658 659 660
		byte = reg_r(gspca_dev, 0x0060);
		if (!(byte & 0x01))
			break;
		msleep(100);
	}
	byte = reg_r(gspca_dev, 0x0063);
	if (byte != 0x17) {
		err("Bad sensor reset %02x", byte);
		/* continue? */
	}

661 662 663 664 665 666
	p = sensor_init;
	while (*p != 0) {
		val[1] = *p++;
		val[3] = *p++;
		if (*p == 0)
			reg_w(gspca_dev, 0x3c80);
667
		reg_w_buf(gspca_dev, val, sizeof val);
668 669 670 671 672 673 674 675
		i = 4;
		while (--i >= 0) {
			msleep(15);
			byte = reg_r(gspca_dev, 0x60);
			if (!(byte & 0x01))
				break;
		}
	}
676 677
	msleep(15);
	reg_w(gspca_dev, 0x3c80);
678 679
}

680 681 682 683 684 685 686 687 688 689 690 691
/* 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_t16;
	cam->nmodes = ARRAY_SIZE(vga_mode_t16);

692 693 694
	sd->brightness = BRIGHTNESS_DEF;
	sd->contrast = CONTRAST_DEF;
	sd->colors = COLORS_DEF;
695
	sd->gamma = GAMMA_DEF;
696 697 698
	sd->autogain = AUTOGAIN_DEF;
	sd->mirror = MIRROR_DEF;
	sd->freq = FREQ_DEF;
699
	sd->awb = AWB_DEF;
700 701
	sd->sharpness = SHARPNESS_DEF;
	sd->effect = EFFECTS_DEF;
702 703 704
	sd->red_gain = RED_GAIN_DEF;
	sd->blue_gain = BLUE_GAIN_DEF;
	sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
705

706 707 708
	return 0;
}

709 710 711 712
static void setbrightness(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	unsigned int brightness;
713
	u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729

	brightness = sd->brightness;
	if (brightness < 7) {
		set6[1] = 0x26;
		set6[3] = 0x70 - brightness * 0x10;
	} else {
		set6[3] = 0x00 + ((brightness - 7) * 0x10);
	}

	reg_w_buf(gspca_dev, set6, sizeof set6);
}

static void setcontrast(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	unsigned int contrast = sd->contrast;
730
	u16 reg_to_write;
731 732 733 734 735 736 737 738 739 740 741 742

	if (contrast < 7)
		reg_to_write = 0x8ea9 - contrast * 0x200;
	else
		reg_to_write = 0x00a9 + (contrast - 7) * 0x200;

	reg_w(gspca_dev, reg_to_write);
}

static void setcolors(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
743
	u16 reg_to_write;
744 745 746 747 748

	reg_to_write = 0x80bb + sd->colors * 0x100;	/* was 0xc0 */
	reg_w(gspca_dev, reg_to_write);
}

749 750 751 752 753
static void setgamma(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
754 755
	reg_w_ixbuf(gspca_dev, 0x90,
		gamma_table[sd->gamma], sizeof gamma_table[0]);
756 757
}

758 759
static void setRGB(struct gspca_dev *gspca_dev)
{
760
	struct sd *sd = (struct sd *) gspca_dev;
761 762 763 764 765 766 767
	u8 all_gain_reg[6] =
		{0x87, 0x00, 0x88, 0x00, 0x89, 0x00};

	all_gain_reg[1] = sd->red_gain;
	all_gain_reg[3] = sd->blue_gain;
	all_gain_reg[5] = sd->green_gain;
	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
768 769
}

770
/* Generic fnc for r/b balance, exposure and awb */
771
static void setawb(struct gspca_dev *gspca_dev)
772 773
{
	struct sd *sd = (struct sd *) gspca_dev;
774 775 776
	u16 reg80;

	reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
777

778
	/* on awb leave defaults values */
779
	if (!sd->awb) {
780
		/* shoud we wait here.. */
781 782 783 784 785
		/* update and reset RGB gains with webcam values */
		sd->red_gain = reg_r(gspca_dev, 0x0087);
		sd->blue_gain = reg_r(gspca_dev, 0x0088);
		sd->green_gain = reg_r(gspca_dev, 0x0089);
		reg80 &= ~0x0400;		/* AWB off */
786
	}
787 788 789
	reg_w(gspca_dev, reg80);
	reg_w(gspca_dev, reg80);
}
790

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
static void init_gains(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u16 reg80;
	u8 all_gain_reg[8] =
		{0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};

	all_gain_reg[1] = sd->red_gain;
	all_gain_reg[3] = sd->blue_gain;
	all_gain_reg[5] = sd->green_gain;
	reg80 = sensor_data[sd->sensor].reg80;
	if (!sd->awb)
		reg80 &= ~0x04;
	all_gain_reg[7] = reg80;
	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);

	reg_w(gspca_dev, (sd->red_gain  << 8) + 0x87);
	reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
	reg_w(gspca_dev, (sd->green_gain  << 8) + 0x89);
810
}
811 812 813 814

static void setsharpness(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
815
	u16 reg_to_write;
816 817 818 819 820 821

	reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;

	reg_w(gspca_dev, reg_to_write);
}

822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
static void setfreq(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 reg66;
	u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };

	switch (sd->sensor) {
	case SENSOR_LT168G:
		if (sd->freq != 0)
			freq[3] = 0xa8;
		reg66 = 0x41;
		break;
	case SENSOR_OM6802:
		reg66 = 0xca;
		break;
	default:
		reg66 = 0x40;
		break;
	}
	switch (sd->freq) {
	case 0:				/* no flicker */
		freq[3] = 0xf0;
		break;
	case 2:				/* 60Hz */
		reg66 &= ~0x40;
		break;
	}
	freq[1] = reg66;

	reg_w_buf(gspca_dev, freq, sizeof freq);
}

854 855
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
856 857 858 859 860
{
	/* some of this registers are not really neded, because
	 * they are overriden by setbrigthness, setcontrast, etc,
	 * but wont hurt anyway, and can help someone with similar webcam
	 * to see the initial parameters.*/
861
	struct sd *sd = (struct sd *) gspca_dev;
862
	const struct additional_sensor_data *sensor;
863
	int i;
864
	u16 sensor_id;
865
	u8 test_byte = 0;
866

867
	static const u8 read_indexs[] =
868
		{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
869 870
		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
	static const u8 n1[] =
871
			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
872
	static const u8 n2[] =
873 874
			{0x08, 0x00};

875 876
	sensor_id = (reg_r(gspca_dev, 0x06) << 8)
			| reg_r(gspca_dev, 0x07);
877
	switch (sensor_id & 0xff0f) {
878
	case 0x0801:
879
		PDEBUG(D_PROBE, "sensor tas5130a");
880
		sd->sensor = SENSOR_TAS5130A;
881
		break;
882 883 884 885
	case 0x0802:
		PDEBUG(D_PROBE, "sensor lt168g");
		sd->sensor = SENSOR_LT168G;
		break;
886
	case 0x0803:
887
		PDEBUG(D_PROBE, "sensor 'other'");
888 889 890
		sd->sensor = SENSOR_OTHER;
		break;
	case 0x0807:
891
		PDEBUG(D_PROBE, "sensor om6802");
892 893 894
		sd->sensor = SENSOR_OM6802;
		break;
	default:
895
		PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
896
		return -EINVAL;
897 898
	}

899
	if (sd->sensor == SENSOR_OM6802) {
900 901 902 903 904 905 906 907 908 909 910
		reg_w_buf(gspca_dev, n1, sizeof n1);
		i = 5;
		while (--i >= 0) {
			reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
			test_byte = reg_r(gspca_dev, 0x0063);
			msleep(100);
			if (test_byte == 0x17)
				break;		/* OK */
		}
		if (i < 0) {
			err("Bad sensor reset %02x", test_byte);
911
			return -EIO;
912 913
		}
		reg_w_buf(gspca_dev, n2, sizeof n2);
914
	}
915

916
	i = 0;
917
	while (read_indexs[i] != 0x00) {
918 919
		test_byte = reg_r(gspca_dev, read_indexs[i]);
		PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
920 921 922 923
		       test_byte);
		i++;
	}

924 925 926
	sensor = &sensor_data[sd->sensor];
	reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
	reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
927

928 929 930 931 932 933 934
	if (sd->sensor == SENSOR_LT168G) {
		test_byte = reg_r(gspca_dev, 0x80);
		PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
		       test_byte);
		reg_w(gspca_dev, 0x6c80);
	}

935 936 937
	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
938

939 940 941
	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
	reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
942

943 944
	setbrightness(gspca_dev);
	setcontrast(gspca_dev);
945
	setgamma(gspca_dev);
946 947
	setcolors(gspca_dev);
	setsharpness(gspca_dev);
948
	init_gains(gspca_dev);
949
	setfreq(gspca_dev);
950

951 952 953
	reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
	reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
954

955 956 957 958 959 960 961
	if (sd->sensor == SENSOR_LT168G) {
		test_byte = reg_r(gspca_dev, 0x80);
		PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
		       test_byte);
		reg_w(gspca_dev, 0x6c80);
	}

962 963 964
	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
965

966 967 968
	return 0;
}

969
static void setmirror(struct gspca_dev *gspca_dev)
970 971
{
	struct sd *sd = (struct sd *) gspca_dev;
972
	u8 hflipcmd[8] =
973
		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
974

975
	if (sd->mirror)
976
		hflipcmd[3] = 0x01;
977

978
	reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
979 980 981 982 983 984
}

static void seteffect(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

985 986
	reg_w_buf(gspca_dev, effects_table[sd->effect],
				sizeof effects_table[0]);
987 988 989 990 991 992 993
	if (sd->effect == 1 || sd->effect == 5) {
		PDEBUG(D_CONF,
		       "This effect have been disabled for webcam \"safety\"");
		return;
	}

	if (sd->effect == 1 || sd->effect == 4)
994
		reg_w(gspca_dev, 0x4aa6);
995
	else
996
		reg_w(gspca_dev, 0xfaa6);
997 998
}

999 1000 1001 1002
/* Is this really needed?
 * i added some module parameters for test with some users */
static void poll_sensor(struct gspca_dev *gspca_dev)
{
1003
	static const u8 poll1[] =
1004 1005 1006 1007
		{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
		 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
		 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
		 0x60, 0x14};
1008
	static const u8 poll2[] =
1009 1010
		{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
		 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
1011
	static const u8 noise03[] =	/* (some differences / ms-drv) */
1012 1013 1014 1015
		{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
		 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
		 0xc2, 0x80, 0xc3, 0x10};

1016 1017 1018
	PDEBUG(D_STREAM, "[Sensor requires polling]");
	reg_w_buf(gspca_dev, poll1, sizeof poll1);
	reg_w_buf(gspca_dev, poll2, sizeof poll2);
1019
	reg_w_buf(gspca_dev, noise03, sizeof noise03);
1020 1021
}

1022 1023 1024
static int sd_start(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
1025
	const struct additional_sensor_data *sensor;
1026
	int i, mode;
1027 1028 1029
	u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
	static const u8 t3[] =
		{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
1030

1031
	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
1032
	switch (mode) {
1033 1034
	case 0:		/* 640x480 (0x00) */
		break;
1035 1036 1037 1038 1039 1040 1041 1042 1043
	case 1:		/* 352x288 */
		t2[1] = 0x40;
		break;
	case 2:		/* 320x240 */
		t2[1] = 0x10;
		break;
	case 3:		/* 176x144 */
		t2[1] = 0x50;
		break;
1044 1045
	default:
/*	case 4:		 * 160x120 */
1046 1047 1048 1049
		t2[1] = 0x20;
		break;
	}

1050 1051 1052 1053
	switch (sd->sensor) {
	case SENSOR_OM6802:
		om6802_sensor_init(gspca_dev);
		break;
1054
	case SENSOR_TAS5130A:
1055
		i = 0;
1056
		for (;;) {
1057
			reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
1058
					 sizeof tas5130a_sensor_init[0]);
1059 1060
			if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
				break;
1061 1062 1063 1064
			i++;
		}
		reg_w(gspca_dev, 0x3c80);
		/* just in case and to keep sync with logs (for mine) */
1065
		reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
1066 1067
				 sizeof tas5130a_sensor_init[0]);
		reg_w(gspca_dev, 0x3c80);
1068
		break;
1069
	}
1070
	sensor = &sensor_data[sd->sensor];
1071
	setfreq(gspca_dev);
1072
	reg_r(gspca_dev, 0x0012);
1073
	reg_w_buf(gspca_dev, t2, sizeof t2);
1074
	reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
1075
	reg_w(gspca_dev, 0x0013);
1076
	msleep(15);
1077 1078 1079 1080 1081
	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);

	if (sd->sensor == SENSOR_OM6802)
		poll_sensor(gspca_dev);
1082

1083 1084 1085
	return 0;
}

1086 1087 1088 1089 1090 1091 1092 1093
static void sd_stopN(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
			sizeof sensor_data[sd->sensor].stream);
	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
			sizeof sensor_data[sd->sensor].stream);
1094
	if (sd->sensor == SENSOR_OM6802) {
1095 1096 1097
		msleep(20);
		reg_w(gspca_dev, 0x0309);
	}
1098 1099
}

1100
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1101
			u8 *data,			/* isoc packet */
1102 1103
			int len)			/* iso packet length */
{
1104
	int pkt_type;
1105 1106 1107 1108 1109 1110 1111 1112 1113

	if (data[0] == 0x5a) {
		/* Control Packet, after this came the header again,
		 * but extra bytes came in the packet before this,
		 * sometimes an EOF arrives, sometimes not... */
		return;
	}
	data += 2;
	len -= 2;
1114 1115 1116 1117 1118 1119 1120
	if (data[0] == 0xff && data[1] == 0xd8)
		pkt_type = FIRST_PACKET;
	else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
		pkt_type = LAST_PACKET;
	else
		pkt_type = INTER_PACKET;
	gspca_frame_add(gspca_dev, pkt_type, data, len);
1121 1122
}

1123
static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
1124 1125 1126
{
	struct sd *sd = (struct sd *) gspca_dev;

1127
	sd->blue_gain = val;
1128 1129 1130 1131 1132
	if (gspca_dev->streaming)
		reg_w(gspca_dev, (val << 8) + 0x88);
	return 0;
}

1133
static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
1134 1135 1136
{
	struct sd *sd = (struct sd *) gspca_dev;

1137
	*val = sd->blue_gain;
1138 1139 1140
	return 0;
}

1141
static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
1142 1143 1144
{
	struct sd *sd = (struct sd *) gspca_dev;

1145
	sd->red_gain = val;
1146 1147 1148 1149 1150 1151
	if (gspca_dev->streaming)
		reg_w(gspca_dev, (val << 8) + 0x87);

	return 0;
}

1152
static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
1153 1154 1155
{
	struct sd *sd = (struct sd *) gspca_dev;

1156
	*val = sd->red_gain;
1157 1158 1159
	return 0;
}

1160
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1161 1162
{
	struct sd *sd = (struct sd *) gspca_dev;
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
	u16 psg, nsg;

	psg = sd->red_gain + sd->blue_gain + sd->green_gain;
	nsg = val * 3;
	sd->red_gain = sd->red_gain * nsg / psg;
	if (sd->red_gain > 0x40)
		sd->red_gain = 0x40;
	else if (sd->red_gain < 0x10)
		sd->red_gain = 0x10;
	sd->blue_gain = sd->blue_gain * nsg / psg;
	if (sd->blue_gain > 0x40)
		sd->blue_gain = 0x40;
	else if (sd->blue_gain < 0x10)
		sd->blue_gain = 0x10;
	sd->green_gain = sd->green_gain * nsg / psg;
	if (sd->green_gain > 0x40)
		sd->green_gain = 0x40;
	else if (sd->green_gain < 0x10)
		sd->green_gain = 0x10;
1182 1183

	if (gspca_dev->streaming)
1184
		setRGB(gspca_dev);
1185 1186 1187
	return 0;
}

1188
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1189 1190 1191
{
	struct sd *sd = (struct sd *) gspca_dev;

1192
	*val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
1193 1194 1195
	return 0;
}

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->brightness = val;
	if (gspca_dev->streaming)
		setbrightness(gspca_dev);
	return 0;
}

static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;
1209

1210 1211 1212 1213
	*val = sd->brightness;
	return *val;
}

1214
static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
1215 1216 1217
{
	struct sd *sd = (struct sd *) gspca_dev;

1218
	sd->awb = val;
1219
	if (gspca_dev->streaming)
1220
		setawb(gspca_dev);
1221 1222 1223
	return 0;
}

1224
static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
1225 1226 1227
{
	struct sd *sd = (struct sd *) gspca_dev;

1228
	*val = sd->awb;
1229 1230 1231
	return *val;
}

1232
static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
1233 1234 1235 1236 1237
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->mirror = val;
	if (gspca_dev->streaming)
1238
		setmirror(gspca_dev);
1239 1240 1241
	return 0;
}

1242
static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->mirror;
	return *val;
}

static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->effect = val;
	if (gspca_dev->streaming)
		seteffect(gspca_dev);
	return 0;
}

static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->effect;
	return *val;
}

static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->contrast = val;
	if (gspca_dev->streaming)
		setcontrast(gspca_dev);
	return 0;
}

static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->contrast;
	return *val;
}

static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->colors = val;
	if (gspca_dev->streaming)
		setcolors(gspca_dev);
	return 0;
}

static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->colors;
	return 0;
}

static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->gamma = val;
	if (gspca_dev->streaming)
		setgamma(gspca_dev);
	return 0;
}

static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;
1317

1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
	*val = sd->gamma;
	return 0;
}

static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->freq = val;
	if (gspca_dev->streaming)
1328
		setfreq(gspca_dev);
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
	return 0;
}

static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->freq;
	return 0;
}

static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->sharpness = val;
	if (gspca_dev->streaming)
		setsharpness(gspca_dev);
	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;
}

/* Low Light set  here......*/
static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->autogain = val;
	if (val != 0)
1365
		reg_w(gspca_dev, 0xf48e);
1366
	else
1367
		reg_w(gspca_dev, 0xb48e);
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
	return 0;
}

static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->autogain;
	return 0;
}

static int sd_querymenu(struct gspca_dev *gspca_dev,
			struct v4l2_querymenu *menu)
{
	switch (menu->id) {
	case V4L2_CID_POWER_LINE_FREQUENCY:
		switch (menu->index) {
		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1386
			strcpy((char *) menu->name, "50 Hz");
1387 1388
			return 0;
		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1389
			strcpy((char *) menu->name, "60 Hz");
1390 1391 1392 1393
			return 0;
		}
		break;
	case V4L2_CID_EFFECTS:
1394 1395
		if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
			strncpy((char *) menu->name,
1396 1397
				effects_control[menu->index],
				sizeof menu->name);
1398 1399
			return 0;
		}
1400 1401
		break;
	}
1402
	return -EINVAL;
1403 1404 1405
}

/* sub-driver description */
1406
static const struct sd_desc sd_desc = {
1407 1408 1409 1410
	.name = MODULE_NAME,
	.ctrls = sd_ctrls,
	.nctrls = ARRAY_SIZE(sd_ctrls),
	.config = sd_config,
1411
	.init = sd_init,
1412
	.start = sd_start,
1413
	.stopN = sd_stopN,
1414 1415 1416 1417 1418
	.pkt_scan = sd_pkt_scan,
	.querymenu = sd_querymenu,
};

/* -- module initialisation -- */
1419
static const __devinitdata struct usb_device_id device_table[] = {
1420
	{USB_DEVICE(0x17a1, 0x0128)},
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
	{}
};
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,
1438 1439 1440 1441
#ifdef CONFIG_PM
	.suspend = gspca_suspend,
	.resume = gspca_resume,
#endif
1442 1443 1444 1445 1446
};

/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
1447 1448 1449
	int ret;
	ret = usb_register(&sd_driver);
	if (ret < 0)
1450
		return ret;
1451
	PDEBUG(D_PROBE, "registered");
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
	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);