blob: 7509d05dc065a1c4fdc959e699c6892bf460ee64 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
Hans de Goede327c4ab2008-09-03 17:12:14 -030022/* Some documentation about various registers as determined by trial and error.
23 When the register addresses differ between the 7202 and the 7311 the 2
24 different addresses are written as 7302addr/7311addr, when one of the 2
25 addresses is a - sign that register description is not valid for the
26 matching IC.
27
28 Register page 1:
29
30 Address Description
31 -/0x08 Unknown compressor related, must always be 8 except when not
32 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
33 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
34 bits 345 seem to toggle per color gains on/off (inverted)
35 0x78 Global control, bit 6 controls the LED (inverted)
36 -/0x80 JPEG compression ratio ? Best not touched
37
38 Register page 3/4:
39
40 Address Description
41 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
Hans de Goede038ec7c2008-09-03 17:12:18 -030042 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
Hans de Goede327c4ab2008-09-03 17:12:14 -030043 -/0x0f Master gain 1-245, low value = high gain
44 0x10/- Master gain 0-31
45 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede8a5b2e92008-09-03 17:12:17 -030047 -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
48 completely disable the analog amplification block. Set to 0x68
49 for max gain, 0x14 for minimal gain.
Hans de Goede327c4ab2008-09-03 17:12:14 -030050*/
51
Joe Perches133a9fe2011-08-21 19:56:57 -030052#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
53
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030054#define MODULE_NAME "pac7311"
55
Hans de Goede32ea3e42010-01-29 11:04:19 -030056#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030057#include "gspca.h"
58
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030059MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
60MODULE_DESCRIPTION("Pixart PAC7311");
61MODULE_LICENSE("GPL");
62
Marton Nemeth1408b842009-11-02 08:13:21 -030063/* specific webcam descriptor for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064struct sd {
65 struct gspca_dev gspca_dev; /* !! must be the first item */
66
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067 unsigned char contrast;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030068 unsigned char gain;
69 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030070 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030071 __u8 hflip;
72 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030073
Hans de Goede327c4ab2008-09-03 17:12:14 -030074 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030075 u8 autogain_ignore_frames;
76
77 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078};
79
80/* V4L2 controls supported by the driver */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030083static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030085static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030089static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
91static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093
Marton Nemeth7e64dc42009-12-30 09:12:41 -030094static const struct ctrl sd_ctrls[] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -030095/* This control is for both the 7302 and the 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030096 {
97 {
98 .id = V4L2_CID_CONTRAST,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Contrast",
101 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300102#define CONTRAST_MAX 255
103 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300105#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300106 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 },
108 .set = sd_setcontrast,
109 .get = sd_getcontrast,
110 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300111/* All controls below are for both the 7302 and the 7311 */
112 {
113 {
114 .id = V4L2_CID_GAIN,
115 .type = V4L2_CTRL_TYPE_INTEGER,
116 .name = "Gain",
117 .minimum = 0,
118#define GAIN_MAX 255
119 .maximum = GAIN_MAX,
120 .step = 1,
121#define GAIN_DEF 127
122#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
123 .default_value = GAIN_DEF,
124 },
125 .set = sd_setgain,
126 .get = sd_getgain,
127 },
128 {
129 {
130 .id = V4L2_CID_EXPOSURE,
131 .type = V4L2_CTRL_TYPE_INTEGER,
132 .name = "Exposure",
133 .minimum = 0,
134#define EXPOSURE_MAX 255
135 .maximum = EXPOSURE_MAX,
136 .step = 1,
137#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
138#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
139 .default_value = EXPOSURE_DEF,
140 },
141 .set = sd_setexposure,
142 .get = sd_getexposure,
143 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300144 {
145 {
146 .id = V4L2_CID_AUTOGAIN,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "Auto Gain",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300152#define AUTOGAIN_DEF 1
153 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300154 },
155 .set = sd_setautogain,
156 .get = sd_getautogain,
157 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300158 {
159 {
160 .id = V4L2_CID_HFLIP,
161 .type = V4L2_CTRL_TYPE_BOOLEAN,
162 .name = "Mirror",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
166#define HFLIP_DEF 0
167 .default_value = HFLIP_DEF,
168 },
169 .set = sd_sethflip,
170 .get = sd_gethflip,
171 },
172 {
173 {
174 .id = V4L2_CID_VFLIP,
175 .type = V4L2_CTRL_TYPE_BOOLEAN,
176 .name = "Vflip",
177 .minimum = 0,
178 .maximum = 1,
179 .step = 1,
180#define VFLIP_DEF 0
181 .default_value = VFLIP_DEF,
182 },
183 .set = sd_setvflip,
184 .get = sd_getvflip,
185 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300186};
187
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300188static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300189 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300190 .bytesperline = 160,
191 .sizeimage = 160 * 120 * 3 / 8 + 590,
192 .colorspace = V4L2_COLORSPACE_JPEG,
193 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300194 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300195 .bytesperline = 320,
196 .sizeimage = 320 * 240 * 3 / 8 + 590,
197 .colorspace = V4L2_COLORSPACE_JPEG,
198 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300199 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300200 .bytesperline = 640,
201 .sizeimage = 640 * 480 * 3 / 8 + 590,
202 .colorspace = V4L2_COLORSPACE_JPEG,
203 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204};
205
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300206#define LOAD_PAGE4 254
207#define END_OF_SEQUENCE 0
208
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300209/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300210static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300211 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
212 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
213 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300214 0xff, 0x04,
215 0x27, 0x80,
216 0x28, 0xca,
217 0x29, 0x53,
218 0x2a, 0x0e,
219 0xff, 0x01,
220 0x3e, 0x20,
221};
222
223static const __u8 start_7311[] = {
224/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300225 0xff, 1, 0x01, /* page 1 */
226 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300227 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
228 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
229 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300232 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300233 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
234 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
235 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
236 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
237 0xd0, 0xff,
238 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
239 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
240 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
241 0x18, 0x20,
242 0x96, 3, 0x01, 0x08, 0x04,
243 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
244 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
245 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300246 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300247 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300248 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300249 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300250};
251
Marton Nemeth1408b842009-11-02 08:13:21 -0300252#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300253/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300254static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300255 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
256 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
257 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
259 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300260 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
261 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
262};
263
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300264static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300265 __u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300266 const u8 *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300268 int ret;
269
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300270 if (gspca_dev->usb_err < 0)
271 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300272 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300273 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300274 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300275 0, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300276 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300277 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300278 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300279 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300280 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300281 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
282 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300283 gspca_dev->usb_err = ret;
284 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285}
286
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300287
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300288static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300289 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300290 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300291{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300292 int ret;
293
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300294 if (gspca_dev->usb_err < 0)
295 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300296 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300297 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300298 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300299 0, /* request */
300 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300301 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300302 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300303 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300304 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
305 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300306 gspca_dev->usb_err = ret;
307 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308}
309
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300310static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300311 const __u8 *seq, int len)
312{
313 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300314 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300315 seq += 2;
316 }
317}
318
319/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300320static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300321 const __u8 *page, int len)
322{
323 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300324 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300325
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300326 if (gspca_dev->usb_err < 0)
327 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300328 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300329 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300330 continue;
331 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300332 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300333 usb_sndctrlpipe(gspca_dev->dev, 0),
334 0, /* request */
335 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
336 0, index, gspca_dev->usb_buf, 1,
337 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300338 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300339 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
340 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300341 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300342 break;
343 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300344 }
345}
346
347/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300348static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300349 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300350 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300351{
352 int index, len;
353
354 for (;;) {
355 index = *seq++;
356 len = *seq++;
357 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300358 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300359 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300360 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300361 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300362 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300363 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300364 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300365 PDEBUG(D_ERR|D_STREAM,
366 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300367 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300368 }
369 while (len > 0) {
370 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300371 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300372 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300373 seq += len;
374 break;
375 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300376 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300377 seq += 8;
378 index += 8;
379 len -= 8;
380 }
381 }
382 }
383 /* not reached */
384}
385
Marton Nemeth1408b842009-11-02 08:13:21 -0300386/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300387static int sd_config(struct gspca_dev *gspca_dev,
388 const struct usb_device_id *id)
389{
390 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300391 struct cam *cam;
392
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300394
Marton Nemeth1408b842009-11-02 08:13:21 -0300395 PDEBUG(D_CONF, "Find Sensor PAC7311");
396 cam->cam_mode = vga_mode;
397 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300399 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300400 sd->gain = GAIN_DEF;
401 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300402 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300403 sd->hflip = HFLIP_DEF;
404 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 return 0;
406}
407
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300408/* This function is used by pac7311 only */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300409static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410{
411 struct sd *sd = (struct sd *) gspca_dev;
412
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300413 reg_w(gspca_dev, 0xff, 0x04);
414 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300416 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417}
418
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300419static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300420{
421 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300422 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423
Marton Nemeth1408b842009-11-02 08:13:21 -0300424 if (gain < 1)
425 gain = 1;
426 else if (gain > 245)
427 gain = 245;
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300428 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
429 reg_w(gspca_dev, 0x0e, 0x00);
430 reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300431
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300432 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300433 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300434}
435
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300436static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300437{
438 struct sd *sd = (struct sd *) gspca_dev;
439 __u8 reg;
440
441 /* register 2 of frame 3/4 contains the clock divider configuring the
442 no fps according to the formula: 60 / reg. sd->exposure is the
443 desired exposure time in ms. */
444 reg = 120 * sd->exposure / 1000;
445 if (reg < 2)
446 reg = 2;
447 else if (reg > 63)
448 reg = 63;
449
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300450 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
451 reg_w(gspca_dev, 0x02, reg);
452
Marton Nemeth1408b842009-11-02 08:13:21 -0300453 /* Page 1 register 8 must always be 0x08 except when not in
454 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300455 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300456 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300457 reg <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300458 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300459 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300460 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300461 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300462
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300463 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300464 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300465}
466
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300467static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300468{
469 struct sd *sd = (struct sd *) gspca_dev;
470 __u8 data;
471
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300472 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300473 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300474 reg_w(gspca_dev, 0x21, data);
475
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300476 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300477 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300478}
479
Marton Nemeth1408b842009-11-02 08:13:21 -0300480/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300481static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300483 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
484 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485}
486
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300487static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300489 struct sd *sd = (struct sd *) gspca_dev;
490
Hans de Goede327c4ab2008-09-03 17:12:14 -0300491 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300493 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300494 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300495 setcontrast(gspca_dev);
496 setgain(gspca_dev);
497 setexposure(gspca_dev);
498 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499
500 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300501 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300502 case 2: /* 160x120 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300503 reg_w(gspca_dev, 0xff, 0x01);
504 reg_w(gspca_dev, 0x17, 0x20);
505 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300507 case 1: /* 320x240 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300508 reg_w(gspca_dev, 0xff, 0x01);
509 reg_w(gspca_dev, 0x17, 0x30);
510 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 break;
512 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300513 reg_w(gspca_dev, 0xff, 0x01);
514 reg_w(gspca_dev, 0x17, 0x00);
515 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300516 break;
517 }
518
Hans de Goede327c4ab2008-09-03 17:12:14 -0300519 sd->sof_read = 0;
520 sd->autogain_ignore_frames = 0;
521 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300522
523 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300524 reg_w(gspca_dev, 0xff, 0x01);
525 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300526
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300527 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528}
529
530static void sd_stopN(struct gspca_dev *gspca_dev)
531{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300532 reg_w(gspca_dev, 0xff, 0x04);
533 reg_w(gspca_dev, 0x27, 0x80);
534 reg_w(gspca_dev, 0x28, 0xca);
535 reg_w(gspca_dev, 0x29, 0x53);
536 reg_w(gspca_dev, 0x2a, 0x0e);
537 reg_w(gspca_dev, 0xff, 0x01);
538 reg_w(gspca_dev, 0x3e, 0x20);
539 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
540 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
541 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542}
543
Marton Nemeth1408b842009-11-02 08:13:21 -0300544/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545static void sd_stop0(struct gspca_dev *gspca_dev)
546{
547}
548
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300549/* Include pac common sof detection functions */
550#include "pac_common.h"
551
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300552static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300553{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300554 struct sd *sd = (struct sd *) gspca_dev;
555 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300556 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300557
558 if (avg_lum == -1)
559 return;
560
Marton Nemeth1408b842009-11-02 08:13:21 -0300561 desired_lum = 200;
562 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300563
564 if (sd->autogain_ignore_frames > 0)
565 sd->autogain_ignore_frames--;
566 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300567 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300568 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569}
570
Marton Nemeth56f6f552009-10-04 13:58:19 -0300571/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300572static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300573 0xff, 0xd8, /* SOI: Start of Image */
574
575 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
576 0x00, 0x11, /* length = 17 bytes (including this length field) */
577 0x08 /* Precision: 8 */
578 /* 2 bytes is placed here: number of image lines */
579 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300580};
581
Marton Nemeth56f6f552009-10-04 13:58:19 -0300582/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300583static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300584 0x03, /* Number of image components: 3 */
585 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
586 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
587 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
588
589 0xff, 0xda, /* SOS: Start Of Scan */
590 0x00, 0x0c, /* length = 12 bytes (including this length field) */
591 0x03, /* number of components: 3 */
592 0x01, 0x00, /* selector 1, table 0x00 */
593 0x02, 0x11, /* selector 2, table 0x11 */
594 0x03, 0x11, /* selector 3, table 0x11 */
595 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
596 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300597};
598
Marton Nemethcc409c02009-11-02 08:09:34 -0300599static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300600 __u16 lines, __u16 samples_per_line)
601{
602 unsigned char tmpbuf[4];
603
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300604 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300605 pac_jpeg_header1, sizeof(pac_jpeg_header1));
606
607 tmpbuf[0] = lines >> 8;
608 tmpbuf[1] = lines & 0xff;
609 tmpbuf[2] = samples_per_line >> 8;
610 tmpbuf[3] = samples_per_line & 0xff;
611
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300612 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300613 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300614 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300615 pac_jpeg_header2, sizeof(pac_jpeg_header2));
616}
617
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300618/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300620 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621 int len) /* iso packet length */
622{
623 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300624 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300625 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626
Marton Nemetha6b69e42009-11-02 08:05:51 -0300627 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300628 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300629 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300630
Marton Nemeth1408b842009-11-02 08:13:21 -0300631 /* 6 bytes after the FF D9 EOF marker a number of lumination
632 bytes are send corresponding to different parts of the
633 image, the 14th and 15th byte after the EOF seem to
634 correspond to the center of the image */
635 lum_offset = 24 + sizeof pac_sof_marker;
636 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300637
638 /* Finish decoding current frame */
639 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
640 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300641 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300642 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300643 } else {
644 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300645 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300646 image = gspca_dev->image;
647 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300648 && image[gspca_dev->image_len - 2] == 0xff
649 && image[gspca_dev->image_len - 1] == 0xd9)
650 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300651
652 n = sof - data;
653 len -= n;
654 data = sof;
655
656 /* Get average lumination */
657 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300658 n >= lum_offset)
659 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300660 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300661 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300662 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300663
664 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300665 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300666 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300668 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300669}
670
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
672{
673 struct sd *sd = (struct sd *) gspca_dev;
674
675 sd->contrast = val;
Jean-François Moine780e3122010-10-19 04:29:10 -0300676 if (gspca_dev->streaming)
Marton Nemeth1408b842009-11-02 08:13:21 -0300677 setcontrast(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300678 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679}
680
681static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
682{
683 struct sd *sd = (struct sd *) gspca_dev;
684
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300685 *val = sd->contrast;
686 return 0;
687}
688
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300689static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
693 sd->gain = val;
694 if (gspca_dev->streaming)
695 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300696 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300697}
698
699static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
700{
701 struct sd *sd = (struct sd *) gspca_dev;
702
703 *val = sd->gain;
704 return 0;
705}
706
707static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 sd->exposure = val;
712 if (gspca_dev->streaming)
713 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300714 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300715}
716
717static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
718{
719 struct sd *sd = (struct sd *) gspca_dev;
720
721 *val = sd->exposure;
722 return 0;
723}
724
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
726{
727 struct sd *sd = (struct sd *) gspca_dev;
728
729 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300730 /* when switching to autogain set defaults to make sure
731 we are on a valid point of the autogain gain /
732 exposure knee graph, and give this change time to
733 take effect before doing autogain. */
734 if (sd->autogain) {
735 sd->exposure = EXPOSURE_DEF;
736 sd->gain = GAIN_DEF;
737 if (gspca_dev->streaming) {
738 sd->autogain_ignore_frames =
739 PAC_AUTOGAIN_IGNORE_FRAMES;
740 setexposure(gspca_dev);
741 setgain(gspca_dev);
742 }
743 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300744
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300745 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300746}
747
748static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
749{
750 struct sd *sd = (struct sd *) gspca_dev;
751
752 *val = sd->autogain;
753 return 0;
754}
755
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300756static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
757{
758 struct sd *sd = (struct sd *) gspca_dev;
759
760 sd->hflip = val;
761 if (gspca_dev->streaming)
762 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300763 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300764}
765
766static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
767{
768 struct sd *sd = (struct sd *) gspca_dev;
769
770 *val = sd->hflip;
771 return 0;
772}
773
774static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
775{
776 struct sd *sd = (struct sd *) gspca_dev;
777
778 sd->vflip = val;
779 if (gspca_dev->streaming)
780 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300781 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300782}
783
784static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
785{
786 struct sd *sd = (struct sd *) gspca_dev;
787
788 *val = sd->vflip;
789 return 0;
790}
791
Jean-François Moine28566432010-10-01 07:33:26 -0300792#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300793static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
794 u8 *data, /* interrupt packet data */
795 int len) /* interrupt packet length */
796{
797 int ret = -EINVAL;
798 u8 data0, data1;
799
800 if (len == 2) {
801 data0 = data[0];
802 data1 = data[1];
803 if ((data0 == 0x00 && data1 == 0x11) ||
804 (data0 == 0x22 && data1 == 0x33) ||
805 (data0 == 0x44 && data1 == 0x55) ||
806 (data0 == 0x66 && data1 == 0x77) ||
807 (data0 == 0x88 && data1 == 0x99) ||
808 (data0 == 0xaa && data1 == 0xbb) ||
809 (data0 == 0xcc && data1 == 0xdd) ||
810 (data0 == 0xee && data1 == 0xff)) {
811 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
812 input_sync(gspca_dev->input_dev);
813 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
814 input_sync(gspca_dev->input_dev);
815 ret = 0;
816 }
817 }
818
819 return ret;
820}
821#endif
822
Marton Nemeth1408b842009-11-02 08:13:21 -0300823/* sub-driver description for pac7311 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300824static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300825 .name = MODULE_NAME,
826 .ctrls = sd_ctrls,
827 .nctrls = ARRAY_SIZE(sd_ctrls),
828 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300829 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830 .start = sd_start,
831 .stopN = sd_stopN,
832 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300834 .dq_callback = do_autogain,
Jean-François Moine28566432010-10-01 07:33:26 -0300835#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300836 .int_pkt_scan = sd_int_pkt_scan,
837#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838};
839
840/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300841static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300842 {USB_DEVICE(0x093a, 0x2600)},
843 {USB_DEVICE(0x093a, 0x2601)},
844 {USB_DEVICE(0x093a, 0x2603)},
845 {USB_DEVICE(0x093a, 0x2608)},
846 {USB_DEVICE(0x093a, 0x260e)},
847 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300848 {}
849};
850MODULE_DEVICE_TABLE(usb, device_table);
851
852/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300853static int sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 const struct usb_device_id *id)
855{
856 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
857 THIS_MODULE);
858}
859
860static struct usb_driver sd_driver = {
861 .name = MODULE_NAME,
862 .id_table = device_table,
863 .probe = sd_probe,
864 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300865#ifdef CONFIG_PM
866 .suspend = gspca_suspend,
867 .resume = gspca_resume,
868#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869};
870
871/* -- module insert / remove -- */
872static int __init sd_mod_init(void)
873{
Jean-François Moine54826432010-09-13 04:53:03 -0300874 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875}
876static void __exit sd_mod_exit(void)
877{
878 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300879}
880
881module_init(sd_mod_init);
882module_exit(sd_mod_exit);