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 probe and resume time */
594 static int sd_init(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 static void do_autogain(struct gspca_dev *gspca_dev)
698 static const unsigned char pac7311_jpeg_header1[] = {
699 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
702 static const unsigned char pac7311_jpeg_header2[] = {
703 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
704 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
707 /* Include pac common sof detection functions */
708 #include "pac_common.h"
710 /* this function is run at interrupt level */
711 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
712 struct gspca_frame *frame, /* target */
713 __u8 *data, /* isoc packet */
714 int len) /* iso packet length */
716 struct sd *sd = (struct sd *) gspca_dev;
719 sof = pac_find_sof(gspca_dev, data, len);
721 unsigned char tmpbuf[4];
722 int n, lum_offset, footer_length;
724 if (sd->sensor == SENSOR_PAC7302) {
725 lum_offset = 34 + sizeof pac_sof_marker;
728 lum_offset = 24 + sizeof pac_sof_marker;
732 /* Finish decoding current frame */
733 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
735 frame->data_end += n;
738 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
740 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
741 frame->data_end[-2] == 0xff &&
742 frame->data_end[-1] == 0xd9)
743 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
750 /* Get average lumination */
751 if (gspca_dev->last_packet_type == LAST_PACKET &&
753 if (sd->sensor == SENSOR_PAC7302)
754 atomic_set(&sd->avg_lum,
755 (data[-lum_offset] << 8) |
756 data[-lum_offset + 1]);
758 atomic_set(&sd->avg_lum,
760 data[-lum_offset + 1]);
762 atomic_set(&sd->avg_lum, -1);
765 /* Start the new frame with the jpeg header */
766 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
767 pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
768 if (sd->sensor == SENSOR_PAC7302) {
769 /* The PAC7302 has the image rotated 90 degrees */
770 tmpbuf[0] = gspca_dev->width >> 8;
771 tmpbuf[1] = gspca_dev->width & 0xff;
772 tmpbuf[2] = gspca_dev->height >> 8;
773 tmpbuf[3] = gspca_dev->height & 0xff;
775 tmpbuf[0] = gspca_dev->height >> 8;
776 tmpbuf[1] = gspca_dev->height & 0xff;
777 tmpbuf[2] = gspca_dev->width >> 8;
778 tmpbuf[3] = gspca_dev->width & 0xff;
780 gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
781 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
782 pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
784 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
787 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
789 struct sd *sd = (struct sd *) gspca_dev;
791 sd->brightness = val;
792 if (gspca_dev->streaming)
793 setbrightness(gspca_dev);
797 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
799 struct sd *sd = (struct sd *) gspca_dev;
801 *val = sd->brightness;
805 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
807 struct sd *sd = (struct sd *) gspca_dev;
810 if (gspca_dev->streaming)
811 setcontrast(gspca_dev);
815 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
817 struct sd *sd = (struct sd *) gspca_dev;
823 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
825 struct sd *sd = (struct sd *) gspca_dev;
828 if (gspca_dev->streaming)
829 setcolors(gspca_dev);
833 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
835 struct sd *sd = (struct sd *) gspca_dev;
841 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
843 struct sd *sd = (struct sd *) gspca_dev;
850 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
852 struct sd *sd = (struct sd *) gspca_dev;
858 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
860 struct sd *sd = (struct sd *) gspca_dev;
863 if (gspca_dev->streaming)
864 sethvflip(gspca_dev);
868 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
870 struct sd *sd = (struct sd *) gspca_dev;
876 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
878 struct sd *sd = (struct sd *) gspca_dev;
881 if (gspca_dev->streaming)
882 sethvflip(gspca_dev);
886 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
888 struct sd *sd = (struct sd *) gspca_dev;
894 /* sub-driver description */
895 static struct sd_desc sd_desc = {
898 .nctrls = ARRAY_SIZE(sd_ctrls),
904 .pkt_scan = sd_pkt_scan,
905 .dq_callback = do_autogain,
908 /* -- module initialisation -- */
909 static __devinitdata struct usb_device_id device_table[] = {
910 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
911 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
912 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
913 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
914 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
915 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
916 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
919 MODULE_DEVICE_TABLE(usb, device_table);
921 /* -- device connect -- */
922 static int sd_probe(struct usb_interface *intf,
923 const struct usb_device_id *id)
925 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
929 static struct usb_driver sd_driver = {
931 .id_table = device_table,
933 .disconnect = gspca_disconnect,
935 .suspend = gspca_suspend,
936 .resume = gspca_resume,
940 /* -- module insert / remove -- */
941 static int __init sd_mod_init(void)
943 if (usb_register(&sd_driver) < 0)
945 PDEBUG(D_PROBE, "registered");
948 static void __exit sd_mod_exit(void)
950 usb_deregister(&sd_driver);
951 PDEBUG(D_PROBE, "deregistered");
954 module_init(sd_mod_init);
955 module_exit(sd_mod_exit);