blob: f05bc800a7cbe8e265c5b590de049adfe6508311 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
Hans de Goede327c4ab2008-09-03 17:12:14 -030022/* Some documentation about various registers as determined by trial and error.
23 When the register addresses differ between the 7202 and the 7311 the 2
24 different addresses are written as 7302addr/7311addr, when one of the 2
25 addresses is a - sign that register description is not valid for the
26 matching IC.
27
28 Register page 1:
29
30 Address Description
31 -/0x08 Unknown compressor related, must always be 8 except when not
32 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
33 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
34 bits 345 seem to toggle per color gains on/off (inverted)
35 0x78 Global control, bit 6 controls the LED (inverted)
36 -/0x80 JPEG compression ratio ? Best not touched
37
38 Register page 3/4:
39
40 Address Description
41 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
Hans de Goede038ec7c2008-09-03 17:12:18 -030042 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
Hans de Goede327c4ab2008-09-03 17:12:14 -030043 -/0x0f Master gain 1-245, low value = high gain
44 0x10/- Master gain 0-31
45 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede8a5b2e92008-09-03 17:12:17 -030047 -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
48 completely disable the analog amplification block. Set to 0x68
49 for max gain, 0x14 for minimal gain.
Hans de Goede327c4ab2008-09-03 17:12:14 -030050*/
51
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052#define MODULE_NAME "pac7311"
53
54#include "gspca.h"
55
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030056MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
57MODULE_DESCRIPTION("Pixart PAC7311");
58MODULE_LICENSE("GPL");
59
60/* specific webcam descriptor */
61struct sd {
62 struct gspca_dev gspca_dev; /* !! must be the first item */
63
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064 unsigned char brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030065 unsigned char contrast;
66 unsigned char colors;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030067 unsigned char gain;
68 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030069 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030070 __u8 hflip;
71 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030072
73 __u8 sensor;
74#define SENSOR_PAC7302 0
75#define SENSOR_PAC7311 1
Hans de Goede327c4ab2008-09-03 17:12:14 -030076
77 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030078 u8 autogain_ignore_frames;
79
80 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081};
82
83/* V4L2 controls supported by the driver */
84static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
90static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030092static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
94static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
95static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030096static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
97static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
98static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
99static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100
101static struct ctrl sd_ctrls[] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300102/* This control is pac7302 only */
103#define BRIGHTNESS_IDX 0
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 {
105 {
106 .id = V4L2_CID_BRIGHTNESS,
107 .type = V4L2_CTRL_TYPE_INTEGER,
108 .name = "Brightness",
109 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300110#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .maximum = BRIGHTNESS_MAX,
112 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300113#define BRIGHTNESS_DEF 0x10
114 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 },
116 .set = sd_setbrightness,
117 .get = sd_getbrightness,
118 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300119/* This control is for both the 7302 and the 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300120 {
121 {
122 .id = V4L2_CID_CONTRAST,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Contrast",
125 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300126#define CONTRAST_MAX 255
127 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300128 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300129#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300130 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300131 },
132 .set = sd_setcontrast,
133 .get = sd_getcontrast,
134 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300135/* This control is pac7302 only */
136#define SATURATION_IDX 2
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300137 {
138 {
139 .id = V4L2_CID_SATURATION,
140 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300141 .name = "Saturation",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142 .minimum = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300143#define COLOR_MAX 255
144 .maximum = COLOR_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300145 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300146#define COLOR_DEF 127
147 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300148 },
149 .set = sd_setcolors,
150 .get = sd_getcolors,
151 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300152/* All controls below are for both the 7302 and the 7311 */
153 {
154 {
155 .id = V4L2_CID_GAIN,
156 .type = V4L2_CTRL_TYPE_INTEGER,
157 .name = "Gain",
158 .minimum = 0,
159#define GAIN_MAX 255
160 .maximum = GAIN_MAX,
161 .step = 1,
162#define GAIN_DEF 127
163#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
164 .default_value = GAIN_DEF,
165 },
166 .set = sd_setgain,
167 .get = sd_getgain,
168 },
169 {
170 {
171 .id = V4L2_CID_EXPOSURE,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "Exposure",
174 .minimum = 0,
175#define EXPOSURE_MAX 255
176 .maximum = EXPOSURE_MAX,
177 .step = 1,
178#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
179#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
180 .default_value = EXPOSURE_DEF,
181 },
182 .set = sd_setexposure,
183 .get = sd_getexposure,
184 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185 {
186 {
187 .id = V4L2_CID_AUTOGAIN,
188 .type = V4L2_CTRL_TYPE_BOOLEAN,
189 .name = "Auto Gain",
190 .minimum = 0,
191 .maximum = 1,
192 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300193#define AUTOGAIN_DEF 1
194 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300195 },
196 .set = sd_setautogain,
197 .get = sd_getautogain,
198 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300199 {
200 {
201 .id = V4L2_CID_HFLIP,
202 .type = V4L2_CTRL_TYPE_BOOLEAN,
203 .name = "Mirror",
204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
207#define HFLIP_DEF 0
208 .default_value = HFLIP_DEF,
209 },
210 .set = sd_sethflip,
211 .get = sd_gethflip,
212 },
213 {
214 {
215 .id = V4L2_CID_VFLIP,
216 .type = V4L2_CTRL_TYPE_BOOLEAN,
217 .name = "Vflip",
218 .minimum = 0,
219 .maximum = 1,
220 .step = 1,
221#define VFLIP_DEF 0
222 .default_value = VFLIP_DEF,
223 },
224 .set = sd_setvflip,
225 .get = sd_getvflip,
226 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227};
228
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300229static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300230 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300231 .bytesperline = 160,
232 .sizeimage = 160 * 120 * 3 / 8 + 590,
233 .colorspace = V4L2_COLORSPACE_JPEG,
234 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300235 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300236 .bytesperline = 320,
237 .sizeimage = 320 * 240 * 3 / 8 + 590,
238 .colorspace = V4L2_COLORSPACE_JPEG,
239 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300240 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300241 .bytesperline = 640,
242 .sizeimage = 640 * 480 * 3 / 8 + 590,
243 .colorspace = V4L2_COLORSPACE_JPEG,
244 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300245};
246
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300247/* pac 7302 */
Hans de Goede271315a2008-09-03 17:12:19 -0300248static const __u8 init_7302[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300249/* index,value */
250 0xff, 0x01, /* page 1 */
251 0x78, 0x00, /* deactivate */
252 0xff, 0x01,
253 0x78, 0x40, /* led off */
254};
255static const __u8 start_7302[] = {
256/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300257 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300258 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
259 0x00, 0x00, 0x00, 0x00,
260 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
261 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
262 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
263 0x26, 2, 0xaa, 0xaa,
264 0x2e, 1, 0x31,
265 0x38, 1, 0x01,
266 0x3a, 3, 0x14, 0xff, 0x5a,
267 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
268 0x00, 0x54, 0x11,
269 0x55, 1, 0x00,
270 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
271 0x6b, 1, 0x00,
272 0x6e, 3, 0x08, 0x06, 0x00,
273 0x72, 3, 0x00, 0xff, 0x00,
274 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
275 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
276 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
277 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
278 0xd2, 0xeb,
279 0xaf, 1, 0x02,
280 0xb5, 2, 0x08, 0x08,
281 0xb8, 2, 0x08, 0x88,
282 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
283 0xcc, 1, 0x00,
284 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
285 0xc1, 0xd7, 0xec,
286 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300287 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300288 0x12, 3, 0x02, 0x00, 0x01,
289 0x3e, 2, 0x00, 0x00,
290 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
291 0x7c, 1, 0x00,
292 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
293 0x02, 0x00,
294 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300295 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300296 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300297 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300298 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300299 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300300 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
301 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300302 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300303 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300304 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300305 0x00, 255, /* load the page 3 */
306 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300307 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300308 0x13, 1, 0x00,
309 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
310 0x27, 2, 0x14, 0x0c,
311 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
312 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
313 0x6e, 1, 0x08,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300314 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300315 0x78, 1, 0x00,
316 0, 0 /* end of sequence */
317};
318
Marton Nemethff75e992009-10-04 13:51:26 -0300319#define SKIP 0xaa
320/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300321static const __u8 page3_7302[] = {
322 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
323 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
324 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
326 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
327 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
328 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
329 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
332 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
336 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
337 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
338 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
341 0x00
342};
343
344/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300345static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300346 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
347 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
348 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300349 0xff, 0x04,
350 0x27, 0x80,
351 0x28, 0xca,
352 0x29, 0x53,
353 0x2a, 0x0e,
354 0xff, 0x01,
355 0x3e, 0x20,
356};
357
358static const __u8 start_7311[] = {
359/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300360 0xff, 1, 0x01, /* page 1 */
361 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300362 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
363 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
364 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300367 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300368 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
369 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
370 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
371 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
372 0xd0, 0xff,
373 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
374 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
375 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
376 0x18, 0x20,
377 0x96, 3, 0x01, 0x08, 0x04,
378 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
379 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
380 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300381 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300382 0x00, 254, /* load the page 4 */
383 0x11, 1, 0x01,
384 0, 0 /* end of sequence */
385};
386
Marton Nemethff75e992009-10-04 13:51:26 -0300387/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300388static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300389 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
390 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
391 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
393 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300394 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
395 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
396};
397
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300399 __u8 index,
400 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300401{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300402 memcpy(gspca_dev->usb_buf, buffer, len);
403 usb_control_msg(gspca_dev->dev,
404 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300405 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300407 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 500);
410}
411
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300413static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300414 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300415 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300417 gspca_dev->usb_buf[0] = value;
418 usb_control_msg(gspca_dev->dev,
419 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300420 0, /* request */
421 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300422 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300423 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424}
425
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300426static void reg_w_seq(struct gspca_dev *gspca_dev,
427 const __u8 *seq, int len)
428{
429 while (--len >= 0) {
430 reg_w(gspca_dev, seq[0], seq[1]);
431 seq += 2;
432 }
433}
434
435/* load the beginning of a page */
436static void reg_w_page(struct gspca_dev *gspca_dev,
437 const __u8 *page, int len)
438{
439 int index;
440
441 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300442 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300443 continue;
444 gspca_dev->usb_buf[0] = page[index];
445 usb_control_msg(gspca_dev->dev,
446 usb_sndctrlpipe(gspca_dev->dev, 0),
447 0, /* request */
448 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
449 0, index, gspca_dev->usb_buf, 1,
450 500);
451 }
452}
453
454/* output a variable sequence */
455static void reg_w_var(struct gspca_dev *gspca_dev,
456 const __u8 *seq)
457{
458 int index, len;
459
460 for (;;) {
461 index = *seq++;
462 len = *seq++;
463 switch (len) {
464 case 0:
465 return;
466 case 254:
467 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
468 break;
469 case 255:
470 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
471 break;
472 default:
Hans de Goede327c4ab2008-09-03 17:12:14 -0300473 if (len > 64) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300474 PDEBUG(D_ERR|D_STREAM,
475 "Incorrect variable sequence");
476 return;
477 }
478 while (len > 0) {
479 if (len < 8) {
480 reg_w_buf(gspca_dev, index, seq, len);
481 seq += len;
482 break;
483 }
484 reg_w_buf(gspca_dev, index, seq, 8);
485 seq += 8;
486 index += 8;
487 len -= 8;
488 }
489 }
490 }
491 /* not reached */
492}
493
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494/* this function is called at probe time */
495static int sd_config(struct gspca_dev *gspca_dev,
496 const struct usb_device_id *id)
497{
498 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499 struct cam *cam;
500
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300502
503 sd->sensor = id->driver_info;
504 if (sd->sensor == SENSOR_PAC7302) {
505 PDEBUG(D_CONF, "Find Sensor PAC7302");
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300506 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
507 cam->nmodes = 1;
508 } else {
509 PDEBUG(D_CONF, "Find Sensor PAC7311");
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300510 cam->cam_mode = vga_mode;
511 cam->nmodes = ARRAY_SIZE(vga_mode);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300512 gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
513 | (1 << SATURATION_IDX);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300514 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300516 sd->brightness = BRIGHTNESS_DEF;
517 sd->contrast = CONTRAST_DEF;
518 sd->colors = COLOR_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300519 sd->gain = GAIN_DEF;
520 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300521 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300522 sd->hflip = HFLIP_DEF;
523 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 return 0;
525}
526
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300527/* This function is used by pac7302 only */
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300528static void setbrightcont(struct gspca_dev *gspca_dev)
529{
530 struct sd *sd = (struct sd *) gspca_dev;
531 int i, v;
532 static const __u8 max[10] =
533 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
534 0xd4, 0xec};
535 static const __u8 delta[10] =
536 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
537 0x11, 0x0b};
538
539 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
540 for (i = 0; i < 10; i++) {
541 v = max[i];
542 v += (sd->brightness - BRIGHTNESS_MAX)
543 * 150 / BRIGHTNESS_MAX; /* 200 ? */
544 v -= delta[i] * sd->contrast / CONTRAST_MAX;
545 if (v < 0)
546 v = 0;
547 else if (v > 0xff)
548 v = 0xff;
549 reg_w(gspca_dev, 0xa2 + i, v);
550 }
551 reg_w(gspca_dev, 0xdc, 0x01);
552}
553
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300554/* This function is used by pac7311 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555static void setcontrast(struct gspca_dev *gspca_dev)
556{
557 struct sd *sd = (struct sd *) gspca_dev;
558
Hans de Goede327c4ab2008-09-03 17:12:14 -0300559 reg_w(gspca_dev, 0xff, 0x04);
560 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300562 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300563}
564
Hans de Goede327c4ab2008-09-03 17:12:14 -0300565/* This function is used by pac7302 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300566static void setcolors(struct gspca_dev *gspca_dev)
567{
568 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300569 int i, v;
570 static const int a[9] =
571 {217, -212, 0, -101, 170, -67, -38, -315, 355};
572 static const int b[9] =
573 {19, 106, 0, 19, 106, 1, 19, 106, 1};
574
575 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
576 reg_w(gspca_dev, 0x11, 0x01);
577 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
578 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
579 for (i = 0; i < 9; i++) {
580 v = a[i] * sd->colors / COLOR_MAX + b[i];
581 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
582 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
583 }
584 reg_w(gspca_dev, 0xdc, 0x01);
585 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
586}
587
588static void setgain(struct gspca_dev *gspca_dev)
589{
590 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300592 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300593 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
594 reg_w(gspca_dev, 0x10, sd->gain >> 3);
595 } else {
596 int gain = GAIN_MAX - sd->gain;
597 if (gain < 1)
598 gain = 1;
599 else if (gain > 245)
600 gain = 245;
601 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
602 reg_w(gspca_dev, 0x0e, 0x00);
603 reg_w(gspca_dev, 0x0f, gain);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300604 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300605 /* load registers to sensor (Bit 0, auto clear) */
606 reg_w(gspca_dev, 0x11, 0x01);
607}
608
609static void setexposure(struct gspca_dev *gspca_dev)
610{
611 struct sd *sd = (struct sd *) gspca_dev;
612 __u8 reg;
613
614 /* register 2 of frame 3/4 contains the clock divider configuring the
615 no fps according to the formula: 60 / reg. sd->exposure is the
616 desired exposure time in ms. */
617 reg = 120 * sd->exposure / 1000;
618 if (reg < 2)
619 reg = 2;
620 else if (reg > 63)
621 reg = 63;
622
623 if (sd->sensor == SENSOR_PAC7302) {
624 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
Hans de Goede038ec7c2008-09-03 17:12:18 -0300625 the nearest multiple of 3, except when between 6 and 12? */
626 if (reg < 6 || reg > 12)
627 reg = ((reg + 1) / 3) * 3;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300628 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
629 reg_w(gspca_dev, 0x02, reg);
630 } else {
631 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
632 reg_w(gspca_dev, 0x02, reg);
633 /* Page 1 register 8 must always be 0x08 except when not in
634 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
635 reg_w(gspca_dev, 0xff, 0x01);
636 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
637 reg <= 3)
638 reg_w(gspca_dev, 0x08, 0x09);
639 else
640 reg_w(gspca_dev, 0x08, 0x08);
641 }
642 /* load registers to sensor (Bit 0, auto clear) */
643 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300644}
645
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300646static void sethvflip(struct gspca_dev *gspca_dev)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649 __u8 data;
650
Hans de Goede327c4ab2008-09-03 17:12:14 -0300651 if (sd->sensor == SENSOR_PAC7302) {
652 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300653 data = (sd->hflip ? 0x08 : 0x00)
Hans de Goede327c4ab2008-09-03 17:12:14 -0300654 | (sd->vflip ? 0x04 : 0x00);
655 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300656 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300657 data = (sd->hflip ? 0x04 : 0x00)
658 | (sd->vflip ? 0x08 : 0x00);
659 }
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300660 reg_w(gspca_dev, 0x21, data);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300661 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300662 reg_w(gspca_dev, 0x11, 0x01);
663}
664
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300665/* this function is called at probe and resume time */
666static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667{
Hans de Goede271315a2008-09-03 17:12:19 -0300668 struct sd *sd = (struct sd *) gspca_dev;
669
670 if (sd->sensor == SENSOR_PAC7302)
671 reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
672 else
673 reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
674
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300675 return 0;
676}
677
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300678static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300680 struct sd *sd = (struct sd *) gspca_dev;
681
Hans de Goede327c4ab2008-09-03 17:12:14 -0300682 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300684 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300685 reg_w_var(gspca_dev, start_7302);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300686 setbrightcont(gspca_dev);
687 setcolors(gspca_dev);
688 } else {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300689 reg_w_var(gspca_dev, start_7311);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300690 setcontrast(gspca_dev);
691 }
692 setgain(gspca_dev);
693 setexposure(gspca_dev);
694 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300695
696 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300697 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300698 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300699 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300700 reg_w(gspca_dev, 0x17, 0x20);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300701 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300703 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300704 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300705 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300706 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 break;
708 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300709 if (sd->sensor == SENSOR_PAC7302)
710 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300711 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300712 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300713 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300714 break;
715 }
716
Hans de Goede327c4ab2008-09-03 17:12:14 -0300717 sd->sof_read = 0;
718 sd->autogain_ignore_frames = 0;
719 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300720
721 /* start stream */
722 reg_w(gspca_dev, 0xff, 0x01);
723 if (sd->sensor == SENSOR_PAC7302)
724 reg_w(gspca_dev, 0x78, 0x01);
725 else
726 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300727 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728}
729
730static void sd_stopN(struct gspca_dev *gspca_dev)
731{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300732 struct sd *sd = (struct sd *) gspca_dev;
733
734 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300735 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300736 reg_w(gspca_dev, 0x78, 0x00);
737 reg_w(gspca_dev, 0x78, 0x00);
738 return;
739 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300740 reg_w(gspca_dev, 0xff, 0x04);
741 reg_w(gspca_dev, 0x27, 0x80);
742 reg_w(gspca_dev, 0x28, 0xca);
743 reg_w(gspca_dev, 0x29, 0x53);
744 reg_w(gspca_dev, 0x2a, 0x0e);
745 reg_w(gspca_dev, 0xff, 0x01);
746 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300747 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
748 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
749 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300750}
751
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300752/* called on streamoff with alt 0 and on disconnect */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300753static void sd_stop0(struct gspca_dev *gspca_dev)
754{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300755 struct sd *sd = (struct sd *) gspca_dev;
756
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300757 if (!gspca_dev->present)
758 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300759 if (sd->sensor == SENSOR_PAC7302) {
760 reg_w(gspca_dev, 0xff, 0x01);
761 reg_w(gspca_dev, 0x78, 0x40);
762 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763}
764
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300765/* Include pac common sof detection functions */
766#include "pac_common.h"
767
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300768static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300770 struct sd *sd = (struct sd *) gspca_dev;
771 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300772 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300773
774 if (avg_lum == -1)
775 return;
776
Hans de Goede038ec7c2008-09-03 17:12:18 -0300777 if (sd->sensor == SENSOR_PAC7302) {
778 desired_lum = 270 + sd->brightness * 4;
779 /* Hack hack, with the 7202 the first exposure step is
780 pretty large, so if we're about to make the first
781 exposure increase make the deadzone large to avoid
782 oscilating */
783 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
784 sd->exposure > EXPOSURE_DEF &&
785 sd->exposure < 42)
786 deadzone = 90;
787 else
788 deadzone = 30;
789 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300790 desired_lum = 200;
Hans de Goede038ec7c2008-09-03 17:12:18 -0300791 deadzone = 20;
792 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300793
794 if (sd->autogain_ignore_frames > 0)
795 sd->autogain_ignore_frames--;
796 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300797 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300798 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300799}
800
Hans de Goede327c4ab2008-09-03 17:12:14 -0300801static const unsigned char pac7311_jpeg_header1[] = {
802 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
803};
804
805static const unsigned char pac7311_jpeg_header2[] = {
806 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
807 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
808};
809
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300810/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811static void sd_pkt_scan(struct gspca_dev *gspca_dev,
812 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300813 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814 int len) /* iso packet length */
815{
816 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300817 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818
Hans de Goede327c4ab2008-09-03 17:12:14 -0300819 sof = pac_find_sof(gspca_dev, data, len);
820 if (sof) {
821 unsigned char tmpbuf[4];
822 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300823
Hans de Goede327c4ab2008-09-03 17:12:14 -0300824 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede038ec7c2008-09-03 17:12:18 -0300825 /* 6 bytes after the FF D9 EOF marker a number of lumination
826 bytes are send corresponding to different parts of the
827 image, the 14th and 15th byte after the EOF seem to
828 correspond to the center of the image */
829 lum_offset = 61 + sizeof pac_sof_marker;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300830 footer_length = 74;
831 } else {
832 lum_offset = 24 + sizeof pac_sof_marker;
833 footer_length = 26;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300834 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300835
836 /* Finish decoding current frame */
837 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
838 if (n < 0) {
839 frame->data_end += n;
840 n = 0;
841 }
842 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
843 data, n);
844 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
845 frame->data_end[-2] == 0xff &&
846 frame->data_end[-1] == 0xd9)
847 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
848 NULL, 0);
849
850 n = sof - data;
851 len -= n;
852 data = sof;
853
854 /* Get average lumination */
855 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300856 n >= lum_offset)
857 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300858 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300859 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300860 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300861
862 /* Start the new frame with the jpeg header */
863 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
864 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
865 if (sd->sensor == SENSOR_PAC7302) {
866 /* The PAC7302 has the image rotated 90 degrees */
867 tmpbuf[0] = gspca_dev->width >> 8;
868 tmpbuf[1] = gspca_dev->width & 0xff;
869 tmpbuf[2] = gspca_dev->height >> 8;
870 tmpbuf[3] = gspca_dev->height & 0xff;
871 } else {
872 tmpbuf[0] = gspca_dev->height >> 8;
873 tmpbuf[1] = gspca_dev->height & 0xff;
874 tmpbuf[2] = gspca_dev->width >> 8;
875 tmpbuf[3] = gspca_dev->width & 0xff;
876 }
877 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
878 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
879 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300880 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300881 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882}
883
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
885{
886 struct sd *sd = (struct sd *) gspca_dev;
887
888 sd->brightness = val;
889 if (gspca_dev->streaming)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300890 setbrightcont(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300891 return 0;
892}
893
894static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
895{
896 struct sd *sd = (struct sd *) gspca_dev;
897
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 *val = sd->brightness;
899 return 0;
900}
901
902static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
903{
904 struct sd *sd = (struct sd *) gspca_dev;
905
906 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300907 if (gspca_dev->streaming) {
908 if (sd->sensor == SENSOR_PAC7302)
909 setbrightcont(gspca_dev);
910 else
911 setcontrast(gspca_dev);
912 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 return 0;
914}
915
916static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
917{
918 struct sd *sd = (struct sd *) gspca_dev;
919
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920 *val = sd->contrast;
921 return 0;
922}
923
924static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
925{
926 struct sd *sd = (struct sd *) gspca_dev;
927
928 sd->colors = val;
929 if (gspca_dev->streaming)
930 setcolors(gspca_dev);
931 return 0;
932}
933
934static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
935{
936 struct sd *sd = (struct sd *) gspca_dev;
937
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300938 *val = sd->colors;
939 return 0;
940}
941
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300942static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
943{
944 struct sd *sd = (struct sd *) gspca_dev;
945
946 sd->gain = val;
947 if (gspca_dev->streaming)
948 setgain(gspca_dev);
949 return 0;
950}
951
952static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
953{
954 struct sd *sd = (struct sd *) gspca_dev;
955
956 *val = sd->gain;
957 return 0;
958}
959
960static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
961{
962 struct sd *sd = (struct sd *) gspca_dev;
963
964 sd->exposure = val;
965 if (gspca_dev->streaming)
966 setexposure(gspca_dev);
967 return 0;
968}
969
970static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
971{
972 struct sd *sd = (struct sd *) gspca_dev;
973
974 *val = sd->exposure;
975 return 0;
976}
977
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300978static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
979{
980 struct sd *sd = (struct sd *) gspca_dev;
981
982 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300983 /* when switching to autogain set defaults to make sure
984 we are on a valid point of the autogain gain /
985 exposure knee graph, and give this change time to
986 take effect before doing autogain. */
987 if (sd->autogain) {
988 sd->exposure = EXPOSURE_DEF;
989 sd->gain = GAIN_DEF;
990 if (gspca_dev->streaming) {
991 sd->autogain_ignore_frames =
992 PAC_AUTOGAIN_IGNORE_FRAMES;
993 setexposure(gspca_dev);
994 setgain(gspca_dev);
995 }
996 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300997
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 return 0;
999}
1000
1001static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1002{
1003 struct sd *sd = (struct sd *) gspca_dev;
1004
1005 *val = sd->autogain;
1006 return 0;
1007}
1008
Jean-Francois Moine41b46972008-09-03 16:47:58 -03001009static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1010{
1011 struct sd *sd = (struct sd *) gspca_dev;
1012
1013 sd->hflip = val;
1014 if (gspca_dev->streaming)
1015 sethvflip(gspca_dev);
1016 return 0;
1017}
1018
1019static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1020{
1021 struct sd *sd = (struct sd *) gspca_dev;
1022
1023 *val = sd->hflip;
1024 return 0;
1025}
1026
1027static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030
1031 sd->vflip = val;
1032 if (gspca_dev->streaming)
1033 sethvflip(gspca_dev);
1034 return 0;
1035}
1036
1037static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1038{
1039 struct sd *sd = (struct sd *) gspca_dev;
1040
1041 *val = sd->vflip;
1042 return 0;
1043}
1044
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045/* sub-driver description */
1046static struct sd_desc sd_desc = {
1047 .name = MODULE_NAME,
1048 .ctrls = sd_ctrls,
1049 .nctrls = ARRAY_SIZE(sd_ctrls),
1050 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001051 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052 .start = sd_start,
1053 .stopN = sd_stopN,
1054 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001056 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001057};
1058
1059/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001060static __devinitdata struct usb_device_id device_table[] = {
Stephane Marguet (Stemp)b5948be2009-08-25 04:14:04 -03001061 {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001062 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
1063 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
1064 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
1065 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
1066 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
1067 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
Hans de Goede71d50f32008-12-27 03:43:53 -03001068 {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001069 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine121520a2008-12-03 07:19:22 -03001070 {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
Hans de Goede8a5b2e92008-09-03 17:12:17 -03001071 {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine08627252008-09-03 17:12:17 -03001072 {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine3eed7822009-06-20 04:58:57 -03001073 {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
Hans de Goede40f17a72008-09-04 03:57:01 -03001074 {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
Jean-Francois Moineca8959b2008-12-15 04:12:57 -03001075 {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001076 {}
1077};
1078MODULE_DEVICE_TABLE(usb, device_table);
1079
1080/* -- device connect -- */
1081static int sd_probe(struct usb_interface *intf,
1082 const struct usb_device_id *id)
1083{
1084 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1085 THIS_MODULE);
1086}
1087
1088static struct usb_driver sd_driver = {
1089 .name = MODULE_NAME,
1090 .id_table = device_table,
1091 .probe = sd_probe,
1092 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001093#ifdef CONFIG_PM
1094 .suspend = gspca_suspend,
1095 .resume = gspca_resume,
1096#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001097};
1098
1099/* -- module insert / remove -- */
1100static int __init sd_mod_init(void)
1101{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001102 int ret;
1103 ret = usb_register(&sd_driver);
1104 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001105 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001106 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001107 return 0;
1108}
1109static void __exit sd_mod_exit(void)
1110{
1111 usb_deregister(&sd_driver);
1112 PDEBUG(D_PROBE, "deregistered");
1113}
1114
1115module_init(sd_mod_init);
1116module_exit(sd_mod_exit);