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, 7)
31 static const char version[] = "2.1.7";
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 static 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;
196 memcpy(gspca_dev->usb_buf, buffer, length);
198 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
199 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
201 gspca_dev->usb_buf, 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;
232 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
233 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
235 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
238 "Failed to read a register (index 0x%04X, error %d)",
243 return gspca_dev->usb_buf[0];
246 /* this function is called at probe time */
247 static int sd_config(struct gspca_dev *gspca_dev,
248 const struct usb_device_id *id)
250 struct sd *sd = (struct sd *) gspca_dev;
254 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
255 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
256 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
257 idreg[1] = idreg[1] & 0x0f;
258 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
261 if (idreg[0] != 0x27) {
262 PDEBUG(D_PROBE, "Error invalid sensor ID!");
266 pac207_write_reg(gspca_dev, 0x41, 0x00);
267 /* Bit_0=Image Format,
269 * Bit_2=Compression test mode enable */
270 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
271 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
274 "Pixart PAC207BCA Image Processor and Control Chip detected"
275 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
277 cam = &gspca_dev->cam;
278 cam->dev_name = (char *) id->driver_info;
280 cam->cam_mode = sif_mode;
281 cam->nmodes = ARRAY_SIZE(sif_mode);
282 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
283 sd->exposure = PAC207_EXPOSURE_DEFAULT;
284 sd->gain = PAC207_GAIN_DEFAULT;
289 /* this function is called at open time */
290 static int sd_open(struct gspca_dev *gspca_dev)
292 struct sd *sd = (struct sd *) gspca_dev;
298 /* -- start the camera -- */
299 static void sd_start(struct gspca_dev *gspca_dev)
301 struct sd *sd = (struct sd *) gspca_dev;
304 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
305 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
306 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
307 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
308 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
309 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
310 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
312 /* Compression Balance */
313 if (gspca_dev->width == 176)
314 pac207_write_reg(gspca_dev, 0x4a, 0xff);
316 pac207_write_reg(gspca_dev, 0x4a, 0x88);
317 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
318 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
320 /* PGA global gain (Bit 4-0) */
321 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
322 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
324 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
325 if (gspca_dev->width == 176) { /* 176x144 */
327 PDEBUG(D_STREAM, "pac207_start mode 176x144");
328 } else { /* 352x288 */
329 PDEBUG(D_STREAM, "pac207_start mode 352x288");
331 pac207_write_reg(gspca_dev, 0x41, mode);
333 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
334 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
336 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
339 sd->autogain_ignore_frames = 0;
340 atomic_set(&sd->avg_lum, -1);
343 static void sd_stopN(struct gspca_dev *gspca_dev)
345 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
346 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
347 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
350 static void sd_stop0(struct gspca_dev *gspca_dev)
354 /* this function is called at close time */
355 static void sd_close(struct gspca_dev *gspca_dev)
359 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
361 struct sd *sd = (struct sd *) gspca_dev;
362 int avg_lum = atomic_read(&sd->avg_lum);
367 if (sd->autogain_ignore_frames > 0)
368 sd->autogain_ignore_frames--;
369 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
370 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
371 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
372 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
375 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
376 unsigned char *m, int len)
378 struct sd *sd = (struct sd *) gspca_dev;
381 /* Search for the SOF marker (fixed part) in the header */
382 for (i = 0; i < len; i++) {
383 if (m[i] == pac207_sof_marker[sd->sof_read]) {
385 if (sd->sof_read == sizeof(pac207_sof_marker)) {
387 "SOF found, bytes to analyze: %u."
388 " Frame starts at byte #%u",
401 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
402 struct gspca_frame *frame,
406 struct sd *sd = (struct sd *) gspca_dev;
409 sof = pac207_find_sof(gspca_dev, data, len);
413 /* finish decoding current frame */
415 if (n > sizeof pac207_sof_marker)
416 n -= sizeof pac207_sof_marker;
419 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
422 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
426 if (sd->header_read < 11) {
429 /* get average lumination from frame header (byte 5) */
430 if (sd->header_read < 5) {
431 needed = 5 - sd->header_read;
433 atomic_set(&sd->avg_lum, data[needed - 1]);
435 /* skip the rest of the header */
436 needed = 11 - sd->header_read;
438 sd->header_read += len;
443 sd->header_read = 11;
446 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
449 static void setbrightness(struct gspca_dev *gspca_dev)
451 struct sd *sd = (struct sd *) gspca_dev;
453 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
454 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
455 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
458 static void setexposure(struct gspca_dev *gspca_dev)
460 struct sd *sd = (struct sd *) gspca_dev;
462 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
463 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
464 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
467 static void setgain(struct gspca_dev *gspca_dev)
469 struct sd *sd = (struct sd *) gspca_dev;
471 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
472 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
473 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
476 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
478 struct sd *sd = (struct sd *) gspca_dev;
480 sd->brightness = val;
481 if (gspca_dev->streaming)
482 setbrightness(gspca_dev);
486 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
488 struct sd *sd = (struct sd *) gspca_dev;
490 *val = sd->brightness;
494 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
496 struct sd *sd = (struct sd *) gspca_dev;
499 if (gspca_dev->streaming)
500 setexposure(gspca_dev);
504 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
506 struct sd *sd = (struct sd *) gspca_dev;
512 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
514 struct sd *sd = (struct sd *) gspca_dev;
517 if (gspca_dev->streaming)
522 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
524 struct sd *sd = (struct sd *) gspca_dev;
530 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
532 struct sd *sd = (struct sd *) gspca_dev;
535 /* when switching to autogain set defaults to make sure
536 we are on a valid point of the autogain gain /
537 exposure knee graph, and give this change time to
538 take effect before doing autogain. */
540 sd->exposure = PAC207_EXPOSURE_DEFAULT;
541 sd->gain = PAC207_GAIN_DEFAULT;
542 if (gspca_dev->streaming) {
543 sd->autogain_ignore_frames =
544 PAC207_AUTOGAIN_IGNORE_FRAMES;
545 setexposure(gspca_dev);
553 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
555 struct sd *sd = (struct sd *) gspca_dev;
561 /* sub-driver description */
562 static const struct sd_desc sd_desc = {
565 .nctrls = ARRAY_SIZE(sd_ctrls),
572 .dq_callback = pac207_do_auto_gain,
573 .pkt_scan = sd_pkt_scan,
576 /* -- module initialisation -- */
577 #define DVNM(name) .driver_info = (kernel_ulong_t) name
578 static const __devinitdata struct usb_device_id device_table[] = {
579 {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
580 {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
581 {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
582 {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
583 {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
584 {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
585 {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
586 {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
587 {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
590 MODULE_DEVICE_TABLE(usb, device_table);
592 /* -- device connect -- */
593 static int sd_probe(struct usb_interface *intf,
594 const struct usb_device_id *id)
596 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
600 static struct usb_driver sd_driver = {
602 .id_table = device_table,
604 .disconnect = gspca_disconnect,
607 /* -- module insert / remove -- */
608 static int __init sd_mod_init(void)
610 if (usb_register(&sd_driver) < 0)
612 PDEBUG(D_PROBE, "v%s registered", version);
615 static void __exit sd_mod_exit(void)
617 usb_deregister(&sd_driver);
618 PDEBUG(D_PROBE, "deregistered");
621 module_init(sd_mod_init);
622 module_exit(sd_mod_exit);