blob: 723219d4964e72751411d7f8f14a44a4bc2c43b3 [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 Moinec2446b32008-07-05 11:49:20 -0300229static 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 */
248static const __u8 probe_7302[] = {
249/* 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
319/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
320static const __u8 page3_7302[] = {
321 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
322 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
323 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
325 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
326 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
327 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
328 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
331 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
335 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
336 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
337 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
340 0x00
341};
342
343/* pac 7311 */
344static const __u8 probe_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300345 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
346 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
347 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300348 0xff, 0x04,
349 0x27, 0x80,
350 0x28, 0xca,
351 0x29, 0x53,
352 0x2a, 0x0e,
353 0xff, 0x01,
354 0x3e, 0x20,
355};
356
357static const __u8 start_7311[] = {
358/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300359 0xff, 1, 0x01, /* page 1 */
360 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300361 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
362 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
363 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300366 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300367 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
368 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
369 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
370 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
371 0xd0, 0xff,
372 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
373 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
374 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
375 0x18, 0x20,
376 0x96, 3, 0x01, 0x08, 0x04,
377 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
378 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
379 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300380 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300381 0x00, 254, /* load the page 4 */
382 0x11, 1, 0x01,
383 0, 0 /* end of sequence */
384};
385
386/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
387static const __u8 page4_7311[] = {
388 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
389 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
390 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300392 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300393 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
394 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
395};
396
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300397static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300398 __u8 index,
399 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300401 memcpy(gspca_dev->usb_buf, buffer, len);
402 usb_control_msg(gspca_dev->dev,
403 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300404 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300406 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300407 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408 500);
409}
410
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300412static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300413 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300414 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300416 gspca_dev->usb_buf[0] = value;
417 usb_control_msg(gspca_dev->dev,
418 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300419 0, /* request */
420 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300421 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300422 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423}
424
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300425static void reg_w_seq(struct gspca_dev *gspca_dev,
426 const __u8 *seq, int len)
427{
428 while (--len >= 0) {
429 reg_w(gspca_dev, seq[0], seq[1]);
430 seq += 2;
431 }
432}
433
434/* load the beginning of a page */
435static void reg_w_page(struct gspca_dev *gspca_dev,
436 const __u8 *page, int len)
437{
438 int index;
439
440 for (index = 0; index < len; index++) {
441 if (page[index] == 0xaa) /* skip this index */
442 continue;
443 gspca_dev->usb_buf[0] = page[index];
444 usb_control_msg(gspca_dev->dev,
445 usb_sndctrlpipe(gspca_dev->dev, 0),
446 0, /* request */
447 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
448 0, index, gspca_dev->usb_buf, 1,
449 500);
450 }
451}
452
453/* output a variable sequence */
454static void reg_w_var(struct gspca_dev *gspca_dev,
455 const __u8 *seq)
456{
457 int index, len;
458
459 for (;;) {
460 index = *seq++;
461 len = *seq++;
462 switch (len) {
463 case 0:
464 return;
465 case 254:
466 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
467 break;
468 case 255:
469 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
470 break;
471 default:
Hans de Goede327c4ab2008-09-03 17:12:14 -0300472 if (len > 64) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300473 PDEBUG(D_ERR|D_STREAM,
474 "Incorrect variable sequence");
475 return;
476 }
477 while (len > 0) {
478 if (len < 8) {
479 reg_w_buf(gspca_dev, index, seq, len);
480 seq += len;
481 break;
482 }
483 reg_w_buf(gspca_dev, index, seq, 8);
484 seq += 8;
485 index += 8;
486 len -= 8;
487 }
488 }
489 }
490 /* not reached */
491}
492
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493/* this function is called at probe time */
494static int sd_config(struct gspca_dev *gspca_dev,
495 const struct usb_device_id *id)
496{
497 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498 struct cam *cam;
499
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 cam->epaddr = 0x05;
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");
506 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
507
508 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
509 cam->nmodes = 1;
510 } else {
511 PDEBUG(D_CONF, "Find Sensor PAC7311");
Hans de Goede327c4ab2008-09-03 17:12:14 -0300512 reg_w_seq(gspca_dev, probe_7311, sizeof probe_7311);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300513
514 cam->cam_mode = vga_mode;
515 cam->nmodes = ARRAY_SIZE(vga_mode);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300516 gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
517 | (1 << SATURATION_IDX);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300518 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300520 sd->brightness = BRIGHTNESS_DEF;
521 sd->contrast = CONTRAST_DEF;
522 sd->colors = COLOR_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300523 sd->gain = GAIN_DEF;
524 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300525 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300526 sd->hflip = HFLIP_DEF;
527 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 return 0;
529}
530
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300531/* This function is used by pac7302 only */
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300532static void setbrightcont(struct gspca_dev *gspca_dev)
533{
534 struct sd *sd = (struct sd *) gspca_dev;
535 int i, v;
536 static const __u8 max[10] =
537 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
538 0xd4, 0xec};
539 static const __u8 delta[10] =
540 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
541 0x11, 0x0b};
542
543 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
544 for (i = 0; i < 10; i++) {
545 v = max[i];
546 v += (sd->brightness - BRIGHTNESS_MAX)
547 * 150 / BRIGHTNESS_MAX; /* 200 ? */
548 v -= delta[i] * sd->contrast / CONTRAST_MAX;
549 if (v < 0)
550 v = 0;
551 else if (v > 0xff)
552 v = 0xff;
553 reg_w(gspca_dev, 0xa2 + i, v);
554 }
555 reg_w(gspca_dev, 0xdc, 0x01);
556}
557
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300558/* This function is used by pac7311 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300559static void setcontrast(struct gspca_dev *gspca_dev)
560{
561 struct sd *sd = (struct sd *) gspca_dev;
562
Hans de Goede327c4ab2008-09-03 17:12:14 -0300563 reg_w(gspca_dev, 0xff, 0x04);
564 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300565 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300566 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567}
568
Hans de Goede327c4ab2008-09-03 17:12:14 -0300569/* This function is used by pac7302 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570static void setcolors(struct gspca_dev *gspca_dev)
571{
572 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300573 int i, v;
574 static const int a[9] =
575 {217, -212, 0, -101, 170, -67, -38, -315, 355};
576 static const int b[9] =
577 {19, 106, 0, 19, 106, 1, 19, 106, 1};
578
579 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
580 reg_w(gspca_dev, 0x11, 0x01);
581 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
582 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
583 for (i = 0; i < 9; i++) {
584 v = a[i] * sd->colors / COLOR_MAX + b[i];
585 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
586 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
587 }
588 reg_w(gspca_dev, 0xdc, 0x01);
589 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
590}
591
592static void setgain(struct gspca_dev *gspca_dev)
593{
594 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300596 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300597 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
598 reg_w(gspca_dev, 0x10, sd->gain >> 3);
599 } else {
600 int gain = GAIN_MAX - sd->gain;
601 if (gain < 1)
602 gain = 1;
603 else if (gain > 245)
604 gain = 245;
605 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
606 reg_w(gspca_dev, 0x0e, 0x00);
607 reg_w(gspca_dev, 0x0f, gain);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300608 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300609 /* load registers to sensor (Bit 0, auto clear) */
610 reg_w(gspca_dev, 0x11, 0x01);
611}
612
613static void setexposure(struct gspca_dev *gspca_dev)
614{
615 struct sd *sd = (struct sd *) gspca_dev;
616 __u8 reg;
617
618 /* register 2 of frame 3/4 contains the clock divider configuring the
619 no fps according to the formula: 60 / reg. sd->exposure is the
620 desired exposure time in ms. */
621 reg = 120 * sd->exposure / 1000;
622 if (reg < 2)
623 reg = 2;
624 else if (reg > 63)
625 reg = 63;
626
627 if (sd->sensor == SENSOR_PAC7302) {
628 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
Hans de Goede038ec7c2008-09-03 17:12:18 -0300629 the nearest multiple of 3, except when between 6 and 12? */
630 if (reg < 6 || reg > 12)
631 reg = ((reg + 1) / 3) * 3;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300632 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
633 reg_w(gspca_dev, 0x02, reg);
634 } else {
635 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
636 reg_w(gspca_dev, 0x02, reg);
637 /* Page 1 register 8 must always be 0x08 except when not in
638 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
639 reg_w(gspca_dev, 0xff, 0x01);
640 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
641 reg <= 3)
642 reg_w(gspca_dev, 0x08, 0x09);
643 else
644 reg_w(gspca_dev, 0x08, 0x08);
645 }
646 /* load registers to sensor (Bit 0, auto clear) */
647 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300648}
649
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300650static void sethvflip(struct gspca_dev *gspca_dev)
651{
652 struct sd *sd = (struct sd *) gspca_dev;
653 __u8 data;
654
Hans de Goede327c4ab2008-09-03 17:12:14 -0300655 if (sd->sensor == SENSOR_PAC7302) {
656 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300657 data = (sd->hflip ? 0x08 : 0x00)
Hans de Goede327c4ab2008-09-03 17:12:14 -0300658 | (sd->vflip ? 0x04 : 0x00);
659 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300660 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300661 data = (sd->hflip ? 0x04 : 0x00)
662 | (sd->vflip ? 0x08 : 0x00);
663 }
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300664 reg_w(gspca_dev, 0x21, data);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300665 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300666 reg_w(gspca_dev, 0x11, 0x01);
667}
668
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300669/* this function is called at probe and resume time */
670static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672 return 0;
673}
674
675static void sd_start(struct gspca_dev *gspca_dev)
676{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300677 struct sd *sd = (struct sd *) gspca_dev;
678
Hans de Goede327c4ab2008-09-03 17:12:14 -0300679 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300681 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300682 reg_w_var(gspca_dev, start_7302);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300683 setbrightcont(gspca_dev);
684 setcolors(gspca_dev);
685 } else {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300686 reg_w_var(gspca_dev, start_7311);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300687 setcontrast(gspca_dev);
688 }
689 setgain(gspca_dev);
690 setexposure(gspca_dev);
691 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692
693 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300694 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300695 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300696 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300697 reg_w(gspca_dev, 0x17, 0x20);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300698 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300700 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300701 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300702 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 break;
705 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300706 if (sd->sensor == SENSOR_PAC7302)
707 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300708 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300709 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300710 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711 break;
712 }
713
Hans de Goede327c4ab2008-09-03 17:12:14 -0300714 sd->sof_read = 0;
715 sd->autogain_ignore_frames = 0;
716 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300717
718 /* start stream */
719 reg_w(gspca_dev, 0xff, 0x01);
720 if (sd->sensor == SENSOR_PAC7302)
721 reg_w(gspca_dev, 0x78, 0x01);
722 else
723 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724}
725
726static void sd_stopN(struct gspca_dev *gspca_dev)
727{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300728 struct sd *sd = (struct sd *) gspca_dev;
729
730 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300731 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300732 reg_w(gspca_dev, 0x78, 0x00);
733 reg_w(gspca_dev, 0x78, 0x00);
734 return;
735 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300736 reg_w(gspca_dev, 0xff, 0x04);
737 reg_w(gspca_dev, 0x27, 0x80);
738 reg_w(gspca_dev, 0x28, 0xca);
739 reg_w(gspca_dev, 0x29, 0x53);
740 reg_w(gspca_dev, 0x2a, 0x0e);
741 reg_w(gspca_dev, 0xff, 0x01);
742 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300743 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
744 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
745 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300746}
747
748static void sd_stop0(struct gspca_dev *gspca_dev)
749{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300750 struct sd *sd = (struct sd *) gspca_dev;
751
752 if (sd->sensor == SENSOR_PAC7302) {
753 reg_w(gspca_dev, 0xff, 0x01);
754 reg_w(gspca_dev, 0x78, 0x40);
755 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756}
757
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300758/* Include pac common sof detection functions */
759#include "pac_common.h"
760
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300761static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300763 struct sd *sd = (struct sd *) gspca_dev;
764 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300765 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300766
767 if (avg_lum == -1)
768 return;
769
Hans de Goede038ec7c2008-09-03 17:12:18 -0300770 if (sd->sensor == SENSOR_PAC7302) {
771 desired_lum = 270 + sd->brightness * 4;
772 /* Hack hack, with the 7202 the first exposure step is
773 pretty large, so if we're about to make the first
774 exposure increase make the deadzone large to avoid
775 oscilating */
776 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
777 sd->exposure > EXPOSURE_DEF &&
778 sd->exposure < 42)
779 deadzone = 90;
780 else
781 deadzone = 30;
782 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300783 desired_lum = 200;
Hans de Goede038ec7c2008-09-03 17:12:18 -0300784 deadzone = 20;
785 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300786
787 if (sd->autogain_ignore_frames > 0)
788 sd->autogain_ignore_frames--;
789 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300790 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300791 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792}
793
Hans de Goede327c4ab2008-09-03 17:12:14 -0300794static const unsigned char pac7311_jpeg_header1[] = {
795 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
796};
797
798static const unsigned char pac7311_jpeg_header2[] = {
799 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
800 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
801};
802
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300803/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804static void sd_pkt_scan(struct gspca_dev *gspca_dev,
805 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300806 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 int len) /* iso packet length */
808{
809 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300810 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811
Hans de Goede327c4ab2008-09-03 17:12:14 -0300812 sof = pac_find_sof(gspca_dev, data, len);
813 if (sof) {
814 unsigned char tmpbuf[4];
815 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300816
Hans de Goede327c4ab2008-09-03 17:12:14 -0300817 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede038ec7c2008-09-03 17:12:18 -0300818 /* 6 bytes after the FF D9 EOF marker a number of lumination
819 bytes are send corresponding to different parts of the
820 image, the 14th and 15th byte after the EOF seem to
821 correspond to the center of the image */
822 lum_offset = 61 + sizeof pac_sof_marker;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300823 footer_length = 74;
824 } else {
825 lum_offset = 24 + sizeof pac_sof_marker;
826 footer_length = 26;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300828
829 /* Finish decoding current frame */
830 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
831 if (n < 0) {
832 frame->data_end += n;
833 n = 0;
834 }
835 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
836 data, n);
837 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
838 frame->data_end[-2] == 0xff &&
839 frame->data_end[-1] == 0xd9)
840 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
841 NULL, 0);
842
843 n = sof - data;
844 len -= n;
845 data = sof;
846
847 /* Get average lumination */
848 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300849 n >= lum_offset)
850 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300851 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300852 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300853 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300854
855 /* Start the new frame with the jpeg header */
856 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
857 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
858 if (sd->sensor == SENSOR_PAC7302) {
859 /* The PAC7302 has the image rotated 90 degrees */
860 tmpbuf[0] = gspca_dev->width >> 8;
861 tmpbuf[1] = gspca_dev->width & 0xff;
862 tmpbuf[2] = gspca_dev->height >> 8;
863 tmpbuf[3] = gspca_dev->height & 0xff;
864 } else {
865 tmpbuf[0] = gspca_dev->height >> 8;
866 tmpbuf[1] = gspca_dev->height & 0xff;
867 tmpbuf[2] = gspca_dev->width >> 8;
868 tmpbuf[3] = gspca_dev->width & 0xff;
869 }
870 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
871 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
872 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300873 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300874 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875}
876
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300877static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
878{
879 struct sd *sd = (struct sd *) gspca_dev;
880
881 sd->brightness = val;
882 if (gspca_dev->streaming)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300883 setbrightcont(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884 return 0;
885}
886
887static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
888{
889 struct sd *sd = (struct sd *) gspca_dev;
890
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300891 *val = sd->brightness;
892 return 0;
893}
894
895static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
896{
897 struct sd *sd = (struct sd *) gspca_dev;
898
899 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300900 if (gspca_dev->streaming) {
901 if (sd->sensor == SENSOR_PAC7302)
902 setbrightcont(gspca_dev);
903 else
904 setcontrast(gspca_dev);
905 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906 return 0;
907}
908
909static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
910{
911 struct sd *sd = (struct sd *) gspca_dev;
912
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 *val = sd->contrast;
914 return 0;
915}
916
917static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
918{
919 struct sd *sd = (struct sd *) gspca_dev;
920
921 sd->colors = val;
922 if (gspca_dev->streaming)
923 setcolors(gspca_dev);
924 return 0;
925}
926
927static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
928{
929 struct sd *sd = (struct sd *) gspca_dev;
930
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300931 *val = sd->colors;
932 return 0;
933}
934
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300935static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
936{
937 struct sd *sd = (struct sd *) gspca_dev;
938
939 sd->gain = val;
940 if (gspca_dev->streaming)
941 setgain(gspca_dev);
942 return 0;
943}
944
945static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
946{
947 struct sd *sd = (struct sd *) gspca_dev;
948
949 *val = sd->gain;
950 return 0;
951}
952
953static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
954{
955 struct sd *sd = (struct sd *) gspca_dev;
956
957 sd->exposure = val;
958 if (gspca_dev->streaming)
959 setexposure(gspca_dev);
960 return 0;
961}
962
963static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
964{
965 struct sd *sd = (struct sd *) gspca_dev;
966
967 *val = sd->exposure;
968 return 0;
969}
970
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
972{
973 struct sd *sd = (struct sd *) gspca_dev;
974
975 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300976 /* when switching to autogain set defaults to make sure
977 we are on a valid point of the autogain gain /
978 exposure knee graph, and give this change time to
979 take effect before doing autogain. */
980 if (sd->autogain) {
981 sd->exposure = EXPOSURE_DEF;
982 sd->gain = GAIN_DEF;
983 if (gspca_dev->streaming) {
984 sd->autogain_ignore_frames =
985 PAC_AUTOGAIN_IGNORE_FRAMES;
986 setexposure(gspca_dev);
987 setgain(gspca_dev);
988 }
989 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300990
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 return 0;
992}
993
994static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
995{
996 struct sd *sd = (struct sd *) gspca_dev;
997
998 *val = sd->autogain;
999 return 0;
1000}
1001
Jean-Francois Moine41b46972008-09-03 16:47:58 -03001002static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1003{
1004 struct sd *sd = (struct sd *) gspca_dev;
1005
1006 sd->hflip = val;
1007 if (gspca_dev->streaming)
1008 sethvflip(gspca_dev);
1009 return 0;
1010}
1011
1012static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1013{
1014 struct sd *sd = (struct sd *) gspca_dev;
1015
1016 *val = sd->hflip;
1017 return 0;
1018}
1019
1020static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1021{
1022 struct sd *sd = (struct sd *) gspca_dev;
1023
1024 sd->vflip = val;
1025 if (gspca_dev->streaming)
1026 sethvflip(gspca_dev);
1027 return 0;
1028}
1029
1030static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1031{
1032 struct sd *sd = (struct sd *) gspca_dev;
1033
1034 *val = sd->vflip;
1035 return 0;
1036}
1037
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001038/* sub-driver description */
1039static struct sd_desc sd_desc = {
1040 .name = MODULE_NAME,
1041 .ctrls = sd_ctrls,
1042 .nctrls = ARRAY_SIZE(sd_ctrls),
1043 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001044 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045 .start = sd_start,
1046 .stopN = sd_stopN,
1047 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001048 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001049 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050};
1051
1052/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001053static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001054 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
1055 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
1056 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
1057 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
1058 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
1059 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
1060 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Hans de Goede8a5b2e92008-09-03 17:12:17 -03001061 {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine08627252008-09-03 17:12:17 -03001062 {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001063 {}
1064};
1065MODULE_DEVICE_TABLE(usb, device_table);
1066
1067/* -- device connect -- */
1068static int sd_probe(struct usb_interface *intf,
1069 const struct usb_device_id *id)
1070{
1071 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1072 THIS_MODULE);
1073}
1074
1075static struct usb_driver sd_driver = {
1076 .name = MODULE_NAME,
1077 .id_table = device_table,
1078 .probe = sd_probe,
1079 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001080#ifdef CONFIG_PM
1081 .suspend = gspca_suspend,
1082 .resume = gspca_resume,
1083#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001084};
1085
1086/* -- module insert / remove -- */
1087static int __init sd_mod_init(void)
1088{
1089 if (usb_register(&sd_driver) < 0)
1090 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001091 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001092 return 0;
1093}
1094static void __exit sd_mod_exit(void)
1095{
1096 usb_deregister(&sd_driver);
1097 PDEBUG(D_PROBE, "deregistered");
1098}
1099
1100module_init(sd_mod_init);
1101module_exit(sd_mod_exit);