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