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