blob: 4877f7ab3d597eba3574abbab1a3945b0b18cca6 [file] [log] [blame]
Marton Nemeth1408b842009-11-02 08:13:21 -03001/*
Jean-François Moineae251e62012-02-27 05:15:12 -03002 * Pixart PAC7302 driver
Marton Nemeth1408b842009-11-02 08:13:21 -03003 *
Jean-François Moineae251e62012-02-27 05:15:12 -03004 * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
5 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
Marton Nemeth1408b842009-11-02 08:13:21 -03006 *
Jean-Francois Moinecc2f82c2010-01-28 16:35:40 -03007 * Separated from Pixart PAC7311 library by Márton Németh
Márton Némethaed6f1b2010-01-28 16:33:38 -03008 * Camera button input handling by Márton Németh <nm127@freemail.hu>
9 * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
Marton Nemeth1408b842009-11-02 08:13:21 -030010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Hans de Goede895d4642012-04-28 10:31:17 -030026/*
27 * Some documentation about various registers as determined by trial and error.
28 *
29 * Register page 1:
30 *
31 * Address Description
32 * 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goede48bb7312012-04-27 13:00:57 -030033 * 0x80 Compression balance, 2 interesting settings:
34 * 0x0f Default
35 * 0x50 Values >= this switch the camera to a lower compression,
36 * using the same table for both luminance and chrominance.
37 * This gives a sharper picture. Only usable when running
38 * at < 15 fps! Note currently the driver does not use this
39 * as the quality gain is small and the generated JPG-s are
40 * only understood by v4l-utils >= 0.8.9
Hans de Goede895d4642012-04-28 10:31:17 -030041 *
42 * Register page 3:
43 *
44 * Address Description
45 * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
46 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
47 * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
48 * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
49 * 63 -> ~27 fps, the 2 msb's must always be 1 !!
50 * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
51 * 1 -> ~30 fps, 2 -> ~20 fps
52 * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
53 * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
Hans de Goede48bb7312012-04-27 13:00:57 -030054 * 0x10 Gain 0-31
55 * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
56 * amplification value of 1 rather then 0 at its lowest setting
Hans de Goede895d4642012-04-28 10:31:17 -030057 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede48bb7312012-04-27 13:00:57 -030058 * 0x80 Another framerate control, best left at 1, moving it from 1 to
59 * 2 causes the framerate to become 3/4th of what it was, and
60 * also seems to cause pixel averaging, resulting in an effective
61 * resolution of 320x240 and thus a much blockier image
Hans de Goede895d4642012-04-28 10:31:17 -030062 *
63 * The registers are accessed in the following functions:
64 *
65 * Page | Register | Function
66 * -----+------------+---------------------------------------------------
67 * 0 | 0x0f..0x20 | setcolors()
68 * 0 | 0xa2..0xab | setbrightcont()
69 * 0 | 0xc5 | setredbalance()
70 * 0 | 0xc6 | setwhitebalance()
71 * 0 | 0xc7 | setbluebalance()
72 * 0 | 0xdc | setbrightcont(), setcolors()
73 * 3 | 0x02 | setexposure()
Hans de Goededf8b9852012-04-28 10:12:28 -030074 * 3 | 0x10, 0x12 | setgain()
Hans de Goede895d4642012-04-28 10:31:17 -030075 * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
76 * 3 | 0x21 | sethvflip()
77 */
Marton Nemeth1408b842009-11-02 08:13:21 -030078
Joe Perches133a9fe2011-08-21 19:56:57 -030079#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
80
Márton Némethaed6f1b2010-01-28 16:33:38 -030081#include <linux/input.h>
Márton Németh6763cc02009-11-09 07:10:46 -030082#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030083#include "gspca.h"
Jean-François Moineac399cd2012-02-27 05:40:47 -030084/* Include pac common sof detection functions */
85#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030086
Hans de Goede74233cd2012-05-14 11:16:09 -030087#define PAC7302_GAIN_DEFAULT 15
88#define PAC7302_GAIN_KNEE 42
89#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */
90#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
91
Jean-François Moineae251e62012-02-27 05:15:12 -030092MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
93 "Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -030094MODULE_DESCRIPTION("Pixart PAC7302");
95MODULE_LICENSE("GPL");
96
Marton Nemeth1408b842009-11-02 08:13:21 -030097struct sd {
98 struct gspca_dev gspca_dev; /* !! must be the first item */
99
Hans de Goede74233cd2012-05-14 11:16:09 -0300100 struct { /* brightness / contrast cluster */
101 struct v4l2_ctrl *brightness;
102 struct v4l2_ctrl *contrast;
103 };
104 struct v4l2_ctrl *saturation;
105 struct v4l2_ctrl *white_balance;
106 struct v4l2_ctrl *red_balance;
107 struct v4l2_ctrl *blue_balance;
108 struct { /* flip cluster */
109 struct v4l2_ctrl *hflip;
110 struct v4l2_ctrl *vflip;
111 };
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300112 u8 flags;
113#define FL_HFLIP 0x01 /* mirrored by default */
114#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -0300115
116 u8 sof_read;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300117 s8 autogain_ignore_frames;
Marton Nemeth1408b842009-11-02 08:13:21 -0300118
119 atomic_t avg_lum;
120};
121
Marton Nemeth1408b842009-11-02 08:13:21 -0300122static const struct v4l2_pix_format vga_mode[] = {
123 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
124 .bytesperline = 640,
125 .sizeimage = 640 * 480 * 3 / 8 + 590,
126 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300127 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300128};
129
130#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300131#define END_OF_SEQUENCE 0
132
Jean-François Moineae251e62012-02-27 05:15:12 -0300133static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300134/* index,value */
135 0xff, 0x01, /* page 1 */
136 0x78, 0x00, /* deactivate */
137 0xff, 0x01,
138 0x78, 0x40, /* led off */
139};
Jean-François Moineae251e62012-02-27 05:15:12 -0300140static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300141/* index, len, [value]* */
142 0xff, 1, 0x00, /* page 0 */
143 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
144 0x00, 0x00, 0x00, 0x00,
145 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
146 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
147 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
148 0x26, 2, 0xaa, 0xaa,
149 0x2e, 1, 0x31,
150 0x38, 1, 0x01,
151 0x3a, 3, 0x14, 0xff, 0x5a,
152 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
153 0x00, 0x54, 0x11,
154 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300155 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300156 0x6b, 1, 0x00,
157 0x6e, 3, 0x08, 0x06, 0x00,
158 0x72, 3, 0x00, 0xff, 0x00,
159 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
160 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
161 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
162 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
163 0xd2, 0xeb,
164 0xaf, 1, 0x02,
165 0xb5, 2, 0x08, 0x08,
166 0xb8, 2, 0x08, 0x88,
167 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
168 0xcc, 1, 0x00,
169 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
170 0xc1, 0xd7, 0xec,
171 0xdc, 1, 0x01,
172 0xff, 1, 0x01, /* page 1 */
173 0x12, 3, 0x02, 0x00, 0x01,
174 0x3e, 2, 0x00, 0x00,
175 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
176 0x7c, 1, 0x00,
177 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
178 0x02, 0x00,
179 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
180 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
181 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
182 0xd8, 1, 0x01,
183 0xdb, 2, 0x00, 0x01,
184 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
185 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
186 0xeb, 1, 0x00,
187 0xff, 1, 0x02, /* page 2 */
188 0x22, 1, 0x00,
189 0xff, 1, 0x03, /* page 3 */
190 0, LOAD_PAGE3, /* load the page 3 */
191 0x11, 1, 0x01,
192 0xff, 1, 0x02, /* page 2 */
193 0x13, 1, 0x00,
194 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
195 0x27, 2, 0x14, 0x0c,
196 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
197 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
198 0x6e, 1, 0x08,
199 0xff, 1, 0x01, /* page 1 */
200 0x78, 1, 0x00,
201 0, END_OF_SEQUENCE /* end of sequence */
202};
203
204#define SKIP 0xaa
205/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300206static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300207 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300208 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
209 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
211 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
212 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
213 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
214 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300216 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300217 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
221 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
222 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
223 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
226 0x00
227};
228
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300229static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300230 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300231 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300232{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300233 int ret;
234
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300235 if (gspca_dev->usb_err < 0)
236 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300237 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300238 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300239 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300240 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300241 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
242 0, /* value */
243 index, gspca_dev->usb_buf, len,
244 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300245 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300246 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300247 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300248 gspca_dev->usb_err = ret;
249 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300250}
251
252
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300253static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300254 u8 index,
255 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300256{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300257 int ret;
258
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300259 if (gspca_dev->usb_err < 0)
260 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300261 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300262 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300263 usb_sndctrlpipe(gspca_dev->dev, 0),
264 0, /* request */
265 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
266 0, index, gspca_dev->usb_buf, 1,
267 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300268 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300269 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300270 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300271 gspca_dev->usb_err = ret;
272 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300273}
274
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300275static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300276 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300277{
278 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300279 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300280 seq += 2;
281 }
282}
283
284/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300285static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300286 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300287{
288 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300289 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300290
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300291 if (gspca_dev->usb_err < 0)
292 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300293 for (index = 0; index < len; index++) {
294 if (page[index] == SKIP) /* skip this index */
295 continue;
296 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300297 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300298 usb_sndctrlpipe(gspca_dev->dev, 0),
299 0, /* request */
300 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
301 0, index, gspca_dev->usb_buf, 1,
302 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300303 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300304 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300305 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300306 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300307 break;
308 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300309 }
310}
311
312/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300313static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300314 const u8 *seq,
315 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300316{
317 int index, len;
318
319 for (;;) {
320 index = *seq++;
321 len = *seq++;
322 switch (len) {
323 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300324 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300325 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300326 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300327 break;
328 default:
Jean-François Moineae251e62012-02-27 05:15:12 -0300329#ifdef GSPCA_DEBUG
Marton Nemeth1408b842009-11-02 08:13:21 -0300330 if (len > USB_BUF_SZ) {
331 PDEBUG(D_ERR|D_STREAM,
332 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300333 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300334 }
Jean-François Moineae251e62012-02-27 05:15:12 -0300335#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300336 while (len > 0) {
337 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300338 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300339 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300340 seq += len;
341 break;
342 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300343 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300344 seq += 8;
345 index += 8;
346 len -= 8;
347 }
348 }
349 }
350 /* not reached */
351}
352
353/* this function is called at probe time for pac7302 */
354static int sd_config(struct gspca_dev *gspca_dev,
355 const struct usb_device_id *id)
356{
357 struct sd *sd = (struct sd *) gspca_dev;
358 struct cam *cam;
359
360 cam = &gspca_dev->cam;
361
Marton Nemeth1408b842009-11-02 08:13:21 -0300362 cam->cam_mode = vga_mode; /* only 640x480 */
363 cam->nmodes = ARRAY_SIZE(vga_mode);
364
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300365 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300366 return 0;
367}
368
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300369static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300370{
371 struct sd *sd = (struct sd *) gspca_dev;
372 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300373 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300374 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
375 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300376 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300377 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
378 0x11, 0x0b};
379
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300380 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300381 for (i = 0; i < 10; i++) {
382 v = max[i];
Hans de Goede74233cd2012-05-14 11:16:09 -0300383 v += (sd->brightness->val - sd->brightness->maximum)
384 * 150 / sd->brightness->maximum; /* 200 ? */
385 v -= delta[i] * sd->contrast->val / sd->contrast->maximum;
Marton Nemeth1408b842009-11-02 08:13:21 -0300386 if (v < 0)
387 v = 0;
388 else if (v > 0xff)
389 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300390 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300391 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300392 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300393}
394
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300395static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300396{
397 struct sd *sd = (struct sd *) gspca_dev;
398 int i, v;
399 static const int a[9] =
400 {217, -212, 0, -101, 170, -67, -38, -315, 355};
401 static const int b[9] =
402 {19, 106, 0, 19, 106, 1, 19, 106, 1};
403
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300404 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
405 reg_w(gspca_dev, 0x11, 0x01);
406 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300407 for (i = 0; i < 9; i++) {
Hans de Goede74233cd2012-05-14 11:16:09 -0300408 v = a[i] * sd->saturation->val / sd->saturation->maximum;
409 v += b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300410 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
411 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300412 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300413 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300414}
415
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300416static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300417{
418 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300419
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300420 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300421 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300422
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300423 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300424}
425
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300426static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300427{
428 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300429
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300430 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300431 reg_w(gspca_dev, 0xc5, sd->red_balance->val);
Márton Németh265a8092009-11-07 15:15:56 -0300432
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300433 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300434}
435
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300436static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300437{
438 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300439
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300440 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300441 reg_w(gspca_dev, 0xc7, sd->blue_balance->val);
Márton Németh265a8092009-11-07 15:15:56 -0300442
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300443 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300444}
445
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300446static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300447{
Hans de Goededf8b9852012-04-28 10:12:28 -0300448 u8 reg10, reg12;
449
Hans de Goede74233cd2012-05-14 11:16:09 -0300450 if (gspca_dev->gain->val < 32) {
451 reg10 = gspca_dev->gain->val;
Hans de Goededf8b9852012-04-28 10:12:28 -0300452 reg12 = 0;
453 } else {
454 reg10 = 31;
Hans de Goede74233cd2012-05-14 11:16:09 -0300455 reg12 = gspca_dev->gain->val - 31;
Hans de Goededf8b9852012-04-28 10:12:28 -0300456 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300457
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300458 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goededf8b9852012-04-28 10:12:28 -0300459 reg_w(gspca_dev, 0x10, reg10);
460 reg_w(gspca_dev, 0x12, reg12);
Marton Nemeth1408b842009-11-02 08:13:21 -0300461
462 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300463 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300464}
465
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300466static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300467{
Jean-François Moineae251e62012-02-27 05:15:12 -0300468 u8 clockdiv;
469 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300470
Hans de Goede895d4642012-04-28 10:31:17 -0300471 /*
472 * Register 2 of frame 3 contains the clock divider configuring the
473 * no fps according to the formula: 90 / reg. sd->exposure is the
474 * desired exposure time in 0.5 ms.
475 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300476 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300477
Hans de Goede895d4642012-04-28 10:31:17 -0300478 /*
479 * Note clockdiv = 3 also works, but when running at 30 fps, depending
480 * on the scene being recorded, the camera switches to another
481 * quantization table for certain JPEG blocks, and we don't know how
482 * to decompress these blocks. So we cap the framerate at 15 fps.
483 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300484 if (clockdiv < 6)
485 clockdiv = 6;
486 else if (clockdiv > 63)
487 clockdiv = 63;
488
Hans de Goede895d4642012-04-28 10:31:17 -0300489 /*
490 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
491 * Always round up, otherwise we cannot get the desired frametime
492 * using the partial frame time exposure control.
493 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300494 if (clockdiv < 6 || clockdiv > 12)
495 clockdiv = ((clockdiv + 2) / 3) * 3;
496
Hans de Goede895d4642012-04-28 10:31:17 -0300497 /*
498 * frame exposure time in ms = 1000 * clockdiv / 90 ->
499 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
500 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300501 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300502 /* 0 = use full frametime, 448 = no exposure, reverse it */
503 exposure = 448 - exposure;
504
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300505 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300506 reg_w(gspca_dev, 0x02, clockdiv);
507 reg_w(gspca_dev, 0x0e, exposure & 0xff);
508 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300509
510 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300511 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300512}
513
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300514static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300515{
516 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300517 u8 data, hflip, vflip;
518
Hans de Goede74233cd2012-05-14 11:16:09 -0300519 hflip = sd->hflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300520 if (sd->flags & FL_HFLIP)
521 hflip = !hflip;
Hans de Goede74233cd2012-05-14 11:16:09 -0300522 vflip = sd->vflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300523 if (sd->flags & FL_VFLIP)
524 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300525
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300526 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300527 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300528 reg_w(gspca_dev, 0x21, data);
529
Marton Nemeth1408b842009-11-02 08:13:21 -0300530 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300531 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300532}
533
534/* this function is called at probe and resume time for pac7302 */
535static int sd_init(struct gspca_dev *gspca_dev)
536{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300537 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
538 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300539}
540
Hans de Goede74233cd2012-05-14 11:16:09 -0300541static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
542{
543 struct gspca_dev *gspca_dev =
544 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
545 struct sd *sd = (struct sd *)gspca_dev;
546
547 gspca_dev->usb_err = 0;
548
549 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
550 /* when switching to autogain set defaults to make sure
551 we are on a valid point of the autogain gain /
552 exposure knee graph, and give this change time to
553 take effect before doing autogain. */
554 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
555 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
556 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
557 }
558
559 if (!gspca_dev->streaming)
560 return 0;
561
562 switch (ctrl->id) {
563 case V4L2_CID_BRIGHTNESS:
564 setbrightcont(gspca_dev);
565 break;
566 case V4L2_CID_SATURATION:
567 setcolors(gspca_dev);
568 break;
569 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
570 setwhitebalance(gspca_dev);
571 break;
572 case V4L2_CID_RED_BALANCE:
573 setredbalance(gspca_dev);
574 break;
575 case V4L2_CID_BLUE_BALANCE:
576 setbluebalance(gspca_dev);
577 break;
578 case V4L2_CID_AUTOGAIN:
579 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
580 setexposure(gspca_dev);
581 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
582 setgain(gspca_dev);
583 break;
584 case V4L2_CID_HFLIP:
585 sethvflip(gspca_dev);
586 break;
587 default:
588 return -EINVAL;
589 }
590 return gspca_dev->usb_err;
591}
592
593static const struct v4l2_ctrl_ops sd_ctrl_ops = {
594 .s_ctrl = sd_s_ctrl,
595};
596
597/* this function is called at probe time */
598static int sd_init_controls(struct gspca_dev *gspca_dev)
599{
600 struct sd *sd = (struct sd *) gspca_dev;
601 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
602
603 gspca_dev->vdev.ctrl_handler = hdl;
604 v4l2_ctrl_handler_init(hdl, 11);
605
606 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
607 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
608 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
609 V4L2_CID_CONTRAST, 0, 255, 1, 127);
610
611 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
612 V4L2_CID_SATURATION, 0, 255, 1, 127);
613 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
614 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
615 0, 255, 1, 4);
616 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
617 V4L2_CID_RED_BALANCE, 0, 3, 1, 1);
618 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
619 V4L2_CID_RED_BALANCE, 0, 3, 1, 1);
620
621 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
622 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
623 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
624 V4L2_CID_EXPOSURE, 0, 1023, 1,
625 PAC7302_EXPOSURE_DEFAULT);
626 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
627 V4L2_CID_GAIN, 0, 62, 1,
628 PAC7302_GAIN_DEFAULT);
629
630 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
631 V4L2_CID_HFLIP, 0, 1, 1, 0);
632 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
633 V4L2_CID_VFLIP, 0, 1, 1, 0);
634
635 if (hdl->error) {
636 pr_err("Could not initialize controls\n");
637 return hdl->error;
638 }
639
640 v4l2_ctrl_cluster(2, &sd->brightness);
641 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
642 v4l2_ctrl_cluster(2, &sd->hflip);
643 return 0;
644}
645
646/* -- start the camera -- */
Marton Nemeth1408b842009-11-02 08:13:21 -0300647static int sd_start(struct gspca_dev *gspca_dev)
648{
649 struct sd *sd = (struct sd *) gspca_dev;
650
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300651 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300652 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300653 setbrightcont(gspca_dev);
654 setcolors(gspca_dev);
655 setwhitebalance(gspca_dev);
656 setredbalance(gspca_dev);
657 setbluebalance(gspca_dev);
Hans de Goede74233cd2012-05-14 11:16:09 -0300658 setexposure(gspca_dev);
659 setgain(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300660 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300661
Marton Nemeth1408b842009-11-02 08:13:21 -0300662 sd->sof_read = 0;
Hans de Goede74233cd2012-05-14 11:16:09 -0300663 sd->autogain_ignore_frames = 0;
664 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300665
666 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300667 reg_w(gspca_dev, 0xff, 0x01);
668 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300669
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300670 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300671}
672
673static void sd_stopN(struct gspca_dev *gspca_dev)
674{
Márton Némethb1784b32009-11-07 05:52:02 -0300675
Márton Németh67c98f72009-11-07 05:45:33 -0300676 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300677 reg_w(gspca_dev, 0xff, 0x01);
678 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300679}
680
681/* called on streamoff with alt 0 and on disconnect for pac7302 */
682static void sd_stop0(struct gspca_dev *gspca_dev)
683{
684 if (!gspca_dev->present)
685 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300686 reg_w(gspca_dev, 0xff, 0x01);
687 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300688}
689
Marton Nemeth1408b842009-11-02 08:13:21 -0300690static void do_autogain(struct gspca_dev *gspca_dev)
691{
692 struct sd *sd = (struct sd *) gspca_dev;
693 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300694 int desired_lum;
695 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300696
Jean-François Moineac399cd2012-02-27 05:40:47 -0300697 if (sd->autogain_ignore_frames < 0)
Marton Nemeth1408b842009-11-02 08:13:21 -0300698 return;
699
Jean-François Moineac399cd2012-02-27 05:40:47 -0300700 if (sd->autogain_ignore_frames > 0) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300701 sd->autogain_ignore_frames--;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300702 } else {
Hans de Goede74233cd2012-05-14 11:16:09 -0300703 desired_lum = 270 + sd->brightness->val;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300704
Hans de Goede74233cd2012-05-14 11:16:09 -0300705 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
706 deadzone, PAC7302_GAIN_KNEE,
707 PAC7302_EXPOSURE_KNEE))
708 sd->autogain_ignore_frames =
709 PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300710 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300711}
712
Jean-François Moine7532e812012-02-27 05:21:57 -0300713/* JPEG header */
714static const u8 jpeg_header[] = {
715 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300716
Jean-François Moine7532e812012-02-27 05:21:57 -0300717 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
718 0x00, 0x11, /* length = 17 bytes (including this length field) */
719 0x08, /* Precision: 8 */
720 0x02, 0x80, /* height = 640 (image rotated) */
721 0x01, 0xe0, /* width = 480 */
722 0x03, /* Number of image components: 3 */
723 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
724 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
725 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
726
727 0xff, 0xda, /* SOS: Start Of Scan */
728 0x00, 0x0c, /* length = 12 bytes (including this length field) */
729 0x03, /* number of components: 3 */
730 0x01, 0x00, /* selector 1, table 0x00 */
731 0x02, 0x11, /* selector 2, table 0x11 */
732 0x03, 0x11, /* selector 3, table 0x11 */
733 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
734 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300735};
736
Marton Nemeth1408b842009-11-02 08:13:21 -0300737/* this function is run at interrupt level */
738static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300739 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300740 int len) /* iso packet length */
741{
742 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300743 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300744 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300745
746 sof = pac_find_sof(&sd->sof_read, data, len);
747 if (sof) {
748 int n, lum_offset, footer_length;
749
Hans de Goede895d4642012-04-28 10:31:17 -0300750 /*
751 * 6 bytes after the FF D9 EOF marker a number of lumination
752 * bytes are send corresponding to different parts of the
753 * image, the 14th and 15th byte after the EOF seem to
754 * correspond to the center of the image.
755 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300756 lum_offset = 61 + sizeof pac_sof_marker;
757 footer_length = 74;
758
759 /* Finish decoding current frame */
760 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
761 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300762 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300763 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300764 } else {
765 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300766 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300767
768 image = gspca_dev->image;
769 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300770 && image[gspca_dev->image_len - 2] == 0xff
771 && image[gspca_dev->image_len - 1] == 0xd9)
772 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300773
774 n = sof - data;
775 len -= n;
776 data = sof;
777
778 /* Get average lumination */
779 if (gspca_dev->last_packet_type == LAST_PACKET &&
780 n >= lum_offset)
781 atomic_set(&sd->avg_lum, data[-lum_offset] +
782 data[-lum_offset + 1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300783
784 /* Start the new frame with the jpeg header */
785 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300786 gspca_frame_add(gspca_dev, FIRST_PACKET,
787 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300788 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300789 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300790}
791
Márton Németh6763cc02009-11-09 07:10:46 -0300792#ifdef CONFIG_VIDEO_ADV_DEBUG
793static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
794 struct v4l2_dbg_register *reg)
795{
Jean-François Moineae251e62012-02-27 05:15:12 -0300796 u8 index;
797 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300798
Hans de Goede895d4642012-04-28 10:31:17 -0300799 /*
800 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
801 * long on the USB bus)
802 */
Márton Németh6763cc02009-11-09 07:10:46 -0300803 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
804 reg->match.addr == 0 &&
805 (reg->reg < 0x000000ff) &&
806 (reg->val <= 0x000000ff)
807 ) {
808 /* Currently writing to page 0 is only supported. */
809 /* reg_w() only supports 8bit index */
Jean-François Moineae251e62012-02-27 05:15:12 -0300810 index = reg->reg;
811 value = reg->val;
Márton Németh6763cc02009-11-09 07:10:46 -0300812
Hans de Goede895d4642012-04-28 10:31:17 -0300813 /*
814 * Note that there shall be no access to other page
815 * by any other function between the page switch and
816 * the actual register write.
817 */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300818 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
819 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300820
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300821 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300822 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300823 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300824}
825
826static int sd_chip_ident(struct gspca_dev *gspca_dev,
827 struct v4l2_dbg_chip_ident *chip)
828{
829 int ret = -EINVAL;
830
831 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
832 chip->match.addr == 0) {
833 chip->revision = 0;
834 chip->ident = V4L2_IDENT_UNKNOWN;
835 ret = 0;
836 }
837 return ret;
838}
839#endif
840
Jean-François Moine28566432010-10-01 07:33:26 -0300841#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300842static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
843 u8 *data, /* interrupt packet data */
844 int len) /* interrput packet length */
845{
846 int ret = -EINVAL;
847 u8 data0, data1;
848
849 if (len == 2) {
850 data0 = data[0];
851 data1 = data[1];
852 if ((data0 == 0x00 && data1 == 0x11) ||
853 (data0 == 0x22 && data1 == 0x33) ||
854 (data0 == 0x44 && data1 == 0x55) ||
855 (data0 == 0x66 && data1 == 0x77) ||
856 (data0 == 0x88 && data1 == 0x99) ||
857 (data0 == 0xaa && data1 == 0xbb) ||
858 (data0 == 0xcc && data1 == 0xdd) ||
859 (data0 == 0xee && data1 == 0xff)) {
860 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
861 input_sync(gspca_dev->input_dev);
862 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
863 input_sync(gspca_dev->input_dev);
864 ret = 0;
865 }
866 }
867
868 return ret;
869}
870#endif
871
Marton Nemeth1408b842009-11-02 08:13:21 -0300872/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300873static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300874 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300875 .config = sd_config,
876 .init = sd_init,
Hans de Goede74233cd2012-05-14 11:16:09 -0300877 .init_controls = sd_init_controls,
Marton Nemeth1408b842009-11-02 08:13:21 -0300878 .start = sd_start,
879 .stopN = sd_stopN,
880 .stop0 = sd_stop0,
881 .pkt_scan = sd_pkt_scan,
882 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300883#ifdef CONFIG_VIDEO_ADV_DEBUG
884 .set_register = sd_dbg_s_register,
885 .get_chip_ident = sd_chip_ident,
886#endif
Jean-François Moine28566432010-10-01 07:33:26 -0300887#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300888 .int_pkt_scan = sd_int_pkt_scan,
889#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300890};
891
892/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300893static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300894 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300895 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300896 {USB_DEVICE(0x093a, 0x2620)},
897 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300898 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
899 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300900 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300901 {USB_DEVICE(0x093a, 0x2626)},
Jozsef Marton5b843252012-05-15 12:05:36 -0300902 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300903 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300904 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300905 {USB_DEVICE(0x093a, 0x262a)},
906 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300907 {USB_DEVICE(0x145f, 0x013c)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300908 {}
909};
910MODULE_DEVICE_TABLE(usb, device_table);
911
912/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300913static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300914 const struct usb_device_id *id)
915{
916 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
917 THIS_MODULE);
918}
919
920static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300921 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300922 .id_table = device_table,
923 .probe = sd_probe,
924 .disconnect = gspca_disconnect,
925#ifdef CONFIG_PM
926 .suspend = gspca_suspend,
927 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300928 .reset_resume = gspca_resume,
Marton Nemeth1408b842009-11-02 08:13:21 -0300929#endif
930};
931
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800932module_usb_driver(sd_driver);