blob: 418d1a36beb0608c552e8eddec7022bac1d6c6c9 [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:
Hans de Goede327c4ab2008-09-03 17:12:14 -0300477 if (len > 64) {
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 */
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{
Hans de Goede271315a2008-09-03 17:12:19 -0300672 struct sd *sd = (struct sd *) gspca_dev;
673
674 if (sd->sensor == SENSOR_PAC7302)
675 reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
676 else
677 reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
678
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679 return 0;
680}
681
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300682static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300684 struct sd *sd = (struct sd *) gspca_dev;
685
Hans de Goede327c4ab2008-09-03 17:12:14 -0300686 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300688 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300689 reg_w_var(gspca_dev, start_7302);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300690 setbrightcont(gspca_dev);
691 setcolors(gspca_dev);
692 } else {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300693 reg_w_var(gspca_dev, start_7311);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300694 setcontrast(gspca_dev);
695 }
696 setgain(gspca_dev);
697 setexposure(gspca_dev);
698 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699
700 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300701 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300702 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300704 reg_w(gspca_dev, 0x17, 0x20);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300705 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300707 case 1: /* 320x240 pac7311 */
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, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300710 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711 break;
712 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300713 if (sd->sensor == SENSOR_PAC7302)
714 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300715 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300716 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300717 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718 break;
719 }
720
Hans de Goede327c4ab2008-09-03 17:12:14 -0300721 sd->sof_read = 0;
722 sd->autogain_ignore_frames = 0;
723 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300724
725 /* start stream */
726 reg_w(gspca_dev, 0xff, 0x01);
727 if (sd->sensor == SENSOR_PAC7302)
728 reg_w(gspca_dev, 0x78, 0x01);
729 else
730 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300731 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732}
733
734static void sd_stopN(struct gspca_dev *gspca_dev)
735{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300736 struct sd *sd = (struct sd *) gspca_dev;
737
738 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300739 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300740 reg_w(gspca_dev, 0x78, 0x00);
741 reg_w(gspca_dev, 0x78, 0x00);
742 return;
743 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300744 reg_w(gspca_dev, 0xff, 0x04);
745 reg_w(gspca_dev, 0x27, 0x80);
746 reg_w(gspca_dev, 0x28, 0xca);
747 reg_w(gspca_dev, 0x29, 0x53);
748 reg_w(gspca_dev, 0x2a, 0x0e);
749 reg_w(gspca_dev, 0xff, 0x01);
750 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300751 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 */
753 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754}
755
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300756/* called on streamoff with alt 0 and on disconnect */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757static void sd_stop0(struct gspca_dev *gspca_dev)
758{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300759 struct sd *sd = (struct sd *) gspca_dev;
760
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300761 if (!gspca_dev->present)
762 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300763 if (sd->sensor == SENSOR_PAC7302) {
764 reg_w(gspca_dev, 0xff, 0x01);
765 reg_w(gspca_dev, 0x78, 0x40);
766 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767}
768
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300769/* Include pac common sof detection functions */
770#include "pac_common.h"
771
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300772static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300773{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300774 struct sd *sd = (struct sd *) gspca_dev;
775 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300776 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300777
778 if (avg_lum == -1)
779 return;
780
Hans de Goede038ec7c2008-09-03 17:12:18 -0300781 if (sd->sensor == SENSOR_PAC7302) {
782 desired_lum = 270 + sd->brightness * 4;
783 /* Hack hack, with the 7202 the first exposure step is
784 pretty large, so if we're about to make the first
785 exposure increase make the deadzone large to avoid
786 oscilating */
787 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
788 sd->exposure > EXPOSURE_DEF &&
789 sd->exposure < 42)
790 deadzone = 90;
791 else
792 deadzone = 30;
793 } else {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300794 desired_lum = 200;
Hans de Goede038ec7c2008-09-03 17:12:18 -0300795 deadzone = 20;
796 }
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300797
798 if (sd->autogain_ignore_frames > 0)
799 sd->autogain_ignore_frames--;
800 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300801 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300802 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803}
804
Hans de Goede327c4ab2008-09-03 17:12:14 -0300805static const unsigned char pac7311_jpeg_header1[] = {
806 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
807};
808
809static const unsigned char pac7311_jpeg_header2[] = {
810 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
811 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
812};
813
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300814/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815static void sd_pkt_scan(struct gspca_dev *gspca_dev,
816 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300817 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 int len) /* iso packet length */
819{
820 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300821 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822
Hans de Goede327c4ab2008-09-03 17:12:14 -0300823 sof = pac_find_sof(gspca_dev, data, len);
824 if (sof) {
825 unsigned char tmpbuf[4];
826 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300827
Hans de Goede327c4ab2008-09-03 17:12:14 -0300828 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede038ec7c2008-09-03 17:12:18 -0300829 /* 6 bytes after the FF D9 EOF marker a number of lumination
830 bytes are send corresponding to different parts of the
831 image, the 14th and 15th byte after the EOF seem to
832 correspond to the center of the image */
833 lum_offset = 61 + sizeof pac_sof_marker;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300834 footer_length = 74;
835 } else {
836 lum_offset = 24 + sizeof pac_sof_marker;
837 footer_length = 26;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300839
840 /* Finish decoding current frame */
841 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
842 if (n < 0) {
843 frame->data_end += n;
844 n = 0;
845 }
846 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
847 data, n);
848 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
849 frame->data_end[-2] == 0xff &&
850 frame->data_end[-1] == 0xd9)
851 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
852 NULL, 0);
853
854 n = sof - data;
855 len -= n;
856 data = sof;
857
858 /* Get average lumination */
859 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300860 n >= lum_offset)
861 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300862 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300863 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300864 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300865
866 /* Start the new frame with the jpeg header */
867 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
868 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
869 if (sd->sensor == SENSOR_PAC7302) {
870 /* The PAC7302 has the image rotated 90 degrees */
871 tmpbuf[0] = gspca_dev->width >> 8;
872 tmpbuf[1] = gspca_dev->width & 0xff;
873 tmpbuf[2] = gspca_dev->height >> 8;
874 tmpbuf[3] = gspca_dev->height & 0xff;
875 } else {
876 tmpbuf[0] = gspca_dev->height >> 8;
877 tmpbuf[1] = gspca_dev->height & 0xff;
878 tmpbuf[2] = gspca_dev->width >> 8;
879 tmpbuf[3] = gspca_dev->width & 0xff;
880 }
881 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
882 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
883 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300885 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886}
887
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
889{
890 struct sd *sd = (struct sd *) gspca_dev;
891
892 sd->brightness = val;
893 if (gspca_dev->streaming)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300894 setbrightcont(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 return 0;
896}
897
898static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
899{
900 struct sd *sd = (struct sd *) gspca_dev;
901
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 *val = sd->brightness;
903 return 0;
904}
905
906static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
907{
908 struct sd *sd = (struct sd *) gspca_dev;
909
910 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300911 if (gspca_dev->streaming) {
912 if (sd->sensor == SENSOR_PAC7302)
913 setbrightcont(gspca_dev);
914 else
915 setcontrast(gspca_dev);
916 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 return 0;
918}
919
920static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
921{
922 struct sd *sd = (struct sd *) gspca_dev;
923
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 *val = sd->contrast;
925 return 0;
926}
927
928static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
929{
930 struct sd *sd = (struct sd *) gspca_dev;
931
932 sd->colors = val;
933 if (gspca_dev->streaming)
934 setcolors(gspca_dev);
935 return 0;
936}
937
938static int sd_getcolors(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->colors;
943 return 0;
944}
945
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300946static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
947{
948 struct sd *sd = (struct sd *) gspca_dev;
949
950 sd->gain = val;
951 if (gspca_dev->streaming)
952 setgain(gspca_dev);
953 return 0;
954}
955
956static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
957{
958 struct sd *sd = (struct sd *) gspca_dev;
959
960 *val = sd->gain;
961 return 0;
962}
963
964static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
965{
966 struct sd *sd = (struct sd *) gspca_dev;
967
968 sd->exposure = val;
969 if (gspca_dev->streaming)
970 setexposure(gspca_dev);
971 return 0;
972}
973
974static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
975{
976 struct sd *sd = (struct sd *) gspca_dev;
977
978 *val = sd->exposure;
979 return 0;
980}
981
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
983{
984 struct sd *sd = (struct sd *) gspca_dev;
985
986 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300987 /* when switching to autogain set defaults to make sure
988 we are on a valid point of the autogain gain /
989 exposure knee graph, and give this change time to
990 take effect before doing autogain. */
991 if (sd->autogain) {
992 sd->exposure = EXPOSURE_DEF;
993 sd->gain = GAIN_DEF;
994 if (gspca_dev->streaming) {
995 sd->autogain_ignore_frames =
996 PAC_AUTOGAIN_IGNORE_FRAMES;
997 setexposure(gspca_dev);
998 setgain(gspca_dev);
999 }
1000 }
Hans de Goede327c4ab2008-09-03 17:12:14 -03001001
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 return 0;
1003}
1004
1005static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1006{
1007 struct sd *sd = (struct sd *) gspca_dev;
1008
1009 *val = sd->autogain;
1010 return 0;
1011}
1012
Jean-Francois Moine41b46972008-09-03 16:47:58 -03001013static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1014{
1015 struct sd *sd = (struct sd *) gspca_dev;
1016
1017 sd->hflip = val;
1018 if (gspca_dev->streaming)
1019 sethvflip(gspca_dev);
1020 return 0;
1021}
1022
1023static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
1026
1027 *val = sd->hflip;
1028 return 0;
1029}
1030
1031static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1032{
1033 struct sd *sd = (struct sd *) gspca_dev;
1034
1035 sd->vflip = val;
1036 if (gspca_dev->streaming)
1037 sethvflip(gspca_dev);
1038 return 0;
1039}
1040
1041static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1042{
1043 struct sd *sd = (struct sd *) gspca_dev;
1044
1045 *val = sd->vflip;
1046 return 0;
1047}
1048
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001049/* sub-driver description */
1050static struct sd_desc sd_desc = {
1051 .name = MODULE_NAME,
1052 .ctrls = sd_ctrls,
1053 .nctrls = ARRAY_SIZE(sd_ctrls),
1054 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001055 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056 .start = sd_start,
1057 .stopN = sd_stopN,
1058 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001060 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001061};
1062
1063/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064static __devinitdata struct usb_device_id device_table[] = {
Stephane Marguet (Stemp)b5948be2009-08-25 04:14:04 -03001065 {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001066 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
1067 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
1068 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
1069 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
1070 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
1071 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
Hans de Goede71d50f32008-12-27 03:43:53 -03001072 {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine49b57db2008-09-03 16:47:25 -03001073 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine121520a2008-12-03 07:19:22 -03001074 {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
Hans de Goede8a5b2e92008-09-03 17:12:17 -03001075 {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine08627252008-09-03 17:12:17 -03001076 {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine3eed7822009-06-20 04:58:57 -03001077 {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
Hans de Goede40f17a72008-09-04 03:57:01 -03001078 {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
Jean-Francois Moineca8959b2008-12-15 04:12:57 -03001079 {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001080 {}
1081};
1082MODULE_DEVICE_TABLE(usb, device_table);
1083
1084/* -- device connect -- */
1085static int sd_probe(struct usb_interface *intf,
1086 const struct usb_device_id *id)
1087{
1088 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1089 THIS_MODULE);
1090}
1091
1092static struct usb_driver sd_driver = {
1093 .name = MODULE_NAME,
1094 .id_table = device_table,
1095 .probe = sd_probe,
1096 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001097#ifdef CONFIG_PM
1098 .suspend = gspca_suspend,
1099 .resume = gspca_resume,
1100#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001101};
1102
1103/* -- module insert / remove -- */
1104static int __init sd_mod_init(void)
1105{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001106 int ret;
1107 ret = usb_register(&sd_driver);
1108 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001109 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001110 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001111 return 0;
1112}
1113static void __exit sd_mod_exit(void)
1114{
1115 usb_deregister(&sd_driver);
1116 PDEBUG(D_PROBE, "deregistered");
1117}
1118
1119module_init(sd_mod_init);
1120module_exit(sd_mod_exit);