blob: 76989d7cab59ef41fb0bb6a4e6d443f35aebaf09 [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) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300279 PDEBUG(D_ERR, "reg_w_buf(): "
280 "Failed to write registers to index 0x%x, error %i",
281 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300282 gspca_dev->usb_err = ret;
283 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300284}
285
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300286
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300287static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300288 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300289 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300291 int ret;
292
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300293 if (gspca_dev->usb_err < 0)
294 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300295 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300296 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300297 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300298 0, /* request */
299 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300300 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300301 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300302 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300303 PDEBUG(D_ERR, "reg_w(): "
304 "Failed to write register to index 0x%x, value 0x%x, error %i",
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) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300339 PDEBUG(D_ERR, "reg_w_page(): "
340 "Failed to write register to index 0x%x, "
341 "value 0x%x, error %i",
342 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300343 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300344 break;
345 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300346 }
347}
348
349/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300350static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300351 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300352 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300353{
354 int index, len;
355
356 for (;;) {
357 index = *seq++;
358 len = *seq++;
359 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300360 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300361 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300362 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300363 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300365 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300366 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300367 PDEBUG(D_ERR|D_STREAM,
368 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300369 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300370 }
371 while (len > 0) {
372 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300373 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300374 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300375 seq += len;
376 break;
377 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300378 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300379 seq += 8;
380 index += 8;
381 len -= 8;
382 }
383 }
384 }
385 /* not reached */
386}
387
Marton Nemeth1408b842009-11-02 08:13:21 -0300388/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300389static int sd_config(struct gspca_dev *gspca_dev,
390 const struct usb_device_id *id)
391{
392 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 struct cam *cam;
394
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300395 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300396
Marton Nemeth1408b842009-11-02 08:13:21 -0300397 PDEBUG(D_CONF, "Find Sensor PAC7311");
398 cam->cam_mode = vga_mode;
399 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300401 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300402 sd->gain = GAIN_DEF;
403 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300404 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300405 sd->hflip = HFLIP_DEF;
406 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 return 0;
408}
409
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300410/* This function is used by pac7311 only */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300411static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412{
413 struct sd *sd = (struct sd *) gspca_dev;
414
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300415 reg_w(gspca_dev, 0xff, 0x04);
416 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300418 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419}
420
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300421static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300422{
423 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300424 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300425
Marton Nemeth1408b842009-11-02 08:13:21 -0300426 if (gain < 1)
427 gain = 1;
428 else if (gain > 245)
429 gain = 245;
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300430 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
431 reg_w(gspca_dev, 0x0e, 0x00);
432 reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300433
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300434 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300435 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300436}
437
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300438static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300439{
440 struct sd *sd = (struct sd *) gspca_dev;
441 __u8 reg;
442
443 /* register 2 of frame 3/4 contains the clock divider configuring the
444 no fps according to the formula: 60 / reg. sd->exposure is the
445 desired exposure time in ms. */
446 reg = 120 * sd->exposure / 1000;
447 if (reg < 2)
448 reg = 2;
449 else if (reg > 63)
450 reg = 63;
451
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300452 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
453 reg_w(gspca_dev, 0x02, reg);
454
Marton Nemeth1408b842009-11-02 08:13:21 -0300455 /* Page 1 register 8 must always be 0x08 except when not in
456 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300457 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300458 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300459 reg <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300460 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300461 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300462 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300463 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300464
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300465 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300466 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300467}
468
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300469static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300470{
471 struct sd *sd = (struct sd *) gspca_dev;
472 __u8 data;
473
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300474 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300475 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300476 reg_w(gspca_dev, 0x21, data);
477
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300478 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300479 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300480}
481
Marton Nemeth1408b842009-11-02 08:13:21 -0300482/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300483static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300485 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
486 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487}
488
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300489static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300490{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300491 struct sd *sd = (struct sd *) gspca_dev;
492
Hans de Goede327c4ab2008-09-03 17:12:14 -0300493 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300495 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300496 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300497 setcontrast(gspca_dev);
498 setgain(gspca_dev);
499 setexposure(gspca_dev);
500 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501
502 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300503 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300504 case 2: /* 160x120 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300505 reg_w(gspca_dev, 0xff, 0x01);
506 reg_w(gspca_dev, 0x17, 0x20);
507 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300509 case 1: /* 320x240 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300510 reg_w(gspca_dev, 0xff, 0x01);
511 reg_w(gspca_dev, 0x17, 0x30);
512 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 break;
514 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300515 reg_w(gspca_dev, 0xff, 0x01);
516 reg_w(gspca_dev, 0x17, 0x00);
517 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300518 break;
519 }
520
Hans de Goede327c4ab2008-09-03 17:12:14 -0300521 sd->sof_read = 0;
522 sd->autogain_ignore_frames = 0;
523 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300524
525 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300526 reg_w(gspca_dev, 0xff, 0x01);
527 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300528
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300529 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530}
531
532static void sd_stopN(struct gspca_dev *gspca_dev)
533{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300534 reg_w(gspca_dev, 0xff, 0x04);
535 reg_w(gspca_dev, 0x27, 0x80);
536 reg_w(gspca_dev, 0x28, 0xca);
537 reg_w(gspca_dev, 0x29, 0x53);
538 reg_w(gspca_dev, 0x2a, 0x0e);
539 reg_w(gspca_dev, 0xff, 0x01);
540 reg_w(gspca_dev, 0x3e, 0x20);
541 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
542 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
543 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544}
545
Marton Nemeth1408b842009-11-02 08:13:21 -0300546/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547static void sd_stop0(struct gspca_dev *gspca_dev)
548{
549}
550
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300551/* Include pac common sof detection functions */
552#include "pac_common.h"
553
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300554static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300556 struct sd *sd = (struct sd *) gspca_dev;
557 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300558 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300559
560 if (avg_lum == -1)
561 return;
562
Marton Nemeth1408b842009-11-02 08:13:21 -0300563 desired_lum = 200;
564 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300565
566 if (sd->autogain_ignore_frames > 0)
567 sd->autogain_ignore_frames--;
568 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300569 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300570 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571}
572
Marton Nemeth56f6f552009-10-04 13:58:19 -0300573/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300574static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300575 0xff, 0xd8, /* SOI: Start of Image */
576
577 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
578 0x00, 0x11, /* length = 17 bytes (including this length field) */
579 0x08 /* Precision: 8 */
580 /* 2 bytes is placed here: number of image lines */
581 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300582};
583
Marton Nemeth56f6f552009-10-04 13:58:19 -0300584/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300585static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300586 0x03, /* Number of image components: 3 */
587 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
588 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
589 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
590
591 0xff, 0xda, /* SOS: Start Of Scan */
592 0x00, 0x0c, /* length = 12 bytes (including this length field) */
593 0x03, /* number of components: 3 */
594 0x01, 0x00, /* selector 1, table 0x00 */
595 0x02, 0x11, /* selector 2, table 0x11 */
596 0x03, 0x11, /* selector 3, table 0x11 */
597 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
598 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300599};
600
Marton Nemethcc409c02009-11-02 08:09:34 -0300601static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300602 __u16 lines, __u16 samples_per_line)
603{
604 unsigned char tmpbuf[4];
605
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300606 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300607 pac_jpeg_header1, sizeof(pac_jpeg_header1));
608
609 tmpbuf[0] = lines >> 8;
610 tmpbuf[1] = lines & 0xff;
611 tmpbuf[2] = samples_per_line >> 8;
612 tmpbuf[3] = samples_per_line & 0xff;
613
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300614 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300615 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300616 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300617 pac_jpeg_header2, sizeof(pac_jpeg_header2));
618}
619
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300620/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300622 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300623 int len) /* iso packet length */
624{
625 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300626 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300627 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300628
Marton Nemetha6b69e42009-11-02 08:05:51 -0300629 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300630 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300631 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300632
Marton Nemeth1408b842009-11-02 08:13:21 -0300633 /* 6 bytes after the FF D9 EOF marker a number of lumination
634 bytes are send corresponding to different parts of the
635 image, the 14th and 15th byte after the EOF seem to
636 correspond to the center of the image */
637 lum_offset = 24 + sizeof pac_sof_marker;
638 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300639
640 /* Finish decoding current frame */
641 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
642 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300643 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300644 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300645 } else {
646 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300647 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300648 image = gspca_dev->image;
649 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300650 && image[gspca_dev->image_len - 2] == 0xff
651 && image[gspca_dev->image_len - 1] == 0xd9)
652 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300653
654 n = sof - data;
655 len -= n;
656 data = sof;
657
658 /* Get average lumination */
659 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300660 n >= lum_offset)
661 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300662 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300663 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300664 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300665
666 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300667 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300668 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300669 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300670 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671}
672
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300673static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
674{
675 struct sd *sd = (struct sd *) gspca_dev;
676
677 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300678 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300679 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300680 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300681 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682}
683
684static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
685{
686 struct sd *sd = (struct sd *) gspca_dev;
687
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688 *val = sd->contrast;
689 return 0;
690}
691
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300692static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
693{
694 struct sd *sd = (struct sd *) gspca_dev;
695
696 sd->gain = val;
697 if (gspca_dev->streaming)
698 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300699 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300700}
701
702static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
703{
704 struct sd *sd = (struct sd *) gspca_dev;
705
706 *val = sd->gain;
707 return 0;
708}
709
710static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
711{
712 struct sd *sd = (struct sd *) gspca_dev;
713
714 sd->exposure = val;
715 if (gspca_dev->streaming)
716 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300717 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300718}
719
720static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
721{
722 struct sd *sd = (struct sd *) gspca_dev;
723
724 *val = sd->exposure;
725 return 0;
726}
727
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
729{
730 struct sd *sd = (struct sd *) gspca_dev;
731
732 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300733 /* when switching to autogain set defaults to make sure
734 we are on a valid point of the autogain gain /
735 exposure knee graph, and give this change time to
736 take effect before doing autogain. */
737 if (sd->autogain) {
738 sd->exposure = EXPOSURE_DEF;
739 sd->gain = GAIN_DEF;
740 if (gspca_dev->streaming) {
741 sd->autogain_ignore_frames =
742 PAC_AUTOGAIN_IGNORE_FRAMES;
743 setexposure(gspca_dev);
744 setgain(gspca_dev);
745 }
746 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300747
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300748 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749}
750
751static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
752{
753 struct sd *sd = (struct sd *) gspca_dev;
754
755 *val = sd->autogain;
756 return 0;
757}
758
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300759static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
760{
761 struct sd *sd = (struct sd *) gspca_dev;
762
763 sd->hflip = val;
764 if (gspca_dev->streaming)
765 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300766 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300767}
768
769static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
770{
771 struct sd *sd = (struct sd *) gspca_dev;
772
773 *val = sd->hflip;
774 return 0;
775}
776
777static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
778{
779 struct sd *sd = (struct sd *) gspca_dev;
780
781 sd->vflip = val;
782 if (gspca_dev->streaming)
783 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300784 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300785}
786
787static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
788{
789 struct sd *sd = (struct sd *) gspca_dev;
790
791 *val = sd->vflip;
792 return 0;
793}
794
Hans de Goede32ea3e42010-01-29 11:04:19 -0300795#ifdef CONFIG_INPUT
796static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
797 u8 *data, /* interrupt packet data */
798 int len) /* interrupt packet length */
799{
800 int ret = -EINVAL;
801 u8 data0, data1;
802
803 if (len == 2) {
804 data0 = data[0];
805 data1 = data[1];
806 if ((data0 == 0x00 && data1 == 0x11) ||
807 (data0 == 0x22 && data1 == 0x33) ||
808 (data0 == 0x44 && data1 == 0x55) ||
809 (data0 == 0x66 && data1 == 0x77) ||
810 (data0 == 0x88 && data1 == 0x99) ||
811 (data0 == 0xaa && data1 == 0xbb) ||
812 (data0 == 0xcc && data1 == 0xdd) ||
813 (data0 == 0xee && data1 == 0xff)) {
814 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
815 input_sync(gspca_dev->input_dev);
816 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
817 input_sync(gspca_dev->input_dev);
818 ret = 0;
819 }
820 }
821
822 return ret;
823}
824#endif
825
Marton Nemeth1408b842009-11-02 08:13:21 -0300826/* sub-driver description for pac7311 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300827static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828 .name = MODULE_NAME,
829 .ctrls = sd_ctrls,
830 .nctrls = ARRAY_SIZE(sd_ctrls),
831 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300832 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 .start = sd_start,
834 .stopN = sd_stopN,
835 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300837 .dq_callback = do_autogain,
Hans de Goede32ea3e42010-01-29 11:04:19 -0300838#ifdef CONFIG_INPUT
839 .int_pkt_scan = sd_int_pkt_scan,
840#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841};
842
843/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300844static const struct usb_device_id device_table[] __devinitconst = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300845 {USB_DEVICE(0x093a, 0x2600)},
846 {USB_DEVICE(0x093a, 0x2601)},
847 {USB_DEVICE(0x093a, 0x2603)},
848 {USB_DEVICE(0x093a, 0x2608)},
849 {USB_DEVICE(0x093a, 0x260e)},
850 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300851 {}
852};
853MODULE_DEVICE_TABLE(usb, device_table);
854
855/* -- device connect -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300856static int __devinit sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 const struct usb_device_id *id)
858{
859 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
860 THIS_MODULE);
861}
862
863static struct usb_driver sd_driver = {
864 .name = MODULE_NAME,
865 .id_table = device_table,
866 .probe = sd_probe,
867 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300868#ifdef CONFIG_PM
869 .suspend = gspca_suspend,
870 .resume = gspca_resume,
871#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872};
873
874/* -- module insert / remove -- */
875static int __init sd_mod_init(void)
876{
Jean-François Moine54826432010-09-13 04:53:03 -0300877 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878}
879static void __exit sd_mod_exit(void)
880{
881 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882}
883
884module_init(sd_mod_init);
885module_exit(sd_mod_exit);