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