blob: 274df69e6f6dce677ed5ec38f1bfde0d5f1ef5b7 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
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 "sonixb"
24
25#include "gspca.h"
26
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
28static const char version[] = "2.1.5";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029
30MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SN9C102 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
Hans de Goededcef3232008-07-10 10:40:53 -030038 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
40 atomic_t avg_lum;
41
42 unsigned short gain;
43 unsigned short exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030044 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030045 unsigned char autogain;
46 unsigned char autogain_ignore_frames;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030048 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 char sensor; /* Type of image sensor chip */
Hans de Goededcef3232008-07-10 10:40:53 -030050 char sensor_has_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#define SENSOR_HV7131R 0
52#define SENSOR_OV6650 1
53#define SENSOR_OV7630 2
54#define SENSOR_OV7630_3 3
55#define SENSOR_PAS106 4
56#define SENSOR_PAS202 5
57#define SENSOR_TAS5110 6
58#define SENSOR_TAS5130CXX 7
59};
60
61#define COMP2 0x8f
62#define COMP 0xc7 /* 0x87 //0x07 */
63#define COMP1 0xc9 /* 0x89 //0x09 */
64
65#define MCK_INIT 0x63
66#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
67
68#define SYS_CLK 0x04
69
Hans de Goededcef3232008-07-10 10:40:53 -030070/* We calculate the autogain at the end of the transfer of a frame, at this
71 moment a frame with the old settings is being transmitted, and a frame is
72 being captured with the old settings. So if we adjust the autogain we must
73 ignore atleast the 2 next frames for the new settings to come into effect
74 before doing any other adjustments */
75#define AUTOGAIN_IGNORE_FRAMES 3
76#define AUTOGAIN_DEADZONE 500
77#define DESIRED_AVG_LUM 7000
78
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079/* V4L2 controls supported by the driver */
80static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030082static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030088
89static struct ctrl sd_ctrls[] = {
90#define SD_BRIGHTNESS 0
91 {
92 {
93 .id = V4L2_CID_BRIGHTNESS,
94 .type = V4L2_CTRL_TYPE_INTEGER,
95 .name = "Brightness",
96 .minimum = 0,
97 .maximum = 255,
98 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -030099#define BRIGHTNESS_DEF 127
100 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 },
102 .set = sd_setbrightness,
103 .get = sd_getbrightness,
104 },
Hans de Goededcef3232008-07-10 10:40:53 -0300105#define SD_GAIN 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300106 {
107 {
Hans de Goededcef3232008-07-10 10:40:53 -0300108 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300110 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .minimum = 0,
Hans de Goededcef3232008-07-10 10:40:53 -0300112 .maximum = 511,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300114#define GAIN_DEF 255
115#define GAIN_KNEE 400
116 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 },
Hans de Goededcef3232008-07-10 10:40:53 -0300118 .set = sd_setgain,
119 .get = sd_getgain,
120 },
121#define SD_EXPOSURE 2
122 {
123 {
124 .id = V4L2_CID_EXPOSURE,
125 .type = V4L2_CTRL_TYPE_INTEGER,
126 .name = "Exposure",
127#define EXPOSURE_DEF 0
128#define EXPOSURE_KNEE 353 /* 10 fps */
129 .minimum = 0,
130 .maximum = 511,
131 .step = 1,
132 .default_value = EXPOSURE_DEF,
133 .flags = 0,
134 },
135 .set = sd_setexposure,
136 .get = sd_getexposure,
137 },
138#define SD_AUTOGAIN 3
139 {
140 {
141 .id = V4L2_CID_AUTOGAIN,
142 .type = V4L2_CTRL_TYPE_BOOLEAN,
143 .name = "Automatic Gain (and Exposure)",
144 .minimum = 0,
145 .maximum = 1,
146 .step = 1,
147 .default_value = 1,
148 .flags = 0,
149 },
150 .set = sd_setautogain,
151 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152 },
153};
154
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300155static struct v4l2_pix_format vga_mode[] = {
156 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
157 .bytesperline = 160,
158 .sizeimage = 160 * 120,
159 .colorspace = V4L2_COLORSPACE_SRGB,
160 .priv = 2},
161 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
162 .bytesperline = 320,
163 .sizeimage = 320 * 240,
164 .colorspace = V4L2_COLORSPACE_SRGB,
165 .priv = 1},
166 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
167 .bytesperline = 640,
168 .sizeimage = 640 * 480,
169 .colorspace = V4L2_COLORSPACE_SRGB,
170 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300171};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300172static struct v4l2_pix_format sif_mode[] = {
173 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
174 .bytesperline = 176,
175 .sizeimage = 176 * 144,
176 .colorspace = V4L2_COLORSPACE_SRGB,
177 .priv = 1},
178 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
179 .bytesperline = 352,
180 .sizeimage = 352 * 288,
181 .colorspace = V4L2_COLORSPACE_SRGB,
182 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183};
184
185static const __u8 probe_ov7630[] = {0x08, 0x44};
186
187static const __u8 initHv7131[] = {
188 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
189 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
191 0x28, 0x1e, 0x60, 0x8a, 0x20,
192 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
193};
194static const __u8 hv7131_sensor_init[][8] = {
195 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
196 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
197 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
198 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
199 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
200};
201static const __u8 initOv6650[] = {
202 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
203 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
205 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
206};
207static const __u8 ov6650_sensor_init[][8] =
208{
209 /* Bright, contrast, etc are set througth SCBB interface.
210 * AVCAP on win2 do not send any data on this controls. */
211 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300212
213 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300214 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300215 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300217 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300218 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
219/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
220 * THIS SET GREEN SCREEN
221 * (pixels could be innverted in decode kind of "brg",
222 * but blue wont be there. Avoid this data ... */
223 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
224 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
225 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300226 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300228 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
230 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231 {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
Hans de Goededcef3232008-07-10 10:40:53 -0300232 /* Framerate adjust register for artificial light 50 hz flicker
233 compensation, identical to ov6630 0x2b register, see 6630 datasheet.
234 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
235 {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300236};
Hans de Goededcef3232008-07-10 10:40:53 -0300237
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238static const __u8 initOv7630[] = {
239 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
240 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
241 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
242 0x28, 0x1e, /* H & V sizes r15 .. r16 */
243 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
244 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
245};
246static const __u8 initOv7630_3[] = {
247 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
248 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
249 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
250 0x28, 0x1e, /* H & V sizes r15 .. r16 */
251 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
252 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
253};
254static const __u8 ov7630_sensor_init_com[][8] = {
255 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
256 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
257/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
258 {0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10}, /* jfm */
259 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
260 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
261 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
262 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
263 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
264 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
265 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
266/* {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, jfm */
267 {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, /* jfm */
268 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
269 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
270 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
271 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
272 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
273 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
274};
275static const __u8 ov7630_sensor_init[][8] = {
276 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
277 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
278 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
279 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
280 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
281};
282static const __u8 ov7630_sensor_init_3[][8] = {
283 {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
284 {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
285 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
286 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
287/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
288 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
289/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
290 {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
291};
292
293static const __u8 initPas106[] = {
294 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
295 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
297 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
298 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
299};
300/* compression 0x86 mckinit1 0x2b */
301static const __u8 pas106_data[][2] = {
302 {0x02, 0x04}, /* Pixel Clock Divider 6 */
303 {0x03, 0x13}, /* Frame Time MSB */
304/* {0x03, 0x12}, * Frame Time MSB */
305 {0x04, 0x06}, /* Frame Time LSB */
306/* {0x04, 0x05}, * Frame Time LSB */
307 {0x05, 0x65}, /* Shutter Time Line Offset */
308/* {0x05, 0x6d}, * Shutter Time Line Offset */
309/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
310 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
311 {0x07, 0xc1}, /* Black Level Subtract Sign */
312/* {0x07, 0x00}, * Black Level Subtract Sign */
313 {0x08, 0x06}, /* Black Level Subtract Level */
314 {0x08, 0x06}, /* Black Level Subtract Level */
315/* {0x08, 0x01}, * Black Level Subtract Level */
316 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
317 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
318 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
319 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
320 {0x0d, 0x00}, /* Color GainH Pixel */
321 {0x0e, 0x0e}, /* Global Gain */
322 {0x0f, 0x00}, /* Contrast */
323 {0x10, 0x06}, /* H&V synchro polarity */
324 {0x11, 0x06}, /* ?default */
325 {0x12, 0x06}, /* DAC scale */
326 {0x14, 0x02}, /* ?default */
327 {0x13, 0x01}, /* Validate Settings */
328};
329static const __u8 initPas202[] = {
330 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
331 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
333 0x28, 0x1e, 0x28, 0x89, 0x30,
334 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
335};
336static const __u8 pas202_sensor_init[][8] = {
337 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
338 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
339 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
340 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
341 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
342 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
343 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
344 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
345 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
346 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
347 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
348 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
349
350 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
351 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
352 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
353 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
354 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
355 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
356 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
357 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
358};
359
360static const __u8 initTas5110[] = {
361 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
362 0x00, 0x00,
363 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
364 0x16, 0x12, 0x60, 0x86, 0x2b,
365 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
366};
367static const __u8 tas5110_sensor_init[][8] = {
368 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
369 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
370 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
371};
372
373static const __u8 initTas5130[] = {
374 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
375 0x00, 0x00,
376 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
377 0x28, 0x1e, 0x60, COMP, MCK_INIT,
378 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
379};
380static const __u8 tas5130_sensor_init[][8] = {
381/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
382 * shutter 0x47 short exposure? */
383 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
384 /* shutter 0x01 long exposure */
385 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
386};
387
388static void reg_r(struct usb_device *dev,
389 __u16 value, __u8 *buffer)
390{
391 usb_control_msg(dev,
392 usb_rcvctrlpipe(dev, 0),
393 0, /* request */
394 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
395 value,
396 0, /* index */
397 buffer, 1,
398 500);
399}
400
401static void reg_w(struct usb_device *dev,
402 __u16 value,
403 const __u8 *buffer,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300404 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300406 __u8 tmpbuf[32];
407
408#ifdef CONFIG_VIDEO_ADV_DEBUG
409 if (len > sizeof tmpbuf) {
410 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
411 return;
412 }
413#endif
414 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415 usb_control_msg(dev,
416 usb_sndctrlpipe(dev, 0),
417 0x08, /* request */
418 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
419 value,
420 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300421 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300422 500);
423}
424
425static int i2c_w(struct usb_device *dev, const __u8 *buffer)
426{
427 int retry = 60;
428 __u8 ByteReceive;
429
430 /* is i2c ready */
431 reg_w(dev, 0x08, buffer, 8);
432 while (retry--) {
433 msleep(10);
434 reg_r(dev, 0x08, &ByteReceive);
435 if (ByteReceive == 4)
436 return 0;
437 }
438 return -1;
439}
440
441static void i2c_w_vector(struct usb_device *dev,
442 const __u8 buffer[][8], int len)
443{
444 for (;;) {
445 reg_w(dev, 0x08, *buffer, 8);
446 len -= 8;
447 if (len <= 0)
448 break;
449 buffer++;
450 }
451}
452
453static void setbrightness(struct gspca_dev *gspca_dev)
454{
455 struct sd *sd = (struct sd *) gspca_dev;
456 __u8 value;
457
458 switch (sd->sensor) {
459 case SENSOR_OV6650: {
460 __u8 i2cOV6650[] =
461 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
462
463 i2cOV6650[3] = sd->brightness;
464 if (i2c_w(gspca_dev->dev, i2cOV6650) < 0)
465 goto err;
466 break;
467 }
468 case SENSOR_OV7630: {
469 __u8 i2cOV[] =
470 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
471
472 /* change reg 0x06 */
473 i2cOV[3] = sd->brightness;
474 if (i2c_w(gspca_dev->dev, i2cOV) < 0)
475 goto err;
476 break;
477 }
478 case SENSOR_PAS106: {
479 __u8 i2c1[] =
480 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
481
482 i2c1[3] = sd->brightness >> 3;
483 i2c1[2] = 0x0e;
484 if (i2c_w(gspca_dev->dev, i2c1) < 0)
485 goto err;
486 i2c1[3] = 0x01;
487 i2c1[2] = 0x13;
488 if (i2c_w(gspca_dev->dev, i2c1) < 0)
489 goto err;
490 break;
491 }
492 case SENSOR_PAS202: {
493 /* __u8 i2cpexpo1[] =
494 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
495 __u8 i2cpexpo[] =
496 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
497 __u8 i2cp202[] =
498 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
499 static __u8 i2cpdoit[] =
500 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
501
502 /* change reg 0x10 */
503 i2cpexpo[4] = 0xff - sd->brightness;
504/* if(i2c_w(gspca_dev->dev,i2cpexpo1) < 0)
505 goto err; */
506/* if(i2c_w(gspca_dev->dev,i2cpdoit) < 0)
507 goto err; */
508 if (i2c_w(gspca_dev->dev, i2cpexpo) < 0)
509 goto err;
510 if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
511 goto err;
512 i2cp202[3] = sd->brightness >> 3;
513 if (i2c_w(gspca_dev->dev, i2cp202) < 0)
514 goto err;
515 if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
516 goto err;
517 break;
518 }
Hans de Goededcef3232008-07-10 10:40:53 -0300519 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300520 __u8 i2c[] =
521 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
522
523 value = 0xff - sd->brightness;
524 i2c[4] = value;
525 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
526 if (i2c_w(gspca_dev->dev, i2c) < 0)
527 goto err;
528 break;
529 }
Hans de Goededcef3232008-07-10 10:40:53 -0300530 case SENSOR_TAS5110:
531 /* FIXME figure out howto control brightness on TAS5110 */
532 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 }
534 return;
535err:
536 PDEBUG(D_ERR, "i2c error brightness");
537}
Hans de Goededcef3232008-07-10 10:40:53 -0300538
539static void setsensorgain(struct gspca_dev *gspca_dev)
540{
541 struct sd *sd = (struct sd *) gspca_dev;
542 unsigned short gain;
543
544 gain = (sd->gain + 1) >> 1;
545 if (gain > 255)
546 gain = 255;
547
548 switch (sd->sensor) {
549
550 case SENSOR_TAS5110: {
551 __u8 i2c[] =
552 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
553
554 i2c[4] = 255 - gain;
555 if (i2c_w(gspca_dev->dev, i2c) < 0)
556 goto err;
557 break; }
558
559 case SENSOR_OV6650: {
560 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
561 i2c[3] = gain;
562 if (i2c_w(gspca_dev->dev, i2c) < 0)
563 goto err;
564 break; }
565 }
566 return;
567err:
568 PDEBUG(D_ERR, "i2c error gain");
569}
570
571static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572{
573 struct sd *sd = (struct sd *) gspca_dev;
574 __u8 gain;
575 __u8 rgb_value;
576
Hans de Goededcef3232008-07-10 10:40:53 -0300577 gain = sd->gain >> 5;
578
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300579 /* red and blue gain */
580 rgb_value = gain << 4 | gain;
581 reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
582 /* green gain */
583 rgb_value = gain;
584 reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300585
586 if (sd->sensor_has_gain)
587 setsensorgain(gspca_dev);
588}
589
590static void setexposure(struct gspca_dev *gspca_dev)
591{
592 struct sd *sd = (struct sd *) gspca_dev;
593 /* translate 0 - 255 to a number of fps in a 30 - 1 scale */
594 int fps = 30 - sd->exposure * 29 / 511;
595
596 switch (sd->sensor) {
597 case SENSOR_TAS5110: {
598 __u8 reg;
599
600 /* register 19's high nibble contains the sn9c10x clock divider
601 The high nibble configures the no fps according to the
602 formula: 60 / high_nibble. With a maximum of 30 fps */
603 reg = 60 / fps;
604 if (reg > 15)
605 reg = 15;
606 reg = (reg << 4) | 0x0b;
607 reg_w(gspca_dev->dev, 0x19, &reg, 1);
608 break; }
609 case SENSOR_OV6650: {
610 __u8 i2c[] = {0xa0, 0x60, 0x11, 0xc0, 0x00, 0x00, 0x00, 0x10};
611 i2c[3] = 30 / fps - 1;
612 if (i2c[3] > 15)
613 i2c[3] = 15;
614 i2c[3] |= 0xc0;
615 if (i2c_w(gspca_dev->dev, i2c) < 0)
616 PDEBUG(D_ERR, "i2c error exposure");
617 break; }
618 }
619}
620
621
622static void do_autogain(struct gspca_dev *gspca_dev)
623{
624 struct sd *sd = (struct sd *) gspca_dev;
625 int avg_lum = atomic_read(&sd->avg_lum);
626
627 if (avg_lum == -1)
628 return;
629
630 if (sd->autogain_ignore_frames > 0)
631 sd->autogain_ignore_frames--;
632 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
633 sd->brightness * DESIRED_AVG_LUM / 127,
634 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
635 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636}
637
638/* this function is called at probe time */
639static int sd_config(struct gspca_dev *gspca_dev,
640 const struct usb_device_id *id)
641{
642 struct sd *sd = (struct sd *) gspca_dev;
643 struct cam *cam;
644/* __u16 vendor; */
645 __u16 product;
646 int sif = 0;
647
Hans de Goededcef3232008-07-10 10:40:53 -0300648 /* nctrls depends upon the sensor, so we use a per cam copy */
649 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
650 gspca_dev->sd_desc = &sd->sd_desc;
651
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300652 sd->fr_h_sz = 12; /* default size of the frame header */
Hans de Goededcef3232008-07-10 10:40:53 -0300653 sd->sd_desc.nctrls = 2; /* default no ctrls */
654
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300655/* vendor = id->idVendor; */
656 product = id->idProduct;
657/* switch (vendor) { */
658/* case 0x0c45: * Sonix */
659 switch (product) {
660 case 0x6001: /* SN9C102 */
661 case 0x6005: /* SN9C101 */
662 case 0x6007: /* SN9C101 */
663 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300664 sd->sensor_has_gain = 1;
665 sd->sd_desc.nctrls = 4;
666 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 sif = 1;
668 break;
669 case 0x6009: /* SN9C101 */
670 case 0x600d: /* SN9C101 */
671 case 0x6029: /* SN9C101 */
672 sd->sensor = SENSOR_PAS106;
673 sif = 1;
674 break;
675 case 0x6011: /* SN9C101 - SN9C101G */
676 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300677 sd->sensor_has_gain = 1;
678 sd->sd_desc.nctrls = 4;
679 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680 sif = 1;
681 break;
682 case 0x6019: /* SN9C101 */
683 case 0x602c: /* SN9C102 */
684 case 0x602e: /* SN9C102 */
685 sd->sensor = SENSOR_OV7630;
686 break;
687 case 0x60b0: /* SN9C103 */
688 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300689 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690 break;
691 case 0x6024: /* SN9C102 */
692 case 0x6025: /* SN9C102 */
693 sd->sensor = SENSOR_TAS5130CXX;
694 break;
695 case 0x6028: /* SN9C102 */
696 sd->sensor = SENSOR_PAS202;
697 break;
698 case 0x602d: /* SN9C102 */
699 sd->sensor = SENSOR_HV7131R;
700 break;
701 case 0x60af: /* SN9C103 */
702 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300703 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 break;
705 }
706/* break; */
707/* } */
708
709 cam = &gspca_dev->cam;
710 cam->dev_name = (char *) id->driver_info;
711 cam->epaddr = 0x01;
712 if (!sif) {
713 cam->cam_mode = vga_mode;
714 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
715 } else {
716 cam->cam_mode = sif_mode;
717 cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
718 }
Hans de Goededcef3232008-07-10 10:40:53 -0300719 sd->brightness = BRIGHTNESS_DEF;
720 sd->gain = GAIN_DEF;
721 sd->exposure = EXPOSURE_DEF;
722 sd->autogain = 1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
724 reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
725 return 0;
726}
727
728/* this function is called at open time */
729static int sd_open(struct gspca_dev *gspca_dev)
730{
731 __u8 ByteReceive;
732
733 reg_r(gspca_dev->dev, 0x00, &ByteReceive);
734 if (ByteReceive != 0x10)
735 return -ENODEV;
736 return 0;
737}
738
739static void pas106_i2cinit(struct usb_device *dev)
740{
741 int i;
742 const __u8 *data;
743 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
744
745 i = ARRAY_SIZE(pas106_data);
746 data = pas106_data[0];
747 while (--i >= 0) {
748 memcpy(&i2c1[2], data, 2);
749 /* copy 2 bytes from the template */
750 if (i2c_w(dev, i2c1) < 0)
751 PDEBUG(D_ERR, "i2c error pas106");
752 data += 2;
753 }
754}
755
756/* -- start the camera -- */
757static void sd_start(struct gspca_dev *gspca_dev)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760 struct usb_device *dev = gspca_dev->dev;
761 int mode, l;
762 const __u8 *sn9c10x;
763 __u8 reg01, reg17;
764 __u8 reg17_19[3];
765
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300766 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767 switch (sd->sensor) {
768 case SENSOR_HV7131R:
769 sn9c10x = initHv7131;
770 reg17_19[0] = 0x60;
771 reg17_19[1] = (mode << 4) | 0x8a;
772 reg17_19[2] = 0x20;
773 break;
774 case SENSOR_OV6650:
775 sn9c10x = initOv6650;
776 reg17_19[0] = 0x68;
777 reg17_19[1] = (mode << 4) | 0x8b;
778 reg17_19[2] = 0x20;
779 break;
780 case SENSOR_OV7630:
781 sn9c10x = initOv7630;
782 reg17_19[0] = 0x68;
783 reg17_19[1] = (mode << 4) | COMP2;
784 reg17_19[2] = MCK_INIT1;
785 break;
786 case SENSOR_OV7630_3:
787 sn9c10x = initOv7630_3;
788 reg17_19[0] = 0x68;
789 reg17_19[1] = (mode << 4) | COMP2;
790 reg17_19[2] = MCK_INIT1;
791 break;
792 case SENSOR_PAS106:
793 sn9c10x = initPas106;
794 reg17_19[0] = 0x24; /* 0x28 */
795 reg17_19[1] = (mode << 4) | COMP1;
796 reg17_19[2] = MCK_INIT1;
797 break;
798 case SENSOR_PAS202:
799 sn9c10x = initPas202;
800 reg17_19[0] = mode ? 0x24 : 0x20;
801 reg17_19[1] = (mode << 4) | 0x89;
802 reg17_19[2] = 0x20;
803 break;
804 case SENSOR_TAS5110:
805 sn9c10x = initTas5110;
806 reg17_19[0] = 0x60;
807 reg17_19[1] = (mode << 4) | 0x86;
808 reg17_19[2] = 0x2b; /* 0xf3; */
809 break;
810 default:
811/* case SENSOR_TAS5130CXX: */
812 sn9c10x = initTas5130;
813 reg17_19[0] = 0x60;
814 reg17_19[1] = (mode << 4) | COMP;
815 reg17_19[2] = mode ? 0x23 : 0x43;
816 break;
817 }
818 switch (sd->sensor) {
819 case SENSOR_OV7630:
820 reg01 = 0x06;
821 reg17 = 0x29;
822 l = 0x10;
823 break;
824 case SENSOR_OV7630_3:
825 reg01 = 0x44;
826 reg17 = 0x68;
827 l = 0x10;
828 break;
829 default:
830 reg01 = sn9c10x[0];
831 reg17 = sn9c10x[0x17 - 1];
832 l = 0x1f;
833 break;
834 }
835
836 /* reg 0x01 bit 2 video transfert on */
837 reg_w(dev, 0x01, &reg01, 1);
838 /* reg 0x17 SensorClk enable inv Clk 0x60 */
839 reg_w(dev, 0x17, &reg17, 1);
840/*fixme: for ov7630 102
841 reg_w(dev, 0x01, {0x06, sn9c10x[1]}, 2); */
842 /* Set the registers from the template */
843 reg_w(dev, 0x01, sn9c10x, l);
844 switch (sd->sensor) {
845 case SENSOR_HV7131R:
846 i2c_w_vector(dev, hv7131_sensor_init,
847 sizeof hv7131_sensor_init);
848 break;
849 case SENSOR_OV6650:
850 i2c_w_vector(dev, ov6650_sensor_init,
851 sizeof ov6650_sensor_init);
852 break;
853 case SENSOR_OV7630:
854 i2c_w_vector(dev, ov7630_sensor_init_com,
855 sizeof ov7630_sensor_init_com);
856 msleep(200);
857 i2c_w_vector(dev, ov7630_sensor_init,
858 sizeof ov7630_sensor_init);
859 break;
860 case SENSOR_OV7630_3:
861 i2c_w_vector(dev, ov7630_sensor_init_com,
862 sizeof ov7630_sensor_init_com);
863 msleep(200);
864 i2c_w_vector(dev, ov7630_sensor_init_3,
865 sizeof ov7630_sensor_init_3);
866 break;
867 case SENSOR_PAS106:
868 pas106_i2cinit(dev);
869 break;
870 case SENSOR_PAS202:
871 i2c_w_vector(dev, pas202_sensor_init,
872 sizeof pas202_sensor_init);
873 break;
874 case SENSOR_TAS5110:
875 i2c_w_vector(dev, tas5110_sensor_init,
876 sizeof tas5110_sensor_init);
877 break;
878 default:
879/* case SENSOR_TAS5130CXX: */
880 i2c_w_vector(dev, tas5130_sensor_init,
881 sizeof tas5130_sensor_init);
882 break;
883 }
884 /* H_size V_size 0x28, 0x1e maybe 640x480 */
885 reg_w(dev, 0x15, &sn9c10x[0x15 - 1], 2);
886 /* compression register */
887 reg_w(dev, 0x18, &reg17_19[1], 1);
888 /* H_start */ /*fixme: not ov7630*/
889 reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
890 /* V_START */ /*fixme: not ov7630*/
891 reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
892 /* reset 0x17 SensorClk enable inv Clk 0x60 */
893 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
894 reg_w(dev, 0x17, &reg17_19[0], 1);
895 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
896 reg_w(dev, 0x19, &reg17_19[2], 1);
897 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
898 reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
899 /* Enable video transfert */
900 reg_w(dev, 0x01, &sn9c10x[0], 1);
901 /* Compression */
902 reg_w(dev, 0x18, &reg17_19[1], 2);
903 msleep(20);
904
Hans de Goededcef3232008-07-10 10:40:53 -0300905 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300907 setexposure(gspca_dev);
908
909 sd->autogain_ignore_frames = 0;
910 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911}
912
913static void sd_stopN(struct gspca_dev *gspca_dev)
914{
915 __u8 ByteSend = 0;
916
917 ByteSend = 0x09; /* 0X00 */
918 reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
919}
920
921static void sd_stop0(struct gspca_dev *gspca_dev)
922{
923}
924
925static void sd_close(struct gspca_dev *gspca_dev)
926{
927}
928
929static void sd_pkt_scan(struct gspca_dev *gspca_dev,
930 struct gspca_frame *frame, /* target */
931 unsigned char *data, /* isoc packet */
932 int len) /* iso packet length */
933{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300934 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300935 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936
937 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300938 for (i = 0; i < len - 6; i++) {
939 if (data[0 + i] == 0xff
940 && data[1 + i] == 0xff
941 && data[2 + i] == 0x00
942 && data[3 + i] == 0xc4
943 && data[4 + i] == 0xc4
944 && data[5 + i] == 0x96) { /* start of frame */
945 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
946 frame, data, 0);
Hans de Goededcef3232008-07-10 10:40:53 -0300947 if (i < (len - 10)) {
948 atomic_set(&sd->avg_lum, data[i + 8] +
949 (data[i + 9] << 8));
950 } else {
951 atomic_set(&sd->avg_lum, -1);
952#ifdef CONFIG_VIDEO_ADV_DEBUG
953 PDEBUG(D_STREAM, "packet too short to "
954 "get avg brightness");
955#endif
956 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300957 data += i + sd->fr_h_sz;
958 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959 gspca_frame_add(gspca_dev, FIRST_PACKET,
960 frame, data, len);
961 return;
962 }
963 }
964 }
965 gspca_frame_add(gspca_dev, INTER_PACKET,
966 frame, data, len);
967}
968
969static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
970{
971 struct sd *sd = (struct sd *) gspca_dev;
972
973 sd->brightness = val;
974 if (gspca_dev->streaming)
975 setbrightness(gspca_dev);
976 return 0;
977}
978
979static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
980{
981 struct sd *sd = (struct sd *) gspca_dev;
982
983 *val = sd->brightness;
984 return 0;
985}
986
Hans de Goededcef3232008-07-10 10:40:53 -0300987static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988{
989 struct sd *sd = (struct sd *) gspca_dev;
990
Hans de Goededcef3232008-07-10 10:40:53 -0300991 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300992 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -0300993 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 return 0;
995}
996
Hans de Goededcef3232008-07-10 10:40:53 -0300997static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998{
999 struct sd *sd = (struct sd *) gspca_dev;
1000
Hans de Goededcef3232008-07-10 10:40:53 -03001001 *val = sd->gain;
1002 return 0;
1003}
1004
1005static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1006{
1007 struct sd *sd = (struct sd *) gspca_dev;
1008
1009 sd->exposure = val;
1010 if (gspca_dev->streaming)
1011 setexposure(gspca_dev);
1012 return 0;
1013}
1014
1015static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1016{
1017 struct sd *sd = (struct sd *) gspca_dev;
1018
1019 *val = sd->exposure;
1020 return 0;
1021}
1022
1023static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
1026
1027 sd->autogain = val;
1028 /* when switching to autogain set defaults to make sure
1029 we are on a valid point of the autogain gain /
1030 exposure knee graph, and give this change time to
1031 take effect before doing autogain. */
1032 if (sd->autogain) {
1033 sd->exposure = EXPOSURE_DEF;
1034 sd->gain = GAIN_DEF;
1035 if (gspca_dev->streaming) {
1036 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1037 setexposure(gspca_dev);
1038 setgain(gspca_dev);
1039 }
1040 }
1041
1042 return 0;
1043}
1044
1045static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1046{
1047 struct sd *sd = (struct sd *) gspca_dev;
1048
1049 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050 return 0;
1051}
1052
1053/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001054static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055 .name = MODULE_NAME,
1056 .ctrls = sd_ctrls,
1057 .nctrls = ARRAY_SIZE(sd_ctrls),
1058 .config = sd_config,
1059 .open = sd_open,
1060 .start = sd_start,
1061 .stopN = sd_stopN,
1062 .stop0 = sd_stop0,
1063 .close = sd_close,
1064 .pkt_scan = sd_pkt_scan,
1065};
1066
1067/* -- module initialisation -- */
1068#define DVNM(name) .driver_info = (kernel_ulong_t) name
1069static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001070#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001071 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1072 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1073 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1074 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1075 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001076 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001077 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1078 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1079 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1080 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1081 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1082 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1083 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1084 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1085 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1086 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001087#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001088 {}
1089};
1090MODULE_DEVICE_TABLE(usb, device_table);
1091
1092/* -- device connect -- */
1093static int sd_probe(struct usb_interface *intf,
1094 const struct usb_device_id *id)
1095{
1096 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1097 THIS_MODULE);
1098}
1099
1100static struct usb_driver sd_driver = {
1101 .name = MODULE_NAME,
1102 .id_table = device_table,
1103 .probe = sd_probe,
1104 .disconnect = gspca_disconnect,
1105};
1106
1107/* -- module insert / remove -- */
1108static int __init sd_mod_init(void)
1109{
1110 if (usb_register(&sd_driver) < 0)
1111 return -1;
1112 PDEBUG(D_PROBE, "v%s registered", version);
1113 return 0;
1114}
1115static void __exit sd_mod_exit(void)
1116{
1117 usb_deregister(&sd_driver);
1118 PDEBUG(D_PROBE, "deregistered");
1119}
1120
1121module_init(sd_mod_init);
1122module_exit(sd_mod_exit);