blob: 02e274452c46239056b2095d907aa5f91c7b1563 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Sunplus spca561 subdriver
3 *
4 * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#define MODULE_NAME "spca561"
24
25#include "gspca.h"
26
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
35 unsigned short contrast;
36 __u8 brightness;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -030037 __u8 white;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030038 __u8 autogain;
39
40 __u8 chip_revision;
41 signed char ag_cnt;
42#define AG_CNT_START 13
43};
44
45/* V4L2 controls supported by the driver */
46static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
47static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
48static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
49static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -030050static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val);
51static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
53static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
54
55static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030056 {
57 {
58 .id = V4L2_CID_BRIGHTNESS,
59 .type = V4L2_CTRL_TYPE_INTEGER,
60 .name = "Brightness",
61 .minimum = 0,
62 .maximum = 63,
63 .step = 1,
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -030064#define BRIGHTNESS_DEF 32
65 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030066 },
67 .set = sd_setbrightness,
68 .get = sd_getbrightness,
69 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030070 {
71 {
72 .id = V4L2_CID_CONTRAST,
73 .type = V4L2_CTRL_TYPE_INTEGER,
74 .name = "Contrast",
75 .minimum = 0,
76 .maximum = 0x3fff,
77 .step = 1,
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -030078#define CONTRAST_DEF 0x2000
79 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080 },
81 .set = sd_setcontrast,
82 .get = sd_getcontrast,
83 },
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -030084 {
85 {
86 .id = V4L2_CID_DO_WHITE_BALANCE,
87 .type = V4L2_CTRL_TYPE_INTEGER,
88 .name = "While Balance",
89 .minimum = 0,
90 .maximum = 0x7f,
91 .step = 1,
92#define WHITE_DEF 40
93 .default_value = WHITE_DEF,
94 },
95 .set = sd_setwhite,
96 .get = sd_getwhite,
97 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098 {
99 {
100 .id = V4L2_CID_AUTOGAIN,
101 .type = V4L2_CTRL_TYPE_BOOLEAN,
102 .name = "Auto Gain",
103 .minimum = 0,
104 .maximum = 1,
105 .step = 1,
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300106#define AUTOGAIN_DEF 1
107 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 },
109 .set = sd_setautogain,
110 .get = sd_getautogain,
111 },
112};
113
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300114static struct v4l2_pix_format sif_mode[] = {
115 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
116 .bytesperline = 160,
117 .sizeimage = 160 * 120,
118 .colorspace = V4L2_COLORSPACE_SRGB,
119 .priv = 3},
120 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
121 .bytesperline = 176,
122 .sizeimage = 176 * 144,
123 .colorspace = V4L2_COLORSPACE_SRGB,
124 .priv = 2},
125 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
126 .bytesperline = 320,
127 .sizeimage = 320 * 240 * 4 / 8,
128 .colorspace = V4L2_COLORSPACE_SRGB,
129 .priv = 1},
130 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
131 .bytesperline = 352,
132 .sizeimage = 352 * 288 * 4 / 8,
133 .colorspace = V4L2_COLORSPACE_SRGB,
134 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300135};
136
137/*
138 * Initialization data
139 * I'm not very sure how to split initialization from open data
140 * chunks. For now, we'll consider everything as initialization
141 */
142/* Frame packet header offsets for the spca561 */
143#define SPCA561_OFFSET_SNAP 1
144#define SPCA561_OFFSET_TYPE 2
145#define SPCA561_OFFSET_COMPRESS 3
146#define SPCA561_OFFSET_FRAMSEQ 4
147#define SPCA561_OFFSET_GPIO 5
148#define SPCA561_OFFSET_USBBUFF 6
149#define SPCA561_OFFSET_WIN2GRAVE 7
150#define SPCA561_OFFSET_WIN2RAVE 8
151#define SPCA561_OFFSET_WIN2BAVE 9
152#define SPCA561_OFFSET_WIN2GBAVE 10
153#define SPCA561_OFFSET_WIN1GRAVE 11
154#define SPCA561_OFFSET_WIN1RAVE 12
155#define SPCA561_OFFSET_WIN1BAVE 13
156#define SPCA561_OFFSET_WIN1GBAVE 14
157#define SPCA561_OFFSET_FREQ 15
158#define SPCA561_OFFSET_VSYNC 16
159#define SPCA561_OFFSET_DATA 1
160#define SPCA561_INDEX_I2C_BASE 0x8800
161#define SPCA561_SNAPBIT 0x20
162#define SPCA561_SNAPCTRL 0x40
163enum {
164 Rev072A = 0,
165 Rev012A,
166};
167
168static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
169{
170 int ret;
171
172 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
173 0, /* request */
174 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
175 value, index, NULL, 0, 500);
176 PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
177 if (ret < 0)
178 PDEBUG(D_ERR, "reg write: error %d", ret);
179}
180
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300181static void write_vector(struct gspca_dev *gspca_dev,
182 const __u16 data[][2])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183{
184 struct usb_device *dev = gspca_dev->dev;
185 int i;
186
187 i = 0;
188 while (data[i][1] != 0) {
189 reg_w_val(dev, data[i][1], data[i][0]);
190 i++;
191 }
192}
193
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300194/* read 'len' bytes to gspca_dev->usb_buf */
195static void reg_r(struct gspca_dev *gspca_dev,
196 __u16 index, __u16 length)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300198 usb_control_msg(gspca_dev->dev,
199 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200 0, /* request */
201 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
202 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300203 index, gspca_dev->usb_buf, length, 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204}
205
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300206static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300207 __u16 index, const __u8 *buffer, __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300208{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300209 memcpy(gspca_dev->usb_buf, buffer, len);
210 usb_control_msg(gspca_dev->dev,
211 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300212 0, /* request */
213 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
214 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300215 index, gspca_dev->usb_buf, len, 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216}
217
218static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
219{
220 reg_w_val(gspca_dev->dev, 0x92, 0x8804);
221 reg_w_val(gspca_dev->dev, mode, 0x8802);
222}
223
224static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
225{
226 int retry = 60;
227 __u8 DataLow;
228 __u8 DataHight;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229
230 DataLow = valeur;
231 DataHight = valeur >> 8;
232 reg_w_val(gspca_dev->dev, reg, 0x8801);
233 reg_w_val(gspca_dev->dev, DataLow, 0x8805);
234 reg_w_val(gspca_dev->dev, DataHight, 0x8800);
235 while (retry--) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300236 reg_r(gspca_dev, 0x8803, 1);
237 if (!gspca_dev->usb_buf[0])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238 break;
239 }
240}
241
242static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
243{
244 int retry = 60;
245 __u8 value;
246 __u8 vallsb;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247
248 reg_w_val(gspca_dev->dev, 0x92, 0x8804);
249 reg_w_val(gspca_dev->dev, reg, 0x8801);
250 reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
251 while (retry--) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300252 reg_r(gspca_dev, 0x8803, 1);
253 if (!gspca_dev->usb_buf)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300254 break;
255 }
256 if (retry == 0)
257 return -1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300258 reg_r(gspca_dev, 0x8800, 1);
259 value = gspca_dev->usb_buf[0];
260 reg_r(gspca_dev, 0x8805, 1);
261 vallsb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300262 return ((int) value << 8) | vallsb;
263}
264
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300265static const __u16 spca561_init_data[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300266 {0x0000, 0x8114}, /* Software GPIO output data */
267 {0x0001, 0x8114}, /* Software GPIO output data */
268 {0x0000, 0x8112}, /* Some kind of reset */
269 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
270 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
271 {0x0011, 0x8118}, /* Enable and conf sensor */
272 {0x0001, 0x8118}, /* Conf sensor */
273 {0x0092, 0x8804}, /* I know nothing about these */
274 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
275 /***************/
276 {0x000d, 0x8805}, /* sensor default setting */
277 {0x0001, 0x8801}, /* 1 <- 0x0d */
278 {0x0000, 0x8800},
279 {0x0018, 0x8805},
280 {0x0002, 0x8801}, /* 2 <- 0x18 */
281 {0x0000, 0x8800},
282 {0x0065, 0x8805},
283 {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */
284 {0x0001, 0x8800},
285 {0x0021, 0x8805},
286 {0x0005, 0x8801}, /* 5 <- 0x21 */
287 {0x0000, 0x8800},
288 {0x00aa, 0x8805},
289 {0x0007, 0x8801}, /* 7 <- 0xaa */
290 {0x0000, 0x8800},
291 {0x0004, 0x8805},
292 {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */
293 {0x0015, 0x8800},
294 {0x0002, 0x8805},
295 {0x0039, 0x8801}, /* 0x39 <- 0x02 */
296 {0x0000, 0x8800},
297 {0x0010, 0x8805},
298 {0x0035, 0x8801}, /* 0x35 <- 0x10 */
299 {0x0000, 0x8800},
300 {0x0049, 0x8805},
301 {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */
302 {0x0010, 0x8800},
303 {0x000b, 0x8805},
304 {0x0028, 0x8801}, /* 0x28 <- 0x0b */
305 {0x0000, 0x8800},
306 {0x000f, 0x8805},
307 {0x003b, 0x8801}, /* 0x3b <- 0x0f */
308 {0x0000, 0x8800},
309 {0x0000, 0x8805},
310 {0x003c, 0x8801}, /* 0x3c <- 0x00 */
311 {0x0000, 0x8800},
312 /***************/
313 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
314 {0x0000, 0x8602}, /* Optical black level for user setting */
315 {0x0060, 0x8604}, /* Optical black horizontal offset */
316 {0x0002, 0x8605}, /* Optical black vertical offset */
317 {0x0000, 0x8603}, /* Non-automatic optical black level */
318 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
319 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
320 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
321 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
322 {0x00e0, 0x8406}, /* Memory buffer threshold */
323 {0x0000, 0x8660}, /* Compensation memory stuff */
324 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
325 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
326 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
327 {0x0007, 0x8201}, /* Output address for r/w serial EEPROM */
328 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
329 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
330 {0x0010, 0x8660}, /* Compensation memory stuff */
331 {0x0018, 0x8660}, /* Compensation memory stuff */
332
333 {0x0004, 0x8611}, /* R offset for white balance */
334 {0x0004, 0x8612}, /* Gr offset for white balance */
335 {0x0007, 0x8613}, /* B offset for white balance */
336 {0x0000, 0x8614}, /* Gb offset for white balance */
337 {0x008c, 0x8651}, /* R gain for white balance */
338 {0x008c, 0x8652}, /* Gr gain for white balance */
339 {0x00b5, 0x8653}, /* B gain for white balance */
340 {0x008c, 0x8654}, /* Gb gain for white balance */
341 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
342
343 {0x0011, 0x8802},
344 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
345 {0x0081, 0x8702}, /* Master clock output enable */
346
347 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
348 /* Originally was 0x0010 (352x288 compression) */
349
350 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
351 {0x0003, 0x865c}, /* Vertical offset for valid lines */
352 /***************//* sensor active */
353 {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */
354 {0x0021, 0x8805},
355 {0x0001, 0x8800},
356 {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */
357 {0x0065, 0x8805},
358 {0x0001, 0x8800},
359 {0x0005, 0x8801}, /* 0x05 <- 0x2f */
360 {0x002f, 0x8805},
361 {0x0000, 0x8800},
362 {0x0006, 0x8801}, /* 0x06 <- 0 */
363 {0x0000, 0x8805},
364 {0x0000, 0x8800},
365 {0x000a, 0x8801}, /* 0x0a <- 2 */
366 {0x0002, 0x8805},
367 {0x0000, 0x8800},
368 {0x0009, 0x8801}, /* 0x09 <- 0x1061 */
369 {0x0061, 0x8805},
370 {0x0010, 0x8800},
371 {0x0035, 0x8801}, /* 0x35 <-0x14 */
372 {0x0014, 0x8805},
373 {0x0000, 0x8800},
374 {0x0030, 0x8112}, /* ISO and drop packet enable */
375 {0x0000, 0x8112}, /* Some kind of reset ???? */
376 {0x0009, 0x8118}, /* Enable sensor and set standby */
377 {0x0000, 0x8114}, /* Software GPIO output data */
378 {0x0000, 0x8114}, /* Software GPIO output data */
379 {0x0001, 0x8114}, /* Software GPIO output data */
380 {0x0000, 0x8112}, /* Some kind of reset ??? */
381 {0x0003, 0x8701},
382 {0x0001, 0x8703},
383 {0x0011, 0x8118},
384 {0x0001, 0x8118},
385 /***************/
386 {0x0092, 0x8804},
387 {0x0010, 0x8802},
388 {0x000d, 0x8805},
389 {0x0001, 0x8801},
390 {0x0000, 0x8800},
391 {0x0018, 0x8805},
392 {0x0002, 0x8801},
393 {0x0000, 0x8800},
394 {0x0065, 0x8805},
395 {0x0004, 0x8801},
396 {0x0001, 0x8800},
397 {0x0021, 0x8805},
398 {0x0005, 0x8801},
399 {0x0000, 0x8800},
400 {0x00aa, 0x8805},
401 {0x0007, 0x8801}, /* mode 0xaa */
402 {0x0000, 0x8800},
403 {0x0004, 0x8805},
404 {0x0020, 0x8801},
405 {0x0015, 0x8800}, /* mode 0x0415 */
406 {0x0002, 0x8805},
407 {0x0039, 0x8801},
408 {0x0000, 0x8800},
409 {0x0010, 0x8805},
410 {0x0035, 0x8801},
411 {0x0000, 0x8800},
412 {0x0049, 0x8805},
413 {0x0009, 0x8801},
414 {0x0010, 0x8800},
415 {0x000b, 0x8805},
416 {0x0028, 0x8801},
417 {0x0000, 0x8800},
418 {0x000f, 0x8805},
419 {0x003b, 0x8801},
420 {0x0000, 0x8800},
421 {0x0000, 0x8805},
422 {0x003c, 0x8801},
423 {0x0000, 0x8800},
424 {0x0002, 0x8502},
425 {0x0039, 0x8801},
426 {0x0000, 0x8805},
427 {0x0000, 0x8800},
428
429 {0x0087, 0x8700}, /* overwrite by start */
430 {0x0081, 0x8702},
431 {0x0000, 0x8500},
432/* {0x0010, 0x8500}, -- Previous line was this */
433 {0x0002, 0x865b},
434 {0x0003, 0x865c},
435 /***************/
436 {0x0003, 0x8801}, /* 0x121-> 289 */
437 {0x0021, 0x8805},
438 {0x0001, 0x8800},
439 {0x0004, 0x8801}, /* 0x165 -> 357 */
440 {0x0065, 0x8805},
441 {0x0001, 0x8800},
442 {0x0005, 0x8801}, /* 0x2f //blanking control colonne */
443 {0x002f, 0x8805},
444 {0x0000, 0x8800},
445 {0x0006, 0x8801}, /* 0x00 //blanking mode row */
446 {0x0000, 0x8805},
447 {0x0000, 0x8800},
448 {0x000a, 0x8801}, /* 0x01 //0x02 */
449 {0x0001, 0x8805},
450 {0x0000, 0x8800},
451 {0x0009, 0x8801}, /* 0x1061 - setexposure times && pixel clock
452 * 0001 0 | 000 0110 0001 */
453 {0x0061, 0x8805}, /* 61 31 */
454 {0x0008, 0x8800}, /* 08 */
455 {0x0035, 0x8801}, /* 0x14 - set gain general */
456 {0x001f, 0x8805}, /* 0x14 */
457 {0x0000, 0x8800},
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300458 {0x000e, 0x8112}, /* white balance - was 30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300459 {}
460};
461
462static void sensor_reset(struct gspca_dev *gspca_dev)
463{
464 reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
465 reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
466 reg_w_val(gspca_dev->dev, 0x8112, 0x00);
467 reg_w_val(gspca_dev->dev, 0x8114, 0x00);
468 reg_w_val(gspca_dev->dev, 0x8118, 0x21);
469 i2c_init(gspca_dev, 0x14);
470 i2c_write(gspca_dev, 1, 0x0d);
471 i2c_write(gspca_dev, 0, 0x0d);
472}
473
474/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300475static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 /* reg, value */
477 {0x8320, 0x3304},
478
479 {0x8303, 0x0125}, /* image area */
480 {0x8304, 0x0169},
481 {0x8328, 0x000b},
482 {0x833c, 0x0001},
483
484 {0x832f, 0x0419},
485 {0x8307, 0x00aa},
486 {0x8301, 0x0003},
487 {0x8302, 0x000e},
488 {}
489};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300490static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 /* reg, value */
492 {0x8339, 0x0000},
493 {0x8307, 0x00aa},
494 {}
495};
496
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300497static const __u16 spca561_161rev12A_data1[][2] = {
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300498 {0x29, 0x8118}, /* white balance - was 21 */
499 {0x08, 0x8114}, /* white balance - was 01 */
500 {0x0e, 0x8112}, /* white balance - was 00 */
501 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300502 {0x92, 0x8804},
503 {0x04, 0x8802}, /* windows uses 08 */
504 {}
505};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300506static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 {0x21, 0x8118},
508 {0x10, 0x8500},
509 {0x07, 0x8601},
510 {0x07, 0x8602},
511 {0x04, 0x8501},
512 {0x21, 0x8118},
513
514 {0x07, 0x8201}, /* windows uses 02 */
515 {0x08, 0x8200},
516 {0x01, 0x8200},
517
518 {0x00, 0x8114},
519 {0x01, 0x8114}, /* windows uses 00 */
520
521 {0x90, 0x8604},
522 {0x00, 0x8605},
523 {0xb0, 0x8603},
524
525 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300526 {0x07, 0x8601}, /* white balance - new */
527 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 {0x00, 0x8610}, /* *red */
529 {0x00, 0x8611}, /* 3f *green */
530 {0x00, 0x8612}, /* green *blue */
531 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300532 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
533 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
534 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
535 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300536
537 {0x0c, 0x8620}, /* 0c */
538 {0xc8, 0x8631}, /* c8 */
539 {0xc8, 0x8634}, /* c8 */
540 {0x23, 0x8635}, /* 23 */
541 {0x1f, 0x8636}, /* 1f */
542 {0xdd, 0x8637}, /* dd */
543 {0xe1, 0x8638}, /* e1 */
544 {0x1d, 0x8639}, /* 1d */
545 {0x21, 0x863a}, /* 21 */
546 {0xe3, 0x863b}, /* e3 */
547 {0xdf, 0x863c}, /* df */
548 {0xf0, 0x8505},
549 {0x32, 0x850a},
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300550 {0x99, 0x8700}, /* - white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 {}
552};
553
554static void sensor_mapwrite(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300555 const __u16 sensormap[][2])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300556{
557 int i = 0;
558 __u8 usbval[2];
559
560 while (sensormap[i][0]) {
561 usbval[0] = sensormap[i][1];
562 usbval[1] = sensormap[i][1] >> 8;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300563 reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564 i++;
565 }
566}
567static void init_161rev12A(struct gspca_dev *gspca_dev)
568{
569 sensor_reset(gspca_dev);
570 write_vector(gspca_dev, spca561_161rev12A_data1);
571 sensor_mapwrite(gspca_dev, Pb100_1map8300);
572 write_vector(gspca_dev, spca561_161rev12A_data2);
573 sensor_mapwrite(gspca_dev, Pb100_2map8300);
574}
575
576/* this function is called at probe time */
577static int sd_config(struct gspca_dev *gspca_dev,
578 const struct usb_device_id *id)
579{
580 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 struct cam *cam;
582 __u16 vendor, product;
583 __u8 data1, data2;
584
585 /* Read frm global register the USB product and vendor IDs, just to
586 * prove that we can communicate with the device. This works, which
587 * confirms at we are communicating properly and that the device
588 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300589 reg_r(gspca_dev, 0x8104, 1);
590 data1 = gspca_dev->usb_buf[0];
591 reg_r(gspca_dev, 0x8105, 1);
592 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594 reg_r(gspca_dev, 0x8106, 1);
595 data1 = gspca_dev->usb_buf[0];
596 reg_r(gspca_dev, 0x8107, 1);
597 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300598 product = (data2 << 8) | data1;
599 if (vendor != id->idVendor || product != id->idProduct) {
600 PDEBUG(D_PROBE, "Bad vendor / product from device");
601 return -EINVAL;
602 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300603
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300604 cam = &gspca_dev->cam;
605 cam->dev_name = (char *) id->driver_info;
606 cam->epaddr = 0x01;
607 gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
608 cam->cam_mode = sif_mode;
609 cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300610
611 sd->chip_revision = id->driver_info;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300612 sd->brightness = BRIGHTNESS_DEF;
613 sd->contrast = CONTRAST_DEF;
614 sd->autogain = AUTOGAIN_DEF;
615 sd->white = WHITE_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300616 return 0;
617}
618
619/* this function is called at open time */
620static int sd_open(struct gspca_dev *gspca_dev)
621{
622 struct sd *sd = (struct sd *) gspca_dev;
623
624 switch (sd->chip_revision) {
625 case Rev072A:
626 PDEBUG(D_STREAM, "Chip revision id: 072a");
627 write_vector(gspca_dev, spca561_init_data);
628 break;
629 default:
630/* case Rev012A: */
631 PDEBUG(D_STREAM, "Chip revision id: 012a");
632 init_161rev12A(gspca_dev);
633 break;
634 }
635 return 0;
636}
637
638static void setcontrast(struct gspca_dev *gspca_dev)
639{
640 struct sd *sd = (struct sd *) gspca_dev;
641 struct usb_device *dev = gspca_dev->dev;
642 __u8 lowb;
643 int expotimes;
644
645 switch (sd->chip_revision) {
646 case Rev072A:
647 lowb = sd->contrast >> 8;
648 reg_w_val(dev, lowb, 0x8651);
649 reg_w_val(dev, lowb, 0x8652);
650 reg_w_val(dev, lowb, 0x8653);
651 reg_w_val(dev, lowb, 0x8654);
652 break;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300653 default: {
654/* case Rev012A: { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300655 __u8 Reg8391[] =
656 { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
657
658 /* Write camera sensor settings */
659 expotimes = (sd->contrast >> 5) & 0x07ff;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300660 /* exposure is in 8309 2b, range 0120 - 5720 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 Reg8391[0] = expotimes & 0xff; /* exposure */
662 Reg8391[1] = 0x18 | (expotimes >> 8);
663 Reg8391[2] = sd->brightness; /* gain */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300664 /* gain in 8335, 2b range 0000 - 2400 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300665 reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
666 reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 break;
668 }
669 }
670}
671
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300672static void setwhite(struct gspca_dev *gspca_dev)
673{
674 struct sd *sd = (struct sd *) gspca_dev;
675 __u16 white;
676 __u8 reg8614, reg8616;
677
678 switch (sd->chip_revision) {
679 case Rev072A:
680 /* no such hardware */
681 break;
682 default:
683/* case Rev012A: */
684 white = sd->white;
685 if (sd->white == 0) {
686 PDEBUG(D_CONF, "Discarding null whiteness");
687 break;
688 }
689 /* try to emulate MS-win as possible */
690 if (white < 0x45)
691 reg8616 = white;
692 else
693 reg8616 = 0x93 + (white >> 2);
694 reg8614 = 0x28 + (white >> 4);
695 reg_w_val(gspca_dev->dev, reg8616, 0x8616);
696 reg_w_val(gspca_dev->dev, reg8614, 0x8614);
697 }
698}
699
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300700static void setautogain(struct gspca_dev *gspca_dev)
701{
702 struct sd *sd = (struct sd *) gspca_dev;
703
704 if (sd->chip_revision == Rev072A) {
705 if (sd->autogain)
706 sd->ag_cnt = AG_CNT_START;
707 else
708 sd->ag_cnt = -1;
709 }
710}
711
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712static void sd_start(struct gspca_dev *gspca_dev)
713{
714 struct sd *sd = (struct sd *) gspca_dev;
715 struct usb_device *dev = gspca_dev->dev;
716 int Clck;
717 __u8 Reg8307[] = { 0xaa, 0x00 };
718 int mode;
719
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300720 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721 switch (sd->chip_revision) {
722 case Rev072A:
723 switch (mode) {
724 default:
725/* case 0:
726 case 1: */
727 Clck = 0x25;
728 break;
729 case 2:
730 Clck = 0x22;
731 break;
732 case 3:
733 Clck = 0x21;
734 break;
735 }
736 reg_w_val(dev, 0x8500, mode); /* mode */
737 reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
738 reg_w_val(dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300739 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300740 break;
741 default:
742/* case Rev012A: */
743 switch (mode) {
744 case 0:
745 case 1:
746 Clck = 0x8a;
747 break;
748 case 2:
749 Clck = 0x85;
750 break;
751 default:
752 Clck = 0x83;
753 break;
754 }
755 if (mode <= 1) {
756 /* Use compression on 320x240 and above */
757 reg_w_val(dev, 0x8500, 0x10 | mode);
758 } else {
759 /* I couldn't get the compression to work below 320x240
760 * Fortunately at these resolutions the bandwidth
761 * is sufficient to push raw frames at ~20fps */
762 reg_w_val(dev, 0x8500, mode);
763 } /* -- qq@kuku.eu.org */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300764 reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
765 reg_w_val(gspca_dev->dev, 0x8700, Clck);
766 /* 0x8f 0x85 0x27 clock */
767 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
768 reg_w_val(gspca_dev->dev, 0x850b, 0x03);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769 setcontrast(gspca_dev);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300770 setwhite(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 break;
772 }
773}
774
775static void sd_stopN(struct gspca_dev *gspca_dev)
776{
777 reg_w_val(gspca_dev->dev, 0x8112, 0x20);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300778 reg_w_val(gspca_dev->dev, 0x8102, 0x00); /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300779}
780
781static void sd_stop0(struct gspca_dev *gspca_dev)
782{
783}
784
785/* this function is called at close time */
786static void sd_close(struct gspca_dev *gspca_dev)
787{
788 reg_w_val(gspca_dev->dev, 0x8114, 0);
789}
790
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300791static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792{
793 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300794 int expotimes;
795 int pixelclk;
796 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797 __u8 R, Gr, Gb, B;
798 int y;
799 __u8 luma_mean = 110;
800 __u8 luma_delta = 20;
801 __u8 spring = 4;
802
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300803 if (sd->ag_cnt < 0)
804 return;
805 if (--sd->ag_cnt >= 0)
806 return;
807 sd->ag_cnt = AG_CNT_START;
808
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300809 switch (sd->chip_revision) {
810 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300811 reg_r(gspca_dev, 0x8621, 1);
812 Gr = gspca_dev->usb_buf[0];
813 reg_r(gspca_dev, 0x8622, 1);
814 R = gspca_dev->usb_buf[0];
815 reg_r(gspca_dev, 0x8623, 1);
816 B = gspca_dev->usb_buf[0];
817 reg_r(gspca_dev, 0x8624, 1);
818 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300819 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
820 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
821 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
822 /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
823
824 if (y < luma_mean - luma_delta ||
825 y > luma_mean + luma_delta) {
826 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
827 pixelclk = 0x0800;
828 expotimes = expotimes & 0x07ff;
829 /* PDEBUG(D_PACK,
830 "Exposition Times 0x%03X Clock 0x%04X ",
831 expotimes,pixelclk); */
832 gainG = i2c_read(gspca_dev, 0x35, 0x10);
833 /* PDEBUG(D_PACK,
834 "reading Gain register %d", gainG); */
835
836 expotimes += (luma_mean - y) >> spring;
837 gainG += (luma_mean - y) / 50;
838 /* PDEBUG(D_PACK,
839 "compute expotimes %d gain %d",
840 expotimes,gainG); */
841
842 if (gainG > 0x3f)
843 gainG = 0x3f;
844 else if (gainG < 4)
845 gainG = 3;
846 i2c_write(gspca_dev, gainG, 0x35);
847
848 if (expotimes >= 0x0256)
849 expotimes = 0x0256;
850 else if (expotimes < 4)
851 expotimes = 3;
852 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
853 }
854 break;
855 case Rev012A:
856 /* sensor registers is access and memory mapped to 0x8300 */
857 /* readind all 0x83xx block the sensor */
858 /*
859 * The data from the header seem wrong where is the luma
860 * and chroma mean value
861 * at the moment set exposure in contrast set
862 */
863 break;
864 }
865}
866
867static void sd_pkt_scan(struct gspca_dev *gspca_dev,
868 struct gspca_frame *frame, /* target */
869 __u8 *data, /* isoc packet */
870 int len) /* iso packet length */
871{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 switch (data[0]) {
873 case 0: /* start of frame */
874 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
875 data, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300876 data += SPCA561_OFFSET_DATA;
877 len -= SPCA561_OFFSET_DATA;
878 if (data[1] & 0x10) {
879 /* compressed bayer */
880 gspca_frame_add(gspca_dev, FIRST_PACKET,
881 frame, data, len);
882 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300883 /* raw bayer (with a header, which we skip) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884 data += 20;
885 len -= 20;
886 gspca_frame_add(gspca_dev, FIRST_PACKET,
887 frame, data, len);
888 }
889 return;
890 case 0xff: /* drop */
891/* gspca_dev->last_packet_type = DISCARD_PACKET; */
892 return;
893 }
894 data++;
895 len--;
896 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
897}
898
899static void setbrightness(struct gspca_dev *gspca_dev)
900{
901 struct sd *sd = (struct sd *) gspca_dev;
902 __u8 value;
903
904 switch (sd->chip_revision) {
905 case Rev072A:
906 value = sd->brightness;
907 reg_w_val(gspca_dev->dev, value, 0x8611);
908 reg_w_val(gspca_dev->dev, value, 0x8612);
909 reg_w_val(gspca_dev->dev, value, 0x8613);
910 reg_w_val(gspca_dev->dev, value, 0x8614);
911 break;
912 default:
913/* case Rev012A: */
914 setcontrast(gspca_dev);
915 break;
916 }
917}
918
919static void getbrightness(struct gspca_dev *gspca_dev)
920{
921 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 __u16 tot;
923
924 switch (sd->chip_revision) {
925 case Rev072A:
926 tot = 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300927 reg_r(gspca_dev, 0x8611, 1);
928 tot += gspca_dev->usb_buf[0];
929 reg_r(gspca_dev, 0x8612, 1);
930 tot += gspca_dev->usb_buf[0];
931 reg_r(gspca_dev, 0x8613, 1);
932 tot += gspca_dev->usb_buf[0];
933 reg_r(gspca_dev, 0x8614, 1);
934 tot += gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300935 sd->brightness = tot >> 2;
936 break;
937 default:
938/* case Rev012A: */
939 /* no way to read sensor settings */
940 break;
941 }
942}
943
944static void getcontrast(struct gspca_dev *gspca_dev)
945{
946 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947 __u16 tot;
948
949 switch (sd->chip_revision) {
950 case Rev072A:
951 tot = 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300952 reg_r(gspca_dev, 0x8651, 1);
953 tot += gspca_dev->usb_buf[0];
954 reg_r(gspca_dev, 0x8652, 1);
955 tot += gspca_dev->usb_buf[0];
956 reg_r(gspca_dev, 0x8653, 1);
957 tot += gspca_dev->usb_buf[0];
958 reg_r(gspca_dev, 0x8654, 1);
959 tot += gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300960 sd->contrast = tot << 6;
961 break;
962 default:
963/* case Rev012A: */
964 /* no way to read sensor settings */
965 break;
966 }
967 PDEBUG(D_CONF, "get contrast %d", sd->contrast);
968}
969
970static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
971{
972 struct sd *sd = (struct sd *) gspca_dev;
973
974 sd->brightness = val;
975 if (gspca_dev->streaming)
976 setbrightness(gspca_dev);
977 return 0;
978}
979
980static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
981{
982 struct sd *sd = (struct sd *) gspca_dev;
983
984 getbrightness(gspca_dev);
985 *val = sd->brightness;
986 return 0;
987}
988
989static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
990{
991 struct sd *sd = (struct sd *) gspca_dev;
992
993 sd->contrast = val;
994 if (gspca_dev->streaming)
995 setcontrast(gspca_dev);
996 return 0;
997}
998
999static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1000{
1001 struct sd *sd = (struct sd *) gspca_dev;
1002
1003 getcontrast(gspca_dev);
1004 *val = sd->contrast;
1005 return 0;
1006}
1007
1008static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1009{
1010 struct sd *sd = (struct sd *) gspca_dev;
1011
1012 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001013 if (gspca_dev->streaming)
1014 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 return 0;
1016}
1017
1018static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1019{
1020 struct sd *sd = (struct sd *) gspca_dev;
1021
1022 *val = sd->autogain;
1023 return 0;
1024}
1025
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -03001026/* white balance - new */
1027static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
1028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030
1031 sd->white = val;
1032 if (gspca_dev->streaming)
1033 setwhite(gspca_dev);
1034 return 0;
1035}
1036
1037static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
1038{
1039 struct sd *sd = (struct sd *) gspca_dev;
1040
1041 *val = sd->white;
1042 return 0;
1043}
1044
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001046static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047 .name = MODULE_NAME,
1048 .ctrls = sd_ctrls,
1049 .nctrls = ARRAY_SIZE(sd_ctrls),
1050 .config = sd_config,
1051 .open = sd_open,
1052 .start = sd_start,
1053 .stopN = sd_stopN,
1054 .stop0 = sd_stop0,
1055 .close = sd_close,
1056 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001057 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001058};
1059
1060/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001061static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001062 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
1063 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
1064 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
1065 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
1066 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
1067 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
1068 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
1069 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
1070 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
1071 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
1072 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
1073 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
1074 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
1075 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
1076 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001077 {}
1078};
1079
1080MODULE_DEVICE_TABLE(usb, device_table);
1081
1082/* -- device connect -- */
1083static int sd_probe(struct usb_interface *intf,
1084 const struct usb_device_id *id)
1085{
1086 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1087 THIS_MODULE);
1088}
1089
1090static struct usb_driver sd_driver = {
1091 .name = MODULE_NAME,
1092 .id_table = device_table,
1093 .probe = sd_probe,
1094 .disconnect = gspca_disconnect,
1095};
1096
1097/* -- module insert / remove -- */
1098static int __init sd_mod_init(void)
1099{
1100 if (usb_register(&sd_driver) < 0)
1101 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001102 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103 return 0;
1104}
1105static void __exit sd_mod_exit(void)
1106{
1107 usb_deregister(&sd_driver);
1108 PDEBUG(D_PROBE, "deregistered");
1109}
1110
1111module_init(sd_mod_init);
1112module_exit(sd_mod_exit);