blob: b9c80e2103b9c99a1f76dae1406e6006c00464d1 [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
Jean-Francois Moine7879d452008-09-03 16:47:32 -030035 __u16 exposure; /* rev12a only */
Hans de Goede0fc23d22008-09-04 16:22:57 -030036#define EXPOSURE_MIN 1
Hans de Goeded0848eb2009-05-25 15:20:16 -030037#define EXPOSURE_DEF 700 /* == 10 fps */
38#define EXPOSURE_MAX (2047 + 325) /* see setexposure */
Jean-Francois Moine7879d452008-09-03 16:47:32 -030039
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030040 __u8 contrast; /* rev72a only */
41#define CONTRAST_MIN 0x00
42#define CONTRAST_DEF 0x20
43#define CONTRAST_MAX 0x3f
44
Jean-Francois Moine7879d452008-09-03 16:47:32 -030045 __u8 brightness; /* rev72a only */
46#define BRIGHTNESS_MIN 0
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030047#define BRIGHTNESS_DEF 0x20
48#define BRIGHTNESS_MAX 0x3f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030049
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030050 __u8 white;
Hans de Goede9035f2e2009-05-25 15:26:59 -030051#define HUE_MIN 1
52#define HUE_DEF 0x40
53#define HUE_MAX 0x7f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030054
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055 __u8 autogain;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030056#define AUTOGAIN_MIN 0
57#define AUTOGAIN_DEF 1
58#define AUTOGAIN_MAX 1
59
60 __u8 gain; /* rev12a only */
Hans de Goeded0848eb2009-05-25 15:20:16 -030061#define GAIN_MIN 0
62#define GAIN_DEF 63
63#define GAIN_MAX 255
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064
Jean-Francois Moined698dc62008-09-03 16:47:51 -030065#define EXPO12A_DEF 3
66 __u8 expo12a; /* expo/gain? for rev 12a */
67
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068 __u8 chip_revision;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030069#define Rev012A 0
70#define Rev072A 1
71
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030072 signed char ag_cnt;
73#define AG_CNT_START 13
74};
75
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030076static const struct v4l2_pix_format sif_012a_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030077 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
78 .bytesperline = 160,
79 .sizeimage = 160 * 120,
80 .colorspace = V4L2_COLORSPACE_SRGB,
81 .priv = 3},
82 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
83 .bytesperline = 176,
84 .sizeimage = 176 * 144,
85 .colorspace = V4L2_COLORSPACE_SRGB,
86 .priv = 2},
87 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
88 .bytesperline = 320,
89 .sizeimage = 320 * 240 * 4 / 8,
90 .colorspace = V4L2_COLORSPACE_SRGB,
91 .priv = 1},
92 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
93 .bytesperline = 352,
94 .sizeimage = 352 * 288 * 4 / 8,
95 .colorspace = V4L2_COLORSPACE_SRGB,
96 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097};
98
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030099static const struct v4l2_pix_format sif_072a_mode[] = {
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300100 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
101 .bytesperline = 160,
102 .sizeimage = 160 * 120,
103 .colorspace = V4L2_COLORSPACE_SRGB,
104 .priv = 3},
105 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
106 .bytesperline = 176,
107 .sizeimage = 176 * 144,
108 .colorspace = V4L2_COLORSPACE_SRGB,
109 .priv = 2},
110 {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
111 .bytesperline = 320,
112 .sizeimage = 320 * 240,
113 .colorspace = V4L2_COLORSPACE_SRGB,
114 .priv = 1},
115 {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
116 .bytesperline = 352,
117 .sizeimage = 352 * 288,
118 .colorspace = V4L2_COLORSPACE_SRGB,
119 .priv = 0},
120};
121
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300122/*
123 * Initialization data
124 * I'm not very sure how to split initialization from open data
125 * chunks. For now, we'll consider everything as initialization
126 */
127/* Frame packet header offsets for the spca561 */
128#define SPCA561_OFFSET_SNAP 1
129#define SPCA561_OFFSET_TYPE 2
130#define SPCA561_OFFSET_COMPRESS 3
131#define SPCA561_OFFSET_FRAMSEQ 4
132#define SPCA561_OFFSET_GPIO 5
133#define SPCA561_OFFSET_USBBUFF 6
134#define SPCA561_OFFSET_WIN2GRAVE 7
135#define SPCA561_OFFSET_WIN2RAVE 8
136#define SPCA561_OFFSET_WIN2BAVE 9
137#define SPCA561_OFFSET_WIN2GBAVE 10
138#define SPCA561_OFFSET_WIN1GRAVE 11
139#define SPCA561_OFFSET_WIN1RAVE 12
140#define SPCA561_OFFSET_WIN1BAVE 13
141#define SPCA561_OFFSET_WIN1GBAVE 14
142#define SPCA561_OFFSET_FREQ 15
143#define SPCA561_OFFSET_VSYNC 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300144#define SPCA561_INDEX_I2C_BASE 0x8800
145#define SPCA561_SNAPBIT 0x20
146#define SPCA561_SNAPCTRL 0x40
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300148static const u16 rev72a_reset[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 {0x0000, 0x8114}, /* Software GPIO output data */
150 {0x0001, 0x8114}, /* Software GPIO output data */
151 {0x0000, 0x8112}, /* Some kind of reset */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300152 {}
153};
154static const __u16 rev72a_init_data1[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
156 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
157 {0x0011, 0x8118}, /* Enable and conf sensor */
158 {0x0001, 0x8118}, /* Conf sensor */
159 {0x0092, 0x8804}, /* I know nothing about these */
160 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300161 {}
162};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300163static const u16 rev72a_init_sensor1[][2] = {
164 {0x0001, 0x000d},
165 {0x0002, 0x0018},
166 {0x0004, 0x0165},
167 {0x0005, 0x0021},
168 {0x0007, 0x00aa},
169 {0x0020, 0x1504},
170 {0x0039, 0x0002},
171 {0x0035, 0x0010},
172 {0x0009, 0x1049},
173 {0x0028, 0x000b},
174 {0x003b, 0x000f},
175 {0x003c, 0x0000},
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300176 {}
177};
178static const __u16 rev72a_init_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300179 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
180 {0x0000, 0x8602}, /* Optical black level for user setting */
181 {0x0060, 0x8604}, /* Optical black horizontal offset */
182 {0x0002, 0x8605}, /* Optical black vertical offset */
183 {0x0000, 0x8603}, /* Non-automatic optical black level */
184 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
185 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
186 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
187 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
188 {0x00e0, 0x8406}, /* Memory buffer threshold */
189 {0x0000, 0x8660}, /* Compensation memory stuff */
190 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
191 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
192 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300193/* from ms-win */
194 {0x0000, 0x8611}, /* R offset for white balance */
195 {0x00fd, 0x8612}, /* Gr offset for white balance */
196 {0x0003, 0x8613}, /* B offset for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197 {0x0000, 0x8614}, /* Gb offset for white balance */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300198/* from ms-win */
199 {0x0035, 0x8651}, /* R gain for white balance */
200 {0x0040, 0x8652}, /* Gr gain for white balance */
201 {0x005f, 0x8653}, /* B gain for white balance */
202 {0x0040, 0x8654}, /* Gb gain for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 {0x0011, 0x8802},
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300205
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300206 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
207 {0x0081, 0x8702}, /* Master clock output enable */
208
209 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
210 /* Originally was 0x0010 (352x288 compression) */
211
212 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
213 {0x0003, 0x865c}, /* Vertical offset for valid lines */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300214 {}
215};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300216static const u16 rev72a_init_sensor2[][2] = {
217 {0x0003, 0x0121},
218 {0x0004, 0x0165},
219 {0x0005, 0x002f}, /* blanking control column */
220 {0x0006, 0x0000}, /* blanking mode row*/
221 {0x000a, 0x0002},
222 {0x0009, 0x1061}, /* setexposure times && pixel clock
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300223 * 0001 0 | 000 0110 0001 */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300224 {0x0035, 0x0014},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300225 {}
226};
227
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300229static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300230 /* reg, value */
231 {0x8320, 0x3304},
232
233 {0x8303, 0x0125}, /* image area */
234 {0x8304, 0x0169},
235 {0x8328, 0x000b},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300236 {0x833c, 0x0001}, /*fixme: win:07*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300238 {0x832f, 0x1904}, /*fixme: was 0419*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300239 {0x8307, 0x00aa},
240 {0x8301, 0x0003},
241 {0x8302, 0x000e},
242 {}
243};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300244static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300245 /* reg, value */
246 {0x8339, 0x0000},
247 {0x8307, 0x00aa},
248 {}
249};
250
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300251static const __u16 spca561_161rev12A_data1[][2] = {
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300252 {0x29, 0x8118}, /* white balance - was 21 */
253 {0x08, 0x8114}, /* white balance - was 01 */
254 {0x0e, 0x8112}, /* white balance - was 00 */
255 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300256 {0x92, 0x8804},
257 {0x04, 0x8802}, /* windows uses 08 */
258 {}
259};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300260static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300261 {0x21, 0x8118},
262 {0x10, 0x8500},
263 {0x07, 0x8601},
264 {0x07, 0x8602},
265 {0x04, 0x8501},
266 {0x21, 0x8118},
267
268 {0x07, 0x8201}, /* windows uses 02 */
269 {0x08, 0x8200},
270 {0x01, 0x8200},
271
272 {0x00, 0x8114},
273 {0x01, 0x8114}, /* windows uses 00 */
274
275 {0x90, 0x8604},
276 {0x00, 0x8605},
277 {0xb0, 0x8603},
278
279 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300280 {0x07, 0x8601}, /* white balance - new */
281 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282 {0x00, 0x8610}, /* *red */
283 {0x00, 0x8611}, /* 3f *green */
284 {0x00, 0x8612}, /* green *blue */
285 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300286 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
287 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
288 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
289 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290
291 {0x0c, 0x8620}, /* 0c */
292 {0xc8, 0x8631}, /* c8 */
293 {0xc8, 0x8634}, /* c8 */
294 {0x23, 0x8635}, /* 23 */
295 {0x1f, 0x8636}, /* 1f */
296 {0xdd, 0x8637}, /* dd */
297 {0xe1, 0x8638}, /* e1 */
298 {0x1d, 0x8639}, /* 1d */
299 {0x21, 0x863a}, /* 21 */
300 {0xe3, 0x863b}, /* e3 */
301 {0xdf, 0x863c}, /* df */
302 {0xf0, 0x8505},
303 {0x32, 0x850a},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300304/* {0x99, 0x8700}, * - white balance - new (removed) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300305 {}
306};
307
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300308static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300310 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300312 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
313 0, /* request */
314 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
315 value, index, NULL, 0, 500);
316 PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
317 if (ret < 0)
318 PDEBUG(D_ERR, "reg write: error %d", ret);
319}
320
321static void write_vector(struct gspca_dev *gspca_dev,
322 const __u16 data[][2])
323{
324 struct usb_device *dev = gspca_dev->dev;
325 int i;
326
327 i = 0;
328 while (data[i][1] != 0) {
329 reg_w_val(dev, data[i][1], data[i][0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330 i++;
331 }
332}
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300333
334/* read 'len' bytes to gspca_dev->usb_buf */
335static void reg_r(struct gspca_dev *gspca_dev,
336 __u16 index, __u16 length)
337{
338 usb_control_msg(gspca_dev->dev,
339 usb_rcvctrlpipe(gspca_dev->dev, 0),
340 0, /* request */
341 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
342 0, /* value */
343 index, gspca_dev->usb_buf, length, 500);
344}
345
346/* write 'len' bytes from gspca_dev->usb_buf */
347static void reg_w_buf(struct gspca_dev *gspca_dev,
348 __u16 index, __u16 len)
349{
350 usb_control_msg(gspca_dev->dev,
351 usb_sndctrlpipe(gspca_dev->dev, 0),
352 0, /* request */
353 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
354 0, /* value */
355 index, gspca_dev->usb_buf, len, 500);
356}
357
358static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
359{
360 int retry = 60;
361
362 reg_w_val(gspca_dev->dev, 0x8801, reg);
363 reg_w_val(gspca_dev->dev, 0x8805, value);
364 reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
365 do {
366 reg_r(gspca_dev, 0x8803, 1);
367 if (!gspca_dev->usb_buf[0])
368 return;
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300369 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300370 } while (--retry);
371}
372
373static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
374{
375 int retry = 60;
376 __u8 value;
377
378 reg_w_val(gspca_dev->dev, 0x8804, 0x92);
379 reg_w_val(gspca_dev->dev, 0x8801, reg);
380 reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
381 do {
382 reg_r(gspca_dev, 0x8803, 1);
383 if (!gspca_dev->usb_buf[0]) {
384 reg_r(gspca_dev, 0x8800, 1);
385 value = gspca_dev->usb_buf[0];
386 reg_r(gspca_dev, 0x8805, 1);
387 return ((int) value << 8) | gspca_dev->usb_buf[0];
388 }
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300389 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300390 } while (--retry);
391 return -1;
392}
393
394static void sensor_mapwrite(struct gspca_dev *gspca_dev,
395 const __u16 (*sensormap)[2])
396{
397 while ((*sensormap)[0]) {
398 gspca_dev->usb_buf[0] = (*sensormap)[1];
399 gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
400 reg_w_buf(gspca_dev, (*sensormap)[0], 2);
401 sensormap++;
402 }
403}
404
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300405static void write_sensor_72a(struct gspca_dev *gspca_dev,
406 const __u16 (*sensor)[2])
407{
408 while ((*sensor)[0]) {
409 i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
410 sensor++;
411 }
412}
413
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414static void init_161rev12A(struct gspca_dev *gspca_dev)
415{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416 write_vector(gspca_dev, spca561_161rev12A_data1);
417 sensor_mapwrite(gspca_dev, Pb100_1map8300);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300418/*fixme: should be in sd_start*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419 write_vector(gspca_dev, spca561_161rev12A_data2);
420 sensor_mapwrite(gspca_dev, Pb100_2map8300);
421}
422
423/* this function is called at probe time */
424static int sd_config(struct gspca_dev *gspca_dev,
425 const struct usb_device_id *id)
426{
427 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428 struct cam *cam;
429 __u16 vendor, product;
430 __u8 data1, data2;
431
432 /* Read frm global register the USB product and vendor IDs, just to
433 * prove that we can communicate with the device. This works, which
434 * confirms at we are communicating properly and that the device
435 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300436 reg_r(gspca_dev, 0x8104, 1);
437 data1 = gspca_dev->usb_buf[0];
438 reg_r(gspca_dev, 0x8105, 1);
439 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300440 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300441 reg_r(gspca_dev, 0x8106, 1);
442 data1 = gspca_dev->usb_buf[0];
443 reg_r(gspca_dev, 0x8107, 1);
444 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445 product = (data2 << 8) | data1;
446 if (vendor != id->idVendor || product != id->idProduct) {
447 PDEBUG(D_PROBE, "Bad vendor / product from device");
448 return -EINVAL;
449 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300450
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300452 gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300453
454 sd->chip_revision = id->driver_info;
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300455 if (sd->chip_revision == Rev012A) {
456 cam->cam_mode = sif_012a_mode;
457 cam->nmodes = ARRAY_SIZE(sif_012a_mode);
458 } else {
459 cam->cam_mode = sif_072a_mode;
460 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
461 }
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300462 sd->brightness = BRIGHTNESS_DEF;
463 sd->contrast = CONTRAST_DEF;
Hans de Goede9035f2e2009-05-25 15:26:59 -0300464 sd->white = HUE_DEF;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300465 sd->exposure = EXPOSURE_DEF;
466 sd->autogain = AUTOGAIN_DEF;
467 sd->gain = GAIN_DEF;
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300468 sd->expo12a = EXPO12A_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 return 0;
470}
471
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300472/* this function is called at probe and resume time */
473static int sd_init_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300475 PDEBUG(D_STREAM, "Chip revision: 012a");
476 init_161rev12A(gspca_dev);
477 return 0;
478}
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300479static int sd_init_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300480{
481 PDEBUG(D_STREAM, "Chip revision: 072a");
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300482 write_vector(gspca_dev, rev72a_reset);
483 msleep(200);
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300484 write_vector(gspca_dev, rev72a_init_data1);
485 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
486 write_vector(gspca_dev, rev72a_init_data2);
487 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300488 reg_w_val(gspca_dev->dev, 0x8112, 0x30);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 return 0;
490}
491
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300492/* rev 72a only */
493static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494{
495 struct sd *sd = (struct sd *) gspca_dev;
496 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300497 __u8 value;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300499 value = sd->brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300501 /* offsets for white balance */
502 reg_w_val(dev, 0x8611, value); /* R */
503 reg_w_val(dev, 0x8612, value); /* Gr */
504 reg_w_val(dev, 0x8613, value); /* B */
505 reg_w_val(dev, 0x8614, value); /* Gb */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506}
507
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300508static void setwhite(struct gspca_dev *gspca_dev)
509{
510 struct sd *sd = (struct sd *) gspca_dev;
511 __u16 white;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300512 __u8 blue, red;
513 __u16 reg;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300514
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300515 /* try to emulate MS-win as possible */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300516 white = sd->white;
517 red = 0x20 + white * 3 / 8;
518 blue = 0x90 - white * 5 / 8;
519 if (sd->chip_revision == Rev012A) {
520 reg = 0x8614;
521 } else {
522 reg = 0x8651;
523 red += sd->contrast - 0x20;
524 blue += sd->contrast - 0x20;
525 }
526 reg_w_val(gspca_dev->dev, reg, red);
527 reg_w_val(gspca_dev->dev, reg + 2, blue);
528}
529
530static void setcontrast(struct gspca_dev *gspca_dev)
531{
532 struct sd *sd = (struct sd *) gspca_dev;
533 struct usb_device *dev = gspca_dev->dev;
534 __u8 value;
535
536 if (sd->chip_revision != Rev072A)
537 return;
538 value = sd->contrast + 0x20;
539
540 /* gains for white balance */
541 setwhite(gspca_dev);
542/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */
543 reg_w_val(dev, 0x8652, value); /* Gr */
544/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */
545 reg_w_val(dev, 0x8654, value); /* Gb */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300546}
547
548/* rev 12a only */
549static void setexposure(struct gspca_dev *gspca_dev)
550{
551 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300552 int i, expo = 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300553
Hans de Goede0fc23d22008-09-04 16:22:57 -0300554 /* Register 0x8309 controls exposure for the spca561,
555 the basic exposure setting goes from 1-2047, where 1 is completely
556 dark and 2047 is very bright. It not only influences exposure but
557 also the framerate (to allow for longer exposure) from 1 - 300 it
558 only raises the exposure time then from 300 - 600 it halves the
559 framerate to be able to further raise the exposure time and for every
560 300 more it halves the framerate again. This allows for a maximum
561 exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
562 Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
563 configure a divider for the base framerate which us used at the
564 exposure setting of 1-300. These bits configure the base framerate
565 according to the following formula: fps = 60 / (value + 2) */
Hans de Goeded0848eb2009-05-25 15:20:16 -0300566
567 /* We choose to use the high bits setting the fixed framerate divisor
568 asap, as setting high basic exposure setting without the fixed
569 divider in combination with high gains makes the cam stop */
570 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
571
572 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
573 if (sd->exposure <= table[i + 1]) {
574 expo = sd->exposure - table[i];
575 if (i)
576 expo += 300;
577 expo |= i << 11;
578 break;
579 }
Hans de Goede0fc23d22008-09-04 16:22:57 -0300580 }
Hans de Goeded0848eb2009-05-25 15:20:16 -0300581
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300582 gspca_dev->usb_buf[0] = expo;
583 gspca_dev->usb_buf[1] = expo >> 8;
584 reg_w_buf(gspca_dev, 0x8309, 2);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300585}
586
587/* rev 12a only */
588static void setgain(struct gspca_dev *gspca_dev)
589{
590 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300591
Hans de Goeded0848eb2009-05-25 15:20:16 -0300592 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
593 sensitivity when set, so 31 + one of them set == 63, and 15
594 with both of them set == 63 */
595 if (sd->gain < 64)
596 gspca_dev->usb_buf[0] = sd->gain;
597 else if (sd->gain < 128)
598 gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
599 else
600 gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
601
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300602 gspca_dev->usb_buf[1] = 0;
603 reg_w_buf(gspca_dev, 0x8335, 2);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300604}
605
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300606static void setautogain(struct gspca_dev *gspca_dev)
607{
608 struct sd *sd = (struct sd *) gspca_dev;
609
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300610 if (sd->autogain)
611 sd->ag_cnt = AG_CNT_START;
612 else
613 sd->ag_cnt = -1;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300614}
615
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300616static int sd_start_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300618 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619 int mode;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300620 static const __u8 Reg8391[8] =
621 {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300622
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300623 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300624 if (mode <= 1) {
625 /* Use compression on 320x240 and above */
626 reg_w_val(dev, 0x8500, 0x10 | mode);
627 } else {
628 /* I couldn't get the compression to work below 320x240
629 * Fortunately at these resolutions the bandwidth
630 * is sufficient to push raw frames at ~20fps */
631 reg_w_val(dev, 0x8500, mode);
632 } /* -- qq@kuku.eu.org */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300633
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300634 gspca_dev->usb_buf[0] = 0xaa;
635 gspca_dev->usb_buf[1] = 0x00;
636 reg_w_buf(gspca_dev, 0x8307, 2);
637 /* clock - lower 0x8X values lead to fps > 30 */
638 reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300639 /* 0x8f 0x85 0x27 clock */
640 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
641 reg_w_val(gspca_dev->dev, 0x850b, 0x03);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300642 memcpy(gspca_dev->usb_buf, Reg8391, 8);
643 reg_w_buf(gspca_dev, 0x8391, 8);
644 reg_w_buf(gspca_dev, 0x8390, 8);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300645 setwhite(gspca_dev);
Hans de Goeded0848eb2009-05-25 15:20:16 -0300646 setgain(gspca_dev);
Hans de Goede0fc23d22008-09-04 16:22:57 -0300647 setexposure(gspca_dev);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300648 return 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300649}
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300650static int sd_start_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300651{
652 struct usb_device *dev = gspca_dev->dev;
653 int Clck;
654 int mode;
655
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300656 write_vector(gspca_dev, rev72a_reset);
657 msleep(200);
658 write_vector(gspca_dev, rev72a_init_data1);
659 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
660
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300661 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
662 switch (mode) {
663 default:
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300664 case 0:
665 Clck = 0x27; /* ms-win 0x87 */
666 break;
667 case 1:
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300668 Clck = 0x25;
669 break;
670 case 2:
671 Clck = 0x22;
672 break;
673 case 3:
674 Clck = 0x21;
675 break;
676 }
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300677 reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300678 reg_w_val(dev, 0x8702, 0x81);
679 reg_w_val(dev, 0x8500, mode); /* mode */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300680 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300681 setcontrast(gspca_dev);
682/* setbrightness(gspca_dev); * fixme: bad values */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300683 setautogain(gspca_dev);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300684 reg_w_val(dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300685 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686}
687
688static void sd_stopN(struct gspca_dev *gspca_dev)
689{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300690 struct sd *sd = (struct sd *) gspca_dev;
691
692 if (sd->chip_revision == Rev012A) {
693 reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
694 } else {
695 reg_w_val(gspca_dev->dev, 0x8112, 0x20);
696/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
697 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698}
699
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300700/* called on streamoff with alt 0 and on disconnect */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701static void sd_stop0(struct gspca_dev *gspca_dev)
702{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300703 struct sd *sd = (struct sd *) gspca_dev;
704
Jean-Francois Moine98522a72008-11-18 06:33:08 -0300705 if (!gspca_dev->present)
706 return;
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300707 if (sd->chip_revision == Rev012A) {
708 reg_w_val(gspca_dev->dev, 0x8118, 0x29);
709 reg_w_val(gspca_dev->dev, 0x8114, 0x08);
710 }
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300711/* reg_w_val(gspca_dev->dev, 0x8114, 0); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712}
713
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300714static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715{
716 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300717 int expotimes;
718 int pixelclk;
719 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720 __u8 R, Gr, Gb, B;
721 int y;
722 __u8 luma_mean = 110;
723 __u8 luma_delta = 20;
724 __u8 spring = 4;
725
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300726 if (sd->ag_cnt < 0)
727 return;
728 if (--sd->ag_cnt >= 0)
729 return;
730 sd->ag_cnt = AG_CNT_START;
731
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732 switch (sd->chip_revision) {
733 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300734 reg_r(gspca_dev, 0x8621, 1);
735 Gr = gspca_dev->usb_buf[0];
736 reg_r(gspca_dev, 0x8622, 1);
737 R = gspca_dev->usb_buf[0];
738 reg_r(gspca_dev, 0x8623, 1);
739 B = gspca_dev->usb_buf[0];
740 reg_r(gspca_dev, 0x8624, 1);
741 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
743 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
744 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
745 /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
746
747 if (y < luma_mean - luma_delta ||
748 y > luma_mean + luma_delta) {
749 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
750 pixelclk = 0x0800;
751 expotimes = expotimes & 0x07ff;
752 /* PDEBUG(D_PACK,
753 "Exposition Times 0x%03X Clock 0x%04X ",
754 expotimes,pixelclk); */
755 gainG = i2c_read(gspca_dev, 0x35, 0x10);
756 /* PDEBUG(D_PACK,
757 "reading Gain register %d", gainG); */
758
759 expotimes += (luma_mean - y) >> spring;
760 gainG += (luma_mean - y) / 50;
761 /* PDEBUG(D_PACK,
762 "compute expotimes %d gain %d",
763 expotimes,gainG); */
764
765 if (gainG > 0x3f)
766 gainG = 0x3f;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300767 else if (gainG < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300768 gainG = 3;
769 i2c_write(gspca_dev, gainG, 0x35);
770
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300771 if (expotimes > 0x0256)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772 expotimes = 0x0256;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300773 else if (expotimes < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300774 expotimes = 3;
775 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
776 }
777 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300778 }
779}
780
781static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300782 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 int len) /* iso packet length */
784{
Hans de Goede0fc23d22008-09-04 16:22:57 -0300785 struct sd *sd = (struct sd *) gspca_dev;
786
Jean-Francois Moine576ed7b2009-01-16 08:57:28 -0300787 len--;
788 switch (*data++) { /* sequence number */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300789 case 0: /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300790 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791 if (data[1] & 0x10) {
792 /* compressed bayer */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300793 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300795 /* raw bayer (with a header, which we skip) */
Hans de Goede0fc23d22008-09-04 16:22:57 -0300796 if (sd->chip_revision == Rev012A) {
797 data += 20;
798 len -= 20;
799 } else {
800 data += 16;
801 len -= 16;
802 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300803 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 }
805 return;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300806 case 0xff: /* drop (empty mpackets) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 return;
808 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300809 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300810}
811
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300812/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
814{
815 struct sd *sd = (struct sd *) gspca_dev;
816
817 sd->brightness = val;
818 if (gspca_dev->streaming)
819 setbrightness(gspca_dev);
820 return 0;
821}
822
823static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
824{
825 struct sd *sd = (struct sd *) gspca_dev;
826
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 *val = sd->brightness;
828 return 0;
829}
830
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300831/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300832static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
833{
834 struct sd *sd = (struct sd *) gspca_dev;
835
836 sd->contrast = val;
837 if (gspca_dev->streaming)
838 setcontrast(gspca_dev);
839 return 0;
840}
841
842static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
843{
844 struct sd *sd = (struct sd *) gspca_dev;
845
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846 *val = sd->contrast;
847 return 0;
848}
849
850static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
851{
852 struct sd *sd = (struct sd *) gspca_dev;
853
854 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300855 if (gspca_dev->streaming)
856 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 return 0;
858}
859
860static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
861{
862 struct sd *sd = (struct sd *) gspca_dev;
863
864 *val = sd->autogain;
865 return 0;
866}
867
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300868static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
869{
870 struct sd *sd = (struct sd *) gspca_dev;
871
872 sd->white = val;
873 if (gspca_dev->streaming)
874 setwhite(gspca_dev);
875 return 0;
876}
877
878static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
879{
880 struct sd *sd = (struct sd *) gspca_dev;
881
882 *val = sd->white;
883 return 0;
884}
885
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300886/* rev12a only */
887static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
888{
889 struct sd *sd = (struct sd *) gspca_dev;
890
891 sd->exposure = val;
892 if (gspca_dev->streaming)
893 setexposure(gspca_dev);
894 return 0;
895}
896
897static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
898{
899 struct sd *sd = (struct sd *) gspca_dev;
900
901 *val = sd->exposure;
902 return 0;
903}
904
905/* rev12a only */
906static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
907{
908 struct sd *sd = (struct sd *) gspca_dev;
909
910 sd->gain = val;
911 if (gspca_dev->streaming)
912 setgain(gspca_dev);
913 return 0;
914}
915
916static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
917{
918 struct sd *sd = (struct sd *) gspca_dev;
919
920 *val = sd->gain;
921 return 0;
922}
923
924/* control tables */
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300925static const struct ctrl sd_ctrls_12a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300926 {
927 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300928 .id = V4L2_CID_HUE,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300929 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300930 .name = "Hue",
931 .minimum = HUE_MIN,
932 .maximum = HUE_MAX,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300933 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300934 .default_value = HUE_DEF,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300935 },
936 .set = sd_setwhite,
937 .get = sd_getwhite,
938 },
939 {
940 {
941 .id = V4L2_CID_EXPOSURE,
942 .type = V4L2_CTRL_TYPE_INTEGER,
943 .name = "Exposure",
944 .minimum = EXPOSURE_MIN,
945 .maximum = EXPOSURE_MAX,
946 .step = 1,
947 .default_value = EXPOSURE_DEF,
948 },
949 .set = sd_setexposure,
950 .get = sd_getexposure,
951 },
952 {
953 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300954 .id = V4L2_CID_GAIN,
955 .type = V4L2_CTRL_TYPE_INTEGER,
956 .name = "Gain",
957 .minimum = GAIN_MIN,
958 .maximum = GAIN_MAX,
959 .step = 1,
960 .default_value = GAIN_DEF,
961 },
962 .set = sd_setgain,
963 .get = sd_getgain,
964 },
965};
966
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300967static const struct ctrl sd_ctrls_72a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300968 {
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300969 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300970 .id = V4L2_CID_HUE,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300971 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300972 .name = "Hue",
973 .minimum = HUE_MIN,
974 .maximum = HUE_MAX,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300975 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300976 .default_value = HUE_DEF,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300977 },
978 .set = sd_setwhite,
979 .get = sd_getwhite,
980 },
981 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300982 {
983 .id = V4L2_CID_BRIGHTNESS,
984 .type = V4L2_CTRL_TYPE_INTEGER,
985 .name = "Brightness",
986 .minimum = BRIGHTNESS_MIN,
987 .maximum = BRIGHTNESS_MAX,
988 .step = 1,
989 .default_value = BRIGHTNESS_DEF,
990 },
991 .set = sd_setbrightness,
992 .get = sd_getbrightness,
993 },
994 {
995 {
996 .id = V4L2_CID_CONTRAST,
997 .type = V4L2_CTRL_TYPE_INTEGER,
998 .name = "Contrast",
999 .minimum = CONTRAST_MIN,
1000 .maximum = CONTRAST_MAX,
1001 .step = 1,
1002 .default_value = CONTRAST_DEF,
1003 },
1004 .set = sd_setcontrast,
1005 .get = sd_getcontrast,
1006 },
1007 {
1008 {
1009 .id = V4L2_CID_AUTOGAIN,
1010 .type = V4L2_CTRL_TYPE_BOOLEAN,
1011 .name = "Auto Gain",
1012 .minimum = AUTOGAIN_MIN,
1013 .maximum = AUTOGAIN_MAX,
1014 .step = 1,
1015 .default_value = AUTOGAIN_DEF,
1016 },
1017 .set = sd_setautogain,
1018 .get = sd_getautogain,
1019 },
1020};
1021
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001022/* sub-driver description */
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001023static const struct sd_desc sd_desc_12a = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024 .name = MODULE_NAME,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001025 .ctrls = sd_ctrls_12a,
1026 .nctrls = ARRAY_SIZE(sd_ctrls_12a),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001027 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001028 .init = sd_init_12a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001029 .start = sd_start_12a,
1030 .stopN = sd_stopN,
1031 .stop0 = sd_stop0,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001032 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001033};
1034static const struct sd_desc sd_desc_72a = {
1035 .name = MODULE_NAME,
1036 .ctrls = sd_ctrls_72a,
1037 .nctrls = ARRAY_SIZE(sd_ctrls_72a),
1038 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001039 .init = sd_init_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001040 .start = sd_start_72a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041 .stopN = sd_stopN,
1042 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001043 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001044 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045};
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001046static const struct sd_desc *sd_desc[2] = {
1047 &sd_desc_12a,
1048 &sd_desc_72a
1049};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050
1051/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001052static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001053 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
1054 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
1055 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
John Ellsonf8f73d02010-03-17 10:22:58 -03001056 {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001057 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
1058 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
1059 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
1060 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
1061 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
1062 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
1063 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
1064 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
1065 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
1066 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
1067 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
1068 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 {}
1070};
1071
1072MODULE_DEVICE_TABLE(usb, device_table);
1073
1074/* -- device connect -- */
1075static int sd_probe(struct usb_interface *intf,
1076 const struct usb_device_id *id)
1077{
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001078 return gspca_dev_probe(intf, id,
1079 sd_desc[id->driver_info],
1080 sizeof(struct sd),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081 THIS_MODULE);
1082}
1083
1084static struct usb_driver sd_driver = {
1085 .name = MODULE_NAME,
1086 .id_table = device_table,
1087 .probe = sd_probe,
1088 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001089#ifdef CONFIG_PM
1090 .suspend = gspca_suspend,
1091 .resume = gspca_resume,
1092#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001093};
1094
1095/* -- module insert / remove -- */
1096static int __init sd_mod_init(void)
1097{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001098 int ret;
1099 ret = usb_register(&sd_driver);
1100 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001101 return ret;
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);