blob: be07a24c4518f10cbb97aee99eb9120139ed13cc [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 *
Frank Schäferb1a19c02012-09-09 15:02:21 -030029 * Register page 0:
30 *
31 * Address Description
Frank Schäfer6f9b3312012-09-23 10:29:42 -030032 * 0x01 Red balance control
33 * 0x02 Green balance control
34 * 0x03 Blue balance control
Frank Schäfer780d6172012-09-09 15:02:24 -030035 * The Windows driver uses a quadratic approach to map
36 * the settable values (0-200) on register values:
Frank Schäfer6f9b3312012-09-23 10:29:42 -030037 * min=0x20, default=0x40, max=0x80
38 * 0x0f-0x20 Color and saturation control
Frank Schäfer780d6172012-09-09 15:02:24 -030039 * 0xa2-0xab Brightness, contrast and gamma control
Frank Schäferb1a19c02012-09-09 15:02:21 -030040 * 0xb6 Sharpness control (bits 0-4)
41 *
Hans de Goede895d4642012-04-28 10:31:17 -030042 * Register page 1:
43 *
44 * Address Description
45 * 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goede48bb7312012-04-27 13:00:57 -030046 * 0x80 Compression balance, 2 interesting settings:
47 * 0x0f Default
48 * 0x50 Values >= this switch the camera to a lower compression,
49 * using the same table for both luminance and chrominance.
50 * This gives a sharper picture. Only usable when running
51 * at < 15 fps! Note currently the driver does not use this
52 * as the quality gain is small and the generated JPG-s are
53 * only understood by v4l-utils >= 0.8.9
Hans de Goede895d4642012-04-28 10:31:17 -030054 *
55 * Register page 3:
56 *
57 * Address Description
58 * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
59 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
60 * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
61 * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
62 * 63 -> ~27 fps, the 2 msb's must always be 1 !!
63 * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
64 * 1 -> ~30 fps, 2 -> ~20 fps
65 * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
66 * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
Hans de Goede48bb7312012-04-27 13:00:57 -030067 * 0x10 Gain 0-31
68 * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
69 * amplification value of 1 rather then 0 at its lowest setting
Hans de Goede895d4642012-04-28 10:31:17 -030070 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede48bb7312012-04-27 13:00:57 -030071 * 0x80 Another framerate control, best left at 1, moving it from 1 to
72 * 2 causes the framerate to become 3/4th of what it was, and
73 * also seems to cause pixel averaging, resulting in an effective
74 * resolution of 320x240 and thus a much blockier image
Hans de Goede895d4642012-04-28 10:31:17 -030075 *
76 * The registers are accessed in the following functions:
77 *
78 * Page | Register | Function
79 * -----+------------+---------------------------------------------------
Frank Schäfer2b34e9d2012-09-23 10:29:43 -030080 * 0 | 0x01 | setredbalance()
81 * 0 | 0x03 | setbluebalance()
Hans de Goede895d4642012-04-28 10:31:17 -030082 * 0 | 0x0f..0x20 | setcolors()
83 * 0 | 0xa2..0xab | setbrightcont()
Frank Schäferb1a19c02012-09-09 15:02:21 -030084 * 0 | 0xb6 | setsharpness()
Hans de Goede895d4642012-04-28 10:31:17 -030085 * 0 | 0xc6 | setwhitebalance()
Hans de Goede895d4642012-04-28 10:31:17 -030086 * 0 | 0xdc | setbrightcont(), setcolors()
87 * 3 | 0x02 | setexposure()
Hans de Goededf8b9852012-04-28 10:12:28 -030088 * 3 | 0x10, 0x12 | setgain()
Hans de Goede895d4642012-04-28 10:31:17 -030089 * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
90 * 3 | 0x21 | sethvflip()
91 */
Marton Nemeth1408b842009-11-02 08:13:21 -030092
Joe Perches133a9fe2011-08-21 19:56:57 -030093#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
94
Márton Némethaed6f1b2010-01-28 16:33:38 -030095#include <linux/input.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030096#include "gspca.h"
Jean-François Moineac399cd2012-02-27 05:40:47 -030097/* Include pac common sof detection functions */
98#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030099
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300100#define PAC7302_RGB_BALANCE_MIN 0
101#define PAC7302_RGB_BALANCE_MAX 200
102#define PAC7302_RGB_BALANCE_DEFAULT 100
103#define PAC7302_GAIN_DEFAULT 15
104#define PAC7302_GAIN_KNEE 42
105#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */
106#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
Hans de Goede74233cd2012-05-14 11:16:09 -0300107
Mauro Carvalho Chehab1ddc9f72016-10-18 17:44:16 -0200108MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -0300109MODULE_DESCRIPTION("Pixart PAC7302");
110MODULE_LICENSE("GPL");
111
Marton Nemeth1408b842009-11-02 08:13:21 -0300112struct sd {
113 struct gspca_dev gspca_dev; /* !! must be the first item */
114
Hans de Goede74233cd2012-05-14 11:16:09 -0300115 struct { /* brightness / contrast cluster */
116 struct v4l2_ctrl *brightness;
117 struct v4l2_ctrl *contrast;
118 };
119 struct v4l2_ctrl *saturation;
120 struct v4l2_ctrl *white_balance;
121 struct v4l2_ctrl *red_balance;
122 struct v4l2_ctrl *blue_balance;
123 struct { /* flip cluster */
124 struct v4l2_ctrl *hflip;
125 struct v4l2_ctrl *vflip;
126 };
Frank Schäferb1a19c02012-09-09 15:02:21 -0300127 struct v4l2_ctrl *sharpness;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300128 u8 flags;
129#define FL_HFLIP 0x01 /* mirrored by default */
130#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -0300131
132 u8 sof_read;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300133 s8 autogain_ignore_frames;
Marton Nemeth1408b842009-11-02 08:13:21 -0300134
135 atomic_t avg_lum;
136};
137
Marton Nemeth1408b842009-11-02 08:13:21 -0300138static const struct v4l2_pix_format vga_mode[] = {
139 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
140 .bytesperline = 640,
141 .sizeimage = 640 * 480 * 3 / 8 + 590,
142 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300143 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300144};
145
146#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300147#define END_OF_SEQUENCE 0
148
Jean-François Moineae251e62012-02-27 05:15:12 -0300149static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300150/* index,value */
151 0xff, 0x01, /* page 1 */
152 0x78, 0x00, /* deactivate */
153 0xff, 0x01,
154 0x78, 0x40, /* led off */
155};
Jean-François Moineae251e62012-02-27 05:15:12 -0300156static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300157/* index, len, [value]* */
158 0xff, 1, 0x00, /* page 0 */
159 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
160 0x00, 0x00, 0x00, 0x00,
161 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
162 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
163 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
164 0x26, 2, 0xaa, 0xaa,
165 0x2e, 1, 0x31,
166 0x38, 1, 0x01,
167 0x3a, 3, 0x14, 0xff, 0x5a,
168 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
169 0x00, 0x54, 0x11,
170 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300171 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300172 0x6b, 1, 0x00,
173 0x6e, 3, 0x08, 0x06, 0x00,
174 0x72, 3, 0x00, 0xff, 0x00,
175 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
176 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
177 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
178 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
179 0xd2, 0xeb,
180 0xaf, 1, 0x02,
181 0xb5, 2, 0x08, 0x08,
182 0xb8, 2, 0x08, 0x88,
183 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
184 0xcc, 1, 0x00,
185 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
186 0xc1, 0xd7, 0xec,
187 0xdc, 1, 0x01,
188 0xff, 1, 0x01, /* page 1 */
189 0x12, 3, 0x02, 0x00, 0x01,
190 0x3e, 2, 0x00, 0x00,
191 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
192 0x7c, 1, 0x00,
193 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
194 0x02, 0x00,
195 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
196 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
197 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
198 0xd8, 1, 0x01,
199 0xdb, 2, 0x00, 0x01,
200 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
201 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
202 0xeb, 1, 0x00,
203 0xff, 1, 0x02, /* page 2 */
204 0x22, 1, 0x00,
205 0xff, 1, 0x03, /* page 3 */
206 0, LOAD_PAGE3, /* load the page 3 */
207 0x11, 1, 0x01,
208 0xff, 1, 0x02, /* page 2 */
209 0x13, 1, 0x00,
210 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
211 0x27, 2, 0x14, 0x0c,
212 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
213 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
214 0x6e, 1, 0x08,
215 0xff, 1, 0x01, /* page 1 */
216 0x78, 1, 0x00,
217 0, END_OF_SEQUENCE /* end of sequence */
218};
219
220#define SKIP 0xaa
221/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300222static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300223 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300224 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
225 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
227 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
228 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
229 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
230 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300232 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300233 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
237 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
238 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
239 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
242 0x00
243};
244
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300245static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300246 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300247 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300248{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300249 int ret;
250
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300251 if (gspca_dev->usb_err < 0)
252 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300253 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300254 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300255 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300256 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300257 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
258 0, /* value */
259 index, gspca_dev->usb_buf, len,
260 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300261 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300262 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300263 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300264 gspca_dev->usb_err = ret;
265 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300266}
267
268
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300269static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300270 u8 index,
271 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300272{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300273 int ret;
274
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300275 if (gspca_dev->usb_err < 0)
276 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300277 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300278 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300279 usb_sndctrlpipe(gspca_dev->dev, 0),
280 0, /* request */
281 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
282 0, index, gspca_dev->usb_buf, 1,
283 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300284 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300285 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300286 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300287 gspca_dev->usb_err = ret;
288 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300289}
290
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300291static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300292 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300293{
294 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300295 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300296 seq += 2;
297 }
298}
299
300/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300301static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300302 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300303{
304 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300305 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300306
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300307 if (gspca_dev->usb_err < 0)
308 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300309 for (index = 0; index < len; index++) {
310 if (page[index] == SKIP) /* skip this index */
311 continue;
312 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300313 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300314 usb_sndctrlpipe(gspca_dev->dev, 0),
315 0, /* request */
316 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
317 0, index, gspca_dev->usb_buf, 1,
318 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300319 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300320 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300321 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300322 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300323 break;
324 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300325 }
326}
327
328/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300329static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300330 const u8 *seq,
331 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300332{
333 int index, len;
334
335 for (;;) {
336 index = *seq++;
337 len = *seq++;
338 switch (len) {
339 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300340 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300341 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300342 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300343 break;
344 default:
345 if (len > USB_BUF_SZ) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300346 PERR("Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300347 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300348 }
349 while (len > 0) {
350 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300351 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300352 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300353 seq += len;
354 break;
355 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300356 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300357 seq += 8;
358 index += 8;
359 len -= 8;
360 }
361 }
362 }
363 /* not reached */
364}
365
366/* this function is called at probe time for pac7302 */
367static int sd_config(struct gspca_dev *gspca_dev,
368 const struct usb_device_id *id)
369{
370 struct sd *sd = (struct sd *) gspca_dev;
371 struct cam *cam;
372
373 cam = &gspca_dev->cam;
374
Marton Nemeth1408b842009-11-02 08:13:21 -0300375 cam->cam_mode = vga_mode; /* only 640x480 */
376 cam->nmodes = ARRAY_SIZE(vga_mode);
377
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300378 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300379 return 0;
380}
381
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300382static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300383{
384 struct sd *sd = (struct sd *) gspca_dev;
385 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300386 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300387 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
388 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300389 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300390 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
391 0x11, 0x0b};
392
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300393 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300394 for (i = 0; i < 10; i++) {
395 v = max[i];
Hans Verkuil0d5e8c42014-07-17 12:31:23 -0300396 v += (sd->brightness->val - (s32)sd->brightness->maximum)
397 * 150 / (s32)sd->brightness->maximum; /* 200 ? */
398 v -= delta[i] * sd->contrast->val / (s32)sd->contrast->maximum;
Marton Nemeth1408b842009-11-02 08:13:21 -0300399 if (v < 0)
400 v = 0;
401 else if (v > 0xff)
402 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300403 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300404 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300405 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300406}
407
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300408static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300409{
410 struct sd *sd = (struct sd *) gspca_dev;
411 int i, v;
412 static const int a[9] =
413 {217, -212, 0, -101, 170, -67, -38, -315, 355};
414 static const int b[9] =
415 {19, 106, 0, 19, 106, 1, 19, 106, 1};
416
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300417 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
418 reg_w(gspca_dev, 0x11, 0x01);
419 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300420 for (i = 0; i < 9; i++) {
Hans Verkuil0d5e8c42014-07-17 12:31:23 -0300421 v = a[i] * sd->saturation->val / (s32)sd->saturation->maximum;
Hans de Goede74233cd2012-05-14 11:16:09 -0300422 v += b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300423 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
424 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300425 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300426 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300427}
428
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300429static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300430{
431 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300432
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300433 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300434 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300435
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300436 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300437}
438
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300439static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
440{
441 const unsigned int k = 1000; /* precision factor */
442 unsigned int norm;
443
444 /* Normed value [0...k] */
445 norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
446 / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
447 /* Qudratic apporach improves control at small (register) values: */
448 return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
449 /* Y = 64*X*X + 32*X + 32
450 * => register values 0x20-0x80; Windows driver uses these limits */
451
452 /* NOTE: for full value range (0x00-0xff) use
453 * Y = 254*X*X + X
454 * => 254 * norm * norm / (k*k) + 1 * norm / k */
455}
456
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300457static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300458{
459 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300460
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300461 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
462 reg_w(gspca_dev, 0x01,
463 rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
Márton Németh265a8092009-11-07 15:15:56 -0300464
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300465 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300466}
467
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300468static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300469{
470 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300471
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300472 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300473 reg_w(gspca_dev, 0x03,
474 rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
Márton Németh265a8092009-11-07 15:15:56 -0300475
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300476 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300477}
478
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300479static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300480{
Hans de Goededf8b9852012-04-28 10:12:28 -0300481 u8 reg10, reg12;
482
Hans de Goede74233cd2012-05-14 11:16:09 -0300483 if (gspca_dev->gain->val < 32) {
484 reg10 = gspca_dev->gain->val;
Hans de Goededf8b9852012-04-28 10:12:28 -0300485 reg12 = 0;
486 } else {
487 reg10 = 31;
Hans de Goede74233cd2012-05-14 11:16:09 -0300488 reg12 = gspca_dev->gain->val - 31;
Hans de Goededf8b9852012-04-28 10:12:28 -0300489 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300490
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300491 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goededf8b9852012-04-28 10:12:28 -0300492 reg_w(gspca_dev, 0x10, reg10);
493 reg_w(gspca_dev, 0x12, reg12);
Marton Nemeth1408b842009-11-02 08:13:21 -0300494
495 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300496 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300497}
498
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300499static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300500{
Jean-François Moineae251e62012-02-27 05:15:12 -0300501 u8 clockdiv;
502 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300503
Hans de Goede895d4642012-04-28 10:31:17 -0300504 /*
505 * Register 2 of frame 3 contains the clock divider configuring the
506 * no fps according to the formula: 90 / reg. sd->exposure is the
507 * desired exposure time in 0.5 ms.
508 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300509 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300510
Hans de Goede895d4642012-04-28 10:31:17 -0300511 /*
512 * Note clockdiv = 3 also works, but when running at 30 fps, depending
513 * on the scene being recorded, the camera switches to another
514 * quantization table for certain JPEG blocks, and we don't know how
515 * to decompress these blocks. So we cap the framerate at 15 fps.
516 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300517 if (clockdiv < 6)
518 clockdiv = 6;
519 else if (clockdiv > 63)
520 clockdiv = 63;
521
Hans de Goede895d4642012-04-28 10:31:17 -0300522 /*
523 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
524 * Always round up, otherwise we cannot get the desired frametime
525 * using the partial frame time exposure control.
526 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300527 if (clockdiv < 6 || clockdiv > 12)
528 clockdiv = ((clockdiv + 2) / 3) * 3;
529
Hans de Goede895d4642012-04-28 10:31:17 -0300530 /*
531 * frame exposure time in ms = 1000 * clockdiv / 90 ->
532 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
533 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300534 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300535 /* 0 = use full frametime, 448 = no exposure, reverse it */
536 exposure = 448 - exposure;
537
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300538 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300539 reg_w(gspca_dev, 0x02, clockdiv);
540 reg_w(gspca_dev, 0x0e, exposure & 0xff);
541 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300542
543 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300544 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300545}
546
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300547static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300548{
549 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300550 u8 data, hflip, vflip;
551
Hans de Goede74233cd2012-05-14 11:16:09 -0300552 hflip = sd->hflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300553 if (sd->flags & FL_HFLIP)
554 hflip = !hflip;
Hans de Goede74233cd2012-05-14 11:16:09 -0300555 vflip = sd->vflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300556 if (sd->flags & FL_VFLIP)
557 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300558
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300559 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300560 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300561 reg_w(gspca_dev, 0x21, data);
562
Marton Nemeth1408b842009-11-02 08:13:21 -0300563 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300564 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300565}
566
Frank Schäferb1a19c02012-09-09 15:02:21 -0300567static void setsharpness(struct gspca_dev *gspca_dev)
568{
569 struct sd *sd = (struct sd *) gspca_dev;
570
571 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
572 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
573
574 reg_w(gspca_dev, 0xdc, 0x01);
575}
576
Marton Nemeth1408b842009-11-02 08:13:21 -0300577/* this function is called at probe and resume time for pac7302 */
578static int sd_init(struct gspca_dev *gspca_dev)
579{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300580 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
581 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300582}
583
Hans de Goede74233cd2012-05-14 11:16:09 -0300584static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
585{
586 struct gspca_dev *gspca_dev =
587 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
588 struct sd *sd = (struct sd *)gspca_dev;
589
590 gspca_dev->usb_err = 0;
591
592 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
593 /* when switching to autogain set defaults to make sure
594 we are on a valid point of the autogain gain /
595 exposure knee graph, and give this change time to
596 take effect before doing autogain. */
597 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
598 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
599 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
600 }
601
602 if (!gspca_dev->streaming)
603 return 0;
604
605 switch (ctrl->id) {
606 case V4L2_CID_BRIGHTNESS:
607 setbrightcont(gspca_dev);
608 break;
609 case V4L2_CID_SATURATION:
610 setcolors(gspca_dev);
611 break;
612 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
613 setwhitebalance(gspca_dev);
614 break;
615 case V4L2_CID_RED_BALANCE:
616 setredbalance(gspca_dev);
617 break;
618 case V4L2_CID_BLUE_BALANCE:
619 setbluebalance(gspca_dev);
620 break;
621 case V4L2_CID_AUTOGAIN:
622 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
623 setexposure(gspca_dev);
624 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
625 setgain(gspca_dev);
626 break;
627 case V4L2_CID_HFLIP:
628 sethvflip(gspca_dev);
629 break;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300630 case V4L2_CID_SHARPNESS:
631 setsharpness(gspca_dev);
632 break;
Hans de Goede74233cd2012-05-14 11:16:09 -0300633 default:
634 return -EINVAL;
635 }
636 return gspca_dev->usb_err;
637}
638
639static const struct v4l2_ctrl_ops sd_ctrl_ops = {
640 .s_ctrl = sd_s_ctrl,
641};
642
643/* this function is called at probe time */
644static int sd_init_controls(struct gspca_dev *gspca_dev)
645{
646 struct sd *sd = (struct sd *) gspca_dev;
647 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
648
649 gspca_dev->vdev.ctrl_handler = hdl;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300650 v4l2_ctrl_handler_init(hdl, 12);
Hans de Goede74233cd2012-05-14 11:16:09 -0300651
652 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
653 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
654 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
655 V4L2_CID_CONTRAST, 0, 255, 1, 127);
656
657 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
658 V4L2_CID_SATURATION, 0, 255, 1, 127);
659 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
660 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
Frank Schäferf58e5cd2012-09-09 15:02:22 -0300661 0, 255, 1, 55);
Hans de Goede74233cd2012-05-14 11:16:09 -0300662 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300663 V4L2_CID_RED_BALANCE,
664 PAC7302_RGB_BALANCE_MIN,
665 PAC7302_RGB_BALANCE_MAX,
666 1, PAC7302_RGB_BALANCE_DEFAULT);
Hans de Goede74233cd2012-05-14 11:16:09 -0300667 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Frank Schäfer2b34e9d2012-09-23 10:29:43 -0300668 V4L2_CID_BLUE_BALANCE,
669 PAC7302_RGB_BALANCE_MIN,
670 PAC7302_RGB_BALANCE_MAX,
671 1, PAC7302_RGB_BALANCE_DEFAULT);
Hans de Goede74233cd2012-05-14 11:16:09 -0300672
673 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
674 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
675 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
676 V4L2_CID_EXPOSURE, 0, 1023, 1,
677 PAC7302_EXPOSURE_DEFAULT);
678 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
679 V4L2_CID_GAIN, 0, 62, 1,
680 PAC7302_GAIN_DEFAULT);
681
682 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
683 V4L2_CID_HFLIP, 0, 1, 1, 0);
684 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
685 V4L2_CID_VFLIP, 0, 1, 1, 0);
686
Frank Schäferb1a19c02012-09-09 15:02:21 -0300687 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
688 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
689
Hans de Goede74233cd2012-05-14 11:16:09 -0300690 if (hdl->error) {
691 pr_err("Could not initialize controls\n");
692 return hdl->error;
693 }
694
695 v4l2_ctrl_cluster(2, &sd->brightness);
696 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
697 v4l2_ctrl_cluster(2, &sd->hflip);
698 return 0;
699}
700
701/* -- start the camera -- */
Marton Nemeth1408b842009-11-02 08:13:21 -0300702static int sd_start(struct gspca_dev *gspca_dev)
703{
704 struct sd *sd = (struct sd *) gspca_dev;
705
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300706 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300707 page3_7302, sizeof(page3_7302));
Marton Nemeth1408b842009-11-02 08:13:21 -0300708
Marton Nemeth1408b842009-11-02 08:13:21 -0300709 sd->sof_read = 0;
Hans de Goede74233cd2012-05-14 11:16:09 -0300710 sd->autogain_ignore_frames = 0;
711 atomic_set(&sd->avg_lum, 270 + sd->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
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 {
Hans de Goede74233cd2012-05-14 11:16:09 -0300750 desired_lum = 270 + sd->brightness->val;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300751
Hans de Goede74233cd2012-05-14 11:16:09 -0300752 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
753 deadzone, PAC7302_GAIN_KNEE,
754 PAC7302_EXPOSURE_KNEE))
755 sd->autogain_ignore_frames =
756 PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300757 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300758}
759
Jean-François Moine7532e812012-02-27 05:21:57 -0300760/* JPEG header */
761static const u8 jpeg_header[] = {
762 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300763
Jean-François Moine7532e812012-02-27 05:21:57 -0300764 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
765 0x00, 0x11, /* length = 17 bytes (including this length field) */
766 0x08, /* Precision: 8 */
767 0x02, 0x80, /* height = 640 (image rotated) */
768 0x01, 0xe0, /* width = 480 */
769 0x03, /* Number of image components: 3 */
770 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
771 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
772 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
773
774 0xff, 0xda, /* SOS: Start Of Scan */
775 0x00, 0x0c, /* length = 12 bytes (including this length field) */
776 0x03, /* number of components: 3 */
777 0x01, 0x00, /* selector 1, table 0x00 */
778 0x02, 0x11, /* selector 2, table 0x11 */
779 0x03, 0x11, /* selector 3, table 0x11 */
780 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
781 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300782};
783
Marton Nemeth1408b842009-11-02 08:13:21 -0300784/* this function is run at interrupt level */
785static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300786 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300787 int len) /* iso packet length */
788{
789 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300790 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300791 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300792
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300793 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300794 if (sof) {
795 int n, lum_offset, footer_length;
796
Hans de Goede895d4642012-04-28 10:31:17 -0300797 /*
798 * 6 bytes after the FF D9 EOF marker a number of lumination
799 * bytes are send corresponding to different parts of the
800 * image, the 14th and 15th byte after the EOF seem to
801 * correspond to the center of the image.
802 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300803 lum_offset = 61 + sizeof pac_sof_marker;
804 footer_length = 74;
805
806 /* Finish decoding current frame */
807 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
808 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300809 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300810 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300811 } else {
812 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300813 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300814
815 image = gspca_dev->image;
816 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300817 && image[gspca_dev->image_len - 2] == 0xff
818 && image[gspca_dev->image_len - 1] == 0xd9)
819 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300820
821 n = sof - data;
822 len -= n;
823 data = sof;
824
825 /* Get average lumination */
826 if (gspca_dev->last_packet_type == LAST_PACKET &&
827 n >= lum_offset)
828 atomic_set(&sd->avg_lum, data[-lum_offset] +
829 data[-lum_offset + 1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300830
831 /* Start the new frame with the jpeg header */
832 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300833 gspca_frame_add(gspca_dev, FIRST_PACKET,
834 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300835 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300836 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300837}
838
Márton Németh6763cc02009-11-09 07:10:46 -0300839#ifdef CONFIG_VIDEO_ADV_DEBUG
840static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
Hans Verkuil977ba3b2013-03-24 08:28:46 -0300841 const struct v4l2_dbg_register *reg)
Márton Németh6763cc02009-11-09 07:10:46 -0300842{
Jean-François Moineae251e62012-02-27 05:15:12 -0300843 u8 index;
844 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300845
Hans de Goede895d4642012-04-28 10:31:17 -0300846 /*
847 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
848 * long on the USB bus)
849 */
Hans Verkuilb1c85cc2013-05-29 06:59:42 -0300850 if (reg->match.addr == 0 &&
Márton Németh6763cc02009-11-09 07:10:46 -0300851 (reg->reg < 0x000000ff) &&
852 (reg->val <= 0x000000ff)
853 ) {
854 /* Currently writing to page 0 is only supported. */
855 /* reg_w() only supports 8bit index */
Jean-François Moineae251e62012-02-27 05:15:12 -0300856 index = reg->reg;
857 value = reg->val;
Márton Németh6763cc02009-11-09 07:10:46 -0300858
Hans de Goede895d4642012-04-28 10:31:17 -0300859 /*
860 * Note that there shall be no access to other page
861 * by any other function between the page switch and
862 * the actual register write.
863 */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300864 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
865 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300866
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300867 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300868 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300869 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300870}
Márton Németh6763cc02009-11-09 07:10:46 -0300871#endif
872
Peter Senna Tschudinae814c02013-01-24 19:29:03 -0300873#if IS_ENABLED(CONFIG_INPUT)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300874static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
875 u8 *data, /* interrupt packet data */
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -0300876 int len) /* interrupt packet length */
Márton Némethaed6f1b2010-01-28 16:33:38 -0300877{
878 int ret = -EINVAL;
879 u8 data0, data1;
880
881 if (len == 2) {
882 data0 = data[0];
883 data1 = data[1];
884 if ((data0 == 0x00 && data1 == 0x11) ||
885 (data0 == 0x22 && data1 == 0x33) ||
886 (data0 == 0x44 && data1 == 0x55) ||
887 (data0 == 0x66 && data1 == 0x77) ||
888 (data0 == 0x88 && data1 == 0x99) ||
889 (data0 == 0xaa && data1 == 0xbb) ||
890 (data0 == 0xcc && data1 == 0xdd) ||
891 (data0 == 0xee && data1 == 0xff)) {
892 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
893 input_sync(gspca_dev->input_dev);
894 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
895 input_sync(gspca_dev->input_dev);
896 ret = 0;
897 }
898 }
899
900 return ret;
901}
902#endif
903
Marton Nemeth1408b842009-11-02 08:13:21 -0300904/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300905static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300906 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300907 .config = sd_config,
908 .init = sd_init,
Hans de Goede74233cd2012-05-14 11:16:09 -0300909 .init_controls = sd_init_controls,
Marton Nemeth1408b842009-11-02 08:13:21 -0300910 .start = sd_start,
911 .stopN = sd_stopN,
912 .stop0 = sd_stop0,
913 .pkt_scan = sd_pkt_scan,
914 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300915#ifdef CONFIG_VIDEO_ADV_DEBUG
916 .set_register = sd_dbg_s_register,
Márton Németh6763cc02009-11-09 07:10:46 -0300917#endif
Peter Senna Tschudinae814c02013-01-24 19:29:03 -0300918#if IS_ENABLED(CONFIG_INPUT)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300919 .int_pkt_scan = sd_int_pkt_scan,
920#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300921};
922
923/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300924static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300925 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300926 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300927 {USB_DEVICE(0x093a, 0x2620)},
928 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300929 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
Hans de Goede242841d2014-07-09 06:20:44 -0300930 {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300931 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300932 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300933 {USB_DEVICE(0x093a, 0x2626)},
Jozsef Marton5b843252012-05-15 12:05:36 -0300934 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300935 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300936 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300937 {USB_DEVICE(0x093a, 0x262a)},
938 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300939 {USB_DEVICE(0x145f, 0x013c)},
Frank Schäfer97d2fbf2012-09-09 15:02:19 -0300940 {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */
Marton Nemeth1408b842009-11-02 08:13:21 -0300941 {}
942};
943MODULE_DEVICE_TABLE(usb, device_table);
944
945/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300946static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300947 const struct usb_device_id *id)
948{
949 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
950 THIS_MODULE);
951}
952
953static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300954 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300955 .id_table = device_table,
956 .probe = sd_probe,
957 .disconnect = gspca_disconnect,
958#ifdef CONFIG_PM
959 .suspend = gspca_suspend,
960 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300961 .reset_resume = gspca_resume,
Marton Nemeth1408b842009-11-02 08:13:21 -0300962#endif
963};
964
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800965module_usb_driver(sd_driver);