blob: 1a27da00ccc180da208ca0f6f2773f5a926fefd9 [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
91static 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_PAGE3 255
204#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
Márton Némethb1784b32009-11-07 05:52:02 -0300262static int 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 Moine739570b2008-07-14 09:38:29 -0300268 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300269 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300270 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300271 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300273 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300274 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300275 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300276 if (ret < 0)
277 PDEBUG(D_ERR, "reg_w_buf(): "
278 "Failed to write registers to index 0x%x, error %i",
279 index, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300280 return ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300281}
282
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300283
Márton Némethb1784b32009-11-07 05:52:02 -0300284static int reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300285 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300286 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300287{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300288 int ret;
289
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300290 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300291 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300292 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300293 0, /* request */
294 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300295 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300296 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300297 if (ret < 0)
298 PDEBUG(D_ERR, "reg_w(): "
299 "Failed to write register to index 0x%x, value 0x%x, error %i",
300 index, value, ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300301 return ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302}
303
Márton Némethb1784b32009-11-07 05:52:02 -0300304static int reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300305 const __u8 *seq, int len)
306{
Márton Némethb1784b32009-11-07 05:52:02 -0300307 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300308 while (--len >= 0) {
Márton Némethb1784b32009-11-07 05:52:02 -0300309 if (0 <= ret)
310 ret = reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300311 seq += 2;
312 }
Márton Némethb1784b32009-11-07 05:52:02 -0300313 return ret;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300314}
315
316/* load the beginning of a page */
Márton Némethb1784b32009-11-07 05:52:02 -0300317static int reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300318 const __u8 *page, int len)
319{
320 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300321 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300322
323 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300324 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300325 continue;
326 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300327 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300328 usb_sndctrlpipe(gspca_dev->dev, 0),
329 0, /* request */
330 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
331 0, index, gspca_dev->usb_buf, 1,
332 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300333 if (ret < 0) {
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300334 PDEBUG(D_ERR, "reg_w_page(): "
335 "Failed to write register to index 0x%x, "
336 "value 0x%x, error %i",
337 index, page[index], ret);
Márton Némethb1784b32009-11-07 05:52:02 -0300338 break;
339 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300340 }
Márton Némethb1784b32009-11-07 05:52:02 -0300341 return ret;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300342}
343
344/* output a variable sequence */
Márton Némethb1784b32009-11-07 05:52:02 -0300345static int reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300346 const __u8 *seq,
347 const __u8 *page3, unsigned int page3_len,
348 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300349{
350 int index, len;
Márton Némethb1784b32009-11-07 05:52:02 -0300351 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300352
353 for (;;) {
354 index = *seq++;
355 len = *seq++;
356 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300357 case END_OF_SEQUENCE:
Márton Némethb1784b32009-11-07 05:52:02 -0300358 return ret;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300359 case LOAD_PAGE4:
Márton Némethb1784b32009-11-07 05:52:02 -0300360 ret = reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300361 break;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300362 case LOAD_PAGE3:
Márton Némethb1784b32009-11-07 05:52:02 -0300363 ret = reg_w_page(gspca_dev, page3, page3_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 break;
365 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");
Márton Némethb1784b32009-11-07 05:52:02 -0300369 return -EINVAL;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300370 }
371 while (len > 0) {
372 if (len < 8) {
Márton Némethb1784b32009-11-07 05:52:02 -0300373 ret = reg_w_buf(gspca_dev,
374 index, seq, len);
375 if (ret < 0)
376 return ret;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300377 seq += len;
378 break;
379 }
Márton Némethb1784b32009-11-07 05:52:02 -0300380 ret = reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300381 seq += 8;
382 index += 8;
383 len -= 8;
384 }
385 }
Márton Némethb1784b32009-11-07 05:52:02 -0300386 if (ret < 0)
387 return ret;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300388 }
389 /* not reached */
390}
391
Marton Nemeth1408b842009-11-02 08:13:21 -0300392/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393static int sd_config(struct gspca_dev *gspca_dev,
394 const struct usb_device_id *id)
395{
396 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397 struct cam *cam;
398
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300399 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300400
Marton Nemeth1408b842009-11-02 08:13:21 -0300401 PDEBUG(D_CONF, "Find Sensor PAC7311");
402 cam->cam_mode = vga_mode;
403 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300405 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300406 sd->gain = GAIN_DEF;
407 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300408 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300409 sd->hflip = HFLIP_DEF;
410 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411 return 0;
412}
413
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300414/* This function is used by pac7311 only */
Márton Némethb1784b32009-11-07 05:52:02 -0300415static int setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416{
417 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300418 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419
Márton Némethb1784b32009-11-07 05:52:02 -0300420 ret = reg_w(gspca_dev, 0xff, 0x04);
421 if (0 <= ret)
422 ret = reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300424 if (0 <= ret)
425 ret = reg_w(gspca_dev, 0x11, 0x01);
426 return ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300427}
428
Márton Némethb1784b32009-11-07 05:52:02 -0300429static int setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300430{
431 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300432 int gain = GAIN_MAX - sd->gain;
Márton Némethb1784b32009-11-07 05:52:02 -0300433 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300434
Marton Nemeth1408b842009-11-02 08:13:21 -0300435 if (gain < 1)
436 gain = 1;
437 else if (gain > 245)
438 gain = 245;
Márton Némethb1784b32009-11-07 05:52:02 -0300439 ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
440 if (0 <= ret)
441 ret = reg_w(gspca_dev, 0x0e, 0x00);
442 if (0 <= ret)
443 ret = reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300444
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300445 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300446 if (0 <= ret)
447 ret = reg_w(gspca_dev, 0x11, 0x01);
448 return ret;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300449}
450
Márton Némethb1784b32009-11-07 05:52:02 -0300451static int setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300452{
453 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300454 int ret;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300455 __u8 reg;
456
457 /* register 2 of frame 3/4 contains the clock divider configuring the
458 no fps according to the formula: 60 / reg. sd->exposure is the
459 desired exposure time in ms. */
460 reg = 120 * sd->exposure / 1000;
461 if (reg < 2)
462 reg = 2;
463 else if (reg > 63)
464 reg = 63;
465
Márton Némethb1784b32009-11-07 05:52:02 -0300466 ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
467 if (0 <= ret)
468 ret = reg_w(gspca_dev, 0x02, reg);
Marton Nemeth1408b842009-11-02 08:13:21 -0300469 /* Page 1 register 8 must always be 0x08 except when not in
470 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
Márton Némethb1784b32009-11-07 05:52:02 -0300471 if (0 <= ret)
472 ret = reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300473 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300474 reg <= 3) {
475 if (0 <= ret)
476 ret = reg_w(gspca_dev, 0x08, 0x09);
477 } else {
478 if (0 <= ret)
479 ret = reg_w(gspca_dev, 0x08, 0x08);
480 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300481
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300482 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300483 if (0 <= ret)
484 ret = reg_w(gspca_dev, 0x11, 0x01);
485 return ret;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300486}
487
Márton Némethb1784b32009-11-07 05:52:02 -0300488static int sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300489{
490 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300491 int ret;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300492 __u8 data;
493
Márton Némethb1784b32009-11-07 05:52:02 -0300494 ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300495 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Márton Némethb1784b32009-11-07 05:52:02 -0300496 if (0 <= ret)
497 ret = reg_w(gspca_dev, 0x21, data);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300498 /* load registers to sensor (Bit 0, auto clear) */
Márton Némethb1784b32009-11-07 05:52:02 -0300499 if (0 <= ret)
500 ret = reg_w(gspca_dev, 0x11, 0x01);
501 return ret;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300502}
503
Marton Nemeth1408b842009-11-02 08:13:21 -0300504/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300505static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506{
Márton Némethb1784b32009-11-07 05:52:02 -0300507 return reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508}
509
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300510static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300512 struct sd *sd = (struct sd *) gspca_dev;
Márton Némethb1784b32009-11-07 05:52:02 -0300513 int ret;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300514
Hans de Goede327c4ab2008-09-03 17:12:14 -0300515 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300516
Márton Némethb1784b32009-11-07 05:52:02 -0300517 ret = reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300518 NULL, 0,
519 page4_7311, sizeof(page4_7311));
Márton Némethb1784b32009-11-07 05:52:02 -0300520 if (0 <= ret)
521 ret = setcontrast(gspca_dev);
522 if (0 <= ret)
523 ret = setgain(gspca_dev);
524 if (0 <= ret)
525 ret = setexposure(gspca_dev);
526 if (0 <= ret)
527 ret = sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528
529 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300530 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300531 case 2: /* 160x120 pac7311 */
Márton Némethb1784b32009-11-07 05:52:02 -0300532 if (0 <= ret)
533 ret = reg_w(gspca_dev, 0xff, 0x01);
534 if (0 <= ret)
535 ret = reg_w(gspca_dev, 0x17, 0x20);
536 if (0 <= ret)
537 ret = reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300539 case 1: /* 320x240 pac7311 */
Márton Némethb1784b32009-11-07 05:52:02 -0300540 if (0 <= ret)
541 ret = reg_w(gspca_dev, 0xff, 0x01);
542 if (0 <= ret)
543 ret = reg_w(gspca_dev, 0x17, 0x30);
544 if (0 <= ret)
545 ret = reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 break;
547 case 0: /* 640x480 */
Márton Némethb1784b32009-11-07 05:52:02 -0300548 if (0 <= ret)
549 ret = reg_w(gspca_dev, 0xff, 0x01);
550 if (0 <= ret)
551 ret = reg_w(gspca_dev, 0x17, 0x00);
552 if (0 <= ret)
553 ret = reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 break;
555 }
556
Hans de Goede327c4ab2008-09-03 17:12:14 -0300557 sd->sof_read = 0;
558 sd->autogain_ignore_frames = 0;
559 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300560
561 /* start stream */
Márton Némethb1784b32009-11-07 05:52:02 -0300562 if (0 <= ret)
563 ret = reg_w(gspca_dev, 0xff, 0x01);
564 if (0 <= ret)
565 ret = reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300566
Márton Némethb1784b32009-11-07 05:52:02 -0300567 return ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568}
569
570static void sd_stopN(struct gspca_dev *gspca_dev)
571{
Márton Németh4d0fc032009-11-09 07:08:04 -0300572 int ret;
573
574 ret = reg_w(gspca_dev, 0xff, 0x04);
575 if (0 <= ret)
576 ret = reg_w(gspca_dev, 0x27, 0x80);
577 if (0 <= ret)
578 ret = reg_w(gspca_dev, 0x28, 0xca);
579 if (0 <= ret)
580 ret = reg_w(gspca_dev, 0x29, 0x53);
581 if (0 <= ret)
582 ret = reg_w(gspca_dev, 0x2a, 0x0e);
583 if (0 <= ret)
584 ret = reg_w(gspca_dev, 0xff, 0x01);
585 if (0 <= ret)
586 ret = reg_w(gspca_dev, 0x3e, 0x20);
587 if (0 <= ret)
588 ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
589 if (0 <= ret)
590 ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
591 if (0 <= ret)
592 ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593}
594
Marton Nemeth1408b842009-11-02 08:13:21 -0300595/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300596static void sd_stop0(struct gspca_dev *gspca_dev)
597{
598}
599
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300600/* Include pac common sof detection functions */
601#include "pac_common.h"
602
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300603static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300604{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300605 struct sd *sd = (struct sd *) gspca_dev;
606 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300607 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300608
609 if (avg_lum == -1)
610 return;
611
Marton Nemeth1408b842009-11-02 08:13:21 -0300612 desired_lum = 200;
613 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300614
615 if (sd->autogain_ignore_frames > 0)
616 sd->autogain_ignore_frames--;
617 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300618 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300619 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620}
621
Marton Nemeth56f6f552009-10-04 13:58:19 -0300622/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300623static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300624 0xff, 0xd8, /* SOI: Start of Image */
625
626 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
627 0x00, 0x11, /* length = 17 bytes (including this length field) */
628 0x08 /* Precision: 8 */
629 /* 2 bytes is placed here: number of image lines */
630 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300631};
632
Marton Nemeth56f6f552009-10-04 13:58:19 -0300633/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300634static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300635 0x03, /* Number of image components: 3 */
636 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
637 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
638 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
639
640 0xff, 0xda, /* SOS: Start Of Scan */
641 0x00, 0x0c, /* length = 12 bytes (including this length field) */
642 0x03, /* number of components: 3 */
643 0x01, 0x00, /* selector 1, table 0x00 */
644 0x02, 0x11, /* selector 2, table 0x11 */
645 0x03, 0x11, /* selector 3, table 0x11 */
646 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
647 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300648};
649
Marton Nemethcc409c02009-11-02 08:09:34 -0300650static void pac_start_frame(struct gspca_dev *gspca_dev,
651 struct gspca_frame *frame,
652 __u16 lines, __u16 samples_per_line)
653{
654 unsigned char tmpbuf[4];
655
656 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
657 pac_jpeg_header1, sizeof(pac_jpeg_header1));
658
659 tmpbuf[0] = lines >> 8;
660 tmpbuf[1] = lines & 0xff;
661 tmpbuf[2] = samples_per_line >> 8;
662 tmpbuf[3] = samples_per_line & 0xff;
663
664 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
665 tmpbuf, sizeof(tmpbuf));
666 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
667 pac_jpeg_header2, sizeof(pac_jpeg_header2));
668}
669
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300670/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671static void sd_pkt_scan(struct gspca_dev *gspca_dev,
672 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300673 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 int len) /* iso packet length */
675{
676 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300677 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678
Marton Nemetha6b69e42009-11-02 08:05:51 -0300679 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300680 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300681 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300682
Marton Nemeth1408b842009-11-02 08:13:21 -0300683 /* 6 bytes after the FF D9 EOF marker a number of lumination
684 bytes are send corresponding to different parts of the
685 image, the 14th and 15th byte after the EOF seem to
686 correspond to the center of the image */
687 lum_offset = 24 + sizeof pac_sof_marker;
688 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300689
690 /* Finish decoding current frame */
691 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
692 if (n < 0) {
693 frame->data_end += n;
694 n = 0;
695 }
696 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
697 data, n);
698 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
699 frame->data_end[-2] == 0xff &&
700 frame->data_end[-1] == 0xd9)
701 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
702 NULL, 0);
703
704 n = sof - data;
705 len -= n;
706 data = sof;
707
708 /* Get average lumination */
709 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300710 n >= lum_offset)
711 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300712 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300713 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300714 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300715
716 /* Start the new frame with the jpeg header */
Marton Nemeth1408b842009-11-02 08:13:21 -0300717 pac_start_frame(gspca_dev, frame,
718 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300720 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721}
722
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
724{
725 struct sd *sd = (struct sd *) gspca_dev;
726
727 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300728 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300729 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300730 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731 return 0;
732}
733
734static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
735{
736 struct sd *sd = (struct sd *) gspca_dev;
737
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 *val = sd->contrast;
739 return 0;
740}
741
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300742static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
743{
744 struct sd *sd = (struct sd *) gspca_dev;
745
746 sd->gain = val;
747 if (gspca_dev->streaming)
748 setgain(gspca_dev);
749 return 0;
750}
751
752static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
753{
754 struct sd *sd = (struct sd *) gspca_dev;
755
756 *val = sd->gain;
757 return 0;
758}
759
760static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
761{
762 struct sd *sd = (struct sd *) gspca_dev;
763
764 sd->exposure = val;
765 if (gspca_dev->streaming)
766 setexposure(gspca_dev);
767 return 0;
768}
769
770static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
771{
772 struct sd *sd = (struct sd *) gspca_dev;
773
774 *val = sd->exposure;
775 return 0;
776}
777
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300778static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
779{
780 struct sd *sd = (struct sd *) gspca_dev;
781
782 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300783 /* when switching to autogain set defaults to make sure
784 we are on a valid point of the autogain gain /
785 exposure knee graph, and give this change time to
786 take effect before doing autogain. */
787 if (sd->autogain) {
788 sd->exposure = EXPOSURE_DEF;
789 sd->gain = GAIN_DEF;
790 if (gspca_dev->streaming) {
791 sd->autogain_ignore_frames =
792 PAC_AUTOGAIN_IGNORE_FRAMES;
793 setexposure(gspca_dev);
794 setgain(gspca_dev);
795 }
796 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300797
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300798 return 0;
799}
800
801static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
802{
803 struct sd *sd = (struct sd *) gspca_dev;
804
805 *val = sd->autogain;
806 return 0;
807}
808
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300809static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
810{
811 struct sd *sd = (struct sd *) gspca_dev;
812
813 sd->hflip = val;
814 if (gspca_dev->streaming)
815 sethvflip(gspca_dev);
816 return 0;
817}
818
819static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
820{
821 struct sd *sd = (struct sd *) gspca_dev;
822
823 *val = sd->hflip;
824 return 0;
825}
826
827static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
828{
829 struct sd *sd = (struct sd *) gspca_dev;
830
831 sd->vflip = val;
832 if (gspca_dev->streaming)
833 sethvflip(gspca_dev);
834 return 0;
835}
836
837static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
838{
839 struct sd *sd = (struct sd *) gspca_dev;
840
841 *val = sd->vflip;
842 return 0;
843}
844
Marton Nemeth1408b842009-11-02 08:13:21 -0300845/* sub-driver description for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846static struct sd_desc sd_desc = {
847 .name = MODULE_NAME,
848 .ctrls = sd_ctrls,
849 .nctrls = ARRAY_SIZE(sd_ctrls),
850 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300851 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300852 .start = sd_start,
853 .stopN = sd_stopN,
854 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300856 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857};
858
859/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860static __devinitdata struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300861 {USB_DEVICE(0x093a, 0x2600)},
862 {USB_DEVICE(0x093a, 0x2601)},
863 {USB_DEVICE(0x093a, 0x2603)},
864 {USB_DEVICE(0x093a, 0x2608)},
865 {USB_DEVICE(0x093a, 0x260e)},
866 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 {}
868};
869MODULE_DEVICE_TABLE(usb, device_table);
870
871/* -- device connect -- */
872static int sd_probe(struct usb_interface *intf,
873 const struct usb_device_id *id)
874{
875 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
876 THIS_MODULE);
877}
878
879static struct usb_driver sd_driver = {
880 .name = MODULE_NAME,
881 .id_table = device_table,
882 .probe = sd_probe,
883 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300884#ifdef CONFIG_PM
885 .suspend = gspca_suspend,
886 .resume = gspca_resume,
887#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888};
889
890/* -- module insert / remove -- */
891static int __init sd_mod_init(void)
892{
Alexey Klimovf69e9522009-01-01 13:02:07 -0300893 int ret;
894 ret = usb_register(&sd_driver);
895 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -0300896 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300897 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 return 0;
899}
900static void __exit sd_mod_exit(void)
901{
902 usb_deregister(&sd_driver);
903 PDEBUG(D_PROBE, "deregistered");
904}
905
906module_init(sd_mod_init);
907module_exit(sd_mod_exit);