blob: c82fd53cef95bb3ee06975760fb02d6f100378d1 [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
Joe Perches133a9fe2011-08-21 19:56:57 -030023#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030025#define MODULE_NAME "spca561"
26
Hans de Goede436c2c52010-02-28 09:41:04 -030027#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030028#include "gspca.h"
29
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030030MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34/* specific webcam descriptor */
35struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */
37
Jean-Francois Moine7879d452008-09-03 16:47:32 -030038 __u16 exposure; /* rev12a only */
Hans de Goede0fc23d22008-09-04 16:22:57 -030039#define EXPOSURE_MIN 1
Hans de Goeded0848eb2009-05-25 15:20:16 -030040#define EXPOSURE_DEF 700 /* == 10 fps */
41#define EXPOSURE_MAX (2047 + 325) /* see setexposure */
Jean-Francois Moine7879d452008-09-03 16:47:32 -030042
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030043 __u8 contrast; /* rev72a only */
44#define CONTRAST_MIN 0x00
45#define CONTRAST_DEF 0x20
46#define CONTRAST_MAX 0x3f
47
Jean-Francois Moine7879d452008-09-03 16:47:32 -030048 __u8 brightness; /* rev72a only */
49#define BRIGHTNESS_MIN 0
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030050#define BRIGHTNESS_DEF 0x20
51#define BRIGHTNESS_MAX 0x3f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030052
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030053 __u8 white;
Hans de Goede9035f2e2009-05-25 15:26:59 -030054#define HUE_MIN 1
55#define HUE_DEF 0x40
56#define HUE_MAX 0x7f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030057
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030058 __u8 autogain;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030059#define AUTOGAIN_MIN 0
60#define AUTOGAIN_DEF 1
61#define AUTOGAIN_MAX 1
62
63 __u8 gain; /* rev12a only */
Hans de Goeded0848eb2009-05-25 15:20:16 -030064#define GAIN_MIN 0
65#define GAIN_DEF 63
66#define GAIN_MAX 255
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067
Jean-Francois Moined698dc62008-09-03 16:47:51 -030068#define EXPO12A_DEF 3
69 __u8 expo12a; /* expo/gain? for rev 12a */
70
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 __u8 chip_revision;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030072#define Rev012A 0
73#define Rev072A 1
74
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075 signed char ag_cnt;
76#define AG_CNT_START 13
77};
78
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030079static const struct v4l2_pix_format sif_012a_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030080 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
81 .bytesperline = 160,
82 .sizeimage = 160 * 120,
83 .colorspace = V4L2_COLORSPACE_SRGB,
84 .priv = 3},
85 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
86 .bytesperline = 176,
87 .sizeimage = 176 * 144,
88 .colorspace = V4L2_COLORSPACE_SRGB,
89 .priv = 2},
90 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
91 .bytesperline = 320,
92 .sizeimage = 320 * 240 * 4 / 8,
93 .colorspace = V4L2_COLORSPACE_SRGB,
94 .priv = 1},
95 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
96 .bytesperline = 352,
97 .sizeimage = 352 * 288 * 4 / 8,
98 .colorspace = V4L2_COLORSPACE_SRGB,
99 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100};
101
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300102static const struct v4l2_pix_format sif_072a_mode[] = {
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300103 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
104 .bytesperline = 160,
105 .sizeimage = 160 * 120,
106 .colorspace = V4L2_COLORSPACE_SRGB,
107 .priv = 3},
108 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
109 .bytesperline = 176,
110 .sizeimage = 176 * 144,
111 .colorspace = V4L2_COLORSPACE_SRGB,
112 .priv = 2},
113 {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
114 .bytesperline = 320,
115 .sizeimage = 320 * 240,
116 .colorspace = V4L2_COLORSPACE_SRGB,
117 .priv = 1},
118 {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
119 .bytesperline = 352,
120 .sizeimage = 352 * 288,
121 .colorspace = V4L2_COLORSPACE_SRGB,
122 .priv = 0},
123};
124
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125/*
126 * Initialization data
127 * I'm not very sure how to split initialization from open data
128 * chunks. For now, we'll consider everything as initialization
129 */
130/* Frame packet header offsets for the spca561 */
131#define SPCA561_OFFSET_SNAP 1
132#define SPCA561_OFFSET_TYPE 2
133#define SPCA561_OFFSET_COMPRESS 3
134#define SPCA561_OFFSET_FRAMSEQ 4
135#define SPCA561_OFFSET_GPIO 5
136#define SPCA561_OFFSET_USBBUFF 6
137#define SPCA561_OFFSET_WIN2GRAVE 7
138#define SPCA561_OFFSET_WIN2RAVE 8
139#define SPCA561_OFFSET_WIN2BAVE 9
140#define SPCA561_OFFSET_WIN2GBAVE 10
141#define SPCA561_OFFSET_WIN1GRAVE 11
142#define SPCA561_OFFSET_WIN1RAVE 12
143#define SPCA561_OFFSET_WIN1BAVE 13
144#define SPCA561_OFFSET_WIN1GBAVE 14
145#define SPCA561_OFFSET_FREQ 15
146#define SPCA561_OFFSET_VSYNC 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147#define SPCA561_INDEX_I2C_BASE 0x8800
148#define SPCA561_SNAPBIT 0x20
149#define SPCA561_SNAPCTRL 0x40
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300150
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300151static const u16 rev72a_reset[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152 {0x0000, 0x8114}, /* Software GPIO output data */
153 {0x0001, 0x8114}, /* Software GPIO output data */
154 {0x0000, 0x8112}, /* Some kind of reset */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300155 {}
156};
157static const __u16 rev72a_init_data1[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300158 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
159 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
160 {0x0011, 0x8118}, /* Enable and conf sensor */
161 {0x0001, 0x8118}, /* Conf sensor */
162 {0x0092, 0x8804}, /* I know nothing about these */
163 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300164 {}
165};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300166static const u16 rev72a_init_sensor1[][2] = {
167 {0x0001, 0x000d},
168 {0x0002, 0x0018},
169 {0x0004, 0x0165},
170 {0x0005, 0x0021},
171 {0x0007, 0x00aa},
172 {0x0020, 0x1504},
173 {0x0039, 0x0002},
174 {0x0035, 0x0010},
175 {0x0009, 0x1049},
176 {0x0028, 0x000b},
177 {0x003b, 0x000f},
178 {0x003c, 0x0000},
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300179 {}
180};
181static const __u16 rev72a_init_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300182 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
183 {0x0000, 0x8602}, /* Optical black level for user setting */
184 {0x0060, 0x8604}, /* Optical black horizontal offset */
185 {0x0002, 0x8605}, /* Optical black vertical offset */
186 {0x0000, 0x8603}, /* Non-automatic optical black level */
187 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
188 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
189 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
190 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
191 {0x00e0, 0x8406}, /* Memory buffer threshold */
192 {0x0000, 0x8660}, /* Compensation memory stuff */
193 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
194 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
195 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300196/* from ms-win */
197 {0x0000, 0x8611}, /* R offset for white balance */
198 {0x00fd, 0x8612}, /* Gr offset for white balance */
199 {0x0003, 0x8613}, /* B offset for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200 {0x0000, 0x8614}, /* Gb offset for white balance */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300201/* from ms-win */
202 {0x0035, 0x8651}, /* R gain for white balance */
203 {0x0040, 0x8652}, /* Gr gain for white balance */
204 {0x005f, 0x8653}, /* B gain for white balance */
205 {0x0040, 0x8654}, /* Gb gain for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300206 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300207 {0x0011, 0x8802},
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300208
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300209 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
210 {0x0081, 0x8702}, /* Master clock output enable */
211
212 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
213 /* Originally was 0x0010 (352x288 compression) */
214
215 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
216 {0x0003, 0x865c}, /* Vertical offset for valid lines */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300217 {}
218};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300219static const u16 rev72a_init_sensor2[][2] = {
220 {0x0003, 0x0121},
221 {0x0004, 0x0165},
222 {0x0005, 0x002f}, /* blanking control column */
223 {0x0006, 0x0000}, /* blanking mode row*/
224 {0x000a, 0x0002},
225 {0x0009, 0x1061}, /* setexposure times && pixel clock
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 * 0001 0 | 000 0110 0001 */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300227 {0x0035, 0x0014},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {}
229};
230
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300232static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233 /* reg, value */
234 {0x8320, 0x3304},
235
236 {0x8303, 0x0125}, /* image area */
237 {0x8304, 0x0169},
238 {0x8328, 0x000b},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300239 {0x833c, 0x0001}, /*fixme: win:07*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300240
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300241 {0x832f, 0x1904}, /*fixme: was 0419*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300242 {0x8307, 0x00aa},
243 {0x8301, 0x0003},
244 {0x8302, 0x000e},
245 {}
246};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300247static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300248 /* reg, value */
249 {0x8339, 0x0000},
250 {0x8307, 0x00aa},
251 {}
252};
253
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300254static const __u16 spca561_161rev12A_data1[][2] = {
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300255 {0x29, 0x8118}, /* Control register (various enable bits) */
256 {0x08, 0x8114}, /* GPIO: Led off */
257 {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300258 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300259 {0x92, 0x8804},
260 {0x04, 0x8802}, /* windows uses 08 */
261 {}
262};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300263static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264 {0x21, 0x8118},
265 {0x10, 0x8500},
266 {0x07, 0x8601},
267 {0x07, 0x8602},
268 {0x04, 0x8501},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269
270 {0x07, 0x8201}, /* windows uses 02 */
271 {0x08, 0x8200},
272 {0x01, 0x8200},
273
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274 {0x90, 0x8604},
275 {0x00, 0x8605},
276 {0xb0, 0x8603},
277
278 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300279 {0x07, 0x8601}, /* white balance - new */
280 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300281 {0x00, 0x8610}, /* *red */
282 {0x00, 0x8611}, /* 3f *green */
283 {0x00, 0x8612}, /* green *blue */
284 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300285 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
286 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
287 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
288 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300289
290 {0x0c, 0x8620}, /* 0c */
291 {0xc8, 0x8631}, /* c8 */
292 {0xc8, 0x8634}, /* c8 */
293 {0x23, 0x8635}, /* 23 */
294 {0x1f, 0x8636}, /* 1f */
295 {0xdd, 0x8637}, /* dd */
296 {0xe1, 0x8638}, /* e1 */
297 {0x1d, 0x8639}, /* 1d */
298 {0x21, 0x863a}, /* 21 */
299 {0xe3, 0x863b}, /* e3 */
300 {0xdf, 0x863c}, /* df */
301 {0xf0, 0x8505},
302 {0x32, 0x850a},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300303/* {0x99, 0x8700}, * - white balance - new (removed) */
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300304 /* HDG we used to do this in stop0, making the init state and the state
305 after a start / stop different, so do this here instead. */
306 {0x29, 0x8118},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307 {}
308};
309
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300310static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300312 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300313
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300314 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
315 0, /* request */
316 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
317 value, index, NULL, 0, 500);
318 PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
319 if (ret < 0)
Joe Perches133a9fe2011-08-21 19:56:57 -0300320 pr_err("reg write: error %d\n", ret);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300321}
322
323static void write_vector(struct gspca_dev *gspca_dev,
324 const __u16 data[][2])
325{
326 struct usb_device *dev = gspca_dev->dev;
327 int i;
328
329 i = 0;
330 while (data[i][1] != 0) {
331 reg_w_val(dev, data[i][1], data[i][0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300332 i++;
333 }
334}
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300335
336/* read 'len' bytes to gspca_dev->usb_buf */
337static void reg_r(struct gspca_dev *gspca_dev,
338 __u16 index, __u16 length)
339{
340 usb_control_msg(gspca_dev->dev,
341 usb_rcvctrlpipe(gspca_dev->dev, 0),
342 0, /* request */
343 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
344 0, /* value */
345 index, gspca_dev->usb_buf, length, 500);
346}
347
348/* write 'len' bytes from gspca_dev->usb_buf */
349static void reg_w_buf(struct gspca_dev *gspca_dev,
350 __u16 index, __u16 len)
351{
352 usb_control_msg(gspca_dev->dev,
353 usb_sndctrlpipe(gspca_dev->dev, 0),
354 0, /* request */
355 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
356 0, /* value */
357 index, gspca_dev->usb_buf, len, 500);
358}
359
360static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
361{
362 int retry = 60;
363
364 reg_w_val(gspca_dev->dev, 0x8801, reg);
365 reg_w_val(gspca_dev->dev, 0x8805, value);
366 reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
367 do {
368 reg_r(gspca_dev, 0x8803, 1);
369 if (!gspca_dev->usb_buf[0])
370 return;
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300371 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300372 } while (--retry);
373}
374
375static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
376{
377 int retry = 60;
378 __u8 value;
379
380 reg_w_val(gspca_dev->dev, 0x8804, 0x92);
381 reg_w_val(gspca_dev->dev, 0x8801, reg);
382 reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
383 do {
384 reg_r(gspca_dev, 0x8803, 1);
385 if (!gspca_dev->usb_buf[0]) {
386 reg_r(gspca_dev, 0x8800, 1);
387 value = gspca_dev->usb_buf[0];
388 reg_r(gspca_dev, 0x8805, 1);
389 return ((int) value << 8) | gspca_dev->usb_buf[0];
390 }
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300391 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300392 } while (--retry);
393 return -1;
394}
395
396static void sensor_mapwrite(struct gspca_dev *gspca_dev,
397 const __u16 (*sensormap)[2])
398{
399 while ((*sensormap)[0]) {
400 gspca_dev->usb_buf[0] = (*sensormap)[1];
401 gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
402 reg_w_buf(gspca_dev, (*sensormap)[0], 2);
403 sensormap++;
404 }
405}
406
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300407static void write_sensor_72a(struct gspca_dev *gspca_dev,
408 const __u16 (*sensor)[2])
409{
410 while ((*sensor)[0]) {
411 i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
412 sensor++;
413 }
414}
415
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416static void init_161rev12A(struct gspca_dev *gspca_dev)
417{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418 write_vector(gspca_dev, spca561_161rev12A_data1);
419 sensor_mapwrite(gspca_dev, Pb100_1map8300);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300420/*fixme: should be in sd_start*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300421 write_vector(gspca_dev, spca561_161rev12A_data2);
422 sensor_mapwrite(gspca_dev, Pb100_2map8300);
423}
424
425/* this function is called at probe time */
426static int sd_config(struct gspca_dev *gspca_dev,
427 const struct usb_device_id *id)
428{
429 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300430 struct cam *cam;
431 __u16 vendor, product;
432 __u8 data1, data2;
433
434 /* Read frm global register the USB product and vendor IDs, just to
435 * prove that we can communicate with the device. This works, which
436 * confirms at we are communicating properly and that the device
437 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300438 reg_r(gspca_dev, 0x8104, 1);
439 data1 = gspca_dev->usb_buf[0];
440 reg_r(gspca_dev, 0x8105, 1);
441 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300442 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300443 reg_r(gspca_dev, 0x8106, 1);
444 data1 = gspca_dev->usb_buf[0];
445 reg_r(gspca_dev, 0x8107, 1);
446 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300447 product = (data2 << 8) | data1;
448 if (vendor != id->idVendor || product != id->idProduct) {
449 PDEBUG(D_PROBE, "Bad vendor / product from device");
450 return -EINVAL;
451 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300452
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300455
456 sd->chip_revision = id->driver_info;
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300457 if (sd->chip_revision == Rev012A) {
458 cam->cam_mode = sif_012a_mode;
459 cam->nmodes = ARRAY_SIZE(sif_012a_mode);
460 } else {
461 cam->cam_mode = sif_072a_mode;
462 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
463 }
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300464 sd->brightness = BRIGHTNESS_DEF;
465 sd->contrast = CONTRAST_DEF;
Hans de Goede9035f2e2009-05-25 15:26:59 -0300466 sd->white = HUE_DEF;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300467 sd->exposure = EXPOSURE_DEF;
468 sd->autogain = AUTOGAIN_DEF;
469 sd->gain = GAIN_DEF;
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300470 sd->expo12a = EXPO12A_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 return 0;
472}
473
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300474/* this function is called at probe and resume time */
475static int sd_init_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300477 PDEBUG(D_STREAM, "Chip revision: 012a");
478 init_161rev12A(gspca_dev);
479 return 0;
480}
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300481static int sd_init_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300482{
483 PDEBUG(D_STREAM, "Chip revision: 072a");
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300484 write_vector(gspca_dev, rev72a_reset);
485 msleep(200);
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300486 write_vector(gspca_dev, rev72a_init_data1);
487 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
488 write_vector(gspca_dev, rev72a_init_data2);
489 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300490 reg_w_val(gspca_dev->dev, 0x8112, 0x30);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 return 0;
492}
493
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300494/* rev 72a only */
495static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496{
497 struct sd *sd = (struct sd *) gspca_dev;
498 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300499 __u8 value;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300501 value = sd->brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300502
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300503 /* offsets for white balance */
504 reg_w_val(dev, 0x8611, value); /* R */
505 reg_w_val(dev, 0x8612, value); /* Gr */
506 reg_w_val(dev, 0x8613, value); /* B */
507 reg_w_val(dev, 0x8614, value); /* Gb */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508}
509
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300510static void setwhite(struct gspca_dev *gspca_dev)
511{
512 struct sd *sd = (struct sd *) gspca_dev;
513 __u16 white;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300514 __u8 blue, red;
515 __u16 reg;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300516
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300517 /* try to emulate MS-win as possible */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300518 white = sd->white;
519 red = 0x20 + white * 3 / 8;
520 blue = 0x90 - white * 5 / 8;
521 if (sd->chip_revision == Rev012A) {
522 reg = 0x8614;
523 } else {
524 reg = 0x8651;
525 red += sd->contrast - 0x20;
526 blue += sd->contrast - 0x20;
527 }
528 reg_w_val(gspca_dev->dev, reg, red);
529 reg_w_val(gspca_dev->dev, reg + 2, blue);
530}
531
532static void setcontrast(struct gspca_dev *gspca_dev)
533{
534 struct sd *sd = (struct sd *) gspca_dev;
535 struct usb_device *dev = gspca_dev->dev;
536 __u8 value;
537
538 if (sd->chip_revision != Rev072A)
539 return;
540 value = sd->contrast + 0x20;
541
542 /* gains for white balance */
543 setwhite(gspca_dev);
544/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */
545 reg_w_val(dev, 0x8652, value); /* Gr */
546/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */
547 reg_w_val(dev, 0x8654, value); /* Gb */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300548}
549
550/* rev 12a only */
551static void setexposure(struct gspca_dev *gspca_dev)
552{
553 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300554 int i, expo = 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300555
Hans de Goede0fc23d22008-09-04 16:22:57 -0300556 /* Register 0x8309 controls exposure for the spca561,
557 the basic exposure setting goes from 1-2047, where 1 is completely
558 dark and 2047 is very bright. It not only influences exposure but
559 also the framerate (to allow for longer exposure) from 1 - 300 it
560 only raises the exposure time then from 300 - 600 it halves the
561 framerate to be able to further raise the exposure time and for every
562 300 more it halves the framerate again. This allows for a maximum
563 exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
564 Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
565 configure a divider for the base framerate which us used at the
566 exposure setting of 1-300. These bits configure the base framerate
567 according to the following formula: fps = 60 / (value + 2) */
Hans de Goeded0848eb2009-05-25 15:20:16 -0300568
569 /* We choose to use the high bits setting the fixed framerate divisor
570 asap, as setting high basic exposure setting without the fixed
571 divider in combination with high gains makes the cam stop */
572 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
573
574 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
575 if (sd->exposure <= table[i + 1]) {
576 expo = sd->exposure - table[i];
577 if (i)
578 expo += 300;
579 expo |= i << 11;
580 break;
581 }
Hans de Goede0fc23d22008-09-04 16:22:57 -0300582 }
Hans de Goeded0848eb2009-05-25 15:20:16 -0300583
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300584 gspca_dev->usb_buf[0] = expo;
585 gspca_dev->usb_buf[1] = expo >> 8;
586 reg_w_buf(gspca_dev, 0x8309, 2);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300587}
588
589/* rev 12a only */
590static void setgain(struct gspca_dev *gspca_dev)
591{
592 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300593
Hans de Goeded0848eb2009-05-25 15:20:16 -0300594 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
595 sensitivity when set, so 31 + one of them set == 63, and 15
596 with both of them set == 63 */
597 if (sd->gain < 64)
598 gspca_dev->usb_buf[0] = sd->gain;
599 else if (sd->gain < 128)
600 gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
601 else
Jean-François Moine1d00d6c2010-10-29 13:58:22 -0300602 gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300603
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300604 gspca_dev->usb_buf[1] = 0;
605 reg_w_buf(gspca_dev, 0x8335, 2);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300606}
607
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300608static void setautogain(struct gspca_dev *gspca_dev)
609{
610 struct sd *sd = (struct sd *) gspca_dev;
611
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300612 if (sd->autogain)
613 sd->ag_cnt = AG_CNT_START;
614 else
615 sd->ag_cnt = -1;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300616}
617
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300618static int sd_start_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621 int mode;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300622 static const __u8 Reg8391[8] =
623 {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300625 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300626 if (mode <= 1) {
627 /* Use compression on 320x240 and above */
628 reg_w_val(dev, 0x8500, 0x10 | mode);
629 } else {
630 /* I couldn't get the compression to work below 320x240
631 * Fortunately at these resolutions the bandwidth
632 * is sufficient to push raw frames at ~20fps */
633 reg_w_val(dev, 0x8500, mode);
634 } /* -- qq@kuku.eu.org */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300635
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300636 gspca_dev->usb_buf[0] = 0xaa;
637 gspca_dev->usb_buf[1] = 0x00;
638 reg_w_buf(gspca_dev, 0x8307, 2);
639 /* clock - lower 0x8X values lead to fps > 30 */
640 reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300641 /* 0x8f 0x85 0x27 clock */
642 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
643 reg_w_val(gspca_dev->dev, 0x850b, 0x03);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300644 memcpy(gspca_dev->usb_buf, Reg8391, 8);
645 reg_w_buf(gspca_dev, 0x8391, 8);
646 reg_w_buf(gspca_dev, 0x8390, 8);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300647 setwhite(gspca_dev);
Hans de Goeded0848eb2009-05-25 15:20:16 -0300648 setgain(gspca_dev);
Hans de Goede0fc23d22008-09-04 16:22:57 -0300649 setexposure(gspca_dev);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300650
651 /* Led ON (bit 3 -> 0 */
652 reg_w_val(gspca_dev->dev, 0x8114, 0x00);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300653 return 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300654}
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300655static int sd_start_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300656{
657 struct usb_device *dev = gspca_dev->dev;
658 int Clck;
659 int mode;
660
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300661 write_vector(gspca_dev, rev72a_reset);
662 msleep(200);
663 write_vector(gspca_dev, rev72a_init_data1);
664 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
665
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300666 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
667 switch (mode) {
668 default:
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300669 case 0:
670 Clck = 0x27; /* ms-win 0x87 */
671 break;
672 case 1:
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300673 Clck = 0x25;
674 break;
675 case 2:
676 Clck = 0x22;
677 break;
678 case 3:
679 Clck = 0x21;
680 break;
681 }
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300682 reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300683 reg_w_val(dev, 0x8702, 0x81);
684 reg_w_val(dev, 0x8500, mode); /* mode */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300685 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300686 setcontrast(gspca_dev);
687/* setbrightness(gspca_dev); * fixme: bad values */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300688 setautogain(gspca_dev);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300689 reg_w_val(dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300690 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691}
692
693static void sd_stopN(struct gspca_dev *gspca_dev)
694{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300695 struct sd *sd = (struct sd *) gspca_dev;
696
697 if (sd->chip_revision == Rev012A) {
698 reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300699 /* Led Off (bit 3 -> 1 */
700 reg_w_val(gspca_dev->dev, 0x8114, 0x08);
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300701 } else {
702 reg_w_val(gspca_dev->dev, 0x8112, 0x20);
703/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
704 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705}
706
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300707static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300708{
709 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300710 int expotimes;
711 int pixelclk;
712 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713 __u8 R, Gr, Gb, B;
714 int y;
715 __u8 luma_mean = 110;
716 __u8 luma_delta = 20;
717 __u8 spring = 4;
718
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300719 if (sd->ag_cnt < 0)
720 return;
721 if (--sd->ag_cnt >= 0)
722 return;
723 sd->ag_cnt = AG_CNT_START;
724
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725 switch (sd->chip_revision) {
726 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300727 reg_r(gspca_dev, 0x8621, 1);
728 Gr = gspca_dev->usb_buf[0];
729 reg_r(gspca_dev, 0x8622, 1);
730 R = gspca_dev->usb_buf[0];
731 reg_r(gspca_dev, 0x8623, 1);
732 B = gspca_dev->usb_buf[0];
733 reg_r(gspca_dev, 0x8624, 1);
734 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
736 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
737 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
738 /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
739
740 if (y < luma_mean - luma_delta ||
741 y > luma_mean + luma_delta) {
742 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
743 pixelclk = 0x0800;
744 expotimes = expotimes & 0x07ff;
745 /* PDEBUG(D_PACK,
746 "Exposition Times 0x%03X Clock 0x%04X ",
747 expotimes,pixelclk); */
748 gainG = i2c_read(gspca_dev, 0x35, 0x10);
749 /* PDEBUG(D_PACK,
750 "reading Gain register %d", gainG); */
751
752 expotimes += (luma_mean - y) >> spring;
753 gainG += (luma_mean - y) / 50;
754 /* PDEBUG(D_PACK,
755 "compute expotimes %d gain %d",
756 expotimes,gainG); */
757
758 if (gainG > 0x3f)
759 gainG = 0x3f;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300760 else if (gainG < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761 gainG = 3;
762 i2c_write(gspca_dev, gainG, 0x35);
763
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300764 if (expotimes > 0x0256)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300765 expotimes = 0x0256;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300766 else if (expotimes < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767 expotimes = 3;
768 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
769 }
770 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 }
772}
773
774static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300775 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300776 int len) /* iso packet length */
777{
Hans de Goede0fc23d22008-09-04 16:22:57 -0300778 struct sd *sd = (struct sd *) gspca_dev;
779
Jean-Francois Moine576ed7b2009-01-16 08:57:28 -0300780 len--;
781 switch (*data++) { /* sequence number */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300782 case 0: /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300783 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede436c2c52010-02-28 09:41:04 -0300784
785 /* This should never happen */
786 if (len < 2) {
787 PDEBUG(D_ERR, "Short SOF packet, ignoring");
788 gspca_dev->last_packet_type = DISCARD_PACKET;
789 return;
790 }
791
Jean-François Moine28566432010-10-01 07:33:26 -0300792#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede436c2c52010-02-28 09:41:04 -0300793 if (data[0] & 0x20) {
794 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
795 input_sync(gspca_dev->input_dev);
796 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
797 input_sync(gspca_dev->input_dev);
798 }
799#endif
800
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 if (data[1] & 0x10) {
802 /* compressed bayer */
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 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300805 /* raw bayer (with a header, which we skip) */
Hans de Goede0fc23d22008-09-04 16:22:57 -0300806 if (sd->chip_revision == Rev012A) {
807 data += 20;
808 len -= 20;
809 } else {
810 data += 16;
811 len -= 16;
812 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300813 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814 }
815 return;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300816 case 0xff: /* drop (empty mpackets) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 return;
818 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300819 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820}
821
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300822/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300823static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
824{
825 struct sd *sd = (struct sd *) gspca_dev;
826
827 sd->brightness = val;
828 if (gspca_dev->streaming)
829 setbrightness(gspca_dev);
830 return 0;
831}
832
833static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
834{
835 struct sd *sd = (struct sd *) gspca_dev;
836
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300837 *val = sd->brightness;
838 return 0;
839}
840
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300841/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300842static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
843{
844 struct sd *sd = (struct sd *) gspca_dev;
845
846 sd->contrast = val;
847 if (gspca_dev->streaming)
848 setcontrast(gspca_dev);
849 return 0;
850}
851
852static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
853{
854 struct sd *sd = (struct sd *) gspca_dev;
855
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 *val = sd->contrast;
857 return 0;
858}
859
860static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
861{
862 struct sd *sd = (struct sd *) gspca_dev;
863
864 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300865 if (gspca_dev->streaming)
866 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 return 0;
868}
869
870static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
871{
872 struct sd *sd = (struct sd *) gspca_dev;
873
874 *val = sd->autogain;
875 return 0;
876}
877
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300878static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
879{
880 struct sd *sd = (struct sd *) gspca_dev;
881
882 sd->white = val;
883 if (gspca_dev->streaming)
884 setwhite(gspca_dev);
885 return 0;
886}
887
888static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
889{
890 struct sd *sd = (struct sd *) gspca_dev;
891
892 *val = sd->white;
893 return 0;
894}
895
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300896/* rev12a only */
897static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
898{
899 struct sd *sd = (struct sd *) gspca_dev;
900
901 sd->exposure = val;
902 if (gspca_dev->streaming)
903 setexposure(gspca_dev);
904 return 0;
905}
906
907static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
908{
909 struct sd *sd = (struct sd *) gspca_dev;
910
911 *val = sd->exposure;
912 return 0;
913}
914
915/* rev12a only */
916static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
917{
918 struct sd *sd = (struct sd *) gspca_dev;
919
920 sd->gain = val;
921 if (gspca_dev->streaming)
922 setgain(gspca_dev);
923 return 0;
924}
925
926static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
927{
928 struct sd *sd = (struct sd *) gspca_dev;
929
930 *val = sd->gain;
931 return 0;
932}
933
934/* control tables */
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300935static const struct ctrl sd_ctrls_12a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300936 {
937 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300938 .id = V4L2_CID_HUE,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300939 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300940 .name = "Hue",
941 .minimum = HUE_MIN,
942 .maximum = HUE_MAX,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300943 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300944 .default_value = HUE_DEF,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300945 },
946 .set = sd_setwhite,
947 .get = sd_getwhite,
948 },
949 {
950 {
951 .id = V4L2_CID_EXPOSURE,
952 .type = V4L2_CTRL_TYPE_INTEGER,
953 .name = "Exposure",
954 .minimum = EXPOSURE_MIN,
955 .maximum = EXPOSURE_MAX,
956 .step = 1,
957 .default_value = EXPOSURE_DEF,
958 },
959 .set = sd_setexposure,
960 .get = sd_getexposure,
961 },
962 {
963 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300964 .id = V4L2_CID_GAIN,
965 .type = V4L2_CTRL_TYPE_INTEGER,
966 .name = "Gain",
967 .minimum = GAIN_MIN,
968 .maximum = GAIN_MAX,
969 .step = 1,
970 .default_value = GAIN_DEF,
971 },
972 .set = sd_setgain,
973 .get = sd_getgain,
974 },
975};
976
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300977static const struct ctrl sd_ctrls_72a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300978 {
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300979 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300980 .id = V4L2_CID_HUE,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300981 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300982 .name = "Hue",
983 .minimum = HUE_MIN,
984 .maximum = HUE_MAX,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300985 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300986 .default_value = HUE_DEF,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300987 },
988 .set = sd_setwhite,
989 .get = sd_getwhite,
990 },
991 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300992 {
993 .id = V4L2_CID_BRIGHTNESS,
994 .type = V4L2_CTRL_TYPE_INTEGER,
995 .name = "Brightness",
996 .minimum = BRIGHTNESS_MIN,
997 .maximum = BRIGHTNESS_MAX,
998 .step = 1,
999 .default_value = BRIGHTNESS_DEF,
1000 },
1001 .set = sd_setbrightness,
1002 .get = sd_getbrightness,
1003 },
1004 {
1005 {
1006 .id = V4L2_CID_CONTRAST,
1007 .type = V4L2_CTRL_TYPE_INTEGER,
1008 .name = "Contrast",
1009 .minimum = CONTRAST_MIN,
1010 .maximum = CONTRAST_MAX,
1011 .step = 1,
1012 .default_value = CONTRAST_DEF,
1013 },
1014 .set = sd_setcontrast,
1015 .get = sd_getcontrast,
1016 },
1017 {
1018 {
1019 .id = V4L2_CID_AUTOGAIN,
1020 .type = V4L2_CTRL_TYPE_BOOLEAN,
1021 .name = "Auto Gain",
1022 .minimum = AUTOGAIN_MIN,
1023 .maximum = AUTOGAIN_MAX,
1024 .step = 1,
1025 .default_value = AUTOGAIN_DEF,
1026 },
1027 .set = sd_setautogain,
1028 .get = sd_getautogain,
1029 },
1030};
1031
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001032/* sub-driver description */
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001033static const struct sd_desc sd_desc_12a = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001034 .name = MODULE_NAME,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001035 .ctrls = sd_ctrls_12a,
1036 .nctrls = ARRAY_SIZE(sd_ctrls_12a),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001037 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001038 .init = sd_init_12a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001039 .start = sd_start_12a,
1040 .stopN = sd_stopN,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001041 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03001042#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede436c2c52010-02-28 09:41:04 -03001043 .other_input = 1,
1044#endif
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001045};
1046static const struct sd_desc sd_desc_72a = {
1047 .name = MODULE_NAME,
1048 .ctrls = sd_ctrls_72a,
1049 .nctrls = ARRAY_SIZE(sd_ctrls_72a),
1050 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001051 .init = sd_init_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001052 .start = sd_start_72a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001053 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001054 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001055 .dq_callback = do_autogain,
Jean-François Moine28566432010-10-01 07:33:26 -03001056#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede436c2c52010-02-28 09:41:04 -03001057 .other_input = 1,
1058#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059};
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001060static const struct sd_desc *sd_desc[2] = {
1061 &sd_desc_12a,
1062 &sd_desc_72a
1063};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064
1065/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001066static const struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001067 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
1068 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
1069 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
John Ellsonf8f73d02010-03-17 10:22:58 -03001070 {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001071 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
1072 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
1073 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
1074 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
1075 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
1076 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
1077 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
1078 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
1079 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
1080 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
1081 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
1082 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001083 {}
1084};
1085
1086MODULE_DEVICE_TABLE(usb, device_table);
1087
1088/* -- device connect -- */
1089static int sd_probe(struct usb_interface *intf,
1090 const struct usb_device_id *id)
1091{
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001092 return gspca_dev_probe(intf, id,
1093 sd_desc[id->driver_info],
1094 sizeof(struct sd),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001095 THIS_MODULE);
1096}
1097
1098static struct usb_driver sd_driver = {
1099 .name = MODULE_NAME,
1100 .id_table = device_table,
1101 .probe = sd_probe,
1102 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001103#ifdef CONFIG_PM
1104 .suspend = gspca_suspend,
1105 .resume = gspca_resume,
1106#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001107};
1108
1109/* -- module insert / remove -- */
1110static int __init sd_mod_init(void)
1111{
Jean-François Moine54826432010-09-13 04:53:03 -03001112 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001113}
1114static void __exit sd_mod_exit(void)
1115{
1116 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001117}
1118
1119module_init(sd_mod_init);
1120module_exit(sd_mod_exit);