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 /* Some documentation about various registers as determined by trial and error.
23 When the register addresses differ between the 7202 and the 7311 the 2
24 different addresses are written as 7302addr/7311addr, when one of the 2
25 addresses is a - sign that register description is not valid for the
31 -/0x08 Unknown compressor related, must always be 8 except when not
32 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
33 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
34 bits 345 seem to toggle per color gains on/off (inverted)
35 0x78 Global control, bit 6 controls the LED (inverted)
36 -/0x80 JPEG compression ratio ? Best not touched
41 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
42 the 7302, so one of 3, 6, 9, ...
43 -/0x0f Master gain 1-245, low value = high gain
44 0x10/- Master gain 0-31
45 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
49 #define MODULE_NAME "pac7311"
53 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
54 MODULE_DESCRIPTION("Pixart PAC7311");
55 MODULE_LICENSE("GPL");
57 /* specific webcam descriptor */
59 struct gspca_dev gspca_dev; /* !! must be the first item */
61 unsigned char brightness;
62 unsigned char contrast;
64 unsigned char autogain;
69 #define SENSOR_PAC7302 0
70 #define SENSOR_PAC7311 1
73 u8 autogain_ignore_frames;
78 /* V4L2 controls supported by the driver */
79 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
80 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
81 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
82 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
83 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
84 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
85 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
86 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
87 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
88 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
89 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
90 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
92 static struct ctrl sd_ctrls[] = {
95 .id = V4L2_CID_BRIGHTNESS,
96 .type = V4L2_CTRL_TYPE_INTEGER,
99 #define BRIGHTNESS_MAX 0x20
100 .maximum = BRIGHTNESS_MAX,
102 #define BRIGHTNESS_DEF 0x10
103 .default_value = BRIGHTNESS_DEF,
105 .set = sd_setbrightness,
106 .get = sd_getbrightness,
110 .id = V4L2_CID_CONTRAST,
111 .type = V4L2_CTRL_TYPE_INTEGER,
114 #define CONTRAST_MAX 255
115 .maximum = CONTRAST_MAX,
117 #define CONTRAST_DEF 127
118 .default_value = CONTRAST_DEF,
120 .set = sd_setcontrast,
121 .get = sd_getcontrast,
125 .id = V4L2_CID_SATURATION,
126 .type = V4L2_CTRL_TYPE_INTEGER,
127 .name = "Saturation",
129 #define COLOR_MAX 255
130 .maximum = COLOR_MAX,
132 #define COLOR_DEF 127
133 .default_value = COLOR_DEF,
140 .id = V4L2_CID_AUTOGAIN,
141 .type = V4L2_CTRL_TYPE_BOOLEAN,
146 #define AUTOGAIN_DEF 1
147 .default_value = AUTOGAIN_DEF,
149 .set = sd_setautogain,
150 .get = sd_getautogain,
152 /* next controls work with pac7302 only */
156 .id = V4L2_CID_HFLIP,
157 .type = V4L2_CTRL_TYPE_BOOLEAN,
163 .default_value = HFLIP_DEF,
171 .id = V4L2_CID_VFLIP,
172 .type = V4L2_CTRL_TYPE_BOOLEAN,
178 .default_value = VFLIP_DEF,
185 static struct v4l2_pix_format vga_mode[] = {
186 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
188 .sizeimage = 160 * 120 * 3 / 8 + 590,
189 .colorspace = V4L2_COLORSPACE_JPEG,
191 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
193 .sizeimage = 320 * 240 * 3 / 8 + 590,
194 .colorspace = V4L2_COLORSPACE_JPEG,
196 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
198 .sizeimage = 640 * 480 * 3 / 8 + 590,
199 .colorspace = V4L2_COLORSPACE_JPEG,
204 static const __u8 probe_7302[] = {
206 0xff, 0x01, /* page 1 */
207 0x78, 0x00, /* deactivate */
209 0x78, 0x40, /* led off */
211 static const __u8 start_7302[] = {
212 /* index, len, [value]* */
213 0xff, 1, 0x00, /* page 0 */
214 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
215 0x00, 0x00, 0x00, 0x00,
216 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
217 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
218 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
222 0x3a, 3, 0x14, 0xff, 0x5a,
223 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
226 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
228 0x6e, 3, 0x08, 0x06, 0x00,
229 0x72, 3, 0x00, 0xff, 0x00,
230 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
231 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
232 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
233 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
238 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
240 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
243 0xff, 1, 0x01, /* page 1 */
244 0x12, 3, 0x02, 0x00, 0x01,
246 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
248 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
250 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
251 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
252 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
255 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
256 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
258 0xff, 1, 0x02, /* page 2 */
260 0xff, 1, 0x03, /* page 3 */
261 0x00, 255, /* load the page 3 */
263 0xff, 1, 0x02, /* page 2 */
265 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
267 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
268 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
270 0xff, 1, 0x01, /* page 1 */
272 0, 0 /* end of sequence */
275 /* page 3 - the value 0xaa says skip the index - see reg_w_page() */
276 static const __u8 page3_7302[] = {
277 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
278 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
279 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
281 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
282 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
283 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
284 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
287 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
291 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
292 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
293 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
300 static const __u8 probe_7311[] = {
301 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
302 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
303 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
313 static const __u8 start_7311[] = {
314 /* index, len, [value]* */
315 0xff, 1, 0x01, /* page 1 */
316 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
317 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
318 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
319 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
323 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
324 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
325 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
326 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
328 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
329 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
330 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
332 0x96, 3, 0x01, 0x08, 0x04,
333 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
334 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
335 0x3f, 0x00, 0x0a, 0x01, 0x00,
336 0xff, 1, 0x04, /* page 4 */
337 0x00, 254, /* load the page 4 */
339 0, 0 /* end of sequence */
342 /* page 4 - the value 0xaa says skip the index - see reg_w_page() */
343 static const __u8 page4_7311[] = {
344 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
345 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
346 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
348 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
349 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
350 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
353 static void reg_w_buf(struct gspca_dev *gspca_dev,
355 const char *buffer, int len)
357 memcpy(gspca_dev->usb_buf, buffer, len);
358 usb_control_msg(gspca_dev->dev,
359 usb_sndctrlpipe(gspca_dev->dev, 0),
361 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
363 index, gspca_dev->usb_buf, len,
368 static void reg_w(struct gspca_dev *gspca_dev,
372 gspca_dev->usb_buf[0] = value;
373 usb_control_msg(gspca_dev->dev,
374 usb_sndctrlpipe(gspca_dev->dev, 0),
376 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
377 value, index, gspca_dev->usb_buf, 1,
381 static void reg_w_seq(struct gspca_dev *gspca_dev,
382 const __u8 *seq, int len)
385 reg_w(gspca_dev, seq[0], seq[1]);
390 /* load the beginning of a page */
391 static void reg_w_page(struct gspca_dev *gspca_dev,
392 const __u8 *page, int len)
396 for (index = 0; index < len; index++) {
397 if (page[index] == 0xaa) /* skip this index */
399 gspca_dev->usb_buf[0] = page[index];
400 usb_control_msg(gspca_dev->dev,
401 usb_sndctrlpipe(gspca_dev->dev, 0),
403 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
404 0, index, gspca_dev->usb_buf, 1,
409 /* output a variable sequence */
410 static void reg_w_var(struct gspca_dev *gspca_dev,
422 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
425 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
429 PDEBUG(D_ERR|D_STREAM,
430 "Incorrect variable sequence");
435 reg_w_buf(gspca_dev, index, seq, len);
439 reg_w_buf(gspca_dev, index, seq, 8);
449 /* this function is called at probe time */
450 static int sd_config(struct gspca_dev *gspca_dev,
451 const struct usb_device_id *id)
453 struct sd *sd = (struct sd *) gspca_dev;
456 cam = &gspca_dev->cam;
459 sd->sensor = id->driver_info;
460 if (sd->sensor == SENSOR_PAC7302) {
461 PDEBUG(D_CONF, "Find Sensor PAC7302");
462 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
464 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
467 PDEBUG(D_CONF, "Find Sensor PAC7311");
468 reg_w_seq(gspca_dev, probe_7311, sizeof probe_7311);
470 cam->cam_mode = vga_mode;
471 cam->nmodes = ARRAY_SIZE(vga_mode);
472 gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
476 sd->brightness = BRIGHTNESS_DEF;
477 sd->contrast = CONTRAST_DEF;
478 sd->colors = COLOR_DEF;
479 sd->autogain = AUTOGAIN_DEF;
480 sd->hflip = HFLIP_DEF;
481 sd->vflip = VFLIP_DEF;
486 static void setbrightcont(struct gspca_dev *gspca_dev)
488 struct sd *sd = (struct sd *) gspca_dev;
490 static const __u8 max[10] =
491 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
493 static const __u8 delta[10] =
494 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
497 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
498 for (i = 0; i < 10; i++) {
500 v += (sd->brightness - BRIGHTNESS_MAX)
501 * 150 / BRIGHTNESS_MAX; /* 200 ? */
502 v -= delta[i] * sd->contrast / CONTRAST_MAX;
507 reg_w(gspca_dev, 0xa2 + i, v);
509 reg_w(gspca_dev, 0xdc, 0x01);
512 /* This function is used by pac7302 only */
513 static void setbrightness(struct gspca_dev *gspca_dev)
515 struct sd *sd = (struct sd *) gspca_dev;
518 if (sd->sensor == SENSOR_PAC7302) {
519 setbrightcont(gspca_dev);
522 /* HDG: this is not brightness but gain, I'll add gain and exposure controls
526 brightness = BRIGHTNESS_MAX - sd->brightness;
527 reg_w(gspca_dev, 0xff, 0x04);
528 reg_w(gspca_dev, 0x0e, 0x00);
529 reg_w(gspca_dev, 0x0f, brightness);
530 /* load registers to sensor (Bit 0, auto clear) */
531 reg_w(gspca_dev, 0x11, 0x01);
532 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
535 static void setcontrast(struct gspca_dev *gspca_dev)
537 struct sd *sd = (struct sd *) gspca_dev;
539 if (sd->sensor == SENSOR_PAC7302) {
540 setbrightcont(gspca_dev);
543 reg_w(gspca_dev, 0xff, 0x04);
544 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
545 /* load registers to sensor (Bit 0, auto clear) */
546 reg_w(gspca_dev, 0x11, 0x01);
549 /* This function is used by pac7302 only */
550 static void setcolors(struct gspca_dev *gspca_dev)
552 struct sd *sd = (struct sd *) gspca_dev;
554 if (sd->sensor == SENSOR_PAC7302) {
556 static const int a[9] =
557 {217, -212, 0, -101, 170, -67, -38, -315, 355};
558 static const int b[9] =
559 {19, 106, 0, 19, 106, 1, 19, 106, 1};
561 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
562 reg_w(gspca_dev, 0x11, 0x01);
563 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
564 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
565 for (i = 0; i < 9; i++) {
566 v = a[i] * sd->colors / COLOR_MAX + b[i];
567 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
568 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
570 reg_w(gspca_dev, 0xdc, 0x01);
571 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
575 static void sethvflip(struct gspca_dev *gspca_dev)
577 struct sd *sd = (struct sd *) gspca_dev;
580 if (sd->sensor == SENSOR_PAC7302) {
581 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
582 data = (sd->hflip ? 0x00 : 0x08)
583 | (sd->vflip ? 0x04 : 0x00);
585 reg_w(gspca_dev, 0xff, 0x04); /* page 3 */
586 data = (sd->hflip ? 0x04 : 0x00)
587 | (sd->vflip ? 0x08 : 0x00);
589 reg_w(gspca_dev, 0x21, data);
590 reg_w(gspca_dev, 0x11, 0x01);
593 /* this function is called at open time */
594 static int sd_open(struct gspca_dev *gspca_dev)
599 static void sd_start(struct gspca_dev *gspca_dev)
601 struct sd *sd = (struct sd *) gspca_dev;
605 if (sd->sensor == SENSOR_PAC7302)
606 reg_w_var(gspca_dev, start_7302);
608 reg_w_var(gspca_dev, start_7311);
610 setcontrast(gspca_dev);
611 setbrightness(gspca_dev);
612 setcolors(gspca_dev);
614 /* set correct resolution */
615 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
616 case 2: /* 160x120 pac7311 */
617 reg_w(gspca_dev, 0xff, 0x04);
618 reg_w(gspca_dev, 0x02, 0x03);
619 reg_w(gspca_dev, 0xff, 0x01);
620 reg_w(gspca_dev, 0x08, 0x09);
621 reg_w(gspca_dev, 0x17, 0x20);
622 reg_w(gspca_dev, 0x1b, 0x00);
623 reg_w(gspca_dev, 0x87, 0x10);
625 case 1: /* 320x240 pac7311 */
626 reg_w(gspca_dev, 0xff, 0x04);
627 reg_w(gspca_dev, 0x02, 0x03);
628 reg_w(gspca_dev, 0xff, 0x01);
629 reg_w(gspca_dev, 0x08, 0x09);
630 reg_w(gspca_dev, 0x17, 0x30);
631 reg_w(gspca_dev, 0x87, 0x11);
633 case 0: /* 640x480 */
634 if (sd->sensor == SENSOR_PAC7302)
636 reg_w(gspca_dev, 0xff, 0x04);
637 reg_w(gspca_dev, 0x02, 0x07);
638 reg_w(gspca_dev, 0xff, 0x01);
639 reg_w(gspca_dev, 0x08, 0x08);
640 reg_w(gspca_dev, 0x17, 0x00);
641 reg_w(gspca_dev, 0x87, 0x12);
646 reg_w(gspca_dev, 0xff, 0x01);
647 if (sd->sensor == SENSOR_PAC7302) {
648 sethvflip(gspca_dev);
649 reg_w(gspca_dev, 0x78, 0x01);
650 reg_w(gspca_dev, 0xff, 0x01);
651 reg_w(gspca_dev, 0x78, 0x01);
653 reg_w(gspca_dev, 0x78, 0x44);
654 reg_w(gspca_dev, 0x78, 0x45);
658 sd->autogain_ignore_frames = 0;
659 atomic_set(&sd->avg_lum, -1);
662 static void sd_stopN(struct gspca_dev *gspca_dev)
664 struct sd *sd = (struct sd *) gspca_dev;
666 if (sd->sensor == SENSOR_PAC7302) {
667 reg_w(gspca_dev, 0xff, 0x01);
668 reg_w(gspca_dev, 0x78, 0x00);
669 reg_w(gspca_dev, 0x78, 0x00);
672 reg_w(gspca_dev, 0xff, 0x04);
673 reg_w(gspca_dev, 0x27, 0x80);
674 reg_w(gspca_dev, 0x28, 0xca);
675 reg_w(gspca_dev, 0x29, 0x53);
676 reg_w(gspca_dev, 0x2a, 0x0e);
677 reg_w(gspca_dev, 0xff, 0x01);
678 reg_w(gspca_dev, 0x3e, 0x20);
679 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
680 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
681 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
684 static void sd_stop0(struct gspca_dev *gspca_dev)
686 struct sd *sd = (struct sd *) gspca_dev;
688 if (sd->sensor == SENSOR_PAC7302) {
689 reg_w(gspca_dev, 0xff, 0x01);
690 reg_w(gspca_dev, 0x78, 0x40);
694 /* this function is called at close time */
695 static void sd_close(struct gspca_dev *gspca_dev)
699 static void do_autogain(struct gspca_dev *gspca_dev)
703 static const unsigned char pac7311_jpeg_header1[] = {
704 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
707 static const unsigned char pac7311_jpeg_header2[] = {
708 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
709 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
712 /* Include pac common sof detection functions */
713 #include "pac_common.h"
715 /* this function is run at interrupt level */
716 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
717 struct gspca_frame *frame, /* target */
718 __u8 *data, /* isoc packet */
719 int len) /* iso packet length */
721 struct sd *sd = (struct sd *) gspca_dev;
724 sof = pac_find_sof(gspca_dev, data, len);
726 unsigned char tmpbuf[4];
727 int n, lum_offset, footer_length;
729 if (sd->sensor == SENSOR_PAC7302) {
730 lum_offset = 34 + sizeof pac_sof_marker;
733 lum_offset = 24 + sizeof pac_sof_marker;
737 /* Finish decoding current frame */
738 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
740 frame->data_end += n;
743 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
745 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
746 frame->data_end[-2] == 0xff &&
747 frame->data_end[-1] == 0xd9)
748 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
755 /* Get average lumination */
756 if (gspca_dev->last_packet_type == LAST_PACKET &&
758 if (sd->sensor == SENSOR_PAC7302)
759 atomic_set(&sd->avg_lum,
760 (data[-lum_offset] << 8) |
761 data[-lum_offset + 1]);
763 atomic_set(&sd->avg_lum,
765 data[-lum_offset + 1]);
767 atomic_set(&sd->avg_lum, -1);
770 /* Start the new frame with the jpeg header */
771 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
772 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
773 if (sd->sensor == SENSOR_PAC7302) {
774 /* The PAC7302 has the image rotated 90 degrees */
775 tmpbuf[0] = gspca_dev->width >> 8;
776 tmpbuf[1] = gspca_dev->width & 0xff;
777 tmpbuf[2] = gspca_dev->height >> 8;
778 tmpbuf[3] = gspca_dev->height & 0xff;
780 tmpbuf[0] = gspca_dev->height >> 8;
781 tmpbuf[1] = gspca_dev->height & 0xff;
782 tmpbuf[2] = gspca_dev->width >> 8;
783 tmpbuf[3] = gspca_dev->width & 0xff;
785 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
786 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
787 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
789 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
792 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
794 struct sd *sd = (struct sd *) gspca_dev;
796 sd->brightness = val;
797 if (gspca_dev->streaming)
798 setbrightness(gspca_dev);
802 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
804 struct sd *sd = (struct sd *) gspca_dev;
806 *val = sd->brightness;
810 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
812 struct sd *sd = (struct sd *) gspca_dev;
815 if (gspca_dev->streaming)
816 setcontrast(gspca_dev);
820 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
822 struct sd *sd = (struct sd *) gspca_dev;
828 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
830 struct sd *sd = (struct sd *) gspca_dev;
833 if (gspca_dev->streaming)
834 setcolors(gspca_dev);
838 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
840 struct sd *sd = (struct sd *) gspca_dev;
846 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
848 struct sd *sd = (struct sd *) gspca_dev;
855 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
857 struct sd *sd = (struct sd *) gspca_dev;
863 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
865 struct sd *sd = (struct sd *) gspca_dev;
868 if (gspca_dev->streaming)
869 sethvflip(gspca_dev);
873 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
875 struct sd *sd = (struct sd *) gspca_dev;
881 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
883 struct sd *sd = (struct sd *) gspca_dev;
886 if (gspca_dev->streaming)
887 sethvflip(gspca_dev);
891 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
893 struct sd *sd = (struct sd *) gspca_dev;
899 /* sub-driver description */
900 static struct sd_desc sd_desc = {
903 .nctrls = ARRAY_SIZE(sd_ctrls),
910 .pkt_scan = sd_pkt_scan,
911 .dq_callback = do_autogain,
914 /* -- module initialisation -- */
915 static __devinitdata struct usb_device_id device_table[] = {
916 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
917 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
918 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
919 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
920 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
921 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
922 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
925 MODULE_DEVICE_TABLE(usb, device_table);
927 /* -- device connect -- */
928 static int sd_probe(struct usb_interface *intf,
929 const struct usb_device_id *id)
931 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
935 static struct usb_driver sd_driver = {
937 .id_table = device_table,
939 .disconnect = gspca_disconnect,
941 .suspend = gspca_suspend,
942 .resume = gspca_resume,
946 /* -- module insert / remove -- */
947 static int __init sd_mod_init(void)
949 if (usb_register(&sd_driver) < 0)
951 PDEBUG(D_PROBE, "registered");
954 static void __exit sd_mod_exit(void)
956 usb_deregister(&sd_driver);
957 PDEBUG(D_PROBE, "deregistered");
960 module_init(sd_mod_init);
961 module_exit(sd_mod_exit);