blob: 42cfcdfd8f4f114649d1e15be5582b52a082a15d [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
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300656 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300657 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
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300664 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300665 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300666 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300667 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,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300672 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300673 int len) /* iso packet length */
674{
675 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300676 unsigned char *sof;
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300677 struct gspca_frame *frame;
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
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300683 frame = gspca_get_i_frame(gspca_dev);
684 if (frame == NULL) {
685 gspca_dev->last_packet_type = DISCARD_PACKET;
686 return;
687 }
688
Marton Nemeth1408b842009-11-02 08:13:21 -0300689 /* 6 bytes after the FF D9 EOF marker a number of lumination
690 bytes are send corresponding to different parts of the
691 image, the 14th and 15th byte after the EOF seem to
692 correspond to the center of the image */
693 lum_offset = 24 + sizeof pac_sof_marker;
694 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300695
696 /* Finish decoding current frame */
697 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
698 if (n < 0) {
699 frame->data_end += n;
700 n = 0;
701 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300702 gspca_frame_add(gspca_dev, INTER_PACKET,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300703 data, n);
704 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
705 frame->data_end[-2] == 0xff &&
706 frame->data_end[-1] == 0xd9)
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300707 gspca_frame_add(gspca_dev, LAST_PACKET,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300708 NULL, 0);
709
710 n = sof - data;
711 len -= n;
712 data = sof;
713
714 /* Get average lumination */
715 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300716 n >= lum_offset)
717 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300718 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300719 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300720 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300721
722 /* Start the new frame with the jpeg header */
Marton Nemeth1408b842009-11-02 08:13:21 -0300723 pac_start_frame(gspca_dev, frame,
724 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300726 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300727}
728
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
730{
731 struct sd *sd = (struct sd *) gspca_dev;
732
733 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300734 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300735 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300736 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300737 return 0;
738}
739
740static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
741{
742 struct sd *sd = (struct sd *) gspca_dev;
743
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300744 *val = sd->contrast;
745 return 0;
746}
747
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300748static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
749{
750 struct sd *sd = (struct sd *) gspca_dev;
751
752 sd->gain = val;
753 if (gspca_dev->streaming)
754 setgain(gspca_dev);
755 return 0;
756}
757
758static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
759{
760 struct sd *sd = (struct sd *) gspca_dev;
761
762 *val = sd->gain;
763 return 0;
764}
765
766static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
767{
768 struct sd *sd = (struct sd *) gspca_dev;
769
770 sd->exposure = val;
771 if (gspca_dev->streaming)
772 setexposure(gspca_dev);
773 return 0;
774}
775
776static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
777{
778 struct sd *sd = (struct sd *) gspca_dev;
779
780 *val = sd->exposure;
781 return 0;
782}
783
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300784static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
785{
786 struct sd *sd = (struct sd *) gspca_dev;
787
788 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300789 /* when switching to autogain set defaults to make sure
790 we are on a valid point of the autogain gain /
791 exposure knee graph, and give this change time to
792 take effect before doing autogain. */
793 if (sd->autogain) {
794 sd->exposure = EXPOSURE_DEF;
795 sd->gain = GAIN_DEF;
796 if (gspca_dev->streaming) {
797 sd->autogain_ignore_frames =
798 PAC_AUTOGAIN_IGNORE_FRAMES;
799 setexposure(gspca_dev);
800 setgain(gspca_dev);
801 }
802 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300803
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 return 0;
805}
806
807static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
808{
809 struct sd *sd = (struct sd *) gspca_dev;
810
811 *val = sd->autogain;
812 return 0;
813}
814
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300815static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
816{
817 struct sd *sd = (struct sd *) gspca_dev;
818
819 sd->hflip = val;
820 if (gspca_dev->streaming)
821 sethvflip(gspca_dev);
822 return 0;
823}
824
825static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
826{
827 struct sd *sd = (struct sd *) gspca_dev;
828
829 *val = sd->hflip;
830 return 0;
831}
832
833static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
834{
835 struct sd *sd = (struct sd *) gspca_dev;
836
837 sd->vflip = val;
838 if (gspca_dev->streaming)
839 sethvflip(gspca_dev);
840 return 0;
841}
842
843static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
844{
845 struct sd *sd = (struct sd *) gspca_dev;
846
847 *val = sd->vflip;
848 return 0;
849}
850
Marton Nemeth1408b842009-11-02 08:13:21 -0300851/* sub-driver description for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300852static struct sd_desc sd_desc = {
853 .name = MODULE_NAME,
854 .ctrls = sd_ctrls,
855 .nctrls = ARRAY_SIZE(sd_ctrls),
856 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300857 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 .start = sd_start,
859 .stopN = sd_stopN,
860 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300861 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300862 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863};
864
865/* -- module initialisation -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300866static const struct usb_device_id device_table[] __devinitconst = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300867 {USB_DEVICE(0x093a, 0x2600)},
868 {USB_DEVICE(0x093a, 0x2601)},
869 {USB_DEVICE(0x093a, 0x2603)},
870 {USB_DEVICE(0x093a, 0x2608)},
871 {USB_DEVICE(0x093a, 0x260e)},
872 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300873 {}
874};
875MODULE_DEVICE_TABLE(usb, device_table);
876
877/* -- device connect -- */
Márton Németh37b372e2009-12-10 11:31:09 -0300878static int __devinit sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300879 const struct usb_device_id *id)
880{
881 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
882 THIS_MODULE);
883}
884
885static struct usb_driver sd_driver = {
886 .name = MODULE_NAME,
887 .id_table = device_table,
888 .probe = sd_probe,
889 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300890#ifdef CONFIG_PM
891 .suspend = gspca_suspend,
892 .resume = gspca_resume,
893#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300894};
895
896/* -- module insert / remove -- */
897static int __init sd_mod_init(void)
898{
Alexey Klimovf69e9522009-01-01 13:02:07 -0300899 int ret;
900 ret = usb_register(&sd_driver);
901 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -0300902 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300903 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904 return 0;
905}
906static void __exit sd_mod_exit(void)
907{
908 usb_deregister(&sd_driver);
909 PDEBUG(D_PROBE, "deregistered");
910}
911
912module_init(sd_mod_init);
913module_exit(sd_mod_exit);