blob: 69d610062d00b813a563418d32dafcc0b523f0ca [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
42 the 7302, so one of 3, 6, 9, ...
43 -/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
47*/
48
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049#define MODULE_NAME "pac7311"
50
51#include "gspca.h"
52
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
54MODULE_DESCRIPTION("Pixart PAC7311");
55MODULE_LICENSE("GPL");
56
57/* specific webcam descriptor */
58struct sd {
59 struct gspca_dev gspca_dev; /* !! must be the first item */
60
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061 unsigned char brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030062 unsigned char contrast;
63 unsigned char colors;
64 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030065 __u8 hflip;
66 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030067
68 __u8 sensor;
69#define SENSOR_PAC7302 0
70#define SENSOR_PAC7311 1
Hans de Goede327c4ab2008-09-03 17:12:14 -030071
72 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030073 u8 autogain_ignore_frames;
74
75 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030076};
77
78/* V4L2 controls supported by the driver */
79static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
80static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
81static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
83static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030087static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091
92static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 {
94 {
95 .id = V4L2_CID_BRIGHTNESS,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Brightness",
98 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030099#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 .maximum = BRIGHTNESS_MAX,
101 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300102#define BRIGHTNESS_DEF 0x10
103 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 },
105 .set = sd_setbrightness,
106 .get = sd_getbrightness,
107 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 {
109 {
110 .id = V4L2_CID_CONTRAST,
111 .type = V4L2_CTRL_TYPE_INTEGER,
112 .name = "Contrast",
113 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300114#define CONTRAST_MAX 255
115 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300116 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300117#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300118 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300119 },
120 .set = sd_setcontrast,
121 .get = sd_getcontrast,
122 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123 {
124 {
125 .id = V4L2_CID_SATURATION,
126 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300127 .name = "Saturation",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300128 .minimum = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300129#define COLOR_MAX 255
130 .maximum = COLOR_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300131 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300132#define COLOR_DEF 127
133 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300134 },
135 .set = sd_setcolors,
136 .get = sd_getcolors,
137 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300138 {
139 {
140 .id = V4L2_CID_AUTOGAIN,
141 .type = V4L2_CTRL_TYPE_BOOLEAN,
142 .name = "Auto Gain",
143 .minimum = 0,
144 .maximum = 1,
145 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300146#define AUTOGAIN_DEF 1
147 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300148 },
149 .set = sd_setautogain,
150 .get = sd_getautogain,
151 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300152/* next controls work with pac7302 only */
Jean-Francois Moinef50ba1b2008-09-03 17:12:14 -0300153#define HFLIP_IDX 4
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300154 {
155 {
156 .id = V4L2_CID_HFLIP,
157 .type = V4L2_CTRL_TYPE_BOOLEAN,
158 .name = "Mirror",
159 .minimum = 0,
160 .maximum = 1,
161 .step = 1,
162#define HFLIP_DEF 0
163 .default_value = HFLIP_DEF,
164 },
165 .set = sd_sethflip,
166 .get = sd_gethflip,
167 },
Jean-Francois Moinef50ba1b2008-09-03 17:12:14 -0300168#define VFLIP_IDX 5
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300169 {
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 Moinec2446b32008-07-05 11:49:20 -0300185static 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
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300203/* pac 7302 */
204static const __u8 probe_7302[] = {
205/* index,value */
206 0xff, 0x01, /* page 1 */
207 0x78, 0x00, /* deactivate */
208 0xff, 0x01,
209 0x78, 0x40, /* led off */
210};
211static const __u8 start_7302[] = {
212/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300213 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300214 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
215 0x00, 0x00, 0x00, 0x00,
216 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
217 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
218 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
219 0x26, 2, 0xaa, 0xaa,
220 0x2e, 1, 0x31,
221 0x38, 1, 0x01,
222 0x3a, 3, 0x14, 0xff, 0x5a,
223 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
224 0x00, 0x54, 0x11,
225 0x55, 1, 0x00,
226 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
227 0x6b, 1, 0x00,
228 0x6e, 3, 0x08, 0x06, 0x00,
229 0x72, 3, 0x00, 0xff, 0x00,
230 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
231 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
232 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
233 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
234 0xd2, 0xeb,
235 0xaf, 1, 0x02,
236 0xb5, 2, 0x08, 0x08,
237 0xb8, 2, 0x08, 0x88,
238 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
239 0xcc, 1, 0x00,
240 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
241 0xc1, 0xd7, 0xec,
242 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300243 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300244 0x12, 3, 0x02, 0x00, 0x01,
245 0x3e, 2, 0x00, 0x00,
246 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
247 0x7c, 1, 0x00,
248 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
249 0x02, 0x00,
250 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300251 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300252 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300253 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300254 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300255 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300256 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
257 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300258 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300259 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300260 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300261 0x00, 255, /* load the page 3 */
262 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300263 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300264 0x13, 1, 0x00,
265 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
266 0x27, 2, 0x14, 0x0c,
267 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
268 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
269 0x6e, 1, 0x08,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300270 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300271 0x78, 1, 0x00,
272 0, 0 /* end of sequence */
273};
274
275/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
276static const __u8 page3_7302[] = {
277 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
278 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
279 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
281 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
282 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
283 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
284 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
287 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
291 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
292 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
293 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
296 0x00
297};
298
299/* pac 7311 */
300static const __u8 probe_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300301 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
302 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
303 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300304 0xff, 0x04,
305 0x27, 0x80,
306 0x28, 0xca,
307 0x29, 0x53,
308 0x2a, 0x0e,
309 0xff, 0x01,
310 0x3e, 0x20,
311};
312
313static const __u8 start_7311[] = {
314/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300315 0xff, 1, 0x01, /* page 1 */
316 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300317 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
318 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
319 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300322 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300323 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
324 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
325 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
326 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
327 0xd0, 0xff,
328 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
329 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
330 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
331 0x18, 0x20,
332 0x96, 3, 0x01, 0x08, 0x04,
333 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
334 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
335 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300336 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300337 0x00, 254, /* load the page 4 */
338 0x11, 1, 0x01,
339 0, 0 /* end of sequence */
340};
341
342/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
343static const __u8 page4_7311[] = {
344 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
345 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
346 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
348 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
349 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
350 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
351};
352
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300353static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300354 __u8 index,
355 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300356{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300357 memcpy(gspca_dev->usb_buf, buffer, len);
358 usb_control_msg(gspca_dev->dev,
359 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300360 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300361 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300362 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300363 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300364 500);
365}
366
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300367
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300368static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300369 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300370 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300371{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300372 gspca_dev->usb_buf[0] = value;
373 usb_control_msg(gspca_dev->dev,
374 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300375 0, /* request */
376 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300377 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300378 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379}
380
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300381static void reg_w_seq(struct gspca_dev *gspca_dev,
382 const __u8 *seq, int len)
383{
384 while (--len >= 0) {
385 reg_w(gspca_dev, seq[0], seq[1]);
386 seq += 2;
387 }
388}
389
390/* load the beginning of a page */
391static void reg_w_page(struct gspca_dev *gspca_dev,
392 const __u8 *page, int len)
393{
394 int index;
395
396 for (index = 0; index < len; index++) {
397 if (page[index] == 0xaa) /* skip this index */
398 continue;
399 gspca_dev->usb_buf[0] = page[index];
400 usb_control_msg(gspca_dev->dev,
401 usb_sndctrlpipe(gspca_dev->dev, 0),
402 0, /* request */
403 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
404 0, index, gspca_dev->usb_buf, 1,
405 500);
406 }
407}
408
409/* output a variable sequence */
410static void reg_w_var(struct gspca_dev *gspca_dev,
411 const __u8 *seq)
412{
413 int index, len;
414
415 for (;;) {
416 index = *seq++;
417 len = *seq++;
418 switch (len) {
419 case 0:
420 return;
421 case 254:
422 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
423 break;
424 case 255:
425 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
426 break;
427 default:
Hans de Goede327c4ab2008-09-03 17:12:14 -0300428 if (len > 64) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300429 PDEBUG(D_ERR|D_STREAM,
430 "Incorrect variable sequence");
431 return;
432 }
433 while (len > 0) {
434 if (len < 8) {
435 reg_w_buf(gspca_dev, index, seq, len);
436 seq += len;
437 break;
438 }
439 reg_w_buf(gspca_dev, index, seq, 8);
440 seq += 8;
441 index += 8;
442 len -= 8;
443 }
444 }
445 }
446 /* not reached */
447}
448
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300449/* this function is called at probe time */
450static int sd_config(struct gspca_dev *gspca_dev,
451 const struct usb_device_id *id)
452{
453 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 struct cam *cam;
455
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300458
459 sd->sensor = id->driver_info;
460 if (sd->sensor == SENSOR_PAC7302) {
461 PDEBUG(D_CONF, "Find Sensor PAC7302");
462 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
463
464 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
465 cam->nmodes = 1;
466 } else {
467 PDEBUG(D_CONF, "Find Sensor PAC7311");
Hans de Goede327c4ab2008-09-03 17:12:14 -0300468 reg_w_seq(gspca_dev, probe_7311, sizeof probe_7311);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300469
470 cam->cam_mode = vga_mode;
471 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinef50ba1b2008-09-03 17:12:14 -0300472 gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
473 | (1 << VFLIP_IDX);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300474 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300476 sd->brightness = BRIGHTNESS_DEF;
477 sd->contrast = CONTRAST_DEF;
478 sd->colors = COLOR_DEF;
479 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300480 sd->hflip = HFLIP_DEF;
481 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 return 0;
483}
484
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300485/* rev 12a only */
486static void setbrightcont(struct gspca_dev *gspca_dev)
487{
488 struct sd *sd = (struct sd *) gspca_dev;
489 int i, v;
490 static const __u8 max[10] =
491 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
492 0xd4, 0xec};
493 static const __u8 delta[10] =
494 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
495 0x11, 0x0b};
496
497 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
498 for (i = 0; i < 10; i++) {
499 v = max[i];
500 v += (sd->brightness - BRIGHTNESS_MAX)
501 * 150 / BRIGHTNESS_MAX; /* 200 ? */
502 v -= delta[i] * sd->contrast / CONTRAST_MAX;
503 if (v < 0)
504 v = 0;
505 else if (v > 0xff)
506 v = 0xff;
507 reg_w(gspca_dev, 0xa2 + i, v);
508 }
509 reg_w(gspca_dev, 0xdc, 0x01);
510}
511
Hans de Goede327c4ab2008-09-03 17:12:14 -0300512/* This function is used by pac7302 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513static void setbrightness(struct gspca_dev *gspca_dev)
514{
515 struct sd *sd = (struct sd *) gspca_dev;
516 int brightness;
517
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300518 if (sd->sensor == SENSOR_PAC7302) {
519 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300520 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300521 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300522/* HDG: this is not brightness but gain, I'll add gain and exposure controls
523 in a next patch */
524 return;
525
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300528 reg_w(gspca_dev, 0x0e, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
533}
534
535static void setcontrast(struct gspca_dev *gspca_dev)
536{
537 struct sd *sd = (struct sd *) gspca_dev;
538
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300539 if (sd->sensor == SENSOR_PAC7302) {
540 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300541 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300542 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300543 reg_w(gspca_dev, 0xff, 0x04);
544 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300546 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547}
548
Hans de Goede327c4ab2008-09-03 17:12:14 -0300549/* This function is used by pac7302 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550static void setcolors(struct gspca_dev *gspca_dev)
551{
552 struct sd *sd = (struct sd *) gspca_dev;
553
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300554 if (sd->sensor == SENSOR_PAC7302) {
555 int i, v;
556 static const int a[9] =
557 {217, -212, 0, -101, 170, -67, -38, -315, 355};
558 static const int b[9] =
559 {19, 106, 0, 19, 106, 1, 19, 106, 1};
560
561 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
562 reg_w(gspca_dev, 0x11, 0x01);
563 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
564 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
565 for (i = 0; i < 9; i++) {
566 v = a[i] * sd->colors / COLOR_MAX + b[i];
567 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
568 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
569 }
570 reg_w(gspca_dev, 0xdc, 0x01);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300571 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300572 }
573}
574
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300575static void sethvflip(struct gspca_dev *gspca_dev)
576{
577 struct sd *sd = (struct sd *) gspca_dev;
578 __u8 data;
579
Hans de Goede327c4ab2008-09-03 17:12:14 -0300580 if (sd->sensor == SENSOR_PAC7302) {
581 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
582 data = (sd->hflip ? 0x00 : 0x08)
583 | (sd->vflip ? 0x04 : 0x00);
584 } else {
585 reg_w(gspca_dev, 0xff, 0x04); /* page 3 */
586 data = (sd->hflip ? 0x04 : 0x00)
587 | (sd->vflip ? 0x08 : 0x00);
588 }
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300589 reg_w(gspca_dev, 0x21, data);
590 reg_w(gspca_dev, 0x11, 0x01);
591}
592
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593/* this function is called at open time */
594static int sd_open(struct gspca_dev *gspca_dev)
595{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300596 return 0;
597}
598
599static void sd_start(struct gspca_dev *gspca_dev)
600{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300601 struct sd *sd = (struct sd *) gspca_dev;
602
Hans de Goede327c4ab2008-09-03 17:12:14 -0300603 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300604
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300605 if (sd->sensor == SENSOR_PAC7302)
606 reg_w_var(gspca_dev, start_7302);
607 else
608 reg_w_var(gspca_dev, start_7311);
609
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300610 setcontrast(gspca_dev);
611 setbrightness(gspca_dev);
612 setcolors(gspca_dev);
613
614 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300615 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300616 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300617 reg_w(gspca_dev, 0xff, 0x04);
618 reg_w(gspca_dev, 0x02, 0x03);
619 reg_w(gspca_dev, 0xff, 0x01);
620 reg_w(gspca_dev, 0x08, 0x09);
621 reg_w(gspca_dev, 0x17, 0x20);
622 reg_w(gspca_dev, 0x1b, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300623 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300625 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300626 reg_w(gspca_dev, 0xff, 0x04);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300627 reg_w(gspca_dev, 0x02, 0x03);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_w(gspca_dev, 0xff, 0x01);
629 reg_w(gspca_dev, 0x08, 0x09);
630 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300631 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300632 break;
633 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300634 if (sd->sensor == SENSOR_PAC7302)
635 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300636 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300637 reg_w(gspca_dev, 0x02, 0x07);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300638 reg_w(gspca_dev, 0xff, 0x01);
639 reg_w(gspca_dev, 0x08, 0x08);
640 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300641 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300642 break;
643 }
644
645 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300646 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300647 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300648 sethvflip(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300649 reg_w(gspca_dev, 0x78, 0x01);
650 reg_w(gspca_dev, 0xff, 0x01);
651 reg_w(gspca_dev, 0x78, 0x01);
652 } else {
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300653 reg_w(gspca_dev, 0x78, 0x44);
654 reg_w(gspca_dev, 0x78, 0x45);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300655 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300656
657 sd->sof_read = 0;
658 sd->autogain_ignore_frames = 0;
659 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300660}
661
662static void sd_stopN(struct gspca_dev *gspca_dev)
663{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300664 struct sd *sd = (struct sd *) gspca_dev;
665
666 if (sd->sensor == SENSOR_PAC7302) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300667 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300668 reg_w(gspca_dev, 0x78, 0x00);
669 reg_w(gspca_dev, 0x78, 0x00);
670 return;
671 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300672 reg_w(gspca_dev, 0xff, 0x04);
673 reg_w(gspca_dev, 0x27, 0x80);
674 reg_w(gspca_dev, 0x28, 0xca);
675 reg_w(gspca_dev, 0x29, 0x53);
676 reg_w(gspca_dev, 0x2a, 0x0e);
677 reg_w(gspca_dev, 0xff, 0x01);
678 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300679 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
680 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
681 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682}
683
684static void sd_stop0(struct gspca_dev *gspca_dev)
685{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300686 struct sd *sd = (struct sd *) gspca_dev;
687
688 if (sd->sensor == SENSOR_PAC7302) {
689 reg_w(gspca_dev, 0xff, 0x01);
690 reg_w(gspca_dev, 0x78, 0x40);
691 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692}
693
694/* this function is called at close time */
695static void sd_close(struct gspca_dev *gspca_dev)
696{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300697}
698
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300699static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300700{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701}
702
Hans de Goede327c4ab2008-09-03 17:12:14 -0300703static const unsigned char pac7311_jpeg_header1[] = {
704 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
705};
706
707static const unsigned char pac7311_jpeg_header2[] = {
708 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
709 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
710};
711
712/* Include pac common sof detection functions */
713#include "pac_common.h"
714
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300715/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300716static void sd_pkt_scan(struct gspca_dev *gspca_dev,
717 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300718 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 int len) /* iso packet length */
720{
721 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300722 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723
Hans de Goede327c4ab2008-09-03 17:12:14 -0300724 sof = pac_find_sof(gspca_dev, data, len);
725 if (sof) {
726 unsigned char tmpbuf[4];
727 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300728
Hans de Goede327c4ab2008-09-03 17:12:14 -0300729 if (sd->sensor == SENSOR_PAC7302) {
730 lum_offset = 34 + sizeof pac_sof_marker;
731 footer_length = 74;
732 } else {
733 lum_offset = 24 + sizeof pac_sof_marker;
734 footer_length = 26;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300736
737 /* Finish decoding current frame */
738 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
739 if (n < 0) {
740 frame->data_end += n;
741 n = 0;
742 }
743 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
744 data, n);
745 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
746 frame->data_end[-2] == 0xff &&
747 frame->data_end[-1] == 0xd9)
748 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
749 NULL, 0);
750
751 n = sof - data;
752 len -= n;
753 data = sof;
754
755 /* Get average lumination */
756 if (gspca_dev->last_packet_type == LAST_PACKET &&
757 n >= lum_offset) {
758 if (sd->sensor == SENSOR_PAC7302)
759 atomic_set(&sd->avg_lum,
760 (data[-lum_offset] << 8) |
761 data[-lum_offset + 1]);
762 else
763 atomic_set(&sd->avg_lum,
764 data[-lum_offset] +
765 data[-lum_offset + 1]);
766 } else {
767 atomic_set(&sd->avg_lum, -1);
768 }
769
770 /* Start the new frame with the jpeg header */
771 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
772 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
773 if (sd->sensor == SENSOR_PAC7302) {
774 /* The PAC7302 has the image rotated 90 degrees */
775 tmpbuf[0] = gspca_dev->width >> 8;
776 tmpbuf[1] = gspca_dev->width & 0xff;
777 tmpbuf[2] = gspca_dev->height >> 8;
778 tmpbuf[3] = gspca_dev->height & 0xff;
779 } else {
780 tmpbuf[0] = gspca_dev->height >> 8;
781 tmpbuf[1] = gspca_dev->height & 0xff;
782 tmpbuf[2] = gspca_dev->width >> 8;
783 tmpbuf[3] = gspca_dev->width & 0xff;
784 }
785 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
786 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
787 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300789 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300790}
791
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795
796 sd->brightness = val;
797 if (gspca_dev->streaming)
798 setbrightness(gspca_dev);
799 return 0;
800}
801
802static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
803{
804 struct sd *sd = (struct sd *) gspca_dev;
805
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 *val = sd->brightness;
807 return 0;
808}
809
810static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
811{
812 struct sd *sd = (struct sd *) gspca_dev;
813
814 sd->contrast = val;
815 if (gspca_dev->streaming)
816 setcontrast(gspca_dev);
817 return 0;
818}
819
820static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
821{
822 struct sd *sd = (struct sd *) gspca_dev;
823
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824 *val = sd->contrast;
825 return 0;
826}
827
828static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
829{
830 struct sd *sd = (struct sd *) gspca_dev;
831
832 sd->colors = val;
833 if (gspca_dev->streaming)
834 setcolors(gspca_dev);
835 return 0;
836}
837
838static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
839{
840 struct sd *sd = (struct sd *) gspca_dev;
841
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300842 *val = sd->colors;
843 return 0;
844}
845
846static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
847{
848 struct sd *sd = (struct sd *) gspca_dev;
849
850 sd->autogain = val;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300851
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300852 return 0;
853}
854
855static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
856{
857 struct sd *sd = (struct sd *) gspca_dev;
858
859 *val = sd->autogain;
860 return 0;
861}
862
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300863static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
864{
865 struct sd *sd = (struct sd *) gspca_dev;
866
867 sd->hflip = val;
868 if (gspca_dev->streaming)
869 sethvflip(gspca_dev);
870 return 0;
871}
872
873static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
874{
875 struct sd *sd = (struct sd *) gspca_dev;
876
877 *val = sd->hflip;
878 return 0;
879}
880
881static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
882{
883 struct sd *sd = (struct sd *) gspca_dev;
884
885 sd->vflip = val;
886 if (gspca_dev->streaming)
887 sethvflip(gspca_dev);
888 return 0;
889}
890
891static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
892{
893 struct sd *sd = (struct sd *) gspca_dev;
894
895 *val = sd->vflip;
896 return 0;
897}
898
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899/* sub-driver description */
900static struct sd_desc sd_desc = {
901 .name = MODULE_NAME,
902 .ctrls = sd_ctrls,
903 .nctrls = ARRAY_SIZE(sd_ctrls),
904 .config = sd_config,
905 .open = sd_open,
906 .start = sd_start,
907 .stopN = sd_stopN,
908 .stop0 = sd_stop0,
909 .close = sd_close,
910 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300911 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300912};
913
914/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300915static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300916 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
917 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
918 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
919 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
920 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
921 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
922 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300923 {}
924};
925MODULE_DEVICE_TABLE(usb, device_table);
926
927/* -- device connect -- */
928static int sd_probe(struct usb_interface *intf,
929 const struct usb_device_id *id)
930{
931 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
932 THIS_MODULE);
933}
934
935static struct usb_driver sd_driver = {
936 .name = MODULE_NAME,
937 .id_table = device_table,
938 .probe = sd_probe,
939 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300940#ifdef CONFIG_PM
941 .suspend = gspca_suspend,
942 .resume = gspca_resume,
943#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300944};
945
946/* -- module insert / remove -- */
947static int __init sd_mod_init(void)
948{
949 if (usb_register(&sd_driver) < 0)
950 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300951 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300952 return 0;
953}
954static void __exit sd_mod_exit(void)
955{
956 usb_deregister(&sd_driver);
957 PDEBUG(D_PROBE, "deregistered");
958}
959
960module_init(sd_mod_init);
961module_exit(sd_mod_exit);