blob: f8bf6a63f0428125120729ae648954876cb81b75 [file] [log] [blame]
Marton Nemeth1408b842009-11-02 08:13:21 -03001/*
2 * Pixart PAC7302 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * Separated from Pixart PAC7311 library by Márton Németh <nm127@freemail.hu>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24/* Some documentation about various registers as determined by trial and error.
25 When the register addresses differ between the 7202 and the 7311 the 2
26 different addresses are written as 7302addr/7311addr, when one of the 2
27 addresses is a - sign that register description is not valid for the
28 matching IC.
29
30 Register page 1:
31
32 Address Description
33 -/0x08 Unknown compressor related, must always be 8 except when not
34 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
35 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
36 bits 345 seem to toggle per color gains on/off (inverted)
37 0x78 Global control, bit 6 controls the LED (inverted)
38 -/0x80 JPEG compression ratio ? Best not touched
39
40 Register page 3/4:
41
42 Address Description
43 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
44 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
45 -/0x0f Master gain 1-245, low value = high gain
46 0x10/- Master gain 0-31
47 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
48 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
49 -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
50 completely disable the analog amplification block. Set to 0x68
51 for max gain, 0x14 for minimal gain.
Márton Németh265a8092009-11-07 15:15:56 -030052
53 The registers are accessed in the following functions:
54
55 Page | Register | Function
56 -----+------------+---------------------------------------------------
57 0 | 0x0f..0x20 | setcolors()
58 0 | 0xa2..0xab | setbrightcont()
59 0 | 0xc5 | setredbalance()
Marton Nemeth23fbee62009-11-08 04:35:12 -030060 0 | 0xc6 | setwhitebalance()
Márton Németh265a8092009-11-07 15:15:56 -030061 0 | 0xc7 | setbluebalance()
62 0 | 0xdc | setbrightcont(), setcolors()
63 3 | 0x02 | setexposure()
64 3 | 0x10 | setgain()
65 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
66 3 | 0x21 | sethvflip()
Marton Nemeth1408b842009-11-02 08:13:21 -030067*/
68
69#define MODULE_NAME "pac7302"
70
71#include "gspca.h"
72
73MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
74MODULE_DESCRIPTION("Pixart PAC7302");
75MODULE_LICENSE("GPL");
76
77/* specific webcam descriptor for pac7302 */
78struct sd {
79 struct gspca_dev gspca_dev; /* !! must be the first item */
80
81 unsigned char brightness;
82 unsigned char contrast;
83 unsigned char colors;
Marton Nemeth23fbee62009-11-08 04:35:12 -030084 unsigned char white_balance;
Márton Németh265a8092009-11-07 15:15:56 -030085 unsigned char red_balance;
86 unsigned char blue_balance;
Marton Nemeth1408b842009-11-02 08:13:21 -030087 unsigned char gain;
88 unsigned char exposure;
89 unsigned char autogain;
90 __u8 hflip;
91 __u8 vflip;
92
93 u8 sof_read;
94 u8 autogain_ignore_frames;
95
96 atomic_t avg_lum;
97};
98
99/* V4L2 controls supported by the driver */
100static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
101static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
102static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
103static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
104static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
105static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300106static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
107static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
Márton Németh265a8092009-11-07 15:15:56 -0300108static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
109static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
110static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
111static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300112static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
113static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
114static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
116static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
117static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
118static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
120static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
122
123static struct ctrl sd_ctrls[] = {
124/* This control is pac7302 only */
125 {
126 {
127 .id = V4L2_CID_BRIGHTNESS,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "Brightness",
130 .minimum = 0,
131#define BRIGHTNESS_MAX 0x20
132 .maximum = BRIGHTNESS_MAX,
133 .step = 1,
134#define BRIGHTNESS_DEF 0x10
135 .default_value = BRIGHTNESS_DEF,
136 },
137 .set = sd_setbrightness,
138 .get = sd_getbrightness,
139 },
140/* This control is for both the 7302 and the 7311 */
141 {
142 {
143 .id = V4L2_CID_CONTRAST,
144 .type = V4L2_CTRL_TYPE_INTEGER,
145 .name = "Contrast",
146 .minimum = 0,
147#define CONTRAST_MAX 255
148 .maximum = CONTRAST_MAX,
149 .step = 1,
150#define CONTRAST_DEF 127
151 .default_value = CONTRAST_DEF,
152 },
153 .set = sd_setcontrast,
154 .get = sd_getcontrast,
155 },
156/* This control is pac7302 only */
157 {
158 {
159 .id = V4L2_CID_SATURATION,
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "Saturation",
162 .minimum = 0,
163#define COLOR_MAX 255
164 .maximum = COLOR_MAX,
165 .step = 1,
166#define COLOR_DEF 127
167 .default_value = COLOR_DEF,
168 },
169 .set = sd_setcolors,
170 .get = sd_getcolors,
171 },
Márton Németh265a8092009-11-07 15:15:56 -0300172 {
173 {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300174 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "White Balance",
177 .minimum = 0,
178 .maximum = 255,
179 .step = 1,
180#define WHITEBALANCE_DEF 4
181 .default_value = WHITEBALANCE_DEF,
182 },
183 .set = sd_setwhitebalance,
184 .get = sd_getwhitebalance,
185 },
186 {
187 {
Márton Németh265a8092009-11-07 15:15:56 -0300188 .id = V4L2_CID_RED_BALANCE,
189 .type = V4L2_CTRL_TYPE_INTEGER,
190 .name = "Red",
191 .minimum = 0,
192 .maximum = 3,
193 .step = 1,
194#define REDBALANCE_DEF 1
195 .default_value = REDBALANCE_DEF,
196 },
197 .set = sd_setredbalance,
198 .get = sd_getredbalance,
199 },
200 {
201 {
202 .id = V4L2_CID_BLUE_BALANCE,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "Blue",
205 .minimum = 0,
206 .maximum = 3,
207 .step = 1,
208#define BLUEBALANCE_DEF 1
209 .default_value = BLUEBALANCE_DEF,
210 },
211 .set = sd_setbluebalance,
212 .get = sd_getbluebalance,
213 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300214/* All controls below are for both the 7302 and the 7311 */
215 {
216 {
217 .id = V4L2_CID_GAIN,
218 .type = V4L2_CTRL_TYPE_INTEGER,
219 .name = "Gain",
220 .minimum = 0,
221#define GAIN_MAX 255
222 .maximum = GAIN_MAX,
223 .step = 1,
224#define GAIN_DEF 127
225#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
226 .default_value = GAIN_DEF,
227 },
228 .set = sd_setgain,
229 .get = sd_getgain,
230 },
231 {
232 {
233 .id = V4L2_CID_EXPOSURE,
234 .type = V4L2_CTRL_TYPE_INTEGER,
235 .name = "Exposure",
236 .minimum = 0,
237#define EXPOSURE_MAX 255
238 .maximum = EXPOSURE_MAX,
239 .step = 1,
240#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
241#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
242 .default_value = EXPOSURE_DEF,
243 },
244 .set = sd_setexposure,
245 .get = sd_getexposure,
246 },
247 {
248 {
249 .id = V4L2_CID_AUTOGAIN,
250 .type = V4L2_CTRL_TYPE_BOOLEAN,
251 .name = "Auto Gain",
252 .minimum = 0,
253 .maximum = 1,
254 .step = 1,
255#define AUTOGAIN_DEF 1
256 .default_value = AUTOGAIN_DEF,
257 },
258 .set = sd_setautogain,
259 .get = sd_getautogain,
260 },
261 {
262 {
263 .id = V4L2_CID_HFLIP,
264 .type = V4L2_CTRL_TYPE_BOOLEAN,
265 .name = "Mirror",
266 .minimum = 0,
267 .maximum = 1,
268 .step = 1,
269#define HFLIP_DEF 0
270 .default_value = HFLIP_DEF,
271 },
272 .set = sd_sethflip,
273 .get = sd_gethflip,
274 },
275 {
276 {
277 .id = V4L2_CID_VFLIP,
278 .type = V4L2_CTRL_TYPE_BOOLEAN,
279 .name = "Vflip",
280 .minimum = 0,
281 .maximum = 1,
282 .step = 1,
283#define VFLIP_DEF 0
284 .default_value = VFLIP_DEF,
285 },
286 .set = sd_setvflip,
287 .get = sd_getvflip,
288 },
289};
290
291static const struct v4l2_pix_format vga_mode[] = {
292 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
293 .bytesperline = 640,
294 .sizeimage = 640 * 480 * 3 / 8 + 590,
295 .colorspace = V4L2_COLORSPACE_JPEG,
296 .priv = 0},
297};
298
299#define LOAD_PAGE3 255
300#define LOAD_PAGE4 254
301#define END_OF_SEQUENCE 0
302
303/* pac 7302 */
304static const __u8 init_7302[] = {
305/* index,value */
306 0xff, 0x01, /* page 1 */
307 0x78, 0x00, /* deactivate */
308 0xff, 0x01,
309 0x78, 0x40, /* led off */
310};
311static const __u8 start_7302[] = {
312/* index, len, [value]* */
313 0xff, 1, 0x00, /* page 0 */
314 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
315 0x00, 0x00, 0x00, 0x00,
316 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
317 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
318 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
319 0x26, 2, 0xaa, 0xaa,
320 0x2e, 1, 0x31,
321 0x38, 1, 0x01,
322 0x3a, 3, 0x14, 0xff, 0x5a,
323 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
324 0x00, 0x54, 0x11,
325 0x55, 1, 0x00,
326 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
327 0x6b, 1, 0x00,
328 0x6e, 3, 0x08, 0x06, 0x00,
329 0x72, 3, 0x00, 0xff, 0x00,
330 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
331 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
332 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
333 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
334 0xd2, 0xeb,
335 0xaf, 1, 0x02,
336 0xb5, 2, 0x08, 0x08,
337 0xb8, 2, 0x08, 0x88,
338 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
339 0xcc, 1, 0x00,
340 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
341 0xc1, 0xd7, 0xec,
342 0xdc, 1, 0x01,
343 0xff, 1, 0x01, /* page 1 */
344 0x12, 3, 0x02, 0x00, 0x01,
345 0x3e, 2, 0x00, 0x00,
346 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
347 0x7c, 1, 0x00,
348 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
349 0x02, 0x00,
350 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
351 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
352 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
353 0xd8, 1, 0x01,
354 0xdb, 2, 0x00, 0x01,
355 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
356 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
357 0xeb, 1, 0x00,
358 0xff, 1, 0x02, /* page 2 */
359 0x22, 1, 0x00,
360 0xff, 1, 0x03, /* page 3 */
361 0, LOAD_PAGE3, /* load the page 3 */
362 0x11, 1, 0x01,
363 0xff, 1, 0x02, /* page 2 */
364 0x13, 1, 0x00,
365 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
366 0x27, 2, 0x14, 0x0c,
367 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
368 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
369 0x6e, 1, 0x08,
370 0xff, 1, 0x01, /* page 1 */
371 0x78, 1, 0x00,
372 0, END_OF_SEQUENCE /* end of sequence */
373};
374
375#define SKIP 0xaa
376/* page 3 - the value SKIP says skip the index - see reg_w_page() */
377static const __u8 page3_7302[] = {
378 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
379 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
380 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
382 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
383 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
384 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
385 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
388 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
392 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
393 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
394 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
397 0x00
398};
399
Márton Némethb1784b32009-11-07 05:52:02 -0300400static int reg_w_buf(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300401 __u8 index,
402 const char *buffer, int len)
403{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300404 int ret;
405
Marton Nemeth1408b842009-11-02 08:13:21 -0300406 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300407 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300408 usb_sndctrlpipe(gspca_dev->dev, 0),
409 1, /* request */
410 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
411 0, /* value */
412 index, gspca_dev->usb_buf, len,
413 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300414 if (ret < 0)
415 PDEBUG(D_ERR, "reg_w_buf(): "
416 "Failed to write registers to index 0x%x, error %i",
417 index, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300418 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300419}
420
421
Márton Némethb1784b32009-11-07 05:52:02 -0300422static int reg_w(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300423 __u8 index,
424 __u8 value)
425{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300426 int ret;
427
Marton Nemeth1408b842009-11-02 08:13:21 -0300428 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300429 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300430 usb_sndctrlpipe(gspca_dev->dev, 0),
431 0, /* request */
432 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
433 0, index, gspca_dev->usb_buf, 1,
434 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300435 if (ret < 0)
436 PDEBUG(D_ERR, "reg_w(): "
437 "Failed to write register to index 0x%x, value 0x%x, error %i",
438 index, value, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300439 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300440}
441
Márton Némethb1784b32009-11-07 05:52:02 -0300442static int reg_w_seq(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300443 const __u8 *seq, int len)
444{
Márton Némethb1784b32009-11-07 05:52:02 -0300445 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300446 while (--len >= 0) {
Márton Némethb1784b32009-11-07 05:52:02 -0300447 if (0 <= ret)
448 ret = reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300449 seq += 2;
450 }
Márton Némethb1784b32009-11-07 05:52:02 -0300451 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300452}
453
454/* load the beginning of a page */
Márton Némethb1784b32009-11-07 05:52:02 -0300455static int reg_w_page(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300456 const __u8 *page, int len)
457{
458 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300459 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300460
461 for (index = 0; index < len; index++) {
462 if (page[index] == SKIP) /* skip this index */
463 continue;
464 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300465 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300466 usb_sndctrlpipe(gspca_dev->dev, 0),
467 0, /* request */
468 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
469 0, index, gspca_dev->usb_buf, 1,
470 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300471 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300472 PDEBUG(D_ERR, "reg_w_page(): "
473 "Failed to write register to index 0x%x, "
474 "value 0x%x, error %i",
475 index, page[index], ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300476 break;
477 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300478 }
Márton Némethb1784b32009-11-07 05:52:02 -0300479 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300480}
481
482/* output a variable sequence */
Márton Némethb1784b32009-11-07 05:52:02 -0300483static int reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300484 const __u8 *seq,
485 const __u8 *page3, unsigned int page3_len,
486 const __u8 *page4, unsigned int page4_len)
487{
488 int index, len;
Márton Némethb1784b32009-11-07 05:52:02 -0300489 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300490
491 for (;;) {
492 index = *seq++;
493 len = *seq++;
494 switch (len) {
495 case END_OF_SEQUENCE:
Márton Némethb1784b32009-11-07 05:52:02 -0300496 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300497 case LOAD_PAGE4:
Márton Némethb1784b32009-11-07 05:52:02 -0300498 ret = reg_w_page(gspca_dev, page4, page4_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300499 break;
500 case LOAD_PAGE3:
Márton Némethb1784b32009-11-07 05:52:02 -0300501 ret = reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300502 break;
503 default:
504 if (len > USB_BUF_SZ) {
505 PDEBUG(D_ERR|D_STREAM,
506 "Incorrect variable sequence");
Márton Némethb1784b32009-11-07 05:52:02 -0300507 return -EINVAL;
Marton Nemeth1408b842009-11-02 08:13:21 -0300508 }
509 while (len > 0) {
510 if (len < 8) {
Márton Némethb1784b32009-11-07 05:52:02 -0300511 ret = reg_w_buf(gspca_dev,
512 index, seq, len);
513 if (ret < 0)
514 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300515 seq += len;
516 break;
517 }
Márton Némethb1784b32009-11-07 05:52:02 -0300518 ret = reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300519 seq += 8;
520 index += 8;
521 len -= 8;
522 }
523 }
Márton Némethb1784b32009-11-07 05:52:02 -0300524 if (ret < 0)
525 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300526 }
527 /* not reached */
528}
529
530/* this function is called at probe time for pac7302 */
531static int sd_config(struct gspca_dev *gspca_dev,
532 const struct usb_device_id *id)
533{
534 struct sd *sd = (struct sd *) gspca_dev;
535 struct cam *cam;
536
537 cam = &gspca_dev->cam;
538
539 PDEBUG(D_CONF, "Find Sensor PAC7302");
540 cam->cam_mode = vga_mode; /* only 640x480 */
541 cam->nmodes = ARRAY_SIZE(vga_mode);
542
543 sd->brightness = BRIGHTNESS_DEF;
544 sd->contrast = CONTRAST_DEF;
545 sd->colors = COLOR_DEF;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300546 sd->white_balance = WHITEBALANCE_DEF;
Márton Németh265a8092009-11-07 15:15:56 -0300547 sd->red_balance = REDBALANCE_DEF;
548 sd->blue_balance = BLUEBALANCE_DEF;
Marton Nemeth1408b842009-11-02 08:13:21 -0300549 sd->gain = GAIN_DEF;
550 sd->exposure = EXPOSURE_DEF;
551 sd->autogain = AUTOGAIN_DEF;
552 sd->hflip = HFLIP_DEF;
553 sd->vflip = VFLIP_DEF;
554 return 0;
555}
556
557/* This function is used by pac7302 only */
Márton Némethb1784b32009-11-07 05:52:02 -0300558static int setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300559{
560 struct sd *sd = (struct sd *) gspca_dev;
561 int i, v;
Márton Némethb1784b32009-11-07 05:52:02 -0300562 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300563 static const __u8 max[10] =
564 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
565 0xd4, 0xec};
566 static const __u8 delta[10] =
567 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
568 0x11, 0x0b};
569
Márton Némethb1784b32009-11-07 05:52:02 -0300570 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300571 for (i = 0; i < 10; i++) {
572 v = max[i];
573 v += (sd->brightness - BRIGHTNESS_MAX)
574 * 150 / BRIGHTNESS_MAX; /* 200 ? */
575 v -= delta[i] * sd->contrast / CONTRAST_MAX;
576 if (v < 0)
577 v = 0;
578 else if (v > 0xff)
579 v = 0xff;
Márton Némethb1784b32009-11-07 05:52:02 -0300580 if (0 <= ret)
581 ret = reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300582 }
Márton Némethb1784b32009-11-07 05:52:02 -0300583 if (0 <= ret)
584 ret = reg_w(gspca_dev, 0xdc, 0x01);
585 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300586}
587
588/* This function is used by pac7302 only */
Márton Némethb1784b32009-11-07 05:52:02 -0300589static int setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300590{
591 struct sd *sd = (struct sd *) gspca_dev;
592 int i, v;
Márton Némethb1784b32009-11-07 05:52:02 -0300593 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300594 static const int a[9] =
595 {217, -212, 0, -101, 170, -67, -38, -315, 355};
596 static const int b[9] =
597 {19, 106, 0, 19, 106, 1, 19, 106, 1};
598
Márton Némethb1784b32009-11-07 05:52:02 -0300599 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
600 if (0 <= ret)
601 ret = reg_w(gspca_dev, 0x11, 0x01);
602 if (0 <= ret)
603 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300604 for (i = 0; i < 9; i++) {
605 v = a[i] * sd->colors / COLOR_MAX + b[i];
Márton Némethb1784b32009-11-07 05:52:02 -0300606 if (0 <= ret)
607 ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
608 if (0 <= ret)
609 ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300610 }
Márton Némethb1784b32009-11-07 05:52:02 -0300611 if (0 <= ret)
612 ret = reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300613 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
Márton Némethb1784b32009-11-07 05:52:02 -0300614 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300615}
616
Marton Nemeth23fbee62009-11-08 04:35:12 -0300617static int setwhitebalance(struct gspca_dev *gspca_dev)
618{
619 struct sd *sd = (struct sd *) gspca_dev;
620 int ret;
621
622 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
623 if (0 <= ret)
624 ret = reg_w(gspca_dev, 0xc6, sd->white_balance);
625
626 if (0 <= ret)
627 ret = reg_w(gspca_dev, 0xdc, 0x01);
628 PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
629 return ret;
630}
631
Márton Németh265a8092009-11-07 15:15:56 -0300632static int setredbalance(struct gspca_dev *gspca_dev)
633{
634 struct sd *sd = (struct sd *) gspca_dev;
635 int ret;
636
637 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
638 if (0 <= ret)
639 ret = reg_w(gspca_dev, 0xc5, sd->red_balance);
640
641 if (0 <= ret)
642 ret = reg_w(gspca_dev, 0xdc, 0x01);
643 PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
644 return ret;
645}
646
647static int setbluebalance(struct gspca_dev *gspca_dev)
648{
649 struct sd *sd = (struct sd *) gspca_dev;
650 int ret;
651
652 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
653 if (0 <= ret)
654 ret = reg_w(gspca_dev, 0xc7, sd->blue_balance);
655
656 if (0 <= ret)
657 ret = reg_w(gspca_dev, 0xdc, 0x01);
658 PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
659 return ret;
660}
661
Márton Némethb1784b32009-11-07 05:52:02 -0300662static int setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300663{
664 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300665 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300666
Márton Némethb1784b32009-11-07 05:52:02 -0300667 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
668 if (0 <= ret)
669 ret = reg_w(gspca_dev, 0x10, sd->gain >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300670
671 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300672 if (0 <= ret)
673 ret = reg_w(gspca_dev, 0x11, 0x01);
674 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300675}
676
Márton Némethb1784b32009-11-07 05:52:02 -0300677static int setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300678{
679 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300680 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300681 __u8 reg;
682
683 /* register 2 of frame 3/4 contains the clock divider configuring the
684 no fps according to the formula: 60 / reg. sd->exposure is the
685 desired exposure time in ms. */
686 reg = 120 * sd->exposure / 1000;
687 if (reg < 2)
688 reg = 2;
689 else if (reg > 63)
690 reg = 63;
691
692 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
693 the nearest multiple of 3, except when between 6 and 12? */
694 if (reg < 6 || reg > 12)
695 reg = ((reg + 1) / 3) * 3;
Márton Némethb1784b32009-11-07 05:52:02 -0300696 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
697 if (0 <= ret)
698 ret = reg_w(gspca_dev, 0x02, reg);
Marton Nemeth1408b842009-11-02 08:13:21 -0300699
700 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300701 if (0 <= ret)
702 ret = reg_w(gspca_dev, 0x11, 0x01);
703 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300704}
705
Márton Némethb1784b32009-11-07 05:52:02 -0300706static int sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300707{
708 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300709 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300710 __u8 data;
711
Márton Némethb1784b32009-11-07 05:52:02 -0300712 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300713 data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00);
Márton Némethb1784b32009-11-07 05:52:02 -0300714 if (0 <= ret)
715 ret = reg_w(gspca_dev, 0x21, data);
Marton Nemeth1408b842009-11-02 08:13:21 -0300716 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300717 if (0 <= ret)
718 ret = reg_w(gspca_dev, 0x11, 0x01);
719 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300720}
721
722/* this function is called at probe and resume time for pac7302 */
723static int sd_init(struct gspca_dev *gspca_dev)
724{
Márton Némethb1784b32009-11-07 05:52:02 -0300725 return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
Marton Nemeth1408b842009-11-02 08:13:21 -0300726}
727
728static int sd_start(struct gspca_dev *gspca_dev)
729{
730 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300731 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300732
733 sd->sof_read = 0;
734
Márton Némethb1784b32009-11-07 05:52:02 -0300735 ret = reg_w_var(gspca_dev, start_7302,
Marton Nemeth1408b842009-11-02 08:13:21 -0300736 page3_7302, sizeof(page3_7302),
737 NULL, 0);
Márton Némethb1784b32009-11-07 05:52:02 -0300738 if (0 <= ret)
739 ret = setbrightcont(gspca_dev);
740 if (0 <= ret)
741 ret = setcolors(gspca_dev);
742 if (0 <= ret)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300743 ret = setwhitebalance(gspca_dev);
744 if (0 <= ret)
Márton Németh265a8092009-11-07 15:15:56 -0300745 ret = setredbalance(gspca_dev);
746 if (0 <= ret)
747 ret = setbluebalance(gspca_dev);
748 if (0 <= ret)
Márton Némethb1784b32009-11-07 05:52:02 -0300749 setgain(gspca_dev);
750 if (0 <= ret)
751 setexposure(gspca_dev);
752 if (0 <= ret)
753 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300754
755 /* only resolution 640x480 is supported for pac7302 */
756
757 sd->sof_read = 0;
758 sd->autogain_ignore_frames = 0;
759 atomic_set(&sd->avg_lum, -1);
760
761 /* start stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300762 if (0 <= ret)
763 ret = reg_w(gspca_dev, 0xff, 0x01);
764 if (0 <= ret)
765 ret = reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300766
Márton Némethb1784b32009-11-07 05:52:02 -0300767 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300768}
769
770static void sd_stopN(struct gspca_dev *gspca_dev)
771{
Márton Némethb1784b32009-11-07 05:52:02 -0300772 int ret;
773
Márton Németh67c98f72009-11-07 05:45:33 -0300774 /* stop stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300775 ret = reg_w(gspca_dev, 0xff, 0x01);
776 if (0 <= ret)
777 ret = reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300778}
779
780/* called on streamoff with alt 0 and on disconnect for pac7302 */
781static void sd_stop0(struct gspca_dev *gspca_dev)
782{
Márton Némethb1784b32009-11-07 05:52:02 -0300783 int ret;
784
Marton Nemeth1408b842009-11-02 08:13:21 -0300785 if (!gspca_dev->present)
786 return;
Márton Némethb1784b32009-11-07 05:52:02 -0300787 ret = reg_w(gspca_dev, 0xff, 0x01);
788 if (0 <= ret)
789 ret = reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300790}
791
792/* Include pac common sof detection functions */
793#include "pac_common.h"
794
795static void do_autogain(struct gspca_dev *gspca_dev)
796{
797 struct sd *sd = (struct sd *) gspca_dev;
798 int avg_lum = atomic_read(&sd->avg_lum);
799 int desired_lum, deadzone;
800
801 if (avg_lum == -1)
802 return;
803
804 desired_lum = 270 + sd->brightness * 4;
805 /* Hack hack, with the 7202 the first exposure step is
806 pretty large, so if we're about to make the first
807 exposure increase make the deadzone large to avoid
808 oscilating */
809 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
810 sd->exposure > EXPOSURE_DEF &&
811 sd->exposure < 42)
812 deadzone = 90;
813 else
814 deadzone = 30;
815
816 if (sd->autogain_ignore_frames > 0)
817 sd->autogain_ignore_frames--;
818 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
819 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
820 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
821}
822
823/* JPEG header, part 1 */
824static const unsigned char pac_jpeg_header1[] = {
825 0xff, 0xd8, /* SOI: Start of Image */
826
827 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
828 0x00, 0x11, /* length = 17 bytes (including this length field) */
829 0x08 /* Precision: 8 */
830 /* 2 bytes is placed here: number of image lines */
831 /* 2 bytes is placed here: samples per line */
832};
833
834/* JPEG header, continued */
835static const unsigned char pac_jpeg_header2[] = {
836 0x03, /* Number of image components: 3 */
837 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
838 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
839 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
840
841 0xff, 0xda, /* SOS: Start Of Scan */
842 0x00, 0x0c, /* length = 12 bytes (including this length field) */
843 0x03, /* number of components: 3 */
844 0x01, 0x00, /* selector 1, table 0x00 */
845 0x02, 0x11, /* selector 2, table 0x11 */
846 0x03, 0x11, /* selector 3, table 0x11 */
847 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
848 0x00 /* Successive approximation: 0 */
849};
850
851static void pac_start_frame(struct gspca_dev *gspca_dev,
852 struct gspca_frame *frame,
853 __u16 lines, __u16 samples_per_line)
854{
855 unsigned char tmpbuf[4];
856
857 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
858 pac_jpeg_header1, sizeof(pac_jpeg_header1));
859
860 tmpbuf[0] = lines >> 8;
861 tmpbuf[1] = lines & 0xff;
862 tmpbuf[2] = samples_per_line >> 8;
863 tmpbuf[3] = samples_per_line & 0xff;
864
865 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
866 tmpbuf, sizeof(tmpbuf));
867 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
868 pac_jpeg_header2, sizeof(pac_jpeg_header2));
869}
870
871/* this function is run at interrupt level */
872static void sd_pkt_scan(struct gspca_dev *gspca_dev,
873 struct gspca_frame *frame, /* target */
874 __u8 *data, /* isoc packet */
875 int len) /* iso packet length */
876{
877 struct sd *sd = (struct sd *) gspca_dev;
878 unsigned char *sof;
879
880 sof = pac_find_sof(&sd->sof_read, data, len);
881 if (sof) {
882 int n, lum_offset, footer_length;
883
884 /* 6 bytes after the FF D9 EOF marker a number of lumination
885 bytes are send corresponding to different parts of the
886 image, the 14th and 15th byte after the EOF seem to
887 correspond to the center of the image */
888 lum_offset = 61 + sizeof pac_sof_marker;
889 footer_length = 74;
890
891 /* Finish decoding current frame */
892 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
893 if (n < 0) {
894 frame->data_end += n;
895 n = 0;
896 }
897 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
898 data, n);
899 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
900 frame->data_end[-2] == 0xff &&
901 frame->data_end[-1] == 0xd9)
902 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
903 NULL, 0);
904
905 n = sof - data;
906 len -= n;
907 data = sof;
908
909 /* Get average lumination */
910 if (gspca_dev->last_packet_type == LAST_PACKET &&
911 n >= lum_offset)
912 atomic_set(&sd->avg_lum, data[-lum_offset] +
913 data[-lum_offset + 1]);
914 else
915 atomic_set(&sd->avg_lum, -1);
916
917 /* Start the new frame with the jpeg header */
918 /* The PAC7302 has the image rotated 90 degrees */
919 pac_start_frame(gspca_dev, frame,
920 gspca_dev->width, gspca_dev->height);
921 }
922 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
923}
924
925static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
926{
927 struct sd *sd = (struct sd *) gspca_dev;
928
929 sd->brightness = val;
930 if (gspca_dev->streaming)
931 setbrightcont(gspca_dev);
932 return 0;
933}
934
935static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
936{
937 struct sd *sd = (struct sd *) gspca_dev;
938
939 *val = sd->brightness;
940 return 0;
941}
942
943static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
944{
945 struct sd *sd = (struct sd *) gspca_dev;
946
947 sd->contrast = val;
948 if (gspca_dev->streaming) {
949 setbrightcont(gspca_dev);
950 }
951 return 0;
952}
953
954static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
955{
956 struct sd *sd = (struct sd *) gspca_dev;
957
958 *val = sd->contrast;
959 return 0;
960}
961
962static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
963{
964 struct sd *sd = (struct sd *) gspca_dev;
965
966 sd->colors = val;
967 if (gspca_dev->streaming)
968 setcolors(gspca_dev);
969 return 0;
970}
971
972static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
973{
974 struct sd *sd = (struct sd *) gspca_dev;
975
976 *val = sd->colors;
977 return 0;
978}
979
Marton Nemeth23fbee62009-11-08 04:35:12 -0300980static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
981{
982 struct sd *sd = (struct sd *) gspca_dev;
983 int ret = 0;
984
985 sd->white_balance = val;
986 if (gspca_dev->streaming)
987 ret = setwhitebalance(gspca_dev);
988 if (0 <= ret)
989 ret = 0;
990 return ret;
991}
992
993static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
994{
995 struct sd *sd = (struct sd *) gspca_dev;
996
997 *val = sd->white_balance;
998 return 0;
999}
1000
Márton Németh265a8092009-11-07 15:15:56 -03001001static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
1002{
1003 struct sd *sd = (struct sd *) gspca_dev;
1004 int ret = 0;
1005
1006 sd->red_balance = val;
1007 if (gspca_dev->streaming)
1008 ret = setredbalance(gspca_dev);
1009 if (0 <= ret)
1010 ret = 0;
1011 return ret;
1012}
1013
1014static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
1015{
1016 struct sd *sd = (struct sd *) gspca_dev;
1017
1018 *val = sd->red_balance;
1019 return 0;
1020}
1021
1022static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
1023{
1024 struct sd *sd = (struct sd *) gspca_dev;
1025 int ret = 0;
1026
1027 sd->blue_balance = val;
1028 if (gspca_dev->streaming)
1029 ret = setbluebalance(gspca_dev);
1030 if (0 <= ret)
1031 ret = 0;
1032 return ret;
1033}
1034
1035static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
1036{
1037 struct sd *sd = (struct sd *) gspca_dev;
1038
1039 *val = sd->blue_balance;
1040 return 0;
1041}
1042
Marton Nemeth1408b842009-11-02 08:13:21 -03001043static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1044{
1045 struct sd *sd = (struct sd *) gspca_dev;
1046
1047 sd->gain = val;
1048 if (gspca_dev->streaming)
1049 setgain(gspca_dev);
1050 return 0;
1051}
1052
1053static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1054{
1055 struct sd *sd = (struct sd *) gspca_dev;
1056
1057 *val = sd->gain;
1058 return 0;
1059}
1060
1061static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1062{
1063 struct sd *sd = (struct sd *) gspca_dev;
1064
1065 sd->exposure = val;
1066 if (gspca_dev->streaming)
1067 setexposure(gspca_dev);
1068 return 0;
1069}
1070
1071static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1072{
1073 struct sd *sd = (struct sd *) gspca_dev;
1074
1075 *val = sd->exposure;
1076 return 0;
1077}
1078
1079static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1080{
1081 struct sd *sd = (struct sd *) gspca_dev;
1082
1083 sd->autogain = val;
1084 /* when switching to autogain set defaults to make sure
1085 we are on a valid point of the autogain gain /
1086 exposure knee graph, and give this change time to
1087 take effect before doing autogain. */
1088 if (sd->autogain) {
1089 sd->exposure = EXPOSURE_DEF;
1090 sd->gain = GAIN_DEF;
1091 if (gspca_dev->streaming) {
1092 sd->autogain_ignore_frames =
1093 PAC_AUTOGAIN_IGNORE_FRAMES;
1094 setexposure(gspca_dev);
1095 setgain(gspca_dev);
1096 }
1097 }
1098
1099 return 0;
1100}
1101
1102static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1103{
1104 struct sd *sd = (struct sd *) gspca_dev;
1105
1106 *val = sd->autogain;
1107 return 0;
1108}
1109
1110static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1111{
1112 struct sd *sd = (struct sd *) gspca_dev;
1113
1114 sd->hflip = val;
1115 if (gspca_dev->streaming)
1116 sethvflip(gspca_dev);
1117 return 0;
1118}
1119
1120static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1121{
1122 struct sd *sd = (struct sd *) gspca_dev;
1123
1124 *val = sd->hflip;
1125 return 0;
1126}
1127
1128static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1129{
1130 struct sd *sd = (struct sd *) gspca_dev;
1131
1132 sd->vflip = val;
1133 if (gspca_dev->streaming)
1134 sethvflip(gspca_dev);
1135 return 0;
1136}
1137
1138static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1139{
1140 struct sd *sd = (struct sd *) gspca_dev;
1141
1142 *val = sd->vflip;
1143 return 0;
1144}
1145
1146/* sub-driver description for pac7302 */
1147static struct sd_desc sd_desc = {
1148 .name = MODULE_NAME,
1149 .ctrls = sd_ctrls,
1150 .nctrls = ARRAY_SIZE(sd_ctrls),
1151 .config = sd_config,
1152 .init = sd_init,
1153 .start = sd_start,
1154 .stopN = sd_stopN,
1155 .stop0 = sd_stop0,
1156 .pkt_scan = sd_pkt_scan,
1157 .dq_callback = do_autogain,
1158};
1159
1160/* -- module initialisation -- */
1161static __devinitdata struct usb_device_id device_table[] = {
1162 {USB_DEVICE(0x06f8, 0x3009)},
1163 {USB_DEVICE(0x093a, 0x2620)},
1164 {USB_DEVICE(0x093a, 0x2621)},
1165 {USB_DEVICE(0x093a, 0x2622)},
1166 {USB_DEVICE(0x093a, 0x2624)},
1167 {USB_DEVICE(0x093a, 0x2626)},
1168 {USB_DEVICE(0x093a, 0x2628)},
1169 {USB_DEVICE(0x093a, 0x2629)},
1170 {USB_DEVICE(0x093a, 0x262a)},
1171 {USB_DEVICE(0x093a, 0x262c)},
1172 {}
1173};
1174MODULE_DEVICE_TABLE(usb, device_table);
1175
1176/* -- device connect -- */
1177static int sd_probe(struct usb_interface *intf,
1178 const struct usb_device_id *id)
1179{
1180 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1181 THIS_MODULE);
1182}
1183
1184static struct usb_driver sd_driver = {
1185 .name = MODULE_NAME,
1186 .id_table = device_table,
1187 .probe = sd_probe,
1188 .disconnect = gspca_disconnect,
1189#ifdef CONFIG_PM
1190 .suspend = gspca_suspend,
1191 .resume = gspca_resume,
1192#endif
1193};
1194
1195/* -- module insert / remove -- */
1196static int __init sd_mod_init(void)
1197{
1198 int ret;
1199 ret = usb_register(&sd_driver);
1200 if (ret < 0)
1201 return ret;
1202 PDEBUG(D_PROBE, "registered");
1203 return 0;
1204}
1205static void __exit sd_mod_exit(void)
1206{
1207 usb_deregister(&sd_driver);
1208 PDEBUG(D_PROBE, "deregistered");
1209}
1210
1211module_init(sd_mod_init);
1212module_exit(sd_mod_exit);