V4L/DVB (9616): tvaudio: cleanup - group all callbacks together
[linux-2.6] / drivers / media / video / gspca / pac7311.c
CommitLineData
6a7eba24
JFM
1/*
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
327c4abf
HG
22/* 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
038ec7c7 42 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
327c4abf
HG
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
8a5b2e90
HG
47 -/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.
327c4abf
HG
50*/
51
6a7eba24
JFM
52#define MODULE_NAME "pac7311"
53
54#include "gspca.h"
55
6a7eba24
JFM
56MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
57MODULE_DESCRIPTION("Pixart PAC7311");
58MODULE_LICENSE("GPL");
59
60/* specific webcam descriptor */
61struct sd {
62 struct gspca_dev gspca_dev; /* !! must be the first item */
63
6a7eba24 64 unsigned char brightness;
6a7eba24
JFM
65 unsigned char contrast;
66 unsigned char colors;
8a5b2e90
HG
67 unsigned char gain;
68 unsigned char exposure;
6a7eba24 69 unsigned char autogain;
41b46974
JFM
70 __u8 hflip;
71 __u8 vflip;
49b57dba
JFM
72
73 __u8 sensor;
74#define SENSOR_PAC7302 0
75#define SENSOR_PAC7311 1
327c4abf
HG
76
77 u8 sof_read;
327c4abf
HG
78 u8 autogain_ignore_frames;
79
80 atomic_t avg_lum;
6a7eba24
JFM
81};
82
83/* V4L2 controls supported by the driver */
84static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
90static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
91static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
41b46974
JFM
92static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
93static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
94static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
95static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
8a5b2e90
HG
96static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
97static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
98static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
99static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
6a7eba24
JFM
100
101static struct ctrl sd_ctrls[] = {
8a5b2e90
HG
102/* This control is pac7302 only */
103#define BRIGHTNESS_IDX 0
6a7eba24
JFM
104 {
105 {
106 .id = V4L2_CID_BRIGHTNESS,
107 .type = V4L2_CTRL_TYPE_INTEGER,
108 .name = "Brightness",
109 .minimum = 0,
a5ae2062 110#define BRIGHTNESS_MAX 0x20
6a7eba24
JFM
111 .maximum = BRIGHTNESS_MAX,
112 .step = 1,
a5ae2062
JFM
113#define BRIGHTNESS_DEF 0x10
114 .default_value = BRIGHTNESS_DEF,
6a7eba24
JFM
115 },
116 .set = sd_setbrightness,
117 .get = sd_getbrightness,
118 },
8a5b2e90 119/* This control is for both the 7302 and the 7311 */
6a7eba24
JFM
120 {
121 {
122 .id = V4L2_CID_CONTRAST,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Contrast",
125 .minimum = 0,
dff6d321
JFM
126#define CONTRAST_MAX 255
127 .maximum = CONTRAST_MAX,
6a7eba24 128 .step = 1,
327c4abf 129#define CONTRAST_DEF 127
a5ae2062 130 .default_value = CONTRAST_DEF,
6a7eba24
JFM
131 },
132 .set = sd_setcontrast,
133 .get = sd_getcontrast,
134 },
8a5b2e90
HG
135/* This control is pac7302 only */
136#define SATURATION_IDX 2
6a7eba24
JFM
137 {
138 {
139 .id = V4L2_CID_SATURATION,
140 .type = V4L2_CTRL_TYPE_INTEGER,
dff6d321 141 .name = "Saturation",
6a7eba24 142 .minimum = 0,
41b46974
JFM
143#define COLOR_MAX 255
144 .maximum = COLOR_MAX,
6a7eba24 145 .step = 1,
a5ae2062
JFM
146#define COLOR_DEF 127
147 .default_value = COLOR_DEF,
6a7eba24
JFM
148 },
149 .set = sd_setcolors,
150 .get = sd_getcolors,
151 },
8a5b2e90
HG
152/* All controls below are for both the 7302 and the 7311 */
153 {
154 {
155 .id = V4L2_CID_GAIN,
156 .type = V4L2_CTRL_TYPE_INTEGER,
157 .name = "Gain",
158 .minimum = 0,
159#define GAIN_MAX 255
160 .maximum = GAIN_MAX,
161 .step = 1,
162#define GAIN_DEF 127
163#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
164 .default_value = GAIN_DEF,
165 },
166 .set = sd_setgain,
167 .get = sd_getgain,
168 },
169 {
170 {
171 .id = V4L2_CID_EXPOSURE,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "Exposure",
174 .minimum = 0,
175#define EXPOSURE_MAX 255
176 .maximum = EXPOSURE_MAX,
177 .step = 1,
178#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
179#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
180 .default_value = EXPOSURE_DEF,
181 },
182 .set = sd_setexposure,
183 .get = sd_getexposure,
184 },
6a7eba24
JFM
185 {
186 {
187 .id = V4L2_CID_AUTOGAIN,
188 .type = V4L2_CTRL_TYPE_BOOLEAN,
189 .name = "Auto Gain",
190 .minimum = 0,
191 .maximum = 1,
192 .step = 1,
a5ae2062
JFM
193#define AUTOGAIN_DEF 1
194 .default_value = AUTOGAIN_DEF,
6a7eba24
JFM
195 },
196 .set = sd_setautogain,
197 .get = sd_getautogain,
198 },
41b46974
JFM
199 {
200 {
201 .id = V4L2_CID_HFLIP,
202 .type = V4L2_CTRL_TYPE_BOOLEAN,
203 .name = "Mirror",
204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
207#define HFLIP_DEF 0
208 .default_value = HFLIP_DEF,
209 },
210 .set = sd_sethflip,
211 .get = sd_gethflip,
212 },
213 {
214 {
215 .id = V4L2_CID_VFLIP,
216 .type = V4L2_CTRL_TYPE_BOOLEAN,
217 .name = "Vflip",
218 .minimum = 0,
219 .maximum = 1,
220 .step = 1,
221#define VFLIP_DEF 0
222 .default_value = VFLIP_DEF,
223 },
224 .set = sd_setvflip,
225 .get = sd_getvflip,
226 },
6a7eba24
JFM
227};
228
c2446b3e 229static struct v4l2_pix_format vga_mode[] = {
f75c4950 230 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
c2446b3e
JFM
231 .bytesperline = 160,
232 .sizeimage = 160 * 120 * 3 / 8 + 590,
233 .colorspace = V4L2_COLORSPACE_JPEG,
234 .priv = 2},
f75c4950 235 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
c2446b3e
JFM
236 .bytesperline = 320,
237 .sizeimage = 320 * 240 * 3 / 8 + 590,
238 .colorspace = V4L2_COLORSPACE_JPEG,
239 .priv = 1},
f75c4950 240 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
c2446b3e
JFM
241 .bytesperline = 640,
242 .sizeimage = 640 * 480 * 3 / 8 + 590,
243 .colorspace = V4L2_COLORSPACE_JPEG,
244 .priv = 0},
6a7eba24
JFM
245};
246
49b57dba 247/* pac 7302 */
271315a9 248static const __u8 init_7302[] = {
49b57dba
JFM
249/* index,value */
250 0xff, 0x01, /* page 1 */
251 0x78, 0x00, /* deactivate */
252 0xff, 0x01,
253 0x78, 0x40, /* led off */
254};
255static const __u8 start_7302[] = {
256/* index, len, [value]* */
285a4f6c 257 0xff, 1, 0x00, /* page 0 */
49b57dba
JFM
258 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
259 0x00, 0x00, 0x00, 0x00,
260 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
261 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
262 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
263 0x26, 2, 0xaa, 0xaa,
264 0x2e, 1, 0x31,
265 0x38, 1, 0x01,
266 0x3a, 3, 0x14, 0xff, 0x5a,
267 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
268 0x00, 0x54, 0x11,
269 0x55, 1, 0x00,
270 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
271 0x6b, 1, 0x00,
272 0x6e, 3, 0x08, 0x06, 0x00,
273 0x72, 3, 0x00, 0xff, 0x00,
274 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
275 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
276 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
277 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
278 0xd2, 0xeb,
279 0xaf, 1, 0x02,
280 0xb5, 2, 0x08, 0x08,
281 0xb8, 2, 0x08, 0x88,
282 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
283 0xcc, 1, 0x00,
284 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
285 0xc1, 0xd7, 0xec,
286 0xdc, 1, 0x01,
285a4f6c 287 0xff, 1, 0x01, /* page 1 */
49b57dba
JFM
288 0x12, 3, 0x02, 0x00, 0x01,
289 0x3e, 2, 0x00, 0x00,
290 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
291 0x7c, 1, 0x00,
292 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
293 0x02, 0x00,
294 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
285a4f6c 295 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
49b57dba 296 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
285a4f6c 297 0xd8, 1, 0x01,
49b57dba 298 0xdb, 2, 0x00, 0x01,
285a4f6c 299 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
49b57dba
JFM
300 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
301 0xeb, 1, 0x00,
285a4f6c 302 0xff, 1, 0x02, /* page 2 */
49b57dba 303 0x22, 1, 0x00,
285a4f6c 304 0xff, 1, 0x03, /* page 3 */
49b57dba
JFM
305 0x00, 255, /* load the page 3 */
306 0x11, 1, 0x01,
285a4f6c 307 0xff, 1, 0x02, /* page 2 */
49b57dba
JFM
308 0x13, 1, 0x00,
309 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
310 0x27, 2, 0x14, 0x0c,
311 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
312 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
313 0x6e, 1, 0x08,
327c4abf 314 0xff, 1, 0x01, /* page 1 */
49b57dba
JFM
315 0x78, 1, 0x00,
316 0, 0 /* end of sequence */
317};
318
319/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
320static const __u8 page3_7302[] = {
321 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
322 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
323 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
325 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
326 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
327 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
328 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
331 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
335 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
336 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
337 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
340 0x00
341};
342
343/* pac 7311 */
271315a9 344static const __u8 init_7311[] = {
327c4abf
HG
345 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
346 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
347 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
49b57dba
JFM
348 0xff, 0x04,
349 0x27, 0x80,
350 0x28, 0xca,
351 0x29, 0x53,
352 0x2a, 0x0e,
353 0xff, 0x01,
354 0x3e, 0x20,
355};
356
357static const __u8 start_7311[] = {
358/* index, len, [value]* */
285a4f6c
JFM
359 0xff, 1, 0x01, /* page 1 */
360 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
49b57dba
JFM
361 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
362 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
363 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00,
285a4f6c 366 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
49b57dba
JFM
367 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
368 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
369 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
370 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
371 0xd0, 0xff,
372 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
373 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
374 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
375 0x18, 0x20,
376 0x96, 3, 0x01, 0x08, 0x04,
377 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
378 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
379 0x3f, 0x00, 0x0a, 0x01, 0x00,
285a4f6c 380 0xff, 1, 0x04, /* page 4 */
49b57dba
JFM
381 0x00, 254, /* load the page 4 */
382 0x11, 1, 0x01,
383 0, 0 /* end of sequence */
384};
385
386/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
387static const __u8 page4_7311[] = {
388 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
389 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
390 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
8a5b2e90 392 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
49b57dba
JFM
393 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
394 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
395};
396
739570bb 397static void reg_w_buf(struct gspca_dev *gspca_dev,
49b57dba
JFM
398 __u8 index,
399 const char *buffer, int len)
6a7eba24 400{
739570bb
JFM
401 memcpy(gspca_dev->usb_buf, buffer, len);
402 usb_control_msg(gspca_dev->dev,
403 usb_sndctrlpipe(gspca_dev->dev, 0),
bf7f0b98 404 1, /* request */
6a7eba24 405 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
bf7f0b98 406 0, /* value */
739570bb 407 index, gspca_dev->usb_buf, len,
6a7eba24
JFM
408 500);
409}
410
6a7eba24 411
739570bb 412static void reg_w(struct gspca_dev *gspca_dev,
49b57dba 413 __u8 index,
739570bb 414 __u8 value)
6a7eba24 415{
739570bb
JFM
416 gspca_dev->usb_buf[0] = value;
417 usb_control_msg(gspca_dev->dev,
418 usb_sndctrlpipe(gspca_dev->dev, 0),
bf7f0b98
JFM
419 0, /* request */
420 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
8a5b2e90 421 0, index, gspca_dev->usb_buf, 1,
bf7f0b98 422 500);
6a7eba24
JFM
423}
424
49b57dba
JFM
425static void reg_w_seq(struct gspca_dev *gspca_dev,
426 const __u8 *seq, int len)
427{
428 while (--len >= 0) {
429 reg_w(gspca_dev, seq[0], seq[1]);
430 seq += 2;
431 }
432}
433
434/* load the beginning of a page */
435static void reg_w_page(struct gspca_dev *gspca_dev,
436 const __u8 *page, int len)
437{
438 int index;
439
440 for (index = 0; index < len; index++) {
441 if (page[index] == 0xaa) /* skip this index */
442 continue;
443 gspca_dev->usb_buf[0] = page[index];
444 usb_control_msg(gspca_dev->dev,
445 usb_sndctrlpipe(gspca_dev->dev, 0),
446 0, /* request */
447 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
448 0, index, gspca_dev->usb_buf, 1,
449 500);
450 }
451}
452
453/* output a variable sequence */
454static void reg_w_var(struct gspca_dev *gspca_dev,
455 const __u8 *seq)
456{
457 int index, len;
458
459 for (;;) {
460 index = *seq++;
461 len = *seq++;
462 switch (len) {
463 case 0:
464 return;
465 case 254:
466 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
467 break;
468 case 255:
469 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
470 break;
471 default:
327c4abf 472 if (len > 64) {
49b57dba
JFM
473 PDEBUG(D_ERR|D_STREAM,
474 "Incorrect variable sequence");
475 return;
476 }
477 while (len > 0) {
478 if (len < 8) {
479 reg_w_buf(gspca_dev, index, seq, len);
480 seq += len;
481 break;
482 }
483 reg_w_buf(gspca_dev, index, seq, 8);
484 seq += 8;
485 index += 8;
486 len -= 8;
487 }
488 }
489 }
490 /* not reached */
491}
492
6a7eba24
JFM
493/* this function is called at probe time */
494static int sd_config(struct gspca_dev *gspca_dev,
495 const struct usb_device_id *id)
496{
497 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24
JFM
498 struct cam *cam;
499
6a7eba24 500 cam = &gspca_dev->cam;
6a7eba24 501 cam->epaddr = 0x05;
49b57dba
JFM
502
503 sd->sensor = id->driver_info;
504 if (sd->sensor == SENSOR_PAC7302) {
505 PDEBUG(D_CONF, "Find Sensor PAC7302");
49b57dba
JFM
506 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
507 cam->nmodes = 1;
508 } else {
509 PDEBUG(D_CONF, "Find Sensor PAC7311");
49b57dba
JFM
510 cam->cam_mode = vga_mode;
511 cam->nmodes = ARRAY_SIZE(vga_mode);
8a5b2e90
HG
512 gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
513 | (1 << SATURATION_IDX);
49b57dba 514 }
6a7eba24 515
a5ae2062
JFM
516 sd->brightness = BRIGHTNESS_DEF;
517 sd->contrast = CONTRAST_DEF;
518 sd->colors = COLOR_DEF;
8a5b2e90
HG
519 sd->gain = GAIN_DEF;
520 sd->exposure = EXPOSURE_DEF;
a5ae2062 521 sd->autogain = AUTOGAIN_DEF;
4a18625e
JFM
522 sd->hflip = HFLIP_DEF;
523 sd->vflip = VFLIP_DEF;
6a7eba24
JFM
524 return 0;
525}
526
8a5b2e90 527/* This function is used by pac7302 only */
dff6d321
JFM
528static void setbrightcont(struct gspca_dev *gspca_dev)
529{
530 struct sd *sd = (struct sd *) gspca_dev;
531 int i, v;
532 static const __u8 max[10] =
533 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
534 0xd4, 0xec};
535 static const __u8 delta[10] =
536 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
537 0x11, 0x0b};
538
539 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
540 for (i = 0; i < 10; i++) {
541 v = max[i];
542 v += (sd->brightness - BRIGHTNESS_MAX)
543 * 150 / BRIGHTNESS_MAX; /* 200 ? */
544 v -= delta[i] * sd->contrast / CONTRAST_MAX;
545 if (v < 0)
546 v = 0;
547 else if (v > 0xff)
548 v = 0xff;
549 reg_w(gspca_dev, 0xa2 + i, v);
550 }
551 reg_w(gspca_dev, 0xdc, 0x01);
552}
553
8a5b2e90
HG
554/* This function is used by pac7311 only */
555static void setcontrast(struct gspca_dev *gspca_dev)
6a7eba24
JFM
556{
557 struct sd *sd = (struct sd *) gspca_dev;
327c4abf 558
739570bb 559 reg_w(gspca_dev, 0xff, 0x04);
8a5b2e90 560 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
6a7eba24 561 /* load registers to sensor (Bit 0, auto clear) */
739570bb 562 reg_w(gspca_dev, 0x11, 0x01);
6a7eba24
JFM
563}
564
8a5b2e90
HG
565/* This function is used by pac7302 only */
566static void setcolors(struct gspca_dev *gspca_dev)
567{
568 struct sd *sd = (struct sd *) gspca_dev;
569 int i, v;
570 static const int a[9] =
571 {217, -212, 0, -101, 170, -67, -38, -315, 355};
572 static const int b[9] =
573 {19, 106, 0, 19, 106, 1, 19, 106, 1};
574
575 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
576 reg_w(gspca_dev, 0x11, 0x01);
577 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
578 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
579 for (i = 0; i < 9; i++) {
580 v = a[i] * sd->colors / COLOR_MAX + b[i];
581 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
582 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
583 }
584 reg_w(gspca_dev, 0xdc, 0x01);
585 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
586}
587
588static void setgain(struct gspca_dev *gspca_dev)
6a7eba24
JFM
589{
590 struct sd *sd = (struct sd *) gspca_dev;
591
dff6d321 592 if (sd->sensor == SENSOR_PAC7302) {
8a5b2e90
HG
593 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
594 reg_w(gspca_dev, 0x10, sd->gain >> 3);
595 } else {
596 int gain = GAIN_MAX - sd->gain;
597 if (gain < 1)
598 gain = 1;
599 else if (gain > 245)
600 gain = 245;
601 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
602 reg_w(gspca_dev, 0x0e, 0x00);
603 reg_w(gspca_dev, 0x0f, gain);
dff6d321 604 }
6a7eba24 605 /* load registers to sensor (Bit 0, auto clear) */
739570bb 606 reg_w(gspca_dev, 0x11, 0x01);
6a7eba24
JFM
607}
608
8a5b2e90 609static void setexposure(struct gspca_dev *gspca_dev)
6a7eba24
JFM
610{
611 struct sd *sd = (struct sd *) gspca_dev;
8a5b2e90
HG
612 __u8 reg;
613
614 /* register 2 of frame 3/4 contains the clock divider configuring the
615 no fps according to the formula: 60 / reg. sd->exposure is the
616 desired exposure time in ms. */
617 reg = 120 * sd->exposure / 1000;
618 if (reg < 2)
619 reg = 2;
620 else if (reg > 63)
621 reg = 63;
6a7eba24 622
41b46974 623 if (sd->sensor == SENSOR_PAC7302) {
8a5b2e90 624 /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
038ec7c7
HG
625 the nearest multiple of 3, except when between 6 and 12? */
626 if (reg < 6 || reg > 12)
627 reg = ((reg + 1) / 3) * 3;
8a5b2e90
HG
628 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
629 reg_w(gspca_dev, 0x02, reg);
630 } else {
631 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
632 reg_w(gspca_dev, 0x02, reg);
633 /* Page 1 register 8 must always be 0x08 except when not in
634 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
635 reg_w(gspca_dev, 0xff, 0x01);
636 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
637 reg <= 3)
638 reg_w(gspca_dev, 0x08, 0x09);
639 else
640 reg_w(gspca_dev, 0x08, 0x08);
41b46974 641 }
8a5b2e90
HG
642 /* load registers to sensor (Bit 0, auto clear) */
643 reg_w(gspca_dev, 0x11, 0x01);
6a7eba24
JFM
644}
645
41b46974
JFM
646static void sethvflip(struct gspca_dev *gspca_dev)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649 __u8 data;
650
327c4abf
HG
651 if (sd->sensor == SENSOR_PAC7302) {
652 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
8a5b2e90 653 data = (sd->hflip ? 0x08 : 0x00)
327c4abf
HG
654 | (sd->vflip ? 0x04 : 0x00);
655 } else {
8a5b2e90 656 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
327c4abf
HG
657 data = (sd->hflip ? 0x04 : 0x00)
658 | (sd->vflip ? 0x08 : 0x00);
659 }
41b46974 660 reg_w(gspca_dev, 0x21, data);
8a5b2e90 661 /* load registers to sensor (Bit 0, auto clear) */
41b46974
JFM
662 reg_w(gspca_dev, 0x11, 0x01);
663}
664
012d6b02
JFM
665/* this function is called at probe and resume time */
666static int sd_init(struct gspca_dev *gspca_dev)
6a7eba24 667{
271315a9
HG
668 struct sd *sd = (struct sd *) gspca_dev;
669
670 if (sd->sensor == SENSOR_PAC7302)
671 reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
672 else
673 reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
674
6a7eba24
JFM
675 return 0;
676}
677
72ab97ce 678static int sd_start(struct gspca_dev *gspca_dev)
6a7eba24 679{
e52a5574
JFM
680 struct sd *sd = (struct sd *) gspca_dev;
681
327c4abf 682 sd->sof_read = 0;
739570bb 683
8a5b2e90 684 if (sd->sensor == SENSOR_PAC7302) {
49b57dba 685 reg_w_var(gspca_dev, start_7302);
8a5b2e90
HG
686 setbrightcont(gspca_dev);
687 setcolors(gspca_dev);
688 } else {
49b57dba 689 reg_w_var(gspca_dev, start_7311);
8a5b2e90
HG
690 setcontrast(gspca_dev);
691 }
692 setgain(gspca_dev);
693 setexposure(gspca_dev);
694 sethvflip(gspca_dev);
6a7eba24
JFM
695
696 /* set correct resolution */
c2446b3e 697 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
49b57dba 698 case 2: /* 160x120 pac7311 */
739570bb 699 reg_w(gspca_dev, 0xff, 0x01);
739570bb 700 reg_w(gspca_dev, 0x17, 0x20);
739570bb 701 reg_w(gspca_dev, 0x87, 0x10);
6a7eba24 702 break;
49b57dba 703 case 1: /* 320x240 pac7311 */
739570bb 704 reg_w(gspca_dev, 0xff, 0x01);
739570bb 705 reg_w(gspca_dev, 0x17, 0x30);
739570bb 706 reg_w(gspca_dev, 0x87, 0x11);
6a7eba24
JFM
707 break;
708 case 0: /* 640x480 */
49b57dba
JFM
709 if (sd->sensor == SENSOR_PAC7302)
710 break;
739570bb 711 reg_w(gspca_dev, 0xff, 0x01);
739570bb 712 reg_w(gspca_dev, 0x17, 0x00);
739570bb 713 reg_w(gspca_dev, 0x87, 0x12);
6a7eba24
JFM
714 break;
715 }
716
327c4abf
HG
717 sd->sof_read = 0;
718 sd->autogain_ignore_frames = 0;
719 atomic_set(&sd->avg_lum, -1);
8a5b2e90
HG
720
721 /* start stream */
722 reg_w(gspca_dev, 0xff, 0x01);
723 if (sd->sensor == SENSOR_PAC7302)
724 reg_w(gspca_dev, 0x78, 0x01);
725 else
726 reg_w(gspca_dev, 0x78, 0x05);
72ab97ce 727 return 0;
6a7eba24
JFM
728}
729
730static void sd_stopN(struct gspca_dev *gspca_dev)
731{
49b57dba
JFM
732 struct sd *sd = (struct sd *) gspca_dev;
733
734 if (sd->sensor == SENSOR_PAC7302) {
327c4abf 735 reg_w(gspca_dev, 0xff, 0x01);
49b57dba
JFM
736 reg_w(gspca_dev, 0x78, 0x00);
737 reg_w(gspca_dev, 0x78, 0x00);
738 return;
739 }
739570bb
JFM
740 reg_w(gspca_dev, 0xff, 0x04);
741 reg_w(gspca_dev, 0x27, 0x80);
742 reg_w(gspca_dev, 0x28, 0xca);
743 reg_w(gspca_dev, 0x29, 0x53);
744 reg_w(gspca_dev, 0x2a, 0x0e);
745 reg_w(gspca_dev, 0xff, 0x01);
746 reg_w(gspca_dev, 0x3e, 0x20);
327c4abf
HG
747 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
748 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
749 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
6a7eba24
JFM
750}
751
752static void sd_stop0(struct gspca_dev *gspca_dev)
753{
49b57dba
JFM
754 struct sd *sd = (struct sd *) gspca_dev;
755
756 if (sd->sensor == SENSOR_PAC7302) {
757 reg_w(gspca_dev, 0xff, 0x01);
758 reg_w(gspca_dev, 0x78, 0x40);
759 }
6a7eba24
JFM
760}
761
8a5b2e90
HG
762/* Include pac common sof detection functions */
763#include "pac_common.h"
764
cebf3b67 765static void do_autogain(struct gspca_dev *gspca_dev)
6a7eba24 766{
8a5b2e90
HG
767 struct sd *sd = (struct sd *) gspca_dev;
768 int avg_lum = atomic_read(&sd->avg_lum);
038ec7c7 769 int desired_lum, deadzone;
8a5b2e90
HG
770
771 if (avg_lum == -1)
772 return;
773
038ec7c7
HG
774 if (sd->sensor == SENSOR_PAC7302) {
775 desired_lum = 270 + sd->brightness * 4;
776 /* Hack hack, with the 7202 the first exposure step is
777 pretty large, so if we're about to make the first
778 exposure increase make the deadzone large to avoid
779 oscilating */
780 if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
781 sd->exposure > EXPOSURE_DEF &&
782 sd->exposure < 42)
783 deadzone = 90;
784 else
785 deadzone = 30;
786 } else {
8a5b2e90 787 desired_lum = 200;
038ec7c7
HG
788 deadzone = 20;
789 }
8a5b2e90
HG
790
791 if (sd->autogain_ignore_frames > 0)
792 sd->autogain_ignore_frames--;
793 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
038ec7c7 794 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
8a5b2e90 795 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
6a7eba24
JFM
796}
797
327c4abf
HG
798static const unsigned char pac7311_jpeg_header1[] = {
799 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
800};
801
802static const unsigned char pac7311_jpeg_header2[] = {
803 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
804 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
805};
806
e52a5574 807/* this function is run at interrupt level */
6a7eba24
JFM
808static void sd_pkt_scan(struct gspca_dev *gspca_dev,
809 struct gspca_frame *frame, /* target */
a5ae2062 810 __u8 *data, /* isoc packet */
6a7eba24
JFM
811 int len) /* iso packet length */
812{
813 struct sd *sd = (struct sd *) gspca_dev;
327c4abf
HG
814 unsigned char *sof;
815
816 sof = pac_find_sof(gspca_dev, data, len);
817 if (sof) {
818 unsigned char tmpbuf[4];
819 int n, lum_offset, footer_length;
820
821 if (sd->sensor == SENSOR_PAC7302) {
038ec7c7
HG
822 /* 6 bytes after the FF D9 EOF marker a number of lumination
823 bytes are send corresponding to different parts of the
824 image, the 14th and 15th byte after the EOF seem to
825 correspond to the center of the image */
826 lum_offset = 61 + sizeof pac_sof_marker;
327c4abf
HG
827 footer_length = 74;
828 } else {
829 lum_offset = 24 + sizeof pac_sof_marker;
830 footer_length = 26;
831 }
832
833 /* Finish decoding current frame */
834 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
835 if (n < 0) {
836 frame->data_end += n;
837 n = 0;
838 }
839 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
840 data, n);
841 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
842 frame->data_end[-2] == 0xff &&
843 frame->data_end[-1] == 0xd9)
844 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
845 NULL, 0);
846
847 n = sof - data;
848 len -= n;
849 data = sof;
850
851 /* Get average lumination */
852 if (gspca_dev->last_packet_type == LAST_PACKET &&
038ec7c7
HG
853 n >= lum_offset)
854 atomic_set(&sd->avg_lum, data[-lum_offset] +
327c4abf 855 data[-lum_offset + 1]);
038ec7c7 856 else
327c4abf 857 atomic_set(&sd->avg_lum, -1);
327c4abf
HG
858
859 /* Start the new frame with the jpeg header */
860 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
861 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
862 if (sd->sensor == SENSOR_PAC7302) {
863 /* The PAC7302 has the image rotated 90 degrees */
864 tmpbuf[0] = gspca_dev->width >> 8;
865 tmpbuf[1] = gspca_dev->width & 0xff;
866 tmpbuf[2] = gspca_dev->height >> 8;
867 tmpbuf[3] = gspca_dev->height & 0xff;
868 } else {
869 tmpbuf[0] = gspca_dev->height >> 8;
870 tmpbuf[1] = gspca_dev->height & 0xff;
871 tmpbuf[2] = gspca_dev->width >> 8;
872 tmpbuf[3] = gspca_dev->width & 0xff;
873 }
874 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
875 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
876 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
6a7eba24 877 }
327c4abf 878 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
6a7eba24
JFM
879}
880
6a7eba24
JFM
881static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
882{
883 struct sd *sd = (struct sd *) gspca_dev;
884
885 sd->brightness = val;
886 if (gspca_dev->streaming)
8a5b2e90 887 setbrightcont(gspca_dev);
6a7eba24
JFM
888 return 0;
889}
890
891static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
892{
893 struct sd *sd = (struct sd *) gspca_dev;
894
6a7eba24
JFM
895 *val = sd->brightness;
896 return 0;
897}
898
899static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
900{
901 struct sd *sd = (struct sd *) gspca_dev;
902
903 sd->contrast = val;
8a5b2e90
HG
904 if (gspca_dev->streaming) {
905 if (sd->sensor == SENSOR_PAC7302)
906 setbrightcont(gspca_dev);
907 else
908 setcontrast(gspca_dev);
909 }
6a7eba24
JFM
910 return 0;
911}
912
913static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
914{
915 struct sd *sd = (struct sd *) gspca_dev;
916
6a7eba24
JFM
917 *val = sd->contrast;
918 return 0;
919}
920
921static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
922{
923 struct sd *sd = (struct sd *) gspca_dev;
924
925 sd->colors = val;
926 if (gspca_dev->streaming)
927 setcolors(gspca_dev);
928 return 0;
929}
930
931static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
932{
933 struct sd *sd = (struct sd *) gspca_dev;
934
6a7eba24
JFM
935 *val = sd->colors;
936 return 0;
937}
938
8a5b2e90
HG
939static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
940{
941 struct sd *sd = (struct sd *) gspca_dev;
942
943 sd->gain = val;
944 if (gspca_dev->streaming)
945 setgain(gspca_dev);
946 return 0;
947}
948
949static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
950{
951 struct sd *sd = (struct sd *) gspca_dev;
952
953 *val = sd->gain;
954 return 0;
955}
956
957static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
958{
959 struct sd *sd = (struct sd *) gspca_dev;
960
961 sd->exposure = val;
962 if (gspca_dev->streaming)
963 setexposure(gspca_dev);
964 return 0;
965}
966
967static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
968{
969 struct sd *sd = (struct sd *) gspca_dev;
970
971 *val = sd->exposure;
972 return 0;
973}
974
6a7eba24
JFM
975static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
976{
977 struct sd *sd = (struct sd *) gspca_dev;
978
979 sd->autogain = val;
8a5b2e90
HG
980 /* when switching to autogain set defaults to make sure
981 we are on a valid point of the autogain gain /
982 exposure knee graph, and give this change time to
983 take effect before doing autogain. */
984 if (sd->autogain) {
985 sd->exposure = EXPOSURE_DEF;
986 sd->gain = GAIN_DEF;
987 if (gspca_dev->streaming) {
988 sd->autogain_ignore_frames =
989 PAC_AUTOGAIN_IGNORE_FRAMES;
990 setexposure(gspca_dev);
991 setgain(gspca_dev);
992 }
993 }
327c4abf 994
6a7eba24
JFM
995 return 0;
996}
997
998static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
999{
1000 struct sd *sd = (struct sd *) gspca_dev;
1001
1002 *val = sd->autogain;
1003 return 0;
1004}
1005
41b46974
JFM
1006static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1007{
1008 struct sd *sd = (struct sd *) gspca_dev;
1009
1010 sd->hflip = val;
1011 if (gspca_dev->streaming)
1012 sethvflip(gspca_dev);
1013 return 0;
1014}
1015
1016static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1017{
1018 struct sd *sd = (struct sd *) gspca_dev;
1019
1020 *val = sd->hflip;
1021 return 0;
1022}
1023
1024static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1025{
1026 struct sd *sd = (struct sd *) gspca_dev;
1027
1028 sd->vflip = val;
1029 if (gspca_dev->streaming)
1030 sethvflip(gspca_dev);
1031 return 0;
1032}
1033
1034static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1035{
1036 struct sd *sd = (struct sd *) gspca_dev;
1037
1038 *val = sd->vflip;
1039 return 0;
1040}
1041
6a7eba24
JFM
1042/* sub-driver description */
1043static struct sd_desc sd_desc = {
1044 .name = MODULE_NAME,
1045 .ctrls = sd_ctrls,
1046 .nctrls = ARRAY_SIZE(sd_ctrls),
1047 .config = sd_config,
012d6b02 1048 .init = sd_init,
6a7eba24
JFM
1049 .start = sd_start,
1050 .stopN = sd_stopN,
1051 .stop0 = sd_stop0,
6a7eba24 1052 .pkt_scan = sd_pkt_scan,
cebf3b67 1053 .dq_callback = do_autogain,
6a7eba24
JFM
1054};
1055
1056/* -- module initialisation -- */
6a7eba24 1057static __devinitdata struct usb_device_id device_table[] = {
49b57dba
JFM
1058 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
1059 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
1060 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
1061 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
1062 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
1063 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
1064 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
8a5b2e90 1065 {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
08627255 1066 {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
40f17a79 1067 {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
6a7eba24
JFM
1068 {}
1069};
1070MODULE_DEVICE_TABLE(usb, device_table);
1071
1072/* -- device connect -- */
1073static int sd_probe(struct usb_interface *intf,
1074 const struct usb_device_id *id)
1075{
1076 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1077 THIS_MODULE);
1078}
1079
1080static struct usb_driver sd_driver = {
1081 .name = MODULE_NAME,
1082 .id_table = device_table,
1083 .probe = sd_probe,
1084 .disconnect = gspca_disconnect,
6a709749
JFM
1085#ifdef CONFIG_PM
1086 .suspend = gspca_suspend,
1087 .resume = gspca_resume,
1088#endif
6a7eba24
JFM
1089};
1090
1091/* -- module insert / remove -- */
1092static int __init sd_mod_init(void)
1093{
1094 if (usb_register(&sd_driver) < 0)
1095 return -1;
10b0e96e 1096 PDEBUG(D_PROBE, "registered");
6a7eba24
JFM
1097 return 0;
1098}
1099static void __exit sd_mod_exit(void)
1100{
1101 usb_deregister(&sd_driver);
1102 PDEBUG(D_PROBE, "deregistered");
1103}
1104
1105module_init(sd_mod_init);
1106module_exit(sd_mod_exit);