blob: 1e88d3a574d914cd3419495fcf5cc29aacda884b [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
Hans de Goede895d4642012-04-28 10:31:17 -030026/*
27 * Some documentation about various registers as determined by trial and error.
28 *
29 * Register page 1:
30 *
31 * Address Description
32 * 0x78 Global control, bit 6 controls the LED (inverted)
33 *
34 * Register page 3:
35 *
36 * Address Description
37 * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
38 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
39 * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
40 * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
41 * 63 -> ~27 fps, the 2 msb's must always be 1 !!
42 * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
43 * 1 -> ~30 fps, 2 -> ~20 fps
44 * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
45 * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
46 * 0x10 Master gain 0-31
47 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
48 *
49 * The registers are accessed in the following functions:
50 *
51 * Page | Register | Function
52 * -----+------------+---------------------------------------------------
53 * 0 | 0x0f..0x20 | setcolors()
54 * 0 | 0xa2..0xab | setbrightcont()
55 * 0 | 0xc5 | setredbalance()
56 * 0 | 0xc6 | setwhitebalance()
57 * 0 | 0xc7 | setbluebalance()
58 * 0 | 0xdc | setbrightcont(), setcolors()
59 * 3 | 0x02 | setexposure()
60 * 3 | 0x10 | setgain()
61 * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
62 * 3 | 0x21 | sethvflip()
63 */
Marton Nemeth1408b842009-11-02 08:13:21 -030064
Joe Perches133a9fe2011-08-21 19:56:57 -030065#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
66
Márton Némethaed6f1b2010-01-28 16:33:38 -030067#include <linux/input.h>
Márton Németh6763cc02009-11-09 07:10:46 -030068#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030069#include "gspca.h"
Jean-François Moineac399cd2012-02-27 05:40:47 -030070/* Include pac common sof detection functions */
71#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030072
Jean-François Moineae251e62012-02-27 05:15:12 -030073MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
74 "Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -030075MODULE_DESCRIPTION("Pixart PAC7302");
76MODULE_LICENSE("GPL");
77
Jean-François Moineaa5b7922012-02-27 05:38:09 -030078enum e_ctrl {
79 BRIGHTNESS,
80 CONTRAST,
81 COLORS,
82 WHITE_BALANCE,
83 RED_BALANCE,
84 BLUE_BALANCE,
85 GAIN,
86 AUTOGAIN,
87 EXPOSURE,
88 VFLIP,
89 HFLIP,
90 NCTRLS /* number of controls */
91};
92
Marton Nemeth1408b842009-11-02 08:13:21 -030093struct sd {
94 struct gspca_dev gspca_dev; /* !! must be the first item */
95
Jean-François Moineaa5b7922012-02-27 05:38:09 -030096 struct gspca_ctrl ctrls[NCTRLS];
97
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -030098 u8 flags;
99#define FL_HFLIP 0x01 /* mirrored by default */
100#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -0300101
102 u8 sof_read;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300103 s8 autogain_ignore_frames;
Marton Nemeth1408b842009-11-02 08:13:21 -0300104
105 atomic_t avg_lum;
106};
107
108/* V4L2 controls supported by the driver */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300109static void setbrightcont(struct gspca_dev *gspca_dev);
110static void setcolors(struct gspca_dev *gspca_dev);
111static void setwhitebalance(struct gspca_dev *gspca_dev);
112static void setredbalance(struct gspca_dev *gspca_dev);
113static void setbluebalance(struct gspca_dev *gspca_dev);
114static void setgain(struct gspca_dev *gspca_dev);
115static void setexposure(struct gspca_dev *gspca_dev);
Jean-François Moineac399cd2012-02-27 05:40:47 -0300116static void setautogain(struct gspca_dev *gspca_dev);
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300117static void sethvflip(struct gspca_dev *gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300118
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300119static const struct ctrl sd_ctrls[] = {
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300120[BRIGHTNESS] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300121 {
122 .id = V4L2_CID_BRIGHTNESS,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Brightness",
125 .minimum = 0,
126#define BRIGHTNESS_MAX 0x20
127 .maximum = BRIGHTNESS_MAX,
128 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300129 .default_value = 0x10,
Marton Nemeth1408b842009-11-02 08:13:21 -0300130 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300131 .set_control = setbrightcont
Marton Nemeth1408b842009-11-02 08:13:21 -0300132 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300133[CONTRAST] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300134 {
135 .id = V4L2_CID_CONTRAST,
136 .type = V4L2_CTRL_TYPE_INTEGER,
137 .name = "Contrast",
138 .minimum = 0,
139#define CONTRAST_MAX 255
140 .maximum = CONTRAST_MAX,
141 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300142 .default_value = 127,
Marton Nemeth1408b842009-11-02 08:13:21 -0300143 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300144 .set_control = setbrightcont
Marton Nemeth1408b842009-11-02 08:13:21 -0300145 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300146[COLORS] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300147 {
148 .id = V4L2_CID_SATURATION,
149 .type = V4L2_CTRL_TYPE_INTEGER,
150 .name = "Saturation",
151 .minimum = 0,
152#define COLOR_MAX 255
153 .maximum = COLOR_MAX,
154 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300155 .default_value = 127
Marton Nemeth1408b842009-11-02 08:13:21 -0300156 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300157 .set_control = setcolors
Marton Nemeth1408b842009-11-02 08:13:21 -0300158 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300159[WHITE_BALANCE] = {
Márton Németh265a8092009-11-07 15:15:56 -0300160 {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300161 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
162 .type = V4L2_CTRL_TYPE_INTEGER,
163 .name = "White Balance",
164 .minimum = 0,
165 .maximum = 255,
166 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300167 .default_value = 4,
Marton Nemeth23fbee62009-11-08 04:35:12 -0300168 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300169 .set_control = setwhitebalance
Marton Nemeth23fbee62009-11-08 04:35:12 -0300170 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300171[RED_BALANCE] = {
Marton Nemeth23fbee62009-11-08 04:35:12 -0300172 {
Márton Németh265a8092009-11-07 15:15:56 -0300173 .id = V4L2_CID_RED_BALANCE,
174 .type = V4L2_CTRL_TYPE_INTEGER,
175 .name = "Red",
176 .minimum = 0,
177 .maximum = 3,
178 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300179 .default_value = 1,
Márton Németh265a8092009-11-07 15:15:56 -0300180 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300181 .set_control = setredbalance
Márton Németh265a8092009-11-07 15:15:56 -0300182 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300183[BLUE_BALANCE] = {
Márton Németh265a8092009-11-07 15:15:56 -0300184 {
185 .id = V4L2_CID_BLUE_BALANCE,
186 .type = V4L2_CTRL_TYPE_INTEGER,
187 .name = "Blue",
188 .minimum = 0,
189 .maximum = 3,
190 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300191 .default_value = 1,
Márton Németh265a8092009-11-07 15:15:56 -0300192 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300193 .set_control = setbluebalance
Márton Németh265a8092009-11-07 15:15:56 -0300194 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300195[GAIN] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300196 {
197 .id = V4L2_CID_GAIN,
198 .type = V4L2_CTRL_TYPE_INTEGER,
199 .name = "Gain",
200 .minimum = 0,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300201 .maximum = 255,
Marton Nemeth1408b842009-11-02 08:13:21 -0300202 .step = 1,
203#define GAIN_DEF 127
204#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
205 .default_value = GAIN_DEF,
206 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300207 .set_control = setgain
Marton Nemeth1408b842009-11-02 08:13:21 -0300208 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300209[EXPOSURE] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300210 {
211 .id = V4L2_CID_EXPOSURE,
212 .type = V4L2_CTRL_TYPE_INTEGER,
213 .name = "Exposure",
214 .minimum = 0,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300215 .maximum = 1023,
Marton Nemeth1408b842009-11-02 08:13:21 -0300216 .step = 1,
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300217#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */
218#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
Marton Nemeth1408b842009-11-02 08:13:21 -0300219 .default_value = EXPOSURE_DEF,
220 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300221 .set_control = setexposure
Marton Nemeth1408b842009-11-02 08:13:21 -0300222 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300223[AUTOGAIN] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300224 {
225 .id = V4L2_CID_AUTOGAIN,
226 .type = V4L2_CTRL_TYPE_BOOLEAN,
227 .name = "Auto Gain",
228 .minimum = 0,
229 .maximum = 1,
230 .step = 1,
231#define AUTOGAIN_DEF 1
232 .default_value = AUTOGAIN_DEF,
233 },
Jean-François Moineac399cd2012-02-27 05:40:47 -0300234 .set_control = setautogain,
Marton Nemeth1408b842009-11-02 08:13:21 -0300235 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300236[HFLIP] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300237 {
238 .id = V4L2_CID_HFLIP,
239 .type = V4L2_CTRL_TYPE_BOOLEAN,
240 .name = "Mirror",
241 .minimum = 0,
242 .maximum = 1,
243 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300244 .default_value = 0,
Marton Nemeth1408b842009-11-02 08:13:21 -0300245 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300246 .set_control = sethvflip,
Marton Nemeth1408b842009-11-02 08:13:21 -0300247 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300248[VFLIP] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300249 {
250 .id = V4L2_CID_VFLIP,
251 .type = V4L2_CTRL_TYPE_BOOLEAN,
252 .name = "Vflip",
253 .minimum = 0,
254 .maximum = 1,
255 .step = 1,
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300256 .default_value = 0,
Marton Nemeth1408b842009-11-02 08:13:21 -0300257 },
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300258 .set_control = sethvflip
Marton Nemeth1408b842009-11-02 08:13:21 -0300259 },
260};
261
262static const struct v4l2_pix_format vga_mode[] = {
263 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
264 .bytesperline = 640,
265 .sizeimage = 640 * 480 * 3 / 8 + 590,
266 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300267 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300268};
269
270#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300271#define END_OF_SEQUENCE 0
272
Jean-François Moineae251e62012-02-27 05:15:12 -0300273static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300274/* index,value */
275 0xff, 0x01, /* page 1 */
276 0x78, 0x00, /* deactivate */
277 0xff, 0x01,
278 0x78, 0x40, /* led off */
279};
Jean-François Moineae251e62012-02-27 05:15:12 -0300280static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300281/* index, len, [value]* */
282 0xff, 1, 0x00, /* page 0 */
283 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
284 0x00, 0x00, 0x00, 0x00,
285 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
286 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
287 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
288 0x26, 2, 0xaa, 0xaa,
289 0x2e, 1, 0x31,
290 0x38, 1, 0x01,
291 0x3a, 3, 0x14, 0xff, 0x5a,
292 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
293 0x00, 0x54, 0x11,
294 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300295 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300296 0x6b, 1, 0x00,
297 0x6e, 3, 0x08, 0x06, 0x00,
298 0x72, 3, 0x00, 0xff, 0x00,
299 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
300 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
301 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
302 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
303 0xd2, 0xeb,
304 0xaf, 1, 0x02,
305 0xb5, 2, 0x08, 0x08,
306 0xb8, 2, 0x08, 0x88,
307 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
308 0xcc, 1, 0x00,
309 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
310 0xc1, 0xd7, 0xec,
311 0xdc, 1, 0x01,
312 0xff, 1, 0x01, /* page 1 */
313 0x12, 3, 0x02, 0x00, 0x01,
314 0x3e, 2, 0x00, 0x00,
315 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
316 0x7c, 1, 0x00,
317 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
318 0x02, 0x00,
319 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
320 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
321 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
322 0xd8, 1, 0x01,
323 0xdb, 2, 0x00, 0x01,
324 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
325 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
326 0xeb, 1, 0x00,
327 0xff, 1, 0x02, /* page 2 */
328 0x22, 1, 0x00,
329 0xff, 1, 0x03, /* page 3 */
330 0, LOAD_PAGE3, /* load the page 3 */
331 0x11, 1, 0x01,
332 0xff, 1, 0x02, /* page 2 */
333 0x13, 1, 0x00,
334 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
335 0x27, 2, 0x14, 0x0c,
336 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
337 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
338 0x6e, 1, 0x08,
339 0xff, 1, 0x01, /* page 1 */
340 0x78, 1, 0x00,
341 0, END_OF_SEQUENCE /* end of sequence */
342};
343
344#define SKIP 0xaa
345/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300346static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300347 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300348 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
349 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
351 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
352 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
353 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
354 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300356 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300357 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
361 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
362 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
363 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
366 0x00
367};
368
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300369static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300370 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300371 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300372{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300373 int ret;
374
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300375 if (gspca_dev->usb_err < 0)
376 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300377 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300378 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300379 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300380 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300381 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
382 0, /* value */
383 index, gspca_dev->usb_buf, len,
384 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300385 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300386 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300387 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300388 gspca_dev->usb_err = ret;
389 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300390}
391
392
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300393static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300394 u8 index,
395 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300396{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300397 int ret;
398
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300399 if (gspca_dev->usb_err < 0)
400 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300401 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300402 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300403 usb_sndctrlpipe(gspca_dev->dev, 0),
404 0, /* request */
405 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
406 0, index, gspca_dev->usb_buf, 1,
407 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300408 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300409 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300410 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300411 gspca_dev->usb_err = ret;
412 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300413}
414
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300415static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300416 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300417{
418 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300419 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300420 seq += 2;
421 }
422}
423
424/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300425static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300426 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300427{
428 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300429 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300430
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300431 if (gspca_dev->usb_err < 0)
432 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300433 for (index = 0; index < len; index++) {
434 if (page[index] == SKIP) /* skip this index */
435 continue;
436 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300437 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300438 usb_sndctrlpipe(gspca_dev->dev, 0),
439 0, /* request */
440 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
441 0, index, gspca_dev->usb_buf, 1,
442 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300443 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300444 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300445 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300446 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300447 break;
448 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300449 }
450}
451
452/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300453static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300454 const u8 *seq,
455 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300456{
457 int index, len;
458
459 for (;;) {
460 index = *seq++;
461 len = *seq++;
462 switch (len) {
463 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300464 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300465 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300466 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300467 break;
468 default:
Jean-François Moineae251e62012-02-27 05:15:12 -0300469#ifdef GSPCA_DEBUG
Marton Nemeth1408b842009-11-02 08:13:21 -0300470 if (len > USB_BUF_SZ) {
471 PDEBUG(D_ERR|D_STREAM,
472 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300473 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300474 }
Jean-François Moineae251e62012-02-27 05:15:12 -0300475#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300476 while (len > 0) {
477 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300478 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300479 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300480 seq += len;
481 break;
482 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300483 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300484 seq += 8;
485 index += 8;
486 len -= 8;
487 }
488 }
489 }
490 /* not reached */
491}
492
493/* this function is called at probe time for pac7302 */
494static int sd_config(struct gspca_dev *gspca_dev,
495 const struct usb_device_id *id)
496{
497 struct sd *sd = (struct sd *) gspca_dev;
498 struct cam *cam;
499
500 cam = &gspca_dev->cam;
501
Marton Nemeth1408b842009-11-02 08:13:21 -0300502 cam->cam_mode = vga_mode; /* only 640x480 */
503 cam->nmodes = ARRAY_SIZE(vga_mode);
504
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300505 gspca_dev->cam.ctrls = sd->ctrls;
506
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300507 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300508 return 0;
509}
510
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
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300537static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300538{
539 struct sd *sd = (struct sd *) gspca_dev;
540 int i, v;
541 static const int a[9] =
542 {217, -212, 0, -101, 170, -67, -38, -315, 355};
543 static const int b[9] =
544 {19, 106, 0, 19, 106, 1, 19, 106, 1};
545
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300546 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
547 reg_w(gspca_dev, 0x11, 0x01);
548 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300549 for (i = 0; i < 9; i++) {
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300550 v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300551 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
552 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300553 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300554 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300555}
556
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300557static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300558{
559 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300560
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300561 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300562 reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300563
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300564 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300565}
566
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300567static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300568{
569 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300570
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300571 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300572 reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300573
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300574 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300575}
576
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300577static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300578{
579 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300580
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300581 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300582 reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300583
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300584 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300585}
586
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300587static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300588{
589 struct sd *sd = (struct sd *) gspca_dev;
590
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300591 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300592 reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300593
594 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300595 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300596}
597
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300598static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300599{
600 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineae251e62012-02-27 05:15:12 -0300601 u8 clockdiv;
602 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300603
Hans de Goede895d4642012-04-28 10:31:17 -0300604 /*
605 * 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.
608 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300609 clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300610
Hans de Goede895d4642012-04-28 10:31:17 -0300611 /*
612 * Note clockdiv = 3 also works, but when running at 30 fps, depending
613 * on the scene being recorded, the camera switches to another
614 * quantization table for certain JPEG blocks, and we don't know how
615 * to decompress these blocks. So we cap the framerate at 15 fps.
616 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300617 if (clockdiv < 6)
618 clockdiv = 6;
619 else if (clockdiv > 63)
620 clockdiv = 63;
621
Hans de Goede895d4642012-04-28 10:31:17 -0300622 /*
623 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
624 * Always round up, otherwise we cannot get the desired frametime
625 * using the partial frame time exposure control.
626 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300627 if (clockdiv < 6 || clockdiv > 12)
628 clockdiv = ((clockdiv + 2) / 3) * 3;
629
Hans de Goede895d4642012-04-28 10:31:17 -0300630 /*
631 * frame exposure time in ms = 1000 * clockdiv / 90 ->
632 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
633 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300634 exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300635 /* 0 = use full frametime, 448 = no exposure, reverse it */
636 exposure = 448 - exposure;
637
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300638 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300639 reg_w(gspca_dev, 0x02, clockdiv);
640 reg_w(gspca_dev, 0x0e, exposure & 0xff);
641 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300642
643 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300644 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300645}
646
Jean-François Moineac399cd2012-02-27 05:40:47 -0300647static void setautogain(struct gspca_dev *gspca_dev)
648{
649 struct sd *sd = (struct sd *) gspca_dev;
650
Hans de Goede895d4642012-04-28 10:31:17 -0300651 /*
652 * When switching to autogain set defaults to make sure
653 * we are on a valid point of the autogain gain /
654 * exposure knee graph, and give this change time to
655 * take effect before doing autogain.
656 */
Jean-François Moineac399cd2012-02-27 05:40:47 -0300657 if (sd->ctrls[AUTOGAIN].val) {
658 sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
659 sd->ctrls[GAIN].val = GAIN_DEF;
660 sd->autogain_ignore_frames =
661 PAC_AUTOGAIN_IGNORE_FRAMES;
662 } else {
663 sd->autogain_ignore_frames = -1;
664 }
665 setexposure(gspca_dev);
666 setgain(gspca_dev);
667}
668
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300669static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300670{
671 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300672 u8 data, hflip, vflip;
673
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300674 hflip = sd->ctrls[HFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300675 if (sd->flags & FL_HFLIP)
676 hflip = !hflip;
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300677 vflip = sd->ctrls[VFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300678 if (sd->flags & FL_VFLIP)
679 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300680
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300681 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300682 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300683 reg_w(gspca_dev, 0x21, data);
684
Marton Nemeth1408b842009-11-02 08:13:21 -0300685 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300686 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300687}
688
689/* this function is called at probe and resume time for pac7302 */
690static int sd_init(struct gspca_dev *gspca_dev)
691{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300692 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
693 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300694}
695
696static int sd_start(struct gspca_dev *gspca_dev)
697{
698 struct sd *sd = (struct sd *) gspca_dev;
699
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300700 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300701 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300702 setbrightcont(gspca_dev);
703 setcolors(gspca_dev);
704 setwhitebalance(gspca_dev);
705 setredbalance(gspca_dev);
706 setbluebalance(gspca_dev);
Jean-François Moineac399cd2012-02-27 05:40:47 -0300707 setautogain(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300708 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300709
Marton Nemeth1408b842009-11-02 08:13:21 -0300710 sd->sof_read = 0;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300711 atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300712
713 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300714 reg_w(gspca_dev, 0xff, 0x01);
715 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300716
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300717 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300718}
719
720static void sd_stopN(struct gspca_dev *gspca_dev)
721{
Márton Némethb1784b32009-11-07 05:52:02 -0300722
Márton Németh67c98f72009-11-07 05:45:33 -0300723 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300724 reg_w(gspca_dev, 0xff, 0x01);
725 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300726}
727
728/* called on streamoff with alt 0 and on disconnect for pac7302 */
729static void sd_stop0(struct gspca_dev *gspca_dev)
730{
731 if (!gspca_dev->present)
732 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300733 reg_w(gspca_dev, 0xff, 0x01);
734 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300735}
736
Hans de Goedea648e312012-04-27 11:32:24 -0300737#define WANT_REGULAR_AUTOGAIN
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300738#include "autogain_functions.h"
739
Marton Nemeth1408b842009-11-02 08:13:21 -0300740static void do_autogain(struct gspca_dev *gspca_dev)
741{
742 struct sd *sd = (struct sd *) gspca_dev;
743 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300744 int desired_lum;
745 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300746
Jean-François Moineac399cd2012-02-27 05:40:47 -0300747 if (sd->autogain_ignore_frames < 0)
Marton Nemeth1408b842009-11-02 08:13:21 -0300748 return;
749
Jean-François Moineac399cd2012-02-27 05:40:47 -0300750 if (sd->autogain_ignore_frames > 0) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300751 sd->autogain_ignore_frames--;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300752 } else {
753 desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
754
755 auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
756 deadzone, GAIN_KNEE, EXPOSURE_KNEE);
Marton Nemeth1408b842009-11-02 08:13:21 -0300757 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300758 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300759}
760
Jean-François Moine7532e812012-02-27 05:21:57 -0300761/* JPEG header */
762static const u8 jpeg_header[] = {
763 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300764
Jean-François Moine7532e812012-02-27 05:21:57 -0300765 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
766 0x00, 0x11, /* length = 17 bytes (including this length field) */
767 0x08, /* Precision: 8 */
768 0x02, 0x80, /* height = 640 (image rotated) */
769 0x01, 0xe0, /* width = 480 */
770 0x03, /* Number of image components: 3 */
771 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
772 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
773 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
774
775 0xff, 0xda, /* SOS: Start Of Scan */
776 0x00, 0x0c, /* length = 12 bytes (including this length field) */
777 0x03, /* number of components: 3 */
778 0x01, 0x00, /* selector 1, table 0x00 */
779 0x02, 0x11, /* selector 2, table 0x11 */
780 0x03, 0x11, /* selector 3, table 0x11 */
781 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
782 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300783};
784
Marton Nemeth1408b842009-11-02 08:13:21 -0300785/* this function is run at interrupt level */
786static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300787 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300788 int len) /* iso packet length */
789{
790 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300791 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300792 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300793
794 sof = pac_find_sof(&sd->sof_read, data, len);
795 if (sof) {
796 int n, lum_offset, footer_length;
797
Hans de Goede895d4642012-04-28 10:31:17 -0300798 /*
799 * 6 bytes after the FF D9 EOF marker a number of lumination
800 * bytes are send corresponding to different parts of the
801 * image, the 14th and 15th byte after the EOF seem to
802 * correspond to the center of the image.
803 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300804 lum_offset = 61 + sizeof pac_sof_marker;
805 footer_length = 74;
806
807 /* Finish decoding current frame */
808 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
809 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300810 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300811 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300812 } else {
813 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300814 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300815
816 image = gspca_dev->image;
817 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300818 && image[gspca_dev->image_len - 2] == 0xff
819 && image[gspca_dev->image_len - 1] == 0xd9)
820 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300821
822 n = sof - data;
823 len -= n;
824 data = sof;
825
826 /* Get average lumination */
827 if (gspca_dev->last_packet_type == LAST_PACKET &&
828 n >= lum_offset)
829 atomic_set(&sd->avg_lum, data[-lum_offset] +
830 data[-lum_offset + 1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300831
832 /* Start the new frame with the jpeg header */
833 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300834 gspca_frame_add(gspca_dev, FIRST_PACKET,
835 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300836 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300837 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300838}
839
Márton Németh6763cc02009-11-09 07:10:46 -0300840#ifdef CONFIG_VIDEO_ADV_DEBUG
841static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
842 struct v4l2_dbg_register *reg)
843{
Jean-François Moineae251e62012-02-27 05:15:12 -0300844 u8 index;
845 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300846
Hans de Goede895d4642012-04-28 10:31:17 -0300847 /*
848 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
849 * long on the USB bus)
850 */
Márton Németh6763cc02009-11-09 07:10:46 -0300851 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
Hans de Goede895d4642012-04-28 10:31:17 -0300861 /*
862 * Note that there shall be no access to other page
863 * by any other function between the page switch and
864 * the actual register write.
865 */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300866 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
867 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300868
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300869 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300870 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300871 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300872}
873
874static int sd_chip_ident(struct gspca_dev *gspca_dev,
875 struct v4l2_dbg_chip_ident *chip)
876{
877 int ret = -EINVAL;
878
879 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
880 chip->match.addr == 0) {
881 chip->revision = 0;
882 chip->ident = V4L2_IDENT_UNKNOWN;
883 ret = 0;
884 }
885 return ret;
886}
887#endif
888
Jean-François Moine28566432010-10-01 07:33:26 -0300889#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300890static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
891 u8 *data, /* interrupt packet data */
892 int len) /* interrput packet length */
893{
894 int ret = -EINVAL;
895 u8 data0, data1;
896
897 if (len == 2) {
898 data0 = data[0];
899 data1 = data[1];
900 if ((data0 == 0x00 && data1 == 0x11) ||
901 (data0 == 0x22 && data1 == 0x33) ||
902 (data0 == 0x44 && data1 == 0x55) ||
903 (data0 == 0x66 && data1 == 0x77) ||
904 (data0 == 0x88 && data1 == 0x99) ||
905 (data0 == 0xaa && data1 == 0xbb) ||
906 (data0 == 0xcc && data1 == 0xdd) ||
907 (data0 == 0xee && data1 == 0xff)) {
908 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
909 input_sync(gspca_dev->input_dev);
910 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
911 input_sync(gspca_dev->input_dev);
912 ret = 0;
913 }
914 }
915
916 return ret;
917}
918#endif
919
Marton Nemeth1408b842009-11-02 08:13:21 -0300920/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300921static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300922 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300923 .ctrls = sd_ctrls,
924 .nctrls = ARRAY_SIZE(sd_ctrls),
925 .config = sd_config,
926 .init = sd_init,
927 .start = sd_start,
928 .stopN = sd_stopN,
929 .stop0 = sd_stop0,
930 .pkt_scan = sd_pkt_scan,
931 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300932#ifdef CONFIG_VIDEO_ADV_DEBUG
933 .set_register = sd_dbg_s_register,
934 .get_chip_ident = sd_chip_ident,
935#endif
Jean-François Moine28566432010-10-01 07:33:26 -0300936#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300937 .int_pkt_scan = sd_int_pkt_scan,
938#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300939};
940
941/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300942static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300943 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300944 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300945 {USB_DEVICE(0x093a, 0x2620)},
946 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300947 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
948 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300949 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300950 {USB_DEVICE(0x093a, 0x2626)},
951 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300952 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300953 {USB_DEVICE(0x093a, 0x262a)},
954 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300955 {USB_DEVICE(0x145f, 0x013c)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300956 {}
957};
958MODULE_DEVICE_TABLE(usb, device_table);
959
960/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300961static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300962 const struct usb_device_id *id)
963{
964 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
965 THIS_MODULE);
966}
967
968static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300969 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300970 .id_table = device_table,
971 .probe = sd_probe,
972 .disconnect = gspca_disconnect,
973#ifdef CONFIG_PM
974 .suspend = gspca_suspend,
975 .resume = gspca_resume,
976#endif
977};
978
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800979module_usb_driver(sd_driver);