]> Pileus Git - ~andy/linux/blob - drivers/media/video/gspca/pac7311.c
2267ae7cb87f53d122a2fedb97b6a407b35be15e
[~andy/linux] / 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->dev_name = (char *) id->driver_info;
267         cam->epaddr = 0x05;
268         cam->cam_mode = vga_mode;
269         cam->nmodes = ARRAY_SIZE(vga_mode);
270
271         sd->brightness = BRIGHTNESS_DEF;
272         sd->contrast = CONTRAST_DEF;
273         sd->colors = COLOR_DEF;
274         sd->autogain = AUTOGAIN_DEF;
275         return 0;
276 }
277
278 static void setbrightness(struct gspca_dev *gspca_dev)
279 {
280         struct sd *sd = (struct sd *) gspca_dev;
281         int brightness;
282
283 /*jfm: inverted?*/
284         brightness = BRIGHTNESS_MAX - sd->brightness;
285         reg_w(gspca_dev, 0xff, 0x04);
286 /*      reg_w(gspca_dev, 0x0e, 0x00); */
287         reg_w(gspca_dev, 0x0f, brightness);
288         /* load registers to sensor (Bit 0, auto clear) */
289         reg_w(gspca_dev, 0x11, 0x01);
290         PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
291 }
292
293 static void setcontrast(struct gspca_dev *gspca_dev)
294 {
295         struct sd *sd = (struct sd *) gspca_dev;
296
297         reg_w(gspca_dev, 0xff, 0x01);
298         reg_w(gspca_dev, 0x80, sd->contrast);
299         /* load registers to sensor (Bit 0, auto clear) */
300         reg_w(gspca_dev, 0x11, 0x01);
301         PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
302 }
303
304 static void setcolors(struct gspca_dev *gspca_dev)
305 {
306         struct sd *sd = (struct sd *) gspca_dev;
307
308         reg_w(gspca_dev, 0xff, 0x01);
309         reg_w(gspca_dev, 0x10, sd->colors);
310         /* load registers to sensor (Bit 0, auto clear) */
311         reg_w(gspca_dev, 0x11, 0x01);
312         PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
313 }
314
315 /* this function is called at open time */
316 static int sd_open(struct gspca_dev *gspca_dev)
317 {
318         reg_w(gspca_dev, 0x78, 0x00);   /* Turn on LED */
319         return 0;
320 }
321
322 static void sd_start(struct gspca_dev *gspca_dev)
323 {
324         struct sd *sd = (struct sd *) gspca_dev;
325
326         reg_w(gspca_dev, 0xff, 0x01);
327         reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
328         reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
329         reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
330         reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
331         reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
332         reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
333         reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
334         reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
335         reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
336         reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
337         reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
338         reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
339         reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
340         reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
341         reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
342         reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
343         reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
344         reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
345         reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
346         reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
347
348         reg_w(gspca_dev, 0xff, 0x04);
349         reg_w(gspca_dev, 0x02, 0x04);
350         reg_w(gspca_dev, 0x03, 0x54);
351         reg_w(gspca_dev, 0x04, 0x07);
352         reg_w(gspca_dev, 0x05, 0x2b);
353         reg_w(gspca_dev, 0x06, 0x09);
354         reg_w(gspca_dev, 0x07, 0x0f);
355         reg_w(gspca_dev, 0x08, 0x09);
356         reg_w(gspca_dev, 0x09, 0x00);
357         reg_w(gspca_dev, 0x0c, 0x07);
358         reg_w(gspca_dev, 0x0d, 0x00);
359         reg_w(gspca_dev, 0x0e, 0x00);
360         reg_w(gspca_dev, 0x0f, 0x62);
361         reg_w(gspca_dev, 0x10, 0x08);
362         reg_w(gspca_dev, 0x12, 0x07);
363         reg_w(gspca_dev, 0x13, 0x00);
364         reg_w(gspca_dev, 0x14, 0x00);
365         reg_w(gspca_dev, 0x15, 0x00);
366         reg_w(gspca_dev, 0x16, 0x00);
367         reg_w(gspca_dev, 0x17, 0x00);
368         reg_w(gspca_dev, 0x18, 0x00);
369         reg_w(gspca_dev, 0x19, 0x00);
370         reg_w(gspca_dev, 0x1a, 0x00);
371         reg_w(gspca_dev, 0x1b, 0x03);
372         reg_w(gspca_dev, 0x1c, 0xa0);
373         reg_w(gspca_dev, 0x1d, 0x01);
374         reg_w(gspca_dev, 0x1e, 0xf4);
375         reg_w(gspca_dev, 0x21, 0x00);
376         reg_w(gspca_dev, 0x22, 0x08);
377         reg_w(gspca_dev, 0x24, 0x03);
378         reg_w(gspca_dev, 0x26, 0x00);
379         reg_w(gspca_dev, 0x27, 0x01);
380         reg_w(gspca_dev, 0x28, 0xca);
381         reg_w(gspca_dev, 0x29, 0x10);
382         reg_w(gspca_dev, 0x2a, 0x06);
383         reg_w(gspca_dev, 0x2b, 0x78);
384         reg_w(gspca_dev, 0x2c, 0x00);
385         reg_w(gspca_dev, 0x2d, 0x00);
386         reg_w(gspca_dev, 0x2e, 0x00);
387         reg_w(gspca_dev, 0x2f, 0x00);
388         reg_w(gspca_dev, 0x30, 0x23);
389         reg_w(gspca_dev, 0x31, 0x28);
390         reg_w(gspca_dev, 0x32, 0x04);
391         reg_w(gspca_dev, 0x33, 0x11);
392         reg_w(gspca_dev, 0x34, 0x00);
393         reg_w(gspca_dev, 0x35, 0x00);
394         reg_w(gspca_dev, 0x11, 0x01);
395         setcontrast(gspca_dev);
396         setbrightness(gspca_dev);
397         setcolors(gspca_dev);
398
399         /* set correct resolution */
400         switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
401         case 2:                                 /* 160x120 */
402                 reg_w(gspca_dev, 0xff, 0x04);
403                 reg_w(gspca_dev, 0x02, 0x03);
404                 reg_w(gspca_dev, 0xff, 0x01);
405                 reg_w(gspca_dev, 0x08, 0x09);
406                 reg_w(gspca_dev, 0x17, 0x20);
407                 reg_w(gspca_dev, 0x1b, 0x00);
408 /*              reg_w(gspca_dev, 0x80, 0x69); */
409                 reg_w(gspca_dev, 0x87, 0x10);
410                 break;
411         case 1:                                 /* 320x240 */
412                 reg_w(gspca_dev, 0xff, 0x04);
413                 reg_w(gspca_dev, 0x02, 0x03);
414                 reg_w(gspca_dev, 0xff, 0x01);
415                 reg_w(gspca_dev, 0x08, 0x09);
416                 reg_w(gspca_dev, 0x17, 0x30);
417 /*              reg_w(gspca_dev, 0x80, 0x3f); */
418                 reg_w(gspca_dev, 0x87, 0x11);
419                 break;
420         case 0:                                 /* 640x480 */
421                 reg_w(gspca_dev, 0xff, 0x04);
422                 reg_w(gspca_dev, 0x02, 0x03);
423                 reg_w(gspca_dev, 0xff, 0x01);
424                 reg_w(gspca_dev, 0x08, 0x08);
425                 reg_w(gspca_dev, 0x17, 0x00);
426 /*              reg_w(gspca_dev, 0x80, 0x1c); */
427                 reg_w(gspca_dev, 0x87, 0x12);
428                 break;
429         }
430
431         /* start stream */
432         reg_w(gspca_dev, 0xff, 0x01);
433         reg_w(gspca_dev, 0x78, 0x04);
434         reg_w(gspca_dev, 0x78, 0x05);
435
436         if (sd->autogain) {
437                 sd->ag_cnt = AG_CNT_START;
438                 sd->avg_lum = 0;
439         } else {
440                 sd->ag_cnt = -1;
441         }
442 }
443
444 static void sd_stopN(struct gspca_dev *gspca_dev)
445 {
446         reg_w(gspca_dev, 0xff, 0x04);
447         reg_w(gspca_dev, 0x27, 0x80);
448         reg_w(gspca_dev, 0x28, 0xca);
449         reg_w(gspca_dev, 0x29, 0x53);
450         reg_w(gspca_dev, 0x2a, 0x0e);
451         reg_w(gspca_dev, 0xff, 0x01);
452         reg_w(gspca_dev, 0x3e, 0x20);
453         reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
454         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
455         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
456 }
457
458 static void sd_stop0(struct gspca_dev *gspca_dev)
459 {
460 }
461
462 /* this function is called at close time */
463 static void sd_close(struct gspca_dev *gspca_dev)
464 {
465         reg_w(gspca_dev, 0xff, 0x04);
466         reg_w(gspca_dev, 0x27, 0x80);
467         reg_w(gspca_dev, 0x28, 0xca);
468         reg_w(gspca_dev, 0x29, 0x53);
469         reg_w(gspca_dev, 0x2a, 0x0e);
470         reg_w(gspca_dev, 0xff, 0x01);
471         reg_w(gspca_dev, 0x3e, 0x20);
472         reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
473         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
474         reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
475 }
476
477 static void setautogain(struct gspca_dev *gspca_dev, int luma)
478 {
479         int luma_mean = 128;
480         int luma_delta = 20;
481         __u8 spring = 5;
482         int Gbright;
483
484         Gbright = reg_r(gspca_dev, 0x02);
485         PDEBUG(D_FRAM, "luma mean %d", luma);
486         if (luma < luma_mean - luma_delta ||
487             luma > luma_mean + luma_delta) {
488                 Gbright += (luma_mean - luma) >> spring;
489                 if (Gbright > 0x1a)
490                         Gbright = 0x1a;
491                 else if (Gbright < 4)
492                         Gbright = 4;
493                 PDEBUG(D_FRAM, "gbright %d", Gbright);
494                 reg_w(gspca_dev, 0xff, 0x04);
495                 reg_w(gspca_dev, 0x0f, Gbright);
496                 /* load registers to sensor (Bit 0, auto clear) */
497                 reg_w(gspca_dev, 0x11, 0x01);
498         }
499 }
500
501 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
502                         struct gspca_frame *frame,      /* target */
503                         __u8 *data,                     /* isoc packet */
504                         int len)                        /* iso packet length */
505 {
506         struct sd *sd = (struct sd *) gspca_dev;
507         unsigned char tmpbuf[4];
508         int i, p, ffseq;
509
510 /*      if (len < 5) { */
511         if (len < 6) {
512 /*              gspca_dev->last_packet_type = DISCARD_PACKET; */
513                 return;
514         }
515
516         ffseq = sd->ffseq;
517
518         for (p = 0; p < len - 6; p++) {
519                 if ((data[0 + p] == 0xff)
520                     && (data[1 + p] == 0xff)
521                     && (data[2 + p] == 0x00)
522                     && (data[3 + p] == 0xff)
523                     && (data[4 + p] == 0x96)) {
524
525                         /* start of frame */
526                         if (sd->ag_cnt >= 0 && p > 28) {
527                                 sd->avg_lum += data[p - 23];
528                                 if (--sd->ag_cnt < 0) {
529                                         sd->ag_cnt = AG_CNT_START;
530                                         setautogain(gspca_dev,
531                                                 sd->avg_lum / AG_CNT_START);
532                                         sd->avg_lum = 0;
533                                 }
534                         }
535
536                         /* copy the end of data to the current frame */
537                         frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
538                                                 data, p);
539
540                         /* put the JPEG header in the new frame */
541                         gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
542                                         (unsigned char *) pac7311_jpeg_header,
543                                         12);
544                         tmpbuf[0] = gspca_dev->height >> 8;
545                         tmpbuf[1] = gspca_dev->height & 0xff;
546                         tmpbuf[2] = gspca_dev->width >> 8;
547                         tmpbuf[3] = gspca_dev->width & 0xff;
548                         gspca_frame_add(gspca_dev, INTER_PACKET, frame,
549                                         tmpbuf, 4);
550                         gspca_frame_add(gspca_dev, INTER_PACKET, frame,
551                                 (unsigned char *) &pac7311_jpeg_header[16],
552                                 PAC7311_JPEG_HEADER_SIZE - 16);
553
554                         data += p + 7;
555                         len -= p + 7;
556                         ffseq = 0;
557                         break;
558                 }
559         }
560
561         /* remove the 'ff ff ff xx' sequences */
562         switch (ffseq) {
563         case 3:
564                 data += 1;
565                 len -= 1;
566                 break;
567         case 2:
568                 if (data[0] == 0xff) {
569                         data += 2;
570                         len -= 2;
571                         frame->data_end -= 2;
572                 }
573                 break;
574         case 1:
575                 if (data[0] == 0xff
576                     && data[1] == 0xff) {
577                         data += 3;
578                         len -= 3;
579                         frame->data_end -= 1;
580                 }
581                 break;
582         }
583         for (i = 0; i < len - 4; i++) {
584                 if (data[i] == 0xff
585                     && data[i + 1] == 0xff
586                     && data[i + 2] == 0xff) {
587                         memmove(&data[i], &data[i + 4], len - i - 4);
588                         len -= 4;
589                 }
590         }
591         ffseq = 0;
592         if (data[len - 4] == 0xff) {
593                 if (data[len - 3] == 0xff
594                     && data[len - 2] == 0xff) {
595                         len -= 4;
596                 }
597         } else if (data[len - 3] == 0xff) {
598                 if (data[len - 2] == 0xff
599                     && data[len - 1] == 0xff)
600                         ffseq = 3;
601         } else if (data[len - 2] == 0xff) {
602                 if (data[len - 1] == 0xff)
603                         ffseq = 2;
604         } else if (data[len - 1] == 0xff)
605                 ffseq = 1;
606         sd->ffseq = ffseq;
607         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
608 }
609
610 static void getbrightness(struct gspca_dev *gspca_dev)
611 {
612 /*      sd->brightness = reg_r(gspca_dev, 0x08);
613         return sd->brightness;  */
614 /*      PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
615 }
616
617
618
619 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
620 {
621         struct sd *sd = (struct sd *) gspca_dev;
622
623         sd->brightness = val;
624         if (gspca_dev->streaming)
625                 setbrightness(gspca_dev);
626         return 0;
627 }
628
629 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
630 {
631         struct sd *sd = (struct sd *) gspca_dev;
632
633         getbrightness(gspca_dev);
634         *val = sd->brightness;
635         return 0;
636 }
637
638 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
639 {
640         struct sd *sd = (struct sd *) gspca_dev;
641
642         sd->contrast = val;
643         if (gspca_dev->streaming)
644                 setcontrast(gspca_dev);
645         return 0;
646 }
647
648 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
649 {
650         struct sd *sd = (struct sd *) gspca_dev;
651
652 /*      getcontrast(gspca_dev); */
653         *val = sd->contrast;
654         return 0;
655 }
656
657 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
658 {
659         struct sd *sd = (struct sd *) gspca_dev;
660
661         sd->colors = val;
662         if (gspca_dev->streaming)
663                 setcolors(gspca_dev);
664         return 0;
665 }
666
667 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
668 {
669         struct sd *sd = (struct sd *) gspca_dev;
670
671 /*      getcolors(gspca_dev); */
672         *val = sd->colors;
673         return 0;
674 }
675
676 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
677 {
678         struct sd *sd = (struct sd *) gspca_dev;
679
680         sd->autogain = val;
681         if (val) {
682                 sd->ag_cnt = AG_CNT_START;
683                 sd->avg_lum = 0;
684         } else {
685                 sd->ag_cnt = -1;
686         }
687         return 0;
688 }
689
690 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
691 {
692         struct sd *sd = (struct sd *) gspca_dev;
693
694         *val = sd->autogain;
695         return 0;
696 }
697
698 /* sub-driver description */
699 static struct sd_desc sd_desc = {
700         .name = MODULE_NAME,
701         .ctrls = sd_ctrls,
702         .nctrls = ARRAY_SIZE(sd_ctrls),
703         .config = sd_config,
704         .open = sd_open,
705         .start = sd_start,
706         .stopN = sd_stopN,
707         .stop0 = sd_stop0,
708         .close = sd_close,
709         .pkt_scan = sd_pkt_scan,
710 };
711
712 /* -- module initialisation -- */
713 #define DVNM(name) .driver_info = (kernel_ulong_t) name
714 static __devinitdata struct usb_device_id device_table[] = {
715         {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
716         {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
717         {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
718         {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
719         {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
720                         /* and also ', Trust WB-3350p, SIGMA cam 2350' */
721         {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
722         {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
723         {}
724 };
725 MODULE_DEVICE_TABLE(usb, device_table);
726
727 /* -- device connect -- */
728 static int sd_probe(struct usb_interface *intf,
729                         const struct usb_device_id *id)
730 {
731         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
732                                 THIS_MODULE);
733 }
734
735 static struct usb_driver sd_driver = {
736         .name = MODULE_NAME,
737         .id_table = device_table,
738         .probe = sd_probe,
739         .disconnect = gspca_disconnect,
740 };
741
742 /* -- module insert / remove -- */
743 static int __init sd_mod_init(void)
744 {
745         if (usb_register(&sd_driver) < 0)
746                 return -1;
747         PDEBUG(D_PROBE, "registered");
748         return 0;
749 }
750 static void __exit sd_mod_exit(void)
751 {
752         usb_deregister(&sd_driver);
753         PDEBUG(D_PROBE, "deregistered");
754 }
755
756 module_init(sd_mod_init);
757 module_exit(sd_mod_exit);