blob: 310bd2439848e5b28ce67057f3cdae2ca21d991d [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
Jean-François Moinecd8955b2010-06-04 07:22:57 -03002 * T613 subdriver
3 *
4 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030019 *
20 *Notes: * t613 + tas5130A
21 * * Focus to light do not balance well as in win.
22 * Quality in win is not good, but its kinda better.
23 * * Fix some "extraneous bytes", most of apps will show the image anyway
24 * * Gamma table, is there, but its really doing something?
25 * * 7~8 Fps, its ok, max on win its 10.
26 * Costantino Leandro
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027 */
28
29#define MODULE_NAME "t613"
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030030
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030031#include "gspca.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030032
Jean-Francois Moinef9b4a372008-09-03 16:48:14 -030033#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030034
35MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
36MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
37MODULE_LICENSE("GPL");
38
39struct sd {
40 struct gspca_dev gspca_dev; /* !! must be the first item */
41
Jean-Francois Moine82e25492009-01-22 07:18:48 -030042 u8 brightness;
43 u8 contrast;
44 u8 colors;
45 u8 autogain;
46 u8 gamma;
47 u8 sharpness;
48 u8 freq;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -030049 u8 red_balance; /* split balance */
50 u8 blue_balance;
51 u8 global_gain; /* aka gain */
Jean-François Moinecd8955b2010-06-04 07:22:57 -030052 u8 awb; /* set default r/g/b and activate */
Jean-Francois Moine82e25492009-01-22 07:18:48 -030053 u8 mirror;
54 u8 effect;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030055
Jean-Francois Moine82e25492009-01-22 07:18:48 -030056 u8 sensor;
Jean-François Moinecd8955b2010-06-04 07:22:57 -030057enum {
58 SENSOR_OM6802,
59 SENSOR_OTHER,
60 SENSOR_TAS5130A,
61 SENSOR_LT168G, /* must verify if this is the actual model */
62} sensors;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030063};
64
65/* 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);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -030080
Jean-François Moinecd8955b2010-06-04 07:22:57 -030081static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -030083static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
89
Jean-François Moinecd8955b2010-06-04 07:22:57 -030090static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030092static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
94static int sd_querymenu(struct gspca_dev *gspca_dev,
95 struct v4l2_querymenu *menu);
96
Marton Nemeth7e64dc42009-12-30 09:12:41 -030097static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098 {
99 {
100 .id = V4L2_CID_BRIGHTNESS,
101 .type = V4L2_CTRL_TYPE_INTEGER,
102 .name = "Brightness",
103 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300104 .maximum = 14,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300105 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300106#define BRIGHTNESS_DEF 8
107 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 },
109 .set = sd_setbrightness,
110 .get = sd_getbrightness,
111 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300112 {
113 {
114 .id = V4L2_CID_CONTRAST,
115 .type = V4L2_CTRL_TYPE_INTEGER,
116 .name = "Contrast",
117 .minimum = 0,
118 .maximum = 0x0d,
119 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300120#define CONTRAST_DEF 0x07
121 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300122 },
123 .set = sd_setcontrast,
124 .get = sd_getcontrast,
125 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126 {
127 {
128 .id = V4L2_CID_SATURATION,
129 .type = V4L2_CTRL_TYPE_INTEGER,
130 .name = "Color",
131 .minimum = 0,
132 .maximum = 0x0f,
133 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300134#define COLORS_DEF 0x05
135 .default_value = COLORS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300136 },
137 .set = sd_setcolors,
138 .get = sd_getcolors,
139 },
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300140#define GAMMA_MAX 16
141#define GAMMA_DEF 10
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142 {
143 {
144 .id = V4L2_CID_GAMMA, /* (gamma on win) */
145 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300146 .name = "Gamma",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300148 .maximum = GAMMA_MAX - 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 .step = 1,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300150 .default_value = GAMMA_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 },
152 .set = sd_setgamma,
153 .get = sd_getgamma,
154 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155 {
156 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300157 .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300158 * some apps dont bring up the
159 * backligth_compensation control) */
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "Low Light",
162 .minimum = 0,
163 .maximum = 1,
164 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300165#define AUTOGAIN_DEF 0x01
166 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300167 },
168 .set = sd_setlowlight,
169 .get = sd_getlowlight,
170 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300171 {
172 {
173 .id = V4L2_CID_HFLIP,
174 .type = V4L2_CTRL_TYPE_BOOLEAN,
175 .name = "Mirror Image",
176 .minimum = 0,
177 .maximum = 1,
178 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300179#define MIRROR_DEF 0
180 .default_value = MIRROR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300181 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300182 .set = sd_setmirror,
183 .get = sd_getmirror
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300184 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185 {
186 {
187 .id = V4L2_CID_POWER_LINE_FREQUENCY,
188 .type = V4L2_CTRL_TYPE_MENU,
189 .name = "Light Frequency Filter",
190 .minimum = 1, /* 1 -> 0x50, 2->0x60 */
191 .maximum = 2,
192 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300193#define FREQ_DEF 1
194 .default_value = FREQ_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300195 },
196 .set = sd_setfreq,
197 .get = sd_getfreq},
198
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300199 {
200 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300201 .id = V4L2_CID_AUTO_WHITE_BALANCE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300202 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300203 .name = "Auto White Balance",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300207#define AWB_DEF 0
208 .default_value = AWB_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300209 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300210 .set = sd_setawb,
211 .get = sd_getawb
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300212 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300213 {
214 {
215 .id = V4L2_CID_SHARPNESS,
216 .type = V4L2_CTRL_TYPE_INTEGER,
217 .name = "Sharpness",
218 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300219 .maximum = 15,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300220 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300221#define SHARPNESS_DEF 0x06
222 .default_value = SHARPNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300223 },
224 .set = sd_setsharpness,
225 .get = sd_getsharpness,
226 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 {
228 {
229 .id = V4L2_CID_EFFECTS,
230 .type = V4L2_CTRL_TYPE_MENU,
231 .name = "Webcam Effects",
232 .minimum = 0,
233 .maximum = 4,
234 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300235#define EFFECTS_DEF 0
236 .default_value = EFFECTS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237 },
238 .set = sd_seteffect,
239 .get = sd_geteffect
240 },
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300241 {
242 {
243 .id = V4L2_CID_BLUE_BALANCE,
244 .type = V4L2_CTRL_TYPE_INTEGER,
245 .name = "Blue Balance",
246 .minimum = 0x10,
247 .maximum = 0x40,
248 .step = 1,
249#define BLUE_BALANCE_DEF 0x20
250 .default_value = BLUE_BALANCE_DEF,
251 },
252 .set = sd_setblue_balance,
253 .get = sd_getblue_balance,
254 },
255 {
256 {
257 .id = V4L2_CID_RED_BALANCE,
258 .type = V4L2_CTRL_TYPE_INTEGER,
259 .name = "Red Balance",
260 .minimum = 0x10,
261 .maximum = 0x40,
262 .step = 1,
263#define RED_BALANCE_DEF 0x20
264 .default_value = RED_BALANCE_DEF,
265 },
266 .set = sd_setred_balance,
267 .get = sd_getred_balance,
268 },
269 {
270 {
271 .id = V4L2_CID_GAIN,
272 .type = V4L2_CTRL_TYPE_INTEGER,
273 .name = "Gain",
274 .minimum = 0x10,
275 .maximum = 0x40,
276 .step = 1,
277#define global_gain_DEF 0x20
278 .default_value = global_gain_DEF,
279 },
280 .set = sd_setglobal_gain,
281 .get = sd_getglobal_gain,
282 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300283};
284
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300285static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300286 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
287 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -0300288 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300289 .colorspace = V4L2_COLORSPACE_JPEG,
290 .priv = 4},
291 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
292 .bytesperline = 176,
293 .sizeimage = 176 * 144 * 3 / 8 + 590,
294 .colorspace = V4L2_COLORSPACE_JPEG,
295 .priv = 3},
296 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
297 .bytesperline = 320,
298 .sizeimage = 320 * 240 * 3 / 8 + 590,
299 .colorspace = V4L2_COLORSPACE_JPEG,
300 .priv = 2},
301 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
302 .bytesperline = 352,
303 .sizeimage = 352 * 288 * 3 / 8 + 590,
304 .colorspace = V4L2_COLORSPACE_JPEG,
305 .priv = 1},
306 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
307 .bytesperline = 640,
308 .sizeimage = 640 * 480 * 3 / 8 + 590,
309 .colorspace = V4L2_COLORSPACE_JPEG,
310 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311};
312
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300313/* sensor specific data */
314struct additional_sensor_data {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300315 const u8 n3[6];
316 const u8 *n4, n4sz;
317 const u8 reg80, reg8e;
318 const u8 nset8[6];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300319 const u8 data1[10];
320 const u8 data2[9];
321 const u8 data3[9];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300322 const u8 data5[6];
323 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300324};
325
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300326static const u8 n4_om6802[] = {
327 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
328 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
329 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
330 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
331 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
332 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
333 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
334 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
335 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
336};
337static const u8 n4_other[] = {
338 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
339 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
340 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
341 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
342 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
343 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
344 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
345 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
346};
347static const u8 n4_tas5130a[] = {
348 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
349 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
350 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
351 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
352 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
353 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
354 0xc6, 0xda
355};
Nicolau Werneck00e80062010-01-30 16:00:15 -0300356static const u8 n4_lt168g[] = {
357 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
358 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
359 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
360 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
361 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
362 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
363 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
364 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
365 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
366};
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300367
Tobias Klausere23b2902009-02-09 18:06:49 -0300368static const struct additional_sensor_data sensor_data[] = {
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300369[SENSOR_OM6802] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300370 .n3 =
371 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
372 .n4 = n4_om6802,
373 .n4sz = sizeof n4_om6802,
374 .reg80 = 0x3c,
375 .reg8e = 0x33,
376 .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300377 .data1 =
378 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
379 0xb3, 0xfc},
380 .data2 =
381 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
382 0xff},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300383 .data3 =
384 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
385 0xff},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300386 .data5 = /* this could be removed later */
387 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
388 .stream =
389 {0x0b, 0x04, 0x0a, 0x78},
390 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300391[SENSOR_OTHER] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300392 .n3 =
393 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
394 .n4 = n4_other,
395 .n4sz = sizeof n4_other,
396 .reg80 = 0xac,
397 .reg8e = 0xb8,
398 .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300399 .data1 =
400 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
401 0xe8, 0xfc},
402 .data2 =
403 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
404 0xd9},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300405 .data3 =
406 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
407 0xd9},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300408 .data5 =
409 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
410 .stream =
411 {0x0b, 0x04, 0x0a, 0x00},
412 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300413[SENSOR_TAS5130A] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300414 .n3 =
415 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
416 .n4 = n4_tas5130a,
417 .n4sz = sizeof n4_tas5130a,
418 .reg80 = 0x3c,
419 .reg8e = 0xb4,
420 .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300421 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300422 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
423 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300424 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300425 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
426 0xe0},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300427 .data3 =
428 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
429 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300430 .data5 =
431 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
432 .stream =
433 {0x0b, 0x04, 0x0a, 0x40},
434 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300435[SENSOR_LT168G] = {
Nicolau Werneck00e80062010-01-30 16:00:15 -0300436 .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
437 .n4 = n4_lt168g,
438 .n4sz = sizeof n4_lt168g,
439 .reg80 = 0x7c,
440 .reg8e = 0xb3,
441 .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
442 .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
443 0xb0, 0xf4},
444 .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
445 0xff},
446 .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
447 0xff},
Nicolau Werneck00e80062010-01-30 16:00:15 -0300448 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
449 .stream = {0x0b, 0x04, 0x0a, 0x28},
450 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300451};
452
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453#define MAX_EFFECTS 7
454/* easily done by soft, this table could be removed,
455 * i keep it here just in case */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300456static char *effects_control[MAX_EFFECTS] = {
457 "Normal",
458 "Emboss", /* disabled */
459 "Monochrome",
460 "Sepia",
461 "Sketch",
462 "Sun Effect", /* disabled */
463 "Negative",
464};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300465static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
467 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
468 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
469 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
470 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
471 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
472 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
473};
474
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300475static const u8 gamma_table[GAMMA_MAX][17] = {
Jean-François Moine79960d32010-06-04 07:24:53 -0300476/* gamma table from cam1690.ini */
477 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
478 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300479 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300480 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
481 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300482 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300483 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
484 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300485 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300486 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
487 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300488 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300489 {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
490 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300491 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300492 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
493 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300494 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300495 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300496 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
497 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300498 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300499 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
500 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300501 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
502 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300503 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300504 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
505 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300506 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300507 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
508 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300509 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300510 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300511 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
512 0xff},
513 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
514 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
515 0xff},
516 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
517 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
518 0xff},
519 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
520 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
521 0xff},
522 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
523 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
524 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525};
526
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300527static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
529 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
530 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531};
532
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300533static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300534
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300536static u8 reg_r(struct gspca_dev *gspca_dev,
537 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300539 usb_control_msg(gspca_dev->dev,
540 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 0, /* request */
542 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
543 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300544 index,
545 gspca_dev->usb_buf, 1, 500);
546 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547}
548
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300549static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300550 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300552 usb_control_msg(gspca_dev->dev,
553 usb_sndctrlpipe(gspca_dev->dev, 0),
554 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300555 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300556 0, index,
557 NULL, 0, 500);
558}
559
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300560static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300561 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300562{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300563 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300564 memcpy(gspca_dev->usb_buf, buffer, len);
565 usb_control_msg(gspca_dev->dev,
566 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300567 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300568 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300569 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300570 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300571 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300572 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300573
574 tmpbuf = kmalloc(len, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300575 if (!tmpbuf) {
576 err("Out of memory");
577 return;
578 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300579 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300580 usb_control_msg(gspca_dev->dev,
581 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300582 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300583 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300584 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300585 tmpbuf, len, 500);
586 kfree(tmpbuf);
587 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588}
589
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300590/* write values to consecutive registers */
591static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
592 u8 reg,
593 const u8 *buffer, u16 len)
594{
595 int i;
596 u8 *p, *tmpbuf;
597
Jean-François Moine24f222e2010-03-07 05:58:55 -0300598 if (len * 2 <= USB_BUF_SZ) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300599 p = tmpbuf = gspca_dev->usb_buf;
Jean-François Moine24f222e2010-03-07 05:58:55 -0300600 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300601 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300602 if (!tmpbuf) {
603 err("Out of memory");
604 return;
605 }
606 }
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300607 i = len;
608 while (--i >= 0) {
609 *p++ = reg++;
610 *p++ = *buffer++;
611 }
612 usb_control_msg(gspca_dev->dev,
613 usb_sndctrlpipe(gspca_dev->dev, 0),
614 0,
615 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
616 0x01, 0,
617 tmpbuf, len * 2, 500);
618 if (len * 2 > USB_BUF_SZ)
619 kfree(tmpbuf);
620}
621
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300622static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300623{
624 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300625 const u8 *p;
626 u8 byte;
627 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
628 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300629 0xdf, 0x6d,
630 0xdd, 0x18,
631 0x5a, 0xe0,
632 0x5c, 0x07,
633 0x5d, 0xb0,
634 0x5e, 0x1e,
635 0x60, 0x71,
636 0xef, 0x00,
637 0xe9, 0x00,
638 0xea, 0x00,
639 0x90, 0x24,
640 0x91, 0xb2,
641 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300642 0xfd, 0x41,
643 0x00 /* table end */
644 };
645
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300646 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300647 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300648 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300649 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300650 byte = reg_r(gspca_dev, 0x0060);
651 if (!(byte & 0x01))
652 break;
653 msleep(100);
654 }
655 byte = reg_r(gspca_dev, 0x0063);
656 if (byte != 0x17) {
657 err("Bad sensor reset %02x", byte);
658 /* continue? */
659 }
660
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300661 p = sensor_init;
662 while (*p != 0) {
663 val[1] = *p++;
664 val[3] = *p++;
665 if (*p == 0)
666 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300667 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300668 i = 4;
669 while (--i >= 0) {
670 msleep(15);
671 byte = reg_r(gspca_dev, 0x60);
672 if (!(byte & 0x01))
673 break;
674 }
675 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300676 msleep(15);
677 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300678}
679
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680/* this function is called at probe time */
681static int sd_config(struct gspca_dev *gspca_dev,
682 const struct usb_device_id *id)
683{
684 struct sd *sd = (struct sd *) gspca_dev;
685 struct cam *cam;
686
687 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688
689 cam->cam_mode = vga_mode_t16;
690 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
691
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300692 sd->brightness = BRIGHTNESS_DEF;
693 sd->contrast = CONTRAST_DEF;
694 sd->colors = COLORS_DEF;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300695 sd->gamma = GAMMA_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300696 sd->autogain = AUTOGAIN_DEF;
697 sd->mirror = MIRROR_DEF;
698 sd->freq = FREQ_DEF;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300699 sd->awb = AWB_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300700 sd->sharpness = SHARPNESS_DEF;
701 sd->effect = EFFECTS_DEF;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300702 sd->red_balance = RED_BALANCE_DEF;
703 sd->blue_balance = BLUE_BALANCE_DEF;
704 sd->global_gain = global_gain_DEF;
705
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 return 0;
707}
708
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300709static void setbrightness(struct gspca_dev *gspca_dev)
710{
711 struct sd *sd = (struct sd *) gspca_dev;
712 unsigned int brightness;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300713 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300714
715 brightness = sd->brightness;
716 if (brightness < 7) {
717 set6[1] = 0x26;
718 set6[3] = 0x70 - brightness * 0x10;
719 } else {
720 set6[3] = 0x00 + ((brightness - 7) * 0x10);
721 }
722
723 reg_w_buf(gspca_dev, set6, sizeof set6);
724}
725
726static void setcontrast(struct gspca_dev *gspca_dev)
727{
728 struct sd *sd = (struct sd *) gspca_dev;
729 unsigned int contrast = sd->contrast;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300730 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300731
732 if (contrast < 7)
733 reg_to_write = 0x8ea9 - contrast * 0x200;
734 else
735 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
736
737 reg_w(gspca_dev, reg_to_write);
738}
739
740static void setcolors(struct gspca_dev *gspca_dev)
741{
742 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300743 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300744
745 reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
746 reg_w(gspca_dev, reg_to_write);
747}
748
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300749static void setgamma(struct gspca_dev *gspca_dev)
750{
751 struct sd *sd = (struct sd *) gspca_dev;
752
753 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300754 reg_w_ixbuf(gspca_dev, 0x90,
755 gamma_table[sd->gamma], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300756}
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300757static void setglobalgain(struct gspca_dev *gspca_dev)
758{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300759
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300760 struct sd *sd = (struct sd *) gspca_dev;
761 reg_w(gspca_dev, (sd->red_balance << 8) + 0x87);
762 reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
763 reg_w(gspca_dev, (sd->global_gain << 8) + 0x89);
764}
765
766/* Generic fnc for r/b balance, exposure and whitebalance */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300767static void setawb(struct gspca_dev *gspca_dev)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300768{
769 struct sd *sd = (struct sd *) gspca_dev;
770
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300771 /* on awb leave defaults values */
772 if (sd->awb) {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300773 reg_w(gspca_dev, 0x3c80);
774 } else {
775 reg_w(gspca_dev, 0x3880);
776 /* shoud we wait here.. */
777 /* update and reset 'global gain' with webcam parameters */
778 sd->red_balance = reg_r(gspca_dev, 0x0087);
779 sd->blue_balance = reg_r(gspca_dev, 0x0088);
780 sd->global_gain = reg_r(gspca_dev, 0x0089);
781 setglobalgain(gspca_dev);
782 }
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300783
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300784}
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300785
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300786static void setsharpness(struct gspca_dev *gspca_dev)
787{
788 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300789 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300790
791 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
792
793 reg_w(gspca_dev, reg_to_write);
794}
795
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300796static void setfreq(struct gspca_dev *gspca_dev)
797{
798 struct sd *sd = (struct sd *) gspca_dev;
799 u8 reg66;
800 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
801
802 switch (sd->sensor) {
803 case SENSOR_LT168G:
804 if (sd->freq != 0)
805 freq[3] = 0xa8;
806 reg66 = 0x41;
807 break;
808 case SENSOR_OM6802:
809 reg66 = 0xca;
810 break;
811 default:
812 reg66 = 0x40;
813 break;
814 }
815 switch (sd->freq) {
816 case 0: /* no flicker */
817 freq[3] = 0xf0;
818 break;
819 case 2: /* 60Hz */
820 reg66 &= ~0x40;
821 break;
822 }
823 freq[1] = reg66;
824
825 reg_w_buf(gspca_dev, freq, sizeof freq);
826}
827
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300828/* this function is called at probe and resume time */
829static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 /* some of this registers are not really neded, because
832 * they are overriden by setbrigthness, setcontrast, etc,
833 * but wont hurt anyway, and can help someone with similar webcam
834 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300835 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300836 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300837 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300838 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300839 u8 test_byte = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300841 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300842 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300843 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
844 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300845 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300846 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 {0x08, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300848
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300849 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
850 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300851 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300852 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300853 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300854 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300855 break;
Nicolau Werneck00e80062010-01-30 16:00:15 -0300856 case 0x0802:
857 PDEBUG(D_PROBE, "sensor lt168g");
858 sd->sensor = SENSOR_LT168G;
859 break;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300860 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300861 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300862 sd->sensor = SENSOR_OTHER;
863 break;
864 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300865 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300866 sd->sensor = SENSOR_OM6802;
867 break;
868 default:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300869 PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300870 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300871 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300873 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300874 reg_w_buf(gspca_dev, n1, sizeof n1);
875 i = 5;
876 while (--i >= 0) {
877 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
878 test_byte = reg_r(gspca_dev, 0x0063);
879 msleep(100);
880 if (test_byte == 0x17)
881 break; /* OK */
882 }
883 if (i < 0) {
884 err("Bad sensor reset %02x", test_byte);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300885 return -EIO;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300886 }
887 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300888 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300889
890 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300891 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300892 test_byte = reg_r(gspca_dev, read_indexs[i]);
893 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300894 test_byte);
895 i++;
896 }
897
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300898 sensor = &sensor_data[sd->sensor];
899 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
900 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300901
Nicolau Werneck00e80062010-01-30 16:00:15 -0300902 if (sd->sensor == SENSOR_LT168G) {
903 test_byte = reg_r(gspca_dev, 0x80);
904 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
905 test_byte);
906 reg_w(gspca_dev, 0x6c80);
907 }
908
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300909 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
910 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
911 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300912
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300913 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
914 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
915 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300916
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300917 setbrightness(gspca_dev);
918 setcontrast(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300919 setgamma(gspca_dev);
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300920 setcolors(gspca_dev);
921 setsharpness(gspca_dev);
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300922 setawb(gspca_dev);
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300923 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300925 reg_w(gspca_dev, 0x2087); /* tied to white balance? */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300926 reg_w(gspca_dev, 0x2088);
927 reg_w(gspca_dev, 0x2089);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300928
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300929 reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
930 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
931 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
932 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300933
Nicolau Werneck00e80062010-01-30 16:00:15 -0300934 if (sd->sensor == SENSOR_LT168G) {
935 test_byte = reg_r(gspca_dev, 0x80);
936 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
937 test_byte);
938 reg_w(gspca_dev, 0x6c80);
939 }
940
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300941 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
942 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
943 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300944
945 return 0;
946}
947
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300948static void setmirror(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949{
950 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300951 u8 hflipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300952 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300953
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300954 if (sd->mirror)
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300955 hflipcmd[3] = 0x01;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300956
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300957 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300958}
959
960static void seteffect(struct gspca_dev *gspca_dev)
961{
962 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300964 reg_w_buf(gspca_dev, effects_table[sd->effect],
965 sizeof effects_table[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300966 if (sd->effect == 1 || sd->effect == 5) {
967 PDEBUG(D_CONF,
968 "This effect have been disabled for webcam \"safety\"");
969 return;
970 }
971
972 if (sd->effect == 1 || sd->effect == 4)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300973 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300974 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300975 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300976}
977
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300978/* Is this really needed?
979 * i added some module parameters for test with some users */
980static void poll_sensor(struct gspca_dev *gspca_dev)
981{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300982 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300983 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
984 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
985 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
986 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300987 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300988 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
989 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300990 static const u8 poll3[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300991 {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300992 static const u8 poll4[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300993 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
994 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
995 0xc2, 0x80, 0xc3, 0x10};
996
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300997 PDEBUG(D_STREAM, "[Sensor requires polling]");
998 reg_w_buf(gspca_dev, poll1, sizeof poll1);
999 reg_w_buf(gspca_dev, poll2, sizeof poll2);
1000 reg_w_buf(gspca_dev, poll3, sizeof poll3);
1001 reg_w_buf(gspca_dev, poll4, sizeof poll4);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001002}
1003
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001004static int sd_start(struct gspca_dev *gspca_dev)
1005{
1006 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001007 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001008 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001009 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1010 static const u8 t3[] =
1011 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001012
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001013 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001014 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001015 case 0: /* 640x480 (0x00) */
1016 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001017 case 1: /* 352x288 */
1018 t2[1] = 0x40;
1019 break;
1020 case 2: /* 320x240 */
1021 t2[1] = 0x10;
1022 break;
1023 case 3: /* 176x144 */
1024 t2[1] = 0x50;
1025 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001026 default:
1027/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001028 t2[1] = 0x20;
1029 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001030 }
1031
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001032 switch (sd->sensor) {
1033 case SENSOR_OM6802:
1034 om6802_sensor_init(gspca_dev);
1035 break;
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001036 case SENSOR_TAS5130A:
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001037 i = 0;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001038 for (;;) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -03001039 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001040 sizeof tas5130a_sensor_init[0]);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001041 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
1042 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001043 i++;
1044 }
1045 reg_w(gspca_dev, 0x3c80);
1046 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001047 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001048 sizeof tas5130a_sensor_init[0]);
1049 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001050 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001051 }
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001052 sensor = &sensor_data[sd->sensor];
Jean-François Moine78b98cb2010-06-05 07:01:46 -03001053 setfreq(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001054 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001055 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001056 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001057 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001058 msleep(15);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001059 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
1060 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001061
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001062 if (sd->sensor == SENSOR_OM6802)
1063 poll_sensor(gspca_dev);
1064
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001065 return 0;
1066}
1067
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001068static void sd_stopN(struct gspca_dev *gspca_dev)
1069{
1070 struct sd *sd = (struct sd *) gspca_dev;
1071
1072 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1073 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001074 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1075 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001076 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001077 msleep(20);
1078 reg_w(gspca_dev, 0x0309);
1079 }
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001080}
1081
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001082static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001083 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001084 int len) /* iso packet length */
1085{
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001086 static u8 ffd9[] = { 0xff, 0xd9 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001087
1088 if (data[0] == 0x5a) {
1089 /* Control Packet, after this came the header again,
1090 * but extra bytes came in the packet before this,
1091 * sometimes an EOF arrives, sometimes not... */
1092 return;
1093 }
1094 data += 2;
1095 len -= 2;
1096 if (data[0] == 0xff && data[1] == 0xd8) {
1097 /* extra bytes....., could be processed too but would be
1098 * a waste of time, right now leave the application and
1099 * libjpeg do it for ourserlves.. */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001100 gspca_frame_add(gspca_dev, LAST_PACKET,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001101 ffd9, 2);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001102 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001103 return;
1104 }
1105
1106 if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
1107 /* Just in case, i have seen packets with the marker,
1108 * other's do not include it... */
1109 len -= 2;
1110 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001111 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001112}
1113
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001114
1115static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
1116{
1117 struct sd *sd = (struct sd *) gspca_dev;
1118
1119 sd->blue_balance = val;
1120 if (gspca_dev->streaming)
1121 reg_w(gspca_dev, (val << 8) + 0x88);
1122 return 0;
1123}
1124
1125static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
1126{
1127 struct sd *sd = (struct sd *) gspca_dev;
1128
1129 *val = sd->blue_balance;
1130 return 0;
1131}
1132
1133static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
1134{
1135 struct sd *sd = (struct sd *) gspca_dev;
1136
1137 sd->red_balance = val;
1138 if (gspca_dev->streaming)
1139 reg_w(gspca_dev, (val << 8) + 0x87);
1140
1141 return 0;
1142}
1143
1144static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
1145{
1146 struct sd *sd = (struct sd *) gspca_dev;
1147
1148 *val = sd->red_balance;
1149 return 0;
1150}
1151
1152
1153
1154static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
1155{
1156 struct sd *sd = (struct sd *) gspca_dev;
1157
1158 sd->global_gain = val;
1159 if (gspca_dev->streaming)
1160 setglobalgain(gspca_dev);
1161
1162 return 0;
1163}
1164
1165static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
1166{
1167 struct sd *sd = (struct sd *) gspca_dev;
1168
1169 *val = sd->global_gain;
1170 return 0;
1171}
1172
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001173static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1174{
1175 struct sd *sd = (struct sd *) gspca_dev;
1176
1177 sd->brightness = val;
1178 if (gspca_dev->streaming)
1179 setbrightness(gspca_dev);
1180 return 0;
1181}
1182
1183static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1184{
1185 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001186
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001187 *val = sd->brightness;
1188 return *val;
1189}
1190
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001191static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001192{
1193 struct sd *sd = (struct sd *) gspca_dev;
1194
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001195 sd->awb = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001196 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001197 setawb(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001198 return 0;
1199}
1200
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001201static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001202{
1203 struct sd *sd = (struct sd *) gspca_dev;
1204
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001205 *val = sd->awb;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001206 return *val;
1207}
1208
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001209static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001210{
1211 struct sd *sd = (struct sd *) gspca_dev;
1212
1213 sd->mirror = val;
1214 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001215 setmirror(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001216 return 0;
1217}
1218
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001219static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001220{
1221 struct sd *sd = (struct sd *) gspca_dev;
1222
1223 *val = sd->mirror;
1224 return *val;
1225}
1226
1227static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
1228{
1229 struct sd *sd = (struct sd *) gspca_dev;
1230
1231 sd->effect = val;
1232 if (gspca_dev->streaming)
1233 seteffect(gspca_dev);
1234 return 0;
1235}
1236
1237static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
1238{
1239 struct sd *sd = (struct sd *) gspca_dev;
1240
1241 *val = sd->effect;
1242 return *val;
1243}
1244
1245static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1246{
1247 struct sd *sd = (struct sd *) gspca_dev;
1248
1249 sd->contrast = val;
1250 if (gspca_dev->streaming)
1251 setcontrast(gspca_dev);
1252 return 0;
1253}
1254
1255static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1256{
1257 struct sd *sd = (struct sd *) gspca_dev;
1258
1259 *val = sd->contrast;
1260 return *val;
1261}
1262
1263static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1264{
1265 struct sd *sd = (struct sd *) gspca_dev;
1266
1267 sd->colors = val;
1268 if (gspca_dev->streaming)
1269 setcolors(gspca_dev);
1270 return 0;
1271}
1272
1273static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1274{
1275 struct sd *sd = (struct sd *) gspca_dev;
1276
1277 *val = sd->colors;
1278 return 0;
1279}
1280
1281static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
1282{
1283 struct sd *sd = (struct sd *) gspca_dev;
1284
1285 sd->gamma = val;
1286 if (gspca_dev->streaming)
1287 setgamma(gspca_dev);
1288 return 0;
1289}
1290
1291static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
1292{
1293 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001294
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001295 *val = sd->gamma;
1296 return 0;
1297}
1298
1299static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1300{
1301 struct sd *sd = (struct sd *) gspca_dev;
1302
1303 sd->freq = val;
1304 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001305 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001306 return 0;
1307}
1308
1309static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1310{
1311 struct sd *sd = (struct sd *) gspca_dev;
1312
1313 *val = sd->freq;
1314 return 0;
1315}
1316
1317static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
1318{
1319 struct sd *sd = (struct sd *) gspca_dev;
1320
1321 sd->sharpness = val;
1322 if (gspca_dev->streaming)
1323 setsharpness(gspca_dev);
1324 return 0;
1325}
1326
1327static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
1328{
1329 struct sd *sd = (struct sd *) gspca_dev;
1330
1331 *val = sd->sharpness;
1332 return 0;
1333}
1334
1335/* Low Light set here......*/
1336static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
1337{
1338 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001339
1340 sd->autogain = val;
1341 if (val != 0)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001342 reg_w(gspca_dev, 0xf48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001343 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001344 reg_w(gspca_dev, 0xb48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001345 return 0;
1346}
1347
1348static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
1349{
1350 struct sd *sd = (struct sd *) gspca_dev;
1351
1352 *val = sd->autogain;
1353 return 0;
1354}
1355
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001356static int sd_querymenu(struct gspca_dev *gspca_dev,
1357 struct v4l2_querymenu *menu)
1358{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001359 switch (menu->id) {
1360 case V4L2_CID_POWER_LINE_FREQUENCY:
1361 switch (menu->index) {
1362 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001363 strcpy((char *) menu->name, "50 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001364 return 0;
1365 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001366 strcpy((char *) menu->name, "60 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001367 return 0;
1368 }
1369 break;
1370 case V4L2_CID_EFFECTS:
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001371 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
1372 strncpy((char *) menu->name,
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001373 effects_control[menu->index],
1374 sizeof menu->name);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001375 return 0;
1376 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001377 break;
1378 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001379 return -EINVAL;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001380}
1381
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001382/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001383static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001384 .name = MODULE_NAME,
1385 .ctrls = sd_ctrls,
1386 .nctrls = ARRAY_SIZE(sd_ctrls),
1387 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001388 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001389 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001390 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001391 .pkt_scan = sd_pkt_scan,
1392 .querymenu = sd_querymenu,
1393};
1394
1395/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001396static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001397 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001398 {}
1399};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001400MODULE_DEVICE_TABLE(usb, device_table);
1401
1402/* -- device connect -- */
1403static int sd_probe(struct usb_interface *intf,
1404 const struct usb_device_id *id)
1405{
1406 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1407 THIS_MODULE);
1408}
1409
1410static struct usb_driver sd_driver = {
1411 .name = MODULE_NAME,
1412 .id_table = device_table,
1413 .probe = sd_probe,
1414 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001415#ifdef CONFIG_PM
1416 .suspend = gspca_suspend,
1417 .resume = gspca_resume,
1418#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001419};
1420
1421/* -- module insert / remove -- */
1422static int __init sd_mod_init(void)
1423{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001424 int ret;
1425 ret = usb_register(&sd_driver);
1426 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001427 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001428 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001429 return 0;
1430}
1431static void __exit sd_mod_exit(void)
1432{
1433 usb_deregister(&sd_driver);
1434 PDEBUG(D_PROBE, "deregistered");
1435}
1436
1437module_init(sd_mod_init);
1438module_exit(sd_mod_exit);