blob: 30662fccb0cf9320591910fad716d0cbfe0d2e06 [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"
Jean-François Moineac399cd2012-02-27 05:40:47 -030069/* Include pac common sof detection functions */
70#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030071
Jean-François Moineae251e62012-02-27 05:15:12 -030072MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
73 "Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -030074MODULE_DESCRIPTION("Pixart PAC7302");
75MODULE_LICENSE("GPL");
76
Jean-François Moineaa5b7922012-02-27 05:38:09 -030077enum e_ctrl {
78 BRIGHTNESS,
79 CONTRAST,
80 COLORS,
81 WHITE_BALANCE,
82 RED_BALANCE,
83 BLUE_BALANCE,
84 GAIN,
85 AUTOGAIN,
86 EXPOSURE,
87 VFLIP,
88 HFLIP,
89 NCTRLS /* number of controls */
90};
91
Marton Nemeth1408b842009-11-02 08:13:21 -030092/* specific webcam descriptor for pac7302 */
93struct 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
273/* pac 7302 */
Jean-François Moineae251e62012-02-27 05:15:12 -0300274static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300275/* index,value */
276 0xff, 0x01, /* page 1 */
277 0x78, 0x00, /* deactivate */
278 0xff, 0x01,
279 0x78, 0x40, /* led off */
280};
Jean-François Moineae251e62012-02-27 05:15:12 -0300281static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300282/* index, len, [value]* */
283 0xff, 1, 0x00, /* page 0 */
284 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
285 0x00, 0x00, 0x00, 0x00,
286 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
287 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
288 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
289 0x26, 2, 0xaa, 0xaa,
290 0x2e, 1, 0x31,
291 0x38, 1, 0x01,
292 0x3a, 3, 0x14, 0xff, 0x5a,
293 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
294 0x00, 0x54, 0x11,
295 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300296 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300297 0x6b, 1, 0x00,
298 0x6e, 3, 0x08, 0x06, 0x00,
299 0x72, 3, 0x00, 0xff, 0x00,
300 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
301 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
302 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
303 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
304 0xd2, 0xeb,
305 0xaf, 1, 0x02,
306 0xb5, 2, 0x08, 0x08,
307 0xb8, 2, 0x08, 0x88,
308 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
309 0xcc, 1, 0x00,
310 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
311 0xc1, 0xd7, 0xec,
312 0xdc, 1, 0x01,
313 0xff, 1, 0x01, /* page 1 */
314 0x12, 3, 0x02, 0x00, 0x01,
315 0x3e, 2, 0x00, 0x00,
316 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
317 0x7c, 1, 0x00,
318 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
319 0x02, 0x00,
320 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
321 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
322 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
323 0xd8, 1, 0x01,
324 0xdb, 2, 0x00, 0x01,
325 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
326 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
327 0xeb, 1, 0x00,
328 0xff, 1, 0x02, /* page 2 */
329 0x22, 1, 0x00,
330 0xff, 1, 0x03, /* page 3 */
331 0, LOAD_PAGE3, /* load the page 3 */
332 0x11, 1, 0x01,
333 0xff, 1, 0x02, /* page 2 */
334 0x13, 1, 0x00,
335 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
336 0x27, 2, 0x14, 0x0c,
337 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
338 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
339 0x6e, 1, 0x08,
340 0xff, 1, 0x01, /* page 1 */
341 0x78, 1, 0x00,
342 0, END_OF_SEQUENCE /* end of sequence */
343};
344
345#define SKIP 0xaa
346/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300347static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300348 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300349 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
350 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
352 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
353 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
354 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
355 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300357 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300358 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
362 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
363 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
364 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
367 0x00
368};
369
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300370static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300371 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300372 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300373{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300374 int ret;
375
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300376 if (gspca_dev->usb_err < 0)
377 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300378 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300379 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300380 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300381 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300382 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
383 0, /* value */
384 index, gspca_dev->usb_buf, len,
385 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300386 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300387 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300388 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300389 gspca_dev->usb_err = ret;
390 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300391}
392
393
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300394static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300395 u8 index,
396 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300397{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300398 int ret;
399
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300400 if (gspca_dev->usb_err < 0)
401 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300402 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300403 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300404 usb_sndctrlpipe(gspca_dev->dev, 0),
405 0, /* request */
406 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
407 0, index, gspca_dev->usb_buf, 1,
408 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300409 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300410 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300411 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300412 gspca_dev->usb_err = ret;
413 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300414}
415
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300416static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300417 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300418{
419 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300420 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300421 seq += 2;
422 }
423}
424
425/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300426static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300427 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300428{
429 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300430 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300431
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300432 if (gspca_dev->usb_err < 0)
433 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300434 for (index = 0; index < len; index++) {
435 if (page[index] == SKIP) /* skip this index */
436 continue;
437 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300438 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300439 usb_sndctrlpipe(gspca_dev->dev, 0),
440 0, /* request */
441 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
442 0, index, gspca_dev->usb_buf, 1,
443 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300444 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300445 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300446 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300447 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300448 break;
449 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300450 }
451}
452
453/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300454static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300455 const u8 *seq,
456 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300457{
458 int index, len;
459
460 for (;;) {
461 index = *seq++;
462 len = *seq++;
463 switch (len) {
464 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300465 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300466 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300467 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300468 break;
469 default:
Jean-François Moineae251e62012-02-27 05:15:12 -0300470#ifdef GSPCA_DEBUG
Marton Nemeth1408b842009-11-02 08:13:21 -0300471 if (len > USB_BUF_SZ) {
472 PDEBUG(D_ERR|D_STREAM,
473 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300474 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300475 }
Jean-François Moineae251e62012-02-27 05:15:12 -0300476#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300477 while (len > 0) {
478 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300479 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300480 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300481 seq += len;
482 break;
483 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300484 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300485 seq += 8;
486 index += 8;
487 len -= 8;
488 }
489 }
490 }
491 /* not reached */
492}
493
494/* this function is called at probe time for pac7302 */
495static int sd_config(struct gspca_dev *gspca_dev,
496 const struct usb_device_id *id)
497{
498 struct sd *sd = (struct sd *) gspca_dev;
499 struct cam *cam;
500
501 cam = &gspca_dev->cam;
502
Marton Nemeth1408b842009-11-02 08:13:21 -0300503 cam->cam_mode = vga_mode; /* only 640x480 */
504 cam->nmodes = ARRAY_SIZE(vga_mode);
505
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300506 gspca_dev->cam.ctrls = sd->ctrls;
507
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300508 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300509 return 0;
510}
511
512/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300513static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300514{
515 struct sd *sd = (struct sd *) gspca_dev;
516 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300517 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300518 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
519 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300520 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300521 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
522 0x11, 0x0b};
523
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300524 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300525 for (i = 0; i < 10; i++) {
526 v = max[i];
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300527 v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
Marton Nemeth1408b842009-11-02 08:13:21 -0300528 * 150 / BRIGHTNESS_MAX; /* 200 ? */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300529 v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
Marton Nemeth1408b842009-11-02 08:13:21 -0300530 if (v < 0)
531 v = 0;
532 else if (v > 0xff)
533 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300534 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300535 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300536 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300537}
538
539/* This function is used by pac7302 only */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300540static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300541{
542 struct sd *sd = (struct sd *) gspca_dev;
543 int i, v;
544 static const int a[9] =
545 {217, -212, 0, -101, 170, -67, -38, -315, 355};
546 static const int b[9] =
547 {19, 106, 0, 19, 106, 1, 19, 106, 1};
548
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300549 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
550 reg_w(gspca_dev, 0x11, 0x01);
551 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300552 for (i = 0; i < 9; i++) {
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300553 v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300554 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
555 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300556 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300557 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300558}
559
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300560static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300561{
562 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300563
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300564 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300565 reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300566
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300567 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300568}
569
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300570static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300571{
572 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300573
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300574 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300575 reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300576
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300577 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300578}
579
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300580static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300581{
582 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300583
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300584 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300585 reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
Márton Németh265a8092009-11-07 15:15:56 -0300586
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300587 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300588}
589
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300590static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300591{
592 struct sd *sd = (struct sd *) gspca_dev;
593
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300594 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300595 reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
Marton Nemeth1408b842009-11-02 08:13:21 -0300596
597 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300598 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300599}
600
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300601static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300602{
603 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineae251e62012-02-27 05:15:12 -0300604 u8 clockdiv;
605 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300606
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300607 /* register 2 of frame 3 contains the clock divider configuring the
608 no fps according to the formula: 90 / reg. sd->exposure is the
609 desired exposure time in 0.5 ms. */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300610 clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300611
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300612 /* 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 if (clockdiv < 6)
617 clockdiv = 6;
618 else if (clockdiv > 63)
619 clockdiv = 63;
620
621 /* reg2 MUST be a multiple of 3, except when between 6 and 12?
622 Always round up, otherwise we cannot get the desired frametime
623 using the partial frame time exposure control */
624 if (clockdiv < 6 || clockdiv > 12)
625 clockdiv = ((clockdiv + 2) / 3) * 3;
626
627 /* frame exposure time in ms = 1000 * clockdiv / 90 ->
628 exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300629 exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300630 /* 0 = use full frametime, 448 = no exposure, reverse it */
631 exposure = 448 - exposure;
632
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300633 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300634 reg_w(gspca_dev, 0x02, clockdiv);
635 reg_w(gspca_dev, 0x0e, exposure & 0xff);
636 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300637
638 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300639 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300640}
641
Jean-François Moineac399cd2012-02-27 05:40:47 -0300642static void setautogain(struct gspca_dev *gspca_dev)
643{
644 struct sd *sd = (struct sd *) gspca_dev;
645
646 /* when switching to autogain set defaults to make sure
647 we are on a valid point of the autogain gain /
648 exposure knee graph, and give this change time to
649 take effect before doing autogain. */
650 if (sd->ctrls[AUTOGAIN].val) {
651 sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
652 sd->ctrls[GAIN].val = GAIN_DEF;
653 sd->autogain_ignore_frames =
654 PAC_AUTOGAIN_IGNORE_FRAMES;
655 } else {
656 sd->autogain_ignore_frames = -1;
657 }
658 setexposure(gspca_dev);
659 setgain(gspca_dev);
660}
661
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300662static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300663{
664 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300665 u8 data, hflip, vflip;
666
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300667 hflip = sd->ctrls[HFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300668 if (sd->flags & FL_HFLIP)
669 hflip = !hflip;
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300670 vflip = sd->ctrls[VFLIP].val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300671 if (sd->flags & FL_VFLIP)
672 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300673
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300674 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300675 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300676 reg_w(gspca_dev, 0x21, data);
677
Marton Nemeth1408b842009-11-02 08:13:21 -0300678 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300679 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300680}
681
682/* this function is called at probe and resume time for pac7302 */
683static int sd_init(struct gspca_dev *gspca_dev)
684{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300685 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
686 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300687}
688
689static int sd_start(struct gspca_dev *gspca_dev)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300693 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300694 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300695 setbrightcont(gspca_dev);
696 setcolors(gspca_dev);
697 setwhitebalance(gspca_dev);
698 setredbalance(gspca_dev);
699 setbluebalance(gspca_dev);
Jean-François Moineac399cd2012-02-27 05:40:47 -0300700 setautogain(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300701 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300702
703 /* only resolution 640x480 is supported for pac7302 */
704
705 sd->sof_read = 0;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300706 atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300707
708 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300709 reg_w(gspca_dev, 0xff, 0x01);
710 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300711
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300712 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300713}
714
715static void sd_stopN(struct gspca_dev *gspca_dev)
716{
Márton Némethb1784b32009-11-07 05:52:02 -0300717
Márton Németh67c98f72009-11-07 05:45:33 -0300718 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300719 reg_w(gspca_dev, 0xff, 0x01);
720 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300721}
722
723/* called on streamoff with alt 0 and on disconnect for pac7302 */
724static void sd_stop0(struct gspca_dev *gspca_dev)
725{
726 if (!gspca_dev->present)
727 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300728 reg_w(gspca_dev, 0xff, 0x01);
729 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300730}
731
Jean-François Moineaa5b7922012-02-27 05:38:09 -0300732/* !! coarse_grained_expo_autogain is not used !! */
733#define exp_too_low_cnt flags
734#define exp_too_high_cnt sof_read
735#include "autogain_functions.h"
736
Marton Nemeth1408b842009-11-02 08:13:21 -0300737static void do_autogain(struct gspca_dev *gspca_dev)
738{
739 struct sd *sd = (struct sd *) gspca_dev;
740 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300741 int desired_lum;
742 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300743
Jean-François Moineac399cd2012-02-27 05:40:47 -0300744 if (sd->autogain_ignore_frames < 0)
Marton Nemeth1408b842009-11-02 08:13:21 -0300745 return;
746
Jean-François Moineac399cd2012-02-27 05:40:47 -0300747 if (sd->autogain_ignore_frames > 0) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300748 sd->autogain_ignore_frames--;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300749 } else {
750 desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
751
752 auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
753 deadzone, GAIN_KNEE, EXPOSURE_KNEE);
Marton Nemeth1408b842009-11-02 08:13:21 -0300754 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300755 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300756}
757
Jean-François Moine7532e812012-02-27 05:21:57 -0300758/* JPEG header */
759static const u8 jpeg_header[] = {
760 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300761
Jean-François Moine7532e812012-02-27 05:21:57 -0300762 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
763 0x00, 0x11, /* length = 17 bytes (including this length field) */
764 0x08, /* Precision: 8 */
765 0x02, 0x80, /* height = 640 (image rotated) */
766 0x01, 0xe0, /* width = 480 */
767 0x03, /* Number of image components: 3 */
768 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
769 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
770 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
771
772 0xff, 0xda, /* SOS: Start Of Scan */
773 0x00, 0x0c, /* length = 12 bytes (including this length field) */
774 0x03, /* number of components: 3 */
775 0x01, 0x00, /* selector 1, table 0x00 */
776 0x02, 0x11, /* selector 2, table 0x11 */
777 0x03, 0x11, /* selector 3, table 0x11 */
778 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
779 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300780};
781
Marton Nemeth1408b842009-11-02 08:13:21 -0300782/* this function is run at interrupt level */
783static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300784 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300785 int len) /* iso packet length */
786{
787 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300788 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300789 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300790
791 sof = pac_find_sof(&sd->sof_read, data, len);
792 if (sof) {
793 int n, lum_offset, footer_length;
794
795 /* 6 bytes after the FF D9 EOF marker a number of lumination
796 bytes are send corresponding to different parts of the
797 image, the 14th and 15th byte after the EOF seem to
798 correspond to the center of the image */
799 lum_offset = 61 + sizeof pac_sof_marker;
800 footer_length = 74;
801
802 /* Finish decoding current frame */
803 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
804 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300805 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300806 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300807 } else {
808 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300809 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300810
811 image = gspca_dev->image;
812 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300813 && image[gspca_dev->image_len - 2] == 0xff
814 && image[gspca_dev->image_len - 1] == 0xd9)
815 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300816
817 n = sof - data;
818 len -= n;
819 data = sof;
820
821 /* Get average lumination */
822 if (gspca_dev->last_packet_type == LAST_PACKET &&
823 n >= lum_offset)
824 atomic_set(&sd->avg_lum, data[-lum_offset] +
825 data[-lum_offset + 1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300826
827 /* Start the new frame with the jpeg header */
828 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300829 gspca_frame_add(gspca_dev, FIRST_PACKET,
830 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300831 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300832 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300833}
834
Márton Németh6763cc02009-11-09 07:10:46 -0300835#ifdef CONFIG_VIDEO_ADV_DEBUG
836static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
837 struct v4l2_dbg_register *reg)
838{
Jean-François Moineae251e62012-02-27 05:15:12 -0300839 u8 index;
840 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300841
842 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
843 long on the USB bus)
844 */
845 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
846 reg->match.addr == 0 &&
847 (reg->reg < 0x000000ff) &&
848 (reg->val <= 0x000000ff)
849 ) {
850 /* Currently writing to page 0 is only supported. */
851 /* reg_w() only supports 8bit index */
Jean-François Moineae251e62012-02-27 05:15:12 -0300852 index = reg->reg;
853 value = reg->val;
Márton Németh6763cc02009-11-09 07:10:46 -0300854
855 /* Note that there shall be no access to other page
856 by any other function between the page swith and
857 the actual register write */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300858 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
859 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300860
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300861 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300862 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300863 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300864}
865
866static int sd_chip_ident(struct gspca_dev *gspca_dev,
867 struct v4l2_dbg_chip_ident *chip)
868{
869 int ret = -EINVAL;
870
871 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
872 chip->match.addr == 0) {
873 chip->revision = 0;
874 chip->ident = V4L2_IDENT_UNKNOWN;
875 ret = 0;
876 }
877 return ret;
878}
879#endif
880
Jean-François Moine28566432010-10-01 07:33:26 -0300881#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300882static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
883 u8 *data, /* interrupt packet data */
884 int len) /* interrput packet length */
885{
886 int ret = -EINVAL;
887 u8 data0, data1;
888
889 if (len == 2) {
890 data0 = data[0];
891 data1 = data[1];
892 if ((data0 == 0x00 && data1 == 0x11) ||
893 (data0 == 0x22 && data1 == 0x33) ||
894 (data0 == 0x44 && data1 == 0x55) ||
895 (data0 == 0x66 && data1 == 0x77) ||
896 (data0 == 0x88 && data1 == 0x99) ||
897 (data0 == 0xaa && data1 == 0xbb) ||
898 (data0 == 0xcc && data1 == 0xdd) ||
899 (data0 == 0xee && data1 == 0xff)) {
900 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
901 input_sync(gspca_dev->input_dev);
902 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
903 input_sync(gspca_dev->input_dev);
904 ret = 0;
905 }
906 }
907
908 return ret;
909}
910#endif
911
Marton Nemeth1408b842009-11-02 08:13:21 -0300912/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300913static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300914 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300915 .ctrls = sd_ctrls,
916 .nctrls = ARRAY_SIZE(sd_ctrls),
917 .config = sd_config,
918 .init = sd_init,
919 .start = sd_start,
920 .stopN = sd_stopN,
921 .stop0 = sd_stop0,
922 .pkt_scan = sd_pkt_scan,
923 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300924#ifdef CONFIG_VIDEO_ADV_DEBUG
925 .set_register = sd_dbg_s_register,
926 .get_chip_ident = sd_chip_ident,
927#endif
Jean-François Moine28566432010-10-01 07:33:26 -0300928#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300929 .int_pkt_scan = sd_int_pkt_scan,
930#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300931};
932
933/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300934static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300935 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300936 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300937 {USB_DEVICE(0x093a, 0x2620)},
938 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300939 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
940 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300941 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300942 {USB_DEVICE(0x093a, 0x2626)},
943 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300944 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300945 {USB_DEVICE(0x093a, 0x262a)},
946 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300947 {USB_DEVICE(0x145f, 0x013c)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300948 {}
949};
950MODULE_DEVICE_TABLE(usb, device_table);
951
952/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300953static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300954 const struct usb_device_id *id)
955{
956 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
957 THIS_MODULE);
958}
959
960static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300961 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300962 .id_table = device_table,
963 .probe = sd_probe,
964 .disconnect = gspca_disconnect,
965#ifdef CONFIG_PM
966 .suspend = gspca_suspend,
967 .resume = gspca_resume,
968#endif
969};
970
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800971module_usb_driver(sd_driver);