blob: 8c2961326a653aaf2f5ba0c4e2b768e21e6b6c89 [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
32 * 0xb6 Sharpness control (bits 0-4)
33 *
Hans de Goede895d4642012-04-28 10:31:17 -030034 * Register page 1:
35 *
36 * Address Description
37 * 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goede48bb7312012-04-27 13:00:57 -030038 * 0x80 Compression balance, 2 interesting settings:
39 * 0x0f Default
40 * 0x50 Values >= this switch the camera to a lower compression,
41 * using the same table for both luminance and chrominance.
42 * This gives a sharper picture. Only usable when running
43 * at < 15 fps! Note currently the driver does not use this
44 * as the quality gain is small and the generated JPG-s are
45 * only understood by v4l-utils >= 0.8.9
Hans de Goede895d4642012-04-28 10:31:17 -030046 *
47 * Register page 3:
48 *
49 * Address Description
50 * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
51 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
52 * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
53 * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
54 * 63 -> ~27 fps, the 2 msb's must always be 1 !!
55 * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
56 * 1 -> ~30 fps, 2 -> ~20 fps
57 * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
58 * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
Hans de Goede48bb7312012-04-27 13:00:57 -030059 * 0x10 Gain 0-31
60 * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
61 * amplification value of 1 rather then 0 at its lowest setting
Hans de Goede895d4642012-04-28 10:31:17 -030062 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede48bb7312012-04-27 13:00:57 -030063 * 0x80 Another framerate control, best left at 1, moving it from 1 to
64 * 2 causes the framerate to become 3/4th of what it was, and
65 * also seems to cause pixel averaging, resulting in an effective
66 * resolution of 320x240 and thus a much blockier image
Hans de Goede895d4642012-04-28 10:31:17 -030067 *
68 * The registers are accessed in the following functions:
69 *
70 * Page | Register | Function
71 * -----+------------+---------------------------------------------------
72 * 0 | 0x0f..0x20 | setcolors()
73 * 0 | 0xa2..0xab | setbrightcont()
Frank Schäferb1a19c02012-09-09 15:02:21 -030074 * 0 | 0xb6 | setsharpness()
Hans de Goede895d4642012-04-28 10:31:17 -030075 * 0 | 0xc5 | setredbalance()
76 * 0 | 0xc6 | setwhitebalance()
77 * 0 | 0xc7 | setbluebalance()
78 * 0 | 0xdc | setbrightcont(), setcolors()
79 * 3 | 0x02 | setexposure()
Hans de Goededf8b9852012-04-28 10:12:28 -030080 * 3 | 0x10, 0x12 | setgain()
Hans de Goede895d4642012-04-28 10:31:17 -030081 * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
82 * 3 | 0x21 | sethvflip()
83 */
Marton Nemeth1408b842009-11-02 08:13:21 -030084
Joe Perches133a9fe2011-08-21 19:56:57 -030085#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
86
Márton Némethaed6f1b2010-01-28 16:33:38 -030087#include <linux/input.h>
Márton Németh6763cc02009-11-09 07:10:46 -030088#include <media/v4l2-chip-ident.h>
Marton Nemeth1408b842009-11-02 08:13:21 -030089#include "gspca.h"
Jean-François Moineac399cd2012-02-27 05:40:47 -030090/* Include pac common sof detection functions */
91#include "pac_common.h"
Marton Nemeth1408b842009-11-02 08:13:21 -030092
Hans de Goede74233cd2012-05-14 11:16:09 -030093#define PAC7302_GAIN_DEFAULT 15
94#define PAC7302_GAIN_KNEE 42
95#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */
96#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
97
Jean-François Moineae251e62012-02-27 05:15:12 -030098MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
99 "Thomas Kaiser thomas@kaiser-linux.li");
Marton Nemeth1408b842009-11-02 08:13:21 -0300100MODULE_DESCRIPTION("Pixart PAC7302");
101MODULE_LICENSE("GPL");
102
Marton Nemeth1408b842009-11-02 08:13:21 -0300103struct sd {
104 struct gspca_dev gspca_dev; /* !! must be the first item */
105
Hans de Goede74233cd2012-05-14 11:16:09 -0300106 struct { /* brightness / contrast cluster */
107 struct v4l2_ctrl *brightness;
108 struct v4l2_ctrl *contrast;
109 };
110 struct v4l2_ctrl *saturation;
111 struct v4l2_ctrl *white_balance;
112 struct v4l2_ctrl *red_balance;
113 struct v4l2_ctrl *blue_balance;
114 struct { /* flip cluster */
115 struct v4l2_ctrl *hflip;
116 struct v4l2_ctrl *vflip;
117 };
Frank Schäferb1a19c02012-09-09 15:02:21 -0300118 struct v4l2_ctrl *sharpness;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300119 u8 flags;
120#define FL_HFLIP 0x01 /* mirrored by default */
121#define FL_VFLIP 0x02 /* vertical flipped by default */
Marton Nemeth1408b842009-11-02 08:13:21 -0300122
123 u8 sof_read;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300124 s8 autogain_ignore_frames;
Marton Nemeth1408b842009-11-02 08:13:21 -0300125
126 atomic_t avg_lum;
127};
128
Marton Nemeth1408b842009-11-02 08:13:21 -0300129static const struct v4l2_pix_format vga_mode[] = {
130 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
131 .bytesperline = 640,
132 .sizeimage = 640 * 480 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
Jean-François Moineae251e62012-02-27 05:15:12 -0300134 },
Marton Nemeth1408b842009-11-02 08:13:21 -0300135};
136
137#define LOAD_PAGE3 255
Marton Nemeth1408b842009-11-02 08:13:21 -0300138#define END_OF_SEQUENCE 0
139
Jean-François Moineae251e62012-02-27 05:15:12 -0300140static const u8 init_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300141/* index,value */
142 0xff, 0x01, /* page 1 */
143 0x78, 0x00, /* deactivate */
144 0xff, 0x01,
145 0x78, 0x40, /* led off */
146};
Jean-François Moineae251e62012-02-27 05:15:12 -0300147static const u8 start_7302[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300148/* index, len, [value]* */
149 0xff, 1, 0x00, /* page 0 */
150 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
151 0x00, 0x00, 0x00, 0x00,
152 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
153 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
154 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
155 0x26, 2, 0xaa, 0xaa,
156 0x2e, 1, 0x31,
157 0x38, 1, 0x01,
158 0x3a, 3, 0x14, 0xff, 0x5a,
159 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
160 0x00, 0x54, 0x11,
161 0x55, 1, 0x00,
Jean-François Moineae251e62012-02-27 05:15:12 -0300162 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
Marton Nemeth1408b842009-11-02 08:13:21 -0300163 0x6b, 1, 0x00,
164 0x6e, 3, 0x08, 0x06, 0x00,
165 0x72, 3, 0x00, 0xff, 0x00,
166 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
167 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
168 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
169 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
170 0xd2, 0xeb,
171 0xaf, 1, 0x02,
172 0xb5, 2, 0x08, 0x08,
173 0xb8, 2, 0x08, 0x88,
174 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
175 0xcc, 1, 0x00,
176 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
177 0xc1, 0xd7, 0xec,
178 0xdc, 1, 0x01,
179 0xff, 1, 0x01, /* page 1 */
180 0x12, 3, 0x02, 0x00, 0x01,
181 0x3e, 2, 0x00, 0x00,
182 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
183 0x7c, 1, 0x00,
184 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
185 0x02, 0x00,
186 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
187 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
188 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
189 0xd8, 1, 0x01,
190 0xdb, 2, 0x00, 0x01,
191 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
192 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
193 0xeb, 1, 0x00,
194 0xff, 1, 0x02, /* page 2 */
195 0x22, 1, 0x00,
196 0xff, 1, 0x03, /* page 3 */
197 0, LOAD_PAGE3, /* load the page 3 */
198 0x11, 1, 0x01,
199 0xff, 1, 0x02, /* page 2 */
200 0x13, 1, 0x00,
201 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
202 0x27, 2, 0x14, 0x0c,
203 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
204 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
205 0x6e, 1, 0x08,
206 0xff, 1, 0x01, /* page 1 */
207 0x78, 1, 0x00,
208 0, END_OF_SEQUENCE /* end of sequence */
209};
210
211#define SKIP 0xaa
212/* page 3 - the value SKIP says skip the index - see reg_w_page() */
Jean-François Moineae251e62012-02-27 05:15:12 -0300213static const u8 page3_7302[] = {
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300214 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
Marton Nemeth1408b842009-11-02 08:13:21 -0300215 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
216 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
218 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
219 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
220 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
221 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
Jean-Francois Moinecdf955c2010-01-11 15:06:12 -0300223 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
Marton Nemeth1408b842009-11-02 08:13:21 -0300224 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
228 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
229 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
230 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
233 0x00
234};
235
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300236static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300237 u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300238 const u8 *buffer, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300239{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300240 int ret;
241
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300242 if (gspca_dev->usb_err < 0)
243 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300244 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300245 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300246 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300247 0, /* request */
Marton Nemeth1408b842009-11-02 08:13:21 -0300248 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
249 0, /* value */
250 index, gspca_dev->usb_buf, len,
251 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300252 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300253 pr_err("reg_w_buf failed i: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300254 index, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300255 gspca_dev->usb_err = ret;
256 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300257}
258
259
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300260static void reg_w(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300261 u8 index,
262 u8 value)
Marton Nemeth1408b842009-11-02 08:13:21 -0300263{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300264 int ret;
265
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300266 if (gspca_dev->usb_err < 0)
267 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300268 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300269 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300270 usb_sndctrlpipe(gspca_dev->dev, 0),
271 0, /* request */
272 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
273 0, index, gspca_dev->usb_buf, 1,
274 500);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300275 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300276 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300277 index, value, ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300278 gspca_dev->usb_err = ret;
279 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300280}
281
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300282static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300283 const u8 *seq, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300284{
285 while (--len >= 0) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300286 reg_w(gspca_dev, seq[0], seq[1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300287 seq += 2;
288 }
289}
290
291/* load the beginning of a page */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300292static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300293 const u8 *page, int len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300294{
295 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300296 int ret = 0;
Marton Nemeth1408b842009-11-02 08:13:21 -0300297
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300298 if (gspca_dev->usb_err < 0)
299 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300300 for (index = 0; index < len; index++) {
301 if (page[index] == SKIP) /* skip this index */
302 continue;
303 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300304 ret = usb_control_msg(gspca_dev->dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300305 usb_sndctrlpipe(gspca_dev->dev, 0),
306 0, /* request */
307 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
308 0, index, gspca_dev->usb_buf, 1,
309 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300310 if (ret < 0) {
Jean-François Moineae251e62012-02-27 05:15:12 -0300311 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
Joe Perches133a9fe2011-08-21 19:56:57 -0300312 index, page[index], ret);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300313 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300314 break;
315 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300316 }
317}
318
319/* output a variable sequence */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300320static void reg_w_var(struct gspca_dev *gspca_dev,
Jean-François Moineae251e62012-02-27 05:15:12 -0300321 const u8 *seq,
322 const u8 *page3, unsigned int page3_len)
Marton Nemeth1408b842009-11-02 08:13:21 -0300323{
324 int index, len;
325
326 for (;;) {
327 index = *seq++;
328 len = *seq++;
329 switch (len) {
330 case END_OF_SEQUENCE:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300331 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300332 case LOAD_PAGE3:
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300333 reg_w_page(gspca_dev, page3, page3_len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300334 break;
335 default:
Jean-François Moineae251e62012-02-27 05:15:12 -0300336#ifdef GSPCA_DEBUG
Marton Nemeth1408b842009-11-02 08:13:21 -0300337 if (len > USB_BUF_SZ) {
338 PDEBUG(D_ERR|D_STREAM,
339 "Incorrect variable sequence");
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300340 return;
Marton Nemeth1408b842009-11-02 08:13:21 -0300341 }
Jean-François Moineae251e62012-02-27 05:15:12 -0300342#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300343 while (len > 0) {
344 if (len < 8) {
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300345 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300346 index, seq, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300347 seq += len;
348 break;
349 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300350 reg_w_buf(gspca_dev, index, seq, 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300351 seq += 8;
352 index += 8;
353 len -= 8;
354 }
355 }
356 }
357 /* not reached */
358}
359
360/* this function is called at probe time for pac7302 */
361static int sd_config(struct gspca_dev *gspca_dev,
362 const struct usb_device_id *id)
363{
364 struct sd *sd = (struct sd *) gspca_dev;
365 struct cam *cam;
366
367 cam = &gspca_dev->cam;
368
Marton Nemeth1408b842009-11-02 08:13:21 -0300369 cam->cam_mode = vga_mode; /* only 640x480 */
370 cam->nmodes = ARRAY_SIZE(vga_mode);
371
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300372 sd->flags = id->driver_info;
Marton Nemeth1408b842009-11-02 08:13:21 -0300373 return 0;
374}
375
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300376static void setbrightcont(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300377{
378 struct sd *sd = (struct sd *) gspca_dev;
379 int i, v;
Jean-François Moineae251e62012-02-27 05:15:12 -0300380 static const u8 max[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300381 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
382 0xd4, 0xec};
Jean-François Moineae251e62012-02-27 05:15:12 -0300383 static const u8 delta[10] =
Marton Nemeth1408b842009-11-02 08:13:21 -0300384 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
385 0x11, 0x0b};
386
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300387 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300388 for (i = 0; i < 10; i++) {
389 v = max[i];
Hans de Goede74233cd2012-05-14 11:16:09 -0300390 v += (sd->brightness->val - sd->brightness->maximum)
391 * 150 / sd->brightness->maximum; /* 200 ? */
392 v -= delta[i] * sd->contrast->val / sd->contrast->maximum;
Marton Nemeth1408b842009-11-02 08:13:21 -0300393 if (v < 0)
394 v = 0;
395 else if (v > 0xff)
396 v = 0xff;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300397 reg_w(gspca_dev, 0xa2 + i, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300398 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300399 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300400}
401
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300402static void setcolors(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300403{
404 struct sd *sd = (struct sd *) gspca_dev;
405 int i, v;
406 static const int a[9] =
407 {217, -212, 0, -101, 170, -67, -38, -315, 355};
408 static const int b[9] =
409 {19, 106, 0, 19, 106, 1, 19, 106, 1};
410
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300411 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
412 reg_w(gspca_dev, 0x11, 0x01);
413 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300414 for (i = 0; i < 9; i++) {
Hans de Goede74233cd2012-05-14 11:16:09 -0300415 v = a[i] * sd->saturation->val / sd->saturation->maximum;
416 v += b[i];
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300417 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
418 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
Marton Nemeth1408b842009-11-02 08:13:21 -0300419 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300420 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300421}
422
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300423static void setwhitebalance(struct gspca_dev *gspca_dev)
Marton Nemeth23fbee62009-11-08 04:35:12 -0300424{
425 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth23fbee62009-11-08 04:35:12 -0300426
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300427 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300428 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300429
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300430 reg_w(gspca_dev, 0xdc, 0x01);
Marton Nemeth23fbee62009-11-08 04:35:12 -0300431}
432
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300433static void setredbalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300434{
435 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300436
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300437 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300438 reg_w(gspca_dev, 0xc5, sd->red_balance->val);
Márton Németh265a8092009-11-07 15:15:56 -0300439
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300440 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300441}
442
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300443static void setbluebalance(struct gspca_dev *gspca_dev)
Márton Németh265a8092009-11-07 15:15:56 -0300444{
445 struct sd *sd = (struct sd *) gspca_dev;
Márton Németh265a8092009-11-07 15:15:56 -0300446
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300447 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300448 reg_w(gspca_dev, 0xc7, sd->blue_balance->val);
Márton Németh265a8092009-11-07 15:15:56 -0300449
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300450 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh265a8092009-11-07 15:15:56 -0300451}
452
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300453static void setgain(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300454{
Hans de Goededf8b9852012-04-28 10:12:28 -0300455 u8 reg10, reg12;
456
Hans de Goede74233cd2012-05-14 11:16:09 -0300457 if (gspca_dev->gain->val < 32) {
458 reg10 = gspca_dev->gain->val;
Hans de Goededf8b9852012-04-28 10:12:28 -0300459 reg12 = 0;
460 } else {
461 reg10 = 31;
Hans de Goede74233cd2012-05-14 11:16:09 -0300462 reg12 = gspca_dev->gain->val - 31;
Hans de Goededf8b9852012-04-28 10:12:28 -0300463 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300464
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300465 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goededf8b9852012-04-28 10:12:28 -0300466 reg_w(gspca_dev, 0x10, reg10);
467 reg_w(gspca_dev, 0x12, reg12);
Marton Nemeth1408b842009-11-02 08:13:21 -0300468
469 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300470 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300471}
472
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300473static void setexposure(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300474{
Jean-François Moineae251e62012-02-27 05:15:12 -0300475 u8 clockdiv;
476 u16 exposure;
Marton Nemeth1408b842009-11-02 08:13:21 -0300477
Hans de Goede895d4642012-04-28 10:31:17 -0300478 /*
479 * Register 2 of frame 3 contains the clock divider configuring the
480 * no fps according to the formula: 90 / reg. sd->exposure is the
481 * desired exposure time in 0.5 ms.
482 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300483 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
Marton Nemeth1408b842009-11-02 08:13:21 -0300484
Hans de Goede895d4642012-04-28 10:31:17 -0300485 /*
486 * Note clockdiv = 3 also works, but when running at 30 fps, depending
487 * on the scene being recorded, the camera switches to another
488 * quantization table for certain JPEG blocks, and we don't know how
489 * to decompress these blocks. So we cap the framerate at 15 fps.
490 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300491 if (clockdiv < 6)
492 clockdiv = 6;
493 else if (clockdiv > 63)
494 clockdiv = 63;
495
Hans de Goede895d4642012-04-28 10:31:17 -0300496 /*
497 * Register 2 MUST be a multiple of 3, except when between 6 and 12?
498 * Always round up, otherwise we cannot get the desired frametime
499 * using the partial frame time exposure control.
500 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300501 if (clockdiv < 6 || clockdiv > 12)
502 clockdiv = ((clockdiv + 2) / 3) * 3;
503
Hans de Goede895d4642012-04-28 10:31:17 -0300504 /*
505 * frame exposure time in ms = 1000 * clockdiv / 90 ->
506 * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
507 */
Hans de Goede74233cd2012-05-14 11:16:09 -0300508 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300509 /* 0 = use full frametime, 448 = no exposure, reverse it */
510 exposure = 448 - exposure;
511
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300512 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300513 reg_w(gspca_dev, 0x02, clockdiv);
514 reg_w(gspca_dev, 0x0e, exposure & 0xff);
515 reg_w(gspca_dev, 0x0f, exposure >> 8);
Marton Nemeth1408b842009-11-02 08:13:21 -0300516
517 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300518 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300519}
520
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300521static void sethvflip(struct gspca_dev *gspca_dev)
Marton Nemeth1408b842009-11-02 08:13:21 -0300522{
523 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300524 u8 data, hflip, vflip;
525
Hans de Goede74233cd2012-05-14 11:16:09 -0300526 hflip = sd->hflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300527 if (sd->flags & FL_HFLIP)
528 hflip = !hflip;
Hans de Goede74233cd2012-05-14 11:16:09 -0300529 vflip = sd->vflip->val;
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300530 if (sd->flags & FL_VFLIP)
531 vflip = !vflip;
Marton Nemeth1408b842009-11-02 08:13:21 -0300532
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300533 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300534 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300535 reg_w(gspca_dev, 0x21, data);
536
Marton Nemeth1408b842009-11-02 08:13:21 -0300537 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300538 reg_w(gspca_dev, 0x11, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300539}
540
Frank Schäferb1a19c02012-09-09 15:02:21 -0300541static void setsharpness(struct gspca_dev *gspca_dev)
542{
543 struct sd *sd = (struct sd *) gspca_dev;
544
545 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
546 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
547
548 reg_w(gspca_dev, 0xdc, 0x01);
549}
550
Marton Nemeth1408b842009-11-02 08:13:21 -0300551/* this function is called at probe and resume time for pac7302 */
552static int sd_init(struct gspca_dev *gspca_dev)
553{
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300554 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
555 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300556}
557
Hans de Goede74233cd2012-05-14 11:16:09 -0300558static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
559{
560 struct gspca_dev *gspca_dev =
561 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
562 struct sd *sd = (struct sd *)gspca_dev;
563
564 gspca_dev->usb_err = 0;
565
566 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
567 /* when switching to autogain set defaults to make sure
568 we are on a valid point of the autogain gain /
569 exposure knee graph, and give this change time to
570 take effect before doing autogain. */
571 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
572 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
573 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
574 }
575
576 if (!gspca_dev->streaming)
577 return 0;
578
579 switch (ctrl->id) {
580 case V4L2_CID_BRIGHTNESS:
581 setbrightcont(gspca_dev);
582 break;
583 case V4L2_CID_SATURATION:
584 setcolors(gspca_dev);
585 break;
586 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
587 setwhitebalance(gspca_dev);
588 break;
589 case V4L2_CID_RED_BALANCE:
590 setredbalance(gspca_dev);
591 break;
592 case V4L2_CID_BLUE_BALANCE:
593 setbluebalance(gspca_dev);
594 break;
595 case V4L2_CID_AUTOGAIN:
596 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
597 setexposure(gspca_dev);
598 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
599 setgain(gspca_dev);
600 break;
601 case V4L2_CID_HFLIP:
602 sethvflip(gspca_dev);
603 break;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300604 case V4L2_CID_SHARPNESS:
605 setsharpness(gspca_dev);
606 break;
Hans de Goede74233cd2012-05-14 11:16:09 -0300607 default:
608 return -EINVAL;
609 }
610 return gspca_dev->usb_err;
611}
612
613static const struct v4l2_ctrl_ops sd_ctrl_ops = {
614 .s_ctrl = sd_s_ctrl,
615};
616
617/* this function is called at probe time */
618static int sd_init_controls(struct gspca_dev *gspca_dev)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
621 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
622
623 gspca_dev->vdev.ctrl_handler = hdl;
Frank Schäferb1a19c02012-09-09 15:02:21 -0300624 v4l2_ctrl_handler_init(hdl, 12);
Hans de Goede74233cd2012-05-14 11:16:09 -0300625
626 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
627 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
628 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
629 V4L2_CID_CONTRAST, 0, 255, 1, 127);
630
631 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
632 V4L2_CID_SATURATION, 0, 255, 1, 127);
633 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
634 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
635 0, 255, 1, 4);
636 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
637 V4L2_CID_RED_BALANCE, 0, 3, 1, 1);
638 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Frank Schäferdb43b9c2012-09-09 15:02:20 -0300639 V4L2_CID_BLUE_BALANCE, 0, 3, 1, 1);
Hans de Goede74233cd2012-05-14 11:16:09 -0300640
641 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
642 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
643 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
644 V4L2_CID_EXPOSURE, 0, 1023, 1,
645 PAC7302_EXPOSURE_DEFAULT);
646 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
647 V4L2_CID_GAIN, 0, 62, 1,
648 PAC7302_GAIN_DEFAULT);
649
650 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
651 V4L2_CID_HFLIP, 0, 1, 1, 0);
652 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
653 V4L2_CID_VFLIP, 0, 1, 1, 0);
654
Frank Schäferb1a19c02012-09-09 15:02:21 -0300655 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
656 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
657
Hans de Goede74233cd2012-05-14 11:16:09 -0300658 if (hdl->error) {
659 pr_err("Could not initialize controls\n");
660 return hdl->error;
661 }
662
663 v4l2_ctrl_cluster(2, &sd->brightness);
664 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
665 v4l2_ctrl_cluster(2, &sd->hflip);
666 return 0;
667}
668
669/* -- start the camera -- */
Marton Nemeth1408b842009-11-02 08:13:21 -0300670static int sd_start(struct gspca_dev *gspca_dev)
671{
672 struct sd *sd = (struct sd *) gspca_dev;
673
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300674 reg_w_var(gspca_dev, start_7302,
Jean-Francois Moine23a5de22010-01-13 08:30:30 -0300675 page3_7302, sizeof(page3_7302));
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300676 setbrightcont(gspca_dev);
677 setcolors(gspca_dev);
678 setwhitebalance(gspca_dev);
679 setredbalance(gspca_dev);
680 setbluebalance(gspca_dev);
Hans de Goede74233cd2012-05-14 11:16:09 -0300681 setexposure(gspca_dev);
682 setgain(gspca_dev);
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300683 sethvflip(gspca_dev);
Marton Nemeth1408b842009-11-02 08:13:21 -0300684
Marton Nemeth1408b842009-11-02 08:13:21 -0300685 sd->sof_read = 0;
Hans de Goede74233cd2012-05-14 11:16:09 -0300686 sd->autogain_ignore_frames = 0;
687 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
Marton Nemeth1408b842009-11-02 08:13:21 -0300688
689 /* start stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300690 reg_w(gspca_dev, 0xff, 0x01);
691 reg_w(gspca_dev, 0x78, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300692
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300693 return gspca_dev->usb_err;
Marton Nemeth1408b842009-11-02 08:13:21 -0300694}
695
696static void sd_stopN(struct gspca_dev *gspca_dev)
697{
Márton Némethb1784b32009-11-07 05:52:02 -0300698
Márton Németh67c98f72009-11-07 05:45:33 -0300699 /* stop stream */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300700 reg_w(gspca_dev, 0xff, 0x01);
701 reg_w(gspca_dev, 0x78, 0x00);
Marton Nemeth1408b842009-11-02 08:13:21 -0300702}
703
704/* called on streamoff with alt 0 and on disconnect for pac7302 */
705static void sd_stop0(struct gspca_dev *gspca_dev)
706{
707 if (!gspca_dev->present)
708 return;
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300709 reg_w(gspca_dev, 0xff, 0x01);
710 reg_w(gspca_dev, 0x78, 0x40);
Marton Nemeth1408b842009-11-02 08:13:21 -0300711}
712
Marton Nemeth1408b842009-11-02 08:13:21 -0300713static void do_autogain(struct gspca_dev *gspca_dev)
714{
715 struct sd *sd = (struct sd *) gspca_dev;
716 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede5fb2dde2010-02-17 11:59:19 -0300717 int desired_lum;
718 const int deadzone = 30;
Marton Nemeth1408b842009-11-02 08:13:21 -0300719
Jean-François Moineac399cd2012-02-27 05:40:47 -0300720 if (sd->autogain_ignore_frames < 0)
Marton Nemeth1408b842009-11-02 08:13:21 -0300721 return;
722
Jean-François Moineac399cd2012-02-27 05:40:47 -0300723 if (sd->autogain_ignore_frames > 0) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300724 sd->autogain_ignore_frames--;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300725 } else {
Hans de Goede74233cd2012-05-14 11:16:09 -0300726 desired_lum = 270 + sd->brightness->val;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300727
Hans de Goede74233cd2012-05-14 11:16:09 -0300728 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
729 deadzone, PAC7302_GAIN_KNEE,
730 PAC7302_EXPOSURE_KNEE))
731 sd->autogain_ignore_frames =
732 PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-François Moineac399cd2012-02-27 05:40:47 -0300733 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300734}
735
Jean-François Moine7532e812012-02-27 05:21:57 -0300736/* JPEG header */
737static const u8 jpeg_header[] = {
738 0xff, 0xd8, /* SOI: Start of Image */
Marton Nemeth1408b842009-11-02 08:13:21 -0300739
Jean-François Moine7532e812012-02-27 05:21:57 -0300740 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
741 0x00, 0x11, /* length = 17 bytes (including this length field) */
742 0x08, /* Precision: 8 */
743 0x02, 0x80, /* height = 640 (image rotated) */
744 0x01, 0xe0, /* width = 480 */
745 0x03, /* Number of image components: 3 */
746 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
747 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
748 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
749
750 0xff, 0xda, /* SOS: Start Of Scan */
751 0x00, 0x0c, /* length = 12 bytes (including this length field) */
752 0x03, /* number of components: 3 */
753 0x01, 0x00, /* selector 1, table 0x00 */
754 0x02, 0x11, /* selector 2, table 0x11 */
755 0x03, 0x11, /* selector 3, table 0x11 */
756 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
757 0x00 /* Successive approximation: 0 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300758};
759
Marton Nemeth1408b842009-11-02 08:13:21 -0300760/* this function is run at interrupt level */
761static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300762 u8 *data, /* isoc packet */
Marton Nemeth1408b842009-11-02 08:13:21 -0300763 int len) /* iso packet length */
764{
765 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300766 u8 *image;
Jean-François Moineae251e62012-02-27 05:15:12 -0300767 u8 *sof;
Marton Nemeth1408b842009-11-02 08:13:21 -0300768
769 sof = pac_find_sof(&sd->sof_read, data, len);
770 if (sof) {
771 int n, lum_offset, footer_length;
772
Hans de Goede895d4642012-04-28 10:31:17 -0300773 /*
774 * 6 bytes after the FF D9 EOF marker a number of lumination
775 * bytes are send corresponding to different parts of the
776 * image, the 14th and 15th byte after the EOF seem to
777 * correspond to the center of the image.
778 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300779 lum_offset = 61 + sizeof pac_sof_marker;
780 footer_length = 74;
781
782 /* Finish decoding current frame */
783 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
784 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300785 gspca_dev->image_len += n;
Marton Nemeth1408b842009-11-02 08:13:21 -0300786 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300787 } else {
788 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Marton Nemeth1408b842009-11-02 08:13:21 -0300789 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300790
791 image = gspca_dev->image;
792 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300793 && image[gspca_dev->image_len - 2] == 0xff
794 && image[gspca_dev->image_len - 1] == 0xd9)
795 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Marton Nemeth1408b842009-11-02 08:13:21 -0300796
797 n = sof - data;
798 len -= n;
799 data = sof;
800
801 /* Get average lumination */
802 if (gspca_dev->last_packet_type == LAST_PACKET &&
803 n >= lum_offset)
804 atomic_set(&sd->avg_lum, data[-lum_offset] +
805 data[-lum_offset + 1]);
Marton Nemeth1408b842009-11-02 08:13:21 -0300806
807 /* Start the new frame with the jpeg header */
808 /* The PAC7302 has the image rotated 90 degrees */
Jean-François Moine7532e812012-02-27 05:21:57 -0300809 gspca_frame_add(gspca_dev, FIRST_PACKET,
810 jpeg_header, sizeof jpeg_header);
Marton Nemeth1408b842009-11-02 08:13:21 -0300811 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300812 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Marton Nemeth1408b842009-11-02 08:13:21 -0300813}
814
Márton Németh6763cc02009-11-09 07:10:46 -0300815#ifdef CONFIG_VIDEO_ADV_DEBUG
816static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
817 struct v4l2_dbg_register *reg)
818{
Jean-François Moineae251e62012-02-27 05:15:12 -0300819 u8 index;
820 u8 value;
Márton Németh6763cc02009-11-09 07:10:46 -0300821
Hans de Goede895d4642012-04-28 10:31:17 -0300822 /*
823 * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
824 * long on the USB bus)
825 */
Márton Németh6763cc02009-11-09 07:10:46 -0300826 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
827 reg->match.addr == 0 &&
828 (reg->reg < 0x000000ff) &&
829 (reg->val <= 0x000000ff)
830 ) {
831 /* Currently writing to page 0 is only supported. */
832 /* reg_w() only supports 8bit index */
Jean-François Moineae251e62012-02-27 05:15:12 -0300833 index = reg->reg;
834 value = reg->val;
Márton Németh6763cc02009-11-09 07:10:46 -0300835
Hans de Goede895d4642012-04-28 10:31:17 -0300836 /*
837 * Note that there shall be no access to other page
838 * by any other function between the page switch and
839 * the actual register write.
840 */
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300841 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
842 reg_w(gspca_dev, index, value);
Márton Németh6763cc02009-11-09 07:10:46 -0300843
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300844 reg_w(gspca_dev, 0xdc, 0x01);
Márton Németh6763cc02009-11-09 07:10:46 -0300845 }
Jean-Francois Moinebe927be2010-01-13 15:09:14 -0300846 return gspca_dev->usb_err;
Márton Németh6763cc02009-11-09 07:10:46 -0300847}
848
849static int sd_chip_ident(struct gspca_dev *gspca_dev,
850 struct v4l2_dbg_chip_ident *chip)
851{
852 int ret = -EINVAL;
853
854 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
855 chip->match.addr == 0) {
856 chip->revision = 0;
857 chip->ident = V4L2_IDENT_UNKNOWN;
858 ret = 0;
859 }
860 return ret;
861}
862#endif
863
Jean-François Moine28566432010-10-01 07:33:26 -0300864#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300865static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
866 u8 *data, /* interrupt packet data */
867 int len) /* interrput packet length */
868{
869 int ret = -EINVAL;
870 u8 data0, data1;
871
872 if (len == 2) {
873 data0 = data[0];
874 data1 = data[1];
875 if ((data0 == 0x00 && data1 == 0x11) ||
876 (data0 == 0x22 && data1 == 0x33) ||
877 (data0 == 0x44 && data1 == 0x55) ||
878 (data0 == 0x66 && data1 == 0x77) ||
879 (data0 == 0x88 && data1 == 0x99) ||
880 (data0 == 0xaa && data1 == 0xbb) ||
881 (data0 == 0xcc && data1 == 0xdd) ||
882 (data0 == 0xee && data1 == 0xff)) {
883 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
884 input_sync(gspca_dev->input_dev);
885 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
886 input_sync(gspca_dev->input_dev);
887 ret = 0;
888 }
889 }
890
891 return ret;
892}
893#endif
894
Marton Nemeth1408b842009-11-02 08:13:21 -0300895/* sub-driver description for pac7302 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300896static const struct sd_desc sd_desc = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300897 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300898 .config = sd_config,
899 .init = sd_init,
Hans de Goede74233cd2012-05-14 11:16:09 -0300900 .init_controls = sd_init_controls,
Marton Nemeth1408b842009-11-02 08:13:21 -0300901 .start = sd_start,
902 .stopN = sd_stopN,
903 .stop0 = sd_stop0,
904 .pkt_scan = sd_pkt_scan,
905 .dq_callback = do_autogain,
Márton Németh6763cc02009-11-09 07:10:46 -0300906#ifdef CONFIG_VIDEO_ADV_DEBUG
907 .set_register = sd_dbg_s_register,
908 .get_chip_ident = sd_chip_ident,
909#endif
Jean-François Moine28566432010-10-01 07:33:26 -0300910#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Márton Némethaed6f1b2010-01-28 16:33:38 -0300911 .int_pkt_scan = sd_int_pkt_scan,
912#endif
Marton Nemeth1408b842009-11-02 08:13:21 -0300913};
914
915/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300916static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300917 {USB_DEVICE(0x06f8, 0x3009)},
Jean-François Moinedd32f982012-02-27 04:58:59 -0300918 {USB_DEVICE(0x06f8, 0x301b)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300919 {USB_DEVICE(0x093a, 0x2620)},
920 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moinefe2b6032009-11-26 14:28:48 -0300921 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
922 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
Márton Németh4e6aeef2010-06-14 17:21:37 -0300923 {USB_DEVICE(0x093a, 0x2625)},
Marton Nemeth1408b842009-11-02 08:13:21 -0300924 {USB_DEVICE(0x093a, 0x2626)},
Jozsef Marton5b843252012-05-15 12:05:36 -0300925 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300926 {USB_DEVICE(0x093a, 0x2628)},
Jean-Francois Moinec4322bf2009-12-02 07:04:35 -0300927 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
Marton Nemeth1408b842009-11-02 08:13:21 -0300928 {USB_DEVICE(0x093a, 0x262a)},
929 {USB_DEVICE(0x093a, 0x262c)},
Hans de Goede4d6454d2011-12-30 19:15:53 -0300930 {USB_DEVICE(0x145f, 0x013c)},
Frank Schäfer97d2fbf2012-09-09 15:02:19 -0300931 {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */
Marton Nemeth1408b842009-11-02 08:13:21 -0300932 {}
933};
934MODULE_DEVICE_TABLE(usb, device_table);
935
936/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300937static int sd_probe(struct usb_interface *intf,
Marton Nemeth1408b842009-11-02 08:13:21 -0300938 const struct usb_device_id *id)
939{
940 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
941 THIS_MODULE);
942}
943
944static struct usb_driver sd_driver = {
Jean-François Moineae251e62012-02-27 05:15:12 -0300945 .name = KBUILD_MODNAME,
Marton Nemeth1408b842009-11-02 08:13:21 -0300946 .id_table = device_table,
947 .probe = sd_probe,
948 .disconnect = gspca_disconnect,
949#ifdef CONFIG_PM
950 .suspend = gspca_suspend,
951 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300952 .reset_resume = gspca_resume,
Marton Nemeth1408b842009-11-02 08:13:21 -0300953#endif
954};
955
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800956module_usb_driver(sd_driver);