blob: d1d733b9359b41e9f012a6d6b651d2f4b2597a3b [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-François Moinebe2a9fa2010-06-04 06:42:32 -030031#include <linux/slab.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030032#include "gspca.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030033
Jean-Francois Moinef9b4a372008-09-03 16:48:14 -030034#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030035
36MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
37MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
38MODULE_LICENSE("GPL");
39
40struct sd {
41 struct gspca_dev gspca_dev; /* !! must be the first item */
42
Jean-Francois Moine82e25492009-01-22 07:18:48 -030043 u8 brightness;
44 u8 contrast;
45 u8 colors;
46 u8 autogain;
47 u8 gamma;
48 u8 sharpness;
49 u8 freq;
Jean-François Moinee9b15652010-06-05 07:07:56 -030050 u8 red_gain;
51 u8 blue_gain;
52 u8 green_gain;
Jean-François Moinecd8955b2010-06-04 07:22:57 -030053 u8 awb; /* set default r/g/b and activate */
Jean-Francois Moine82e25492009-01-22 07:18:48 -030054 u8 mirror;
55 u8 effect;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030056
Jean-Francois Moine82e25492009-01-22 07:18:48 -030057 u8 sensor;
Jean-François Moine11ce8842010-07-26 06:39:40 -030058};
59enum sensors {
Jean-François Moinecd8955b2010-06-04 07:22:57 -030060 SENSOR_OM6802,
61 SENSOR_OTHER,
62 SENSOR_TAS5130A,
63 SENSOR_LT168G, /* must verify if this is the actual model */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064};
65
66/* V4L2 controls supported by the driver */
67static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
71static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
72static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
73static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
74static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
75static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
76static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
77static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
78static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
79static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
80static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -030081
Jean-François Moinecd8955b2010-06-04 07:22:57 -030082static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
Jean-François Moinee9b15652010-06-05 07:07:56 -030084static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -030090
Jean-François Moinecd8955b2010-06-04 07:22:57 -030091static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
94static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030095
Marton Nemeth7e64dc42009-12-30 09:12:41 -030096static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 {
98 {
99 .id = V4L2_CID_BRIGHTNESS,
100 .type = V4L2_CTRL_TYPE_INTEGER,
101 .name = "Brightness",
102 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300103 .maximum = 14,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300105#define BRIGHTNESS_DEF 8
106 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 },
108 .set = sd_setbrightness,
109 .get = sd_getbrightness,
110 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 {
112 {
113 .id = V4L2_CID_CONTRAST,
114 .type = V4L2_CTRL_TYPE_INTEGER,
115 .name = "Contrast",
116 .minimum = 0,
117 .maximum = 0x0d,
118 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300119#define CONTRAST_DEF 0x07
120 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300121 },
122 .set = sd_setcontrast,
123 .get = sd_getcontrast,
124 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125 {
126 {
127 .id = V4L2_CID_SATURATION,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "Color",
130 .minimum = 0,
131 .maximum = 0x0f,
132 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300133#define COLORS_DEF 0x05
134 .default_value = COLORS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300135 },
136 .set = sd_setcolors,
137 .get = sd_getcolors,
138 },
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300139#define GAMMA_MAX 16
140#define GAMMA_DEF 10
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300141 {
142 {
143 .id = V4L2_CID_GAMMA, /* (gamma on win) */
144 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300145 .name = "Gamma",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300146 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300147 .maximum = GAMMA_MAX - 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300148 .step = 1,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300149 .default_value = GAMMA_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300150 },
151 .set = sd_setgamma,
152 .get = sd_getgamma,
153 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300154 {
155 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300156 .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300157 * some apps dont bring up the
158 * backligth_compensation control) */
159 .type = V4L2_CTRL_TYPE_INTEGER,
160 .name = "Low Light",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300164#define AUTOGAIN_DEF 0x01
165 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300166 },
167 .set = sd_setlowlight,
168 .get = sd_getlowlight,
169 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300170 {
171 {
172 .id = V4L2_CID_HFLIP,
173 .type = V4L2_CTRL_TYPE_BOOLEAN,
174 .name = "Mirror Image",
175 .minimum = 0,
176 .maximum = 1,
177 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300178#define MIRROR_DEF 0
179 .default_value = MIRROR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300181 .set = sd_setmirror,
182 .get = sd_getmirror
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300184 {
185 {
186 .id = V4L2_CID_POWER_LINE_FREQUENCY,
187 .type = V4L2_CTRL_TYPE_MENU,
188 .name = "Light Frequency Filter",
189 .minimum = 1, /* 1 -> 0x50, 2->0x60 */
190 .maximum = 2,
191 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300192#define FREQ_DEF 1
193 .default_value = FREQ_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300194 },
195 .set = sd_setfreq,
196 .get = sd_getfreq},
197
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198 {
199 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300200 .id = V4L2_CID_AUTO_WHITE_BALANCE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300201 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300202 .name = "Auto White Balance",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203 .minimum = 0,
204 .maximum = 1,
205 .step = 1,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300206#define AWB_DEF 0
207 .default_value = AWB_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300208 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300209 .set = sd_setawb,
210 .get = sd_getawb
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300212 {
213 {
214 .id = V4L2_CID_SHARPNESS,
215 .type = V4L2_CTRL_TYPE_INTEGER,
216 .name = "Sharpness",
217 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300218 .maximum = 15,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300220#define SHARPNESS_DEF 0x06
221 .default_value = SHARPNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300222 },
223 .set = sd_setsharpness,
224 .get = sd_getsharpness,
225 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 {
227 {
228 .id = V4L2_CID_EFFECTS,
229 .type = V4L2_CTRL_TYPE_MENU,
230 .name = "Webcam Effects",
231 .minimum = 0,
232 .maximum = 4,
233 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300234#define EFFECTS_DEF 0
235 .default_value = EFFECTS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300236 },
237 .set = sd_seteffect,
238 .get = sd_geteffect
239 },
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300240 {
241 {
242 .id = V4L2_CID_BLUE_BALANCE,
243 .type = V4L2_CTRL_TYPE_INTEGER,
244 .name = "Blue Balance",
245 .minimum = 0x10,
246 .maximum = 0x40,
247 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300248#define BLUE_GAIN_DEF 0x20
249 .default_value = BLUE_GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300250 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300251 .set = sd_setblue_gain,
252 .get = sd_getblue_gain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300253 },
254 {
255 {
256 .id = V4L2_CID_RED_BALANCE,
257 .type = V4L2_CTRL_TYPE_INTEGER,
258 .name = "Red Balance",
259 .minimum = 0x10,
260 .maximum = 0x40,
261 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300262#define RED_GAIN_DEF 0x20
263 .default_value = RED_GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300264 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300265 .set = sd_setred_gain,
266 .get = sd_getred_gain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300267 },
268 {
269 {
270 .id = V4L2_CID_GAIN,
271 .type = V4L2_CTRL_TYPE_INTEGER,
272 .name = "Gain",
273 .minimum = 0x10,
274 .maximum = 0x40,
275 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300276#define GAIN_DEF 0x20
277 .default_value = GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300278 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300279 .set = sd_setgain,
280 .get = sd_getgain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300281 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282};
283
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300284static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300285 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
286 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -0300287 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300288 .colorspace = V4L2_COLORSPACE_JPEG,
289 .priv = 4},
290 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
291 .bytesperline = 176,
292 .sizeimage = 176 * 144 * 3 / 8 + 590,
293 .colorspace = V4L2_COLORSPACE_JPEG,
294 .priv = 3},
295 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
296 .bytesperline = 320,
297 .sizeimage = 320 * 240 * 3 / 8 + 590,
298 .colorspace = V4L2_COLORSPACE_JPEG,
299 .priv = 2},
300 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
301 .bytesperline = 352,
302 .sizeimage = 352 * 288 * 3 / 8 + 590,
303 .colorspace = V4L2_COLORSPACE_JPEG,
304 .priv = 1},
305 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
306 .bytesperline = 640,
307 .sizeimage = 640 * 480 * 3 / 8 + 590,
308 .colorspace = V4L2_COLORSPACE_JPEG,
309 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310};
311
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300312/* sensor specific data */
313struct additional_sensor_data {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300314 const u8 n3[6];
315 const u8 *n4, n4sz;
316 const u8 reg80, reg8e;
317 const u8 nset8[6];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300318 const u8 data1[10];
319 const u8 data2[9];
320 const u8 data3[9];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300321 const u8 data5[6];
322 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300323};
324
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300325static const u8 n4_om6802[] = {
326 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
327 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
328 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
329 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
330 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
331 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
332 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
333 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
334 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
335};
336static const u8 n4_other[] = {
337 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
338 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
339 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
340 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
341 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
342 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
343 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
344 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
345};
346static const u8 n4_tas5130a[] = {
347 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
348 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
349 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
350 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
351 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
352 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
353 0xc6, 0xda
354};
Nicolau Werneck00e80062010-01-30 16:00:15 -0300355static const u8 n4_lt168g[] = {
356 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
357 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
358 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
359 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
360 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
361 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
362 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
363 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
364 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
365};
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300366
Tobias Klausere23b2902009-02-09 18:06:49 -0300367static const struct additional_sensor_data sensor_data[] = {
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300368[SENSOR_OM6802] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300369 .n3 =
370 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
371 .n4 = n4_om6802,
372 .n4sz = sizeof n4_om6802,
373 .reg80 = 0x3c,
374 .reg8e = 0x33,
375 .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300376 .data1 =
377 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
378 0xb3, 0xfc},
379 .data2 =
380 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
381 0xff},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300382 .data3 =
383 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
384 0xff},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300385 .data5 = /* this could be removed later */
386 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
387 .stream =
388 {0x0b, 0x04, 0x0a, 0x78},
389 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300390[SENSOR_OTHER] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300391 .n3 =
392 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
393 .n4 = n4_other,
394 .n4sz = sizeof n4_other,
395 .reg80 = 0xac,
396 .reg8e = 0xb8,
397 .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300398 .data1 =
399 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
400 0xe8, 0xfc},
401 .data2 =
402 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
403 0xd9},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300404 .data3 =
405 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
406 0xd9},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300407 .data5 =
408 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
409 .stream =
410 {0x0b, 0x04, 0x0a, 0x00},
411 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300412[SENSOR_TAS5130A] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300413 .n3 =
414 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
415 .n4 = n4_tas5130a,
416 .n4sz = sizeof n4_tas5130a,
417 .reg80 = 0x3c,
418 .reg8e = 0xb4,
419 .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300420 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300421 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
422 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300423 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300424 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
425 0xe0},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300426 .data3 =
427 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
428 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300429 .data5 =
430 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
431 .stream =
432 {0x0b, 0x04, 0x0a, 0x40},
433 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300434[SENSOR_LT168G] = {
Nicolau Werneck00e80062010-01-30 16:00:15 -0300435 .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
436 .n4 = n4_lt168g,
437 .n4sz = sizeof n4_lt168g,
438 .reg80 = 0x7c,
439 .reg8e = 0xb3,
440 .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
441 .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
442 0xb0, 0xf4},
443 .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
444 0xff},
445 .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
446 0xff},
Nicolau Werneck00e80062010-01-30 16:00:15 -0300447 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
448 .stream = {0x0b, 0x04, 0x0a, 0x28},
449 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300450};
451
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300452#define MAX_EFFECTS 7
453/* easily done by soft, this table could be removed,
454 * i keep it here just in case */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300455static char *effects_control[MAX_EFFECTS] = {
456 "Normal",
457 "Emboss", /* disabled */
458 "Monochrome",
459 "Sepia",
460 "Sketch",
461 "Sun Effect", /* disabled */
462 "Negative",
463};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300464static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
466 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
467 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
468 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
469 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
470 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
471 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
472};
473
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300474static const u8 gamma_table[GAMMA_MAX][17] = {
Jean-François Moine79960d32010-06-04 07:24:53 -0300475/* gamma table from cam1690.ini */
476 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
477 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300478 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300479 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
480 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300481 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300482 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
483 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300484 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300485 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
486 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300487 0xff},
Jean-François Moine1d00d6c2010-10-29 13:58:22 -0300488 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
Jean-François Moine79960d32010-06-04 07:24:53 -0300489 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300490 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300491 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
492 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300493 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300494 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300495 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
496 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300497 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300498 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
499 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300500 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
501 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300502 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300503 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
504 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300505 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300506 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
507 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300508 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300509 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300510 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
511 0xff},
512 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
513 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
514 0xff},
515 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
516 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
517 0xff},
518 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
519 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
520 0xff},
521 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
522 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
523 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524};
525
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300526static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
528 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
529 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530};
531
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300532static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300533
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300535static u8 reg_r(struct gspca_dev *gspca_dev,
536 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 usb_control_msg(gspca_dev->dev,
539 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 0, /* request */
541 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
542 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 index,
544 gspca_dev->usb_buf, 1, 500);
545 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546}
547
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300548static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300549 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300551 usb_control_msg(gspca_dev->dev,
552 usb_sndctrlpipe(gspca_dev->dev, 0),
553 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300554 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300555 0, index,
556 NULL, 0, 500);
557}
558
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300559static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300560 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300561{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300562 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300563 memcpy(gspca_dev->usb_buf, buffer, len);
564 usb_control_msg(gspca_dev->dev,
565 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300566 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300567 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300568 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300569 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300570 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300571 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300572
Julia Lawallfeda79b2010-07-01 01:30:11 -0300573 tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300574 if (!tmpbuf) {
575 err("Out of memory");
576 return;
577 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300578 usb_control_msg(gspca_dev->dev,
579 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300580 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300581 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300582 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300583 tmpbuf, len, 500);
584 kfree(tmpbuf);
585 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586}
587
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300588/* write values to consecutive registers */
589static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
590 u8 reg,
591 const u8 *buffer, u16 len)
592{
593 int i;
594 u8 *p, *tmpbuf;
595
Jean-François Moine24f222e2010-03-07 05:58:55 -0300596 if (len * 2 <= USB_BUF_SZ) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300597 p = tmpbuf = gspca_dev->usb_buf;
Jean-François Moine24f222e2010-03-07 05:58:55 -0300598 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300599 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300600 if (!tmpbuf) {
601 err("Out of memory");
602 return;
603 }
604 }
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300605 i = len;
606 while (--i >= 0) {
607 *p++ = reg++;
608 *p++ = *buffer++;
609 }
610 usb_control_msg(gspca_dev->dev,
611 usb_sndctrlpipe(gspca_dev->dev, 0),
612 0,
613 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
614 0x01, 0,
615 tmpbuf, len * 2, 500);
616 if (len * 2 > USB_BUF_SZ)
617 kfree(tmpbuf);
618}
619
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300620static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300621{
622 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300623 const u8 *p;
624 u8 byte;
625 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
626 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300627 0xdf, 0x6d,
628 0xdd, 0x18,
629 0x5a, 0xe0,
630 0x5c, 0x07,
631 0x5d, 0xb0,
632 0x5e, 0x1e,
633 0x60, 0x71,
634 0xef, 0x00,
635 0xe9, 0x00,
636 0xea, 0x00,
637 0x90, 0x24,
638 0x91, 0xb2,
639 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300640 0xfd, 0x41,
641 0x00 /* table end */
642 };
643
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300644 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300645 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300646 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300647 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300648 byte = reg_r(gspca_dev, 0x0060);
649 if (!(byte & 0x01))
650 break;
651 msleep(100);
652 }
653 byte = reg_r(gspca_dev, 0x0063);
654 if (byte != 0x17) {
655 err("Bad sensor reset %02x", byte);
656 /* continue? */
657 }
658
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300659 p = sensor_init;
660 while (*p != 0) {
661 val[1] = *p++;
662 val[3] = *p++;
663 if (*p == 0)
664 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300665 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300666 i = 4;
667 while (--i >= 0) {
668 msleep(15);
669 byte = reg_r(gspca_dev, 0x60);
670 if (!(byte & 0x01))
671 break;
672 }
673 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300674 msleep(15);
675 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300676}
677
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678/* this function is called at probe time */
679static int sd_config(struct gspca_dev *gspca_dev,
680 const struct usb_device_id *id)
681{
682 struct sd *sd = (struct sd *) gspca_dev;
683 struct cam *cam;
684
685 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686
687 cam->cam_mode = vga_mode_t16;
688 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
689
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300690 sd->brightness = BRIGHTNESS_DEF;
691 sd->contrast = CONTRAST_DEF;
692 sd->colors = COLORS_DEF;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300693 sd->gamma = GAMMA_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300694 sd->autogain = AUTOGAIN_DEF;
695 sd->mirror = MIRROR_DEF;
696 sd->freq = FREQ_DEF;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300697 sd->awb = AWB_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300698 sd->sharpness = SHARPNESS_DEF;
699 sd->effect = EFFECTS_DEF;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300700 sd->red_gain = RED_GAIN_DEF;
701 sd->blue_gain = BLUE_GAIN_DEF;
702 sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300703
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 return 0;
705}
706
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300707static void setbrightness(struct gspca_dev *gspca_dev)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710 unsigned int brightness;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300711 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300712
713 brightness = sd->brightness;
714 if (brightness < 7) {
715 set6[1] = 0x26;
716 set6[3] = 0x70 - brightness * 0x10;
717 } else {
718 set6[3] = 0x00 + ((brightness - 7) * 0x10);
719 }
720
721 reg_w_buf(gspca_dev, set6, sizeof set6);
722}
723
724static void setcontrast(struct gspca_dev *gspca_dev)
725{
726 struct sd *sd = (struct sd *) gspca_dev;
727 unsigned int contrast = sd->contrast;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300728 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300729
730 if (contrast < 7)
731 reg_to_write = 0x8ea9 - contrast * 0x200;
732 else
733 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
734
735 reg_w(gspca_dev, reg_to_write);
736}
737
738static void setcolors(struct gspca_dev *gspca_dev)
739{
740 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300741 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300742
743 reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
744 reg_w(gspca_dev, reg_to_write);
745}
746
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300747static void setgamma(struct gspca_dev *gspca_dev)
748{
749 struct sd *sd = (struct sd *) gspca_dev;
750
751 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300752 reg_w_ixbuf(gspca_dev, 0x90,
753 gamma_table[sd->gamma], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300754}
755
Jean-François Moinee9b15652010-06-05 07:07:56 -0300756static void setRGB(struct gspca_dev *gspca_dev)
757{
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300758 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300759 u8 all_gain_reg[6] =
760 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
761
762 all_gain_reg[1] = sd->red_gain;
763 all_gain_reg[3] = sd->blue_gain;
764 all_gain_reg[5] = sd->green_gain;
765 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300766}
767
Jean-François Moinee9b15652010-06-05 07:07:56 -0300768/* Generic fnc for r/b balance, exposure and awb */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300769static void setawb(struct gspca_dev *gspca_dev)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300770{
771 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300772 u16 reg80;
773
774 reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300775
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300776 /* on awb leave defaults values */
Jean-François Moinee9b15652010-06-05 07:07:56 -0300777 if (!sd->awb) {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300778 /* shoud we wait here.. */
Jean-François Moinee9b15652010-06-05 07:07:56 -0300779 /* update and reset RGB gains with webcam values */
780 sd->red_gain = reg_r(gspca_dev, 0x0087);
781 sd->blue_gain = reg_r(gspca_dev, 0x0088);
782 sd->green_gain = reg_r(gspca_dev, 0x0089);
783 reg80 &= ~0x0400; /* AWB off */
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300784 }
Jean-François Moinee9b15652010-06-05 07:07:56 -0300785 reg_w(gspca_dev, reg80);
786 reg_w(gspca_dev, reg80);
787}
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300788
Jean-François Moinee9b15652010-06-05 07:07:56 -0300789static void init_gains(struct gspca_dev *gspca_dev)
790{
791 struct sd *sd = (struct sd *) gspca_dev;
792 u16 reg80;
793 u8 all_gain_reg[8] =
794 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
795
796 all_gain_reg[1] = sd->red_gain;
797 all_gain_reg[3] = sd->blue_gain;
798 all_gain_reg[5] = sd->green_gain;
799 reg80 = sensor_data[sd->sensor].reg80;
800 if (!sd->awb)
801 reg80 &= ~0x04;
802 all_gain_reg[7] = reg80;
803 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
804
805 reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);
806 reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
807 reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300808}
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300809
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300810static void setsharpness(struct gspca_dev *gspca_dev)
811{
812 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300813 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300814
815 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
816
817 reg_w(gspca_dev, reg_to_write);
818}
819
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300820static void setfreq(struct gspca_dev *gspca_dev)
821{
822 struct sd *sd = (struct sd *) gspca_dev;
823 u8 reg66;
824 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
825
826 switch (sd->sensor) {
827 case SENSOR_LT168G:
828 if (sd->freq != 0)
829 freq[3] = 0xa8;
830 reg66 = 0x41;
831 break;
832 case SENSOR_OM6802:
833 reg66 = 0xca;
834 break;
835 default:
836 reg66 = 0x40;
837 break;
838 }
839 switch (sd->freq) {
840 case 0: /* no flicker */
841 freq[3] = 0xf0;
842 break;
843 case 2: /* 60Hz */
844 reg66 &= ~0x40;
845 break;
846 }
847 freq[1] = reg66;
848
849 reg_w_buf(gspca_dev, freq, sizeof freq);
850}
851
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300852/* this function is called at probe and resume time */
853static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855 /* some of this registers are not really neded, because
856 * they are overriden by setbrigthness, setcontrast, etc,
857 * but wont hurt anyway, and can help someone with similar webcam
858 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300859 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300860 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300861 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300862 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300863 u8 test_byte = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300864
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300865 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300866 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300867 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
868 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300870 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 {0x08, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300873 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
874 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300875 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300876 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300877 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300878 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300879 break;
Nicolau Werneck00e80062010-01-30 16:00:15 -0300880 case 0x0802:
881 PDEBUG(D_PROBE, "sensor lt168g");
882 sd->sensor = SENSOR_LT168G;
883 break;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300884 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300885 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300886 sd->sensor = SENSOR_OTHER;
887 break;
888 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300889 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300890 sd->sensor = SENSOR_OM6802;
891 break;
892 default:
Jean-François Moine0b656322010-09-13 05:19:58 -0300893 err("unknown sensor %04x", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300894 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300895 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300897 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300898 reg_w_buf(gspca_dev, n1, sizeof n1);
899 i = 5;
900 while (--i >= 0) {
901 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
902 test_byte = reg_r(gspca_dev, 0x0063);
903 msleep(100);
904 if (test_byte == 0x17)
905 break; /* OK */
906 }
907 if (i < 0) {
908 err("Bad sensor reset %02x", test_byte);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300909 return -EIO;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300910 }
911 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300912 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300913
914 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300915 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300916 test_byte = reg_r(gspca_dev, read_indexs[i]);
917 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 test_byte);
919 i++;
920 }
921
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300922 sensor = &sensor_data[sd->sensor];
923 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
924 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300925
Nicolau Werneck00e80062010-01-30 16:00:15 -0300926 if (sd->sensor == SENSOR_LT168G) {
927 test_byte = reg_r(gspca_dev, 0x80);
928 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
929 test_byte);
930 reg_w(gspca_dev, 0x6c80);
931 }
932
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300933 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
934 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
935 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300936
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300937 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
938 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
939 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300940
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300941 setbrightness(gspca_dev);
942 setcontrast(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300943 setgamma(gspca_dev);
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300944 setcolors(gspca_dev);
945 setsharpness(gspca_dev);
Jean-François Moinee9b15652010-06-05 07:07:56 -0300946 init_gains(gspca_dev);
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300947 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300948
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300949 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
950 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
951 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300952
Nicolau Werneck00e80062010-01-30 16:00:15 -0300953 if (sd->sensor == SENSOR_LT168G) {
954 test_byte = reg_r(gspca_dev, 0x80);
955 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
956 test_byte);
957 reg_w(gspca_dev, 0x6c80);
958 }
959
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300960 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
961 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
962 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963
964 return 0;
965}
966
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300967static void setmirror(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968{
969 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300970 u8 hflipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300971 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300972
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300973 if (sd->mirror)
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300974 hflipcmd[3] = 0x01;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300975
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300976 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977}
978
979static void seteffect(struct gspca_dev *gspca_dev)
980{
981 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300983 reg_w_buf(gspca_dev, effects_table[sd->effect],
984 sizeof effects_table[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985 if (sd->effect == 1 || sd->effect == 5) {
986 PDEBUG(D_CONF,
987 "This effect have been disabled for webcam \"safety\"");
988 return;
989 }
990
991 if (sd->effect == 1 || sd->effect == 4)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300992 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300994 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300995}
996
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300997/* Is this really needed?
998 * i added some module parameters for test with some users */
999static void poll_sensor(struct gspca_dev *gspca_dev)
1000{
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001001 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001002 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
1003 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
1004 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
1005 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001006 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001007 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
1008 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-François Moine98388242010-06-04 07:30:21 -03001009 static const u8 noise03[] = /* (some differences / ms-drv) */
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001010 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
1011 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
1012 0xc2, 0x80, 0xc3, 0x10};
1013
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001014 PDEBUG(D_STREAM, "[Sensor requires polling]");
1015 reg_w_buf(gspca_dev, poll1, sizeof poll1);
1016 reg_w_buf(gspca_dev, poll2, sizeof poll2);
Jean-François Moine98388242010-06-04 07:30:21 -03001017 reg_w_buf(gspca_dev, noise03, sizeof noise03);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001018}
1019
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001020static int sd_start(struct gspca_dev *gspca_dev)
1021{
1022 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001023 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001024 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001025 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1026 static const u8 t3[] =
1027 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001028
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001029 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001030 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001031 case 0: /* 640x480 (0x00) */
1032 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001033 case 1: /* 352x288 */
1034 t2[1] = 0x40;
1035 break;
1036 case 2: /* 320x240 */
1037 t2[1] = 0x10;
1038 break;
1039 case 3: /* 176x144 */
1040 t2[1] = 0x50;
1041 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001042 default:
1043/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001044 t2[1] = 0x20;
1045 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001046 }
1047
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001048 switch (sd->sensor) {
1049 case SENSOR_OM6802:
1050 om6802_sensor_init(gspca_dev);
1051 break;
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001052 case SENSOR_TAS5130A:
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001053 i = 0;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001054 for (;;) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -03001055 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001056 sizeof tas5130a_sensor_init[0]);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001057 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
1058 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001059 i++;
1060 }
1061 reg_w(gspca_dev, 0x3c80);
1062 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001063 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001064 sizeof tas5130a_sensor_init[0]);
1065 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001066 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001067 }
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001068 sensor = &sensor_data[sd->sensor];
Jean-François Moine78b98cb2010-06-05 07:01:46 -03001069 setfreq(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001070 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001071 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001072 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001073 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001074 msleep(15);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001075 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
1076 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001077
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001078 if (sd->sensor == SENSOR_OM6802)
1079 poll_sensor(gspca_dev);
1080
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001081 return 0;
1082}
1083
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001084static void sd_stopN(struct gspca_dev *gspca_dev)
1085{
1086 struct sd *sd = (struct sd *) gspca_dev;
1087
1088 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1089 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001090 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1091 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001092 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001093 msleep(20);
1094 reg_w(gspca_dev, 0x0309);
1095 }
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001096}
1097
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001098static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001099 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001100 int len) /* iso packet length */
1101{
Jean-François Moineebb78c52010-06-05 06:56:48 -03001102 int pkt_type;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001103
1104 if (data[0] == 0x5a) {
1105 /* Control Packet, after this came the header again,
1106 * but extra bytes came in the packet before this,
1107 * sometimes an EOF arrives, sometimes not... */
1108 return;
1109 }
1110 data += 2;
1111 len -= 2;
Jean-François Moineebb78c52010-06-05 06:56:48 -03001112 if (data[0] == 0xff && data[1] == 0xd8)
1113 pkt_type = FIRST_PACKET;
1114 else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
1115 pkt_type = LAST_PACKET;
1116 else
1117 pkt_type = INTER_PACKET;
1118 gspca_frame_add(gspca_dev, pkt_type, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001119}
1120
Jean-François Moinee9b15652010-06-05 07:07:56 -03001121static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001122{
1123 struct sd *sd = (struct sd *) gspca_dev;
1124
Jean-François Moinee9b15652010-06-05 07:07:56 -03001125 sd->blue_gain = val;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001126 if (gspca_dev->streaming)
1127 reg_w(gspca_dev, (val << 8) + 0x88);
1128 return 0;
1129}
1130
Jean-François Moinee9b15652010-06-05 07:07:56 -03001131static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001132{
1133 struct sd *sd = (struct sd *) gspca_dev;
1134
Jean-François Moinee9b15652010-06-05 07:07:56 -03001135 *val = sd->blue_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001136 return 0;
1137}
1138
Jean-François Moinee9b15652010-06-05 07:07:56 -03001139static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001140{
1141 struct sd *sd = (struct sd *) gspca_dev;
1142
Jean-François Moinee9b15652010-06-05 07:07:56 -03001143 sd->red_gain = val;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001144 if (gspca_dev->streaming)
1145 reg_w(gspca_dev, (val << 8) + 0x87);
1146
1147 return 0;
1148}
1149
Jean-François Moinee9b15652010-06-05 07:07:56 -03001150static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001151{
1152 struct sd *sd = (struct sd *) gspca_dev;
1153
Jean-François Moinee9b15652010-06-05 07:07:56 -03001154 *val = sd->red_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001155 return 0;
1156}
1157
Jean-François Moinee9b15652010-06-05 07:07:56 -03001158static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001159{
1160 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -03001161 u16 psg, nsg;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001162
Jean-François Moinee9b15652010-06-05 07:07:56 -03001163 psg = sd->red_gain + sd->blue_gain + sd->green_gain;
1164 nsg = val * 3;
1165 sd->red_gain = sd->red_gain * nsg / psg;
1166 if (sd->red_gain > 0x40)
1167 sd->red_gain = 0x40;
1168 else if (sd->red_gain < 0x10)
1169 sd->red_gain = 0x10;
1170 sd->blue_gain = sd->blue_gain * nsg / psg;
1171 if (sd->blue_gain > 0x40)
1172 sd->blue_gain = 0x40;
1173 else if (sd->blue_gain < 0x10)
1174 sd->blue_gain = 0x10;
1175 sd->green_gain = sd->green_gain * nsg / psg;
1176 if (sd->green_gain > 0x40)
1177 sd->green_gain = 0x40;
1178 else if (sd->green_gain < 0x10)
1179 sd->green_gain = 0x10;
1180
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001181 if (gspca_dev->streaming)
Jean-François Moinee9b15652010-06-05 07:07:56 -03001182 setRGB(gspca_dev);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001183 return 0;
1184}
1185
Jean-François Moinee9b15652010-06-05 07:07:56 -03001186static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001187{
1188 struct sd *sd = (struct sd *) gspca_dev;
1189
Jean-François Moinee9b15652010-06-05 07:07:56 -03001190 *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001191 return 0;
1192}
1193
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001194static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1195{
1196 struct sd *sd = (struct sd *) gspca_dev;
1197
1198 sd->brightness = val;
1199 if (gspca_dev->streaming)
1200 setbrightness(gspca_dev);
1201 return 0;
1202}
1203
1204static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1205{
1206 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001207
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001208 *val = sd->brightness;
1209 return *val;
1210}
1211
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001212static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001213{
1214 struct sd *sd = (struct sd *) gspca_dev;
1215
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001216 sd->awb = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001217 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001218 setawb(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001219 return 0;
1220}
1221
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001222static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001223{
1224 struct sd *sd = (struct sd *) gspca_dev;
1225
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001226 *val = sd->awb;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001227 return *val;
1228}
1229
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001230static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001231{
1232 struct sd *sd = (struct sd *) gspca_dev;
1233
1234 sd->mirror = val;
1235 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001236 setmirror(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001237 return 0;
1238}
1239
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001240static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001241{
1242 struct sd *sd = (struct sd *) gspca_dev;
1243
1244 *val = sd->mirror;
1245 return *val;
1246}
1247
1248static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
1249{
1250 struct sd *sd = (struct sd *) gspca_dev;
1251
1252 sd->effect = val;
1253 if (gspca_dev->streaming)
1254 seteffect(gspca_dev);
1255 return 0;
1256}
1257
1258static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
1259{
1260 struct sd *sd = (struct sd *) gspca_dev;
1261
1262 *val = sd->effect;
1263 return *val;
1264}
1265
1266static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1267{
1268 struct sd *sd = (struct sd *) gspca_dev;
1269
1270 sd->contrast = val;
1271 if (gspca_dev->streaming)
1272 setcontrast(gspca_dev);
1273 return 0;
1274}
1275
1276static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1277{
1278 struct sd *sd = (struct sd *) gspca_dev;
1279
1280 *val = sd->contrast;
1281 return *val;
1282}
1283
1284static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1285{
1286 struct sd *sd = (struct sd *) gspca_dev;
1287
1288 sd->colors = val;
1289 if (gspca_dev->streaming)
1290 setcolors(gspca_dev);
1291 return 0;
1292}
1293
1294static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1295{
1296 struct sd *sd = (struct sd *) gspca_dev;
1297
1298 *val = sd->colors;
1299 return 0;
1300}
1301
1302static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
1303{
1304 struct sd *sd = (struct sd *) gspca_dev;
1305
1306 sd->gamma = val;
1307 if (gspca_dev->streaming)
1308 setgamma(gspca_dev);
1309 return 0;
1310}
1311
1312static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
1313{
1314 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001315
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001316 *val = sd->gamma;
1317 return 0;
1318}
1319
1320static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1321{
1322 struct sd *sd = (struct sd *) gspca_dev;
1323
1324 sd->freq = val;
1325 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001326 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001327 return 0;
1328}
1329
1330static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1331{
1332 struct sd *sd = (struct sd *) gspca_dev;
1333
1334 *val = sd->freq;
1335 return 0;
1336}
1337
1338static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
1339{
1340 struct sd *sd = (struct sd *) gspca_dev;
1341
1342 sd->sharpness = val;
1343 if (gspca_dev->streaming)
1344 setsharpness(gspca_dev);
1345 return 0;
1346}
1347
1348static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
1349{
1350 struct sd *sd = (struct sd *) gspca_dev;
1351
1352 *val = sd->sharpness;
1353 return 0;
1354}
1355
1356/* Low Light set here......*/
1357static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
1358{
1359 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001360
1361 sd->autogain = val;
1362 if (val != 0)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001363 reg_w(gspca_dev, 0xf48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001364 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001365 reg_w(gspca_dev, 0xb48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001366 return 0;
1367}
1368
1369static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
1370{
1371 struct sd *sd = (struct sd *) gspca_dev;
1372
1373 *val = sd->autogain;
1374 return 0;
1375}
1376
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001377static int sd_querymenu(struct gspca_dev *gspca_dev,
1378 struct v4l2_querymenu *menu)
1379{
Jean-François Moinebff60692011-05-17 03:58:57 -03001380 static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
1381
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001382 switch (menu->id) {
1383 case V4L2_CID_POWER_LINE_FREQUENCY:
Jean-François Moinebff60692011-05-17 03:58:57 -03001384 if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
1385 break;
1386 strcpy((char *) menu->name, freq_nm[menu->index]);
1387 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001388 case V4L2_CID_EFFECTS:
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001389 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
Hans de Goedee7d712c2011-06-05 14:58:46 -03001390 strlcpy((char *) menu->name,
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001391 effects_control[menu->index],
1392 sizeof menu->name);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001393 return 0;
1394 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001395 break;
1396 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001397 return -EINVAL;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001398}
1399
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001400/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001401static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001402 .name = MODULE_NAME,
1403 .ctrls = sd_ctrls,
1404 .nctrls = ARRAY_SIZE(sd_ctrls),
1405 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001406 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001407 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001408 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001409 .pkt_scan = sd_pkt_scan,
1410 .querymenu = sd_querymenu,
1411};
1412
1413/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001414static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001415 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001416 {}
1417};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001418MODULE_DEVICE_TABLE(usb, device_table);
1419
1420/* -- device connect -- */
1421static int sd_probe(struct usb_interface *intf,
1422 const struct usb_device_id *id)
1423{
1424 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1425 THIS_MODULE);
1426}
1427
1428static struct usb_driver sd_driver = {
1429 .name = MODULE_NAME,
1430 .id_table = device_table,
1431 .probe = sd_probe,
1432 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001433#ifdef CONFIG_PM
1434 .suspend = gspca_suspend,
1435 .resume = gspca_resume,
1436#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001437};
1438
1439/* -- module insert / remove -- */
1440static int __init sd_mod_init(void)
1441{
Jean-François Moine54826432010-09-13 04:53:03 -03001442 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001443}
1444static void __exit sd_mod_exit(void)
1445{
1446 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001447}
1448
1449module_init(sd_mod_init);
1450module_exit(sd_mod_exit);