2 * Pixart PAC207BCA library
4 * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
5 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
6 * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
8 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #define MODULE_NAME "pac207"
30 #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
31 static const char version[] = "2.1.5";
33 MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
34 MODULE_DESCRIPTION("Pixart PAC207");
35 MODULE_LICENSE("GPL");
37 #define PAC207_CTRL_TIMEOUT 100 /* ms */
39 #define PAC207_BRIGHTNESS_MIN 0
40 #define PAC207_BRIGHTNESS_MAX 255
41 #define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */
43 /* An exposure value of 4 also works (3 does not) but then we need to lower
44 the compression balance setting when in 352x288 mode, otherwise the usb
45 bandwidth is not enough and packets get dropped resulting in corrupt
46 frames. The problem with this is that when the compression balance gets
47 lowered below 0x80, the pac207 starts using a different compression
48 algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
49 and currently we do not know how to decompress these lines, so for now
50 we use a minimum exposure value of 5 */
51 #define PAC207_EXPOSURE_MIN 5
52 #define PAC207_EXPOSURE_MAX 26
53 #define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
54 #define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
56 #define PAC207_GAIN_MIN 0
57 #define PAC207_GAIN_MAX 31
58 #define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
59 #define PAC207_GAIN_KNEE 20
61 #define PAC207_AUTOGAIN_DEADZONE 30
62 /* We calculating the autogain at the end of the transfer of a frame, at this
63 moment a frame with the old settings is being transmitted, and a frame is
64 being captured with the old settings. So if we adjust the autogain we must
65 ignore atleast the 2 next frames for the new settings to come into effect
66 before doing any other adjustments */
67 #define PAC207_AUTOGAIN_IGNORE_FRAMES 3
69 /* specific webcam descriptor */
71 struct gspca_dev gspca_dev; /* !! must be the first item */
82 u8 autogain_ignore_frames;
87 /* V4L2 controls supported by the driver */
88 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
89 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
90 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
91 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
92 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
93 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
94 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
95 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
97 static struct ctrl sd_ctrls[] = {
98 #define SD_BRIGHTNESS 0
101 .id = V4L2_CID_BRIGHTNESS,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Brightness",
104 .minimum = PAC207_BRIGHTNESS_MIN,
105 .maximum = PAC207_BRIGHTNESS_MAX,
107 .default_value = PAC207_BRIGHTNESS_DEFAULT,
110 .set = sd_setbrightness,
111 .get = sd_getbrightness,
113 #define SD_EXPOSURE 1
116 .id = V4L2_CID_EXPOSURE,
117 .type = V4L2_CTRL_TYPE_INTEGER,
119 .minimum = PAC207_EXPOSURE_MIN,
120 .maximum = PAC207_EXPOSURE_MAX,
122 .default_value = PAC207_EXPOSURE_DEFAULT,
125 .set = sd_setexposure,
126 .get = sd_getexposure,
128 #define SD_AUTOGAIN 2
131 .id = V4L2_CID_AUTOGAIN,
132 .type = V4L2_CTRL_TYPE_BOOLEAN,
140 .set = sd_setautogain,
141 .get = sd_getautogain,
147 .type = V4L2_CTRL_TYPE_INTEGER,
149 .minimum = PAC207_GAIN_MIN,
150 .maximum = PAC207_GAIN_MAX,
152 .default_value = PAC207_GAIN_DEFAULT,
160 static struct v4l2_pix_format sif_mode[] = {
161 {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
163 .sizeimage = (176 + 2) * 144,
164 /* uncompressed, add 2 bytes / line for line header */
165 .colorspace = V4L2_COLORSPACE_SRGB,
167 {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
169 /* compressed, but only when needed (not compressed
170 when the framerate is low) */
171 .sizeimage = (352 + 2) * 288,
172 .colorspace = V4L2_COLORSPACE_SRGB,
176 static const __u8 pac207_sensor_init[][8] = {
177 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
178 {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
179 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
180 {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
181 {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
184 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
185 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
187 static const unsigned char pac207_sof_marker[5] =
188 { 0xff, 0xff, 0x00, 0xff, 0x96 };
190 int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
191 const u8 *buffer, u16 length)
193 struct usb_device *udev = gspca_dev->dev;
197 memcpy(kbuf, buffer, length);
199 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
200 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
201 0x00, index, kbuf, length, PAC207_CTRL_TIMEOUT);
204 "Failed to write registers to index 0x%04X, error %d)",
211 int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
213 struct usb_device *udev = gspca_dev->dev;
216 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
217 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
218 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
220 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
221 " value 0x%02X, error %d)", index, value, err);
227 int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
229 struct usb_device *udev = gspca_dev->dev;
233 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
234 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
235 0x00, index, &buff, 1, PAC207_CTRL_TIMEOUT);
238 "Failed to read a register (index 0x%04X, error %d)",
247 /* this function is called at probe time */
248 static int sd_config(struct gspca_dev *gspca_dev,
249 const struct usb_device_id *id)
251 struct sd *sd = (struct sd *) gspca_dev;
255 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
256 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
257 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
258 idreg[1] = idreg[1] & 0x0f;
259 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
262 if (idreg[0] != 0x27) {
263 PDEBUG(D_PROBE, "Error invalid sensor ID!");
267 pac207_write_reg(gspca_dev, 0x41, 0x00);
268 /* Bit_0=Image Format,
270 * Bit_2=Compression test mode enable */
271 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
272 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
275 "Pixart PAC207BCA Image Processor and Control Chip detected"
276 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
278 cam = &gspca_dev->cam;
279 cam->dev_name = (char *) id->driver_info;
281 cam->cam_mode = sif_mode;
282 cam->nmodes = ARRAY_SIZE(sif_mode);
283 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
284 sd->exposure = PAC207_EXPOSURE_DEFAULT;
285 sd->gain = PAC207_GAIN_DEFAULT;
290 /* this function is called at open time */
291 static int sd_open(struct gspca_dev *gspca_dev)
293 struct sd *sd = (struct sd *) gspca_dev;
299 /* -- start the camera -- */
300 static void sd_start(struct gspca_dev *gspca_dev)
302 struct sd *sd = (struct sd *) gspca_dev;
305 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
306 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
307 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
308 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
309 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
310 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
311 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
313 /* Compression Balance */
314 if (gspca_dev->width == 176)
315 pac207_write_reg(gspca_dev, 0x4a, 0xff);
317 pac207_write_reg(gspca_dev, 0x4a, 0x88);
318 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
319 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
321 /* PGA global gain (Bit 4-0) */
322 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
323 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
325 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
326 if (gspca_dev->width == 176) { /* 176x144 */
328 PDEBUG(D_STREAM, "pac207_start mode 176x144");
329 } else { /* 352x288 */
330 PDEBUG(D_STREAM, "pac207_start mode 352x288");
332 pac207_write_reg(gspca_dev, 0x41, mode);
334 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
335 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
337 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
340 sd->autogain_ignore_frames = 0;
341 atomic_set(&sd->avg_lum, -1);
344 static void sd_stopN(struct gspca_dev *gspca_dev)
346 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
347 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
348 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
351 static void sd_stop0(struct gspca_dev *gspca_dev)
355 /* this function is called at close time */
356 static void sd_close(struct gspca_dev *gspca_dev)
360 /* auto gain and exposure algorithm based on the knee algorithm described here:
361 * <http://ytse.tricolour.net/docs/LowLightOptimization.html> */
362 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
364 struct sd *sd = (struct sd *) gspca_dev;
365 int i, steps, desired_avg_lum;
366 int orig_gain = sd->gain;
367 int orig_exposure = sd->exposure;
368 int avg_lum = atomic_read(&sd->avg_lum);
370 if (!sd->autogain || avg_lum == -1)
373 if (sd->autogain_ignore_frames > 0) {
374 sd->autogain_ignore_frames--;
378 /* correct desired lumination for the configured brightness */
379 desired_avg_lum = 100 + sd->brightness / 2;
381 /* If we are of a multiple of deadzone, do multiple step to reach the
382 desired lumination fast (with the risc of a slight overshoot) */
383 steps = abs(desired_avg_lum - avg_lum) / PAC207_AUTOGAIN_DEADZONE;
385 for (i = 0; i < steps; i++) {
386 if (avg_lum > desired_avg_lum) {
387 if (sd->gain > PAC207_GAIN_KNEE)
389 else if (sd->exposure > PAC207_EXPOSURE_KNEE)
391 else if (sd->gain > PAC207_GAIN_DEFAULT)
393 else if (sd->exposure > PAC207_EXPOSURE_MIN)
395 else if (sd->gain > PAC207_GAIN_MIN)
400 if (sd->gain < PAC207_GAIN_DEFAULT)
402 else if (sd->exposure < PAC207_EXPOSURE_KNEE)
404 else if (sd->gain < PAC207_GAIN_KNEE)
406 else if (sd->exposure < PAC207_EXPOSURE_MAX)
408 else if (sd->gain < PAC207_GAIN_MAX)
415 if (sd->exposure != orig_exposure || sd->gain != orig_gain) {
416 if (sd->exposure != orig_exposure)
417 pac207_write_reg(gspca_dev, 0x0002, sd->exposure);
418 if (sd->gain != orig_gain)
419 pac207_write_reg(gspca_dev, 0x000e, sd->gain);
420 pac207_write_reg(gspca_dev, 0x13, 0x01); /* load reg to sen */
421 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
422 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
426 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
427 unsigned char *m, int len)
429 struct sd *sd = (struct sd *) gspca_dev;
432 /* Search for the SOF marker (fixed part) in the header */
433 for (i = 0; i < len; i++) {
434 if (m[i] == pac207_sof_marker[sd->sof_read]) {
436 if (sd->sof_read == sizeof(pac207_sof_marker)) {
438 "SOF found, bytes to analyze: %u."
439 " Frame starts at byte #%u",
452 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
453 struct gspca_frame *frame,
457 struct sd *sd = (struct sd *) gspca_dev;
460 sof = pac207_find_sof(gspca_dev, data, len);
464 /* finish decoding current frame */
466 if (n > sizeof pac207_sof_marker)
467 n -= sizeof pac207_sof_marker;
470 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
473 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
477 if (sd->header_read < 11) {
480 /* get average lumination from frame header (byte 5) */
481 if (sd->header_read < 5) {
482 needed = 5 - sd->header_read;
484 atomic_set(&sd->avg_lum, data[needed - 1]);
486 /* skip the rest of the header */
487 needed = 11 - sd->header_read;
489 sd->header_read += len;
494 sd->header_read = 11;
497 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
500 static void setbrightness(struct gspca_dev *gspca_dev)
502 struct sd *sd = (struct sd *) gspca_dev;
504 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
505 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
506 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
509 static void setexposure(struct gspca_dev *gspca_dev)
511 struct sd *sd = (struct sd *) gspca_dev;
513 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
514 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
515 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
518 static void setgain(struct gspca_dev *gspca_dev)
520 struct sd *sd = (struct sd *) gspca_dev;
522 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
523 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
524 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
527 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
529 struct sd *sd = (struct sd *) gspca_dev;
531 sd->brightness = val;
532 if (gspca_dev->streaming)
533 setbrightness(gspca_dev);
537 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
539 struct sd *sd = (struct sd *) gspca_dev;
541 *val = sd->brightness;
545 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
547 struct sd *sd = (struct sd *) gspca_dev;
549 /* don't allow mucking with exposure when using autogain */
554 if (gspca_dev->streaming)
555 setexposure(gspca_dev);
559 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
561 struct sd *sd = (struct sd *) gspca_dev;
567 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
569 struct sd *sd = (struct sd *) gspca_dev;
571 /* don't allow mucking with gain when using autogain */
576 if (gspca_dev->streaming)
581 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
583 struct sd *sd = (struct sd *) gspca_dev;
589 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
591 struct sd *sd = (struct sd *) gspca_dev;
594 /* when switching to autogain set defaults to make sure
595 we are on a valid point of the autogain gain /
596 exposure knee graph, and give this change time to
597 take effect before doing autogain. */
599 sd->exposure = PAC207_EXPOSURE_DEFAULT;
600 sd->gain = PAC207_GAIN_DEFAULT;
601 if (gspca_dev->streaming) {
602 sd->autogain_ignore_frames =
603 PAC207_AUTOGAIN_IGNORE_FRAMES;
604 setexposure(gspca_dev);
612 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
614 struct sd *sd = (struct sd *) gspca_dev;
620 /* sub-driver description */
621 static const struct sd_desc sd_desc = {
624 .nctrls = ARRAY_SIZE(sd_ctrls),
631 .dq_callback = pac207_do_auto_gain,
632 .pkt_scan = sd_pkt_scan,
635 /* -- module initialisation -- */
636 #define DVNM(name) .driver_info = (kernel_ulong_t) name
637 static const __devinitdata struct usb_device_id device_table[] = {
638 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
639 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
640 {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
641 {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
642 {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
643 {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
644 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
645 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
646 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
649 MODULE_DEVICE_TABLE(usb, device_table);
651 /* -- device connect -- */
652 static int sd_probe(struct usb_interface *intf,
653 const struct usb_device_id *id)
655 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
659 static struct usb_driver sd_driver = {
661 .id_table = device_table,
663 .disconnect = gspca_disconnect,
666 /* -- module insert / remove -- */
667 static int __init sd_mod_init(void)
669 if (usb_register(&sd_driver) < 0)
671 PDEBUG(D_PROBE, "v%s registered", version);
674 static void __exit sd_mod_exit(void)
676 usb_deregister(&sd_driver);
677 PDEBUG(D_PROBE, "deregistered");
680 module_init(sd_mod_init);
681 module_exit(sd_mod_exit);