blob: a3fbd307bb76e64ab3d078d08d4a35a581be6c20 [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
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300247#define LOAD_PAGE3 255
248#define LOAD_PAGE4 254
249#define END_OF_SEQUENCE 0
250
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300251/* pac 7302 */
Hans de Goede271315a2008-09-03 17:12:19 -0300252static const __u8 init_7302[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300253/* index,value */
254 0xff, 0x01, /* page 1 */
255 0x78, 0x00, /* deactivate */
256 0xff, 0x01,
257 0x78, 0x40, /* led off */
258};
259static const __u8 start_7302[] = {
260/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300261 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300262 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
263 0x00, 0x00, 0x00, 0x00,
264 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
265 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
266 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
267 0x26, 2, 0xaa, 0xaa,
268 0x2e, 1, 0x31,
269 0x38, 1, 0x01,
270 0x3a, 3, 0x14, 0xff, 0x5a,
271 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
272 0x00, 0x54, 0x11,
273 0x55, 1, 0x00,
274 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
275 0x6b, 1, 0x00,
276 0x6e, 3, 0x08, 0x06, 0x00,
277 0x72, 3, 0x00, 0xff, 0x00,
278 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
279 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
280 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
281 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
282 0xd2, 0xeb,
283 0xaf, 1, 0x02,
284 0xb5, 2, 0x08, 0x08,
285 0xb8, 2, 0x08, 0x88,
286 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
287 0xcc, 1, 0x00,
288 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
289 0xc1, 0xd7, 0xec,
290 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300291 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300292 0x12, 3, 0x02, 0x00, 0x01,
293 0x3e, 2, 0x00, 0x00,
294 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
295 0x7c, 1, 0x00,
296 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
297 0x02, 0x00,
298 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300299 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300300 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300301 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300302 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300303 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300304 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
305 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300306 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300307 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300308 0xff, 1, 0x03, /* page 3 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300309 0, LOAD_PAGE3, /* load the page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300310 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300311 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300312 0x13, 1, 0x00,
313 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
314 0x27, 2, 0x14, 0x0c,
315 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
316 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
317 0x6e, 1, 0x08,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300318 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300319 0x78, 1, 0x00,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300320 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300321};
322
Marton Nemethff75e992009-10-04 13:51:26 -0300323#define SKIP 0xaa
324/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300325static const __u8 page3_7302[] = {
326 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
327 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
328 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
330 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
331 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
332 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
333 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
336 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
340 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
341 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
342 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
345 0x00
346};
347
348/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300349static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300350 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
351 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
352 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300353 0xff, 0x04,
354 0x27, 0x80,
355 0x28, 0xca,
356 0x29, 0x53,
357 0x2a, 0x0e,
358 0xff, 0x01,
359 0x3e, 0x20,
360};
361
362static const __u8 start_7311[] = {
363/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300364 0xff, 1, 0x01, /* page 1 */
365 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300366 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
367 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
368 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300371 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300372 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
373 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
374 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
375 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
376 0xd0, 0xff,
377 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
378 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
379 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
380 0x18, 0x20,
381 0x96, 3, 0x01, 0x08, 0x04,
382 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
383 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
384 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300385 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300386 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300387 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300388 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300389};
390
Marton Nemethff75e992009-10-04 13:51:26 -0300391/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300392static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300393 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
394 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
395 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
397 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300398 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
399 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
400};
401
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300402static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300403 __u8 index,
404 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300406 memcpy(gspca_dev->usb_buf, buffer, len);
407 usb_control_msg(gspca_dev->dev,
408 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300409 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300411 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300412 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300413 500);
414}
415
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300417static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300418 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300419 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300421 gspca_dev->usb_buf[0] = value;
422 usb_control_msg(gspca_dev->dev,
423 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300424 0, /* request */
425 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300426 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300427 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428}
429
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300430static void reg_w_seq(struct gspca_dev *gspca_dev,
431 const __u8 *seq, int len)
432{
433 while (--len >= 0) {
434 reg_w(gspca_dev, seq[0], seq[1]);
435 seq += 2;
436 }
437}
438
439/* load the beginning of a page */
440static void reg_w_page(struct gspca_dev *gspca_dev,
441 const __u8 *page, int len)
442{
443 int index;
444
445 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300446 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300447 continue;
448 gspca_dev->usb_buf[0] = page[index];
449 usb_control_msg(gspca_dev->dev,
450 usb_sndctrlpipe(gspca_dev->dev, 0),
451 0, /* request */
452 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
453 0, index, gspca_dev->usb_buf, 1,
454 500);
455 }
456}
457
458/* output a variable sequence */
459static void reg_w_var(struct gspca_dev *gspca_dev,
460 const __u8 *seq)
461{
462 int index, len;
463
464 for (;;) {
465 index = *seq++;
466 len = *seq++;
467 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300468 case END_OF_SEQUENCE:
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300469 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300470 case LOAD_PAGE4:
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300471 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
472 break;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300473 case LOAD_PAGE3:
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300474 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
475 break;
476 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300477 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300478 PDEBUG(D_ERR|D_STREAM,
479 "Incorrect variable sequence");
480 return;
481 }
482 while (len > 0) {
483 if (len < 8) {
484 reg_w_buf(gspca_dev, index, seq, len);
485 seq += len;
486 break;
487 }
488 reg_w_buf(gspca_dev, index, seq, 8);
489 seq += 8;
490 index += 8;
491 len -= 8;
492 }
493 }
494 }
495 /* not reached */
496}
497
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498/* this function is called at probe time */
499static int sd_config(struct gspca_dev *gspca_dev,
500 const struct usb_device_id *id)
501{
502 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 struct cam *cam;
504
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300506
507 sd->sensor = id->driver_info;
508 if (sd->sensor == SENSOR_PAC7302) {
509 PDEBUG(D_CONF, "Find Sensor PAC7302");
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300510 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
511 cam->nmodes = 1;
512 } else {
513 PDEBUG(D_CONF, "Find Sensor PAC7311");
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300514 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 */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300582 for (i = 0; i < 9; i++) {
583 v = a[i] * sd->colors / COLOR_MAX + b[i];
584 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
585 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
586 }
587 reg_w(gspca_dev, 0xdc, 0x01);
588 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
589}
590
591static void setgain(struct gspca_dev *gspca_dev)
592{
593 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300594
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300595 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300596 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
597 reg_w(gspca_dev, 0x10, sd->gain >> 3);
598 } else {
599 int gain = GAIN_MAX - sd->gain;
600 if (gain < 1)
601 gain = 1;
602 else if (gain > 245)
603 gain = 245;
604 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
605 reg_w(gspca_dev, 0x0e, 0x00);
606 reg_w(gspca_dev, 0x0f, gain);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300607 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300608 /* load registers to sensor (Bit 0, auto clear) */
609 reg_w(gspca_dev, 0x11, 0x01);
610}
611
612static void setexposure(struct gspca_dev *gspca_dev)
613{
614 struct sd *sd = (struct sd *) gspca_dev;
615 __u8 reg;
616
617 /* register 2 of frame 3/4 contains the clock divider configuring the
618 no fps according to the formula: 60 / reg. sd->exposure is the
619 desired exposure time in ms. */
620 reg = 120 * sd->exposure / 1000;
621 if (reg < 2)
622 reg = 2;
623 else if (reg > 63)
624 reg = 63;
625
626 if (sd->sensor == SENSOR_PAC7302) {
627 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
Hans de Goede038ec7c2008-09-03 17:12:18 -0300628 the nearest multiple of 3, except when between 6 and 12? */
629 if (reg < 6 || reg > 12)
630 reg = ((reg + 1) / 3) * 3;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300631 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
632 reg_w(gspca_dev, 0x02, reg);
633 } else {
634 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
635 reg_w(gspca_dev, 0x02, reg);
636 /* Page 1 register 8 must always be 0x08 except when not in
637 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
638 reg_w(gspca_dev, 0xff, 0x01);
639 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
640 reg <= 3)
641 reg_w(gspca_dev, 0x08, 0x09);
642 else
643 reg_w(gspca_dev, 0x08, 0x08);
644 }
645 /* load registers to sensor (Bit 0, auto clear) */
646 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300647}
648
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300649static void sethvflip(struct gspca_dev *gspca_dev)
650{
651 struct sd *sd = (struct sd *) gspca_dev;
652 __u8 data;
653
Hans de Goede327c4ab2008-09-03 17:12:14 -0300654 if (sd->sensor == SENSOR_PAC7302) {
655 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300656 data = (sd->hflip ? 0x08 : 0x00)
Hans de Goede327c4ab2008-09-03 17:12:14 -0300657 | (sd->vflip ? 0x04 : 0x00);
658 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300659 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300660 data = (sd->hflip ? 0x04 : 0x00)
661 | (sd->vflip ? 0x08 : 0x00);
662 }
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300663 reg_w(gspca_dev, 0x21, data);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300664 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300665 reg_w(gspca_dev, 0x11, 0x01);
666}
667
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300668/* this function is called at probe and resume time */
669static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670{
Hans de Goede271315a2008-09-03 17:12:19 -0300671 struct sd *sd = (struct sd *) gspca_dev;
672
673 if (sd->sensor == SENSOR_PAC7302)
674 reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
675 else
676 reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
677
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678 return 0;
679}
680
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300681static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300683 struct sd *sd = (struct sd *) gspca_dev;
684
Hans de Goede327c4ab2008-09-03 17:12:14 -0300685 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300687 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300688 reg_w_var(gspca_dev, start_7302);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300689 setbrightcont(gspca_dev);
690 setcolors(gspca_dev);
691 } else {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300692 reg_w_var(gspca_dev, start_7311);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300693 setcontrast(gspca_dev);
694 }
695 setgain(gspca_dev);
696 setexposure(gspca_dev);
697 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698
699 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300700 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300701 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300702 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 reg_w(gspca_dev, 0x17, 0x20);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300704 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300706 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300707 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300708 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300709 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710 break;
711 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300712 if (sd->sensor == SENSOR_PAC7302)
713 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300714 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300715 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300716 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717 break;
718 }
719
Hans de Goede327c4ab2008-09-03 17:12:14 -0300720 sd->sof_read = 0;
721 sd->autogain_ignore_frames = 0;
722 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300723
724 /* start stream */
725 reg_w(gspca_dev, 0xff, 0x01);
726 if (sd->sensor == SENSOR_PAC7302)
727 reg_w(gspca_dev, 0x78, 0x01);
728 else
729 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300730 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731}
732
733static void sd_stopN(struct gspca_dev *gspca_dev)
734{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300735 struct sd *sd = (struct sd *) gspca_dev;
736
737 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300738 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300739 reg_w(gspca_dev, 0x78, 0x00);
740 reg_w(gspca_dev, 0x78, 0x00);
741 return;
742 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300743 reg_w(gspca_dev, 0xff, 0x04);
744 reg_w(gspca_dev, 0x27, 0x80);
745 reg_w(gspca_dev, 0x28, 0xca);
746 reg_w(gspca_dev, 0x29, 0x53);
747 reg_w(gspca_dev, 0x2a, 0x0e);
748 reg_w(gspca_dev, 0xff, 0x01);
749 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300750 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
751 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
752 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300753}
754
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300755/* called on streamoff with alt 0 and on disconnect */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756static void sd_stop0(struct gspca_dev *gspca_dev)
757{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300758 struct sd *sd = (struct sd *) gspca_dev;
759
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300760 if (!gspca_dev->present)
761 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300762 if (sd->sensor == SENSOR_PAC7302) {
763 reg_w(gspca_dev, 0xff, 0x01);
764 reg_w(gspca_dev, 0x78, 0x40);
765 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300766}
767
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300768/* Include pac common sof detection functions */
769#include "pac_common.h"
770
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300771static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300773 struct sd *sd = (struct sd *) gspca_dev;
774 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300775 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300776
777 if (avg_lum == -1)
778 return;
779
Hans de Goede038ec7c2008-09-03 17:12:18 -0300780 if (sd->sensor == SENSOR_PAC7302) {
781 desired_lum = 270 + sd->brightness * 4;
782 /* Hack hack, with the 7202 the first exposure step is
783 pretty large, so if we're about to make the first
784 exposure increase make the deadzone large to avoid
785 oscilating */
786 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
787 sd->exposure > EXPOSURE_DEF &&
788 sd->exposure < 42)
789 deadzone = 90;
790 else
791 deadzone = 30;
792 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300793 desired_lum = 200;
Hans de Goede038ec7c2008-09-03 17:12:18 -0300794 deadzone = 20;
795 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300796
797 if (sd->autogain_ignore_frames > 0)
798 sd->autogain_ignore_frames--;
799 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300800 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300801 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300802}
803
Marton Nemeth56f6f552009-10-04 13:58:19 -0300804/* JPEG header, part 1 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300805static const unsigned char pac7311_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300806 0xff, 0xd8, /* SOI: Start of Image */
807
808 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
809 0x00, 0x11, /* length = 17 bytes (including this length field) */
810 0x08 /* Precision: 8 */
811 /* 2 bytes is placed here: number of image lines */
812 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300813};
814
Marton Nemeth56f6f552009-10-04 13:58:19 -0300815/* JPEG header, continued */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300816static const unsigned char pac7311_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300817 0x03, /* Number of image components: 3 */
818 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
819 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
820 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
821
822 0xff, 0xda, /* SOS: Start Of Scan */
823 0x00, 0x0c, /* length = 12 bytes (including this length field) */
824 0x03, /* number of components: 3 */
825 0x01, 0x00, /* selector 1, table 0x00 */
826 0x02, 0x11, /* selector 2, table 0x11 */
827 0x03, 0x11, /* selector 3, table 0x11 */
828 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
829 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300830};
831
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300832/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833static void sd_pkt_scan(struct gspca_dev *gspca_dev,
834 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300835 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 int len) /* iso packet length */
837{
838 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300839 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840
Hans de Goede327c4ab2008-09-03 17:12:14 -0300841 sof = pac_find_sof(gspca_dev, data, len);
842 if (sof) {
843 unsigned char tmpbuf[4];
844 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300845
Hans de Goede327c4ab2008-09-03 17:12:14 -0300846 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede038ec7c2008-09-03 17:12:18 -0300847 /* 6 bytes after the FF D9 EOF marker a number of lumination
848 bytes are send corresponding to different parts of the
849 image, the 14th and 15th byte after the EOF seem to
850 correspond to the center of the image */
851 lum_offset = 61 + sizeof pac_sof_marker;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300852 footer_length = 74;
853 } else {
854 lum_offset = 24 + sizeof pac_sof_marker;
855 footer_length = 26;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300857
858 /* Finish decoding current frame */
859 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
860 if (n < 0) {
861 frame->data_end += n;
862 n = 0;
863 }
864 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
865 data, n);
866 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
867 frame->data_end[-2] == 0xff &&
868 frame->data_end[-1] == 0xd9)
869 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
870 NULL, 0);
871
872 n = sof - data;
873 len -= n;
874 data = sof;
875
876 /* Get average lumination */
877 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300878 n >= lum_offset)
879 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300880 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300881 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300882 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300883
884 /* Start the new frame with the jpeg header */
885 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
886 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
887 if (sd->sensor == SENSOR_PAC7302) {
888 /* The PAC7302 has the image rotated 90 degrees */
889 tmpbuf[0] = gspca_dev->width >> 8;
890 tmpbuf[1] = gspca_dev->width & 0xff;
891 tmpbuf[2] = gspca_dev->height >> 8;
892 tmpbuf[3] = gspca_dev->height & 0xff;
893 } else {
894 tmpbuf[0] = gspca_dev->height >> 8;
895 tmpbuf[1] = gspca_dev->height & 0xff;
896 tmpbuf[2] = gspca_dev->width >> 8;
897 tmpbuf[3] = gspca_dev->width & 0xff;
898 }
899 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
900 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
901 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300903 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904}
905
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
907{
908 struct sd *sd = (struct sd *) gspca_dev;
909
910 sd->brightness = val;
911 if (gspca_dev->streaming)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300912 setbrightcont(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 return 0;
914}
915
916static int sd_getbrightness(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->brightness;
921 return 0;
922}
923
924static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
925{
926 struct sd *sd = (struct sd *) gspca_dev;
927
928 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300929 if (gspca_dev->streaming) {
930 if (sd->sensor == SENSOR_PAC7302)
931 setbrightcont(gspca_dev);
932 else
933 setcontrast(gspca_dev);
934 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300935 return 0;
936}
937
938static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
939{
940 struct sd *sd = (struct sd *) gspca_dev;
941
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300942 *val = sd->contrast;
943 return 0;
944}
945
946static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
947{
948 struct sd *sd = (struct sd *) gspca_dev;
949
950 sd->colors = val;
951 if (gspca_dev->streaming)
952 setcolors(gspca_dev);
953 return 0;
954}
955
956static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
957{
958 struct sd *sd = (struct sd *) gspca_dev;
959
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300960 *val = sd->colors;
961 return 0;
962}
963
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300964static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
965{
966 struct sd *sd = (struct sd *) gspca_dev;
967
968 sd->gain = val;
969 if (gspca_dev->streaming)
970 setgain(gspca_dev);
971 return 0;
972}
973
974static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
975{
976 struct sd *sd = (struct sd *) gspca_dev;
977
978 *val = sd->gain;
979 return 0;
980}
981
982static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
983{
984 struct sd *sd = (struct sd *) gspca_dev;
985
986 sd->exposure = val;
987 if (gspca_dev->streaming)
988 setexposure(gspca_dev);
989 return 0;
990}
991
992static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
993{
994 struct sd *sd = (struct sd *) gspca_dev;
995
996 *val = sd->exposure;
997 return 0;
998}
999
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001000static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1001{
1002 struct sd *sd = (struct sd *) gspca_dev;
1003
1004 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -03001005 /* when switching to autogain set defaults to make sure
1006 we are on a valid point of the autogain gain /
1007 exposure knee graph, and give this change time to
1008 take effect before doing autogain. */
1009 if (sd->autogain) {
1010 sd->exposure = EXPOSURE_DEF;
1011 sd->gain = GAIN_DEF;
1012 if (gspca_dev->streaming) {
1013 sd->autogain_ignore_frames =
1014 PAC_AUTOGAIN_IGNORE_FRAMES;
1015 setexposure(gspca_dev);
1016 setgain(gspca_dev);
1017 }
1018 }
Hans de Goede327c4ab2008-09-03 17:12:14 -03001019
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001020 return 0;
1021}
1022
1023static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
1026
1027 *val = sd->autogain;
1028 return 0;
1029}
1030
Jean-Francois Moine41b46972008-09-03 16:47:58 -03001031static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1032{
1033 struct sd *sd = (struct sd *) gspca_dev;
1034
1035 sd->hflip = val;
1036 if (gspca_dev->streaming)
1037 sethvflip(gspca_dev);
1038 return 0;
1039}
1040
1041static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1042{
1043 struct sd *sd = (struct sd *) gspca_dev;
1044
1045 *val = sd->hflip;
1046 return 0;
1047}
1048
1049static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1050{
1051 struct sd *sd = (struct sd *) gspca_dev;
1052
1053 sd->vflip = val;
1054 if (gspca_dev->streaming)
1055 sethvflip(gspca_dev);
1056 return 0;
1057}
1058
1059static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1060{
1061 struct sd *sd = (struct sd *) gspca_dev;
1062
1063 *val = sd->vflip;
1064 return 0;
1065}
1066
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001067/* sub-driver description */
1068static struct sd_desc sd_desc = {
1069 .name = MODULE_NAME,
1070 .ctrls = sd_ctrls,
1071 .nctrls = ARRAY_SIZE(sd_ctrls),
1072 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001073 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001074 .start = sd_start,
1075 .stopN = sd_stopN,
1076 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001077 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001078 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001079};
1080
1081/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001082static __devinitdata struct usb_device_id device_table[] = {
Stephane Marguet (Stemp)b5948be2009-08-25 04:14:04 -03001083 {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001084 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
1085 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
1086 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
1087 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
1088 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
1089 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
Hans de Goede71d50f32008-12-27 03:43:53 -03001090 {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001091 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine121520a2008-12-03 07:19:22 -03001092 {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
Hans de Goede8a5b2e92008-09-03 17:12:17 -03001093 {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine08627252008-09-03 17:12:17 -03001094 {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine56e93ed2009-10-20 04:34:11 -03001095 {USB_DEVICE(0x093a, 0x2628), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine3eed7822009-06-20 04:58:57 -03001096 {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
Hans de Goede40f17a72008-09-04 03:57:01 -03001097 {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
Jean-Francois Moineca8959b2008-12-15 04:12:57 -03001098 {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 {}
1100};
1101MODULE_DEVICE_TABLE(usb, device_table);
1102
1103/* -- device connect -- */
1104static int sd_probe(struct usb_interface *intf,
1105 const struct usb_device_id *id)
1106{
1107 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1108 THIS_MODULE);
1109}
1110
1111static struct usb_driver sd_driver = {
1112 .name = MODULE_NAME,
1113 .id_table = device_table,
1114 .probe = sd_probe,
1115 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001116#ifdef CONFIG_PM
1117 .suspend = gspca_suspend,
1118 .resume = gspca_resume,
1119#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001120};
1121
1122/* -- module insert / remove -- */
1123static int __init sd_mod_init(void)
1124{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001125 int ret;
1126 ret = usb_register(&sd_driver);
1127 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001128 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001129 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001130 return 0;
1131}
1132static void __exit sd_mod_exit(void)
1133{
1134 usb_deregister(&sd_driver);
1135 PDEBUG(D_PROBE, "deregistered");
1136}
1137
1138module_init(sd_mod_init);
1139module_exit(sd_mod_exit);