blob: 336d97ddf54e2ffa5c9e39e9f1ac46fe9d14df0f [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
Márton Németh6763cc02009-11-09 07:10:46 -030071#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030072#include "gspca.h"
73
74MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
75MODULE_DESCRIPTION("Pixart PAC7302");
76MODULE_LICENSE("GPL");
77
78/* specific webcam descriptor for pac7302 */
79struct sd {
80 struct gspca_dev gspca_dev; /* !! must be the first item */
81
82 unsigned char brightness;
83 unsigned char contrast;
84 unsigned char colors;
Marton Nemeth23fbee62009-11-08 04:35:12 -030085 unsigned char white_balance;
Márton Németh265a8092009-11-07 15:15:56 -030086 unsigned char red_balance;
87 unsigned char blue_balance;
Marton Nemeth1408b842009-11-02 08:13:21 -030088 unsigned char gain;
89 unsigned char exposure;
90 unsigned char autogain;
91 __u8 hflip;
92 __u8 vflip;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -030093 u8 flags;
94#define FL_HFLIP 0x01 /* mirrored by default */
95#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -030096
97 u8 sof_read;
98 u8 autogain_ignore_frames;
99
100 atomic_t avg_lum;
101};
102
103/* V4L2 controls supported by the driver */
104static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
105static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
106static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
107static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
108static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
109static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300110static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
111static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
Márton Németh265a8092009-11-07 15:15:56 -0300112static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
113static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
114static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300116static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
117static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
118static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
120static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
122static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
123static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
124static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
125static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
126
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300127static const struct ctrl sd_ctrls[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300128/* This control is pac7302 only */
129 {
130 {
131 .id = V4L2_CID_BRIGHTNESS,
132 .type = V4L2_CTRL_TYPE_INTEGER,
133 .name = "Brightness",
134 .minimum = 0,
135#define BRIGHTNESS_MAX 0x20
136 .maximum = BRIGHTNESS_MAX,
137 .step = 1,
138#define BRIGHTNESS_DEF 0x10
139 .default_value = BRIGHTNESS_DEF,
140 },
141 .set = sd_setbrightness,
142 .get = sd_getbrightness,
143 },
144/* This control is for both the 7302 and the 7311 */
145 {
146 {
147 .id = V4L2_CID_CONTRAST,
148 .type = V4L2_CTRL_TYPE_INTEGER,
149 .name = "Contrast",
150 .minimum = 0,
151#define CONTRAST_MAX 255
152 .maximum = CONTRAST_MAX,
153 .step = 1,
154#define CONTRAST_DEF 127
155 .default_value = CONTRAST_DEF,
156 },
157 .set = sd_setcontrast,
158 .get = sd_getcontrast,
159 },
160/* This control is pac7302 only */
161 {
162 {
163 .id = V4L2_CID_SATURATION,
164 .type = V4L2_CTRL_TYPE_INTEGER,
165 .name = "Saturation",
166 .minimum = 0,
167#define COLOR_MAX 255
168 .maximum = COLOR_MAX,
169 .step = 1,
170#define COLOR_DEF 127
171 .default_value = COLOR_DEF,
172 },
173 .set = sd_setcolors,
174 .get = sd_getcolors,
175 },
Márton Németh265a8092009-11-07 15:15:56 -0300176 {
177 {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300178 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
179 .type = V4L2_CTRL_TYPE_INTEGER,
180 .name = "White Balance",
181 .minimum = 0,
182 .maximum = 255,
183 .step = 1,
184#define WHITEBALANCE_DEF 4
185 .default_value = WHITEBALANCE_DEF,
186 },
187 .set = sd_setwhitebalance,
188 .get = sd_getwhitebalance,
189 },
190 {
191 {
Márton Németh265a8092009-11-07 15:15:56 -0300192 .id = V4L2_CID_RED_BALANCE,
193 .type = V4L2_CTRL_TYPE_INTEGER,
194 .name = "Red",
195 .minimum = 0,
196 .maximum = 3,
197 .step = 1,
198#define REDBALANCE_DEF 1
199 .default_value = REDBALANCE_DEF,
200 },
201 .set = sd_setredbalance,
202 .get = sd_getredbalance,
203 },
204 {
205 {
206 .id = V4L2_CID_BLUE_BALANCE,
207 .type = V4L2_CTRL_TYPE_INTEGER,
208 .name = "Blue",
209 .minimum = 0,
210 .maximum = 3,
211 .step = 1,
212#define BLUEBALANCE_DEF 1
213 .default_value = BLUEBALANCE_DEF,
214 },
215 .set = sd_setbluebalance,
216 .get = sd_getbluebalance,
217 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300218/* All controls below are for both the 7302 and the 7311 */
219 {
220 {
221 .id = V4L2_CID_GAIN,
222 .type = V4L2_CTRL_TYPE_INTEGER,
223 .name = "Gain",
224 .minimum = 0,
225#define GAIN_MAX 255
226 .maximum = GAIN_MAX,
227 .step = 1,
228#define GAIN_DEF 127
229#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
230 .default_value = GAIN_DEF,
231 },
232 .set = sd_setgain,
233 .get = sd_getgain,
234 },
235 {
236 {
237 .id = V4L2_CID_EXPOSURE,
238 .type = V4L2_CTRL_TYPE_INTEGER,
239 .name = "Exposure",
240 .minimum = 0,
241#define EXPOSURE_MAX 255
242 .maximum = EXPOSURE_MAX,
243 .step = 1,
244#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
245#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
246 .default_value = EXPOSURE_DEF,
247 },
248 .set = sd_setexposure,
249 .get = sd_getexposure,
250 },
251 {
252 {
253 .id = V4L2_CID_AUTOGAIN,
254 .type = V4L2_CTRL_TYPE_BOOLEAN,
255 .name = "Auto Gain",
256 .minimum = 0,
257 .maximum = 1,
258 .step = 1,
259#define AUTOGAIN_DEF 1
260 .default_value = AUTOGAIN_DEF,
261 },
262 .set = sd_setautogain,
263 .get = sd_getautogain,
264 },
265 {
266 {
267 .id = V4L2_CID_HFLIP,
268 .type = V4L2_CTRL_TYPE_BOOLEAN,
269 .name = "Mirror",
270 .minimum = 0,
271 .maximum = 1,
272 .step = 1,
273#define HFLIP_DEF 0
274 .default_value = HFLIP_DEF,
275 },
276 .set = sd_sethflip,
277 .get = sd_gethflip,
278 },
279 {
280 {
281 .id = V4L2_CID_VFLIP,
282 .type = V4L2_CTRL_TYPE_BOOLEAN,
283 .name = "Vflip",
284 .minimum = 0,
285 .maximum = 1,
286 .step = 1,
287#define VFLIP_DEF 0
288 .default_value = VFLIP_DEF,
289 },
290 .set = sd_setvflip,
291 .get = sd_getvflip,
292 },
293};
294
295static const struct v4l2_pix_format vga_mode[] = {
296 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
297 .bytesperline = 640,
298 .sizeimage = 640 * 480 * 3 / 8 + 590,
299 .colorspace = V4L2_COLORSPACE_JPEG,
300 .priv = 0},
301};
302
303#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300304#define END_OF_SEQUENCE 0
305
306/* pac 7302 */
307static const __u8 init_7302[] = {
308/* index,value */
309 0xff, 0x01, /* page 1 */
310 0x78, 0x00, /* deactivate */
311 0xff, 0x01,
312 0x78, 0x40, /* led off */
313};
314static const __u8 start_7302[] = {
315/* index, len, [value]* */
316 0xff, 1, 0x00, /* page 0 */
317 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
318 0x00, 0x00, 0x00, 0x00,
319 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
320 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
321 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
322 0x26, 2, 0xaa, 0xaa,
323 0x2e, 1, 0x31,
324 0x38, 1, 0x01,
325 0x3a, 3, 0x14, 0xff, 0x5a,
326 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
327 0x00, 0x54, 0x11,
328 0x55, 1, 0x00,
329 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
330 0x6b, 1, 0x00,
331 0x6e, 3, 0x08, 0x06, 0x00,
332 0x72, 3, 0x00, 0xff, 0x00,
333 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
334 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
335 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
336 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
337 0xd2, 0xeb,
338 0xaf, 1, 0x02,
339 0xb5, 2, 0x08, 0x08,
340 0xb8, 2, 0x08, 0x88,
341 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
342 0xcc, 1, 0x00,
343 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
344 0xc1, 0xd7, 0xec,
345 0xdc, 1, 0x01,
346 0xff, 1, 0x01, /* page 1 */
347 0x12, 3, 0x02, 0x00, 0x01,
348 0x3e, 2, 0x00, 0x00,
349 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
350 0x7c, 1, 0x00,
351 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
352 0x02, 0x00,
353 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
354 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
355 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
356 0xd8, 1, 0x01,
357 0xdb, 2, 0x00, 0x01,
358 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
359 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
360 0xeb, 1, 0x00,
361 0xff, 1, 0x02, /* page 2 */
362 0x22, 1, 0x00,
363 0xff, 1, 0x03, /* page 3 */
364 0, LOAD_PAGE3, /* load the page 3 */
365 0x11, 1, 0x01,
366 0xff, 1, 0x02, /* page 2 */
367 0x13, 1, 0x00,
368 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
369 0x27, 2, 0x14, 0x0c,
370 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
371 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
372 0x6e, 1, 0x08,
373 0xff, 1, 0x01, /* page 1 */
374 0x78, 1, 0x00,
375 0, END_OF_SEQUENCE /* end of sequence */
376};
377
378#define SKIP 0xaa
379/* page 3 - the value SKIP says skip the index - see reg_w_page() */
380static const __u8 page3_7302[] = {
381 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
382 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
383 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
385 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
386 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
387 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
388 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300390 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300391 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
395 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
396 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
397 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
400 0x00
401};
402
Márton Némethb1784b32009-11-07 05:52:02 -0300403static int reg_w_buf(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300404 __u8 index,
405 const char *buffer, int len)
406{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300407 int ret;
408
Marton Nemeth1408b842009-11-02 08:13:21 -0300409 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300410 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300411 usb_sndctrlpipe(gspca_dev->dev, 0),
412 1, /* request */
413 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
414 0, /* value */
415 index, gspca_dev->usb_buf, len,
416 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300417 if (ret < 0)
418 PDEBUG(D_ERR, "reg_w_buf(): "
419 "Failed to write registers to index 0x%x, error %i",
420 index, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300421 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300422}
423
424
Márton Némethb1784b32009-11-07 05:52:02 -0300425static int reg_w(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300426 __u8 index,
427 __u8 value)
428{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300429 int ret;
430
Marton Nemeth1408b842009-11-02 08:13:21 -0300431 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300432 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300433 usb_sndctrlpipe(gspca_dev->dev, 0),
434 0, /* request */
435 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
436 0, index, gspca_dev->usb_buf, 1,
437 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300438 if (ret < 0)
439 PDEBUG(D_ERR, "reg_w(): "
440 "Failed to write register to index 0x%x, value 0x%x, error %i",
441 index, value, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300442 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300443}
444
Márton Némethb1784b32009-11-07 05:52:02 -0300445static int reg_w_seq(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300446 const __u8 *seq, int len)
447{
Márton Némethb1784b32009-11-07 05:52:02 -0300448 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300449 while (--len >= 0) {
Márton Némethb1784b32009-11-07 05:52:02 -0300450 if (0 <= ret)
451 ret = reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300452 seq += 2;
453 }
Márton Némethb1784b32009-11-07 05:52:02 -0300454 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300455}
456
457/* load the beginning of a page */
Márton Némethb1784b32009-11-07 05:52:02 -0300458static int reg_w_page(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300459 const __u8 *page, int len)
460{
461 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300462 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300463
464 for (index = 0; index < len; index++) {
465 if (page[index] == SKIP) /* skip this index */
466 continue;
467 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300468 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300469 usb_sndctrlpipe(gspca_dev->dev, 0),
470 0, /* request */
471 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
472 0, index, gspca_dev->usb_buf, 1,
473 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300474 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300475 PDEBUG(D_ERR, "reg_w_page(): "
476 "Failed to write register to index 0x%x, "
477 "value 0x%x, error %i",
478 index, page[index], ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300479 break;
480 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300481 }
Márton Némethb1784b32009-11-07 05:52:02 -0300482 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300483}
484
485/* output a variable sequence */
Márton Némethb1784b32009-11-07 05:52:02 -0300486static int reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300487 const __u8 *seq,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300488 const __u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300489{
490 int index, len;
Márton Némethb1784b32009-11-07 05:52:02 -0300491 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300492
493 for (;;) {
494 index = *seq++;
495 len = *seq++;
496 switch (len) {
497 case END_OF_SEQUENCE:
Márton Némethb1784b32009-11-07 05:52:02 -0300498 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300499 case LOAD_PAGE3:
Márton Némethb1784b32009-11-07 05:52:02 -0300500 ret = reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300501 break;
502 default:
503 if (len > USB_BUF_SZ) {
504 PDEBUG(D_ERR|D_STREAM,
505 "Incorrect variable sequence");
Márton Némethb1784b32009-11-07 05:52:02 -0300506 return -EINVAL;
Marton Nemeth1408b842009-11-02 08:13:21 -0300507 }
508 while (len > 0) {
509 if (len < 8) {
Márton Némethb1784b32009-11-07 05:52:02 -0300510 ret = reg_w_buf(gspca_dev,
511 index, seq, len);
512 if (ret < 0)
513 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300514 seq += len;
515 break;
516 }
Márton Némethb1784b32009-11-07 05:52:02 -0300517 ret = reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300518 seq += 8;
519 index += 8;
520 len -= 8;
521 }
522 }
Márton Némethb1784b32009-11-07 05:52:02 -0300523 if (ret < 0)
524 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300525 }
526 /* not reached */
527}
528
529/* this function is called at probe time for pac7302 */
530static int sd_config(struct gspca_dev *gspca_dev,
531 const struct usb_device_id *id)
532{
533 struct sd *sd = (struct sd *) gspca_dev;
534 struct cam *cam;
535
536 cam = &gspca_dev->cam;
537
538 PDEBUG(D_CONF, "Find Sensor PAC7302");
539 cam->cam_mode = vga_mode; /* only 640x480 */
540 cam->nmodes = ARRAY_SIZE(vga_mode);
541
542 sd->brightness = BRIGHTNESS_DEF;
543 sd->contrast = CONTRAST_DEF;
544 sd->colors = COLOR_DEF;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300545 sd->white_balance = WHITEBALANCE_DEF;
Márton Németh265a8092009-11-07 15:15:56 -0300546 sd->red_balance = REDBALANCE_DEF;
547 sd->blue_balance = BLUEBALANCE_DEF;
Marton Nemeth1408b842009-11-02 08:13:21 -0300548 sd->gain = GAIN_DEF;
549 sd->exposure = EXPOSURE_DEF;
550 sd->autogain = AUTOGAIN_DEF;
551 sd->hflip = HFLIP_DEF;
552 sd->vflip = VFLIP_DEF;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300553 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300554 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;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300710 u8 data, hflip, vflip;
711
712 hflip = sd->hflip;
713 if (sd->flags & FL_HFLIP)
714 hflip = !hflip;
715 vflip = sd->vflip;
716 if (sd->flags & FL_VFLIP)
717 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300718
Márton Némethb1784b32009-11-07 05:52:02 -0300719 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300720 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Márton Némethb1784b32009-11-07 05:52:02 -0300721 if (0 <= ret)
722 ret = reg_w(gspca_dev, 0x21, data);
Marton Nemeth1408b842009-11-02 08:13:21 -0300723 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300724 if (0 <= ret)
725 ret = reg_w(gspca_dev, 0x11, 0x01);
726 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300727}
728
729/* this function is called at probe and resume time for pac7302 */
730static int sd_init(struct gspca_dev *gspca_dev)
731{
Márton Némethb1784b32009-11-07 05:52:02 -0300732 return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
Marton Nemeth1408b842009-11-02 08:13:21 -0300733}
734
735static int sd_start(struct gspca_dev *gspca_dev)
736{
737 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300738 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300739
740 sd->sof_read = 0;
741
Márton Némethb1784b32009-11-07 05:52:02 -0300742 ret = reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300743 page3_7302, sizeof(page3_7302));
Márton Némethb1784b32009-11-07 05:52:02 -0300744 if (0 <= ret)
745 ret = setbrightcont(gspca_dev);
746 if (0 <= ret)
747 ret = setcolors(gspca_dev);
748 if (0 <= ret)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300749 ret = setwhitebalance(gspca_dev);
750 if (0 <= ret)
Márton Németh265a8092009-11-07 15:15:56 -0300751 ret = setredbalance(gspca_dev);
752 if (0 <= ret)
753 ret = setbluebalance(gspca_dev);
754 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300755 ret = setgain(gspca_dev);
Márton Némethb1784b32009-11-07 05:52:02 -0300756 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300757 ret = setexposure(gspca_dev);
Márton Némethb1784b32009-11-07 05:52:02 -0300758 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300759 ret = sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300760
761 /* only resolution 640x480 is supported for pac7302 */
762
763 sd->sof_read = 0;
764 sd->autogain_ignore_frames = 0;
765 atomic_set(&sd->avg_lum, -1);
766
767 /* start stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300768 if (0 <= ret)
769 ret = reg_w(gspca_dev, 0xff, 0x01);
770 if (0 <= ret)
771 ret = reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300772
Márton Némethb1784b32009-11-07 05:52:02 -0300773 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300774}
775
776static void sd_stopN(struct gspca_dev *gspca_dev)
777{
Márton Némethb1784b32009-11-07 05:52:02 -0300778 int ret;
779
Márton Németh67c98f72009-11-07 05:45:33 -0300780 /* stop stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300781 ret = reg_w(gspca_dev, 0xff, 0x01);
782 if (0 <= ret)
783 ret = reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300784}
785
786/* called on streamoff with alt 0 and on disconnect for pac7302 */
787static void sd_stop0(struct gspca_dev *gspca_dev)
788{
Márton Némethb1784b32009-11-07 05:52:02 -0300789 int ret;
790
Marton Nemeth1408b842009-11-02 08:13:21 -0300791 if (!gspca_dev->present)
792 return;
Márton Némethb1784b32009-11-07 05:52:02 -0300793 ret = reg_w(gspca_dev, 0xff, 0x01);
794 if (0 <= ret)
795 ret = reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300796}
797
798/* Include pac common sof detection functions */
799#include "pac_common.h"
800
801static void do_autogain(struct gspca_dev *gspca_dev)
802{
803 struct sd *sd = (struct sd *) gspca_dev;
804 int avg_lum = atomic_read(&sd->avg_lum);
805 int desired_lum, deadzone;
806
807 if (avg_lum == -1)
808 return;
809
810 desired_lum = 270 + sd->brightness * 4;
811 /* Hack hack, with the 7202 the first exposure step is
812 pretty large, so if we're about to make the first
813 exposure increase make the deadzone large to avoid
814 oscilating */
815 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
816 sd->exposure > EXPOSURE_DEF &&
817 sd->exposure < 42)
818 deadzone = 90;
819 else
820 deadzone = 30;
821
822 if (sd->autogain_ignore_frames > 0)
823 sd->autogain_ignore_frames--;
824 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
825 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
826 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
827}
828
829/* JPEG header, part 1 */
830static const unsigned char pac_jpeg_header1[] = {
831 0xff, 0xd8, /* SOI: Start of Image */
832
833 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
834 0x00, 0x11, /* length = 17 bytes (including this length field) */
835 0x08 /* Precision: 8 */
836 /* 2 bytes is placed here: number of image lines */
837 /* 2 bytes is placed here: samples per line */
838};
839
840/* JPEG header, continued */
841static const unsigned char pac_jpeg_header2[] = {
842 0x03, /* Number of image components: 3 */
843 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
844 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
845 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
846
847 0xff, 0xda, /* SOS: Start Of Scan */
848 0x00, 0x0c, /* length = 12 bytes (including this length field) */
849 0x03, /* number of components: 3 */
850 0x01, 0x00, /* selector 1, table 0x00 */
851 0x02, 0x11, /* selector 2, table 0x11 */
852 0x03, 0x11, /* selector 3, table 0x11 */
853 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
854 0x00 /* Successive approximation: 0 */
855};
856
857static void pac_start_frame(struct gspca_dev *gspca_dev,
858 struct gspca_frame *frame,
859 __u16 lines, __u16 samples_per_line)
860{
861 unsigned char tmpbuf[4];
862
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300863 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300864 pac_jpeg_header1, sizeof(pac_jpeg_header1));
865
866 tmpbuf[0] = lines >> 8;
867 tmpbuf[1] = lines & 0xff;
868 tmpbuf[2] = samples_per_line >> 8;
869 tmpbuf[3] = samples_per_line & 0xff;
870
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300871 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300872 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300873 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300874 pac_jpeg_header2, sizeof(pac_jpeg_header2));
875}
876
877/* this function is run at interrupt level */
878static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300879 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300880 int len) /* iso packet length */
881{
882 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300883 struct gspca_frame *frame;
Marton Nemeth1408b842009-11-02 08:13:21 -0300884 unsigned char *sof;
885
886 sof = pac_find_sof(&sd->sof_read, data, len);
887 if (sof) {
888 int n, lum_offset, footer_length;
889
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300890 frame = gspca_get_i_frame(gspca_dev);
891 if (frame == NULL) {
892 gspca_dev->last_packet_type = DISCARD_PACKET;
893 return;
894 }
895
Marton Nemeth1408b842009-11-02 08:13:21 -0300896 /* 6 bytes after the FF D9 EOF marker a number of lumination
897 bytes are send corresponding to different parts of the
898 image, the 14th and 15th byte after the EOF seem to
899 correspond to the center of the image */
900 lum_offset = 61 + sizeof pac_sof_marker;
901 footer_length = 74;
902
903 /* Finish decoding current frame */
904 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
905 if (n < 0) {
906 frame->data_end += n;
907 n = 0;
908 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300909 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300910 data, n);
911 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
912 frame->data_end[-2] == 0xff &&
913 frame->data_end[-1] == 0xd9)
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300914 gspca_frame_add(gspca_dev, LAST_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300915 NULL, 0);
916
917 n = sof - data;
918 len -= n;
919 data = sof;
920
921 /* Get average lumination */
922 if (gspca_dev->last_packet_type == LAST_PACKET &&
923 n >= lum_offset)
924 atomic_set(&sd->avg_lum, data[-lum_offset] +
925 data[-lum_offset + 1]);
926 else
927 atomic_set(&sd->avg_lum, -1);
928
929 /* Start the new frame with the jpeg header */
930 /* The PAC7302 has the image rotated 90 degrees */
931 pac_start_frame(gspca_dev, frame,
932 gspca_dev->width, gspca_dev->height);
933 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300934 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300935}
936
937static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
938{
939 struct sd *sd = (struct sd *) gspca_dev;
940
941 sd->brightness = val;
942 if (gspca_dev->streaming)
943 setbrightcont(gspca_dev);
944 return 0;
945}
946
947static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
948{
949 struct sd *sd = (struct sd *) gspca_dev;
950
951 *val = sd->brightness;
952 return 0;
953}
954
955static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
956{
957 struct sd *sd = (struct sd *) gspca_dev;
958
959 sd->contrast = val;
960 if (gspca_dev->streaming) {
961 setbrightcont(gspca_dev);
962 }
963 return 0;
964}
965
966static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
967{
968 struct sd *sd = (struct sd *) gspca_dev;
969
970 *val = sd->contrast;
971 return 0;
972}
973
974static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
975{
976 struct sd *sd = (struct sd *) gspca_dev;
977
978 sd->colors = val;
979 if (gspca_dev->streaming)
980 setcolors(gspca_dev);
981 return 0;
982}
983
984static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
985{
986 struct sd *sd = (struct sd *) gspca_dev;
987
988 *val = sd->colors;
989 return 0;
990}
991
Marton Nemeth23fbee62009-11-08 04:35:12 -0300992static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
993{
994 struct sd *sd = (struct sd *) gspca_dev;
995 int ret = 0;
996
997 sd->white_balance = val;
998 if (gspca_dev->streaming)
999 ret = setwhitebalance(gspca_dev);
1000 if (0 <= ret)
1001 ret = 0;
1002 return ret;
1003}
1004
1005static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
1006{
1007 struct sd *sd = (struct sd *) gspca_dev;
1008
1009 *val = sd->white_balance;
1010 return 0;
1011}
1012
Márton Németh265a8092009-11-07 15:15:56 -03001013static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
1014{
1015 struct sd *sd = (struct sd *) gspca_dev;
1016 int ret = 0;
1017
1018 sd->red_balance = val;
1019 if (gspca_dev->streaming)
1020 ret = setredbalance(gspca_dev);
1021 if (0 <= ret)
1022 ret = 0;
1023 return ret;
1024}
1025
1026static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
1027{
1028 struct sd *sd = (struct sd *) gspca_dev;
1029
1030 *val = sd->red_balance;
1031 return 0;
1032}
1033
1034static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
1035{
1036 struct sd *sd = (struct sd *) gspca_dev;
1037 int ret = 0;
1038
1039 sd->blue_balance = val;
1040 if (gspca_dev->streaming)
1041 ret = setbluebalance(gspca_dev);
1042 if (0 <= ret)
1043 ret = 0;
1044 return ret;
1045}
1046
1047static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
1048{
1049 struct sd *sd = (struct sd *) gspca_dev;
1050
1051 *val = sd->blue_balance;
1052 return 0;
1053}
1054
Marton Nemeth1408b842009-11-02 08:13:21 -03001055static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1056{
1057 struct sd *sd = (struct sd *) gspca_dev;
1058
1059 sd->gain = val;
1060 if (gspca_dev->streaming)
1061 setgain(gspca_dev);
1062 return 0;
1063}
1064
1065static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1066{
1067 struct sd *sd = (struct sd *) gspca_dev;
1068
1069 *val = sd->gain;
1070 return 0;
1071}
1072
1073static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1074{
1075 struct sd *sd = (struct sd *) gspca_dev;
1076
1077 sd->exposure = val;
1078 if (gspca_dev->streaming)
1079 setexposure(gspca_dev);
1080 return 0;
1081}
1082
1083static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1084{
1085 struct sd *sd = (struct sd *) gspca_dev;
1086
1087 *val = sd->exposure;
1088 return 0;
1089}
1090
1091static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1092{
1093 struct sd *sd = (struct sd *) gspca_dev;
1094
1095 sd->autogain = val;
1096 /* when switching to autogain set defaults to make sure
1097 we are on a valid point of the autogain gain /
1098 exposure knee graph, and give this change time to
1099 take effect before doing autogain. */
1100 if (sd->autogain) {
1101 sd->exposure = EXPOSURE_DEF;
1102 sd->gain = GAIN_DEF;
1103 if (gspca_dev->streaming) {
1104 sd->autogain_ignore_frames =
1105 PAC_AUTOGAIN_IGNORE_FRAMES;
1106 setexposure(gspca_dev);
1107 setgain(gspca_dev);
1108 }
1109 }
1110
1111 return 0;
1112}
1113
1114static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1115{
1116 struct sd *sd = (struct sd *) gspca_dev;
1117
1118 *val = sd->autogain;
1119 return 0;
1120}
1121
1122static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1123{
1124 struct sd *sd = (struct sd *) gspca_dev;
1125
1126 sd->hflip = val;
1127 if (gspca_dev->streaming)
1128 sethvflip(gspca_dev);
1129 return 0;
1130}
1131
1132static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1133{
1134 struct sd *sd = (struct sd *) gspca_dev;
1135
1136 *val = sd->hflip;
1137 return 0;
1138}
1139
1140static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1141{
1142 struct sd *sd = (struct sd *) gspca_dev;
1143
1144 sd->vflip = val;
1145 if (gspca_dev->streaming)
1146 sethvflip(gspca_dev);
1147 return 0;
1148}
1149
1150static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1151{
1152 struct sd *sd = (struct sd *) gspca_dev;
1153
1154 *val = sd->vflip;
1155 return 0;
1156}
1157
Márton Németh6763cc02009-11-09 07:10:46 -03001158#ifdef CONFIG_VIDEO_ADV_DEBUG
1159static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1160 struct v4l2_dbg_register *reg)
1161{
1162 int ret = -EINVAL;
1163 __u8 index;
1164 __u8 value;
1165
1166 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
1167 long on the USB bus)
1168 */
1169 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
1170 reg->match.addr == 0 &&
1171 (reg->reg < 0x000000ff) &&
1172 (reg->val <= 0x000000ff)
1173 ) {
1174 /* Currently writing to page 0 is only supported. */
1175 /* reg_w() only supports 8bit index */
1176 index = reg->reg & 0x000000ff;
1177 value = reg->val & 0x000000ff;
1178
1179 /* Note that there shall be no access to other page
1180 by any other function between the page swith and
1181 the actual register write */
1182 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
1183 if (0 <= ret)
1184 ret = reg_w(gspca_dev, index, value);
1185
1186 if (0 <= ret)
1187 ret = reg_w(gspca_dev, 0xdc, 0x01);
1188 }
1189 return ret;
1190}
1191
1192static int sd_chip_ident(struct gspca_dev *gspca_dev,
1193 struct v4l2_dbg_chip_ident *chip)
1194{
1195 int ret = -EINVAL;
1196
1197 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1198 chip->match.addr == 0) {
1199 chip->revision = 0;
1200 chip->ident = V4L2_IDENT_UNKNOWN;
1201 ret = 0;
1202 }
1203 return ret;
1204}
1205#endif
1206
Marton Nemeth1408b842009-11-02 08:13:21 -03001207/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -03001208static const struct sd_desc sd_desc = {
Marton Nemeth1408b842009-11-02 08:13:21 -03001209 .name = MODULE_NAME,
1210 .ctrls = sd_ctrls,
1211 .nctrls = ARRAY_SIZE(sd_ctrls),
1212 .config = sd_config,
1213 .init = sd_init,
1214 .start = sd_start,
1215 .stopN = sd_stopN,
1216 .stop0 = sd_stop0,
1217 .pkt_scan = sd_pkt_scan,
1218 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -03001219#ifdef CONFIG_VIDEO_ADV_DEBUG
1220 .set_register = sd_dbg_s_register,
1221 .get_chip_ident = sd_chip_ident,
1222#endif
Marton Nemeth1408b842009-11-02 08:13:21 -03001223};
1224
1225/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -03001226static const struct usb_device_id device_table[] __devinitconst = {
Marton Nemeth1408b842009-11-02 08:13:21 -03001227 {USB_DEVICE(0x06f8, 0x3009)},
1228 {USB_DEVICE(0x093a, 0x2620)},
1229 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -03001230 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
1231 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -03001232 {USB_DEVICE(0x093a, 0x2626)},
1233 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -03001234 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -03001235 {USB_DEVICE(0x093a, 0x262a)},
1236 {USB_DEVICE(0x093a, 0x262c)},
1237 {}
1238};
1239MODULE_DEVICE_TABLE(usb, device_table);
1240
1241/* -- device connect -- */
Márton Németh37b372e2009-12-10 11:31:09 -03001242static int __devinit sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -03001243 const struct usb_device_id *id)
1244{
1245 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1246 THIS_MODULE);
1247}
1248
1249static struct usb_driver sd_driver = {
1250 .name = MODULE_NAME,
1251 .id_table = device_table,
1252 .probe = sd_probe,
1253 .disconnect = gspca_disconnect,
1254#ifdef CONFIG_PM
1255 .suspend = gspca_suspend,
1256 .resume = gspca_resume,
1257#endif
1258};
1259
1260/* -- module insert / remove -- */
1261static int __init sd_mod_init(void)
1262{
1263 int ret;
1264 ret = usb_register(&sd_driver);
1265 if (ret < 0)
1266 return ret;
1267 PDEBUG(D_PROBE, "registered");
1268 return 0;
1269}
1270static void __exit sd_mod_exit(void)
1271{
1272 usb_deregister(&sd_driver);
1273 PDEBUG(D_PROBE, "deregistered");
1274}
1275
1276module_init(sd_mod_init);
1277module_exit(sd_mod_exit);