blob: b8ff201c7bb920b51e82529b75f79a80e69f16fb [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.
Marton Nemeth1408b842009-11-02 08:13:21 -030020 */
21
Hans de Goede895d4642012-04-28 10:31:17 -030022/*
23 * Some documentation about various registers as determined by trial and error.
24 *
Frank Schäferb1a19c02012-09-09 15:02:21 -030025 * Register page 0:
26 *
27 * Address Description
Frank Schäfer6f9b3312012-09-23 10:29:42 -030028 * 0x01 Red balance control
29 * 0x02 Green balance control
30 * 0x03 Blue balance control
Frank Schäfer780d6172012-09-09 15:02:24 -030031 * The Windows driver uses a quadratic approach to map
32 * the settable values (0-200) on register values:
Frank Schäfer6f9b3312012-09-23 10:29:42 -030033 * min=0x20, default=0x40, max=0x80
34 * 0x0f-0x20 Color and saturation control
Frank Schäfer780d6172012-09-09 15:02:24 -030035 * 0xa2-0xab Brightness, contrast and gamma control
Frank Schäferb1a19c02012-09-09 15:02:21 -030036 * 0xb6 Sharpness control (bits 0-4)
37 *
Hans de Goede895d4642012-04-28 10:31:17 -030038 * Register page 1:
39 *
40 * Address Description
41 * 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goede48bb7312012-04-27 13:00:57 -030042 * 0x80 Compression balance, 2 interesting settings:
43 * 0x0f Default
44 * 0x50 Values >= this switch the camera to a lower compression,
45 * using the same table for both luminance and chrominance.
46 * This gives a sharper picture. Only usable when running
47 * at < 15 fps! Note currently the driver does not use this
48 * as the quality gain is small and the generated JPG-s are
49 * only understood by v4l-utils >= 0.8.9
Hans de Goede895d4642012-04-28 10:31:17 -030050 *
51 * Register page 3:
52 *
53 * Address Description
54 * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
55 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
56 * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
57 * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
58 * 63 -> ~27 fps, the 2 msb's must always be 1 !!
59 * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
60 * 1 -> ~30 fps, 2 -> ~20 fps
61 * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
62 * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
Hans de Goede48bb7312012-04-27 13:00:57 -030063 * 0x10 Gain 0-31
64 * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
65 * amplification value of 1 rather then 0 at its lowest setting
Hans de Goede895d4642012-04-28 10:31:17 -030066 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede48bb7312012-04-27 13:00:57 -030067 * 0x80 Another framerate control, best left at 1, moving it from 1 to
68 * 2 causes the framerate to become 3/4th of what it was, and
69 * also seems to cause pixel averaging, resulting in an effective
70 * resolution of 320x240 and thus a much blockier image
Hans de Goede895d4642012-04-28 10:31:17 -030071 *
72 * The registers are accessed in the following functions:
73 *
74 * Page | Register | Function
75 * -----+------------+---------------------------------------------------
Frank Schäfer2b34e9d2012-09-23 10:29:43 -030076 * 0 | 0x01 | setredbalance()
77 * 0 | 0x03 | setbluebalance()
Hans de Goede895d4642012-04-28 10:31:17 -030078 * 0 | 0x0f..0x20 | setcolors()
79 * 0 | 0xa2..0xab | setbrightcont()
Frank Schäferb1a19c02012-09-09 15:02:21 -030080 * 0 | 0xb6 | setsharpness()
Hans de Goede895d4642012-04-28 10:31:17 -030081 * 0 | 0xc6 | setwhitebalance()
Hans de Goede895d4642012-04-28 10:31:17 -030082 * 0 | 0xdc | setbrightcont(), setcolors()
83 * 3 | 0x02 | setexposure()
Hans de Goededf8b9852012-04-28 10:12:28 -030084 * 3 | 0x10, 0x12 | setgain()
Hans de Goede895d4642012-04-28 10:31:17 -030085 * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
86 * 3 | 0x21 | sethvflip()
87 */
Marton Nemeth1408b842009-11-02 08:13:21 -030088
Joe Perches133a9fe2011-08-21 19:56:57 -030089#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
90
Márton Némethaed6f1b2010-01-28 16:33:38 -030091#include <linux/input.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030092#include "gspca.h"
Jean-François Moineac399cd2012-02-27 05:40:47 -030093/* Include pac common sof detection functions */
94#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030095
Frank Schäfer2b34e9d2012-09-23 10:29:43 -030096#define PAC7302_RGB_BALANCE_MIN 0
97#define PAC7302_RGB_BALANCE_MAX 200
98#define PAC7302_RGB_BALANCE_DEFAULT 100
99#define PAC7302_GAIN_DEFAULT 15
100#define PAC7302_GAIN_KNEE 42
101#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */
102#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
Hans de Goede74233cd2012-05-14 11:16:09 -0300103
Mauro Carvalho Chehab1ddc9f72016-10-18 17:44:16 -0200104MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -0300105MODULE_DESCRIPTION("Pixart PAC7302");
106MODULE_LICENSE("GPL");
107
Marton Nemeth1408b842009-11-02 08:13:21 -0300108struct sd {
109 struct gspca_dev gspca_dev; /* !! must be the first item */
110
Hans de Goede74233cd2012-05-14 11:16:09 -0300111 struct { /* brightness / contrast cluster */
112 struct v4l2_ctrl *brightness;
113 struct v4l2_ctrl *contrast;
114 };
115 struct v4l2_ctrl *saturation;
116 struct v4l2_ctrl *white_balance;
117 struct v4l2_ctrl *red_balance;
118 struct v4l2_ctrl *blue_balance;
119 struct { /* flip cluster */
120 struct v4l2_ctrl *hflip;
121 struct v4l2_ctrl *vflip;
122 };
Frank Schäferb1a19c02012-09-09 15:02:21 -0300123 struct v4l2_ctrl *sharpness;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300124 u8 flags;
125#define FL_HFLIP 0x01 /* mirrored by default */
126#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -0300127
128 u8 sof_read;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300129 s8 autogain_ignore_frames;
Marton Nemeth1408b842009-11-02 08:13:21 -0300130
131 atomic_t avg_lum;
132};
133
Marton Nemeth1408b842009-11-02 08:13:21 -0300134static const struct v4l2_pix_format vga_mode[] = {
135 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
136 .bytesperline = 640,
137 .sizeimage = 640 * 480 * 3 / 8 + 590,
138 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300139 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300140};
141
142#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300143#define END_OF_SEQUENCE 0
144
Jean-François Moineae251e62012-02-27 05:15:12 -0300145static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300146/* index,value */
147 0xff, 0x01, /* page 1 */
148 0x78, 0x00, /* deactivate */
149 0xff, 0x01,
150 0x78, 0x40, /* led off */
151};
Jean-François Moineae251e62012-02-27 05:15:12 -0300152static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300153/* index, len, [value]* */
154 0xff, 1, 0x00, /* page 0 */
155 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
156 0x00, 0x00, 0x00, 0x00,
157 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
158 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
159 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
160 0x26, 2, 0xaa, 0xaa,
161 0x2e, 1, 0x31,
162 0x38, 1, 0x01,
163 0x3a, 3, 0x14, 0xff, 0x5a,
164 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
165 0x00, 0x54, 0x11,
166 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300167 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300168 0x6b, 1, 0x00,
169 0x6e, 3, 0x08, 0x06, 0x00,
170 0x72, 3, 0x00, 0xff, 0x00,
171 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
172 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
173 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
174 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
175 0xd2, 0xeb,
176 0xaf, 1, 0x02,
177 0xb5, 2, 0x08, 0x08,
178 0xb8, 2, 0x08, 0x88,
179 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
180 0xcc, 1, 0x00,
181 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
182 0xc1, 0xd7, 0xec,
183 0xdc, 1, 0x01,
184 0xff, 1, 0x01, /* page 1 */
185 0x12, 3, 0x02, 0x00, 0x01,
186 0x3e, 2, 0x00, 0x00,
187 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
188 0x7c, 1, 0x00,
189 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
190 0x02, 0x00,
191 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
192 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
193 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
194 0xd8, 1, 0x01,
195 0xdb, 2, 0x00, 0x01,
196 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
197 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
198 0xeb, 1, 0x00,
199 0xff, 1, 0x02, /* page 2 */
200 0x22, 1, 0x00,
201 0xff, 1, 0x03, /* page 3 */
202 0, LOAD_PAGE3, /* load the page 3 */
203 0x11, 1, 0x01,
204 0xff, 1, 0x02, /* page 2 */
205 0x13, 1, 0x00,
206 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
207 0x27, 2, 0x14, 0x0c,
208 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
209 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
210 0x6e, 1, 0x08,
211 0xff, 1, 0x01, /* page 1 */
212 0x78, 1, 0x00,
213 0, END_OF_SEQUENCE /* end of sequence */
214};
215
216#define SKIP 0xaa
217/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300218static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300219 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300220 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
221 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
223 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
224 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
225 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
226 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300228 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300229 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
233 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
234 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
235 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
238 0x00
239};
240
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300241static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300242 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300243 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300244{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300245 int ret;
246
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300247 if (gspca_dev->usb_err < 0)
248 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300249 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300250 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300251 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300252 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300253 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
254 0, /* value */
255 index, gspca_dev->usb_buf, len,
256 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300257 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300258 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300259 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300260 gspca_dev->usb_err = ret;
261 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300262}
263
264
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300265static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300266 u8 index,
267 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300268{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300269 int ret;
270
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300271 if (gspca_dev->usb_err < 0)
272 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300273 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300274 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300275 usb_sndctrlpipe(gspca_dev->dev, 0),
276 0, /* request */
277 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
278 0, index, gspca_dev->usb_buf, 1,
279 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300280 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300281 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300282 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300283 gspca_dev->usb_err = ret;
284 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300285}
286
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300287static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300288 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300289{
290 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300291 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300292 seq += 2;
293 }
294}
295
296/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300297static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300298 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300299{
300 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300301 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300302
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300303 if (gspca_dev->usb_err < 0)
304 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300305 for (index = 0; index < len; index++) {
306 if (page[index] == SKIP) /* skip this index */
307 continue;
308 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300309 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300310 usb_sndctrlpipe(gspca_dev->dev, 0),
311 0, /* request */
312 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
313 0, index, gspca_dev->usb_buf, 1,
314 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300315 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300316 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300317 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300318 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300319 break;
320 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300321 }
322}
323
324/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300325static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300326 const u8 *seq,
327 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300328{
329 int index, len;
330
331 for (;;) {
332 index = *seq++;
333 len = *seq++;
334 switch (len) {
335 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300336 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300337 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300338 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300339 break;
340 default:
341 if (len > USB_BUF_SZ) {
Joe Perches52173c5f2017-09-22 14:33:35 -0400342 gspca_err(gspca_dev, "Incorrect variable sequence\n");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300343 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300344 }
345 while (len > 0) {
346 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300347 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300348 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300349 seq += len;
350 break;
351 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300352 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300353 seq += 8;
354 index += 8;
355 len -= 8;
356 }
357 }
358 }
359 /* not reached */
360}
361
362/* this function is called at probe time for pac7302 */
363static int sd_config(struct gspca_dev *gspca_dev,
364 const struct usb_device_id *id)
365{
366 struct sd *sd = (struct sd *) gspca_dev;
367 struct cam *cam;
368
369 cam = &gspca_dev->cam;
370
Marton Nemeth1408b842009-11-02 08:13:21 -0300371 cam->cam_mode = vga_mode; /* only 640x480 */
372 cam->nmodes = ARRAY_SIZE(vga_mode);
373
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300374 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300375 return 0;
376}
377
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300378static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300379{
380 struct sd *sd = (struct sd *) gspca_dev;
381 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300382 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300383 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
384 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300385 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300386 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
387 0x11, 0x0b};
388
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300389 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300390 for (i = 0; i < 10; i++) {
391 v = max[i];
Hans Verkuil0d5e8c42014-07-17 12:31:23 -0300392 v += (sd->brightness->val - (s32)sd->brightness->maximum)
393 * 150 / (s32)sd->brightness->maximum; /* 200 ? */
394 v -= delta[i] * sd->contrast->val / (s32)sd->contrast->maximum;
Marton Nemeth1408b842009-11-02 08:13:21 -0300395 if (v < 0)
396 v = 0;
397 else if (v > 0xff)
398 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300399 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300400 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300401 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300402}
403
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300404static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300405{
406 struct sd *sd = (struct sd *) gspca_dev;
407 int i, v;
408 static const int a[9] =
409 {217, -212, 0, -101, 170, -67, -38, -315, 355};
410 static const int b[9] =
411 {19, 106, 0, 19, 106, 1, 19, 106, 1};
412
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300413 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
414 reg_w(gspca_dev, 0x11, 0x01);
415 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300416 for (i = 0; i < 9; i++) {
Hans Verkuil0d5e8c42014-07-17 12:31:23 -0300417 v = a[i] * sd->saturation->val / (s32)sd->saturation->maximum;
Hans de Goede74233cd2012-05-14 11:16:09 -0300418 v += b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300419 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
420 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300421 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300422 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300423}
424
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300425static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300426{
427 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300428
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300429 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300430 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300431
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300432 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300433}
434
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300435static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
436{
437 const unsigned int k = 1000; /* precision factor */
438 unsigned int norm;
439
440 /* Normed value [0...k] */
441 norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
442 / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
443 /* Qudratic apporach improves control at small (register) values: */
444 return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
445 /* Y = 64*X*X + 32*X + 32
446 * => register values 0x20-0x80; Windows driver uses these limits */
447
448 /* NOTE: for full value range (0x00-0xff) use
449 * Y = 254*X*X + X
450 * => 254 * norm * norm / (k*k) + 1 * norm / k */
451}
452
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300453static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300454{
455 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300456
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300457 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
458 reg_w(gspca_dev, 0x01,
459 rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
Márton Németh265a8092009-11-07 15:15:56 -0300460
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300461 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300462}
463
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300464static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300465{
466 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300467
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300468 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300469 reg_w(gspca_dev, 0x03,
470 rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
Márton Németh265a8092009-11-07 15:15:56 -0300471
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300472 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300473}
474
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300475static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300476{
Hans de Goededf8b9852012-04-28 10:12:28 -0300477 u8 reg10, reg12;
478
Hans de Goede74233cd2012-05-14 11:16:09 -0300479 if (gspca_dev->gain->val < 32) {
480 reg10 = gspca_dev->gain->val;
Hans de Goededf8b9852012-04-28 10:12:28 -0300481 reg12 = 0;
482 } else {
483 reg10 = 31;
Hans de Goede74233cd2012-05-14 11:16:09 -0300484 reg12 = gspca_dev->gain->val - 31;
Hans de Goededf8b9852012-04-28 10:12:28 -0300485 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300486
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300487 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goededf8b9852012-04-28 10:12:28 -0300488 reg_w(gspca_dev, 0x10, reg10);
489 reg_w(gspca_dev, 0x12, reg12);
Marton Nemeth1408b842009-11-02 08:13:21 -0300490
491 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300492 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300493}
494
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300495static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300496{
Jean-François Moineae251e62012-02-27 05:15:12 -0300497 u8 clockdiv;
498 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300499
Hans de Goede895d4642012-04-28 10:31:17 -0300500 /*
501 * Register 2 of frame 3 contains the clock divider configuring the
502 * no fps according to the formula: 90 / reg. sd->exposure is the
503 * desired exposure time in 0.5 ms.
504 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300505 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300506
Hans de Goede895d4642012-04-28 10:31:17 -0300507 /*
508 * Note clockdiv = 3 also works, but when running at 30 fps, depending
509 * on the scene being recorded, the camera switches to another
510 * quantization table for certain JPEG blocks, and we don't know how
511 * to decompress these blocks. So we cap the framerate at 15 fps.
512 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300513 if (clockdiv < 6)
514 clockdiv = 6;
515 else if (clockdiv > 63)
516 clockdiv = 63;
517
Hans de Goede895d4642012-04-28 10:31:17 -0300518 /*
519 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
520 * Always round up, otherwise we cannot get the desired frametime
521 * using the partial frame time exposure control.
522 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300523 if (clockdiv < 6 || clockdiv > 12)
524 clockdiv = ((clockdiv + 2) / 3) * 3;
525
Hans de Goede895d4642012-04-28 10:31:17 -0300526 /*
527 * frame exposure time in ms = 1000 * clockdiv / 90 ->
528 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
529 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300530 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300531 /* 0 = use full frametime, 448 = no exposure, reverse it */
532 exposure = 448 - exposure;
533
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300534 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300535 reg_w(gspca_dev, 0x02, clockdiv);
536 reg_w(gspca_dev, 0x0e, exposure & 0xff);
537 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300538
539 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300540 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300541}
542
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300543static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300544{
545 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300546 u8 data, hflip, vflip;
547
Hans de Goede74233cd2012-05-14 11:16:09 -0300548 hflip = sd->hflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300549 if (sd->flags & FL_HFLIP)
550 hflip = !hflip;
Hans de Goede74233cd2012-05-14 11:16:09 -0300551 vflip = sd->vflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300552 if (sd->flags & FL_VFLIP)
553 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300554
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300555 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300556 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300557 reg_w(gspca_dev, 0x21, data);
558
Marton Nemeth1408b842009-11-02 08:13:21 -0300559 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300560 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300561}
562
Frank Schäferb1a19c02012-09-09 15:02:21 -0300563static void setsharpness(struct gspca_dev *gspca_dev)
564{
565 struct sd *sd = (struct sd *) gspca_dev;
566
567 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
568 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
569
570 reg_w(gspca_dev, 0xdc, 0x01);
571}
572
Marton Nemeth1408b842009-11-02 08:13:21 -0300573/* this function is called at probe and resume time for pac7302 */
574static int sd_init(struct gspca_dev *gspca_dev)
575{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300576 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
577 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300578}
579
Hans de Goede74233cd2012-05-14 11:16:09 -0300580static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
581{
582 struct gspca_dev *gspca_dev =
583 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
584 struct sd *sd = (struct sd *)gspca_dev;
585
586 gspca_dev->usb_err = 0;
587
588 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
589 /* when switching to autogain set defaults to make sure
590 we are on a valid point of the autogain gain /
591 exposure knee graph, and give this change time to
592 take effect before doing autogain. */
593 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
594 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
595 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
596 }
597
598 if (!gspca_dev->streaming)
599 return 0;
600
601 switch (ctrl->id) {
602 case V4L2_CID_BRIGHTNESS:
603 setbrightcont(gspca_dev);
604 break;
605 case V4L2_CID_SATURATION:
606 setcolors(gspca_dev);
607 break;
608 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
609 setwhitebalance(gspca_dev);
610 break;
611 case V4L2_CID_RED_BALANCE:
612 setredbalance(gspca_dev);
613 break;
614 case V4L2_CID_BLUE_BALANCE:
615 setbluebalance(gspca_dev);
616 break;
617 case V4L2_CID_AUTOGAIN:
618 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
619 setexposure(gspca_dev);
620 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
621 setgain(gspca_dev);
622 break;
623 case V4L2_CID_HFLIP:
624 sethvflip(gspca_dev);
625 break;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300626 case V4L2_CID_SHARPNESS:
627 setsharpness(gspca_dev);
628 break;
Hans de Goede74233cd2012-05-14 11:16:09 -0300629 default:
630 return -EINVAL;
631 }
632 return gspca_dev->usb_err;
633}
634
635static const struct v4l2_ctrl_ops sd_ctrl_ops = {
636 .s_ctrl = sd_s_ctrl,
637};
638
639/* this function is called at probe time */
640static int sd_init_controls(struct gspca_dev *gspca_dev)
641{
642 struct sd *sd = (struct sd *) gspca_dev;
643 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
644
645 gspca_dev->vdev.ctrl_handler = hdl;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300646 v4l2_ctrl_handler_init(hdl, 12);
Hans de Goede74233cd2012-05-14 11:16:09 -0300647
648 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
649 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
650 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
651 V4L2_CID_CONTRAST, 0, 255, 1, 127);
652
653 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
654 V4L2_CID_SATURATION, 0, 255, 1, 127);
655 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
656 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
Frank Schäferf58e5cd2012-09-09 15:02:22 -0300657 0, 255, 1, 55);
Hans de Goede74233cd2012-05-14 11:16:09 -0300658 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300659 V4L2_CID_RED_BALANCE,
660 PAC7302_RGB_BALANCE_MIN,
661 PAC7302_RGB_BALANCE_MAX,
662 1, PAC7302_RGB_BALANCE_DEFAULT);
Hans de Goede74233cd2012-05-14 11:16:09 -0300663 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300664 V4L2_CID_BLUE_BALANCE,
665 PAC7302_RGB_BALANCE_MIN,
666 PAC7302_RGB_BALANCE_MAX,
667 1, PAC7302_RGB_BALANCE_DEFAULT);
Hans de Goede74233cd2012-05-14 11:16:09 -0300668
669 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
670 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
671 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
672 V4L2_CID_EXPOSURE, 0, 1023, 1,
673 PAC7302_EXPOSURE_DEFAULT);
674 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
675 V4L2_CID_GAIN, 0, 62, 1,
676 PAC7302_GAIN_DEFAULT);
677
678 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
679 V4L2_CID_HFLIP, 0, 1, 1, 0);
680 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
681 V4L2_CID_VFLIP, 0, 1, 1, 0);
682
Frank Schäferb1a19c02012-09-09 15:02:21 -0300683 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
684 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
685
Hans de Goede74233cd2012-05-14 11:16:09 -0300686 if (hdl->error) {
687 pr_err("Could not initialize controls\n");
688 return hdl->error;
689 }
690
691 v4l2_ctrl_cluster(2, &sd->brightness);
692 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
693 v4l2_ctrl_cluster(2, &sd->hflip);
694 return 0;
695}
696
697/* -- start the camera -- */
Marton Nemeth1408b842009-11-02 08:13:21 -0300698static int sd_start(struct gspca_dev *gspca_dev)
699{
700 struct sd *sd = (struct sd *) gspca_dev;
701
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300702 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300703 page3_7302, sizeof(page3_7302));
Marton Nemeth1408b842009-11-02 08:13:21 -0300704
Marton Nemeth1408b842009-11-02 08:13:21 -0300705 sd->sof_read = 0;
Hans de Goede74233cd2012-05-14 11:16:09 -0300706 sd->autogain_ignore_frames = 0;
707 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300708
709 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300710 reg_w(gspca_dev, 0xff, 0x01);
711 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300712
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300713 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300714}
715
716static void sd_stopN(struct gspca_dev *gspca_dev)
717{
Márton Némethb1784b32009-11-07 05:52:02 -0300718
Márton Németh67c98f72009-11-07 05:45:33 -0300719 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300720 reg_w(gspca_dev, 0xff, 0x01);
721 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300722}
723
724/* called on streamoff with alt 0 and on disconnect for pac7302 */
725static void sd_stop0(struct gspca_dev *gspca_dev)
726{
727 if (!gspca_dev->present)
728 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300729 reg_w(gspca_dev, 0xff, 0x01);
730 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300731}
732
Marton Nemeth1408b842009-11-02 08:13:21 -0300733static void do_autogain(struct gspca_dev *gspca_dev)
734{
735 struct sd *sd = (struct sd *) gspca_dev;
736 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300737 int desired_lum;
738 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300739
Jean-François Moineac399cd2012-02-27 05:40:47 -0300740 if (sd->autogain_ignore_frames < 0)
Marton Nemeth1408b842009-11-02 08:13:21 -0300741 return;
742
Jean-François Moineac399cd2012-02-27 05:40:47 -0300743 if (sd->autogain_ignore_frames > 0) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300744 sd->autogain_ignore_frames--;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300745 } else {
Hans de Goede74233cd2012-05-14 11:16:09 -0300746 desired_lum = 270 + sd->brightness->val;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300747
Hans de Goede74233cd2012-05-14 11:16:09 -0300748 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
749 deadzone, PAC7302_GAIN_KNEE,
750 PAC7302_EXPOSURE_KNEE))
751 sd->autogain_ignore_frames =
752 PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300753 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300754}
755
Jean-François Moine7532e812012-02-27 05:21:57 -0300756/* JPEG header */
757static const u8 jpeg_header[] = {
758 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300759
Jean-François Moine7532e812012-02-27 05:21:57 -0300760 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
761 0x00, 0x11, /* length = 17 bytes (including this length field) */
762 0x08, /* Precision: 8 */
763 0x02, 0x80, /* height = 640 (image rotated) */
764 0x01, 0xe0, /* width = 480 */
765 0x03, /* Number of image components: 3 */
766 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
767 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
768 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
769
770 0xff, 0xda, /* SOS: Start Of Scan */
771 0x00, 0x0c, /* length = 12 bytes (including this length field) */
772 0x03, /* number of components: 3 */
773 0x01, 0x00, /* selector 1, table 0x00 */
774 0x02, 0x11, /* selector 2, table 0x11 */
775 0x03, 0x11, /* selector 3, table 0x11 */
776 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
777 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300778};
779
Marton Nemeth1408b842009-11-02 08:13:21 -0300780/* this function is run at interrupt level */
781static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300782 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300783 int len) /* iso packet length */
784{
785 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300786 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300787 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300788
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300789 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300790 if (sof) {
791 int n, lum_offset, footer_length;
792
Hans de Goede895d4642012-04-28 10:31:17 -0300793 /*
794 * 6 bytes after the FF D9 EOF marker a number of lumination
795 * bytes are send corresponding to different parts of the
796 * image, the 14th and 15th byte after the EOF seem to
797 * correspond to the center of the image.
798 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300799 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,
Hans Verkuil977ba3b12013-03-24 08:28:46 -0300837 const struct v4l2_dbg_register *reg)
Márton Németh6763cc02009-11-09 07:10:46 -0300838{
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
Hans de Goede895d4642012-04-28 10:31:17 -0300842 /*
843 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
844 * long on the USB bus)
845 */
Hans Verkuilb1c85cc2013-05-29 06:59:42 -0300846 if (reg->match.addr == 0 &&
Márton Németh6763cc02009-11-09 07:10:46 -0300847 (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
Hans de Goede895d4642012-04-28 10:31:17 -0300855 /*
856 * Note that there shall be no access to other page
857 * by any other function between the page switch and
858 * the actual register write.
859 */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300860 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
861 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300862
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300863 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300864 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300865 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300866}
Márton Németh6763cc02009-11-09 07:10:46 -0300867#endif
868
Peter Senna Tschudinae814c082013-01-24 19:29:03 -0300869#if IS_ENABLED(CONFIG_INPUT)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300870static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
871 u8 *data, /* interrupt packet data */
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -0300872 int len) /* interrupt packet length */
Márton Némethaed6f1b2010-01-28 16:33:38 -0300873{
874 int ret = -EINVAL;
875 u8 data0, data1;
876
877 if (len == 2) {
878 data0 = data[0];
879 data1 = data[1];
880 if ((data0 == 0x00 && data1 == 0x11) ||
881 (data0 == 0x22 && data1 == 0x33) ||
882 (data0 == 0x44 && data1 == 0x55) ||
883 (data0 == 0x66 && data1 == 0x77) ||
884 (data0 == 0x88 && data1 == 0x99) ||
885 (data0 == 0xaa && data1 == 0xbb) ||
886 (data0 == 0xcc && data1 == 0xdd) ||
887 (data0 == 0xee && data1 == 0xff)) {
888 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
889 input_sync(gspca_dev->input_dev);
890 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
891 input_sync(gspca_dev->input_dev);
892 ret = 0;
893 }
894 }
895
896 return ret;
897}
898#endif
899
Marton Nemeth1408b842009-11-02 08:13:21 -0300900/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300901static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300902 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300903 .config = sd_config,
904 .init = sd_init,
Hans de Goede74233cd2012-05-14 11:16:09 -0300905 .init_controls = sd_init_controls,
Marton Nemeth1408b842009-11-02 08:13:21 -0300906 .start = sd_start,
907 .stopN = sd_stopN,
908 .stop0 = sd_stop0,
909 .pkt_scan = sd_pkt_scan,
910 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300911#ifdef CONFIG_VIDEO_ADV_DEBUG
912 .set_register = sd_dbg_s_register,
Márton Németh6763cc02009-11-09 07:10:46 -0300913#endif
Peter Senna Tschudinae814c082013-01-24 19:29:03 -0300914#if IS_ENABLED(CONFIG_INPUT)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300915 .int_pkt_scan = sd_int_pkt_scan,
916#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300917};
918
919/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300920static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300921 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300922 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300923 {USB_DEVICE(0x093a, 0x2620)},
924 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300925 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
Hans de Goede242841d2014-07-09 06:20:44 -0300926 {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300927 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300928 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300929 {USB_DEVICE(0x093a, 0x2626)},
Jozsef Marton5b843252012-05-15 12:05:36 -0300930 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300931 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300932 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300933 {USB_DEVICE(0x093a, 0x262a)},
934 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300935 {USB_DEVICE(0x145f, 0x013c)},
Frank Schäfer97d2fbf2012-09-09 15:02:19 -0300936 {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */
Marton Nemeth1408b842009-11-02 08:13:21 -0300937 {}
938};
939MODULE_DEVICE_TABLE(usb, device_table);
940
941/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300942static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300943 const struct usb_device_id *id)
944{
945 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
946 THIS_MODULE);
947}
948
949static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300950 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300951 .id_table = device_table,
952 .probe = sd_probe,
953 .disconnect = gspca_disconnect,
954#ifdef CONFIG_PM
955 .suspend = gspca_suspend,
956 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300957 .reset_resume = gspca_resume,
Marton Nemeth1408b842009-11-02 08:13:21 -0300958#endif
959};
960
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800961module_usb_driver(sd_driver);