Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
[pandora-kernel.git] / drivers / media / video / gspca / pac7311.c
1 /*
2  *              Pixart PAC7311 library
3  *              Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4  *
5  * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21
22 #define MODULE_NAME "pac7311"
23
24 #include "gspca.h"
25
26 #define DRIVER_VERSION_NUMBER   KERNEL_VERSION(2, 1, 7)
27 static const char version[] = "2.1.7";
28
29 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
30 MODULE_DESCRIPTION("Pixart PAC7311");
31 MODULE_LICENSE("GPL");
32
33 /* specific webcam descriptor */
34 struct sd {
35         struct gspca_dev gspca_dev;             /* !! must be the first item */
36
37         int avg_lum;
38
39         unsigned char brightness;
40         unsigned char contrast;
41         unsigned char colors;
42         unsigned char autogain;
43
44         char ffseq;
45         signed char ag_cnt;
46 #define AG_CNT_START 13
47 };
48
49 /* V4L2 controls supported by the driver */
50 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
51 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
52 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
53 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
54 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
55 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
56 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
57 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
58
59 static struct ctrl sd_ctrls[] = {
60         {
61             {
62                 .id      = V4L2_CID_BRIGHTNESS,
63                 .type    = V4L2_CTRL_TYPE_INTEGER,
64                 .name    = "Brightness",
65                 .minimum = 0,
66 #define BRIGHTNESS_MAX 0x20
67                 .maximum = BRIGHTNESS_MAX,
68                 .step    = 1,
69 #define BRIGHTNESS_DEF 0x10
70                 .default_value = BRIGHTNESS_DEF,
71             },
72             .set = sd_setbrightness,
73             .get = sd_getbrightness,
74         },
75         {
76             {
77                 .id      = V4L2_CID_CONTRAST,
78                 .type    = V4L2_CTRL_TYPE_INTEGER,
79                 .name    = "Contrast",
80                 .minimum = 0,
81                 .maximum = 255,
82                 .step    = 1,
83 #define CONTRAST_DEF 127
84                 .default_value = CONTRAST_DEF,
85             },
86             .set = sd_setcontrast,
87             .get = sd_getcontrast,
88         },
89         {
90             {
91                 .id      = V4L2_CID_SATURATION,
92                 .type    = V4L2_CTRL_TYPE_INTEGER,
93                 .name    = "Color",
94                 .minimum = 0,
95                 .maximum = 255,
96                 .step    = 1,
97 #define COLOR_DEF 127
98                 .default_value = COLOR_DEF,
99             },
100             .set = sd_setcolors,
101             .get = sd_getcolors,
102         },
103         {
104             {
105                 .id      = V4L2_CID_AUTOGAIN,
106                 .type    = V4L2_CTRL_TYPE_BOOLEAN,
107                 .name    = "Auto Gain",
108                 .minimum = 0,
109                 .maximum = 1,
110                 .step    = 1,
111 #define AUTOGAIN_DEF 1
112                 .default_value = AUTOGAIN_DEF,
113             },
114             .set = sd_setautogain,
115             .get = sd_getautogain,
116         },
117 };
118
119 static struct v4l2_pix_format vga_mode[] = {
120         {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
121                 .bytesperline = 160,
122                 .sizeimage = 160 * 120 * 3 / 8 + 590,
123                 .colorspace = V4L2_COLORSPACE_JPEG,
124                 .priv = 2},
125         {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
126                 .bytesperline = 320,
127                 .sizeimage = 320 * 240 * 3 / 8 + 590,
128                 .colorspace = V4L2_COLORSPACE_JPEG,
129                 .priv = 1},
130         {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131                 .bytesperline = 640,
132                 .sizeimage = 640 * 480 * 3 / 8 + 590,
133                 .colorspace = V4L2_COLORSPACE_JPEG,
134                 .priv = 0},
135 };
136
137 #define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header)   /* (594) */
138
139 static const __u8 pac7311_jpeg_header[] = {
140         0xff, 0xd8,
141         0xff, 0xe0, 0x00, 0x03, 0x20,
142         0xff, 0xc0, 0x00, 0x11, 0x08,
143                 0x01, 0xe0,                     /* 12: height */
144                 0x02, 0x80,                     /* 14: width */
145                 0x03,                           /* 16 */
146                         0x01, 0x21, 0x00,
147                         0x02, 0x11, 0x01,
148                         0x03, 0x11, 0x01,
149         0xff, 0xdb, 0x00, 0x84,
150         0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
151         0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
152         0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
153         0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
154         0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
155         0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
156         0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
157         0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
158         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
159         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
160         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
161         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
162         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
163         0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
164         0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165         0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
166         0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
167         0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
168         0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
169         0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
170         0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
171         0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
172         0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
173         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
174         0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
175         0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
176         0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
177         0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
178         0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
179         0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
180         0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
181         0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
182         0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
183         0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
184         0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
185         0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
187         0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
188         0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
189         0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
190         0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
191         0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
192         0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
193         0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
194         0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
195         0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
196         0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
197         0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
198         0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
199         0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
200         0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
201         0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
202         0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
203         0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
204         0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
205         0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
206         0x11, 0x00, 0x3f, 0x00
207 };
208
209 static void reg_w_buf(struct gspca_dev *gspca_dev,
210                   __u16 index,
211                   const char *buffer, __u16 len)
212 {
213         memcpy(gspca_dev->usb_buf, buffer, len);
214         usb_control_msg(gspca_dev->dev,
215                         usb_sndctrlpipe(gspca_dev->dev, 0),
216                         1,              /* request */
217                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
218                         0,              /* value */
219                         index, gspca_dev->usb_buf, len,
220                         500);
221 }
222
223 static __u8 reg_r(struct gspca_dev *gspca_dev,
224                              __u16 index)
225 {
226         usb_control_msg(gspca_dev->dev,
227                         usb_rcvctrlpipe(gspca_dev->dev, 0),
228                         0,                      /* request */
229                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
230                         0,                      /* value */
231                         index, gspca_dev->usb_buf, 1,
232                         500);
233         return gspca_dev->usb_buf[0];
234 }
235
236 static void reg_w(struct gspca_dev *gspca_dev,
237                   __u16 index,
238                   __u8 value)
239 {
240         gspca_dev->usb_buf[0] = value;
241         usb_control_msg(gspca_dev->dev,
242                         usb_sndctrlpipe(gspca_dev->dev, 0),
243                         0,                      /* request */
244                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
245                         value, index, gspca_dev->usb_buf, 1,
246                         500);
247 }
248
249 /* this function is called at probe time */
250 static int sd_config(struct gspca_dev *gspca_dev,
251                         const struct usb_device_id *id)
252 {
253         struct sd *sd = (struct sd *) gspca_dev;
254         struct cam *cam;
255
256         PDEBUG(D_CONF, "Find Sensor PAC7311");
257         reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
258         reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
259         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
260         reg_w(gspca_dev, 0xff, 0x04);
261         reg_w(gspca_dev, 0x27, 0x80);
262         reg_w(gspca_dev, 0x28, 0xca);
263         reg_w(gspca_dev, 0x29, 0x53);
264         reg_w(gspca_dev, 0x2a, 0x0e);
265         reg_w(gspca_dev, 0xff, 0x01);
266         reg_w(gspca_dev, 0x3e, 0x20);
267
268         cam = &gspca_dev->cam;
269         cam->dev_name = (char *) id->driver_info;
270         cam->epaddr = 0x05;
271         cam->cam_mode = vga_mode;
272         cam->nmodes = ARRAY_SIZE(vga_mode);
273
274         sd->brightness = BRIGHTNESS_DEF;
275         sd->contrast = CONTRAST_DEF;
276         sd->colors = COLOR_DEF;
277         sd->autogain = AUTOGAIN_DEF;
278         return 0;
279 }
280
281 static void setbrightness(struct gspca_dev *gspca_dev)
282 {
283         struct sd *sd = (struct sd *) gspca_dev;
284         int brightness;
285
286 /*jfm: inverted?*/
287         brightness = BRIGHTNESS_MAX - sd->brightness;
288         reg_w(gspca_dev, 0xff, 0x04);
289 /*      reg_w(gspca_dev, 0x0e, 0x00); */
290         reg_w(gspca_dev, 0x0f, brightness);
291         /* load registers to sensor (Bit 0, auto clear) */
292         reg_w(gspca_dev, 0x11, 0x01);
293         PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
294 }
295
296 static void setcontrast(struct gspca_dev *gspca_dev)
297 {
298         struct sd *sd = (struct sd *) gspca_dev;
299
300         reg_w(gspca_dev, 0xff, 0x01);
301         reg_w(gspca_dev, 0x80, sd->contrast);
302         /* load registers to sensor (Bit 0, auto clear) */
303         reg_w(gspca_dev, 0x11, 0x01);
304         PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
305 }
306
307 static void setcolors(struct gspca_dev *gspca_dev)
308 {
309         struct sd *sd = (struct sd *) gspca_dev;
310
311         reg_w(gspca_dev, 0xff, 0x01);
312         reg_w(gspca_dev, 0x10, sd->colors);
313         /* load registers to sensor (Bit 0, auto clear) */
314         reg_w(gspca_dev, 0x11, 0x01);
315         PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
316 }
317
318 /* this function is called at open time */
319 static int sd_open(struct gspca_dev *gspca_dev)
320 {
321         reg_w(gspca_dev, 0x78, 0x00);   /* Turn on LED */
322         return 0;
323 }
324
325 static void sd_start(struct gspca_dev *gspca_dev)
326 {
327         struct sd *sd = (struct sd *) gspca_dev;
328
329         reg_w(gspca_dev, 0xff, 0x01);
330         reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
331         reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
332         reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
333         reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
334         reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
335         reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
336         reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
337         reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
338         reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
339         reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
340         reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
341         reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
342         reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
343         reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
344         reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
345         reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
346         reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
347         reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
348         reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
349         reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
350
351         reg_w(gspca_dev, 0xff, 0x04);
352         reg_w(gspca_dev, 0x02, 0x04);
353         reg_w(gspca_dev, 0x03, 0x54);
354         reg_w(gspca_dev, 0x04, 0x07);
355         reg_w(gspca_dev, 0x05, 0x2b);
356         reg_w(gspca_dev, 0x06, 0x09);
357         reg_w(gspca_dev, 0x07, 0x0f);
358         reg_w(gspca_dev, 0x08, 0x09);
359         reg_w(gspca_dev, 0x09, 0x00);
360         reg_w(gspca_dev, 0x0c, 0x07);
361         reg_w(gspca_dev, 0x0d, 0x00);
362         reg_w(gspca_dev, 0x0e, 0x00);
363         reg_w(gspca_dev, 0x0f, 0x62);
364         reg_w(gspca_dev, 0x10, 0x08);
365         reg_w(gspca_dev, 0x12, 0x07);
366         reg_w(gspca_dev, 0x13, 0x00);
367         reg_w(gspca_dev, 0x14, 0x00);
368         reg_w(gspca_dev, 0x15, 0x00);
369         reg_w(gspca_dev, 0x16, 0x00);
370         reg_w(gspca_dev, 0x17, 0x00);
371         reg_w(gspca_dev, 0x18, 0x00);
372         reg_w(gspca_dev, 0x19, 0x00);
373         reg_w(gspca_dev, 0x1a, 0x00);
374         reg_w(gspca_dev, 0x1b, 0x03);
375         reg_w(gspca_dev, 0x1c, 0xa0);
376         reg_w(gspca_dev, 0x1d, 0x01);
377         reg_w(gspca_dev, 0x1e, 0xf4);
378         reg_w(gspca_dev, 0x21, 0x00);
379         reg_w(gspca_dev, 0x22, 0x08);
380         reg_w(gspca_dev, 0x24, 0x03);
381         reg_w(gspca_dev, 0x26, 0x00);
382         reg_w(gspca_dev, 0x27, 0x01);
383         reg_w(gspca_dev, 0x28, 0xca);
384         reg_w(gspca_dev, 0x29, 0x10);
385         reg_w(gspca_dev, 0x2a, 0x06);
386         reg_w(gspca_dev, 0x2b, 0x78);
387         reg_w(gspca_dev, 0x2c, 0x00);
388         reg_w(gspca_dev, 0x2d, 0x00);
389         reg_w(gspca_dev, 0x2e, 0x00);
390         reg_w(gspca_dev, 0x2f, 0x00);
391         reg_w(gspca_dev, 0x30, 0x23);
392         reg_w(gspca_dev, 0x31, 0x28);
393         reg_w(gspca_dev, 0x32, 0x04);
394         reg_w(gspca_dev, 0x33, 0x11);
395         reg_w(gspca_dev, 0x34, 0x00);
396         reg_w(gspca_dev, 0x35, 0x00);
397         reg_w(gspca_dev, 0x11, 0x01);
398         setcontrast(gspca_dev);
399         setbrightness(gspca_dev);
400         setcolors(gspca_dev);
401
402         /* set correct resolution */
403         switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
404         case 2:                                 /* 160x120 */
405                 reg_w(gspca_dev, 0xff, 0x04);
406                 reg_w(gspca_dev, 0x02, 0x03);
407                 reg_w(gspca_dev, 0xff, 0x01);
408                 reg_w(gspca_dev, 0x08, 0x09);
409                 reg_w(gspca_dev, 0x17, 0x20);
410                 reg_w(gspca_dev, 0x1b, 0x00);
411 /*              reg_w(gspca_dev, 0x80, 0x69); */
412                 reg_w(gspca_dev, 0x87, 0x10);
413                 break;
414         case 1:                                 /* 320x240 */
415                 reg_w(gspca_dev, 0xff, 0x04);
416                 reg_w(gspca_dev, 0x02, 0x03);
417                 reg_w(gspca_dev, 0xff, 0x01);
418                 reg_w(gspca_dev, 0x08, 0x09);
419                 reg_w(gspca_dev, 0x17, 0x30);
420 /*              reg_w(gspca_dev, 0x80, 0x3f); */
421                 reg_w(gspca_dev, 0x87, 0x11);
422                 break;
423         case 0:                                 /* 640x480 */
424                 reg_w(gspca_dev, 0xff, 0x04);
425                 reg_w(gspca_dev, 0x02, 0x03);
426                 reg_w(gspca_dev, 0xff, 0x01);
427                 reg_w(gspca_dev, 0x08, 0x08);
428                 reg_w(gspca_dev, 0x17, 0x00);
429 /*              reg_w(gspca_dev, 0x80, 0x1c); */
430                 reg_w(gspca_dev, 0x87, 0x12);
431                 break;
432         }
433
434         /* start stream */
435         reg_w(gspca_dev, 0xff, 0x01);
436         reg_w(gspca_dev, 0x78, 0x04);
437         reg_w(gspca_dev, 0x78, 0x05);
438
439         if (sd->autogain) {
440                 sd->ag_cnt = AG_CNT_START;
441                 sd->avg_lum = 0;
442         } else {
443                 sd->ag_cnt = -1;
444         }
445 }
446
447 static void sd_stopN(struct gspca_dev *gspca_dev)
448 {
449         reg_w(gspca_dev, 0xff, 0x04);
450         reg_w(gspca_dev, 0x27, 0x80);
451         reg_w(gspca_dev, 0x28, 0xca);
452         reg_w(gspca_dev, 0x29, 0x53);
453         reg_w(gspca_dev, 0x2a, 0x0e);
454         reg_w(gspca_dev, 0xff, 0x01);
455         reg_w(gspca_dev, 0x3e, 0x20);
456         reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
457         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
458         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
459 }
460
461 static void sd_stop0(struct gspca_dev *gspca_dev)
462 {
463 }
464
465 /* this function is called at close time */
466 static void sd_close(struct gspca_dev *gspca_dev)
467 {
468         reg_w(gspca_dev, 0xff, 0x04);
469         reg_w(gspca_dev, 0x27, 0x80);
470         reg_w(gspca_dev, 0x28, 0xca);
471         reg_w(gspca_dev, 0x29, 0x53);
472         reg_w(gspca_dev, 0x2a, 0x0e);
473         reg_w(gspca_dev, 0xff, 0x01);
474         reg_w(gspca_dev, 0x3e, 0x20);
475         reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
476         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
477         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
478 }
479
480 static void setautogain(struct gspca_dev *gspca_dev, int luma)
481 {
482         int luma_mean = 128;
483         int luma_delta = 20;
484         __u8 spring = 5;
485         int Gbright;
486
487         Gbright = reg_r(gspca_dev, 0x02);
488         PDEBUG(D_FRAM, "luma mean %d", luma);
489         if (luma < luma_mean - luma_delta ||
490             luma > luma_mean + luma_delta) {
491                 Gbright += (luma_mean - luma) >> spring;
492                 if (Gbright > 0x1a)
493                         Gbright = 0x1a;
494                 else if (Gbright < 4)
495                         Gbright = 4;
496                 PDEBUG(D_FRAM, "gbright %d", Gbright);
497                 reg_w(gspca_dev, 0xff, 0x04);
498                 reg_w(gspca_dev, 0x0f, Gbright);
499                 /* load registers to sensor (Bit 0, auto clear) */
500                 reg_w(gspca_dev, 0x11, 0x01);
501         }
502 }
503
504 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
505                         struct gspca_frame *frame,      /* target */
506                         __u8 *data,                     /* isoc packet */
507                         int len)                        /* iso packet length */
508 {
509         struct sd *sd = (struct sd *) gspca_dev;
510         unsigned char tmpbuf[4];
511         int i, p, ffseq;
512
513 /*      if (len < 5) { */
514         if (len < 6) {
515 /*              gspca_dev->last_packet_type = DISCARD_PACKET; */
516                 return;
517         }
518
519         ffseq = sd->ffseq;
520
521         for (p = 0; p < len - 6; p++) {
522                 if ((data[0 + p] == 0xff)
523                     && (data[1 + p] == 0xff)
524                     && (data[2 + p] == 0x00)
525                     && (data[3 + p] == 0xff)
526                     && (data[4 + p] == 0x96)) {
527
528                         /* start of frame */
529                         if (sd->ag_cnt >= 0 && p > 28) {
530                                 sd->avg_lum += data[p - 23];
531                                 if (--sd->ag_cnt < 0) {
532                                         sd->ag_cnt = AG_CNT_START;
533                                         setautogain(gspca_dev,
534                                                 sd->avg_lum / AG_CNT_START);
535                                         sd->avg_lum = 0;
536                                 }
537                         }
538
539                         /* copy the end of data to the current frame */
540                         frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
541                                                 data, p);
542
543                         /* put the JPEG header in the new frame */
544                         gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
545                                         (unsigned char *) pac7311_jpeg_header,
546                                         12);
547                         tmpbuf[0] = gspca_dev->height >> 8;
548                         tmpbuf[1] = gspca_dev->height & 0xff;
549                         tmpbuf[2] = gspca_dev->width >> 8;
550                         tmpbuf[3] = gspca_dev->width & 0xff;
551                         gspca_frame_add(gspca_dev, INTER_PACKET, frame,
552                                         tmpbuf, 4);
553                         gspca_frame_add(gspca_dev, INTER_PACKET, frame,
554                                 (unsigned char *) &pac7311_jpeg_header[16],
555                                 PAC7311_JPEG_HEADER_SIZE - 16);
556
557                         data += p + 7;
558                         len -= p + 7;
559                         ffseq = 0;
560                         break;
561                 }
562         }
563
564         /* remove the 'ff ff ff xx' sequences */
565         switch (ffseq) {
566         case 3:
567                 data += 1;
568                 len -= 1;
569                 break;
570         case 2:
571                 if (data[0] == 0xff) {
572                         data += 2;
573                         len -= 2;
574                         frame->data_end -= 2;
575                 }
576                 break;
577         case 1:
578                 if (data[0] == 0xff
579                     && data[1] == 0xff) {
580                         data += 3;
581                         len -= 3;
582                         frame->data_end -= 1;
583                 }
584                 break;
585         }
586         for (i = 0; i < len - 4; i++) {
587                 if (data[i] == 0xff
588                     && data[i + 1] == 0xff
589                     && data[i + 2] == 0xff) {
590                         memmove(&data[i], &data[i + 4], len - i - 4);
591                         len -= 4;
592                 }
593         }
594         ffseq = 0;
595         if (data[len - 4] == 0xff) {
596                 if (data[len - 3] == 0xff
597                     && data[len - 2] == 0xff) {
598                         len -= 4;
599                 }
600         } else if (data[len - 3] == 0xff) {
601                 if (data[len - 2] == 0xff
602                     && data[len - 1] == 0xff)
603                         ffseq = 3;
604         } else if (data[len - 2] == 0xff) {
605                 if (data[len - 1] == 0xff)
606                         ffseq = 2;
607         } else if (data[len - 1] == 0xff)
608                 ffseq = 1;
609         sd->ffseq = ffseq;
610         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
611 }
612
613 static void getbrightness(struct gspca_dev *gspca_dev)
614 {
615 /*      sd->brightness = reg_r(gspca_dev, 0x08);
616         return sd->brightness;  */
617 /*      PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
618 }
619
620
621
622 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
623 {
624         struct sd *sd = (struct sd *) gspca_dev;
625
626         sd->brightness = val;
627         if (gspca_dev->streaming)
628                 setbrightness(gspca_dev);
629         return 0;
630 }
631
632 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
633 {
634         struct sd *sd = (struct sd *) gspca_dev;
635
636         getbrightness(gspca_dev);
637         *val = sd->brightness;
638         return 0;
639 }
640
641 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
642 {
643         struct sd *sd = (struct sd *) gspca_dev;
644
645         sd->contrast = val;
646         if (gspca_dev->streaming)
647                 setcontrast(gspca_dev);
648         return 0;
649 }
650
651 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
652 {
653         struct sd *sd = (struct sd *) gspca_dev;
654
655 /*      getcontrast(gspca_dev); */
656         *val = sd->contrast;
657         return 0;
658 }
659
660 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
661 {
662         struct sd *sd = (struct sd *) gspca_dev;
663
664         sd->colors = val;
665         if (gspca_dev->streaming)
666                 setcolors(gspca_dev);
667         return 0;
668 }
669
670 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
671 {
672         struct sd *sd = (struct sd *) gspca_dev;
673
674 /*      getcolors(gspca_dev); */
675         *val = sd->colors;
676         return 0;
677 }
678
679 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
680 {
681         struct sd *sd = (struct sd *) gspca_dev;
682
683         sd->autogain = val;
684         if (val) {
685                 sd->ag_cnt = AG_CNT_START;
686                 sd->avg_lum = 0;
687         } else {
688                 sd->ag_cnt = -1;
689         }
690         return 0;
691 }
692
693 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
694 {
695         struct sd *sd = (struct sd *) gspca_dev;
696
697         *val = sd->autogain;
698         return 0;
699 }
700
701 /* sub-driver description */
702 static struct sd_desc sd_desc = {
703         .name = MODULE_NAME,
704         .ctrls = sd_ctrls,
705         .nctrls = ARRAY_SIZE(sd_ctrls),
706         .config = sd_config,
707         .open = sd_open,
708         .start = sd_start,
709         .stopN = sd_stopN,
710         .stop0 = sd_stop0,
711         .close = sd_close,
712         .pkt_scan = sd_pkt_scan,
713 };
714
715 /* -- module initialisation -- */
716 #define DVNM(name) .driver_info = (kernel_ulong_t) name
717 static __devinitdata struct usb_device_id device_table[] = {
718         {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
719         {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
720         {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
721         {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
722         {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
723                         /* and also ', Trust WB-3350p, SIGMA cam 2350' */
724         {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
725         {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
726         {}
727 };
728 MODULE_DEVICE_TABLE(usb, device_table);
729
730 /* -- device connect -- */
731 static int sd_probe(struct usb_interface *intf,
732                         const struct usb_device_id *id)
733 {
734         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
735                                 THIS_MODULE);
736 }
737
738 static struct usb_driver sd_driver = {
739         .name = MODULE_NAME,
740         .id_table = device_table,
741         .probe = sd_probe,
742         .disconnect = gspca_disconnect,
743 };
744
745 /* -- module insert / remove -- */
746 static int __init sd_mod_init(void)
747 {
748         if (usb_register(&sd_driver) < 0)
749                 return -1;
750         PDEBUG(D_PROBE, "v%s registered", version);
751         return 0;
752 }
753 static void __exit sd_mod_exit(void)
754 {
755         usb_deregister(&sd_driver);
756         PDEBUG(D_PROBE, "deregistered");
757 }
758
759 module_init(sd_mod_init);
760 module_exit(sd_mod_exit);