blob: 404214b8cd2bed98d22e036f6d71bd8b4672add9 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03002 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030017 *
18 *Notes: * t613 + tas5130A
19 * * Focus to light do not balance well as in win.
20 * Quality in win is not good, but its kinda better.
21 * * Fix some "extraneous bytes", most of apps will show the image anyway
22 * * Gamma table, is there, but its really doing something?
23 * * 7~8 Fps, its ok, max on win its 10.
24 * Costantino Leandro
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030025 */
26
27#define MODULE_NAME "t613"
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030028
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029#include "gspca.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030030
Jean-Francois Moinef9b4a372008-09-03 16:48:14 -030031#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030032
33MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
34MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
35MODULE_LICENSE("GPL");
36
37struct sd {
38 struct gspca_dev gspca_dev; /* !! must be the first item */
39
Jean-Francois Moine82e25492009-01-22 07:18:48 -030040 u8 brightness;
41 u8 contrast;
42 u8 colors;
43 u8 autogain;
44 u8 gamma;
45 u8 sharpness;
46 u8 freq;
47 u8 whitebalance;
48 u8 mirror;
49 u8 effect;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030050
Jean-Francois Moine82e25492009-01-22 07:18:48 -030051 u8 sensor;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -030052#define SENSOR_OM6802 0
53#define SENSOR_OTHER 1
54#define SENSOR_TAS5130A 2
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055};
56
57/* V4L2 controls supported by the driver */
58static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
59static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
60static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
62static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
64static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
66static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
67static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
68static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
69static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
70static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
71static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
72static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
73static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
74static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
75static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
76static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
77static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
78static int sd_querymenu(struct gspca_dev *gspca_dev,
79 struct v4l2_querymenu *menu);
80
81static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030082 {
83 {
84 .id = V4L2_CID_BRIGHTNESS,
85 .type = V4L2_CTRL_TYPE_INTEGER,
86 .name = "Brightness",
87 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030088 .maximum = 14,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030089 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -030090#define BRIGHTNESS_DEF 8
91 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030092 },
93 .set = sd_setbrightness,
94 .get = sd_getbrightness,
95 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030096 {
97 {
98 .id = V4L2_CID_CONTRAST,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Contrast",
101 .minimum = 0,
102 .maximum = 0x0d,
103 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300104#define CONTRAST_DEF 0x07
105 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300106 },
107 .set = sd_setcontrast,
108 .get = sd_getcontrast,
109 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300110 {
111 {
112 .id = V4L2_CID_SATURATION,
113 .type = V4L2_CTRL_TYPE_INTEGER,
114 .name = "Color",
115 .minimum = 0,
116 .maximum = 0x0f,
117 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300118#define COLORS_DEF 0x05
119 .default_value = COLORS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300120 },
121 .set = sd_setcolors,
122 .get = sd_getcolors,
123 },
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300124#define GAMMA_MAX 16
125#define GAMMA_DEF 10
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126 {
127 {
128 .id = V4L2_CID_GAMMA, /* (gamma on win) */
129 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300130 .name = "Gamma",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300131 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300132 .maximum = GAMMA_MAX - 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300133 .step = 1,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300134 .default_value = GAMMA_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300135 },
136 .set = sd_setgamma,
137 .get = sd_getgamma,
138 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300139 {
140 {
141 .id = V4L2_CID_GAIN, /* here, i activate only the lowlight,
142 * some apps dont bring up the
143 * backligth_compensation control) */
144 .type = V4L2_CTRL_TYPE_INTEGER,
145 .name = "Low Light",
146 .minimum = 0,
147 .maximum = 1,
148 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300149#define AUTOGAIN_DEF 0x01
150 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 },
152 .set = sd_setlowlight,
153 .get = sd_getlowlight,
154 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155 {
156 {
157 .id = V4L2_CID_HFLIP,
158 .type = V4L2_CTRL_TYPE_BOOLEAN,
159 .name = "Mirror Image",
160 .minimum = 0,
161 .maximum = 1,
162 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300163#define MIRROR_DEF 0
164 .default_value = MIRROR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300165 },
166 .set = sd_setflip,
167 .get = sd_getflip
168 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300169 {
170 {
171 .id = V4L2_CID_POWER_LINE_FREQUENCY,
172 .type = V4L2_CTRL_TYPE_MENU,
173 .name = "Light Frequency Filter",
174 .minimum = 1, /* 1 -> 0x50, 2->0x60 */
175 .maximum = 2,
176 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300177#define FREQ_DEF 1
178 .default_value = FREQ_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300179 },
180 .set = sd_setfreq,
181 .get = sd_getfreq},
182
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183 {
184 {
185 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
186 .type = V4L2_CTRL_TYPE_INTEGER,
187 .name = "White Balance",
188 .minimum = 0,
189 .maximum = 1,
190 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300191#define WHITE_BALANCE_DEF 0
192 .default_value = WHITE_BALANCE_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300193 },
194 .set = sd_setwhitebalance,
195 .get = sd_getwhitebalance
196 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197 {
198 {
199 .id = V4L2_CID_SHARPNESS,
200 .type = V4L2_CTRL_TYPE_INTEGER,
201 .name = "Sharpness",
202 .minimum = 0,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300203 .maximum = 15,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300205#define SHARPNESS_DEF 0x06
206 .default_value = SHARPNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300207 },
208 .set = sd_setsharpness,
209 .get = sd_getsharpness,
210 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 {
212 {
213 .id = V4L2_CID_EFFECTS,
214 .type = V4L2_CTRL_TYPE_MENU,
215 .name = "Webcam Effects",
216 .minimum = 0,
217 .maximum = 4,
218 .step = 1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300219#define EFFECTS_DEF 0
220 .default_value = EFFECTS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300221 },
222 .set = sd_seteffect,
223 .get = sd_geteffect
224 },
225};
226
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300227static char *effects_control[] = {
228 "Normal",
229 "Emboss", /* disabled */
230 "Monochrome",
231 "Sepia",
232 "Sketch",
233 "Sun Effect", /* disabled */
234 "Negative",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235};
236
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300237static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300238 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
239 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -0300240 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300241 .colorspace = V4L2_COLORSPACE_JPEG,
242 .priv = 4},
243 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
244 .bytesperline = 176,
245 .sizeimage = 176 * 144 * 3 / 8 + 590,
246 .colorspace = V4L2_COLORSPACE_JPEG,
247 .priv = 3},
248 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
249 .bytesperline = 320,
250 .sizeimage = 320 * 240 * 3 / 8 + 590,
251 .colorspace = V4L2_COLORSPACE_JPEG,
252 .priv = 2},
253 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
254 .bytesperline = 352,
255 .sizeimage = 352 * 288 * 3 / 8 + 590,
256 .colorspace = V4L2_COLORSPACE_JPEG,
257 .priv = 1},
258 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
259 .bytesperline = 640,
260 .sizeimage = 640 * 480 * 3 / 8 + 590,
261 .colorspace = V4L2_COLORSPACE_JPEG,
262 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300263};
264
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300265/* sensor specific data */
266struct additional_sensor_data {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300267 const u8 data1[10];
268 const u8 data2[9];
269 const u8 data3[9];
270 const u8 data4[4];
271 const u8 data5[6];
272 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300273};
274
Tobias Klausere23b2902009-02-09 18:06:49 -0300275static const struct additional_sensor_data sensor_data[] = {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300276 { /* OM6802 */
277 .data1 =
278 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
279 0xb3, 0xfc},
280 .data2 =
281 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
282 0xff},
283 .data4 = /*Freq (50/60Hz). Splitted for test purpose */
284 {0x66, 0xca, 0xa8, 0xf0},
285 .data5 = /* this could be removed later */
286 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
287 .stream =
288 {0x0b, 0x04, 0x0a, 0x78},
289 },
290 { /* OTHER */
291 .data1 =
292 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
293 0xe8, 0xfc},
294 .data2 =
295 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
296 0xd9},
297 .data4 =
298 {0x66, 0x00, 0xa8, 0xa8},
299 .data5 =
300 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
301 .stream =
302 {0x0b, 0x04, 0x0a, 0x00},
303 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300304 { /* TAS5130A */
305 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300306 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
307 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300308 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300309 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
310 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300311 .data4 = /* Freq (50/60Hz). Splitted for test purpose */
312 {0x66, 0x00, 0xa8, 0xe8},
313 .data5 =
314 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
315 .stream =
316 {0x0b, 0x04, 0x0a, 0x40},
317 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300318};
319
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300320#define MAX_EFFECTS 7
321/* easily done by soft, this table could be removed,
322 * i keep it here just in case */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300323static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300324 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
325 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
326 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
327 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
328 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
329 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
330 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
331};
332
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300333static const u8 gamma_table[GAMMA_MAX][17] = {
334 {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9, /* 0 */
335 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
336 0xff},
337 {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad, /* 1 */
338 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
339 0xff},
340 {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6, /* 2 */
341 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
342 0xff},
343 {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e, /* 3 */
344 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
345 0xff},
346 {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95, /* 4 */
347 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
348 0xff},
349 {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87, /* 5 */
350 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
351 0xff},
352 {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67, /* 6 */
353 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
354 0xff},
355 {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70, /* 7 */
356 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
357 0xff},
358 {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79, /* 8 */
359 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
360 0xff},
361 {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84, /* 9 */
362 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
363 0xff},
364 {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
365 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
366 0xff},
367 {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8D, 0x9B, /* 11 */
368 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
369 0xff},
370 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
371 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
372 0xff},
373 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
374 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
375 0xff},
376 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
377 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
378 0xff},
379 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
380 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
381 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382};
383
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300384static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300385 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
386 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
387 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
388 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
389 {},
390};
391
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300392static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300393
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300394/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300395static u8 reg_r(struct gspca_dev *gspca_dev,
396 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398 usb_control_msg(gspca_dev->dev,
399 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 0, /* request */
401 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
402 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300403 index,
404 gspca_dev->usb_buf, 1, 500);
405 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406}
407
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300409 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300411 usb_control_msg(gspca_dev->dev,
412 usb_sndctrlpipe(gspca_dev->dev, 0),
413 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300414 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300415 0, index,
416 NULL, 0, 500);
417}
418
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300419static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300420 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300421{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300422 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300423 memcpy(gspca_dev->usb_buf, buffer, len);
424 usb_control_msg(gspca_dev->dev,
425 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300426 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300427 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300428 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300429 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300430 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300431 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300432
433 tmpbuf = kmalloc(len, GFP_KERNEL);
434 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300435 usb_control_msg(gspca_dev->dev,
436 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300437 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300438 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300439 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300440 tmpbuf, len, 500);
441 kfree(tmpbuf);
442 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300443}
444
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300445/* write values to consecutive registers */
446static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
447 u8 reg,
448 const u8 *buffer, u16 len)
449{
450 int i;
451 u8 *p, *tmpbuf;
452
453 if (len * 2 <= USB_BUF_SZ)
454 p = tmpbuf = gspca_dev->usb_buf;
455 else
456 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
457 i = len;
458 while (--i >= 0) {
459 *p++ = reg++;
460 *p++ = *buffer++;
461 }
462 usb_control_msg(gspca_dev->dev,
463 usb_sndctrlpipe(gspca_dev->dev, 0),
464 0,
465 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
466 0x01, 0,
467 tmpbuf, len * 2, 500);
468 if (len * 2 > USB_BUF_SZ)
469 kfree(tmpbuf);
470}
471
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300472/* Reported as OM6802*/
473static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300474{
475 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300476 const u8 *p;
477 u8 byte;
478 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
479 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300480 0xdf, 0x6d,
481 0xdd, 0x18,
482 0x5a, 0xe0,
483 0x5c, 0x07,
484 0x5d, 0xb0,
485 0x5e, 0x1e,
486 0x60, 0x71,
487 0xef, 0x00,
488 0xe9, 0x00,
489 0xea, 0x00,
490 0x90, 0x24,
491 0x91, 0xb2,
492 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300493 0xfd, 0x41,
494 0x00 /* table end */
495 };
496
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300497 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300498 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300499 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300500 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300501 byte = reg_r(gspca_dev, 0x0060);
502 if (!(byte & 0x01))
503 break;
504 msleep(100);
505 }
506 byte = reg_r(gspca_dev, 0x0063);
507 if (byte != 0x17) {
508 err("Bad sensor reset %02x", byte);
509 /* continue? */
510 }
511
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300512 p = sensor_init;
513 while (*p != 0) {
514 val[1] = *p++;
515 val[3] = *p++;
516 if (*p == 0)
517 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300518 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300519 i = 4;
520 while (--i >= 0) {
521 msleep(15);
522 byte = reg_r(gspca_dev, 0x60);
523 if (!(byte & 0x01))
524 break;
525 }
526 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300527 msleep(15);
528 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300529}
530
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531/* this function is called at probe time */
532static int sd_config(struct gspca_dev *gspca_dev,
533 const struct usb_device_id *id)
534{
535 struct sd *sd = (struct sd *) gspca_dev;
536 struct cam *cam;
537
538 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539
540 cam->cam_mode = vga_mode_t16;
541 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
542
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300543 sd->brightness = BRIGHTNESS_DEF;
544 sd->contrast = CONTRAST_DEF;
545 sd->colors = COLORS_DEF;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300546 sd->gamma = GAMMA_DEF;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300547 sd->autogain = AUTOGAIN_DEF;
548 sd->mirror = MIRROR_DEF;
549 sd->freq = FREQ_DEF;
550 sd->whitebalance = WHITE_BALANCE_DEF;
551 sd->sharpness = SHARPNESS_DEF;
552 sd->effect = EFFECTS_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300553 return 0;
554}
555
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300556static void setbrightness(struct gspca_dev *gspca_dev)
557{
558 struct sd *sd = (struct sd *) gspca_dev;
559 unsigned int brightness;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300560 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300561
562 brightness = sd->brightness;
563 if (brightness < 7) {
564 set6[1] = 0x26;
565 set6[3] = 0x70 - brightness * 0x10;
566 } else {
567 set6[3] = 0x00 + ((brightness - 7) * 0x10);
568 }
569
570 reg_w_buf(gspca_dev, set6, sizeof set6);
571}
572
573static void setcontrast(struct gspca_dev *gspca_dev)
574{
575 struct sd *sd = (struct sd *) gspca_dev;
576 unsigned int contrast = sd->contrast;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300577 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300578
579 if (contrast < 7)
580 reg_to_write = 0x8ea9 - contrast * 0x200;
581 else
582 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
583
584 reg_w(gspca_dev, reg_to_write);
585}
586
587static void setcolors(struct gspca_dev *gspca_dev)
588{
589 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300590 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300591
592 reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
593 reg_w(gspca_dev, reg_to_write);
594}
595
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300596static void setgamma(struct gspca_dev *gspca_dev)
597{
598 struct sd *sd = (struct sd *) gspca_dev;
599
600 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300601 reg_w_ixbuf(gspca_dev, 0x90,
602 gamma_table[sd->gamma], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300603}
604
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300605static void setwhitebalance(struct gspca_dev *gspca_dev)
606{
607 struct sd *sd = (struct sd *) gspca_dev;
608
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300609 u8 white_balance[8] =
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300610 {0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
611
612 if (sd->whitebalance)
613 white_balance[7] = 0x3c;
614
615 reg_w_buf(gspca_dev, white_balance, sizeof white_balance);
616}
617
618static void setsharpness(struct gspca_dev *gspca_dev)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300621 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300622
623 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
624
625 reg_w(gspca_dev, reg_to_write);
626}
627
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300628/* this function is called at probe and resume time */
629static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300631 /* some of this registers are not really neded, because
632 * they are overriden by setbrigthness, setcontrast, etc,
633 * but wont hurt anyway, and can help someone with similar webcam
634 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300635 struct sd *sd = (struct sd *) gspca_dev;
636 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300637 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300638 u8 test_byte = 0;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300639 u16 reg80, reg8e;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300640
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300641 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300642 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300643 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
644 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300645 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300646 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647 {0x08, 0x00};
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300648 static const u8 n3[6] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300649 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300650 static const u8 n3_other[6] =
651 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300652 static const u8 n4[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653 {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
654 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
655 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
656 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
657 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
658 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
659 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
660 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
661 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300662 static const u8 n4_other[] =
663 {0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
664 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
665 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
666 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
667 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
668 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
669 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
670 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300671 static const u8 nset8[6] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672 { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300673 static const u8 nset8_other[6] =
674 { 0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00 };
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300675 static const u8 nset9[4] =
676 { 0x0b, 0x04, 0x0a, 0x78 };
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300677 static const u8 nset9_other[4] =
678 { 0x0b, 0x04, 0x0a, 0x00 };
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300680 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
681 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300682 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300683 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300684 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300685 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300686 break;
687 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300688 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300689 sd->sensor = SENSOR_OTHER;
690 break;
691 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300692 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300693 sd->sensor = SENSOR_OM6802;
694 break;
695 default:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300696 PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300697 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300698 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300700 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300701 reg_w_buf(gspca_dev, n1, sizeof n1);
702 i = 5;
703 while (--i >= 0) {
704 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
705 test_byte = reg_r(gspca_dev, 0x0063);
706 msleep(100);
707 if (test_byte == 0x17)
708 break; /* OK */
709 }
710 if (i < 0) {
711 err("Bad sensor reset %02x", test_byte);
712/* return -EIO; */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300713/*fixme: test - continue */
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300714 }
715 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300716 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300717
718 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300720 test_byte = reg_r(gspca_dev, read_indexs[i]);
721 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 test_byte);
723 i++;
724 }
725
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300726 if (sd->sensor != SENSOR_OTHER) {
727 reg_w_buf(gspca_dev, n3, sizeof n3);
728 reg_w_buf(gspca_dev, n4, sizeof n4);
729 reg_r(gspca_dev, 0x0080);
730 reg_w(gspca_dev, 0x2c80);
731 reg80 = 0x3880;
732 reg8e = 0x338e;
733 } else {
734 reg_w_buf(gspca_dev, n3_other, sizeof n3_other);
735 reg_w_buf(gspca_dev, n4_other, sizeof n4_other);
736 sd->gamma = 5;
737 reg80 = 0xac80;
738 reg8e = 0xb88e;
739 }
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300740
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300741 reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300742 sizeof sensor_data[sd->sensor].data1);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300743 reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
744 sizeof sensor_data[sd->sensor].data2);
745 reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300746 sizeof sensor_data[sd->sensor].data2);
747
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300748 reg_w(gspca_dev, reg80);
749 reg_w(gspca_dev, reg80);
750 reg_w(gspca_dev, reg8e);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300751
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300752 setbrightness(gspca_dev);
753 setcontrast(gspca_dev);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300754 setgamma(gspca_dev);
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300755 setcolors(gspca_dev);
756 setsharpness(gspca_dev);
757 setwhitebalance(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300758
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300759 reg_w(gspca_dev, 0x2087); /* tied to white balance? */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300760 reg_w(gspca_dev, 0x2088);
761 reg_w(gspca_dev, 0x2089);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300763 reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
764 sizeof sensor_data[sd->sensor].data4);
765 reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
766 sizeof sensor_data[sd->sensor].data5);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300767 if (sd->sensor != SENSOR_OTHER) {
768 reg_w_buf(gspca_dev, nset8, sizeof nset8);
769 reg_w_buf(gspca_dev, nset9, sizeof nset9);
770 reg_w(gspca_dev, 0x2880);
771 } else {
772 reg_w_buf(gspca_dev, nset8_other, sizeof nset8_other);
773 reg_w_buf(gspca_dev, nset9_other, sizeof nset9_other);
774 }
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300775
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300776 reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300777 sizeof sensor_data[sd->sensor].data1);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300778 reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
779 sizeof sensor_data[sd->sensor].data2);
780 reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300781 sizeof sensor_data[sd->sensor].data2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782
783 return 0;
784}
785
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300786static void setflip(struct gspca_dev *gspca_dev)
787{
788 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300789 u8 flipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300790 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300792 if (sd->mirror)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300793 flipcmd[3] = 0x01;
794
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300795 reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796}
797
798static void seteffect(struct gspca_dev *gspca_dev)
799{
800 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300802 reg_w_buf(gspca_dev, effects_table[sd->effect],
803 sizeof effects_table[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 if (sd->effect == 1 || sd->effect == 5) {
805 PDEBUG(D_CONF,
806 "This effect have been disabled for webcam \"safety\"");
807 return;
808 }
809
810 if (sd->effect == 1 || sd->effect == 4)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300811 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300812 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300813 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814}
815
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816static void setlightfreq(struct gspca_dev *gspca_dev)
817{
818 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300819 u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820
821 if (sd->freq == 2) /* 60hz */
822 freq[1] = 0x00;
823
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300824 reg_w_buf(gspca_dev, freq, sizeof freq);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300825}
826
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300827/* Is this really needed?
828 * i added some module parameters for test with some users */
829static void poll_sensor(struct gspca_dev *gspca_dev)
830{
831 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300832 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300833 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
834 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
835 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
836 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300837 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300838 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
839 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300840 static const u8 poll3[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300841 {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300842 static const u8 poll4[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300843 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
844 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
845 0xc2, 0x80, 0xc3, 0x10};
846
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300847 if (sd->sensor == SENSOR_OM6802) {
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300848 PDEBUG(D_STREAM, "[Sensor requires polling]");
849 reg_w_buf(gspca_dev, poll1, sizeof poll1);
850 reg_w_buf(gspca_dev, poll2, sizeof poll2);
851 reg_w_buf(gspca_dev, poll3, sizeof poll3);
852 reg_w_buf(gspca_dev, poll4, sizeof poll4);
853 }
854}
855
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300856static int sd_start(struct gspca_dev *gspca_dev)
857{
858 struct sd *sd = (struct sd *) gspca_dev;
859 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300860 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
861 static const u8 t3[] =
862 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300863
864 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
865 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300866 case 0: /* 640x480 (0x00) */
867 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300868 case 1: /* 352x288 */
869 t2[1] = 0x40;
870 break;
871 case 2: /* 320x240 */
872 t2[1] = 0x10;
873 break;
874 case 3: /* 176x144 */
875 t2[1] = 0x50;
876 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300877 default:
878/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300879 t2[1] = 0x20;
880 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300881 }
882
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300883 switch (sd->sensor) {
884 case SENSOR_OM6802:
885 om6802_sensor_init(gspca_dev);
886 break;
887 case SENSOR_OTHER:
888 break;
889 default:
890/* case SENSOR_TAS5130A: */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300891 i = 0;
892 while (tas5130a_sensor_init[i][0] != 0) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300893 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300894 sizeof tas5130a_sensor_init[0]);
895 i++;
896 }
897 reg_w(gspca_dev, 0x3c80);
898 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300899 reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300900 sizeof tas5130a_sensor_init[0]);
901 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300902 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300903 }
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300904 reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
905 sizeof sensor_data[sd->sensor].data4);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300906 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300907 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300908 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300909 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300910 msleep(15);
911 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
912 sizeof sensor_data[sd->sensor].stream);
913 poll_sensor(gspca_dev);
914
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300915 /* restart on each start, just in case, sometimes regs goes wrong
916 * when using controls from app */
917 setbrightness(gspca_dev);
918 setcontrast(gspca_dev);
919 setcolors(gspca_dev);
920 return 0;
921}
922
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300923static void sd_stopN(struct gspca_dev *gspca_dev)
924{
925 struct sd *sd = (struct sd *) gspca_dev;
926
927 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
928 sizeof sensor_data[sd->sensor].stream);
929 msleep(20);
930 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
931 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300932 if (sd->sensor != SENSOR_OTHER) {
933 msleep(20);
934 reg_w(gspca_dev, 0x0309);
935 }
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300936}
937
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300938static void sd_pkt_scan(struct gspca_dev *gspca_dev,
939 struct gspca_frame *frame, /* target */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300940 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300941 int len) /* iso packet length */
942{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300943 static u8 ffd9[] = { 0xff, 0xd9 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300944
945 if (data[0] == 0x5a) {
946 /* Control Packet, after this came the header again,
947 * but extra bytes came in the packet before this,
948 * sometimes an EOF arrives, sometimes not... */
949 return;
950 }
951 data += 2;
952 len -= 2;
953 if (data[0] == 0xff && data[1] == 0xd8) {
954 /* extra bytes....., could be processed too but would be
955 * a waste of time, right now leave the application and
956 * libjpeg do it for ourserlves.. */
957 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
958 ffd9, 2);
959 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
960 return;
961 }
962
963 if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
964 /* Just in case, i have seen packets with the marker,
965 * other's do not include it... */
966 len -= 2;
967 }
968 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300969}
970
971static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
972{
973 struct sd *sd = (struct sd *) gspca_dev;
974
975 sd->brightness = val;
976 if (gspca_dev->streaming)
977 setbrightness(gspca_dev);
978 return 0;
979}
980
981static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
982{
983 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300984
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985 *val = sd->brightness;
986 return *val;
987}
988
989static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
990{
991 struct sd *sd = (struct sd *) gspca_dev;
992
993 sd->whitebalance = val;
994 if (gspca_dev->streaming)
995 setwhitebalance(gspca_dev);
996 return 0;
997}
998
999static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
1000{
1001 struct sd *sd = (struct sd *) gspca_dev;
1002
1003 *val = sd->whitebalance;
1004 return *val;
1005}
1006
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
1008{
1009 struct sd *sd = (struct sd *) gspca_dev;
1010
1011 sd->mirror = val;
1012 if (gspca_dev->streaming)
1013 setflip(gspca_dev);
1014 return 0;
1015}
1016
1017static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
1018{
1019 struct sd *sd = (struct sd *) gspca_dev;
1020
1021 *val = sd->mirror;
1022 return *val;
1023}
1024
1025static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
1026{
1027 struct sd *sd = (struct sd *) gspca_dev;
1028
1029 sd->effect = val;
1030 if (gspca_dev->streaming)
1031 seteffect(gspca_dev);
1032 return 0;
1033}
1034
1035static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
1036{
1037 struct sd *sd = (struct sd *) gspca_dev;
1038
1039 *val = sd->effect;
1040 return *val;
1041}
1042
1043static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1044{
1045 struct sd *sd = (struct sd *) gspca_dev;
1046
1047 sd->contrast = val;
1048 if (gspca_dev->streaming)
1049 setcontrast(gspca_dev);
1050 return 0;
1051}
1052
1053static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1054{
1055 struct sd *sd = (struct sd *) gspca_dev;
1056
1057 *val = sd->contrast;
1058 return *val;
1059}
1060
1061static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1062{
1063 struct sd *sd = (struct sd *) gspca_dev;
1064
1065 sd->colors = val;
1066 if (gspca_dev->streaming)
1067 setcolors(gspca_dev);
1068 return 0;
1069}
1070
1071static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1072{
1073 struct sd *sd = (struct sd *) gspca_dev;
1074
1075 *val = sd->colors;
1076 return 0;
1077}
1078
1079static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
1080{
1081 struct sd *sd = (struct sd *) gspca_dev;
1082
1083 sd->gamma = val;
1084 if (gspca_dev->streaming)
1085 setgamma(gspca_dev);
1086 return 0;
1087}
1088
1089static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
1090{
1091 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001092
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001093 *val = sd->gamma;
1094 return 0;
1095}
1096
1097static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1098{
1099 struct sd *sd = (struct sd *) gspca_dev;
1100
1101 sd->freq = val;
1102 if (gspca_dev->streaming)
1103 setlightfreq(gspca_dev);
1104 return 0;
1105}
1106
1107static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1108{
1109 struct sd *sd = (struct sd *) gspca_dev;
1110
1111 *val = sd->freq;
1112 return 0;
1113}
1114
1115static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
1116{
1117 struct sd *sd = (struct sd *) gspca_dev;
1118
1119 sd->sharpness = val;
1120 if (gspca_dev->streaming)
1121 setsharpness(gspca_dev);
1122 return 0;
1123}
1124
1125static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
1126{
1127 struct sd *sd = (struct sd *) gspca_dev;
1128
1129 *val = sd->sharpness;
1130 return 0;
1131}
1132
1133/* Low Light set here......*/
1134static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
1135{
1136 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001137
1138 sd->autogain = val;
1139 if (val != 0)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001140 reg_w(gspca_dev, 0xf48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001141 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -03001142 reg_w(gspca_dev, 0xb48e);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001143 return 0;
1144}
1145
1146static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
1147{
1148 struct sd *sd = (struct sd *) gspca_dev;
1149
1150 *val = sd->autogain;
1151 return 0;
1152}
1153
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001154static int sd_querymenu(struct gspca_dev *gspca_dev,
1155 struct v4l2_querymenu *menu)
1156{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001157 switch (menu->id) {
1158 case V4L2_CID_POWER_LINE_FREQUENCY:
1159 switch (menu->index) {
1160 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001161 strcpy((char *) menu->name, "50 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001162 return 0;
1163 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001164 strcpy((char *) menu->name, "60 Hz");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001165 return 0;
1166 }
1167 break;
1168 case V4L2_CID_EFFECTS:
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001169 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
1170 strncpy((char *) menu->name,
1171 effects_control[menu->index], 32);
1172 return 0;
1173 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001174 break;
1175 }
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001176 return -EINVAL;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001177}
1178
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001179/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001180static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001181 .name = MODULE_NAME,
1182 .ctrls = sd_ctrls,
1183 .nctrls = ARRAY_SIZE(sd_ctrls),
1184 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001185 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001186 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001187 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001188 .pkt_scan = sd_pkt_scan,
1189 .querymenu = sd_querymenu,
1190};
1191
1192/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001193static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001194 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001195 {}
1196};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001197MODULE_DEVICE_TABLE(usb, device_table);
1198
1199/* -- device connect -- */
1200static int sd_probe(struct usb_interface *intf,
1201 const struct usb_device_id *id)
1202{
1203 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1204 THIS_MODULE);
1205}
1206
1207static struct usb_driver sd_driver = {
1208 .name = MODULE_NAME,
1209 .id_table = device_table,
1210 .probe = sd_probe,
1211 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001212#ifdef CONFIG_PM
1213 .suspend = gspca_suspend,
1214 .resume = gspca_resume,
1215#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001216};
1217
1218/* -- module insert / remove -- */
1219static int __init sd_mod_init(void)
1220{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001221 int ret;
1222 ret = usb_register(&sd_driver);
1223 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001224 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001225 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226 return 0;
1227}
1228static void __exit sd_mod_exit(void)
1229{
1230 usb_deregister(&sd_driver);
1231 PDEBUG(D_PROBE, "deregistered");
1232}
1233
1234module_init(sd_mod_init);
1235module_exit(sd_mod_exit);