blob: 041dffcb57671ec1696edbfb64914261672834c7 [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
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052#define MODULE_NAME "pac7311"
53
Hans de Goede32ea3e42010-01-29 11:04:19 -030054#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055#include "gspca.h"
56
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030057MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
58MODULE_DESCRIPTION("Pixart PAC7311");
59MODULE_LICENSE("GPL");
60
Marton Nemeth1408b842009-11-02 08:13:21 -030061/* specific webcam descriptor for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030062struct sd {
63 struct gspca_dev gspca_dev; /* !! must be the first item */
64
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030065 unsigned char contrast;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030066 unsigned char gain;
67 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030069 __u8 hflip;
70 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030071
Hans de Goede327c4ab2008-09-03 17:12:14 -030072 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030073 u8 autogain_ignore_frames;
74
75 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030076};
77
78/* V4L2 controls supported by the driver */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
80static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030083static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030087static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091
Marton Nemeth7e64dc42009-12-30 09:12:41 -030092static const struct ctrl sd_ctrls[] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -030093/* This control is for both the 7302 and the 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030094 {
95 {
96 .id = V4L2_CID_CONTRAST,
97 .type = V4L2_CTRL_TYPE_INTEGER,
98 .name = "Contrast",
99 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300100#define CONTRAST_MAX 255
101 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300102 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300103#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300104 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300105 },
106 .set = sd_setcontrast,
107 .get = sd_getcontrast,
108 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300109/* All controls below are for both the 7302 and the 7311 */
110 {
111 {
112 .id = V4L2_CID_GAIN,
113 .type = V4L2_CTRL_TYPE_INTEGER,
114 .name = "Gain",
115 .minimum = 0,
116#define GAIN_MAX 255
117 .maximum = GAIN_MAX,
118 .step = 1,
119#define GAIN_DEF 127
120#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
121 .default_value = GAIN_DEF,
122 },
123 .set = sd_setgain,
124 .get = sd_getgain,
125 },
126 {
127 {
128 .id = V4L2_CID_EXPOSURE,
129 .type = V4L2_CTRL_TYPE_INTEGER,
130 .name = "Exposure",
131 .minimum = 0,
132#define EXPOSURE_MAX 255
133 .maximum = EXPOSURE_MAX,
134 .step = 1,
135#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
136#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
137 .default_value = EXPOSURE_DEF,
138 },
139 .set = sd_setexposure,
140 .get = sd_getexposure,
141 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142 {
143 {
144 .id = V4L2_CID_AUTOGAIN,
145 .type = V4L2_CTRL_TYPE_BOOLEAN,
146 .name = "Auto Gain",
147 .minimum = 0,
148 .maximum = 1,
149 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300150#define AUTOGAIN_DEF 1
151 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152 },
153 .set = sd_setautogain,
154 .get = sd_getautogain,
155 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300156 {
157 {
158 .id = V4L2_CID_HFLIP,
159 .type = V4L2_CTRL_TYPE_BOOLEAN,
160 .name = "Mirror",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
164#define HFLIP_DEF 0
165 .default_value = HFLIP_DEF,
166 },
167 .set = sd_sethflip,
168 .get = sd_gethflip,
169 },
170 {
171 {
172 .id = V4L2_CID_VFLIP,
173 .type = V4L2_CTRL_TYPE_BOOLEAN,
174 .name = "Vflip",
175 .minimum = 0,
176 .maximum = 1,
177 .step = 1,
178#define VFLIP_DEF 0
179 .default_value = VFLIP_DEF,
180 },
181 .set = sd_setvflip,
182 .get = sd_getvflip,
183 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300184};
185
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300186static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300187 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300188 .bytesperline = 160,
189 .sizeimage = 160 * 120 * 3 / 8 + 590,
190 .colorspace = V4L2_COLORSPACE_JPEG,
191 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300192 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300193 .bytesperline = 320,
194 .sizeimage = 320 * 240 * 3 / 8 + 590,
195 .colorspace = V4L2_COLORSPACE_JPEG,
196 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300197 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300198 .bytesperline = 640,
199 .sizeimage = 640 * 480 * 3 / 8 + 590,
200 .colorspace = V4L2_COLORSPACE_JPEG,
201 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300202};
203
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300204#define LOAD_PAGE4 254
205#define END_OF_SEQUENCE 0
206
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300207/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300208static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300209 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
210 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
211 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300212 0xff, 0x04,
213 0x27, 0x80,
214 0x28, 0xca,
215 0x29, 0x53,
216 0x2a, 0x0e,
217 0xff, 0x01,
218 0x3e, 0x20,
219};
220
221static const __u8 start_7311[] = {
222/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300223 0xff, 1, 0x01, /* page 1 */
224 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300225 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
226 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
227 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300230 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300231 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
232 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
233 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
234 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
235 0xd0, 0xff,
236 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
237 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
238 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
239 0x18, 0x20,
240 0x96, 3, 0x01, 0x08, 0x04,
241 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
242 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
243 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300244 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300245 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300246 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300247 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300248};
249
Marton Nemeth1408b842009-11-02 08:13:21 -0300250#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300251/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300252static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300253 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
254 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
255 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
257 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300258 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
259 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
260};
261
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300262static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300263 __u8 index,
264 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300266 int ret;
267
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300268 if (gspca_dev->usb_err < 0)
269 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300270 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300271 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300272 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300273 0, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300275 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300276 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300277 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300278 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300279 err("reg_w_buf() failed index 0x%02x, error %d",
280 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300281 gspca_dev->usb_err = ret;
282 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300283}
284
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300286static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300287 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300288 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300289{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300290 int ret;
291
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300292 if (gspca_dev->usb_err < 0)
293 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300294 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300295 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300296 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300297 0, /* request */
298 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300299 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300300 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300301 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300302 err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
303 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300304 gspca_dev->usb_err = ret;
305 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300306}
307
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300308static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300309 const __u8 *seq, int len)
310{
311 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300312 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300313 seq += 2;
314 }
315}
316
317/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300318static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300319 const __u8 *page, int len)
320{
321 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300322 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300323
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300324 if (gspca_dev->usb_err < 0)
325 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300326 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300327 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300328 continue;
329 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300330 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300331 usb_sndctrlpipe(gspca_dev->dev, 0),
332 0, /* request */
333 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
334 0, index, gspca_dev->usb_buf, 1,
335 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300336 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300337 err("reg_w_page() failed index 0x%02x, "
338 "value 0x%02x, error %d",
339 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300340 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300341 break;
342 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300343 }
344}
345
346/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300347static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300348 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300349 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300350{
351 int index, len;
352
353 for (;;) {
354 index = *seq++;
355 len = *seq++;
356 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300357 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300358 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300359 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300360 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300361 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300362 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300363 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 PDEBUG(D_ERR|D_STREAM,
365 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300366 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300367 }
368 while (len > 0) {
369 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300370 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300371 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300372 seq += len;
373 break;
374 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300375 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300376 seq += 8;
377 index += 8;
378 len -= 8;
379 }
380 }
381 }
382 /* not reached */
383}
384
Marton Nemeth1408b842009-11-02 08:13:21 -0300385/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300386static int sd_config(struct gspca_dev *gspca_dev,
387 const struct usb_device_id *id)
388{
389 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300390 struct cam *cam;
391
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300392 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300393
Marton Nemeth1408b842009-11-02 08:13:21 -0300394 PDEBUG(D_CONF, "Find Sensor PAC7311");
395 cam->cam_mode = vga_mode;
396 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300398 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300399 sd->gain = GAIN_DEF;
400 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300401 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300402 sd->hflip = HFLIP_DEF;
403 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404 return 0;
405}
406
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300407/* This function is used by pac7311 only */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300408static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409{
410 struct sd *sd = (struct sd *) gspca_dev;
411
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300412 reg_w(gspca_dev, 0xff, 0x04);
413 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300415 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416}
417
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300418static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300419{
420 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300421 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300422
Marton Nemeth1408b842009-11-02 08:13:21 -0300423 if (gain < 1)
424 gain = 1;
425 else if (gain > 245)
426 gain = 245;
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300427 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
428 reg_w(gspca_dev, 0x0e, 0x00);
429 reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300430
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300431 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300432 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300433}
434
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300435static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300436{
437 struct sd *sd = (struct sd *) gspca_dev;
438 __u8 reg;
439
440 /* register 2 of frame 3/4 contains the clock divider configuring the
441 no fps according to the formula: 60 / reg. sd->exposure is the
442 desired exposure time in ms. */
443 reg = 120 * sd->exposure / 1000;
444 if (reg < 2)
445 reg = 2;
446 else if (reg > 63)
447 reg = 63;
448
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300449 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
450 reg_w(gspca_dev, 0x02, reg);
451
Marton Nemeth1408b842009-11-02 08:13:21 -0300452 /* Page 1 register 8 must always be 0x08 except when not in
453 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300454 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300455 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300456 reg <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300457 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300458 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300459 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300460 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300461
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300462 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300463 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300464}
465
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300466static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300467{
468 struct sd *sd = (struct sd *) gspca_dev;
469 __u8 data;
470
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300471 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300472 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300473 reg_w(gspca_dev, 0x21, data);
474
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300475 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300476 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300477}
478
Marton Nemeth1408b842009-11-02 08:13:21 -0300479/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300480static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300481{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300482 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
483 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484}
485
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300486static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300488 struct sd *sd = (struct sd *) gspca_dev;
489
Hans de Goede327c4ab2008-09-03 17:12:14 -0300490 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300492 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300493 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300494 setcontrast(gspca_dev);
495 setgain(gspca_dev);
496 setexposure(gspca_dev);
497 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498
499 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300500 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300501 case 2: /* 160x120 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300502 reg_w(gspca_dev, 0xff, 0x01);
503 reg_w(gspca_dev, 0x17, 0x20);
504 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300506 case 1: /* 320x240 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300507 reg_w(gspca_dev, 0xff, 0x01);
508 reg_w(gspca_dev, 0x17, 0x30);
509 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510 break;
511 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300512 reg_w(gspca_dev, 0xff, 0x01);
513 reg_w(gspca_dev, 0x17, 0x00);
514 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515 break;
516 }
517
Hans de Goede327c4ab2008-09-03 17:12:14 -0300518 sd->sof_read = 0;
519 sd->autogain_ignore_frames = 0;
520 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300521
522 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300523 reg_w(gspca_dev, 0xff, 0x01);
524 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300525
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300526 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527}
528
529static void sd_stopN(struct gspca_dev *gspca_dev)
530{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300531 reg_w(gspca_dev, 0xff, 0x04);
532 reg_w(gspca_dev, 0x27, 0x80);
533 reg_w(gspca_dev, 0x28, 0xca);
534 reg_w(gspca_dev, 0x29, 0x53);
535 reg_w(gspca_dev, 0x2a, 0x0e);
536 reg_w(gspca_dev, 0xff, 0x01);
537 reg_w(gspca_dev, 0x3e, 0x20);
538 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
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 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541}
542
Marton Nemeth1408b842009-11-02 08:13:21 -0300543/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544static void sd_stop0(struct gspca_dev *gspca_dev)
545{
546}
547
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300548/* Include pac common sof detection functions */
549#include "pac_common.h"
550
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300551static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300553 struct sd *sd = (struct sd *) gspca_dev;
554 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300555 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300556
557 if (avg_lum == -1)
558 return;
559
Marton Nemeth1408b842009-11-02 08:13:21 -0300560 desired_lum = 200;
561 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300562
563 if (sd->autogain_ignore_frames > 0)
564 sd->autogain_ignore_frames--;
565 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300566 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300567 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568}
569
Marton Nemeth56f6f552009-10-04 13:58:19 -0300570/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300571static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300572 0xff, 0xd8, /* SOI: Start of Image */
573
574 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
575 0x00, 0x11, /* length = 17 bytes (including this length field) */
576 0x08 /* Precision: 8 */
577 /* 2 bytes is placed here: number of image lines */
578 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300579};
580
Marton Nemeth56f6f552009-10-04 13:58:19 -0300581/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300582static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300583 0x03, /* Number of image components: 3 */
584 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
585 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
586 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
587
588 0xff, 0xda, /* SOS: Start Of Scan */
589 0x00, 0x0c, /* length = 12 bytes (including this length field) */
590 0x03, /* number of components: 3 */
591 0x01, 0x00, /* selector 1, table 0x00 */
592 0x02, 0x11, /* selector 2, table 0x11 */
593 0x03, 0x11, /* selector 3, table 0x11 */
594 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
595 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300596};
597
Marton Nemethcc409c02009-11-02 08:09:34 -0300598static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300599 __u16 lines, __u16 samples_per_line)
600{
601 unsigned char tmpbuf[4];
602
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300603 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300604 pac_jpeg_header1, sizeof(pac_jpeg_header1));
605
606 tmpbuf[0] = lines >> 8;
607 tmpbuf[1] = lines & 0xff;
608 tmpbuf[2] = samples_per_line >> 8;
609 tmpbuf[3] = samples_per_line & 0xff;
610
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300611 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300612 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300613 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300614 pac_jpeg_header2, sizeof(pac_jpeg_header2));
615}
616
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300617/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300618static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300619 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620 int len) /* iso packet length */
621{
622 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300623 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300624 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300625
Marton Nemetha6b69e42009-11-02 08:05:51 -0300626 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300627 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300628 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300629
Marton Nemeth1408b842009-11-02 08:13:21 -0300630 /* 6 bytes after the FF D9 EOF marker a number of lumination
631 bytes are send corresponding to different parts of the
632 image, the 14th and 15th byte after the EOF seem to
633 correspond to the center of the image */
634 lum_offset = 24 + sizeof pac_sof_marker;
635 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300636
637 /* Finish decoding current frame */
638 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
639 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300640 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300641 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300642 } else {
643 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300644 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300645 image = gspca_dev->image;
646 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300647 && image[gspca_dev->image_len - 2] == 0xff
648 && image[gspca_dev->image_len - 1] == 0xd9)
649 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300650
651 n = sof - data;
652 len -= n;
653 data = sof;
654
655 /* Get average lumination */
656 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300657 n >= lum_offset)
658 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300659 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300660 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300661 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300662
663 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300664 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300665 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300667 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300668}
669
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
671{
672 struct sd *sd = (struct sd *) gspca_dev;
673
674 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300675 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300676 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300677 }
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
Hans de Goede32ea3e42010-01-29 11:04:19 -0300792#ifdef CONFIG_INPUT
793static 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,
Hans de Goede32ea3e42010-01-29 11:04:19 -0300835#ifdef CONFIG_INPUT
836 .int_pkt_scan = sd_int_pkt_scan,
837#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838};
839
840/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300841static const struct usb_device_id device_table[] __devinitconst = {
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 -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300853static int __devinit 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);