2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
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
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.
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
22 #define MODULE_NAME "pac7311"
26 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
27 MODULE_DESCRIPTION("Pixart PAC7311");
28 MODULE_LICENSE("GPL");
30 /* specific webcam descriptor */
32 struct gspca_dev gspca_dev; /* !! must be the first item */
38 unsigned char brightness;
39 unsigned char contrast;
41 unsigned char autogain;
45 #define AG_CNT_START 13
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);
58 static struct ctrl sd_ctrls[] = {
61 .id = V4L2_CID_BRIGHTNESS,
62 .type = V4L2_CTRL_TYPE_INTEGER,
65 #define BRIGHTNESS_MAX 0x20
66 .maximum = BRIGHTNESS_MAX,
68 #define BRIGHTNESS_DEF 0x10
69 .default_value = BRIGHTNESS_DEF,
71 .set = sd_setbrightness,
72 .get = sd_getbrightness,
76 .id = V4L2_CID_CONTRAST,
77 .type = V4L2_CTRL_TYPE_INTEGER,
82 #define CONTRAST_DEF 127
83 .default_value = CONTRAST_DEF,
85 .set = sd_setcontrast,
86 .get = sd_getcontrast,
90 .id = V4L2_CID_SATURATION,
91 .type = V4L2_CTRL_TYPE_INTEGER,
97 .default_value = COLOR_DEF,
104 .id = V4L2_CID_AUTOGAIN,
105 .type = V4L2_CTRL_TYPE_BOOLEAN,
110 #define AUTOGAIN_DEF 1
111 .default_value = AUTOGAIN_DEF,
113 .set = sd_setautogain,
114 .get = sd_getautogain,
118 static struct v4l2_pix_format vga_mode[] = {
119 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
121 .sizeimage = 160 * 120 * 3 / 8 + 590,
122 .colorspace = V4L2_COLORSPACE_JPEG,
124 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
126 .sizeimage = 320 * 240 * 3 / 8 + 590,
127 .colorspace = V4L2_COLORSPACE_JPEG,
129 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .sizeimage = 640 * 480 * 3 / 8 + 590,
132 .colorspace = V4L2_COLORSPACE_JPEG,
136 #define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
138 static const __u8 pac7311_jpeg_header[] = {
140 0xff, 0xe0, 0x00, 0x03, 0x20,
141 0xff, 0xc0, 0x00, 0x11, 0x08,
142 0x01, 0xe0, /* 12: height */
143 0x02, 0x80, /* 14: width */
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
208 static void reg_w_buf(struct gspca_dev *gspca_dev,
210 const char *buffer, __u16 len)
212 memcpy(gspca_dev->usb_buf, buffer, len);
213 usb_control_msg(gspca_dev->dev,
214 usb_sndctrlpipe(gspca_dev->dev, 0),
216 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
218 index, gspca_dev->usb_buf, len,
222 static __u8 reg_r(struct gspca_dev *gspca_dev,
225 usb_control_msg(gspca_dev->dev,
226 usb_rcvctrlpipe(gspca_dev->dev, 0),
228 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
230 index, gspca_dev->usb_buf, 1,
232 return gspca_dev->usb_buf[0];
235 static void reg_w(struct gspca_dev *gspca_dev,
239 gspca_dev->usb_buf[0] = value;
240 usb_control_msg(gspca_dev->dev,
241 usb_sndctrlpipe(gspca_dev->dev, 0),
243 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
244 value, index, gspca_dev->usb_buf, 1,
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)
252 struct sd *sd = (struct sd *) gspca_dev;
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);
267 cam = &gspca_dev->cam;
269 cam->cam_mode = vga_mode;
270 cam->nmodes = ARRAY_SIZE(vga_mode);
272 sd->brightness = BRIGHTNESS_DEF;
273 sd->contrast = CONTRAST_DEF;
274 sd->colors = COLOR_DEF;
275 sd->autogain = AUTOGAIN_DEF;
280 static void setbrightness(struct gspca_dev *gspca_dev)
282 struct sd *sd = (struct sd *) gspca_dev;
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);
295 static void setcontrast(struct gspca_dev *gspca_dev)
297 struct sd *sd = (struct sd *) gspca_dev;
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);
306 static void setcolors(struct gspca_dev *gspca_dev)
308 struct sd *sd = (struct sd *) gspca_dev;
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);
317 static void setautogain(struct gspca_dev *gspca_dev)
319 struct sd *sd = (struct sd *) gspca_dev;
323 sd->ag_cnt = AG_CNT_START;
329 /* this function is called at open time */
330 static int sd_open(struct gspca_dev *gspca_dev)
332 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
336 static void sd_start(struct gspca_dev *gspca_dev)
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);
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);
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);
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);
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);
445 reg_w(gspca_dev, 0xff, 0x01);
446 reg_w(gspca_dev, 0x78, 0x04);
447 reg_w(gspca_dev, 0x78, 0x05);
450 static void sd_stopN(struct gspca_dev *gspca_dev)
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 */
464 static void sd_stop0(struct gspca_dev *gspca_dev)
468 /* this function is called at close time */
469 static void sd_close(struct gspca_dev *gspca_dev)
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 */
483 static void do_autogain(struct gspca_dev *gspca_dev)
485 struct sd *sd = (struct sd *) gspca_dev;
492 if (!atomic_read(&sd->do_gain))
494 atomic_set(&sd->do_gain, 0);
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;
504 else if (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);
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 */
519 struct sd *sd = (struct sd *) gspca_dev;
520 unsigned char tmpbuf[4];
525 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
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)) {
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);
546 atomic_set(&sd->do_gain, 1);
550 /* copy the end of data to the current frame */
551 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
554 /* put the JPEG header in the new frame */
555 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
556 (unsigned char *) pac7311_jpeg_header,
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,
564 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
565 (unsigned char *) &pac7311_jpeg_header[16],
566 PAC7311_JPEG_HEADER_SIZE - 16);
575 /* remove the 'ff ff ff xx' sequences */
582 if (data[0] == 0xff) {
585 frame->data_end -= 2;
590 && data[1] == 0xff) {
593 frame->data_end -= 1;
597 for (i = 0; i < len - 4; i++) {
599 && data[i + 1] == 0xff
600 && data[i + 2] == 0xff) {
601 memmove(&data[i], &data[i + 4], len - i - 4);
606 if (data[len - 4] == 0xff) {
607 if (data[len - 3] == 0xff
608 && data[len - 2] == 0xff) {
611 } else if (data[len - 3] == 0xff) {
612 if (data[len - 2] == 0xff
613 && data[len - 1] == 0xff)
615 } else if (data[len - 2] == 0xff) {
616 if (data[len - 1] == 0xff)
618 } else if (data[len - 1] == 0xff)
621 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
624 static void getbrightness(struct gspca_dev *gspca_dev)
626 /* sd->brightness = reg_r(gspca_dev, 0x08);
627 return sd->brightness; */
628 /* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
633 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
635 struct sd *sd = (struct sd *) gspca_dev;
637 sd->brightness = val;
638 if (gspca_dev->streaming)
639 setbrightness(gspca_dev);
643 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
645 struct sd *sd = (struct sd *) gspca_dev;
647 getbrightness(gspca_dev);
648 *val = sd->brightness;
652 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
654 struct sd *sd = (struct sd *) gspca_dev;
657 if (gspca_dev->streaming)
658 setcontrast(gspca_dev);
662 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
664 struct sd *sd = (struct sd *) gspca_dev;
666 /* getcontrast(gspca_dev); */
671 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
673 struct sd *sd = (struct sd *) gspca_dev;
676 if (gspca_dev->streaming)
677 setcolors(gspca_dev);
681 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
683 struct sd *sd = (struct sd *) gspca_dev;
685 /* getcolors(gspca_dev); */
690 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
692 struct sd *sd = (struct sd *) gspca_dev;
695 if (gspca_dev->streaming)
696 setautogain(gspca_dev);
700 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
702 struct sd *sd = (struct sd *) gspca_dev;
708 /* sub-driver description */
709 static struct sd_desc sd_desc = {
712 .nctrls = ARRAY_SIZE(sd_ctrls),
719 .pkt_scan = sd_pkt_scan,
720 .dq_callback = do_autogain,
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)},
734 MODULE_DEVICE_TABLE(usb, device_table);
736 /* -- device connect -- */
737 static int sd_probe(struct usb_interface *intf,
738 const struct usb_device_id *id)
740 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
744 static struct usb_driver sd_driver = {
746 .id_table = device_table,
748 .disconnect = gspca_disconnect,
751 /* -- module insert / remove -- */
752 static int __init sd_mod_init(void)
754 if (usb_register(&sd_driver) < 0)
756 PDEBUG(D_PROBE, "registered");
759 static void __exit sd_mod_exit(void)
761 usb_deregister(&sd_driver);
762 PDEBUG(D_PROBE, "deregistered");
765 module_init(sd_mod_init);
766 module_exit(sd_mod_exit);