blob: 1f3fdbf341e6900ef8204eb630837dfeb8a0649c [file] [log] [blame]
Marton Nemeth1408b842009-11-02 08:13:21 -03001/*
Jean-François Moineae251e62012-02-27 05:15:12 -03002 * Pixart PAC7302 driver
Marton Nemeth1408b842009-11-02 08:13:21 -03003 *
Jean-François Moineae251e62012-02-27 05:15:12 -03004 * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
5 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
Marton Nemeth1408b842009-11-02 08:13:21 -03006 *
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
Márton Némethaed6f1b2010-01-28 16:33:38 -030066#include <linux/input.h>
Márton Németh6763cc02009-11-09 07:10:46 -030067#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030068#include "gspca.h"
69
Jean-François Moineae251e62012-02-27 05:15:12 -030070MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
71 "Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -030072MODULE_DESCRIPTION("Pixart PAC7302");
73MODULE_LICENSE("GPL");
74
Jean-François Moineaa5b7922012-02-27 05:38:09 -030075enum e_ctrl {
76 BRIGHTNESS,
77 CONTRAST,
78 COLORS,
79 WHITE_BALANCE,
80 RED_BALANCE,
81 BLUE_BALANCE,
82 GAIN,
83 AUTOGAIN,
84 EXPOSURE,
85 VFLIP,
86 HFLIP,
87 NCTRLS /* number of controls */
88};
89
Marton Nemeth1408b842009-11-02 08:13:21 -030090/* specific webcam descriptor for pac7302 */
91struct sd {
92 struct gspca_dev gspca_dev; /* !! must be the first item */
93
Jean-François Moineaa5b7922012-02-27 05:38:09 -030094 struct gspca_ctrl ctrls[NCTRLS];
95
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -030096 u8 flags;
97#define FL_HFLIP 0x01 /* mirrored by default */
98#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -030099
100 u8 sof_read;
101 u8 autogain_ignore_frames;
102
103 atomic_t avg_lum;
104};
105
106/* V4L2 controls supported by the driver */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300107static void setbrightcont(struct gspca_dev *gspca_dev);
108static void setcolors(struct gspca_dev *gspca_dev);
109static void setwhitebalance(struct gspca_dev *gspca_dev);
110static void setredbalance(struct gspca_dev *gspca_dev);
111static void setbluebalance(struct gspca_dev *gspca_dev);
112static void setgain(struct gspca_dev *gspca_dev);
113static void setexposure(struct gspca_dev *gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300114static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300115static void sethvflip(struct gspca_dev *gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300116
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300117static const struct ctrl sd_ctrls[] = {
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300118[BRIGHTNESS] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300119 {
120 .id = V4L2_CID_BRIGHTNESS,
121 .type = V4L2_CTRL_TYPE_INTEGER,
122 .name = "Brightness",
123 .minimum = 0,
124#define BRIGHTNESS_MAX 0x20
125 .maximum = BRIGHTNESS_MAX,
126 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300127 .default_value = 0x10,
Marton Nemeth1408b842009-11-02 08:13:21 -0300128 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300129 .set_control = setbrightcont
Marton Nemeth1408b842009-11-02 08:13:21 -0300130 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300131[CONTRAST] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300132 {
133 .id = V4L2_CID_CONTRAST,
134 .type = V4L2_CTRL_TYPE_INTEGER,
135 .name = "Contrast",
136 .minimum = 0,
137#define CONTRAST_MAX 255
138 .maximum = CONTRAST_MAX,
139 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300140 .default_value = 127,
Marton Nemeth1408b842009-11-02 08:13:21 -0300141 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300142 .set_control = setbrightcont
Marton Nemeth1408b842009-11-02 08:13:21 -0300143 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300144[COLORS] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300145 {
146 .id = V4L2_CID_SATURATION,
147 .type = V4L2_CTRL_TYPE_INTEGER,
148 .name = "Saturation",
149 .minimum = 0,
150#define COLOR_MAX 255
151 .maximum = COLOR_MAX,
152 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300153 .default_value = 127
Marton Nemeth1408b842009-11-02 08:13:21 -0300154 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300155 .set_control = setcolors
Marton Nemeth1408b842009-11-02 08:13:21 -0300156 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300157[WHITE_BALANCE] = {
Márton Németh265a8092009-11-07 15:15:56 -0300158 {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300159 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "White Balance",
162 .minimum = 0,
163 .maximum = 255,
164 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300165 .default_value = 4,
Marton Nemeth23fbee62009-11-08 04:35:12 -0300166 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300167 .set_control = setwhitebalance
Marton Nemeth23fbee62009-11-08 04:35:12 -0300168 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300169[RED_BALANCE] = {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300170 {
Márton Németh265a8092009-11-07 15:15:56 -0300171 .id = V4L2_CID_RED_BALANCE,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "Red",
174 .minimum = 0,
175 .maximum = 3,
176 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300177 .default_value = 1,
Márton Németh265a8092009-11-07 15:15:56 -0300178 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300179 .set_control = setredbalance
Márton Németh265a8092009-11-07 15:15:56 -0300180 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300181[BLUE_BALANCE] = {
Márton Németh265a8092009-11-07 15:15:56 -0300182 {
183 .id = V4L2_CID_BLUE_BALANCE,
184 .type = V4L2_CTRL_TYPE_INTEGER,
185 .name = "Blue",
186 .minimum = 0,
187 .maximum = 3,
188 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300189 .default_value = 1,
Márton Németh265a8092009-11-07 15:15:56 -0300190 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300191 .set_control = setbluebalance
Márton Németh265a8092009-11-07 15:15:56 -0300192 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300193[GAIN] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300194 {
195 .id = V4L2_CID_GAIN,
196 .type = V4L2_CTRL_TYPE_INTEGER,
197 .name = "Gain",
198 .minimum = 0,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300199 .maximum = 255,
Marton Nemeth1408b842009-11-02 08:13:21 -0300200 .step = 1,
201#define GAIN_DEF 127
202#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
203 .default_value = GAIN_DEF,
204 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300205 .set_control = setgain
Marton Nemeth1408b842009-11-02 08:13:21 -0300206 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300207[EXPOSURE] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300208 {
209 .id = V4L2_CID_EXPOSURE,
210 .type = V4L2_CTRL_TYPE_INTEGER,
211 .name = "Exposure",
212 .minimum = 0,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300213 .maximum = 1023,
Marton Nemeth1408b842009-11-02 08:13:21 -0300214 .step = 1,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300215#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */
216#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
Marton Nemeth1408b842009-11-02 08:13:21 -0300217 .default_value = EXPOSURE_DEF,
218 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300219 .set_control = setexposure
Marton Nemeth1408b842009-11-02 08:13:21 -0300220 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300221[AUTOGAIN] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300222 {
223 .id = V4L2_CID_AUTOGAIN,
224 .type = V4L2_CTRL_TYPE_BOOLEAN,
225 .name = "Auto Gain",
226 .minimum = 0,
227 .maximum = 1,
228 .step = 1,
229#define AUTOGAIN_DEF 1
230 .default_value = AUTOGAIN_DEF,
231 },
232 .set = sd_setautogain,
Marton Nemeth1408b842009-11-02 08:13:21 -0300233 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300234[HFLIP] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300235 {
236 .id = V4L2_CID_HFLIP,
237 .type = V4L2_CTRL_TYPE_BOOLEAN,
238 .name = "Mirror",
239 .minimum = 0,
240 .maximum = 1,
241 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300242 .default_value = 0,
Marton Nemeth1408b842009-11-02 08:13:21 -0300243 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300244 .set_control = sethvflip,
Marton Nemeth1408b842009-11-02 08:13:21 -0300245 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300246[VFLIP] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300247 {
248 .id = V4L2_CID_VFLIP,
249 .type = V4L2_CTRL_TYPE_BOOLEAN,
250 .name = "Vflip",
251 .minimum = 0,
252 .maximum = 1,
253 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300254 .default_value = 0,
Marton Nemeth1408b842009-11-02 08:13:21 -0300255 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300256 .set_control = sethvflip
Marton Nemeth1408b842009-11-02 08:13:21 -0300257 },
258};
259
260static const struct v4l2_pix_format vga_mode[] = {
261 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
262 .bytesperline = 640,
263 .sizeimage = 640 * 480 * 3 / 8 + 590,
264 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300265 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300266};
267
268#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300269#define END_OF_SEQUENCE 0
270
271/* pac 7302 */
Jean-François Moineae251e62012-02-27 05:15:12 -0300272static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300273/* index,value */
274 0xff, 0x01, /* page 1 */
275 0x78, 0x00, /* deactivate */
276 0xff, 0x01,
277 0x78, 0x40, /* led off */
278};
Jean-François Moineae251e62012-02-27 05:15:12 -0300279static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300280/* index, len, [value]* */
281 0xff, 1, 0x00, /* page 0 */
282 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
283 0x00, 0x00, 0x00, 0x00,
284 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
285 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
286 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
287 0x26, 2, 0xaa, 0xaa,
288 0x2e, 1, 0x31,
289 0x38, 1, 0x01,
290 0x3a, 3, 0x14, 0xff, 0x5a,
291 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
292 0x00, 0x54, 0x11,
293 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300294 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300295 0x6b, 1, 0x00,
296 0x6e, 3, 0x08, 0x06, 0x00,
297 0x72, 3, 0x00, 0xff, 0x00,
298 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
299 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
300 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
301 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
302 0xd2, 0xeb,
303 0xaf, 1, 0x02,
304 0xb5, 2, 0x08, 0x08,
305 0xb8, 2, 0x08, 0x88,
306 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
307 0xcc, 1, 0x00,
308 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
309 0xc1, 0xd7, 0xec,
310 0xdc, 1, 0x01,
311 0xff, 1, 0x01, /* page 1 */
312 0x12, 3, 0x02, 0x00, 0x01,
313 0x3e, 2, 0x00, 0x00,
314 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
315 0x7c, 1, 0x00,
316 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
317 0x02, 0x00,
318 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
319 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
320 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
321 0xd8, 1, 0x01,
322 0xdb, 2, 0x00, 0x01,
323 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
324 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
325 0xeb, 1, 0x00,
326 0xff, 1, 0x02, /* page 2 */
327 0x22, 1, 0x00,
328 0xff, 1, 0x03, /* page 3 */
329 0, LOAD_PAGE3, /* load the page 3 */
330 0x11, 1, 0x01,
331 0xff, 1, 0x02, /* page 2 */
332 0x13, 1, 0x00,
333 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
334 0x27, 2, 0x14, 0x0c,
335 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
336 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
337 0x6e, 1, 0x08,
338 0xff, 1, 0x01, /* page 1 */
339 0x78, 1, 0x00,
340 0, END_OF_SEQUENCE /* end of sequence */
341};
342
343#define SKIP 0xaa
344/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300345static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300346 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300347 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
348 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
350 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
351 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
352 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
353 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300355 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300356 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
360 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
361 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
362 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
365 0x00
366};
367
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300368static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300369 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300370 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300371{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300372 int ret;
373
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300374 if (gspca_dev->usb_err < 0)
375 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300376 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300377 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300378 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300379 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300380 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
381 0, /* value */
382 index, gspca_dev->usb_buf, len,
383 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300384 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300385 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300386 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300387 gspca_dev->usb_err = ret;
388 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300389}
390
391
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300392static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300393 u8 index,
394 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300395{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300396 int ret;
397
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300398 if (gspca_dev->usb_err < 0)
399 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300400 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300401 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300402 usb_sndctrlpipe(gspca_dev->dev, 0),
403 0, /* request */
404 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
405 0, index, gspca_dev->usb_buf, 1,
406 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300407 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300408 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300409 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300410 gspca_dev->usb_err = ret;
411 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300412}
413
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300414static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300415 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300416{
417 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300418 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300419 seq += 2;
420 }
421}
422
423/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300424static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300425 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300426{
427 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300428 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300429
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300430 if (gspca_dev->usb_err < 0)
431 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300432 for (index = 0; index < len; index++) {
433 if (page[index] == SKIP) /* skip this index */
434 continue;
435 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300436 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300437 usb_sndctrlpipe(gspca_dev->dev, 0),
438 0, /* request */
439 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
440 0, index, gspca_dev->usb_buf, 1,
441 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300442 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300443 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300444 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300445 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300446 break;
447 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300448 }
449}
450
451/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300452static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300453 const u8 *seq,
454 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300455{
456 int index, len;
457
458 for (;;) {
459 index = *seq++;
460 len = *seq++;
461 switch (len) {
462 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300463 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300464 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300465 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300466 break;
467 default:
Jean-François Moineae251e62012-02-27 05:15:12 -0300468#ifdef GSPCA_DEBUG
Marton Nemeth1408b842009-11-02 08:13:21 -0300469 if (len > USB_BUF_SZ) {
470 PDEBUG(D_ERR|D_STREAM,
471 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300472 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300473 }
Jean-François Moineae251e62012-02-27 05:15:12 -0300474#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300475 while (len > 0) {
476 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300477 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300478 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300479 seq += len;
480 break;
481 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300482 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300483 seq += 8;
484 index += 8;
485 len -= 8;
486 }
487 }
488 }
489 /* not reached */
490}
491
492/* this function is called at probe time for pac7302 */
493static int sd_config(struct gspca_dev *gspca_dev,
494 const struct usb_device_id *id)
495{
496 struct sd *sd = (struct sd *) gspca_dev;
497 struct cam *cam;
498
499 cam = &gspca_dev->cam;
500
Marton Nemeth1408b842009-11-02 08:13:21 -0300501 cam->cam_mode = vga_mode; /* only 640x480 */
502 cam->nmodes = ARRAY_SIZE(vga_mode);
503
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300504 gspca_dev->cam.ctrls = sd->ctrls;
505
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300506 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300507 return 0;
508}
509
510/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300511static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300512{
513 struct sd *sd = (struct sd *) gspca_dev;
514 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300515 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300516 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
517 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300518 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300519 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
520 0x11, 0x0b};
521
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300522 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300523 for (i = 0; i < 10; i++) {
524 v = max[i];
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300525 v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
Marton Nemeth1408b842009-11-02 08:13:21 -0300526 * 150 / BRIGHTNESS_MAX; /* 200 ? */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300527 v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
Marton Nemeth1408b842009-11-02 08:13:21 -0300528 if (v < 0)
529 v = 0;
530 else if (v > 0xff)
531 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300532 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300533 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300534 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300535}
536
537/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300538static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300539{
540 struct sd *sd = (struct sd *) gspca_dev;
541 int i, v;
542 static const int a[9] =
543 {217, -212, 0, -101, 170, -67, -38, -315, 355};
544 static const int b[9] =
545 {19, 106, 0, 19, 106, 1, 19, 106, 1};
546
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300547 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
548 reg_w(gspca_dev, 0x11, 0x01);
549 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300550 for (i = 0; i < 9; i++) {
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300551 v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300552 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
553 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300554 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300555 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300556}
557
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300558static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300559{
560 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300561
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300562 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300563 reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300564
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300565 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300566}
567
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300568static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300569{
570 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300571
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300572 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300573 reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300574
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300575 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300576}
577
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300578static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300579{
580 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300581
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300582 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300583 reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300584
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300585 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300586}
587
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300588static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300589{
590 struct sd *sd = (struct sd *) gspca_dev;
591
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300592 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300593 reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300594
595 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300596 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300597}
598
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300599static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300600{
601 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineae251e62012-02-27 05:15:12 -0300602 u8 clockdiv;
603 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300604
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300605 /* register 2 of frame 3 contains the clock divider configuring the
606 no fps according to the formula: 90 / reg. sd->exposure is the
607 desired exposure time in 0.5 ms. */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300608 clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300609
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300610 /* Note clockdiv = 3 also works, but when running at 30 fps, depending
611 on the scene being recorded, the camera switches to another
612 quantization table for certain JPEG blocks, and we don't know how
613 to decompress these blocks. So we cap the framerate at 15 fps */
614 if (clockdiv < 6)
615 clockdiv = 6;
616 else if (clockdiv > 63)
617 clockdiv = 63;
618
619 /* reg2 MUST be a multiple of 3, except when between 6 and 12?
620 Always round up, otherwise we cannot get the desired frametime
621 using the partial frame time exposure control */
622 if (clockdiv < 6 || clockdiv > 12)
623 clockdiv = ((clockdiv + 2) / 3) * 3;
624
625 /* frame exposure time in ms = 1000 * clockdiv / 90 ->
626 exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300627 exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300628 /* 0 = use full frametime, 448 = no exposure, reverse it */
629 exposure = 448 - exposure;
630
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300631 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300632 reg_w(gspca_dev, 0x02, clockdiv);
633 reg_w(gspca_dev, 0x0e, exposure & 0xff);
634 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300635
636 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300637 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300638}
639
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300640static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300641{
642 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300643 u8 data, hflip, vflip;
644
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300645 hflip = sd->ctrls[HFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300646 if (sd->flags & FL_HFLIP)
647 hflip = !hflip;
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300648 vflip = sd->ctrls[VFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300649 if (sd->flags & FL_VFLIP)
650 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300651
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300652 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300653 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300654 reg_w(gspca_dev, 0x21, data);
655
Marton Nemeth1408b842009-11-02 08:13:21 -0300656 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300657 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300658}
659
660/* this function is called at probe and resume time for pac7302 */
661static int sd_init(struct gspca_dev *gspca_dev)
662{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300663 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
664 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300665}
666
667static int sd_start(struct gspca_dev *gspca_dev)
668{
669 struct sd *sd = (struct sd *) gspca_dev;
670
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300671 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300672 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300673 setbrightcont(gspca_dev);
674 setcolors(gspca_dev);
675 setwhitebalance(gspca_dev);
676 setredbalance(gspca_dev);
677 setbluebalance(gspca_dev);
678 setgain(gspca_dev);
679 setexposure(gspca_dev);
680 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300681
682 /* only resolution 640x480 is supported for pac7302 */
683
684 sd->sof_read = 0;
685 sd->autogain_ignore_frames = 0;
686 atomic_set(&sd->avg_lum, -1);
687
688 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300689 reg_w(gspca_dev, 0xff, 0x01);
690 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300691
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300692 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300693}
694
695static void sd_stopN(struct gspca_dev *gspca_dev)
696{
Márton Némethb1784b32009-11-07 05:52:02 -0300697
Márton Németh67c98f72009-11-07 05:45:33 -0300698 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300699 reg_w(gspca_dev, 0xff, 0x01);
700 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300701}
702
703/* called on streamoff with alt 0 and on disconnect for pac7302 */
704static void sd_stop0(struct gspca_dev *gspca_dev)
705{
706 if (!gspca_dev->present)
707 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300708 reg_w(gspca_dev, 0xff, 0x01);
709 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300710}
711
712/* Include pac common sof detection functions */
713#include "pac_common.h"
714
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300715/* !! coarse_grained_expo_autogain is not used !! */
716#define exp_too_low_cnt flags
717#define exp_too_high_cnt sof_read
718#include "autogain_functions.h"
719
Marton Nemeth1408b842009-11-02 08:13:21 -0300720static void do_autogain(struct gspca_dev *gspca_dev)
721{
722 struct sd *sd = (struct sd *) gspca_dev;
723 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300724 int desired_lum;
725 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300726
727 if (avg_lum == -1)
728 return;
729
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300730 desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
Marton Nemeth1408b842009-11-02 08:13:21 -0300731
732 if (sd->autogain_ignore_frames > 0)
733 sd->autogain_ignore_frames--;
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300734 else if (auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Marton Nemeth1408b842009-11-02 08:13:21 -0300735 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
736 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
737}
738
Jean-François Moine7532e812012-02-27 05:21:57 -0300739/* JPEG header */
740static const u8 jpeg_header[] = {
741 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300742
Jean-François Moine7532e812012-02-27 05:21:57 -0300743 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
744 0x00, 0x11, /* length = 17 bytes (including this length field) */
745 0x08, /* Precision: 8 */
746 0x02, 0x80, /* height = 640 (image rotated) */
747 0x01, 0xe0, /* width = 480 */
748 0x03, /* Number of image components: 3 */
749 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
750 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
751 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
752
753 0xff, 0xda, /* SOS: Start Of Scan */
754 0x00, 0x0c, /* length = 12 bytes (including this length field) */
755 0x03, /* number of components: 3 */
756 0x01, 0x00, /* selector 1, table 0x00 */
757 0x02, 0x11, /* selector 2, table 0x11 */
758 0x03, 0x11, /* selector 3, table 0x11 */
759 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
760 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300761};
762
Marton Nemeth1408b842009-11-02 08:13:21 -0300763/* this function is run at interrupt level */
764static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300765 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300766 int len) /* iso packet length */
767{
768 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300769 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300770 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300771
772 sof = pac_find_sof(&sd->sof_read, data, len);
773 if (sof) {
774 int n, lum_offset, footer_length;
775
776 /* 6 bytes after the FF D9 EOF marker a number of lumination
777 bytes are send corresponding to different parts of the
778 image, the 14th and 15th byte after the EOF seem to
779 correspond to the center of the image */
780 lum_offset = 61 + sizeof pac_sof_marker;
781 footer_length = 74;
782
783 /* Finish decoding current frame */
784 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
785 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300786 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300787 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300788 } else {
789 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300790 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300791
792 image = gspca_dev->image;
793 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300794 && image[gspca_dev->image_len - 2] == 0xff
795 && image[gspca_dev->image_len - 1] == 0xd9)
796 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300797
798 n = sof - data;
799 len -= n;
800 data = sof;
801
802 /* Get average lumination */
803 if (gspca_dev->last_packet_type == LAST_PACKET &&
804 n >= lum_offset)
805 atomic_set(&sd->avg_lum, data[-lum_offset] +
806 data[-lum_offset + 1]);
807 else
808 atomic_set(&sd->avg_lum, -1);
809
810 /* Start the new frame with the jpeg header */
811 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300812 gspca_frame_add(gspca_dev, FIRST_PACKET,
813 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300814 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300815 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300816}
817
Marton Nemeth1408b842009-11-02 08:13:21 -0300818static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
819{
820 struct sd *sd = (struct sd *) gspca_dev;
821
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300822 sd->ctrls[AUTOGAIN].val = val;
Marton Nemeth1408b842009-11-02 08:13:21 -0300823 /* when switching to autogain set defaults to make sure
824 we are on a valid point of the autogain gain /
825 exposure knee graph, and give this change time to
826 take effect before doing autogain. */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300827 if (sd->ctrls[AUTOGAIN].val) {
828 sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
829 sd->ctrls[GAIN].val = GAIN_DEF;
Marton Nemeth1408b842009-11-02 08:13:21 -0300830 if (gspca_dev->streaming) {
831 sd->autogain_ignore_frames =
832 PAC_AUTOGAIN_IGNORE_FRAMES;
833 setexposure(gspca_dev);
834 setgain(gspca_dev);
835 }
836 }
837
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300838 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300839}
840
Márton Németh6763cc02009-11-09 07:10:46 -0300841#ifdef CONFIG_VIDEO_ADV_DEBUG
842static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
843 struct v4l2_dbg_register *reg)
844{
Jean-François Moineae251e62012-02-27 05:15:12 -0300845 u8 index;
846 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300847
848 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
849 long on the USB bus)
850 */
851 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
852 reg->match.addr == 0 &&
853 (reg->reg < 0x000000ff) &&
854 (reg->val <= 0x000000ff)
855 ) {
856 /* Currently writing to page 0 is only supported. */
857 /* reg_w() only supports 8bit index */
Jean-François Moineae251e62012-02-27 05:15:12 -0300858 index = reg->reg;
859 value = reg->val;
Márton Németh6763cc02009-11-09 07:10:46 -0300860
861 /* Note that there shall be no access to other page
862 by any other function between the page swith and
863 the actual register write */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300864 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
865 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300866
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300867 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300868 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300869 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300870}
871
872static int sd_chip_ident(struct gspca_dev *gspca_dev,
873 struct v4l2_dbg_chip_ident *chip)
874{
875 int ret = -EINVAL;
876
877 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
878 chip->match.addr == 0) {
879 chip->revision = 0;
880 chip->ident = V4L2_IDENT_UNKNOWN;
881 ret = 0;
882 }
883 return ret;
884}
885#endif
886
Jean-François Moine28566432010-10-01 07:33:26 -0300887#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300888static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
889 u8 *data, /* interrupt packet data */
890 int len) /* interrput packet length */
891{
892 int ret = -EINVAL;
893 u8 data0, data1;
894
895 if (len == 2) {
896 data0 = data[0];
897 data1 = data[1];
898 if ((data0 == 0x00 && data1 == 0x11) ||
899 (data0 == 0x22 && data1 == 0x33) ||
900 (data0 == 0x44 && data1 == 0x55) ||
901 (data0 == 0x66 && data1 == 0x77) ||
902 (data0 == 0x88 && data1 == 0x99) ||
903 (data0 == 0xaa && data1 == 0xbb) ||
904 (data0 == 0xcc && data1 == 0xdd) ||
905 (data0 == 0xee && data1 == 0xff)) {
906 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
907 input_sync(gspca_dev->input_dev);
908 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
909 input_sync(gspca_dev->input_dev);
910 ret = 0;
911 }
912 }
913
914 return ret;
915}
916#endif
917
Marton Nemeth1408b842009-11-02 08:13:21 -0300918/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300919static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300920 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300921 .ctrls = sd_ctrls,
922 .nctrls = ARRAY_SIZE(sd_ctrls),
923 .config = sd_config,
924 .init = sd_init,
925 .start = sd_start,
926 .stopN = sd_stopN,
927 .stop0 = sd_stop0,
928 .pkt_scan = sd_pkt_scan,
929 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300930#ifdef CONFIG_VIDEO_ADV_DEBUG
931 .set_register = sd_dbg_s_register,
932 .get_chip_ident = sd_chip_ident,
933#endif
Jean-François Moine28566432010-10-01 07:33:26 -0300934#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300935 .int_pkt_scan = sd_int_pkt_scan,
936#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300937};
938
939/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300940static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300941 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300942 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300943 {USB_DEVICE(0x093a, 0x2620)},
944 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300945 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
946 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300947 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300948 {USB_DEVICE(0x093a, 0x2626)},
949 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300950 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300951 {USB_DEVICE(0x093a, 0x262a)},
952 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300953 {USB_DEVICE(0x145f, 0x013c)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300954 {}
955};
956MODULE_DEVICE_TABLE(usb, device_table);
957
958/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300959static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300960 const struct usb_device_id *id)
961{
962 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
963 THIS_MODULE);
964}
965
966static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300967 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300968 .id_table = device_table,
969 .probe = sd_probe,
970 .disconnect = gspca_disconnect,
971#ifdef CONFIG_PM
972 .suspend = gspca_suspend,
973 .resume = gspca_resume,
974#endif
975};
976
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800977module_usb_driver(sd_driver);