blob: ba73eb847fd1032ada00ac8f104eec9cd228cc5a [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
54#include "gspca.h"
55
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030056MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
57MODULE_DESCRIPTION("Pixart PAC7311");
58MODULE_LICENSE("GPL");
59
Marton Nemeth1408b842009-11-02 08:13:21 -030060/* specific webcam descriptor for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061struct sd {
62 struct gspca_dev gspca_dev; /* !! must be the first item */
63
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064 unsigned char contrast;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030065 unsigned char gain;
66 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030068 __u8 hflip;
69 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030070
Hans de Goede327c4ab2008-09-03 17:12:14 -030071 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030072 u8 autogain_ignore_frames;
73
74 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075};
76
77/* V4L2 controls supported by the driver */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
79static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030082static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030086static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090
Marton Nemeth7e64dc42009-12-30 09:12:41 -030091static const struct ctrl sd_ctrls[] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -030092/* This control is for both the 7302 and the 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 {
94 {
95 .id = V4L2_CID_CONTRAST,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Contrast",
98 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030099#define CONTRAST_MAX 255
100 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300102#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300103 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 },
105 .set = sd_setcontrast,
106 .get = sd_getcontrast,
107 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300108/* All controls below are for both the 7302 and the 7311 */
109 {
110 {
111 .id = V4L2_CID_GAIN,
112 .type = V4L2_CTRL_TYPE_INTEGER,
113 .name = "Gain",
114 .minimum = 0,
115#define GAIN_MAX 255
116 .maximum = GAIN_MAX,
117 .step = 1,
118#define GAIN_DEF 127
119#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
120 .default_value = GAIN_DEF,
121 },
122 .set = sd_setgain,
123 .get = sd_getgain,
124 },
125 {
126 {
127 .id = V4L2_CID_EXPOSURE,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "Exposure",
130 .minimum = 0,
131#define EXPOSURE_MAX 255
132 .maximum = EXPOSURE_MAX,
133 .step = 1,
134#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
135#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
136 .default_value = EXPOSURE_DEF,
137 },
138 .set = sd_setexposure,
139 .get = sd_getexposure,
140 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300141 {
142 {
143 .id = V4L2_CID_AUTOGAIN,
144 .type = V4L2_CTRL_TYPE_BOOLEAN,
145 .name = "Auto Gain",
146 .minimum = 0,
147 .maximum = 1,
148 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300149#define AUTOGAIN_DEF 1
150 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 },
152 .set = sd_setautogain,
153 .get = sd_getautogain,
154 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300155 {
156 {
157 .id = V4L2_CID_HFLIP,
158 .type = V4L2_CTRL_TYPE_BOOLEAN,
159 .name = "Mirror",
160 .minimum = 0,
161 .maximum = 1,
162 .step = 1,
163#define HFLIP_DEF 0
164 .default_value = HFLIP_DEF,
165 },
166 .set = sd_sethflip,
167 .get = sd_gethflip,
168 },
169 {
170 {
171 .id = V4L2_CID_VFLIP,
172 .type = V4L2_CTRL_TYPE_BOOLEAN,
173 .name = "Vflip",
174 .minimum = 0,
175 .maximum = 1,
176 .step = 1,
177#define VFLIP_DEF 0
178 .default_value = VFLIP_DEF,
179 },
180 .set = sd_setvflip,
181 .get = sd_getvflip,
182 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183};
184
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300185static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300186 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300187 .bytesperline = 160,
188 .sizeimage = 160 * 120 * 3 / 8 + 590,
189 .colorspace = V4L2_COLORSPACE_JPEG,
190 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300191 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300192 .bytesperline = 320,
193 .sizeimage = 320 * 240 * 3 / 8 + 590,
194 .colorspace = V4L2_COLORSPACE_JPEG,
195 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300196 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300197 .bytesperline = 640,
198 .sizeimage = 640 * 480 * 3 / 8 + 590,
199 .colorspace = V4L2_COLORSPACE_JPEG,
200 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300201};
202
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300203#define LOAD_PAGE4 254
204#define END_OF_SEQUENCE 0
205
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300206/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300207static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300208 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
209 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
210 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300211 0xff, 0x04,
212 0x27, 0x80,
213 0x28, 0xca,
214 0x29, 0x53,
215 0x2a, 0x0e,
216 0xff, 0x01,
217 0x3e, 0x20,
218};
219
220static const __u8 start_7311[] = {
221/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300222 0xff, 1, 0x01, /* page 1 */
223 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300224 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
225 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
226 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300229 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300230 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
231 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
232 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
233 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
234 0xd0, 0xff,
235 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
236 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
237 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
238 0x18, 0x20,
239 0x96, 3, 0x01, 0x08, 0x04,
240 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
241 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
242 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300243 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300244 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300245 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300246 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300247};
248
Marton Nemeth1408b842009-11-02 08:13:21 -0300249#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300250/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300251static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300252 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
253 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
254 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
256 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300257 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
258 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
259};
260
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300261static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300262 __u8 index,
263 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300265 int ret;
266
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300267 if (gspca_dev->usb_err < 0)
268 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300269 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300270 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300271 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300272 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300273 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300274 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300275 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300276 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300277 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300278 PDEBUG(D_ERR, "reg_w_buf(): "
279 "Failed to write registers to index 0x%x, error %i",
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) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300302 PDEBUG(D_ERR, "reg_w(): "
303 "Failed to write register to index 0x%x, value 0x%x, error %i",
304 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300305 gspca_dev->usb_err = ret;
306 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307}
308
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300309static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300310 const __u8 *seq, int len)
311{
312 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300313 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300314 seq += 2;
315 }
316}
317
318/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300319static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300320 const __u8 *page, int len)
321{
322 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300323 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300324
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300325 if (gspca_dev->usb_err < 0)
326 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300327 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300328 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300329 continue;
330 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300331 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300332 usb_sndctrlpipe(gspca_dev->dev, 0),
333 0, /* request */
334 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
335 0, index, gspca_dev->usb_buf, 1,
336 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300337 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300338 PDEBUG(D_ERR, "reg_w_page(): "
339 "Failed to write register to index 0x%x, "
340 "value 0x%x, error %i",
341 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300342 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300343 break;
344 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300345 }
346}
347
348/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300349static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300350 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300351 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300352{
353 int index, len;
354
355 for (;;) {
356 index = *seq++;
357 len = *seq++;
358 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300359 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300360 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300361 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300362 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300363 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300365 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300366 PDEBUG(D_ERR|D_STREAM,
367 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300368 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300369 }
370 while (len > 0) {
371 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300372 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300373 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300374 seq += len;
375 break;
376 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300377 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300378 seq += 8;
379 index += 8;
380 len -= 8;
381 }
382 }
383 }
384 /* not reached */
385}
386
Marton Nemeth1408b842009-11-02 08:13:21 -0300387/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300388static int sd_config(struct gspca_dev *gspca_dev,
389 const struct usb_device_id *id)
390{
391 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300392 struct cam *cam;
393
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300394 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300395
Marton Nemeth1408b842009-11-02 08:13:21 -0300396 PDEBUG(D_CONF, "Find Sensor PAC7311");
397 cam->cam_mode = vga_mode;
398 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300399
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300400 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300401 sd->gain = GAIN_DEF;
402 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300403 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300404 sd->hflip = HFLIP_DEF;
405 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406 return 0;
407}
408
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300409/* This function is used by pac7311 only */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300410static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411{
412 struct sd *sd = (struct sd *) gspca_dev;
413
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300414 reg_w(gspca_dev, 0xff, 0x04);
415 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300417 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418}
419
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300420static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300421{
422 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300423 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424
Marton Nemeth1408b842009-11-02 08:13:21 -0300425 if (gain < 1)
426 gain = 1;
427 else if (gain > 245)
428 gain = 245;
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300429 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
430 reg_w(gspca_dev, 0x0e, 0x00);
431 reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300432
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300433 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300434 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300435}
436
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300437static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300438{
439 struct sd *sd = (struct sd *) gspca_dev;
440 __u8 reg;
441
442 /* register 2 of frame 3/4 contains the clock divider configuring the
443 no fps according to the formula: 60 / reg. sd->exposure is the
444 desired exposure time in ms. */
445 reg = 120 * sd->exposure / 1000;
446 if (reg < 2)
447 reg = 2;
448 else if (reg > 63)
449 reg = 63;
450
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300451 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
452 reg_w(gspca_dev, 0x02, reg);
453
Marton Nemeth1408b842009-11-02 08:13:21 -0300454 /* Page 1 register 8 must always be 0x08 except when not in
455 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300456 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300457 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300458 reg <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300459 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300460 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300461 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300462 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300463
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300464 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300465 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300466}
467
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300468static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300469{
470 struct sd *sd = (struct sd *) gspca_dev;
471 __u8 data;
472
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300473 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300474 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300475 reg_w(gspca_dev, 0x21, data);
476
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300477 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300478 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300479}
480
Marton Nemeth1408b842009-11-02 08:13:21 -0300481/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300482static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300484 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
485 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486}
487
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300488static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300490 struct sd *sd = (struct sd *) gspca_dev;
491
Hans de Goede327c4ab2008-09-03 17:12:14 -0300492 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300494 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300495 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300496 setcontrast(gspca_dev);
497 setgain(gspca_dev);
498 setexposure(gspca_dev);
499 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500
501 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300502 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300503 case 2: /* 160x120 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300504 reg_w(gspca_dev, 0xff, 0x01);
505 reg_w(gspca_dev, 0x17, 0x20);
506 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300508 case 1: /* 320x240 pac7311 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300509 reg_w(gspca_dev, 0xff, 0x01);
510 reg_w(gspca_dev, 0x17, 0x30);
511 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300512 break;
513 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300514 reg_w(gspca_dev, 0xff, 0x01);
515 reg_w(gspca_dev, 0x17, 0x00);
516 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 break;
518 }
519
Hans de Goede327c4ab2008-09-03 17:12:14 -0300520 sd->sof_read = 0;
521 sd->autogain_ignore_frames = 0;
522 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300523
524 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300525 reg_w(gspca_dev, 0xff, 0x01);
526 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300527
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300528 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529}
530
531static void sd_stopN(struct gspca_dev *gspca_dev)
532{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300533 reg_w(gspca_dev, 0xff, 0x04);
534 reg_w(gspca_dev, 0x27, 0x80);
535 reg_w(gspca_dev, 0x28, 0xca);
536 reg_w(gspca_dev, 0x29, 0x53);
537 reg_w(gspca_dev, 0x2a, 0x0e);
538 reg_w(gspca_dev, 0xff, 0x01);
539 reg_w(gspca_dev, 0x3e, 0x20);
540 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
541 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
542 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543}
544
Marton Nemeth1408b842009-11-02 08:13:21 -0300545/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546static void sd_stop0(struct gspca_dev *gspca_dev)
547{
548}
549
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300550/* Include pac common sof detection functions */
551#include "pac_common.h"
552
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300553static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300555 struct sd *sd = (struct sd *) gspca_dev;
556 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300557 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300558
559 if (avg_lum == -1)
560 return;
561
Marton Nemeth1408b842009-11-02 08:13:21 -0300562 desired_lum = 200;
563 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300564
565 if (sd->autogain_ignore_frames > 0)
566 sd->autogain_ignore_frames--;
567 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300568 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300569 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570}
571
Marton Nemeth56f6f552009-10-04 13:58:19 -0300572/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300573static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300574 0xff, 0xd8, /* SOI: Start of Image */
575
576 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
577 0x00, 0x11, /* length = 17 bytes (including this length field) */
578 0x08 /* Precision: 8 */
579 /* 2 bytes is placed here: number of image lines */
580 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300581};
582
Marton Nemeth56f6f552009-10-04 13:58:19 -0300583/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300584static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300585 0x03, /* Number of image components: 3 */
586 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
587 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
588 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
589
590 0xff, 0xda, /* SOS: Start Of Scan */
591 0x00, 0x0c, /* length = 12 bytes (including this length field) */
592 0x03, /* number of components: 3 */
593 0x01, 0x00, /* selector 1, table 0x00 */
594 0x02, 0x11, /* selector 2, table 0x11 */
595 0x03, 0x11, /* selector 3, table 0x11 */
596 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
597 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300598};
599
Marton Nemethcc409c02009-11-02 08:09:34 -0300600static void pac_start_frame(struct gspca_dev *gspca_dev,
601 struct gspca_frame *frame,
602 __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;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300626 unsigned char *sof;
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300627 struct gspca_frame *frame;
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-Francois Moine76dd2722009-11-13 09:21:03 -0300633 frame = gspca_get_i_frame(gspca_dev);
634 if (frame == NULL) {
635 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) {
649 frame->data_end += n;
650 n = 0;
651 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300652 gspca_frame_add(gspca_dev, INTER_PACKET,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300653 data, n);
654 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
655 frame->data_end[-2] == 0xff &&
656 frame->data_end[-1] == 0xd9)
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300657 gspca_frame_add(gspca_dev, LAST_PACKET,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300658 NULL, 0);
659
660 n = sof - data;
661 len -= n;
662 data = sof;
663
664 /* Get average lumination */
665 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300666 n >= lum_offset)
667 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300668 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300669 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300670 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300671
672 /* Start the new frame with the jpeg header */
Marton Nemeth1408b842009-11-02 08:13:21 -0300673 pac_start_frame(gspca_dev, frame,
674 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300675 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300676 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300677}
678
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
680{
681 struct sd *sd = (struct sd *) gspca_dev;
682
683 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300684 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300685 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300686 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300687 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688}
689
690static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
691{
692 struct sd *sd = (struct sd *) gspca_dev;
693
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300694 *val = sd->contrast;
695 return 0;
696}
697
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300698static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
699{
700 struct sd *sd = (struct sd *) gspca_dev;
701
702 sd->gain = val;
703 if (gspca_dev->streaming)
704 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300705 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300706}
707
708static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
709{
710 struct sd *sd = (struct sd *) gspca_dev;
711
712 *val = sd->gain;
713 return 0;
714}
715
716static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
717{
718 struct sd *sd = (struct sd *) gspca_dev;
719
720 sd->exposure = val;
721 if (gspca_dev->streaming)
722 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300723 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300724}
725
726static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
727{
728 struct sd *sd = (struct sd *) gspca_dev;
729
730 *val = sd->exposure;
731 return 0;
732}
733
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300734static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
735{
736 struct sd *sd = (struct sd *) gspca_dev;
737
738 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300739 /* when switching to autogain set defaults to make sure
740 we are on a valid point of the autogain gain /
741 exposure knee graph, and give this change time to
742 take effect before doing autogain. */
743 if (sd->autogain) {
744 sd->exposure = EXPOSURE_DEF;
745 sd->gain = GAIN_DEF;
746 if (gspca_dev->streaming) {
747 sd->autogain_ignore_frames =
748 PAC_AUTOGAIN_IGNORE_FRAMES;
749 setexposure(gspca_dev);
750 setgain(gspca_dev);
751 }
752 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300753
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300754 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300755}
756
757static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760
761 *val = sd->autogain;
762 return 0;
763}
764
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300765static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
766{
767 struct sd *sd = (struct sd *) gspca_dev;
768
769 sd->hflip = val;
770 if (gspca_dev->streaming)
771 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300772 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300773}
774
775static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
776{
777 struct sd *sd = (struct sd *) gspca_dev;
778
779 *val = sd->hflip;
780 return 0;
781}
782
783static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
784{
785 struct sd *sd = (struct sd *) gspca_dev;
786
787 sd->vflip = val;
788 if (gspca_dev->streaming)
789 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300790 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300791}
792
793static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
794{
795 struct sd *sd = (struct sd *) gspca_dev;
796
797 *val = sd->vflip;
798 return 0;
799}
800
Marton Nemeth1408b842009-11-02 08:13:21 -0300801/* sub-driver description for pac7311 */
Márton Némethaabcdfb2010-01-05 12:39:02 -0300802static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803 .name = MODULE_NAME,
804 .ctrls = sd_ctrls,
805 .nctrls = ARRAY_SIZE(sd_ctrls),
806 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300807 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808 .start = sd_start,
809 .stopN = sd_stopN,
810 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300812 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813};
814
815/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300816static const struct usb_device_id device_table[] __devinitconst = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300817 {USB_DEVICE(0x093a, 0x2600)},
818 {USB_DEVICE(0x093a, 0x2601)},
819 {USB_DEVICE(0x093a, 0x2603)},
820 {USB_DEVICE(0x093a, 0x2608)},
821 {USB_DEVICE(0x093a, 0x260e)},
822 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300823 {}
824};
825MODULE_DEVICE_TABLE(usb, device_table);
826
827/* -- device connect -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300828static int __devinit sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300829 const struct usb_device_id *id)
830{
831 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
832 THIS_MODULE);
833}
834
835static struct usb_driver sd_driver = {
836 .name = MODULE_NAME,
837 .id_table = device_table,
838 .probe = sd_probe,
839 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300840#ifdef CONFIG_PM
841 .suspend = gspca_suspend,
842 .resume = gspca_resume,
843#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844};
845
846/* -- module insert / remove -- */
847static int __init sd_mod_init(void)
848{
Alexey Klimovf69e9522009-01-01 13:02:07 -0300849 int ret;
850 ret = usb_register(&sd_driver);
851 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -0300852 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300853 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 return 0;
855}
856static void __exit sd_mod_exit(void)
857{
858 usb_deregister(&sd_driver);
859 PDEBUG(D_PROBE, "deregistered");
860}
861
862module_init(sd_mod_init);
863module_exit(sd_mod_exit);