1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31#define MODULE_NAME "t613"
32
33#include <linux/slab.h>
34#include "gspca.h"
35
36#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
37
38MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
39MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
40MODULE_LICENSE("GPL");
41
42struct sd {
43 struct gspca_dev gspca_dev;
44
45 u8 brightness;
46 u8 contrast;
47 u8 colors;
48 u8 autogain;
49 u8 gamma;
50 u8 sharpness;
51 u8 freq;
52 u8 red_gain;
53 u8 blue_gain;
54 u8 green_gain;
55 u8 awb;
56 u8 mirror;
57 u8 effect;
58
59 u8 sensor;
60};
61enum sensors {
62 SENSOR_OM6802,
63 SENSOR_OTHER,
64 SENSOR_TAS5130A,
65 SENSOR_LT168G,
66};
67
68
69static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
71static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
72static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
73static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
74static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
75static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
76static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
77static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
78static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
79static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
80static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
81static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
83
84static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
90static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
92
93static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
94static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
95static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
96static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
97
98static const struct ctrl sd_ctrls[] = {
99 {
100 {
101 .id = V4L2_CID_BRIGHTNESS,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Brightness",
104 .minimum = 0,
105 .maximum = 14,
106 .step = 1,
107#define BRIGHTNESS_DEF 8
108 .default_value = BRIGHTNESS_DEF,
109 },
110 .set = sd_setbrightness,
111 .get = sd_getbrightness,
112 },
113 {
114 {
115 .id = V4L2_CID_CONTRAST,
116 .type = V4L2_CTRL_TYPE_INTEGER,
117 .name = "Contrast",
118 .minimum = 0,
119 .maximum = 0x0d,
120 .step = 1,
121#define CONTRAST_DEF 0x07
122 .default_value = CONTRAST_DEF,
123 },
124 .set = sd_setcontrast,
125 .get = sd_getcontrast,
126 },
127 {
128 {
129 .id = V4L2_CID_SATURATION,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Color",
132 .minimum = 0,
133 .maximum = 0x0f,
134 .step = 1,
135#define COLORS_DEF 0x05
136 .default_value = COLORS_DEF,
137 },
138 .set = sd_setcolors,
139 .get = sd_getcolors,
140 },
141#define GAMMA_MAX 16
142#define GAMMA_DEF 10
143 {
144 {
145 .id = V4L2_CID_GAMMA,
146 .type = V4L2_CTRL_TYPE_INTEGER,
147 .name = "Gamma",
148 .minimum = 0,
149 .maximum = GAMMA_MAX - 1,
150 .step = 1,
151 .default_value = GAMMA_DEF,
152 },
153 .set = sd_setgamma,
154 .get = sd_getgamma,
155 },
156 {
157 {
158 .id = V4L2_CID_BACKLIGHT_COMPENSATION,
159
160
161 .type = V4L2_CTRL_TYPE_INTEGER,
162 .name = "Low Light",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
166#define AUTOGAIN_DEF 0x01
167 .default_value = AUTOGAIN_DEF,
168 },
169 .set = sd_setlowlight,
170 .get = sd_getlowlight,
171 },
172 {
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,
180#define MIRROR_DEF 0
181 .default_value = MIRROR_DEF,
182 },
183 .set = sd_setmirror,
184 .get = sd_getmirror
185 },
186 {
187 {
188 .id = V4L2_CID_POWER_LINE_FREQUENCY,
189 .type = V4L2_CTRL_TYPE_MENU,
190 .name = "Light Frequency Filter",
191 .minimum = 1,
192 .maximum = 2,
193 .step = 1,
194#define FREQ_DEF 1
195 .default_value = FREQ_DEF,
196 },
197 .set = sd_setfreq,
198 .get = sd_getfreq},
199
200 {
201 {
202 .id = V4L2_CID_AUTO_WHITE_BALANCE,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "Auto White Balance",
205 .minimum = 0,
206 .maximum = 1,
207 .step = 1,
208#define AWB_DEF 0
209 .default_value = AWB_DEF,
210 },
211 .set = sd_setawb,
212 .get = sd_getawb
213 },
214 {
215 {
216 .id = V4L2_CID_SHARPNESS,
217 .type = V4L2_CTRL_TYPE_INTEGER,
218 .name = "Sharpness",
219 .minimum = 0,
220 .maximum = 15,
221 .step = 1,
222#define SHARPNESS_DEF 0x06
223 .default_value = SHARPNESS_DEF,
224 },
225 .set = sd_setsharpness,
226 .get = sd_getsharpness,
227 },
228 {
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,
236#define EFFECTS_DEF 0
237 .default_value = EFFECTS_DEF,
238 },
239 .set = sd_seteffect,
240 .get = sd_geteffect
241 },
242 {
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,
250#define BLUE_GAIN_DEF 0x20
251 .default_value = BLUE_GAIN_DEF,
252 },
253 .set = sd_setblue_gain,
254 .get = sd_getblue_gain,
255 },
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,
264#define RED_GAIN_DEF 0x20
265 .default_value = RED_GAIN_DEF,
266 },
267 .set = sd_setred_gain,
268 .get = sd_getred_gain,
269 },
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,
278#define GAIN_DEF 0x20
279 .default_value = GAIN_DEF,
280 },
281 .set = sd_setgain,
282 .get = sd_getgain,
283 },
284};
285
286static const struct v4l2_pix_format vga_mode_t16[] = {
287 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
288 .bytesperline = 160,
289 .sizeimage = 160 * 120 * 4 / 8 + 590,
290 .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},
312};
313
314
315struct additional_sensor_data {
316 const u8 n3[6];
317 const u8 *n4, n4sz;
318 const u8 reg80, reg8e;
319 const u8 nset8[6];
320 const u8 data1[10];
321 const u8 data2[9];
322 const u8 data3[9];
323 const u8 data5[6];
324 const u8 stream[4];
325};
326
327static 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};
357static 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};
368
369static const struct additional_sensor_data sensor_data[] = {
370[SENSOR_OM6802] = {
371 .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},
378 .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},
384 .data3 =
385 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
386 0xff},
387 .data5 =
388 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
389 .stream =
390 {0x0b, 0x04, 0x0a, 0x78},
391 },
392[SENSOR_OTHER] = {
393 .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},
400 .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},
406 .data3 =
407 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
408 0xd9},
409 .data5 =
410 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
411 .stream =
412 {0x0b, 0x04, 0x0a, 0x00},
413 },
414[SENSOR_TAS5130A] = {
415 .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},
422 .data1 =
423 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
424 0xc8, 0xfc},
425 .data2 =
426 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
427 0xe0},
428 .data3 =
429 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
430 0xe0},
431 .data5 =
432 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
433 .stream =
434 {0x0b, 0x04, 0x0a, 0x40},
435 },
436[SENSOR_LT168G] = {
437 .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},
449 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
450 .stream = {0x0b, 0x04, 0x0a, 0x28},
451 },
452};
453
454#define MAX_EFFECTS 7
455
456
457static char *effects_control[MAX_EFFECTS] = {
458 "Normal",
459 "Emboss",
460 "Monochrome",
461 "Sepia",
462 "Sketch",
463 "Sun Effect",
464 "Negative",
465};
466static const u8 effects_table[MAX_EFFECTS][6] = {
467 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},
468 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},
469 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},
470 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},
471 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},
472 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},
473 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},
474};
475
476static const u8 gamma_table[GAMMA_MAX][17] = {
477
478 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,
479 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
480 0xff},
481 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,
482 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
483 0xff},
484 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,
485 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
486 0xff},
487 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,
488 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
489 0xff},
490 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a,
491 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
492 0xff},
493 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,
494 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
495 0xff},
496 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,
497 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
498 0xff},
499 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
500 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
501 0xff},
502 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,
503 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
504 0xff},
505 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,
506 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
507 0xff},
508 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,
509 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
510 0xff},
511 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,
512 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
513 0xff},
514 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,
515 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
516 0xff},
517 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,
518 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
519 0xff},
520 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,
521 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
522 0xff},
523 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,
524 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
525 0xff}
526};
527
528static const u8 tas5130a_sensor_init[][8] = {
529 {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},
532};
533
534static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
535
536
537static u8 reg_r(struct gspca_dev *gspca_dev,
538 u16 index)
539{
540 usb_control_msg(gspca_dev->dev,
541 usb_rcvctrlpipe(gspca_dev->dev, 0),
542 0,
543 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
544 0,
545 index,
546 gspca_dev->usb_buf, 1, 500);
547 return gspca_dev->usb_buf[0];
548}
549
550static void reg_w(struct gspca_dev *gspca_dev,
551 u16 index)
552{
553 usb_control_msg(gspca_dev->dev,
554 usb_sndctrlpipe(gspca_dev->dev, 0),
555 0,
556 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
557 0, index,
558 NULL, 0, 500);
559}
560
561static void reg_w_buf(struct gspca_dev *gspca_dev,
562 const u8 *buffer, u16 len)
563{
564 if (len <= USB_BUF_SZ) {
565 memcpy(gspca_dev->usb_buf, buffer, len);
566 usb_control_msg(gspca_dev->dev,
567 usb_sndctrlpipe(gspca_dev->dev, 0),
568 0,
569 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
570 0x01, 0,
571 gspca_dev->usb_buf, len, 500);
572 } else {
573 u8 *tmpbuf;
574
575 tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
576 if (!tmpbuf) {
577 pr_err("Out of memory\n");
578 return;
579 }
580 usb_control_msg(gspca_dev->dev,
581 usb_sndctrlpipe(gspca_dev->dev, 0),
582 0,
583 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
584 0x01, 0,
585 tmpbuf, len, 500);
586 kfree(tmpbuf);
587 }
588}
589
590
591static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
592 u8 reg,
593 const u8 *buffer, u16 len)
594{
595 int i;
596 u8 *p, *tmpbuf;
597
598 if (len * 2 <= USB_BUF_SZ) {
599 p = tmpbuf = gspca_dev->usb_buf;
600 } else {
601 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
602 if (!tmpbuf) {
603 pr_err("Out of memory\n");
604 return;
605 }
606 }
607 i = len;
608 while (--i >= 0) {
609 *p++ = reg++;
610 *p++ = *buffer++;
611 }
612 usb_control_msg(gspca_dev->dev,
613 usb_sndctrlpipe(gspca_dev->dev, 0),
614 0,
615 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
616 0x01, 0,
617 tmpbuf, len * 2, 500);
618 if (len * 2 > USB_BUF_SZ)
619 kfree(tmpbuf);
620}
621
622static void om6802_sensor_init(struct gspca_dev *gspca_dev)
623{
624 int i;
625 const u8 *p;
626 u8 byte;
627 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
628 static const u8 sensor_init[] = {
629 0xdf, 0x6d,
630 0xdd, 0x18,
631 0x5a, 0xe0,
632 0x5c, 0x07,
633 0x5d, 0xb0,
634 0x5e, 0x1e,
635 0x60, 0x71,
636 0xef, 0x00,
637 0xe9, 0x00,
638 0xea, 0x00,
639 0x90, 0x24,
640 0x91, 0xb2,
641 0x82, 0x32,
642 0xfd, 0x41,
643 0x00
644 };
645
646 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
647 msleep(100);
648 i = 4;
649 while (--i > 0) {
650 byte = reg_r(gspca_dev, 0x0060);
651 if (!(byte & 0x01))
652 break;
653 msleep(100);
654 }
655 byte = reg_r(gspca_dev, 0x0063);
656 if (byte != 0x17) {
657 pr_err("Bad sensor reset %02x\n", byte);
658
659 }
660
661 p = sensor_init;
662 while (*p != 0) {
663 val[1] = *p++;
664 val[3] = *p++;
665 if (*p == 0)
666 reg_w(gspca_dev, 0x3c80);
667 reg_w_buf(gspca_dev, val, sizeof val);
668 i = 4;
669 while (--i >= 0) {
670 msleep(15);
671 byte = reg_r(gspca_dev, 0x60);
672 if (!(byte & 0x01))
673 break;
674 }
675 }
676 msleep(15);
677 reg_w(gspca_dev, 0x3c80);
678}
679
680
681static int sd_config(struct gspca_dev *gspca_dev,
682 const struct usb_device_id *id)
683{
684 struct sd *sd = (struct sd *) gspca_dev;
685 struct cam *cam;
686
687 cam = &gspca_dev->cam;
688
689 cam->cam_mode = vga_mode_t16;
690 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
691
692 sd->brightness = BRIGHTNESS_DEF;
693 sd->contrast = CONTRAST_DEF;
694 sd->colors = COLORS_DEF;
695 sd->gamma = GAMMA_DEF;
696 sd->autogain = AUTOGAIN_DEF;
697 sd->mirror = MIRROR_DEF;
698 sd->freq = FREQ_DEF;
699 sd->awb = AWB_DEF;
700 sd->sharpness = SHARPNESS_DEF;
701 sd->effect = EFFECTS_DEF;
702 sd->red_gain = RED_GAIN_DEF;
703 sd->blue_gain = BLUE_GAIN_DEF;
704 sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
705
706 return 0;
707}
708
709static void setbrightness(struct gspca_dev *gspca_dev)
710{
711 struct sd *sd = (struct sd *) gspca_dev;
712 unsigned int brightness;
713 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
714
715 brightness = sd->brightness;
716 if (brightness < 7) {
717 set6[1] = 0x26;
718 set6[3] = 0x70 - brightness * 0x10;
719 } else {
720 set6[3] = 0x00 + ((brightness - 7) * 0x10);
721 }
722
723 reg_w_buf(gspca_dev, set6, sizeof set6);
724}
725
726static void setcontrast(struct gspca_dev *gspca_dev)
727{
728 struct sd *sd = (struct sd *) gspca_dev;
729 unsigned int contrast = sd->contrast;
730 u16 reg_to_write;
731
732 if (contrast < 7)
733 reg_to_write = 0x8ea9 - contrast * 0x200;
734 else
735 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
736
737 reg_w(gspca_dev, reg_to_write);
738}
739
740static void setcolors(struct gspca_dev *gspca_dev)
741{
742 struct sd *sd = (struct sd *) gspca_dev;
743 u16 reg_to_write;
744
745 reg_to_write = 0x80bb + sd->colors * 0x100;
746 reg_w(gspca_dev, reg_to_write);
747}
748
749static void setgamma(struct gspca_dev *gspca_dev)
750{
751 struct sd *sd = (struct sd *) gspca_dev;
752
753 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
754 reg_w_ixbuf(gspca_dev, 0x90,
755 gamma_table[sd->gamma], sizeof gamma_table[0]);
756}
757
758static void setRGB(struct gspca_dev *gspca_dev)
759{
760 struct sd *sd = (struct sd *) gspca_dev;
761 u8 all_gain_reg[6] =
762 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
763
764 all_gain_reg[1] = sd->red_gain;
765 all_gain_reg[3] = sd->blue_gain;
766 all_gain_reg[5] = sd->green_gain;
767 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
768}
769
770
771static void setawb(struct gspca_dev *gspca_dev)
772{
773 struct sd *sd = (struct sd *) gspca_dev;
774 u16 reg80;
775
776 reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
777
778
779 if (!sd->awb) {
780
781
782 sd->red_gain = reg_r(gspca_dev, 0x0087);
783 sd->blue_gain = reg_r(gspca_dev, 0x0088);
784 sd->green_gain = reg_r(gspca_dev, 0x0089);
785 reg80 &= ~0x0400;
786 }
787 reg_w(gspca_dev, reg80);
788 reg_w(gspca_dev, reg80);
789}
790
791static void init_gains(struct gspca_dev *gspca_dev)
792{
793 struct sd *sd = (struct sd *) gspca_dev;
794 u16 reg80;
795 u8 all_gain_reg[8] =
796 {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
797
798 all_gain_reg[1] = sd->red_gain;
799 all_gain_reg[3] = sd->blue_gain;
800 all_gain_reg[5] = sd->green_gain;
801 reg80 = sensor_data[sd->sensor].reg80;
802 if (!sd->awb)
803 reg80 &= ~0x04;
804 all_gain_reg[7] = reg80;
805 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
806
807 reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);
808 reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
809 reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);
810}
811
812static void setsharpness(struct gspca_dev *gspca_dev)
813{
814 struct sd *sd = (struct sd *) gspca_dev;
815 u16 reg_to_write;
816
817 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
818
819 reg_w(gspca_dev, reg_to_write);
820}
821
822static void setfreq(struct gspca_dev *gspca_dev)
823{
824 struct sd *sd = (struct sd *) gspca_dev;
825 u8 reg66;
826 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
827
828 switch (sd->sensor) {
829 case SENSOR_LT168G:
830 if (sd->freq != 0)
831 freq[3] = 0xa8;
832 reg66 = 0x41;
833 break;
834 case SENSOR_OM6802:
835 reg66 = 0xca;
836 break;
837 default:
838 reg66 = 0x40;
839 break;
840 }
841 switch (sd->freq) {
842 case 0:
843 freq[3] = 0xf0;
844 break;
845 case 2:
846 reg66 &= ~0x40;
847 break;
848 }
849 freq[1] = reg66;
850
851 reg_w_buf(gspca_dev, freq, sizeof freq);
852}
853
854
855static int sd_init(struct gspca_dev *gspca_dev)
856{
857
858
859
860
861 struct sd *sd = (struct sd *) gspca_dev;
862 const struct additional_sensor_data *sensor;
863 int i;
864 u16 sensor_id;
865 u8 test_byte = 0;
866
867 static const u8 read_indexs[] =
868 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
869 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
870 static const u8 n1[] =
871 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
872 static const u8 n2[] =
873 {0x08, 0x00};
874
875 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
876 | reg_r(gspca_dev, 0x07);
877 switch (sensor_id & 0xff0f) {
878 case 0x0801:
879 PDEBUG(D_PROBE, "sensor tas5130a");
880 sd->sensor = SENSOR_TAS5130A;
881 break;
882 case 0x0802:
883 PDEBUG(D_PROBE, "sensor lt168g");
884 sd->sensor = SENSOR_LT168G;
885 break;
886 case 0x0803:
887 PDEBUG(D_PROBE, "sensor 'other'");
888 sd->sensor = SENSOR_OTHER;
889 break;
890 case 0x0807:
891 PDEBUG(D_PROBE, "sensor om6802");
892 sd->sensor = SENSOR_OM6802;
893 break;
894 default:
895 pr_err("unknown sensor %04x\n", sensor_id);
896 return -EINVAL;
897 }
898
899 if (sd->sensor == SENSOR_OM6802) {
900 reg_w_buf(gspca_dev, n1, sizeof n1);
901 i = 5;
902 while (--i >= 0) {
903 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
904 test_byte = reg_r(gspca_dev, 0x0063);
905 msleep(100);
906 if (test_byte == 0x17)
907 break;
908 }
909 if (i < 0) {
910 pr_err("Bad sensor reset %02x\n", test_byte);
911 return -EIO;
912 }
913 reg_w_buf(gspca_dev, n2, sizeof n2);
914 }
915
916 i = 0;
917 while (read_indexs[i] != 0x00) {
918 test_byte = reg_r(gspca_dev, read_indexs[i]);
919 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
920 test_byte);
921 i++;
922 }
923
924 sensor = &sensor_data[sd->sensor];
925 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
926 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
927
928 if (sd->sensor == SENSOR_LT168G) {
929 test_byte = reg_r(gspca_dev, 0x80);
930 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
931 test_byte);
932 reg_w(gspca_dev, 0x6c80);
933 }
934
935 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
936 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
937 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
938
939 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
940 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
941 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
942
943 setbrightness(gspca_dev);
944 setcontrast(gspca_dev);
945 setgamma(gspca_dev);
946 setcolors(gspca_dev);
947 setsharpness(gspca_dev);
948 init_gains(gspca_dev);
949 setfreq(gspca_dev);
950
951 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
952 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
953 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
954
955 if (sd->sensor == SENSOR_LT168G) {
956 test_byte = reg_r(gspca_dev, 0x80);
957 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
958 test_byte);
959 reg_w(gspca_dev, 0x6c80);
960 }
961
962 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
963 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
964 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
965
966 return 0;
967}
968
969static void setmirror(struct gspca_dev *gspca_dev)
970{
971 struct sd *sd = (struct sd *) gspca_dev;
972 u8 hflipcmd[8] =
973 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
974
975 if (sd->mirror)
976 hflipcmd[3] = 0x01;
977
978 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
979}
980
981static void seteffect(struct gspca_dev *gspca_dev)
982{
983 struct sd *sd = (struct sd *) gspca_dev;
984
985 reg_w_buf(gspca_dev, effects_table[sd->effect],
986 sizeof effects_table[0]);
987 if (sd->effect == 1 || sd->effect == 5) {
988 PDEBUG(D_CONF,
989 "This effect have been disabled for webcam \"safety\"");
990 return;
991 }
992
993 if (sd->effect == 1 || sd->effect == 4)
994 reg_w(gspca_dev, 0x4aa6);
995 else
996 reg_w(gspca_dev, 0xfaa6);
997}
998
999
1000
1001static void poll_sensor(struct gspca_dev *gspca_dev)
1002{
1003 static const u8 poll1[] =
1004 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
1005 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
1006 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
1007 0x60, 0x14};
1008 static const u8 poll2[] =
1009 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
1010 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
1011 static const u8 noise03[] =
1012 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
1013 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
1014 0xc2, 0x80, 0xc3, 0x10};
1015
1016 PDEBUG(D_STREAM, "[Sensor requires polling]");
1017 reg_w_buf(gspca_dev, poll1, sizeof poll1);
1018 reg_w_buf(gspca_dev, poll2, sizeof poll2);
1019 reg_w_buf(gspca_dev, noise03, sizeof noise03);
1020}
1021
1022static int sd_start(struct gspca_dev *gspca_dev)
1023{
1024 struct sd *sd = (struct sd *) gspca_dev;
1025 const struct additional_sensor_data *sensor;
1026 int i, mode;
1027 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
1028 static const u8 t3[] =
1029 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
1030
1031 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
1032 switch (mode) {
1033 case 0:
1034 break;
1035 case 1:
1036 t2[1] = 0x40;
1037 break;
1038 case 2:
1039 t2[1] = 0x10;
1040 break;
1041 case 3:
1042 t2[1] = 0x50;
1043 break;
1044 default:
1045
1046 t2[1] = 0x20;
1047 break;
1048 }
1049
1050 switch (sd->sensor) {
1051 case SENSOR_OM6802:
1052 om6802_sensor_init(gspca_dev);
1053 break;
1054 case SENSOR_TAS5130A:
1055 i = 0;
1056 for (;;) {
1057 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
1058 sizeof tas5130a_sensor_init[0]);
1059 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
1060 break;
1061 i++;
1062 }
1063 reg_w(gspca_dev, 0x3c80);
1064
1065 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
1066 sizeof tas5130a_sensor_init[0]);
1067 reg_w(gspca_dev, 0x3c80);
1068 break;
1069 }
1070 sensor = &sensor_data[sd->sensor];
1071 setfreq(gspca_dev);
1072 reg_r(gspca_dev, 0x0012);
1073 reg_w_buf(gspca_dev, t2, sizeof t2);
1074 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
1075 reg_w(gspca_dev, 0x0013);
1076 msleep(15);
1077 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
1078 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
1079
1080 if (sd->sensor == SENSOR_OM6802)
1081 poll_sensor(gspca_dev);
1082
1083 return 0;
1084}
1085
1086static void sd_stopN(struct gspca_dev *gspca_dev)
1087{
1088 struct sd *sd = (struct sd *) gspca_dev;
1089
1090 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1091 sizeof sensor_data[sd->sensor].stream);
1092 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
1093 sizeof sensor_data[sd->sensor].stream);
1094 if (sd->sensor == SENSOR_OM6802) {
1095 msleep(20);
1096 reg_w(gspca_dev, 0x0309);
1097 }
1098}
1099
1100static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1101 u8 *data,
1102 int len)
1103{
1104 int pkt_type;
1105
1106 if (data[0] == 0x5a) {
1107
1108
1109
1110 return;
1111 }
1112 data += 2;
1113 len -= 2;
1114 if (data[0] == 0xff && data[1] == 0xd8)
1115 pkt_type = FIRST_PACKET;
1116 else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
1117 pkt_type = LAST_PACKET;
1118 else
1119 pkt_type = INTER_PACKET;
1120 gspca_frame_add(gspca_dev, pkt_type, data, len);
1121}
1122
1123static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
1124{
1125 struct sd *sd = (struct sd *) gspca_dev;
1126
1127 sd->blue_gain = val;
1128 if (gspca_dev->streaming)
1129 reg_w(gspca_dev, (val << 8) + 0x88);
1130 return 0;
1131}
1132
1133static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
1134{
1135 struct sd *sd = (struct sd *) gspca_dev;
1136
1137 *val = sd->blue_gain;
1138 return 0;
1139}
1140
1141static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
1142{
1143 struct sd *sd = (struct sd *) gspca_dev;
1144
1145 sd->red_gain = val;
1146 if (gspca_dev->streaming)
1147 reg_w(gspca_dev, (val << 8) + 0x87);
1148
1149 return 0;
1150}
1151
1152static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
1153{
1154 struct sd *sd = (struct sd *) gspca_dev;
1155
1156 *val = sd->red_gain;
1157 return 0;
1158}
1159
1160static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1161{
1162 struct sd *sd = (struct sd *) gspca_dev;
1163 u16 psg, nsg;
1164
1165 psg = sd->red_gain + sd->blue_gain + sd->green_gain;
1166 nsg = val * 3;
1167 sd->red_gain = sd->red_gain * nsg / psg;
1168 if (sd->red_gain > 0x40)
1169 sd->red_gain = 0x40;
1170 else if (sd->red_gain < 0x10)
1171 sd->red_gain = 0x10;
1172 sd->blue_gain = sd->blue_gain * nsg / psg;
1173 if (sd->blue_gain > 0x40)
1174 sd->blue_gain = 0x40;
1175 else if (sd->blue_gain < 0x10)
1176 sd->blue_gain = 0x10;
1177 sd->green_gain = sd->green_gain * nsg / psg;
1178 if (sd->green_gain > 0x40)
1179 sd->green_gain = 0x40;
1180 else if (sd->green_gain < 0x10)
1181 sd->green_gain = 0x10;
1182
1183 if (gspca_dev->streaming)
1184 setRGB(gspca_dev);
1185 return 0;
1186}
1187
1188static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1189{
1190 struct sd *sd = (struct sd *) gspca_dev;
1191
1192 *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
1193 return 0;
1194}
1195
1196static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1197{
1198 struct sd *sd = (struct sd *) gspca_dev;
1199
1200 sd->brightness = val;
1201 if (gspca_dev->streaming)
1202 setbrightness(gspca_dev);
1203 return 0;
1204}
1205
1206static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1207{
1208 struct sd *sd = (struct sd *) gspca_dev;
1209
1210 *val = sd->brightness;
1211 return *val;
1212}
1213
1214static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
1215{
1216 struct sd *sd = (struct sd *) gspca_dev;
1217
1218 sd->awb = val;
1219 if (gspca_dev->streaming)
1220 setawb(gspca_dev);
1221 return 0;
1222}
1223
1224static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
1225{
1226 struct sd *sd = (struct sd *) gspca_dev;
1227
1228 *val = sd->awb;
1229 return *val;
1230}
1231
1232static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
1233{
1234 struct sd *sd = (struct sd *) gspca_dev;
1235
1236 sd->mirror = val;
1237 if (gspca_dev->streaming)
1238 setmirror(gspca_dev);
1239 return 0;
1240}
1241
1242static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
1243{
1244 struct sd *sd = (struct sd *) gspca_dev;
1245
1246 *val = sd->mirror;
1247 return *val;
1248}
1249
1250static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
1251{
1252 struct sd *sd = (struct sd *) gspca_dev;
1253
1254 sd->effect = val;
1255 if (gspca_dev->streaming)
1256 seteffect(gspca_dev);
1257 return 0;
1258}
1259
1260static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
1261{
1262 struct sd *sd = (struct sd *) gspca_dev;
1263
1264 *val = sd->effect;
1265 return *val;
1266}
1267
1268static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1269{
1270 struct sd *sd = (struct sd *) gspca_dev;
1271
1272 sd->contrast = val;
1273 if (gspca_dev->streaming)
1274 setcontrast(gspca_dev);
1275 return 0;
1276}
1277
1278static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1279{
1280 struct sd *sd = (struct sd *) gspca_dev;
1281
1282 *val = sd->contrast;
1283 return *val;
1284}
1285
1286static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1287{
1288 struct sd *sd = (struct sd *) gspca_dev;
1289
1290 sd->colors = val;
1291 if (gspca_dev->streaming)
1292 setcolors(gspca_dev);
1293 return 0;
1294}
1295
1296static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1297{
1298 struct sd *sd = (struct sd *) gspca_dev;
1299
1300 *val = sd->colors;
1301 return 0;
1302}
1303
1304static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
1305{
1306 struct sd *sd = (struct sd *) gspca_dev;
1307
1308 sd->gamma = val;
1309 if (gspca_dev->streaming)
1310 setgamma(gspca_dev);
1311 return 0;
1312}
1313
1314static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
1315{
1316 struct sd *sd = (struct sd *) gspca_dev;
1317
1318 *val = sd->gamma;
1319 return 0;
1320}
1321
1322static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1323{
1324 struct sd *sd = (struct sd *) gspca_dev;
1325
1326 sd->freq = val;
1327 if (gspca_dev->streaming)
1328 setfreq(gspca_dev);
1329 return 0;
1330}
1331
1332static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1333{
1334 struct sd *sd = (struct sd *) gspca_dev;
1335
1336 *val = sd->freq;
1337 return 0;
1338}
1339
1340static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
1341{
1342 struct sd *sd = (struct sd *) gspca_dev;
1343
1344 sd->sharpness = val;
1345 if (gspca_dev->streaming)
1346 setsharpness(gspca_dev);
1347 return 0;
1348}
1349
1350static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
1351{
1352 struct sd *sd = (struct sd *) gspca_dev;
1353
1354 *val = sd->sharpness;
1355 return 0;
1356}
1357
1358
1359static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
1360{
1361 struct sd *sd = (struct sd *) gspca_dev;
1362
1363 sd->autogain = val;
1364 if (val != 0)
1365 reg_w(gspca_dev, 0xf48e);
1366 else
1367 reg_w(gspca_dev, 0xb48e);
1368 return 0;
1369}
1370
1371static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
1372{
1373 struct sd *sd = (struct sd *) gspca_dev;
1374
1375 *val = sd->autogain;
1376 return 0;
1377}
1378
1379static int sd_querymenu(struct gspca_dev *gspca_dev,
1380 struct v4l2_querymenu *menu)
1381{
1382 static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
1383
1384 switch (menu->id) {
1385 case V4L2_CID_POWER_LINE_FREQUENCY:
1386 if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
1387 break;
1388 strcpy((char *) menu->name, freq_nm[menu->index]);
1389 return 0;
1390 case V4L2_CID_EFFECTS:
1391 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
1392 strlcpy((char *) menu->name,
1393 effects_control[menu->index],
1394 sizeof menu->name);
1395 return 0;
1396 }
1397 break;
1398 }
1399 return -EINVAL;
1400}
1401
1402
1403static const struct sd_desc sd_desc = {
1404 .name = MODULE_NAME,
1405 .ctrls = sd_ctrls,
1406 .nctrls = ARRAY_SIZE(sd_ctrls),
1407 .config = sd_config,
1408 .init = sd_init,
1409 .start = sd_start,
1410 .stopN = sd_stopN,
1411 .pkt_scan = sd_pkt_scan,
1412 .querymenu = sd_querymenu,
1413};
1414
1415
1416static const struct usb_device_id device_table[] = {
1417 {USB_DEVICE(0x17a1, 0x0128)},
1418 {}
1419};
1420MODULE_DEVICE_TABLE(usb, device_table);
1421
1422
1423static int sd_probe(struct usb_interface *intf,
1424 const struct usb_device_id *id)
1425{
1426 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1427 THIS_MODULE);
1428}
1429
1430static struct usb_driver sd_driver = {
1431 .name = MODULE_NAME,
1432 .id_table = device_table,
1433 .probe = sd_probe,
1434 .disconnect = gspca_disconnect,
1435#ifdef CONFIG_PM
1436 .suspend = gspca_suspend,
1437 .resume = gspca_resume,
1438#endif
1439};
1440
1441
1442static int __init sd_mod_init(void)
1443{
1444 return usb_register(&sd_driver);
1445}
1446static void __exit sd_mod_exit(void)
1447{
1448 usb_deregister(&sd_driver);
1449}
1450
1451module_init(sd_mod_init);
1452module_exit(sd_mod_exit);
1453