blob: b4049c0c687deb59179aae7e567a33f130298bfe [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
127static struct ctrl sd_ctrls[] = {
128/* 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
304#define LOAD_PAGE4 254
305#define END_OF_SEQUENCE 0
306
307/* pac 7302 */
308static const __u8 init_7302[] = {
309/* index,value */
310 0xff, 0x01, /* page 1 */
311 0x78, 0x00, /* deactivate */
312 0xff, 0x01,
313 0x78, 0x40, /* led off */
314};
315static const __u8 start_7302[] = {
316/* index, len, [value]* */
317 0xff, 1, 0x00, /* page 0 */
318 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
319 0x00, 0x00, 0x00, 0x00,
320 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
321 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
322 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
323 0x26, 2, 0xaa, 0xaa,
324 0x2e, 1, 0x31,
325 0x38, 1, 0x01,
326 0x3a, 3, 0x14, 0xff, 0x5a,
327 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
328 0x00, 0x54, 0x11,
329 0x55, 1, 0x00,
330 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
331 0x6b, 1, 0x00,
332 0x6e, 3, 0x08, 0x06, 0x00,
333 0x72, 3, 0x00, 0xff, 0x00,
334 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
335 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
336 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
337 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
338 0xd2, 0xeb,
339 0xaf, 1, 0x02,
340 0xb5, 2, 0x08, 0x08,
341 0xb8, 2, 0x08, 0x88,
342 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
343 0xcc, 1, 0x00,
344 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
345 0xc1, 0xd7, 0xec,
346 0xdc, 1, 0x01,
347 0xff, 1, 0x01, /* page 1 */
348 0x12, 3, 0x02, 0x00, 0x01,
349 0x3e, 2, 0x00, 0x00,
350 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
351 0x7c, 1, 0x00,
352 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
353 0x02, 0x00,
354 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
355 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
356 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
357 0xd8, 1, 0x01,
358 0xdb, 2, 0x00, 0x01,
359 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
360 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
361 0xeb, 1, 0x00,
362 0xff, 1, 0x02, /* page 2 */
363 0x22, 1, 0x00,
364 0xff, 1, 0x03, /* page 3 */
365 0, LOAD_PAGE3, /* load the page 3 */
366 0x11, 1, 0x01,
367 0xff, 1, 0x02, /* page 2 */
368 0x13, 1, 0x00,
369 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
370 0x27, 2, 0x14, 0x0c,
371 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
372 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
373 0x6e, 1, 0x08,
374 0xff, 1, 0x01, /* page 1 */
375 0x78, 1, 0x00,
376 0, END_OF_SEQUENCE /* end of sequence */
377};
378
379#define SKIP 0xaa
380/* page 3 - the value SKIP says skip the index - see reg_w_page() */
381static const __u8 page3_7302[] = {
382 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
383 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
384 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
386 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
387 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
388 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
389 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
392 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
396 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
397 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
398 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
401 0x00
402};
403
Márton Némethb1784b32009-11-07 05:52:02 -0300404static int reg_w_buf(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300405 __u8 index,
406 const char *buffer, int len)
407{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300408 int ret;
409
Marton Nemeth1408b842009-11-02 08:13:21 -0300410 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300411 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300412 usb_sndctrlpipe(gspca_dev->dev, 0),
413 1, /* request */
414 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
415 0, /* value */
416 index, gspca_dev->usb_buf, len,
417 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300418 if (ret < 0)
419 PDEBUG(D_ERR, "reg_w_buf(): "
420 "Failed to write registers to index 0x%x, error %i",
421 index, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300422 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300423}
424
425
Márton Némethb1784b32009-11-07 05:52:02 -0300426static int reg_w(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300427 __u8 index,
428 __u8 value)
429{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300430 int ret;
431
Marton Nemeth1408b842009-11-02 08:13:21 -0300432 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300433 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300434 usb_sndctrlpipe(gspca_dev->dev, 0),
435 0, /* request */
436 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
437 0, index, gspca_dev->usb_buf, 1,
438 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300439 if (ret < 0)
440 PDEBUG(D_ERR, "reg_w(): "
441 "Failed to write register to index 0x%x, value 0x%x, error %i",
442 index, value, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300443 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300444}
445
Márton Némethb1784b32009-11-07 05:52:02 -0300446static int reg_w_seq(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300447 const __u8 *seq, int len)
448{
Márton Némethb1784b32009-11-07 05:52:02 -0300449 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300450 while (--len >= 0) {
Márton Némethb1784b32009-11-07 05:52:02 -0300451 if (0 <= ret)
452 ret = reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300453 seq += 2;
454 }
Márton Némethb1784b32009-11-07 05:52:02 -0300455 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300456}
457
458/* load the beginning of a page */
Márton Némethb1784b32009-11-07 05:52:02 -0300459static int reg_w_page(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300460 const __u8 *page, int len)
461{
462 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300463 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300464
465 for (index = 0; index < len; index++) {
466 if (page[index] == SKIP) /* skip this index */
467 continue;
468 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300469 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300470 usb_sndctrlpipe(gspca_dev->dev, 0),
471 0, /* request */
472 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
473 0, index, gspca_dev->usb_buf, 1,
474 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300475 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300476 PDEBUG(D_ERR, "reg_w_page(): "
477 "Failed to write register to index 0x%x, "
478 "value 0x%x, error %i",
479 index, page[index], ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300480 break;
481 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300482 }
Márton Némethb1784b32009-11-07 05:52:02 -0300483 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300484}
485
486/* output a variable sequence */
Márton Némethb1784b32009-11-07 05:52:02 -0300487static int reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300488 const __u8 *seq,
489 const __u8 *page3, unsigned int page3_len,
490 const __u8 *page4, unsigned int page4_len)
491{
492 int index, len;
Márton Némethb1784b32009-11-07 05:52:02 -0300493 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300494
495 for (;;) {
496 index = *seq++;
497 len = *seq++;
498 switch (len) {
499 case END_OF_SEQUENCE:
Márton Némethb1784b32009-11-07 05:52:02 -0300500 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300501 case LOAD_PAGE4:
Márton Némethb1784b32009-11-07 05:52:02 -0300502 ret = reg_w_page(gspca_dev, page4, page4_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300503 break;
504 case LOAD_PAGE3:
Márton Némethb1784b32009-11-07 05:52:02 -0300505 ret = reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300506 break;
507 default:
508 if (len > USB_BUF_SZ) {
509 PDEBUG(D_ERR|D_STREAM,
510 "Incorrect variable sequence");
Márton Némethb1784b32009-11-07 05:52:02 -0300511 return -EINVAL;
Marton Nemeth1408b842009-11-02 08:13:21 -0300512 }
513 while (len > 0) {
514 if (len < 8) {
Márton Némethb1784b32009-11-07 05:52:02 -0300515 ret = reg_w_buf(gspca_dev,
516 index, seq, len);
517 if (ret < 0)
518 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300519 seq += len;
520 break;
521 }
Márton Némethb1784b32009-11-07 05:52:02 -0300522 ret = reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300523 seq += 8;
524 index += 8;
525 len -= 8;
526 }
527 }
Márton Némethb1784b32009-11-07 05:52:02 -0300528 if (ret < 0)
529 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300530 }
531 /* not reached */
532}
533
534/* this function is called at probe time for pac7302 */
535static int sd_config(struct gspca_dev *gspca_dev,
536 const struct usb_device_id *id)
537{
538 struct sd *sd = (struct sd *) gspca_dev;
539 struct cam *cam;
540
541 cam = &gspca_dev->cam;
542
543 PDEBUG(D_CONF, "Find Sensor PAC7302");
544 cam->cam_mode = vga_mode; /* only 640x480 */
545 cam->nmodes = ARRAY_SIZE(vga_mode);
546
547 sd->brightness = BRIGHTNESS_DEF;
548 sd->contrast = CONTRAST_DEF;
549 sd->colors = COLOR_DEF;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300550 sd->white_balance = WHITEBALANCE_DEF;
Márton Németh265a8092009-11-07 15:15:56 -0300551 sd->red_balance = REDBALANCE_DEF;
552 sd->blue_balance = BLUEBALANCE_DEF;
Marton Nemeth1408b842009-11-02 08:13:21 -0300553 sd->gain = GAIN_DEF;
554 sd->exposure = EXPOSURE_DEF;
555 sd->autogain = AUTOGAIN_DEF;
556 sd->hflip = HFLIP_DEF;
557 sd->vflip = VFLIP_DEF;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300558 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300559 return 0;
560}
561
562/* This function is used by pac7302 only */
Márton Némethb1784b32009-11-07 05:52:02 -0300563static int setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300564{
565 struct sd *sd = (struct sd *) gspca_dev;
566 int i, v;
Márton Némethb1784b32009-11-07 05:52:02 -0300567 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300568 static const __u8 max[10] =
569 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
570 0xd4, 0xec};
571 static const __u8 delta[10] =
572 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
573 0x11, 0x0b};
574
Márton Némethb1784b32009-11-07 05:52:02 -0300575 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300576 for (i = 0; i < 10; i++) {
577 v = max[i];
578 v += (sd->brightness - BRIGHTNESS_MAX)
579 * 150 / BRIGHTNESS_MAX; /* 200 ? */
580 v -= delta[i] * sd->contrast / CONTRAST_MAX;
581 if (v < 0)
582 v = 0;
583 else if (v > 0xff)
584 v = 0xff;
Márton Némethb1784b32009-11-07 05:52:02 -0300585 if (0 <= ret)
586 ret = reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300587 }
Márton Némethb1784b32009-11-07 05:52:02 -0300588 if (0 <= ret)
589 ret = reg_w(gspca_dev, 0xdc, 0x01);
590 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300591}
592
593/* This function is used by pac7302 only */
Márton Némethb1784b32009-11-07 05:52:02 -0300594static int setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300595{
596 struct sd *sd = (struct sd *) gspca_dev;
597 int i, v;
Márton Némethb1784b32009-11-07 05:52:02 -0300598 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300599 static const int a[9] =
600 {217, -212, 0, -101, 170, -67, -38, -315, 355};
601 static const int b[9] =
602 {19, 106, 0, 19, 106, 1, 19, 106, 1};
603
Márton Némethb1784b32009-11-07 05:52:02 -0300604 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
605 if (0 <= ret)
606 ret = reg_w(gspca_dev, 0x11, 0x01);
607 if (0 <= ret)
608 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300609 for (i = 0; i < 9; i++) {
610 v = a[i] * sd->colors / COLOR_MAX + b[i];
Márton Némethb1784b32009-11-07 05:52:02 -0300611 if (0 <= ret)
612 ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
613 if (0 <= ret)
614 ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300615 }
Márton Némethb1784b32009-11-07 05:52:02 -0300616 if (0 <= ret)
617 ret = reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300618 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
Márton Némethb1784b32009-11-07 05:52:02 -0300619 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300620}
621
Marton Nemeth23fbee62009-11-08 04:35:12 -0300622static int setwhitebalance(struct gspca_dev *gspca_dev)
623{
624 struct sd *sd = (struct sd *) gspca_dev;
625 int ret;
626
627 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
628 if (0 <= ret)
629 ret = reg_w(gspca_dev, 0xc6, sd->white_balance);
630
631 if (0 <= ret)
632 ret = reg_w(gspca_dev, 0xdc, 0x01);
633 PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
634 return ret;
635}
636
Márton Németh265a8092009-11-07 15:15:56 -0300637static int setredbalance(struct gspca_dev *gspca_dev)
638{
639 struct sd *sd = (struct sd *) gspca_dev;
640 int ret;
641
642 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
643 if (0 <= ret)
644 ret = reg_w(gspca_dev, 0xc5, sd->red_balance);
645
646 if (0 <= ret)
647 ret = reg_w(gspca_dev, 0xdc, 0x01);
648 PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
649 return ret;
650}
651
652static int setbluebalance(struct gspca_dev *gspca_dev)
653{
654 struct sd *sd = (struct sd *) gspca_dev;
655 int ret;
656
657 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
658 if (0 <= ret)
659 ret = reg_w(gspca_dev, 0xc7, sd->blue_balance);
660
661 if (0 <= ret)
662 ret = reg_w(gspca_dev, 0xdc, 0x01);
663 PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
664 return ret;
665}
666
Márton Némethb1784b32009-11-07 05:52:02 -0300667static int setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300668{
669 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300670 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300671
Márton Némethb1784b32009-11-07 05:52:02 -0300672 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
673 if (0 <= ret)
674 ret = reg_w(gspca_dev, 0x10, sd->gain >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300675
676 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300677 if (0 <= ret)
678 ret = reg_w(gspca_dev, 0x11, 0x01);
679 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300680}
681
Márton Némethb1784b32009-11-07 05:52:02 -0300682static int setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300683{
684 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300685 int ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300686 __u8 reg;
687
688 /* register 2 of frame 3/4 contains the clock divider configuring the
689 no fps according to the formula: 60 / reg. sd->exposure is the
690 desired exposure time in ms. */
691 reg = 120 * sd->exposure / 1000;
692 if (reg < 2)
693 reg = 2;
694 else if (reg > 63)
695 reg = 63;
696
697 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
698 the nearest multiple of 3, except when between 6 and 12? */
699 if (reg < 6 || reg > 12)
700 reg = ((reg + 1) / 3) * 3;
Márton Némethb1784b32009-11-07 05:52:02 -0300701 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
702 if (0 <= ret)
703 ret = reg_w(gspca_dev, 0x02, reg);
Marton Nemeth1408b842009-11-02 08:13:21 -0300704
705 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300706 if (0 <= ret)
707 ret = reg_w(gspca_dev, 0x11, 0x01);
708 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300709}
710
Márton Némethb1784b32009-11-07 05:52:02 -0300711static int sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300712{
713 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300714 int ret;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300715 u8 data, hflip, vflip;
716
717 hflip = sd->hflip;
718 if (sd->flags & FL_HFLIP)
719 hflip = !hflip;
720 vflip = sd->vflip;
721 if (sd->flags & FL_VFLIP)
722 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300723
Márton Némethb1784b32009-11-07 05:52:02 -0300724 ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300725 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Márton Némethb1784b32009-11-07 05:52:02 -0300726 if (0 <= ret)
727 ret = reg_w(gspca_dev, 0x21, data);
Marton Nemeth1408b842009-11-02 08:13:21 -0300728 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300729 if (0 <= ret)
730 ret = reg_w(gspca_dev, 0x11, 0x01);
731 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300732}
733
734/* this function is called at probe and resume time for pac7302 */
735static int sd_init(struct gspca_dev *gspca_dev)
736{
Márton Némethb1784b32009-11-07 05:52:02 -0300737 return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
Marton Nemeth1408b842009-11-02 08:13:21 -0300738}
739
740static int sd_start(struct gspca_dev *gspca_dev)
741{
742 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300743 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300744
745 sd->sof_read = 0;
746
Márton Némethb1784b32009-11-07 05:52:02 -0300747 ret = reg_w_var(gspca_dev, start_7302,
Marton Nemeth1408b842009-11-02 08:13:21 -0300748 page3_7302, sizeof(page3_7302),
749 NULL, 0);
Márton Némethb1784b32009-11-07 05:52:02 -0300750 if (0 <= ret)
751 ret = setbrightcont(gspca_dev);
752 if (0 <= ret)
753 ret = setcolors(gspca_dev);
754 if (0 <= ret)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300755 ret = setwhitebalance(gspca_dev);
756 if (0 <= ret)
Márton Németh265a8092009-11-07 15:15:56 -0300757 ret = setredbalance(gspca_dev);
758 if (0 <= ret)
759 ret = setbluebalance(gspca_dev);
760 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300761 ret = setgain(gspca_dev);
Márton Némethb1784b32009-11-07 05:52:02 -0300762 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300763 ret = setexposure(gspca_dev);
Márton Némethb1784b32009-11-07 05:52:02 -0300764 if (0 <= ret)
Marton Nemeth012880b2009-11-08 04:41:28 -0300765 ret = sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300766
767 /* only resolution 640x480 is supported for pac7302 */
768
769 sd->sof_read = 0;
770 sd->autogain_ignore_frames = 0;
771 atomic_set(&sd->avg_lum, -1);
772
773 /* start stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300774 if (0 <= ret)
775 ret = reg_w(gspca_dev, 0xff, 0x01);
776 if (0 <= ret)
777 ret = reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300778
Márton Némethb1784b32009-11-07 05:52:02 -0300779 return ret;
Marton Nemeth1408b842009-11-02 08:13:21 -0300780}
781
782static void sd_stopN(struct gspca_dev *gspca_dev)
783{
Márton Némethb1784b32009-11-07 05:52:02 -0300784 int ret;
785
Márton Németh67c98f72009-11-07 05:45:33 -0300786 /* stop stream */
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, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300790}
791
792/* called on streamoff with alt 0 and on disconnect for pac7302 */
793static void sd_stop0(struct gspca_dev *gspca_dev)
794{
Márton Némethb1784b32009-11-07 05:52:02 -0300795 int ret;
796
Marton Nemeth1408b842009-11-02 08:13:21 -0300797 if (!gspca_dev->present)
798 return;
Márton Némethb1784b32009-11-07 05:52:02 -0300799 ret = reg_w(gspca_dev, 0xff, 0x01);
800 if (0 <= ret)
801 ret = reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300802}
803
804/* Include pac common sof detection functions */
805#include "pac_common.h"
806
807static void do_autogain(struct gspca_dev *gspca_dev)
808{
809 struct sd *sd = (struct sd *) gspca_dev;
810 int avg_lum = atomic_read(&sd->avg_lum);
811 int desired_lum, deadzone;
812
813 if (avg_lum == -1)
814 return;
815
816 desired_lum = 270 + sd->brightness * 4;
817 /* Hack hack, with the 7202 the first exposure step is
818 pretty large, so if we're about to make the first
819 exposure increase make the deadzone large to avoid
820 oscilating */
821 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
822 sd->exposure > EXPOSURE_DEF &&
823 sd->exposure < 42)
824 deadzone = 90;
825 else
826 deadzone = 30;
827
828 if (sd->autogain_ignore_frames > 0)
829 sd->autogain_ignore_frames--;
830 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
831 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
832 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
833}
834
835/* JPEG header, part 1 */
836static const unsigned char pac_jpeg_header1[] = {
837 0xff, 0xd8, /* SOI: Start of Image */
838
839 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
840 0x00, 0x11, /* length = 17 bytes (including this length field) */
841 0x08 /* Precision: 8 */
842 /* 2 bytes is placed here: number of image lines */
843 /* 2 bytes is placed here: samples per line */
844};
845
846/* JPEG header, continued */
847static const unsigned char pac_jpeg_header2[] = {
848 0x03, /* Number of image components: 3 */
849 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
850 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
851 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
852
853 0xff, 0xda, /* SOS: Start Of Scan */
854 0x00, 0x0c, /* length = 12 bytes (including this length field) */
855 0x03, /* number of components: 3 */
856 0x01, 0x00, /* selector 1, table 0x00 */
857 0x02, 0x11, /* selector 2, table 0x11 */
858 0x03, 0x11, /* selector 3, table 0x11 */
859 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
860 0x00 /* Successive approximation: 0 */
861};
862
863static void pac_start_frame(struct gspca_dev *gspca_dev,
864 struct gspca_frame *frame,
865 __u16 lines, __u16 samples_per_line)
866{
867 unsigned char tmpbuf[4];
868
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300869 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300870 pac_jpeg_header1, sizeof(pac_jpeg_header1));
871
872 tmpbuf[0] = lines >> 8;
873 tmpbuf[1] = lines & 0xff;
874 tmpbuf[2] = samples_per_line >> 8;
875 tmpbuf[3] = samples_per_line & 0xff;
876
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300877 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300878 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300879 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300880 pac_jpeg_header2, sizeof(pac_jpeg_header2));
881}
882
883/* this function is run at interrupt level */
884static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300885 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300886 int len) /* iso packet length */
887{
888 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300889 struct gspca_frame *frame;
Marton Nemeth1408b842009-11-02 08:13:21 -0300890 unsigned char *sof;
891
892 sof = pac_find_sof(&sd->sof_read, data, len);
893 if (sof) {
894 int n, lum_offset, footer_length;
895
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300896 frame = gspca_get_i_frame(gspca_dev);
897 if (frame == NULL) {
898 gspca_dev->last_packet_type = DISCARD_PACKET;
899 return;
900 }
901
Marton Nemeth1408b842009-11-02 08:13:21 -0300902 /* 6 bytes after the FF D9 EOF marker a number of lumination
903 bytes are send corresponding to different parts of the
904 image, the 14th and 15th byte after the EOF seem to
905 correspond to the center of the image */
906 lum_offset = 61 + sizeof pac_sof_marker;
907 footer_length = 74;
908
909 /* Finish decoding current frame */
910 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
911 if (n < 0) {
912 frame->data_end += n;
913 n = 0;
914 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300915 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300916 data, n);
917 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
918 frame->data_end[-2] == 0xff &&
919 frame->data_end[-1] == 0xd9)
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300920 gspca_frame_add(gspca_dev, LAST_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300921 NULL, 0);
922
923 n = sof - data;
924 len -= n;
925 data = sof;
926
927 /* Get average lumination */
928 if (gspca_dev->last_packet_type == LAST_PACKET &&
929 n >= lum_offset)
930 atomic_set(&sd->avg_lum, data[-lum_offset] +
931 data[-lum_offset + 1]);
932 else
933 atomic_set(&sd->avg_lum, -1);
934
935 /* Start the new frame with the jpeg header */
936 /* The PAC7302 has the image rotated 90 degrees */
937 pac_start_frame(gspca_dev, frame,
938 gspca_dev->width, gspca_dev->height);
939 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300940 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300941}
942
943static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
944{
945 struct sd *sd = (struct sd *) gspca_dev;
946
947 sd->brightness = val;
948 if (gspca_dev->streaming)
949 setbrightcont(gspca_dev);
950 return 0;
951}
952
953static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
954{
955 struct sd *sd = (struct sd *) gspca_dev;
956
957 *val = sd->brightness;
958 return 0;
959}
960
961static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
962{
963 struct sd *sd = (struct sd *) gspca_dev;
964
965 sd->contrast = val;
966 if (gspca_dev->streaming) {
967 setbrightcont(gspca_dev);
968 }
969 return 0;
970}
971
972static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
973{
974 struct sd *sd = (struct sd *) gspca_dev;
975
976 *val = sd->contrast;
977 return 0;
978}
979
980static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
981{
982 struct sd *sd = (struct sd *) gspca_dev;
983
984 sd->colors = val;
985 if (gspca_dev->streaming)
986 setcolors(gspca_dev);
987 return 0;
988}
989
990static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
991{
992 struct sd *sd = (struct sd *) gspca_dev;
993
994 *val = sd->colors;
995 return 0;
996}
997
Marton Nemeth23fbee62009-11-08 04:35:12 -0300998static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
999{
1000 struct sd *sd = (struct sd *) gspca_dev;
1001 int ret = 0;
1002
1003 sd->white_balance = val;
1004 if (gspca_dev->streaming)
1005 ret = setwhitebalance(gspca_dev);
1006 if (0 <= ret)
1007 ret = 0;
1008 return ret;
1009}
1010
1011static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
1012{
1013 struct sd *sd = (struct sd *) gspca_dev;
1014
1015 *val = sd->white_balance;
1016 return 0;
1017}
1018
Márton Németh265a8092009-11-07 15:15:56 -03001019static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
1020{
1021 struct sd *sd = (struct sd *) gspca_dev;
1022 int ret = 0;
1023
1024 sd->red_balance = val;
1025 if (gspca_dev->streaming)
1026 ret = setredbalance(gspca_dev);
1027 if (0 <= ret)
1028 ret = 0;
1029 return ret;
1030}
1031
1032static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
1033{
1034 struct sd *sd = (struct sd *) gspca_dev;
1035
1036 *val = sd->red_balance;
1037 return 0;
1038}
1039
1040static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
1041{
1042 struct sd *sd = (struct sd *) gspca_dev;
1043 int ret = 0;
1044
1045 sd->blue_balance = val;
1046 if (gspca_dev->streaming)
1047 ret = setbluebalance(gspca_dev);
1048 if (0 <= ret)
1049 ret = 0;
1050 return ret;
1051}
1052
1053static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
1054{
1055 struct sd *sd = (struct sd *) gspca_dev;
1056
1057 *val = sd->blue_balance;
1058 return 0;
1059}
1060
Marton Nemeth1408b842009-11-02 08:13:21 -03001061static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1062{
1063 struct sd *sd = (struct sd *) gspca_dev;
1064
1065 sd->gain = val;
1066 if (gspca_dev->streaming)
1067 setgain(gspca_dev);
1068 return 0;
1069}
1070
1071static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1072{
1073 struct sd *sd = (struct sd *) gspca_dev;
1074
1075 *val = sd->gain;
1076 return 0;
1077}
1078
1079static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1080{
1081 struct sd *sd = (struct sd *) gspca_dev;
1082
1083 sd->exposure = val;
1084 if (gspca_dev->streaming)
1085 setexposure(gspca_dev);
1086 return 0;
1087}
1088
1089static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1090{
1091 struct sd *sd = (struct sd *) gspca_dev;
1092
1093 *val = sd->exposure;
1094 return 0;
1095}
1096
1097static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1098{
1099 struct sd *sd = (struct sd *) gspca_dev;
1100
1101 sd->autogain = val;
1102 /* when switching to autogain set defaults to make sure
1103 we are on a valid point of the autogain gain /
1104 exposure knee graph, and give this change time to
1105 take effect before doing autogain. */
1106 if (sd->autogain) {
1107 sd->exposure = EXPOSURE_DEF;
1108 sd->gain = GAIN_DEF;
1109 if (gspca_dev->streaming) {
1110 sd->autogain_ignore_frames =
1111 PAC_AUTOGAIN_IGNORE_FRAMES;
1112 setexposure(gspca_dev);
1113 setgain(gspca_dev);
1114 }
1115 }
1116
1117 return 0;
1118}
1119
1120static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1121{
1122 struct sd *sd = (struct sd *) gspca_dev;
1123
1124 *val = sd->autogain;
1125 return 0;
1126}
1127
1128static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1129{
1130 struct sd *sd = (struct sd *) gspca_dev;
1131
1132 sd->hflip = val;
1133 if (gspca_dev->streaming)
1134 sethvflip(gspca_dev);
1135 return 0;
1136}
1137
1138static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1139{
1140 struct sd *sd = (struct sd *) gspca_dev;
1141
1142 *val = sd->hflip;
1143 return 0;
1144}
1145
1146static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1147{
1148 struct sd *sd = (struct sd *) gspca_dev;
1149
1150 sd->vflip = val;
1151 if (gspca_dev->streaming)
1152 sethvflip(gspca_dev);
1153 return 0;
1154}
1155
1156static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1157{
1158 struct sd *sd = (struct sd *) gspca_dev;
1159
1160 *val = sd->vflip;
1161 return 0;
1162}
1163
Márton Németh6763cc02009-11-09 07:10:46 -03001164#ifdef CONFIG_VIDEO_ADV_DEBUG
1165static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1166 struct v4l2_dbg_register *reg)
1167{
1168 int ret = -EINVAL;
1169 __u8 index;
1170 __u8 value;
1171
1172 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
1173 long on the USB bus)
1174 */
1175 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
1176 reg->match.addr == 0 &&
1177 (reg->reg < 0x000000ff) &&
1178 (reg->val <= 0x000000ff)
1179 ) {
1180 /* Currently writing to page 0 is only supported. */
1181 /* reg_w() only supports 8bit index */
1182 index = reg->reg & 0x000000ff;
1183 value = reg->val & 0x000000ff;
1184
1185 /* Note that there shall be no access to other page
1186 by any other function between the page swith and
1187 the actual register write */
1188 ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
1189 if (0 <= ret)
1190 ret = reg_w(gspca_dev, index, value);
1191
1192 if (0 <= ret)
1193 ret = reg_w(gspca_dev, 0xdc, 0x01);
1194 }
1195 return ret;
1196}
1197
1198static int sd_chip_ident(struct gspca_dev *gspca_dev,
1199 struct v4l2_dbg_chip_ident *chip)
1200{
1201 int ret = -EINVAL;
1202
1203 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1204 chip->match.addr == 0) {
1205 chip->revision = 0;
1206 chip->ident = V4L2_IDENT_UNKNOWN;
1207 ret = 0;
1208 }
1209 return ret;
1210}
1211#endif
1212
Marton Nemeth1408b842009-11-02 08:13:21 -03001213/* sub-driver description for pac7302 */
1214static struct sd_desc sd_desc = {
1215 .name = MODULE_NAME,
1216 .ctrls = sd_ctrls,
1217 .nctrls = ARRAY_SIZE(sd_ctrls),
1218 .config = sd_config,
1219 .init = sd_init,
1220 .start = sd_start,
1221 .stopN = sd_stopN,
1222 .stop0 = sd_stop0,
1223 .pkt_scan = sd_pkt_scan,
1224 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -03001225#ifdef CONFIG_VIDEO_ADV_DEBUG
1226 .set_register = sd_dbg_s_register,
1227 .get_chip_ident = sd_chip_ident,
1228#endif
Marton Nemeth1408b842009-11-02 08:13:21 -03001229};
1230
1231/* -- module initialisation -- */
1232static __devinitdata struct usb_device_id device_table[] = {
1233 {USB_DEVICE(0x06f8, 0x3009)},
1234 {USB_DEVICE(0x093a, 0x2620)},
1235 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -03001236 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
1237 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -03001238 {USB_DEVICE(0x093a, 0x2626)},
1239 {USB_DEVICE(0x093a, 0x2628)},
1240 {USB_DEVICE(0x093a, 0x2629)},
1241 {USB_DEVICE(0x093a, 0x262a)},
1242 {USB_DEVICE(0x093a, 0x262c)},
1243 {}
1244};
1245MODULE_DEVICE_TABLE(usb, device_table);
1246
1247/* -- device connect -- */
1248static int sd_probe(struct usb_interface *intf,
1249 const struct usb_device_id *id)
1250{
1251 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1252 THIS_MODULE);
1253}
1254
1255static struct usb_driver sd_driver = {
1256 .name = MODULE_NAME,
1257 .id_table = device_table,
1258 .probe = sd_probe,
1259 .disconnect = gspca_disconnect,
1260#ifdef CONFIG_PM
1261 .suspend = gspca_suspend,
1262 .resume = gspca_resume,
1263#endif
1264};
1265
1266/* -- module insert / remove -- */
1267static int __init sd_mod_init(void)
1268{
1269 int ret;
1270 ret = usb_register(&sd_driver);
1271 if (ret < 0)
1272 return ret;
1273 PDEBUG(D_PROBE, "registered");
1274 return 0;
1275}
1276static void __exit sd_mod_exit(void)
1277{
1278 usb_deregister(&sd_driver);
1279 PDEBUG(D_PROBE, "deregistered");
1280}
1281
1282module_init(sd_mod_init);
1283module_exit(sd_mod_exit);