blob: 5568c41a296c179d25b696cf0ec1cf6e5477e5f4 [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
Jean-François Moineb192ca92010-06-27 03:08:19 -0300633 image = gspca_dev->image;
634 if (image == NULL) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300635 gspca_dev->last_packet_type = DISCARD_PACKET;
636 return;
637 }
638
Marton Nemeth1408b842009-11-02 08:13:21 -0300639 /* 6 bytes after the FF D9 EOF marker a number of lumination
640 bytes are send corresponding to different parts of the
641 image, the 14th and 15th byte after the EOF seem to
642 correspond to the center of the image */
643 lum_offset = 24 + sizeof pac_sof_marker;
644 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300645
646 /* Finish decoding current frame */
647 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
648 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300649 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300650 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300651 } else {
652 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300653 }
Jean-François Moineb192ca92010-06-27 03:08:19 -0300654 if (gspca_dev->last_packet_type != DISCARD_PACKET
655 && image[gspca_dev->image_len - 2] == 0xff
656 && image[gspca_dev->image_len - 1] == 0xd9)
657 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300658
659 n = sof - data;
660 len -= n;
661 data = sof;
662
663 /* Get average lumination */
664 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300665 n >= lum_offset)
666 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300667 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300668 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300669 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300670
671 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300672 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300673 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300675 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676}
677
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
679{
680 struct sd *sd = (struct sd *) gspca_dev;
681
682 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300683 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300684 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300685 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300686 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687}
688
689static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693 *val = sd->contrast;
694 return 0;
695}
696
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300697static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
698{
699 struct sd *sd = (struct sd *) gspca_dev;
700
701 sd->gain = val;
702 if (gspca_dev->streaming)
703 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300704 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300705}
706
707static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 *val = sd->gain;
712 return 0;
713}
714
715static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
716{
717 struct sd *sd = (struct sd *) gspca_dev;
718
719 sd->exposure = val;
720 if (gspca_dev->streaming)
721 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300722 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300723}
724
725static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
726{
727 struct sd *sd = (struct sd *) gspca_dev;
728
729 *val = sd->exposure;
730 return 0;
731}
732
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
734{
735 struct sd *sd = (struct sd *) gspca_dev;
736
737 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300738 /* when switching to autogain set defaults to make sure
739 we are on a valid point of the autogain gain /
740 exposure knee graph, and give this change time to
741 take effect before doing autogain. */
742 if (sd->autogain) {
743 sd->exposure = EXPOSURE_DEF;
744 sd->gain = GAIN_DEF;
745 if (gspca_dev->streaming) {
746 sd->autogain_ignore_frames =
747 PAC_AUTOGAIN_IGNORE_FRAMES;
748 setexposure(gspca_dev);
749 setgain(gspca_dev);
750 }
751 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300752
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300753 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754}
755
756static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
757{
758 struct sd *sd = (struct sd *) gspca_dev;
759
760 *val = sd->autogain;
761 return 0;
762}
763
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300764static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
765{
766 struct sd *sd = (struct sd *) gspca_dev;
767
768 sd->hflip = val;
769 if (gspca_dev->streaming)
770 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300771 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300772}
773
774static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
775{
776 struct sd *sd = (struct sd *) gspca_dev;
777
778 *val = sd->hflip;
779 return 0;
780}
781
782static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
783{
784 struct sd *sd = (struct sd *) gspca_dev;
785
786 sd->vflip = val;
787 if (gspca_dev->streaming)
788 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300789 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300790}
791
792static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795
796 *val = sd->vflip;
797 return 0;
798}
799
Hans de Goede32ea3e42010-01-29 11:04:19 -0300800#ifdef CONFIG_INPUT
801static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
802 u8 *data, /* interrupt packet data */
803 int len) /* interrupt packet length */
804{
805 int ret = -EINVAL;
806 u8 data0, data1;
807
808 if (len == 2) {
809 data0 = data[0];
810 data1 = data[1];
811 if ((data0 == 0x00 && data1 == 0x11) ||
812 (data0 == 0x22 && data1 == 0x33) ||
813 (data0 == 0x44 && data1 == 0x55) ||
814 (data0 == 0x66 && data1 == 0x77) ||
815 (data0 == 0x88 && data1 == 0x99) ||
816 (data0 == 0xaa && data1 == 0xbb) ||
817 (data0 == 0xcc && data1 == 0xdd) ||
818 (data0 == 0xee && data1 == 0xff)) {
819 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
820 input_sync(gspca_dev->input_dev);
821 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
822 input_sync(gspca_dev->input_dev);
823 ret = 0;
824 }
825 }
826
827 return ret;
828}
829#endif
830
Marton Nemeth1408b842009-11-02 08:13:21 -0300831/* sub-driver description for pac7311 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300832static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 .name = MODULE_NAME,
834 .ctrls = sd_ctrls,
835 .nctrls = ARRAY_SIZE(sd_ctrls),
836 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300837 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 .start = sd_start,
839 .stopN = sd_stopN,
840 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300842 .dq_callback = do_autogain,
Hans de Goede32ea3e42010-01-29 11:04:19 -0300843#ifdef CONFIG_INPUT
844 .int_pkt_scan = sd_int_pkt_scan,
845#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846};
847
848/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300849static const struct usb_device_id device_table[] __devinitconst = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300850 {USB_DEVICE(0x093a, 0x2600)},
851 {USB_DEVICE(0x093a, 0x2601)},
852 {USB_DEVICE(0x093a, 0x2603)},
853 {USB_DEVICE(0x093a, 0x2608)},
854 {USB_DEVICE(0x093a, 0x260e)},
855 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 {}
857};
858MODULE_DEVICE_TABLE(usb, device_table);
859
860/* -- device connect -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300861static int __devinit sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862 const struct usb_device_id *id)
863{
864 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
865 THIS_MODULE);
866}
867
868static struct usb_driver sd_driver = {
869 .name = MODULE_NAME,
870 .id_table = device_table,
871 .probe = sd_probe,
872 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300873#ifdef CONFIG_PM
874 .suspend = gspca_suspend,
875 .resume = gspca_resume,
876#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300877};
878
879/* -- module insert / remove -- */
880static int __init sd_mod_init(void)
881{
Alexey Klimovf69e9522009-01-01 13:02:07 -0300882 int ret;
883 ret = usb_register(&sd_driver);
884 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -0300885 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300886 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887 return 0;
888}
889static void __exit sd_mod_exit(void)
890{
891 usb_deregister(&sd_driver);
892 PDEBUG(D_PROBE, "deregistered");
893}
894
895module_init(sd_mod_init);
896module_exit(sd_mod_exit);