1 /* 2 * Pixart PAC207BCA library 3 * 4 * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com> 5 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li 6 * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr 7 * 8 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> 9 * 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. 14 * 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. 19 * 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 23 * 24 */ 25 26 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 27 28 #define MODULE_NAME "pac207" 29 30 #include <linux/input.h> 31 #include "gspca.h" 32 /* Include pac common sof detection functions */ 33 #include "pac_common.h" 34 35 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 36 MODULE_DESCRIPTION("Pixart PAC207"); 37 MODULE_LICENSE("GPL"); 38 39 #define PAC207_CTRL_TIMEOUT 100 /* ms */ 40 41 #define PAC207_BRIGHTNESS_MIN 0 42 #define PAC207_BRIGHTNESS_MAX 255 43 #define PAC207_BRIGHTNESS_DEFAULT 46 44 #define PAC207_BRIGHTNESS_REG 0x08 45 46 #define PAC207_EXPOSURE_MIN 3 47 #define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */ 48 #define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ 49 #define PAC207_EXPOSURE_REG 0x02 50 51 #define PAC207_GAIN_MIN 0 52 #define PAC207_GAIN_MAX 31 53 #define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */ 54 #define PAC207_GAIN_REG 0x0e 55 56 #define PAC207_AUTOGAIN_DEADZONE 30 57 58 /* specific webcam descriptor */ 59 struct sd { 60 struct gspca_dev gspca_dev; /* !! must be the first item */ 61 62 struct v4l2_ctrl *brightness; 63 64 u8 mode; 65 u8 sof_read; 66 u8 header_read; 67 u8 autogain_ignore_frames; 68 69 atomic_t avg_lum; 70 }; 71 72 static const struct v4l2_pix_format sif_mode[] = { 73 {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, 74 .bytesperline = 176, 75 .sizeimage = (176 + 2) * 144, 76 /* uncompressed, add 2 bytes / line for line header */ 77 .colorspace = V4L2_COLORSPACE_SRGB, 78 .priv = 1}, 79 {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, 80 .bytesperline = 352, 81 /* compressed, but only when needed (not compressed 82 when the framerate is low) */ 83 .sizeimage = (352 + 2) * 288, 84 .colorspace = V4L2_COLORSPACE_SRGB, 85 .priv = 0}, 86 }; 87 88 static const __u8 pac207_sensor_init[][8] = { 89 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84}, 90 {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, 91 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, 92 {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00}, 93 }; 94 95 static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, 96 const u8 *buffer, u16 length) 97 { 98 struct usb_device *udev = gspca_dev->dev; 99 int err; 100 101 if (gspca_dev->usb_err < 0) 102 return; 103 104 memcpy(gspca_dev->usb_buf, buffer, length); 105 106 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, 107 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 108 0x00, index, 109 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); 110 if (err < 0) { 111 pr_err("Failed to write registers to index 0x%04X, error %d\n", 112 index, err); 113 gspca_dev->usb_err = err; 114 } 115 } 116 117 static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) 118 { 119 struct usb_device *udev = gspca_dev->dev; 120 int err; 121 122 if (gspca_dev->usb_err < 0) 123 return; 124 125 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 126 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 127 value, index, NULL, 0, PAC207_CTRL_TIMEOUT); 128 if (err) { 129 pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", 130 index, value, err); 131 gspca_dev->usb_err = err; 132 } 133 } 134 135 static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) 136 { 137 struct usb_device *udev = gspca_dev->dev; 138 int res; 139 140 if (gspca_dev->usb_err < 0) 141 return 0; 142 143 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 144 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 145 0x00, index, 146 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); 147 if (res < 0) { 148 pr_err("Failed to read a register (index 0x%04X, error %d)\n", 149 index, res); 150 gspca_dev->usb_err = res; 151 return 0; 152 } 153 154 return gspca_dev->usb_buf[0]; 155 } 156 157 /* this function is called at probe time */ 158 static int sd_config(struct gspca_dev *gspca_dev, 159 const struct usb_device_id *id) 160 { 161 struct cam *cam; 162 u8 idreg[2]; 163 164 idreg[0] = pac207_read_reg(gspca_dev, 0x0000); 165 idreg[1] = pac207_read_reg(gspca_dev, 0x0001); 166 idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4); 167 idreg[1] = idreg[1] & 0x0f; 168 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X", 169 idreg[0], idreg[1]); 170 171 if (idreg[0] != 0x27) { 172 PDEBUG(D_PROBE, "Error invalid sensor ID!"); 173 return -ENODEV; 174 } 175 176 PDEBUG(D_PROBE, 177 "Pixart PAC207BCA Image Processor and Control Chip detected" 178 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); 179 180 cam = &gspca_dev->cam; 181 cam->cam_mode = sif_mode; 182 cam->nmodes = ARRAY_SIZE(sif_mode); 183 184 return 0; 185 } 186 187 /* this function is called at probe and resume time */ 188 static int sd_init(struct gspca_dev *gspca_dev) 189 { 190 pac207_write_reg(gspca_dev, 0x41, 0x00); 191 /* Bit_0=Image Format, 192 * Bit_1=LED, 193 * Bit_2=Compression test mode enable */ 194 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ 195 196 return gspca_dev->usb_err; 197 } 198 199 static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val) 200 { 201 pac207_write_reg(gspca_dev, reg, val); 202 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ 203 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ 204 } 205 206 static int sd_s_ctrl(struct v4l2_ctrl *ctrl) 207 { 208 struct gspca_dev *gspca_dev = 209 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 210 struct sd *sd = (struct sd *)gspca_dev; 211 212 gspca_dev->usb_err = 0; 213 214 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) { 215 /* when switching to autogain set defaults to make sure 216 we are on a valid point of the autogain gain / 217 exposure knee graph, and give this change time to 218 take effect before doing autogain. */ 219 gspca_dev->exposure->val = PAC207_EXPOSURE_DEFAULT; 220 gspca_dev->gain->val = PAC207_GAIN_DEFAULT; 221 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; 222 } 223 224 if (!gspca_dev->streaming) 225 return 0; 226 227 switch (ctrl->id) { 228 case V4L2_CID_BRIGHTNESS: 229 setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val); 230 break; 231 case V4L2_CID_AUTOGAIN: 232 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val)) 233 setcontrol(gspca_dev, PAC207_EXPOSURE_REG, 234 gspca_dev->exposure->val); 235 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val)) 236 setcontrol(gspca_dev, PAC207_GAIN_REG, 237 gspca_dev->gain->val); 238 break; 239 default: 240 return -EINVAL; 241 } 242 return gspca_dev->usb_err; 243 } 244 245 static const struct v4l2_ctrl_ops sd_ctrl_ops = { 246 .s_ctrl = sd_s_ctrl, 247 }; 248 249 /* this function is called at probe time */ 250 static int sd_init_controls(struct gspca_dev *gspca_dev) 251 { 252 struct sd *sd = (struct sd *) gspca_dev; 253 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 254 255 gspca_dev->vdev.ctrl_handler = hdl; 256 v4l2_ctrl_handler_init(hdl, 4); 257 258 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 259 V4L2_CID_BRIGHTNESS, 260 PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX, 261 1, PAC207_BRIGHTNESS_DEFAULT); 262 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 263 V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 264 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 265 V4L2_CID_EXPOSURE, 266 PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX, 267 1, PAC207_EXPOSURE_DEFAULT); 268 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 269 V4L2_CID_GAIN, 270 PAC207_GAIN_MIN, PAC207_GAIN_MAX, 271 1, PAC207_GAIN_DEFAULT); 272 if (hdl->error) { 273 pr_err("Could not initialize controls\n"); 274 return hdl->error; 275 } 276 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); 277 return 0; 278 } 279 280 /* -- start the camera -- */ 281 static int sd_start(struct gspca_dev *gspca_dev) 282 { 283 struct sd *sd = (struct sd *) gspca_dev; 284 __u8 mode; 285 286 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */ 287 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); 288 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); 289 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); 290 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); 291 292 /* Compression Balance */ 293 if (gspca_dev->width == 176) 294 pac207_write_reg(gspca_dev, 0x4a, 0xff); 295 else 296 pac207_write_reg(gspca_dev, 0x4a, 0x30); 297 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ 298 pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness)); 299 300 /* PGA global gain (Bit 4-0) */ 301 pac207_write_reg(gspca_dev, 0x0e, 302 v4l2_ctrl_g_ctrl(gspca_dev->gain)); 303 pac207_write_reg(gspca_dev, 0x02, 304 v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */ 305 306 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */ 307 if (gspca_dev->width == 176) { /* 176x144 */ 308 mode |= 0x01; 309 PDEBUG(D_STREAM, "pac207_start mode 176x144"); 310 } else { /* 352x288 */ 311 PDEBUG(D_STREAM, "pac207_start mode 352x288"); 312 } 313 pac207_write_reg(gspca_dev, 0x41, mode); 314 315 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ 316 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ 317 msleep(10); 318 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */ 319 320 sd->sof_read = 0; 321 sd->autogain_ignore_frames = 0; 322 atomic_set(&sd->avg_lum, -1); 323 return gspca_dev->usb_err; 324 } 325 326 static void sd_stopN(struct gspca_dev *gspca_dev) 327 { 328 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */ 329 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */ 330 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ 331 } 332 333 334 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) 335 { 336 struct sd *sd = (struct sd *) gspca_dev; 337 int avg_lum = atomic_read(&sd->avg_lum); 338 339 if (avg_lum == -1) 340 return; 341 342 if (sd->autogain_ignore_frames > 0) 343 sd->autogain_ignore_frames--; 344 else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, 345 90, PAC207_AUTOGAIN_DEADZONE)) 346 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; 347 } 348 349 static void sd_pkt_scan(struct gspca_dev *gspca_dev, 350 u8 *data, 351 int len) 352 { 353 struct sd *sd = (struct sd *) gspca_dev; 354 unsigned char *sof; 355 356 sof = pac_find_sof(&sd->sof_read, data, len); 357 if (sof) { 358 int n; 359 360 /* finish decoding current frame */ 361 n = sof - data; 362 if (n > sizeof pac_sof_marker) 363 n -= sizeof pac_sof_marker; 364 else 365 n = 0; 366 gspca_frame_add(gspca_dev, LAST_PACKET, 367 data, n); 368 sd->header_read = 0; 369 gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); 370 len -= sof - data; 371 data = sof; 372 } 373 if (sd->header_read < 11) { 374 int needed; 375 376 /* get average lumination from frame header (byte 5) */ 377 if (sd->header_read < 5) { 378 needed = 5 - sd->header_read; 379 if (len >= needed) 380 atomic_set(&sd->avg_lum, data[needed - 1]); 381 } 382 /* skip the rest of the header */ 383 needed = 11 - sd->header_read; 384 if (len <= needed) { 385 sd->header_read += len; 386 return; 387 } 388 data += needed; 389 len -= needed; 390 sd->header_read = 11; 391 } 392 393 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 394 } 395 396 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 397 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, 398 u8 *data, /* interrupt packet data */ 399 int len) /* interrput packet length */ 400 { 401 int ret = -EINVAL; 402 403 if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) { 404 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); 405 input_sync(gspca_dev->input_dev); 406 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); 407 input_sync(gspca_dev->input_dev); 408 ret = 0; 409 } 410 411 return ret; 412 } 413 #endif 414 415 /* sub-driver description */ 416 static const struct sd_desc sd_desc = { 417 .name = MODULE_NAME, 418 .config = sd_config, 419 .init = sd_init, 420 .init_controls = sd_init_controls, 421 .start = sd_start, 422 .stopN = sd_stopN, 423 .dq_callback = pac207_do_auto_gain, 424 .pkt_scan = sd_pkt_scan, 425 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 426 .int_pkt_scan = sd_int_pkt_scan, 427 #endif 428 }; 429 430 /* -- module initialisation -- */ 431 static const struct usb_device_id device_table[] = { 432 {USB_DEVICE(0x041e, 0x4028)}, 433 {USB_DEVICE(0x093a, 0x2460)}, 434 {USB_DEVICE(0x093a, 0x2461)}, 435 {USB_DEVICE(0x093a, 0x2463)}, 436 {USB_DEVICE(0x093a, 0x2464)}, 437 {USB_DEVICE(0x093a, 0x2468)}, 438 {USB_DEVICE(0x093a, 0x2470)}, 439 {USB_DEVICE(0x093a, 0x2471)}, 440 {USB_DEVICE(0x093a, 0x2472)}, 441 {USB_DEVICE(0x093a, 0x2474)}, 442 {USB_DEVICE(0x093a, 0x2476)}, 443 {USB_DEVICE(0x145f, 0x013a)}, 444 {USB_DEVICE(0x2001, 0xf115)}, 445 {} 446 }; 447 MODULE_DEVICE_TABLE(usb, device_table); 448 449 /* -- device connect -- */ 450 static int sd_probe(struct usb_interface *intf, 451 const struct usb_device_id *id) 452 { 453 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 454 THIS_MODULE); 455 } 456 457 static struct usb_driver sd_driver = { 458 .name = MODULE_NAME, 459 .id_table = device_table, 460 .probe = sd_probe, 461 .disconnect = gspca_disconnect, 462 #ifdef CONFIG_PM 463 .suspend = gspca_suspend, 464 .resume = gspca_resume, 465 .reset_resume = gspca_resume, 466 #endif 467 }; 468 469 module_usb_driver(sd_driver); 470