blob: 1c44f78ff9e2cdcd55559b69da73d668904236cf [file] [log] [blame]
Marton Nemeth1408b842009-11-02 08:13:21 -03001/*
2 * Pixart PAC7302 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
Jean-Francois Moinecc2f82c2010-01-28 16:35:40 -03007 * Separated from Pixart PAC7311 library by Márton Németh
Márton Némethaed6f1b2010-01-28 16:33:38 -03008 * Camera button input handling by Márton Németh <nm127@freemail.hu>
9 * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
Marton Nemeth1408b842009-11-02 08:13:21 -030010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26/* Some documentation about various registers as determined by trial and error.
Marton Nemeth1408b842009-11-02 08:13:21 -030027
28 Register page 1:
29
30 Address Description
Marton Nemeth1408b842009-11-02 08:13:21 -030031 0x78 Global control, bit 6 controls the LED (inverted)
Marton Nemeth1408b842009-11-02 08:13:21 -030032
Hans de Goede5fb2dde2010-02-17 11:59:19 -030033 Register page 3:
Marton Nemeth1408b842009-11-02 08:13:21 -030034
35 Address Description
Hans de Goede5fb2dde2010-02-17 11:59:19 -030036 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
Marton Nemeth1408b842009-11-02 08:13:21 -030037 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
Hans de Goede5fb2dde2010-02-17 11:59:19 -030038 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
39 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
40 63 -> ~27 fps, the 2 msb's must always be 1 !!
41 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
42 1 -> ~30 fps, 2 -> ~20 fps
43 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
44 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
45 0x10 Master gain 0-31
Marton Nemeth1408b842009-11-02 08:13:21 -030046 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Márton Németh265a8092009-11-07 15:15:56 -030047
48 The registers are accessed in the following functions:
49
50 Page | Register | Function
51 -----+------------+---------------------------------------------------
52 0 | 0x0f..0x20 | setcolors()
53 0 | 0xa2..0xab | setbrightcont()
54 0 | 0xc5 | setredbalance()
Marton Nemeth23fbee62009-11-08 04:35:12 -030055 0 | 0xc6 | setwhitebalance()
Márton Németh265a8092009-11-07 15:15:56 -030056 0 | 0xc7 | setbluebalance()
57 0 | 0xdc | setbrightcont(), setcolors()
58 3 | 0x02 | setexposure()
59 3 | 0x10 | setgain()
60 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
61 3 | 0x21 | sethvflip()
Marton Nemeth1408b842009-11-02 08:13:21 -030062*/
63
Joe Perches133a9fe2011-08-21 19:56:57 -030064#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
65
Marton Nemeth1408b842009-11-02 08:13:21 -030066#define MODULE_NAME "pac7302"
67
Márton Némethaed6f1b2010-01-28 16:33:38 -030068#include <linux/input.h>
Márton Németh6763cc02009-11-09 07:10:46 -030069#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030070#include "gspca.h"
71
72MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
73MODULE_DESCRIPTION("Pixart PAC7302");
74MODULE_LICENSE("GPL");
75
76/* specific webcam descriptor for pac7302 */
77struct sd {
78 struct gspca_dev gspca_dev; /* !! must be the first item */
79
80 unsigned char brightness;
81 unsigned char contrast;
82 unsigned char colors;
Marton Nemeth23fbee62009-11-08 04:35:12 -030083 unsigned char white_balance;
Márton Németh265a8092009-11-07 15:15:56 -030084 unsigned char red_balance;
85 unsigned char blue_balance;
Marton Nemeth1408b842009-11-02 08:13:21 -030086 unsigned char gain;
Marton Nemeth1408b842009-11-02 08:13:21 -030087 unsigned char autogain;
Hans de Goede5fb2dde2010-02-17 11:59:19 -030088 unsigned short exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -030089 __u8 hflip;
90 __u8 vflip;
Jean-Francois Moinefe2b60322009-11-26 14:28:48 -030091 u8 flags;
92#define FL_HFLIP 0x01 /* mirrored by default */
93#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -030094
95 u8 sof_read;
96 u8 autogain_ignore_frames;
97
98 atomic_t avg_lum;
99};
100
101/* V4L2 controls supported by the driver */
102static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
103static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
104static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
105static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
106static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
107static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300108static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
109static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
Márton Németh265a8092009-11-07 15:15:56 -0300110static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
111static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
112static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
113static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300114static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
116static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
117static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
118static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
120static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
122static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
123static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
124
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300125static const struct ctrl sd_ctrls[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300126 {
127 {
128 .id = V4L2_CID_BRIGHTNESS,
129 .type = V4L2_CTRL_TYPE_INTEGER,
130 .name = "Brightness",
131 .minimum = 0,
132#define BRIGHTNESS_MAX 0x20
133 .maximum = BRIGHTNESS_MAX,
134 .step = 1,
135#define BRIGHTNESS_DEF 0x10
136 .default_value = BRIGHTNESS_DEF,
137 },
138 .set = sd_setbrightness,
139 .get = sd_getbrightness,
140 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300141 {
142 {
143 .id = V4L2_CID_CONTRAST,
144 .type = V4L2_CTRL_TYPE_INTEGER,
145 .name = "Contrast",
146 .minimum = 0,
147#define CONTRAST_MAX 255
148 .maximum = CONTRAST_MAX,
149 .step = 1,
150#define CONTRAST_DEF 127
151 .default_value = CONTRAST_DEF,
152 },
153 .set = sd_setcontrast,
154 .get = sd_getcontrast,
155 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300156 {
157 {
158 .id = V4L2_CID_SATURATION,
159 .type = V4L2_CTRL_TYPE_INTEGER,
160 .name = "Saturation",
161 .minimum = 0,
162#define COLOR_MAX 255
163 .maximum = COLOR_MAX,
164 .step = 1,
165#define COLOR_DEF 127
166 .default_value = COLOR_DEF,
167 },
168 .set = sd_setcolors,
169 .get = sd_getcolors,
170 },
Márton Németh265a8092009-11-07 15:15:56 -0300171 {
172 {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300173 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
174 .type = V4L2_CTRL_TYPE_INTEGER,
175 .name = "White Balance",
176 .minimum = 0,
177 .maximum = 255,
178 .step = 1,
179#define WHITEBALANCE_DEF 4
180 .default_value = WHITEBALANCE_DEF,
181 },
182 .set = sd_setwhitebalance,
183 .get = sd_getwhitebalance,
184 },
185 {
186 {
Márton Németh265a8092009-11-07 15:15:56 -0300187 .id = V4L2_CID_RED_BALANCE,
188 .type = V4L2_CTRL_TYPE_INTEGER,
189 .name = "Red",
190 .minimum = 0,
191 .maximum = 3,
192 .step = 1,
193#define REDBALANCE_DEF 1
194 .default_value = REDBALANCE_DEF,
195 },
196 .set = sd_setredbalance,
197 .get = sd_getredbalance,
198 },
199 {
200 {
201 .id = V4L2_CID_BLUE_BALANCE,
202 .type = V4L2_CTRL_TYPE_INTEGER,
203 .name = "Blue",
204 .minimum = 0,
205 .maximum = 3,
206 .step = 1,
207#define BLUEBALANCE_DEF 1
208 .default_value = BLUEBALANCE_DEF,
209 },
210 .set = sd_setbluebalance,
211 .get = sd_getbluebalance,
212 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300213 {
214 {
215 .id = V4L2_CID_GAIN,
216 .type = V4L2_CTRL_TYPE_INTEGER,
217 .name = "Gain",
218 .minimum = 0,
219#define GAIN_MAX 255
220 .maximum = GAIN_MAX,
221 .step = 1,
222#define GAIN_DEF 127
223#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
224 .default_value = GAIN_DEF,
225 },
226 .set = sd_setgain,
227 .get = sd_getgain,
228 },
229 {
230 {
231 .id = V4L2_CID_EXPOSURE,
232 .type = V4L2_CTRL_TYPE_INTEGER,
233 .name = "Exposure",
234 .minimum = 0,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300235 .maximum = 1023,
Marton Nemeth1408b842009-11-02 08:13:21 -0300236 .step = 1,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300237#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */
238#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
Marton Nemeth1408b842009-11-02 08:13:21 -0300239 .default_value = EXPOSURE_DEF,
240 },
241 .set = sd_setexposure,
242 .get = sd_getexposure,
243 },
244 {
245 {
246 .id = V4L2_CID_AUTOGAIN,
247 .type = V4L2_CTRL_TYPE_BOOLEAN,
248 .name = "Auto Gain",
249 .minimum = 0,
250 .maximum = 1,
251 .step = 1,
252#define AUTOGAIN_DEF 1
253 .default_value = AUTOGAIN_DEF,
254 },
255 .set = sd_setautogain,
256 .get = sd_getautogain,
257 },
258 {
259 {
260 .id = V4L2_CID_HFLIP,
261 .type = V4L2_CTRL_TYPE_BOOLEAN,
262 .name = "Mirror",
263 .minimum = 0,
264 .maximum = 1,
265 .step = 1,
266#define HFLIP_DEF 0
267 .default_value = HFLIP_DEF,
268 },
269 .set = sd_sethflip,
270 .get = sd_gethflip,
271 },
272 {
273 {
274 .id = V4L2_CID_VFLIP,
275 .type = V4L2_CTRL_TYPE_BOOLEAN,
276 .name = "Vflip",
277 .minimum = 0,
278 .maximum = 1,
279 .step = 1,
280#define VFLIP_DEF 0
281 .default_value = VFLIP_DEF,
282 },
283 .set = sd_setvflip,
284 .get = sd_getvflip,
285 },
286};
287
288static const struct v4l2_pix_format vga_mode[] = {
289 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
290 .bytesperline = 640,
291 .sizeimage = 640 * 480 * 3 / 8 + 590,
292 .colorspace = V4L2_COLORSPACE_JPEG,
293 .priv = 0},
294};
295
296#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300297#define END_OF_SEQUENCE 0
298
299/* pac 7302 */
300static const __u8 init_7302[] = {
301/* index,value */
302 0xff, 0x01, /* page 1 */
303 0x78, 0x00, /* deactivate */
304 0xff, 0x01,
305 0x78, 0x40, /* led off */
306};
307static const __u8 start_7302[] = {
308/* index, len, [value]* */
309 0xff, 1, 0x00, /* page 0 */
310 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
311 0x00, 0x00, 0x00, 0x00,
312 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
313 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
314 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
315 0x26, 2, 0xaa, 0xaa,
316 0x2e, 1, 0x31,
317 0x38, 1, 0x01,
318 0x3a, 3, 0x14, 0xff, 0x5a,
319 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
320 0x00, 0x54, 0x11,
321 0x55, 1, 0x00,
322 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
323 0x6b, 1, 0x00,
324 0x6e, 3, 0x08, 0x06, 0x00,
325 0x72, 3, 0x00, 0xff, 0x00,
326 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
327 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
328 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
329 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
330 0xd2, 0xeb,
331 0xaf, 1, 0x02,
332 0xb5, 2, 0x08, 0x08,
333 0xb8, 2, 0x08, 0x88,
334 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
335 0xcc, 1, 0x00,
336 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
337 0xc1, 0xd7, 0xec,
338 0xdc, 1, 0x01,
339 0xff, 1, 0x01, /* page 1 */
340 0x12, 3, 0x02, 0x00, 0x01,
341 0x3e, 2, 0x00, 0x00,
342 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
343 0x7c, 1, 0x00,
344 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
345 0x02, 0x00,
346 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
347 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
348 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
349 0xd8, 1, 0x01,
350 0xdb, 2, 0x00, 0x01,
351 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
352 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
353 0xeb, 1, 0x00,
354 0xff, 1, 0x02, /* page 2 */
355 0x22, 1, 0x00,
356 0xff, 1, 0x03, /* page 3 */
357 0, LOAD_PAGE3, /* load the page 3 */
358 0x11, 1, 0x01,
359 0xff, 1, 0x02, /* page 2 */
360 0x13, 1, 0x00,
361 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
362 0x27, 2, 0x14, 0x0c,
363 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
364 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
365 0x6e, 1, 0x08,
366 0xff, 1, 0x01, /* page 1 */
367 0x78, 1, 0x00,
368 0, END_OF_SEQUENCE /* end of sequence */
369};
370
371#define SKIP 0xaa
372/* page 3 - the value SKIP says skip the index - see reg_w_page() */
373static const __u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300374 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300375 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
376 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
378 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
379 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
380 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
381 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300383 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300384 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
388 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
389 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
390 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
393 0x00
394};
395
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300396static void reg_w_buf(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300397 __u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300398 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300399{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300400 int ret;
401
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300402 if (gspca_dev->usb_err < 0)
403 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300404 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300405 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300406 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300407 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300408 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
409 0, /* value */
410 index, gspca_dev->usb_buf, len,
411 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300412 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300413 pr_err("reg_w_buf failed index 0x%02x, error %d\n",
414 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300415 gspca_dev->usb_err = ret;
416 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300417}
418
419
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300420static void reg_w(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300421 __u8 index,
422 __u8 value)
423{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300424 int ret;
425
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300426 if (gspca_dev->usb_err < 0)
427 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300428 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300429 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300430 usb_sndctrlpipe(gspca_dev->dev, 0),
431 0, /* request */
432 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
433 0, index, gspca_dev->usb_buf, 1,
434 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300435 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300436 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
437 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300438 gspca_dev->usb_err = ret;
439 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300440}
441
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300442static void reg_w_seq(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300443 const __u8 *seq, int len)
444{
445 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300446 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300447 seq += 2;
448 }
449}
450
451/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300452static void reg_w_page(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300453 const __u8 *page, int len)
454{
455 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300456 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300457
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300458 if (gspca_dev->usb_err < 0)
459 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300460 for (index = 0; index < len; index++) {
461 if (page[index] == SKIP) /* skip this index */
462 continue;
463 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300464 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300465 usb_sndctrlpipe(gspca_dev->dev, 0),
466 0, /* request */
467 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
468 0, index, gspca_dev->usb_buf, 1,
469 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300470 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300471 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
472 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300473 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300474 break;
475 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300476 }
477}
478
479/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300480static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300481 const __u8 *seq,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300482 const __u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300483{
484 int index, len;
485
486 for (;;) {
487 index = *seq++;
488 len = *seq++;
489 switch (len) {
490 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300491 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300492 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300493 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300494 break;
495 default:
496 if (len > USB_BUF_SZ) {
497 PDEBUG(D_ERR|D_STREAM,
498 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300499 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300500 }
501 while (len > 0) {
502 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300503 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300504 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300505 seq += len;
506 break;
507 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300508 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300509 seq += 8;
510 index += 8;
511 len -= 8;
512 }
513 }
514 }
515 /* not reached */
516}
517
518/* this function is called at probe time for pac7302 */
519static int sd_config(struct gspca_dev *gspca_dev,
520 const struct usb_device_id *id)
521{
522 struct sd *sd = (struct sd *) gspca_dev;
523 struct cam *cam;
524
525 cam = &gspca_dev->cam;
526
527 PDEBUG(D_CONF, "Find Sensor PAC7302");
528 cam->cam_mode = vga_mode; /* only 640x480 */
529 cam->nmodes = ARRAY_SIZE(vga_mode);
530
531 sd->brightness = BRIGHTNESS_DEF;
532 sd->contrast = CONTRAST_DEF;
533 sd->colors = COLOR_DEF;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300534 sd->white_balance = WHITEBALANCE_DEF;
Márton Németh265a8092009-11-07 15:15:56 -0300535 sd->red_balance = REDBALANCE_DEF;
536 sd->blue_balance = BLUEBALANCE_DEF;
Marton Nemeth1408b842009-11-02 08:13:21 -0300537 sd->gain = GAIN_DEF;
538 sd->exposure = EXPOSURE_DEF;
539 sd->autogain = AUTOGAIN_DEF;
540 sd->hflip = HFLIP_DEF;
541 sd->vflip = VFLIP_DEF;
Jean-Francois Moinefe2b60322009-11-26 14:28:48 -0300542 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300543 return 0;
544}
545
546/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300547static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300548{
549 struct sd *sd = (struct sd *) gspca_dev;
550 int i, v;
551 static const __u8 max[10] =
552 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
553 0xd4, 0xec};
554 static const __u8 delta[10] =
555 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
556 0x11, 0x0b};
557
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300558 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300559 for (i = 0; i < 10; i++) {
560 v = max[i];
561 v += (sd->brightness - BRIGHTNESS_MAX)
562 * 150 / BRIGHTNESS_MAX; /* 200 ? */
563 v -= delta[i] * sd->contrast / CONTRAST_MAX;
564 if (v < 0)
565 v = 0;
566 else if (v > 0xff)
567 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300568 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300569 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300570 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300571}
572
573/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300574static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300575{
576 struct sd *sd = (struct sd *) gspca_dev;
577 int i, v;
578 static const int a[9] =
579 {217, -212, 0, -101, 170, -67, -38, -315, 355};
580 static const int b[9] =
581 {19, 106, 0, 19, 106, 1, 19, 106, 1};
582
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300583 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
584 reg_w(gspca_dev, 0x11, 0x01);
585 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300586 for (i = 0; i < 9; i++) {
587 v = a[i] * sd->colors / COLOR_MAX + b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300588 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
589 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300590 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300591 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300592 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
593}
594
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300595static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300596{
597 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300598
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300599 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
600 reg_w(gspca_dev, 0xc6, sd->white_balance);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300601
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300602 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300603 PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300604}
605
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300606static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300607{
608 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300609
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300610 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
611 reg_w(gspca_dev, 0xc5, sd->red_balance);
Márton Németh265a8092009-11-07 15:15:56 -0300612
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300613 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300614 PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
Márton Németh265a8092009-11-07 15:15:56 -0300615}
616
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300617static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300618{
619 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300620
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300621 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
622 reg_w(gspca_dev, 0xc7, sd->blue_balance);
Márton Németh265a8092009-11-07 15:15:56 -0300623
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300624 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300625 PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
Márton Németh265a8092009-11-07 15:15:56 -0300626}
627
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300628static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300629{
630 struct sd *sd = (struct sd *) gspca_dev;
631
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300632 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
633 reg_w(gspca_dev, 0x10, sd->gain >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300634
635 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300636 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300637}
638
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300639static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300640{
641 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300642 __u8 clockdiv;
643 __u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300644
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300645 /* register 2 of frame 3 contains the clock divider configuring the
646 no fps according to the formula: 90 / reg. sd->exposure is the
647 desired exposure time in 0.5 ms. */
648 clockdiv = (90 * sd->exposure + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300649
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300650 /* Note clockdiv = 3 also works, but when running at 30 fps, depending
651 on the scene being recorded, the camera switches to another
652 quantization table for certain JPEG blocks, and we don't know how
653 to decompress these blocks. So we cap the framerate at 15 fps */
654 if (clockdiv < 6)
655 clockdiv = 6;
656 else if (clockdiv > 63)
657 clockdiv = 63;
658
659 /* reg2 MUST be a multiple of 3, except when between 6 and 12?
660 Always round up, otherwise we cannot get the desired frametime
661 using the partial frame time exposure control */
662 if (clockdiv < 6 || clockdiv > 12)
663 clockdiv = ((clockdiv + 2) / 3) * 3;
664
665 /* frame exposure time in ms = 1000 * clockdiv / 90 ->
666 exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
667 exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
668 /* 0 = use full frametime, 448 = no exposure, reverse it */
669 exposure = 448 - exposure;
670
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300671 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300672 reg_w(gspca_dev, 0x02, clockdiv);
673 reg_w(gspca_dev, 0x0e, exposure & 0xff);
674 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300675
676 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300677 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300678}
679
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300680static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300681{
682 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b60322009-11-26 14:28:48 -0300683 u8 data, hflip, vflip;
684
685 hflip = sd->hflip;
686 if (sd->flags & FL_HFLIP)
687 hflip = !hflip;
688 vflip = sd->vflip;
689 if (sd->flags & FL_VFLIP)
690 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300691
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300692 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b60322009-11-26 14:28:48 -0300693 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300694 reg_w(gspca_dev, 0x21, data);
695
Marton Nemeth1408b842009-11-02 08:13:21 -0300696 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300697 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300698}
699
700/* this function is called at probe and resume time for pac7302 */
701static int sd_init(struct gspca_dev *gspca_dev)
702{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300703 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
704 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300705}
706
707static int sd_start(struct gspca_dev *gspca_dev)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 sd->sof_read = 0;
712
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300713 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300714 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300715 setbrightcont(gspca_dev);
716 setcolors(gspca_dev);
717 setwhitebalance(gspca_dev);
718 setredbalance(gspca_dev);
719 setbluebalance(gspca_dev);
720 setgain(gspca_dev);
721 setexposure(gspca_dev);
722 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300723
724 /* only resolution 640x480 is supported for pac7302 */
725
726 sd->sof_read = 0;
727 sd->autogain_ignore_frames = 0;
728 atomic_set(&sd->avg_lum, -1);
729
730 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300731 reg_w(gspca_dev, 0xff, 0x01);
732 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300733
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300734 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300735}
736
737static void sd_stopN(struct gspca_dev *gspca_dev)
738{
Márton Némethb1784b32009-11-07 05:52:02 -0300739
Márton Németh67c98f72009-11-07 05:45:33 -0300740 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300741 reg_w(gspca_dev, 0xff, 0x01);
742 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300743}
744
745/* called on streamoff with alt 0 and on disconnect for pac7302 */
746static void sd_stop0(struct gspca_dev *gspca_dev)
747{
748 if (!gspca_dev->present)
749 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300750 reg_w(gspca_dev, 0xff, 0x01);
751 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300752}
753
754/* Include pac common sof detection functions */
755#include "pac_common.h"
756
757static void do_autogain(struct gspca_dev *gspca_dev)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300761 int desired_lum;
762 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300763
764 if (avg_lum == -1)
765 return;
766
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300767 desired_lum = 270 + sd->brightness;
Marton Nemeth1408b842009-11-02 08:13:21 -0300768
769 if (sd->autogain_ignore_frames > 0)
770 sd->autogain_ignore_frames--;
771 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
772 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
773 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
774}
775
776/* JPEG header, part 1 */
777static const unsigned char pac_jpeg_header1[] = {
778 0xff, 0xd8, /* SOI: Start of Image */
779
780 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
781 0x00, 0x11, /* length = 17 bytes (including this length field) */
782 0x08 /* Precision: 8 */
783 /* 2 bytes is placed here: number of image lines */
784 /* 2 bytes is placed here: samples per line */
785};
786
787/* JPEG header, continued */
788static const unsigned char pac_jpeg_header2[] = {
789 0x03, /* Number of image components: 3 */
790 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
791 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
792 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
793
794 0xff, 0xda, /* SOS: Start Of Scan */
795 0x00, 0x0c, /* length = 12 bytes (including this length field) */
796 0x03, /* number of components: 3 */
797 0x01, 0x00, /* selector 1, table 0x00 */
798 0x02, 0x11, /* selector 2, table 0x11 */
799 0x03, 0x11, /* selector 3, table 0x11 */
800 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
801 0x00 /* Successive approximation: 0 */
802};
803
804static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300805 __u16 lines, __u16 samples_per_line)
806{
807 unsigned char tmpbuf[4];
808
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300809 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300810 pac_jpeg_header1, sizeof(pac_jpeg_header1));
811
812 tmpbuf[0] = lines >> 8;
813 tmpbuf[1] = lines & 0xff;
814 tmpbuf[2] = samples_per_line >> 8;
815 tmpbuf[3] = samples_per_line & 0xff;
816
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300817 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300818 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300819 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemeth1408b842009-11-02 08:13:21 -0300820 pac_jpeg_header2, sizeof(pac_jpeg_header2));
821}
822
823/* this function is run at interrupt level */
824static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300825 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300826 int len) /* iso packet length */
827{
828 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300829 u8 *image;
Marton Nemeth1408b842009-11-02 08:13:21 -0300830 unsigned char *sof;
831
832 sof = pac_find_sof(&sd->sof_read, data, len);
833 if (sof) {
834 int n, lum_offset, footer_length;
835
836 /* 6 bytes after the FF D9 EOF marker a number of lumination
837 bytes are send corresponding to different parts of the
838 image, the 14th and 15th byte after the EOF seem to
839 correspond to the center of the image */
840 lum_offset = 61 + sizeof pac_sof_marker;
841 footer_length = 74;
842
843 /* Finish decoding current frame */
844 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
845 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300846 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300847 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300848 } else {
849 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300850 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300851
852 image = gspca_dev->image;
853 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300854 && image[gspca_dev->image_len - 2] == 0xff
855 && image[gspca_dev->image_len - 1] == 0xd9)
856 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300857
858 n = sof - data;
859 len -= n;
860 data = sof;
861
862 /* Get average lumination */
863 if (gspca_dev->last_packet_type == LAST_PACKET &&
864 n >= lum_offset)
865 atomic_set(&sd->avg_lum, data[-lum_offset] +
866 data[-lum_offset + 1]);
867 else
868 atomic_set(&sd->avg_lum, -1);
869
870 /* Start the new frame with the jpeg header */
871 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300872 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300873 gspca_dev->width, gspca_dev->height);
874 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300875 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300876}
877
878static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
879{
880 struct sd *sd = (struct sd *) gspca_dev;
881
882 sd->brightness = val;
883 if (gspca_dev->streaming)
884 setbrightcont(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300885 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300886}
887
888static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
889{
890 struct sd *sd = (struct sd *) gspca_dev;
891
892 *val = sd->brightness;
893 return 0;
894}
895
896static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
897{
898 struct sd *sd = (struct sd *) gspca_dev;
899
900 sd->contrast = val;
Jean-François Moine780e3122010-10-19 04:29:10 -0300901 if (gspca_dev->streaming)
Marton Nemeth1408b842009-11-02 08:13:21 -0300902 setbrightcont(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300903 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300904}
905
906static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
907{
908 struct sd *sd = (struct sd *) gspca_dev;
909
910 *val = sd->contrast;
911 return 0;
912}
913
914static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
915{
916 struct sd *sd = (struct sd *) gspca_dev;
917
918 sd->colors = val;
919 if (gspca_dev->streaming)
920 setcolors(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300921 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300922}
923
924static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
925{
926 struct sd *sd = (struct sd *) gspca_dev;
927
928 *val = sd->colors;
929 return 0;
930}
931
Marton Nemeth23fbee62009-11-08 04:35:12 -0300932static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
933{
934 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300935
936 sd->white_balance = val;
937 if (gspca_dev->streaming)
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300938 setwhitebalance(gspca_dev);
939 return gspca_dev->usb_err;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300940}
941
942static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
943{
944 struct sd *sd = (struct sd *) gspca_dev;
945
946 *val = sd->white_balance;
947 return 0;
948}
949
Márton Németh265a8092009-11-07 15:15:56 -0300950static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
951{
952 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300953
954 sd->red_balance = val;
955 if (gspca_dev->streaming)
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300956 setredbalance(gspca_dev);
957 return gspca_dev->usb_err;
Márton Németh265a8092009-11-07 15:15:56 -0300958}
959
960static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
961{
962 struct sd *sd = (struct sd *) gspca_dev;
963
964 *val = sd->red_balance;
965 return 0;
966}
967
968static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
969{
970 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300971
972 sd->blue_balance = val;
973 if (gspca_dev->streaming)
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300974 setbluebalance(gspca_dev);
975 return gspca_dev->usb_err;
Márton Németh265a8092009-11-07 15:15:56 -0300976}
977
978static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
979{
980 struct sd *sd = (struct sd *) gspca_dev;
981
982 *val = sd->blue_balance;
983 return 0;
984}
985
Marton Nemeth1408b842009-11-02 08:13:21 -0300986static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
987{
988 struct sd *sd = (struct sd *) gspca_dev;
989
990 sd->gain = val;
991 if (gspca_dev->streaming)
992 setgain(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300993 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300994}
995
996static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
997{
998 struct sd *sd = (struct sd *) gspca_dev;
999
1000 *val = sd->gain;
1001 return 0;
1002}
1003
1004static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1005{
1006 struct sd *sd = (struct sd *) gspca_dev;
1007
1008 sd->exposure = val;
1009 if (gspca_dev->streaming)
1010 setexposure(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001011 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -03001012}
1013
1014static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1015{
1016 struct sd *sd = (struct sd *) gspca_dev;
1017
1018 *val = sd->exposure;
1019 return 0;
1020}
1021
1022static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1023{
1024 struct sd *sd = (struct sd *) gspca_dev;
1025
1026 sd->autogain = val;
1027 /* when switching to autogain set defaults to make sure
1028 we are on a valid point of the autogain gain /
1029 exposure knee graph, and give this change time to
1030 take effect before doing autogain. */
1031 if (sd->autogain) {
1032 sd->exposure = EXPOSURE_DEF;
1033 sd->gain = GAIN_DEF;
1034 if (gspca_dev->streaming) {
1035 sd->autogain_ignore_frames =
1036 PAC_AUTOGAIN_IGNORE_FRAMES;
1037 setexposure(gspca_dev);
1038 setgain(gspca_dev);
1039 }
1040 }
1041
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001042 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -03001043}
1044
1045static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1046{
1047 struct sd *sd = (struct sd *) gspca_dev;
1048
1049 *val = sd->autogain;
1050 return 0;
1051}
1052
1053static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1054{
1055 struct sd *sd = (struct sd *) gspca_dev;
1056
1057 sd->hflip = val;
1058 if (gspca_dev->streaming)
1059 sethvflip(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001060 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -03001061}
1062
1063static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1064{
1065 struct sd *sd = (struct sd *) gspca_dev;
1066
1067 *val = sd->hflip;
1068 return 0;
1069}
1070
1071static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1072{
1073 struct sd *sd = (struct sd *) gspca_dev;
1074
1075 sd->vflip = val;
1076 if (gspca_dev->streaming)
1077 sethvflip(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001078 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -03001079}
1080
1081static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1082{
1083 struct sd *sd = (struct sd *) gspca_dev;
1084
1085 *val = sd->vflip;
1086 return 0;
1087}
1088
Márton Németh6763cc02009-11-09 07:10:46 -03001089#ifdef CONFIG_VIDEO_ADV_DEBUG
1090static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1091 struct v4l2_dbg_register *reg)
1092{
Márton Németh6763cc02009-11-09 07:10:46 -03001093 __u8 index;
1094 __u8 value;
1095
1096 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
1097 long on the USB bus)
1098 */
1099 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
1100 reg->match.addr == 0 &&
1101 (reg->reg < 0x000000ff) &&
1102 (reg->val <= 0x000000ff)
1103 ) {
1104 /* Currently writing to page 0 is only supported. */
1105 /* reg_w() only supports 8bit index */
1106 index = reg->reg & 0x000000ff;
1107 value = reg->val & 0x000000ff;
1108
1109 /* Note that there shall be no access to other page
1110 by any other function between the page swith and
1111 the actual register write */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001112 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
1113 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -03001114
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001115 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -03001116 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -03001117 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -03001118}
1119
1120static int sd_chip_ident(struct gspca_dev *gspca_dev,
1121 struct v4l2_dbg_chip_ident *chip)
1122{
1123 int ret = -EINVAL;
1124
1125 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1126 chip->match.addr == 0) {
1127 chip->revision = 0;
1128 chip->ident = V4L2_IDENT_UNKNOWN;
1129 ret = 0;
1130 }
1131 return ret;
1132}
1133#endif
1134
Jean-François Moine28566432010-10-01 07:33:26 -03001135#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -03001136static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
1137 u8 *data, /* interrupt packet data */
1138 int len) /* interrput packet length */
1139{
1140 int ret = -EINVAL;
1141 u8 data0, data1;
1142
1143 if (len == 2) {
1144 data0 = data[0];
1145 data1 = data[1];
1146 if ((data0 == 0x00 && data1 == 0x11) ||
1147 (data0 == 0x22 && data1 == 0x33) ||
1148 (data0 == 0x44 && data1 == 0x55) ||
1149 (data0 == 0x66 && data1 == 0x77) ||
1150 (data0 == 0x88 && data1 == 0x99) ||
1151 (data0 == 0xaa && data1 == 0xbb) ||
1152 (data0 == 0xcc && data1 == 0xdd) ||
1153 (data0 == 0xee && data1 == 0xff)) {
1154 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
1155 input_sync(gspca_dev->input_dev);
1156 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
1157 input_sync(gspca_dev->input_dev);
1158 ret = 0;
1159 }
1160 }
1161
1162 return ret;
1163}
1164#endif
1165
Marton Nemeth1408b842009-11-02 08:13:21 -03001166/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -03001167static const struct sd_desc sd_desc = {
Marton Nemeth1408b842009-11-02 08:13:21 -03001168 .name = MODULE_NAME,
1169 .ctrls = sd_ctrls,
1170 .nctrls = ARRAY_SIZE(sd_ctrls),
1171 .config = sd_config,
1172 .init = sd_init,
1173 .start = sd_start,
1174 .stopN = sd_stopN,
1175 .stop0 = sd_stop0,
1176 .pkt_scan = sd_pkt_scan,
1177 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -03001178#ifdef CONFIG_VIDEO_ADV_DEBUG
1179 .set_register = sd_dbg_s_register,
1180 .get_chip_ident = sd_chip_ident,
1181#endif
Jean-François Moine28566432010-10-01 07:33:26 -03001182#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -03001183 .int_pkt_scan = sd_int_pkt_scan,
1184#endif
Marton Nemeth1408b842009-11-02 08:13:21 -03001185};
1186
1187/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001188static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -03001189 {USB_DEVICE(0x06f8, 0x3009)},
1190 {USB_DEVICE(0x093a, 0x2620)},
1191 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b60322009-11-26 14:28:48 -03001192 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
1193 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -03001194 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -03001195 {USB_DEVICE(0x093a, 0x2626)},
1196 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -03001197 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -03001198 {USB_DEVICE(0x093a, 0x262a)},
1199 {USB_DEVICE(0x093a, 0x262c)},
1200 {}
1201};
1202MODULE_DEVICE_TABLE(usb, device_table);
1203
1204/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001205static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -03001206 const struct usb_device_id *id)
1207{
1208 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1209 THIS_MODULE);
1210}
1211
1212static struct usb_driver sd_driver = {
1213 .name = MODULE_NAME,
1214 .id_table = device_table,
1215 .probe = sd_probe,
1216 .disconnect = gspca_disconnect,
1217#ifdef CONFIG_PM
1218 .suspend = gspca_suspend,
1219 .resume = gspca_resume,
1220#endif
1221};
1222
1223/* -- module insert / remove -- */
1224static int __init sd_mod_init(void)
1225{
Jean-François Moine54826432010-09-13 04:53:03 -03001226 return usb_register(&sd_driver);
Marton Nemeth1408b842009-11-02 08:13:21 -03001227}
1228static void __exit sd_mod_exit(void)
1229{
1230 usb_deregister(&sd_driver);
Marton Nemeth1408b842009-11-02 08:13:21 -03001231}
1232
1233module_init(sd_mod_init);
1234module_exit(sd_mod_exit);