blob: f5d006b28c368d5cdfed701908dcae7aff607913 [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 Moinecd8955b2010-06-04 07:22:57 -030058enum {
59 SENSOR_OM6802,
60 SENSOR_OTHER,
61 SENSOR_TAS5130A,
62 SENSOR_LT168G, /* must verify if this is the actual model */
63} sensors;
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);
95static int sd_querymenu(struct gspca_dev *gspca_dev,
96 struct v4l2_querymenu *menu);
97
Marton Nemeth7e64dc42009-12-30 09:12:41 -030098static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 {
100 {
101 .id = V4L2_CID_BRIGHTNESS,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Brightness",
104 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300105 .maximum = 14,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300106 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300107#define BRIGHTNESS_DEF 8
108 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 },
110 .set = sd_setbrightness,
111 .get = sd_getbrightness,
112 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 {
114 {
115 .id = V4L2_CID_CONTRAST,
116 .type = V4L2_CTRL_TYPE_INTEGER,
117 .name = "Contrast",
118 .minimum = 0,
119 .maximum = 0x0d,
120 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300121#define CONTRAST_DEF 0x07
122 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123 },
124 .set = sd_setcontrast,
125 .get = sd_getcontrast,
126 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300127 {
128 {
129 .id = V4L2_CID_SATURATION,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Color",
132 .minimum = 0,
133 .maximum = 0x0f,
134 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300135#define COLORS_DEF 0x05
136 .default_value = COLORS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300137 },
138 .set = sd_setcolors,
139 .get = sd_getcolors,
140 },
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300141#define GAMMA_MAX 16
142#define GAMMA_DEF 10
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300143 {
144 {
145 .id = V4L2_CID_GAMMA, /* (gamma on win) */
146 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300147 .name = "Gamma",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300148 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300149 .maximum = GAMMA_MAX - 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300150 .step = 1,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300151 .default_value = GAMMA_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152 },
153 .set = sd_setgamma,
154 .get = sd_getgamma,
155 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300156 {
157 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300158 .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300159 * some apps dont bring up the
160 * backligth_compensation control) */
161 .type = V4L2_CTRL_TYPE_INTEGER,
162 .name = "Low Light",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300166#define AUTOGAIN_DEF 0x01
167 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300168 },
169 .set = sd_setlowlight,
170 .get = sd_getlowlight,
171 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300172 {
173 {
174 .id = V4L2_CID_HFLIP,
175 .type = V4L2_CTRL_TYPE_BOOLEAN,
176 .name = "Mirror Image",
177 .minimum = 0,
178 .maximum = 1,
179 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300180#define MIRROR_DEF 0
181 .default_value = MIRROR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300182 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300183 .set = sd_setmirror,
184 .get = sd_getmirror
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300186 {
187 {
188 .id = V4L2_CID_POWER_LINE_FREQUENCY,
189 .type = V4L2_CTRL_TYPE_MENU,
190 .name = "Light Frequency Filter",
191 .minimum = 1, /* 1 -> 0x50, 2->0x60 */
192 .maximum = 2,
193 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300194#define FREQ_DEF 1
195 .default_value = FREQ_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300196 },
197 .set = sd_setfreq,
198 .get = sd_getfreq},
199
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200 {
201 {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300202 .id = V4L2_CID_AUTO_WHITE_BALANCE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300204 .name = "Auto White Balance",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300205 .minimum = 0,
206 .maximum = 1,
207 .step = 1,
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300208#define AWB_DEF 0
209 .default_value = AWB_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300210 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300211 .set = sd_setawb,
212 .get = sd_getawb
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300213 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300214 {
215 {
216 .id = V4L2_CID_SHARPNESS,
217 .type = V4L2_CTRL_TYPE_INTEGER,
218 .name = "Sharpness",
219 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300220 .maximum = 15,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300221 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300222#define SHARPNESS_DEF 0x06
223 .default_value = SHARPNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 },
225 .set = sd_setsharpness,
226 .get = sd_getsharpness,
227 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {
229 {
230 .id = V4L2_CID_EFFECTS,
231 .type = V4L2_CTRL_TYPE_MENU,
232 .name = "Webcam Effects",
233 .minimum = 0,
234 .maximum = 4,
235 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300236#define EFFECTS_DEF 0
237 .default_value = EFFECTS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238 },
239 .set = sd_seteffect,
240 .get = sd_geteffect
241 },
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300242 {
243 {
244 .id = V4L2_CID_BLUE_BALANCE,
245 .type = V4L2_CTRL_TYPE_INTEGER,
246 .name = "Blue Balance",
247 .minimum = 0x10,
248 .maximum = 0x40,
249 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300250#define BLUE_GAIN_DEF 0x20
251 .default_value = BLUE_GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300252 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300253 .set = sd_setblue_gain,
254 .get = sd_getblue_gain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300255 },
256 {
257 {
258 .id = V4L2_CID_RED_BALANCE,
259 .type = V4L2_CTRL_TYPE_INTEGER,
260 .name = "Red Balance",
261 .minimum = 0x10,
262 .maximum = 0x40,
263 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300264#define RED_GAIN_DEF 0x20
265 .default_value = RED_GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300266 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300267 .set = sd_setred_gain,
268 .get = sd_getred_gain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300269 },
270 {
271 {
272 .id = V4L2_CID_GAIN,
273 .type = V4L2_CTRL_TYPE_INTEGER,
274 .name = "Gain",
275 .minimum = 0x10,
276 .maximum = 0x40,
277 .step = 1,
Jean-François Moinee9b15652010-06-05 07:07:56 -0300278#define GAIN_DEF 0x20
279 .default_value = GAIN_DEF,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300280 },
Jean-François Moinee9b15652010-06-05 07:07:56 -0300281 .set = sd_setgain,
282 .get = sd_getgain,
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300283 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300284};
285
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300286static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300287 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
288 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -0300289 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300290 .colorspace = V4L2_COLORSPACE_JPEG,
291 .priv = 4},
292 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
293 .bytesperline = 176,
294 .sizeimage = 176 * 144 * 3 / 8 + 590,
295 .colorspace = V4L2_COLORSPACE_JPEG,
296 .priv = 3},
297 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
298 .bytesperline = 320,
299 .sizeimage = 320 * 240 * 3 / 8 + 590,
300 .colorspace = V4L2_COLORSPACE_JPEG,
301 .priv = 2},
302 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
303 .bytesperline = 352,
304 .sizeimage = 352 * 288 * 3 / 8 + 590,
305 .colorspace = V4L2_COLORSPACE_JPEG,
306 .priv = 1},
307 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
308 .bytesperline = 640,
309 .sizeimage = 640 * 480 * 3 / 8 + 590,
310 .colorspace = V4L2_COLORSPACE_JPEG,
311 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300312};
313
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300314/* sensor specific data */
315struct additional_sensor_data {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300316 const u8 n3[6];
317 const u8 *n4, n4sz;
318 const u8 reg80, reg8e;
319 const u8 nset8[6];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300320 const u8 data1[10];
321 const u8 data2[9];
322 const u8 data3[9];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300323 const u8 data5[6];
324 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300325};
326
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300327static const u8 n4_om6802[] = {
328 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
329 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
330 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
331 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
332 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
333 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
334 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
335 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
336 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
337};
338static const u8 n4_other[] = {
339 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
340 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
341 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
342 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
343 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
344 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
345 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
346 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
347};
348static const u8 n4_tas5130a[] = {
349 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
350 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
351 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
352 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
353 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
354 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
355 0xc6, 0xda
356};
Nicolau Werneck00e80062010-01-30 16:00:15 -0300357static const u8 n4_lt168g[] = {
358 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
359 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
360 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
361 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
362 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
363 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
364 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
365 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
366 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
367};
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300368
Tobias Klausere23b2902009-02-09 18:06:49 -0300369static const struct additional_sensor_data sensor_data[] = {
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300370[SENSOR_OM6802] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300371 .n3 =
372 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
373 .n4 = n4_om6802,
374 .n4sz = sizeof n4_om6802,
375 .reg80 = 0x3c,
376 .reg8e = 0x33,
377 .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300378 .data1 =
379 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
380 0xb3, 0xfc},
381 .data2 =
382 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
383 0xff},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300384 .data3 =
385 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
386 0xff},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300387 .data5 = /* this could be removed later */
388 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
389 .stream =
390 {0x0b, 0x04, 0x0a, 0x78},
391 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300392[SENSOR_OTHER] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300393 .n3 =
394 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
395 .n4 = n4_other,
396 .n4sz = sizeof n4_other,
397 .reg80 = 0xac,
398 .reg8e = 0xb8,
399 .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300400 .data1 =
401 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
402 0xe8, 0xfc},
403 .data2 =
404 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
405 0xd9},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300406 .data3 =
407 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
408 0xd9},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300409 .data5 =
410 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
411 .stream =
412 {0x0b, 0x04, 0x0a, 0x00},
413 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300414[SENSOR_TAS5130A] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300415 .n3 =
416 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
417 .n4 = n4_tas5130a,
418 .n4sz = sizeof n4_tas5130a,
419 .reg80 = 0x3c,
420 .reg8e = 0xb4,
421 .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300422 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300423 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
424 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300425 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300426 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
427 0xe0},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300428 .data3 =
429 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
430 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300431 .data5 =
432 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
433 .stream =
434 {0x0b, 0x04, 0x0a, 0x40},
435 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300436[SENSOR_LT168G] = {
Nicolau Werneck00e80062010-01-30 16:00:15 -0300437 .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
438 .n4 = n4_lt168g,
439 .n4sz = sizeof n4_lt168g,
440 .reg80 = 0x7c,
441 .reg8e = 0xb3,
442 .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
443 .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
444 0xb0, 0xf4},
445 .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
446 0xff},
447 .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
448 0xff},
Nicolau Werneck00e80062010-01-30 16:00:15 -0300449 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
450 .stream = {0x0b, 0x04, 0x0a, 0x28},
451 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300452};
453
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454#define MAX_EFFECTS 7
455/* easily done by soft, this table could be removed,
456 * i keep it here just in case */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300457static char *effects_control[MAX_EFFECTS] = {
458 "Normal",
459 "Emboss", /* disabled */
460 "Monochrome",
461 "Sepia",
462 "Sketch",
463 "Sun Effect", /* disabled */
464 "Negative",
465};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300466static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
468 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
469 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
470 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
471 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
472 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
473 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
474};
475
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300476static const u8 gamma_table[GAMMA_MAX][17] = {
Jean-François Moine79960d32010-06-04 07:24:53 -0300477/* gamma table from cam1690.ini */
478 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
479 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300480 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300481 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
482 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300483 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300484 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
485 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300486 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300487 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
488 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300489 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300490 {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
491 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300492 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300493 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
494 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300495 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300496 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300497 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
498 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300499 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300500 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
501 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300502 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
503 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300504 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300505 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
506 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300507 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300508 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
509 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300510 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300511 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300512 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
513 0xff},
514 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
515 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
516 0xff},
517 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
518 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
519 0xff},
520 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
521 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
522 0xff},
523 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
524 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
525 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526};
527
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300528static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
530 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
531 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532};
533
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300534static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300535
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300536/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300537static u8 reg_r(struct gspca_dev *gspca_dev,
538 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300540 usb_control_msg(gspca_dev->dev,
541 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542 0, /* request */
543 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
544 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300545 index,
546 gspca_dev->usb_buf, 1, 500);
547 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548}
549
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300551 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300553 usb_control_msg(gspca_dev->dev,
554 usb_sndctrlpipe(gspca_dev->dev, 0),
555 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300556 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300557 0, index,
558 NULL, 0, 500);
559}
560
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300561static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300562 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300563{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300564 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300565 memcpy(gspca_dev->usb_buf, buffer, len);
566 usb_control_msg(gspca_dev->dev,
567 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300568 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300569 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300570 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300571 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300572 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300573 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300574
575 tmpbuf = kmalloc(len, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300576 if (!tmpbuf) {
577 err("Out of memory");
578 return;
579 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300580 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300581 usb_control_msg(gspca_dev->dev,
582 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300583 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300584 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300585 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300586 tmpbuf, len, 500);
587 kfree(tmpbuf);
588 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300589}
590
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300591/* write values to consecutive registers */
592static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
593 u8 reg,
594 const u8 *buffer, u16 len)
595{
596 int i;
597 u8 *p, *tmpbuf;
598
Jean-François Moine24f222e2010-03-07 05:58:55 -0300599 if (len * 2 <= USB_BUF_SZ) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300600 p = tmpbuf = gspca_dev->usb_buf;
Jean-François Moine24f222e2010-03-07 05:58:55 -0300601 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300602 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300603 if (!tmpbuf) {
604 err("Out of memory");
605 return;
606 }
607 }
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300608 i = len;
609 while (--i >= 0) {
610 *p++ = reg++;
611 *p++ = *buffer++;
612 }
613 usb_control_msg(gspca_dev->dev,
614 usb_sndctrlpipe(gspca_dev->dev, 0),
615 0,
616 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
617 0x01, 0,
618 tmpbuf, len * 2, 500);
619 if (len * 2 > USB_BUF_SZ)
620 kfree(tmpbuf);
621}
622
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300623static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300624{
625 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300626 const u8 *p;
627 u8 byte;
628 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
629 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300630 0xdf, 0x6d,
631 0xdd, 0x18,
632 0x5a, 0xe0,
633 0x5c, 0x07,
634 0x5d, 0xb0,
635 0x5e, 0x1e,
636 0x60, 0x71,
637 0xef, 0x00,
638 0xe9, 0x00,
639 0xea, 0x00,
640 0x90, 0x24,
641 0x91, 0xb2,
642 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300643 0xfd, 0x41,
644 0x00 /* table end */
645 };
646
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300647 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300648 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300649 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300650 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300651 byte = reg_r(gspca_dev, 0x0060);
652 if (!(byte & 0x01))
653 break;
654 msleep(100);
655 }
656 byte = reg_r(gspca_dev, 0x0063);
657 if (byte != 0x17) {
658 err("Bad sensor reset %02x", byte);
659 /* continue? */
660 }
661
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300662 p = sensor_init;
663 while (*p != 0) {
664 val[1] = *p++;
665 val[3] = *p++;
666 if (*p == 0)
667 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300668 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300669 i = 4;
670 while (--i >= 0) {
671 msleep(15);
672 byte = reg_r(gspca_dev, 0x60);
673 if (!(byte & 0x01))
674 break;
675 }
676 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300677 msleep(15);
678 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300679}
680
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300681/* this function is called at probe time */
682static int sd_config(struct gspca_dev *gspca_dev,
683 const struct usb_device_id *id)
684{
685 struct sd *sd = (struct sd *) gspca_dev;
686 struct cam *cam;
687
688 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689
690 cam->cam_mode = vga_mode_t16;
691 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
692
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300693 sd->brightness = BRIGHTNESS_DEF;
694 sd->contrast = CONTRAST_DEF;
695 sd->colors = COLORS_DEF;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300696 sd->gamma = GAMMA_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300697 sd->autogain = AUTOGAIN_DEF;
698 sd->mirror = MIRROR_DEF;
699 sd->freq = FREQ_DEF;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300700 sd->awb = AWB_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300701 sd->sharpness = SHARPNESS_DEF;
702 sd->effect = EFFECTS_DEF;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300703 sd->red_gain = RED_GAIN_DEF;
704 sd->blue_gain = BLUE_GAIN_DEF;
705 sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300706
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 return 0;
708}
709
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300710static void setbrightness(struct gspca_dev *gspca_dev)
711{
712 struct sd *sd = (struct sd *) gspca_dev;
713 unsigned int brightness;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300714 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300715
716 brightness = sd->brightness;
717 if (brightness < 7) {
718 set6[1] = 0x26;
719 set6[3] = 0x70 - brightness * 0x10;
720 } else {
721 set6[3] = 0x00 + ((brightness - 7) * 0x10);
722 }
723
724 reg_w_buf(gspca_dev, set6, sizeof set6);
725}
726
727static void setcontrast(struct gspca_dev *gspca_dev)
728{
729 struct sd *sd = (struct sd *) gspca_dev;
730 unsigned int contrast = sd->contrast;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300731 u16 reg_to_write;
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300732
733 if (contrast < 7)
734 reg_to_write = 0x8ea9 - contrast * 0x200;
735 else
736 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
737
738 reg_w(gspca_dev, reg_to_write);
739}
740
741static void setcolors(struct gspca_dev *gspca_dev)
742{
743 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300744 u16 reg_to_write;
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300745
746 reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
747 reg_w(gspca_dev, reg_to_write);
748}
749
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300750static void setgamma(struct gspca_dev *gspca_dev)
751{
752 struct sd *sd = (struct sd *) gspca_dev;
753
754 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300755 reg_w_ixbuf(gspca_dev, 0x90,
756 gamma_table[sd->gamma], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300757}
758
Jean-François Moinee9b15652010-06-05 07:07:56 -0300759static void setRGB(struct gspca_dev *gspca_dev)
760{
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300761 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300762 u8 all_gain_reg[6] =
763 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
764
765 all_gain_reg[1] = sd->red_gain;
766 all_gain_reg[3] = sd->blue_gain;
767 all_gain_reg[5] = sd->green_gain;
768 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300769}
770
Jean-François Moinee9b15652010-06-05 07:07:56 -0300771/* Generic fnc for r/b balance, exposure and awb */
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300772static void setawb(struct gspca_dev *gspca_dev)
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300773{
774 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300775 u16 reg80;
776
777 reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300778
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300779 /* on awb leave defaults values */
Jean-François Moinee9b15652010-06-05 07:07:56 -0300780 if (!sd->awb) {
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300781 /* shoud we wait here.. */
Jean-François Moinee9b15652010-06-05 07:07:56 -0300782 /* update and reset RGB gains with webcam values */
783 sd->red_gain = reg_r(gspca_dev, 0x0087);
784 sd->blue_gain = reg_r(gspca_dev, 0x0088);
785 sd->green_gain = reg_r(gspca_dev, 0x0089);
786 reg80 &= ~0x0400; /* AWB off */
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300787 }
Jean-François Moinee9b15652010-06-05 07:07:56 -0300788 reg_w(gspca_dev, reg80);
789 reg_w(gspca_dev, reg80);
790}
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300791
Jean-François Moinee9b15652010-06-05 07:07:56 -0300792static void init_gains(struct gspca_dev *gspca_dev)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795 u16 reg80;
796 u8 all_gain_reg[8] =
797 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
798
799 all_gain_reg[1] = sd->red_gain;
800 all_gain_reg[3] = sd->blue_gain;
801 all_gain_reg[5] = sd->green_gain;
802 reg80 = sensor_data[sd->sensor].reg80;
803 if (!sd->awb)
804 reg80 &= ~0x04;
805 all_gain_reg[7] = reg80;
806 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
807
808 reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);
809 reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
810 reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300811}
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300812
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300813static void setsharpness(struct gspca_dev *gspca_dev)
814{
815 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300816 u16 reg_to_write;
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300817
818 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
819
820 reg_w(gspca_dev, reg_to_write);
821}
822
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300823static void setfreq(struct gspca_dev *gspca_dev)
824{
825 struct sd *sd = (struct sd *) gspca_dev;
826 u8 reg66;
827 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
828
829 switch (sd->sensor) {
830 case SENSOR_LT168G:
831 if (sd->freq != 0)
832 freq[3] = 0xa8;
833 reg66 = 0x41;
834 break;
835 case SENSOR_OM6802:
836 reg66 = 0xca;
837 break;
838 default:
839 reg66 = 0x40;
840 break;
841 }
842 switch (sd->freq) {
843 case 0: /* no flicker */
844 freq[3] = 0xf0;
845 break;
846 case 2: /* 60Hz */
847 reg66 &= ~0x40;
848 break;
849 }
850 freq[1] = reg66;
851
852 reg_w_buf(gspca_dev, freq, sizeof freq);
853}
854
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300855/* this function is called at probe and resume time */
856static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 /* some of this registers are not really neded, because
859 * they are overriden by setbrigthness, setcontrast, etc,
860 * but wont hurt anyway, and can help someone with similar webcam
861 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300862 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300863 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300864 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300865 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300866 u8 test_byte = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300868 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300869 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300870 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
871 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300873 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300874 {0x08, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300876 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
877 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300878 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300879 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300880 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300881 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300882 break;
Nicolau Werneck00e80062010-01-30 16:00:15 -0300883 case 0x0802:
884 PDEBUG(D_PROBE, "sensor lt168g");
885 sd->sensor = SENSOR_LT168G;
886 break;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300887 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300888 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300889 sd->sensor = SENSOR_OTHER;
890 break;
891 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300892 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300893 sd->sensor = SENSOR_OM6802;
894 break;
895 default:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300896 PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300897 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300898 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300900 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300901 reg_w_buf(gspca_dev, n1, sizeof n1);
902 i = 5;
903 while (--i >= 0) {
904 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
905 test_byte = reg_r(gspca_dev, 0x0063);
906 msleep(100);
907 if (test_byte == 0x17)
908 break; /* OK */
909 }
910 if (i < 0) {
911 err("Bad sensor reset %02x", test_byte);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300912 return -EIO;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300913 }
914 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300915 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300916
917 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300919 test_byte = reg_r(gspca_dev, read_indexs[i]);
920 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300921 test_byte);
922 i++;
923 }
924
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300925 sensor = &sensor_data[sd->sensor];
926 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
927 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300928
Nicolau Werneck00e80062010-01-30 16:00:15 -0300929 if (sd->sensor == SENSOR_LT168G) {
930 test_byte = reg_r(gspca_dev, 0x80);
931 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
932 test_byte);
933 reg_w(gspca_dev, 0x6c80);
934 }
935
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300936 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
937 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
938 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300939
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300940 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
941 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
942 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300943
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300944 setbrightness(gspca_dev);
945 setcontrast(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300946 setgamma(gspca_dev);
Jean-Francois Moine35480b62008-10-17 05:19:46 -0300947 setcolors(gspca_dev);
948 setsharpness(gspca_dev);
Jean-François Moinee9b15652010-06-05 07:07:56 -0300949 init_gains(gspca_dev);
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300950 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300951
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300952 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
953 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
954 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300955
Nicolau Werneck00e80062010-01-30 16:00:15 -0300956 if (sd->sensor == SENSOR_LT168G) {
957 test_byte = reg_r(gspca_dev, 0x80);
958 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
959 test_byte);
960 reg_w(gspca_dev, 0x6c80);
961 }
962
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300963 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
964 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
965 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300966
967 return 0;
968}
969
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300970static void setmirror(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971{
972 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300973 u8 hflipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300974 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300975
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300976 if (sd->mirror)
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300977 hflipcmd[3] = 0x01;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300978
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300979 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980}
981
982static void seteffect(struct gspca_dev *gspca_dev)
983{
984 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300986 reg_w_buf(gspca_dev, effects_table[sd->effect],
987 sizeof effects_table[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988 if (sd->effect == 1 || sd->effect == 5) {
989 PDEBUG(D_CONF,
990 "This effect have been disabled for webcam \"safety\"");
991 return;
992 }
993
994 if (sd->effect == 1 || sd->effect == 4)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300995 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300997 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998}
999
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001000/* Is this really needed?
1001 * i added some module parameters for test with some users */
1002static void poll_sensor(struct gspca_dev *gspca_dev)
1003{
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001004 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001005 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
1006 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
1007 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
1008 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001009 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001010 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
1011 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-François Moine98388242010-06-04 07:30:21 -03001012 static const u8 noise03[] = /* (some differences / ms-drv) */
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001013 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
1014 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
1015 0xc2, 0x80, 0xc3, 0x10};
1016
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001017 PDEBUG(D_STREAM, "[Sensor requires polling]");
1018 reg_w_buf(gspca_dev, poll1, sizeof poll1);
1019 reg_w_buf(gspca_dev, poll2, sizeof poll2);
Jean-François Moine98388242010-06-04 07:30:21 -03001020 reg_w_buf(gspca_dev, noise03, sizeof noise03);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001021}
1022
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001023static int sd_start(struct gspca_dev *gspca_dev)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001026 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001027 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001028 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1029 static const u8 t3[] =
1030 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001031
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001032 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001033 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001034 case 0: /* 640x480 (0x00) */
1035 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001036 case 1: /* 352x288 */
1037 t2[1] = 0x40;
1038 break;
1039 case 2: /* 320x240 */
1040 t2[1] = 0x10;
1041 break;
1042 case 3: /* 176x144 */
1043 t2[1] = 0x50;
1044 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001045 default:
1046/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001047 t2[1] = 0x20;
1048 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001049 }
1050
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001051 switch (sd->sensor) {
1052 case SENSOR_OM6802:
1053 om6802_sensor_init(gspca_dev);
1054 break;
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001055 case SENSOR_TAS5130A:
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001056 i = 0;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001057 for (;;) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -03001058 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001059 sizeof tas5130a_sensor_init[0]);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001060 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
1061 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001062 i++;
1063 }
1064 reg_w(gspca_dev, 0x3c80);
1065 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001066 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001067 sizeof tas5130a_sensor_init[0]);
1068 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001069 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001070 }
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001071 sensor = &sensor_data[sd->sensor];
Jean-François Moine78b98cb2010-06-05 07:01:46 -03001072 setfreq(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001073 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001074 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001075 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001076 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001077 msleep(15);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001078 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
1079 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -03001080
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001081 if (sd->sensor == SENSOR_OM6802)
1082 poll_sensor(gspca_dev);
1083
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001084 return 0;
1085}
1086
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001087static void sd_stopN(struct gspca_dev *gspca_dev)
1088{
1089 struct sd *sd = (struct sd *) gspca_dev;
1090
1091 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1092 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001093 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1094 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -03001095 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -03001096 msleep(20);
1097 reg_w(gspca_dev, 0x0309);
1098 }
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001099}
1100
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001101static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -03001102 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001103 int len) /* iso packet length */
1104{
Jean-François Moineebb78c52010-06-05 06:56:48 -03001105 int pkt_type;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001106
1107 if (data[0] == 0x5a) {
1108 /* Control Packet, after this came the header again,
1109 * but extra bytes came in the packet before this,
1110 * sometimes an EOF arrives, sometimes not... */
1111 return;
1112 }
1113 data += 2;
1114 len -= 2;
Jean-François Moineebb78c52010-06-05 06:56:48 -03001115 if (data[0] == 0xff && data[1] == 0xd8)
1116 pkt_type = FIRST_PACKET;
1117 else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
1118 pkt_type = LAST_PACKET;
1119 else
1120 pkt_type = INTER_PACKET;
1121 gspca_frame_add(gspca_dev, pkt_type, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001122}
1123
Jean-François Moinee9b15652010-06-05 07:07:56 -03001124static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001125{
1126 struct sd *sd = (struct sd *) gspca_dev;
1127
Jean-François Moinee9b15652010-06-05 07:07:56 -03001128 sd->blue_gain = val;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001129 if (gspca_dev->streaming)
1130 reg_w(gspca_dev, (val << 8) + 0x88);
1131 return 0;
1132}
1133
Jean-François Moinee9b15652010-06-05 07:07:56 -03001134static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001135{
1136 struct sd *sd = (struct sd *) gspca_dev;
1137
Jean-François Moinee9b15652010-06-05 07:07:56 -03001138 *val = sd->blue_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001139 return 0;
1140}
1141
Jean-François Moinee9b15652010-06-05 07:07:56 -03001142static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001143{
1144 struct sd *sd = (struct sd *) gspca_dev;
1145
Jean-François Moinee9b15652010-06-05 07:07:56 -03001146 sd->red_gain = val;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001147 if (gspca_dev->streaming)
1148 reg_w(gspca_dev, (val << 8) + 0x87);
1149
1150 return 0;
1151}
1152
Jean-François Moinee9b15652010-06-05 07:07:56 -03001153static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001154{
1155 struct sd *sd = (struct sd *) gspca_dev;
1156
Jean-François Moinee9b15652010-06-05 07:07:56 -03001157 *val = sd->red_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001158 return 0;
1159}
1160
Jean-François Moinee9b15652010-06-05 07:07:56 -03001161static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001162{
1163 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinee9b15652010-06-05 07:07:56 -03001164 u16 psg, nsg;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001165
Jean-François Moinee9b15652010-06-05 07:07:56 -03001166 psg = sd->red_gain + sd->blue_gain + sd->green_gain;
1167 nsg = val * 3;
1168 sd->red_gain = sd->red_gain * nsg / psg;
1169 if (sd->red_gain > 0x40)
1170 sd->red_gain = 0x40;
1171 else if (sd->red_gain < 0x10)
1172 sd->red_gain = 0x10;
1173 sd->blue_gain = sd->blue_gain * nsg / psg;
1174 if (sd->blue_gain > 0x40)
1175 sd->blue_gain = 0x40;
1176 else if (sd->blue_gain < 0x10)
1177 sd->blue_gain = 0x10;
1178 sd->green_gain = sd->green_gain * nsg / psg;
1179 if (sd->green_gain > 0x40)
1180 sd->green_gain = 0x40;
1181 else if (sd->green_gain < 0x10)
1182 sd->green_gain = 0x10;
1183
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001184 if (gspca_dev->streaming)
Jean-François Moinee9b15652010-06-05 07:07:56 -03001185 setRGB(gspca_dev);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001186 return 0;
1187}
1188
Jean-François Moinee9b15652010-06-05 07:07:56 -03001189static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001190{
1191 struct sd *sd = (struct sd *) gspca_dev;
1192
Jean-François Moinee9b15652010-06-05 07:07:56 -03001193 *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -03001194 return 0;
1195}
1196
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001197static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1198{
1199 struct sd *sd = (struct sd *) gspca_dev;
1200
1201 sd->brightness = val;
1202 if (gspca_dev->streaming)
1203 setbrightness(gspca_dev);
1204 return 0;
1205}
1206
1207static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1208{
1209 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001210
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001211 *val = sd->brightness;
1212 return *val;
1213}
1214
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001215static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001216{
1217 struct sd *sd = (struct sd *) gspca_dev;
1218
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001219 sd->awb = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001220 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001221 setawb(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001222 return 0;
1223}
1224
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001225static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226{
1227 struct sd *sd = (struct sd *) gspca_dev;
1228
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001229 *val = sd->awb;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001230 return *val;
1231}
1232
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001233static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001234{
1235 struct sd *sd = (struct sd *) gspca_dev;
1236
1237 sd->mirror = val;
1238 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001239 setmirror(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001240 return 0;
1241}
1242
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001243static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244{
1245 struct sd *sd = (struct sd *) gspca_dev;
1246
1247 *val = sd->mirror;
1248 return *val;
1249}
1250
1251static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
1252{
1253 struct sd *sd = (struct sd *) gspca_dev;
1254
1255 sd->effect = val;
1256 if (gspca_dev->streaming)
1257 seteffect(gspca_dev);
1258 return 0;
1259}
1260
1261static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
1262{
1263 struct sd *sd = (struct sd *) gspca_dev;
1264
1265 *val = sd->effect;
1266 return *val;
1267}
1268
1269static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1270{
1271 struct sd *sd = (struct sd *) gspca_dev;
1272
1273 sd->contrast = val;
1274 if (gspca_dev->streaming)
1275 setcontrast(gspca_dev);
1276 return 0;
1277}
1278
1279static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1280{
1281 struct sd *sd = (struct sd *) gspca_dev;
1282
1283 *val = sd->contrast;
1284 return *val;
1285}
1286
1287static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1288{
1289 struct sd *sd = (struct sd *) gspca_dev;
1290
1291 sd->colors = val;
1292 if (gspca_dev->streaming)
1293 setcolors(gspca_dev);
1294 return 0;
1295}
1296
1297static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1298{
1299 struct sd *sd = (struct sd *) gspca_dev;
1300
1301 *val = sd->colors;
1302 return 0;
1303}
1304
1305static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
1306{
1307 struct sd *sd = (struct sd *) gspca_dev;
1308
1309 sd->gamma = val;
1310 if (gspca_dev->streaming)
1311 setgamma(gspca_dev);
1312 return 0;
1313}
1314
1315static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
1316{
1317 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001318
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001319 *val = sd->gamma;
1320 return 0;
1321}
1322
1323static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1324{
1325 struct sd *sd = (struct sd *) gspca_dev;
1326
1327 sd->freq = val;
1328 if (gspca_dev->streaming)
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001329 setfreq(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001330 return 0;
1331}
1332
1333static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1334{
1335 struct sd *sd = (struct sd *) gspca_dev;
1336
1337 *val = sd->freq;
1338 return 0;
1339}
1340
1341static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
1342{
1343 struct sd *sd = (struct sd *) gspca_dev;
1344
1345 sd->sharpness = val;
1346 if (gspca_dev->streaming)
1347 setsharpness(gspca_dev);
1348 return 0;
1349}
1350
1351static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
1352{
1353 struct sd *sd = (struct sd *) gspca_dev;
1354
1355 *val = sd->sharpness;
1356 return 0;
1357}
1358
1359/* Low Light set here......*/
1360static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
1361{
1362 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001363
1364 sd->autogain = val;
1365 if (val != 0)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001366 reg_w(gspca_dev, 0xf48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001367 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001368 reg_w(gspca_dev, 0xb48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001369 return 0;
1370}
1371
1372static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
1373{
1374 struct sd *sd = (struct sd *) gspca_dev;
1375
1376 *val = sd->autogain;
1377 return 0;
1378}
1379
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001380static int sd_querymenu(struct gspca_dev *gspca_dev,
1381 struct v4l2_querymenu *menu)
1382{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001383 switch (menu->id) {
1384 case V4L2_CID_POWER_LINE_FREQUENCY:
1385 switch (menu->index) {
1386 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001387 strcpy((char *) menu->name, "50 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001388 return 0;
1389 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001390 strcpy((char *) menu->name, "60 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001391 return 0;
1392 }
1393 break;
1394 case V4L2_CID_EFFECTS:
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001395 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
1396 strncpy((char *) menu->name,
Jean-François Moinecd8955b2010-06-04 07:22:57 -03001397 effects_control[menu->index],
1398 sizeof menu->name);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001399 return 0;
1400 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001401 break;
1402 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001403 return -EINVAL;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001404}
1405
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001406/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001407static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001408 .name = MODULE_NAME,
1409 .ctrls = sd_ctrls,
1410 .nctrls = ARRAY_SIZE(sd_ctrls),
1411 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001412 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001413 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001414 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001415 .pkt_scan = sd_pkt_scan,
1416 .querymenu = sd_querymenu,
1417};
1418
1419/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001420static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001421 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001422 {}
1423};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001424MODULE_DEVICE_TABLE(usb, device_table);
1425
1426/* -- device connect -- */
1427static int sd_probe(struct usb_interface *intf,
1428 const struct usb_device_id *id)
1429{
1430 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1431 THIS_MODULE);
1432}
1433
1434static struct usb_driver sd_driver = {
1435 .name = MODULE_NAME,
1436 .id_table = device_table,
1437 .probe = sd_probe,
1438 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001439#ifdef CONFIG_PM
1440 .suspend = gspca_suspend,
1441 .resume = gspca_resume,
1442#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001443};
1444
1445/* -- module insert / remove -- */
1446static int __init sd_mod_init(void)
1447{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001448 int ret;
1449 ret = usb_register(&sd_driver);
1450 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001451 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001452 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001453 return 0;
1454}
1455static void __exit sd_mod_exit(void)
1456{
1457 usb_deregister(&sd_driver);
1458 PDEBUG(D_PROBE, "deregistered");
1459}
1460
1461module_init(sd_mod_init);
1462module_exit(sd_mod_exit);