1609 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ov534-ov7xxx gspca driver4 *5 * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>6 * Copyright (C) 2008 Jim Paris <jim@jtan.com>7 * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr8 *9 * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>10 * USB protocol reverse engineered by Jim Paris <jim@jtan.com>11 * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/12 *13 * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr14 * PS3 Eye camera - brightness, contrast, awb, agc, aec controls15 * added by Max Thrun <bear24rw@gmail.com>16 * PS3 Eye camera - FPS range extended by Joseph Howse17 * <josephhowse@nummist.com> https://nummist.com18 */19 20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt21 22#define MODULE_NAME "ov534"23 24#include "gspca.h"25 26#include <linux/fixp-arith.h>27#include <media/v4l2-ctrls.h>28 29#define OV534_REG_ADDRESS 0xf1 /* sensor address */30#define OV534_REG_SUBADDR 0xf231#define OV534_REG_WRITE 0xf332#define OV534_REG_READ 0xf433#define OV534_REG_OPERATION 0xf534#define OV534_REG_STATUS 0xf635 36#define OV534_OP_WRITE_3 0x3737#define OV534_OP_WRITE_2 0x3338#define OV534_OP_READ_2 0xf939 40#define CTRL_TIMEOUT 50041#define DEFAULT_FRAME_RATE 3042 43MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");44MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");45MODULE_LICENSE("GPL");46 47/* specific webcam descriptor */48struct sd {49 struct gspca_dev gspca_dev; /* !! must be the first item */50 51 struct v4l2_ctrl_handler ctrl_handler;52 struct v4l2_ctrl *hue;53 struct v4l2_ctrl *saturation;54 struct v4l2_ctrl *brightness;55 struct v4l2_ctrl *contrast;56 struct { /* gain control cluster */57 struct v4l2_ctrl *autogain;58 struct v4l2_ctrl *gain;59 };60 struct v4l2_ctrl *autowhitebalance;61 struct { /* exposure control cluster */62 struct v4l2_ctrl *autoexposure;63 struct v4l2_ctrl *exposure;64 };65 struct v4l2_ctrl *sharpness;66 struct v4l2_ctrl *hflip;67 struct v4l2_ctrl *vflip;68 struct v4l2_ctrl *plfreq;69 70 __u32 last_pts;71 u16 last_fid;72 u8 frame_rate;73 74 u8 sensor;75};76enum sensors {77 SENSOR_OV767x,78 SENSOR_OV772x,79 NSENSORS80};81 82static int sd_start(struct gspca_dev *gspca_dev);83static void sd_stopN(struct gspca_dev *gspca_dev);84 85 86static const struct v4l2_pix_format ov772x_mode[] = {87 {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,88 .bytesperline = 320 * 2,89 .sizeimage = 320 * 240 * 2,90 .colorspace = V4L2_COLORSPACE_SRGB,91 .priv = 1},92 {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,93 .bytesperline = 640 * 2,94 .sizeimage = 640 * 480 * 2,95 .colorspace = V4L2_COLORSPACE_SRGB,96 .priv = 0},97 {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,98 .bytesperline = 320,99 .sizeimage = 320 * 240,100 .colorspace = V4L2_COLORSPACE_SRGB,101 .priv = 1},102 {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,103 .bytesperline = 640,104 .sizeimage = 640 * 480,105 .colorspace = V4L2_COLORSPACE_SRGB,106 .priv = 0},107};108static const struct v4l2_pix_format ov767x_mode[] = {109 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,110 .bytesperline = 320,111 .sizeimage = 320 * 240 * 3 / 8 + 590,112 .colorspace = V4L2_COLORSPACE_JPEG},113 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,114 .bytesperline = 640,115 .sizeimage = 640 * 480 * 3 / 8 + 590,116 .colorspace = V4L2_COLORSPACE_JPEG},117};118 119static const u8 qvga_rates[] = {187, 150, 137, 125, 100, 75, 60, 50, 37, 30};120static const u8 vga_rates[] = {60, 50, 40, 30, 15};121 122static const struct framerates ov772x_framerates[] = {123 { /* 320x240 */124 .rates = qvga_rates,125 .nrates = ARRAY_SIZE(qvga_rates),126 },127 { /* 640x480 */128 .rates = vga_rates,129 .nrates = ARRAY_SIZE(vga_rates),130 },131 { /* 320x240 SGBRG8 */132 .rates = qvga_rates,133 .nrates = ARRAY_SIZE(qvga_rates),134 },135 { /* 640x480 SGBRG8 */136 .rates = vga_rates,137 .nrates = ARRAY_SIZE(vga_rates),138 },139};140 141struct reg_array {142 const u8 (*val)[2];143 int len;144};145 146static const u8 bridge_init_767x[][2] = {147/* comments from the ms-win file apollo7670.set */148/* str1 */149 {0xf1, 0x42},150 {0x88, 0xf8},151 {0x89, 0xff},152 {0x76, 0x03},153 {0x92, 0x03},154 {0x95, 0x10},155 {0xe2, 0x00},156 {0xe7, 0x3e},157 {0x8d, 0x1c},158 {0x8e, 0x00},159 {0x8f, 0x00},160 {0x1f, 0x00},161 {0xc3, 0xf9},162 {0x89, 0xff},163 {0x88, 0xf8},164 {0x76, 0x03},165 {0x92, 0x01},166 {0x93, 0x18},167 {0x1c, 0x00},168 {0x1d, 0x48},169 {0x1d, 0x00},170 {0x1d, 0xff},171 {0x1d, 0x02},172 {0x1d, 0x58},173 {0x1d, 0x00},174 {0x1c, 0x0a},175 {0x1d, 0x0a},176 {0x1d, 0x0e},177 {0xc0, 0x50}, /* HSize 640 */178 {0xc1, 0x3c}, /* VSize 480 */179 {0x34, 0x05}, /* enable Audio Suspend mode */180 {0xc2, 0x0c}, /* Input YUV */181 {0xc3, 0xf9}, /* enable PRE */182 {0x34, 0x05}, /* enable Audio Suspend mode */183 {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */184 {0x31, 0xf9}, /* enable 1.8V Suspend */185 {0x35, 0x02}, /* turn on JPEG */186 {0xd9, 0x10},187 {0x25, 0x42}, /* GPIO[8]:Input */188 {0x94, 0x11}, /* If the default setting is loaded when189 * system boots up, this flag is closed here */190};191static const u8 sensor_init_767x[][2] = {192 {0x12, 0x80},193 {0x11, 0x03},194 {0x3a, 0x04},195 {0x12, 0x00},196 {0x17, 0x13},197 {0x18, 0x01},198 {0x32, 0xb6},199 {0x19, 0x02},200 {0x1a, 0x7a},201 {0x03, 0x0a},202 {0x0c, 0x00},203 {0x3e, 0x00},204 {0x70, 0x3a},205 {0x71, 0x35},206 {0x72, 0x11},207 {0x73, 0xf0},208 {0xa2, 0x02},209 {0x7a, 0x2a}, /* set Gamma=1.6 below */210 {0x7b, 0x12},211 {0x7c, 0x1d},212 {0x7d, 0x2d},213 {0x7e, 0x45},214 {0x7f, 0x50},215 {0x80, 0x59},216 {0x81, 0x62},217 {0x82, 0x6b},218 {0x83, 0x73},219 {0x84, 0x7b},220 {0x85, 0x8a},221 {0x86, 0x98},222 {0x87, 0xb2},223 {0x88, 0xca},224 {0x89, 0xe0},225 {0x13, 0xe0},226 {0x00, 0x00},227 {0x10, 0x00},228 {0x0d, 0x40},229 {0x14, 0x38}, /* gain max 16x */230 {0xa5, 0x05},231 {0xab, 0x07},232 {0x24, 0x95},233 {0x25, 0x33},234 {0x26, 0xe3},235 {0x9f, 0x78},236 {0xa0, 0x68},237 {0xa1, 0x03},238 {0xa6, 0xd8},239 {0xa7, 0xd8},240 {0xa8, 0xf0},241 {0xa9, 0x90},242 {0xaa, 0x94},243 {0x13, 0xe5},244 {0x0e, 0x61},245 {0x0f, 0x4b},246 {0x16, 0x02},247 {0x21, 0x02},248 {0x22, 0x91},249 {0x29, 0x07},250 {0x33, 0x0b},251 {0x35, 0x0b},252 {0x37, 0x1d},253 {0x38, 0x71},254 {0x39, 0x2a},255 {0x3c, 0x78},256 {0x4d, 0x40},257 {0x4e, 0x20},258 {0x69, 0x00},259 {0x6b, 0x4a},260 {0x74, 0x10},261 {0x8d, 0x4f},262 {0x8e, 0x00},263 {0x8f, 0x00},264 {0x90, 0x00},265 {0x91, 0x00},266 {0x96, 0x00},267 {0x9a, 0x80},268 {0xb0, 0x84},269 {0xb1, 0x0c},270 {0xb2, 0x0e},271 {0xb3, 0x82},272 {0xb8, 0x0a},273 {0x43, 0x0a},274 {0x44, 0xf0},275 {0x45, 0x34},276 {0x46, 0x58},277 {0x47, 0x28},278 {0x48, 0x3a},279 {0x59, 0x88},280 {0x5a, 0x88},281 {0x5b, 0x44},282 {0x5c, 0x67},283 {0x5d, 0x49},284 {0x5e, 0x0e},285 {0x6c, 0x0a},286 {0x6d, 0x55},287 {0x6e, 0x11},288 {0x6f, 0x9f},289 {0x6a, 0x40},290 {0x01, 0x40},291 {0x02, 0x40},292 {0x13, 0xe7},293 {0x4f, 0x80},294 {0x50, 0x80},295 {0x51, 0x00},296 {0x52, 0x22},297 {0x53, 0x5e},298 {0x54, 0x80},299 {0x58, 0x9e},300 {0x41, 0x08},301 {0x3f, 0x00},302 {0x75, 0x04},303 {0x76, 0xe1},304 {0x4c, 0x00},305 {0x77, 0x01},306 {0x3d, 0xc2},307 {0x4b, 0x09},308 {0xc9, 0x60},309 {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */310 {0x56, 0x40},311 {0x34, 0x11},312 {0x3b, 0xc2},313 {0xa4, 0x8a}, /* Night mode trigger point */314 {0x96, 0x00},315 {0x97, 0x30},316 {0x98, 0x20},317 {0x99, 0x20},318 {0x9a, 0x84},319 {0x9b, 0x29},320 {0x9c, 0x03},321 {0x9d, 0x4c},322 {0x9e, 0x3f},323 {0x78, 0x04},324 {0x79, 0x01},325 {0xc8, 0xf0},326 {0x79, 0x0f},327 {0xc8, 0x00},328 {0x79, 0x10},329 {0xc8, 0x7e},330 {0x79, 0x0a},331 {0xc8, 0x80},332 {0x79, 0x0b},333 {0xc8, 0x01},334 {0x79, 0x0c},335 {0xc8, 0x0f},336 {0x79, 0x0d},337 {0xc8, 0x20},338 {0x79, 0x09},339 {0xc8, 0x80},340 {0x79, 0x02},341 {0xc8, 0xc0},342 {0x79, 0x03},343 {0xc8, 0x20},344 {0x79, 0x26},345};346static const u8 bridge_start_vga_767x[][2] = {347/* str59 JPG */348 {0x94, 0xaa},349 {0xf1, 0x42},350 {0xe5, 0x04},351 {0xc0, 0x50},352 {0xc1, 0x3c},353 {0xc2, 0x0c},354 {0x35, 0x02}, /* turn on JPEG */355 {0xd9, 0x10},356 {0xda, 0x00}, /* for higher clock rate(30fps) */357 {0x34, 0x05}, /* enable Audio Suspend mode */358 {0xc3, 0xf9}, /* enable PRE */359 {0x8c, 0x00}, /* CIF VSize LSB[2:0] */360 {0x8d, 0x1c}, /* output YUV */361/* {0x34, 0x05}, * enable Audio Suspend mode (?) */362 {0x50, 0x00}, /* H/V divider=0 */363 {0x51, 0xa0}, /* input H=640/4 */364 {0x52, 0x3c}, /* input V=480/4 */365 {0x53, 0x00}, /* offset X=0 */366 {0x54, 0x00}, /* offset Y=0 */367 {0x55, 0x00}, /* H/V size[8]=0 */368 {0x57, 0x00}, /* H-size[9]=0 */369 {0x5c, 0x00}, /* output size[9:8]=0 */370 {0x5a, 0xa0}, /* output H=640/4 */371 {0x5b, 0x78}, /* output V=480/4 */372 {0x1c, 0x0a},373 {0x1d, 0x0a},374 {0x94, 0x11},375};376static const u8 sensor_start_vga_767x[][2] = {377 {0x11, 0x01},378 {0x1e, 0x04},379 {0x19, 0x02},380 {0x1a, 0x7a},381};382static const u8 bridge_start_qvga_767x[][2] = {383/* str86 JPG */384 {0x94, 0xaa},385 {0xf1, 0x42},386 {0xe5, 0x04},387 {0xc0, 0x80},388 {0xc1, 0x60},389 {0xc2, 0x0c},390 {0x35, 0x02}, /* turn on JPEG */391 {0xd9, 0x10},392 {0xc0, 0x50}, /* CIF HSize 640 */393 {0xc1, 0x3c}, /* CIF VSize 480 */394 {0x8c, 0x00}, /* CIF VSize LSB[2:0] */395 {0x8d, 0x1c}, /* output YUV */396 {0x34, 0x05}, /* enable Audio Suspend mode */397 {0xc2, 0x4c}, /* output YUV and Enable DCW */398 {0xc3, 0xf9}, /* enable PRE */399 {0x1c, 0x00}, /* indirect addressing */400 {0x1d, 0x48}, /* output YUV422 */401 {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */402 {0x51, 0xa0}, /* DCW input H=640/4 */403 {0x52, 0x78}, /* DCW input V=480/4 */404 {0x53, 0x00}, /* offset X=0 */405 {0x54, 0x00}, /* offset Y=0 */406 {0x55, 0x00}, /* H/V size[8]=0 */407 {0x57, 0x00}, /* H-size[9]=0 */408 {0x5c, 0x00}, /* DCW output size[9:8]=0 */409 {0x5a, 0x50}, /* DCW output H=320/4 */410 {0x5b, 0x3c}, /* DCW output V=240/4 */411 {0x1c, 0x0a},412 {0x1d, 0x0a},413 {0x94, 0x11},414};415static const u8 sensor_start_qvga_767x[][2] = {416 {0x11, 0x01},417 {0x1e, 0x04},418 {0x19, 0x02},419 {0x1a, 0x7a},420};421 422static const u8 bridge_init_772x[][2] = {423 { 0x88, 0xf8 },424 { 0x89, 0xff },425 { 0x76, 0x03 },426 { 0x92, 0x01 },427 { 0x93, 0x18 },428 { 0x94, 0x10 },429 { 0x95, 0x10 },430 { 0xe2, 0x00 },431 { 0xe7, 0x3e },432 433 { 0x96, 0x00 },434 435 { 0x97, 0x20 },436 { 0x97, 0x20 },437 { 0x97, 0x20 },438 { 0x97, 0x0a },439 { 0x97, 0x3f },440 { 0x97, 0x4a },441 { 0x97, 0x20 },442 { 0x97, 0x15 },443 { 0x97, 0x0b },444 445 { 0x8e, 0x40 },446 { 0x1f, 0x81 },447 { 0x34, 0x05 },448 { 0xe3, 0x04 },449 { 0x89, 0x00 },450 { 0x76, 0x00 },451 { 0xe7, 0x2e },452 { 0x31, 0xf9 },453 { 0x25, 0x42 },454 { 0x21, 0xf0 },455 456 { 0x1c, 0x0a },457 { 0x1d, 0x08 }, /* turn on UVC header */458 { 0x1d, 0x0e }, /* .. */459};460static const u8 sensor_init_772x[][2] = {461 { 0x12, 0x80 },462 { 0x11, 0x01 },463/*fixme: better have a delay?*/464 { 0x11, 0x01 },465 { 0x11, 0x01 },466 { 0x11, 0x01 },467 { 0x11, 0x01 },468 { 0x11, 0x01 },469 { 0x11, 0x01 },470 { 0x11, 0x01 },471 { 0x11, 0x01 },472 { 0x11, 0x01 },473 { 0x11, 0x01 },474 475 { 0x3d, 0x03 },476 { 0x17, 0x26 },477 { 0x18, 0xa0 },478 { 0x19, 0x07 },479 { 0x1a, 0xf0 },480 { 0x32, 0x00 },481 { 0x29, 0xa0 },482 { 0x2c, 0xf0 },483 { 0x65, 0x20 },484 { 0x11, 0x01 },485 { 0x42, 0x7f },486 { 0x63, 0xaa }, /* AWB - was e0 */487 { 0x64, 0xff },488 { 0x66, 0x00 },489 { 0x13, 0xf0 }, /* com8 */490 { 0x0d, 0x41 },491 { 0x0f, 0xc5 },492 { 0x14, 0x11 },493 494 { 0x22, 0x7f },495 { 0x23, 0x03 },496 { 0x24, 0x40 },497 { 0x25, 0x30 },498 { 0x26, 0xa1 },499 { 0x2a, 0x00 },500 { 0x2b, 0x00 },501 { 0x6b, 0xaa },502 { 0x13, 0xff }, /* AWB */503 504 { 0x90, 0x05 },505 { 0x91, 0x01 },506 { 0x92, 0x03 },507 { 0x93, 0x00 },508 { 0x94, 0x60 },509 { 0x95, 0x3c },510 { 0x96, 0x24 },511 { 0x97, 0x1e },512 { 0x98, 0x62 },513 { 0x99, 0x80 },514 { 0x9a, 0x1e },515 { 0x9b, 0x08 },516 { 0x9c, 0x20 },517 { 0x9e, 0x81 },518 519 { 0xa6, 0x07 },520 { 0x7e, 0x0c },521 { 0x7f, 0x16 },522 { 0x80, 0x2a },523 { 0x81, 0x4e },524 { 0x82, 0x61 },525 { 0x83, 0x6f },526 { 0x84, 0x7b },527 { 0x85, 0x86 },528 { 0x86, 0x8e },529 { 0x87, 0x97 },530 { 0x88, 0xa4 },531 { 0x89, 0xaf },532 { 0x8a, 0xc5 },533 { 0x8b, 0xd7 },534 { 0x8c, 0xe8 },535 { 0x8d, 0x20 },536 537 { 0x2b, 0x00 },538 { 0x22, 0x7f },539 { 0x23, 0x03 },540 { 0x11, 0x01 },541 { 0x64, 0xff },542 { 0x0d, 0x41 },543 544 { 0x14, 0x41 },545 { 0x0e, 0xcd },546 { 0xac, 0xbf },547 { 0x8e, 0x00 }, /* De-noise threshold */548};549static const u8 bridge_start_vga_yuyv_772x[][2] = {550 {0x88, 0x00},551 {0x1c, 0x00},552 {0x1d, 0x40},553 {0x1d, 0x02},554 {0x1d, 0x00},555 {0x1d, 0x02},556 {0x1d, 0x58},557 {0x1d, 0x00},558 {0x8d, 0x1c},559 {0x8e, 0x80},560 {0xc0, 0x50},561 {0xc1, 0x3c},562 {0xc2, 0x0c},563 {0xc3, 0x69},564};565static const u8 sensor_start_vga_yuyv_772x[][2] = {566 {0x12, 0x00},567 {0x17, 0x26},568 {0x18, 0xa0},569 {0x19, 0x07},570 {0x1a, 0xf0},571 {0x29, 0xa0},572 {0x2c, 0xf0},573 {0x65, 0x20},574 {0x67, 0x00},575};576static const u8 bridge_start_qvga_yuyv_772x[][2] = {577 {0x88, 0x00},578 {0x1c, 0x00},579 {0x1d, 0x40},580 {0x1d, 0x02},581 {0x1d, 0x00},582 {0x1d, 0x01},583 {0x1d, 0x4b},584 {0x1d, 0x00},585 {0x8d, 0x1c},586 {0x8e, 0x80},587 {0xc0, 0x28},588 {0xc1, 0x1e},589 {0xc2, 0x0c},590 {0xc3, 0x69},591};592static const u8 sensor_start_qvga_yuyv_772x[][2] = {593 {0x12, 0x40},594 {0x17, 0x3f},595 {0x18, 0x50},596 {0x19, 0x03},597 {0x1a, 0x78},598 {0x29, 0x50},599 {0x2c, 0x78},600 {0x65, 0x2f},601 {0x67, 0x00},602};603static const u8 bridge_start_vga_gbrg_772x[][2] = {604 {0x88, 0x08},605 {0x1c, 0x00},606 {0x1d, 0x00},607 {0x1d, 0x02},608 {0x1d, 0x00},609 {0x1d, 0x01},610 {0x1d, 0x2c},611 {0x1d, 0x00},612 {0x8d, 0x00},613 {0x8e, 0x00},614 {0xc0, 0x50},615 {0xc1, 0x3c},616 {0xc2, 0x01},617 {0xc3, 0x01},618};619static const u8 sensor_start_vga_gbrg_772x[][2] = {620 {0x12, 0x01},621 {0x17, 0x26},622 {0x18, 0xa0},623 {0x19, 0x07},624 {0x1a, 0xf0},625 {0x29, 0xa0},626 {0x2c, 0xf0},627 {0x65, 0x20},628 {0x67, 0x02},629};630static const u8 bridge_start_qvga_gbrg_772x[][2] = {631 {0x88, 0x08},632 {0x1c, 0x00},633 {0x1d, 0x00},634 {0x1d, 0x02},635 {0x1d, 0x00},636 {0x1d, 0x00},637 {0x1d, 0x4b},638 {0x1d, 0x00},639 {0x8d, 0x00},640 {0x8e, 0x00},641 {0xc0, 0x28},642 {0xc1, 0x1e},643 {0xc2, 0x01},644 {0xc3, 0x01},645};646static const u8 sensor_start_qvga_gbrg_772x[][2] = {647 {0x12, 0x41},648 {0x17, 0x3f},649 {0x18, 0x50},650 {0x19, 0x03},651 {0x1a, 0x78},652 {0x29, 0x50},653 {0x2c, 0x78},654 {0x65, 0x2f},655 {0x67, 0x02},656};657 658static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)659{660 struct usb_device *udev = gspca_dev->dev;661 int ret;662 663 if (gspca_dev->usb_err < 0)664 return;665 666 gspca_dbg(gspca_dev, D_USBO, "SET 01 0000 %04x %02x\n", reg, val);667 gspca_dev->usb_buf[0] = val;668 ret = usb_control_msg(udev,669 usb_sndctrlpipe(udev, 0),670 0x01,671 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,672 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);673 if (ret < 0) {674 pr_err("write failed %d\n", ret);675 gspca_dev->usb_err = ret;676 }677}678 679static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)680{681 struct usb_device *udev = gspca_dev->dev;682 int ret;683 684 if (gspca_dev->usb_err < 0)685 return 0;686 ret = usb_control_msg(udev,687 usb_rcvctrlpipe(udev, 0),688 0x01,689 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,690 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);691 gspca_dbg(gspca_dev, D_USBI, "GET 01 0000 %04x %02x\n",692 reg, gspca_dev->usb_buf[0]);693 if (ret < 0) {694 pr_err("read failed %d\n", ret);695 gspca_dev->usb_err = ret;696 /*697 * Make sure the result is zeroed to avoid uninitialized698 * values.699 */700 gspca_dev->usb_buf[0] = 0;701 }702 return gspca_dev->usb_buf[0];703}704 705/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.706 * (direction and output)? */707static void ov534_set_led(struct gspca_dev *gspca_dev, int status)708{709 u8 data;710 711 gspca_dbg(gspca_dev, D_CONF, "led status: %d\n", status);712 713 data = ov534_reg_read(gspca_dev, 0x21);714 data |= 0x80;715 ov534_reg_write(gspca_dev, 0x21, data);716 717 data = ov534_reg_read(gspca_dev, 0x23);718 if (status)719 data |= 0x80;720 else721 data &= ~0x80;722 723 ov534_reg_write(gspca_dev, 0x23, data);724 725 if (!status) {726 data = ov534_reg_read(gspca_dev, 0x21);727 data &= ~0x80;728 ov534_reg_write(gspca_dev, 0x21, data);729 }730}731 732static int sccb_check_status(struct gspca_dev *gspca_dev)733{734 u8 data;735 int i;736 737 for (i = 0; i < 5; i++) {738 usleep_range(10000, 20000);739 data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);740 741 switch (data) {742 case 0x00:743 return 1;744 case 0x04:745 return 0;746 case 0x03:747 break;748 default:749 gspca_err(gspca_dev, "sccb status 0x%02x, attempt %d/5\n",750 data, i + 1);751 }752 }753 return 0;754}755 756static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)757{758 gspca_dbg(gspca_dev, D_USBO, "sccb write: %02x %02x\n", reg, val);759 ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);760 ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);761 ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);762 763 if (!sccb_check_status(gspca_dev)) {764 pr_err("sccb_reg_write failed\n");765 gspca_dev->usb_err = -EIO;766 }767}768 769static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)770{771 ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);772 ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);773 if (!sccb_check_status(gspca_dev))774 pr_err("sccb_reg_read failed 1\n");775 776 ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);777 if (!sccb_check_status(gspca_dev))778 pr_err("sccb_reg_read failed 2\n");779 780 return ov534_reg_read(gspca_dev, OV534_REG_READ);781}782 783/* output a bridge sequence (reg - val) */784static void reg_w_array(struct gspca_dev *gspca_dev,785 const u8 (*data)[2], int len)786{787 while (--len >= 0) {788 ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]);789 data++;790 }791}792 793/* output a sensor sequence (reg - val) */794static void sccb_w_array(struct gspca_dev *gspca_dev,795 const u8 (*data)[2], int len)796{797 while (--len >= 0) {798 if ((*data)[0] != 0xff) {799 sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]);800 } else {801 sccb_reg_read(gspca_dev, (*data)[1]);802 sccb_reg_write(gspca_dev, 0xff, 0x00);803 }804 data++;805 }806}807 808/* ov772x specific controls */809static void set_frame_rate(struct gspca_dev *gspca_dev)810{811 struct sd *sd = (struct sd *) gspca_dev;812 int i;813 struct rate_s {814 u8 fps;815 u8 r11;816 u8 r0d;817 u8 re5;818 };819 const struct rate_s *r;820 static const struct rate_s rate_0[] = { /* 640x480 */821 {60, 0x01, 0xc1, 0x04},822 {50, 0x01, 0x41, 0x02},823 {40, 0x02, 0xc1, 0x04},824 {30, 0x04, 0x81, 0x02},825 {15, 0x03, 0x41, 0x04},826 };827 static const struct rate_s rate_1[] = { /* 320x240 */828/* {205, 0x01, 0xc1, 0x02}, * 205 FPS: video is partly corrupt */829 {187, 0x01, 0x81, 0x02}, /* 187 FPS or below: video is valid */830 {150, 0x01, 0xc1, 0x04},831 {137, 0x02, 0xc1, 0x02},832 {125, 0x02, 0x81, 0x02},833 {100, 0x02, 0xc1, 0x04},834 {75, 0x03, 0xc1, 0x04},835 {60, 0x04, 0xc1, 0x04},836 {50, 0x02, 0x41, 0x04},837 {37, 0x03, 0x41, 0x04},838 {30, 0x04, 0x41, 0x04},839 };840 841 if (sd->sensor != SENSOR_OV772x)842 return;843 if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) {844 r = rate_0;845 i = ARRAY_SIZE(rate_0);846 } else {847 r = rate_1;848 i = ARRAY_SIZE(rate_1);849 }850 while (--i > 0) {851 if (sd->frame_rate >= r->fps)852 break;853 r++;854 }855 856 sccb_reg_write(gspca_dev, 0x11, r->r11);857 sccb_reg_write(gspca_dev, 0x0d, r->r0d);858 ov534_reg_write(gspca_dev, 0xe5, r->re5);859 860 gspca_dbg(gspca_dev, D_PROBE, "frame_rate: %d\n", r->fps);861}862 863static void sethue(struct gspca_dev *gspca_dev, s32 val)864{865 struct sd *sd = (struct sd *) gspca_dev;866 867 if (sd->sensor == SENSOR_OV767x) {868 /* TBD */869 } else {870 s16 huesin;871 s16 huecos;872 873 /* According to the datasheet the registers expect HUESIN and874 * HUECOS to be the result of the trigonometric functions,875 * scaled by 0x80.876 *877 * The 0x7fff here represents the maximum absolute value878 * returned byt fixp_sin and fixp_cos, so the scaling will879 * consider the result like in the interval [-1.0, 1.0].880 */881 huesin = fixp_sin16(val) * 0x80 / 0x7fff;882 huecos = fixp_cos16(val) * 0x80 / 0x7fff;883 884 if (huesin < 0) {885 sccb_reg_write(gspca_dev, 0xab,886 sccb_reg_read(gspca_dev, 0xab) | 0x2);887 huesin = -huesin;888 } else {889 sccb_reg_write(gspca_dev, 0xab,890 sccb_reg_read(gspca_dev, 0xab) & ~0x2);891 892 }893 sccb_reg_write(gspca_dev, 0xa9, (u8)huecos);894 sccb_reg_write(gspca_dev, 0xaa, (u8)huesin);895 }896}897 898static void setsaturation(struct gspca_dev *gspca_dev, s32 val)899{900 struct sd *sd = (struct sd *) gspca_dev;901 902 if (sd->sensor == SENSOR_OV767x) {903 int i;904 static u8 color_tb[][6] = {905 {0x42, 0x42, 0x00, 0x11, 0x30, 0x41},906 {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},907 {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},908 {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},909 {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},910 {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},911 {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},912 };913 914 for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)915 sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);916 } else {917 sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */918 sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */919 }920}921 922static void setbrightness(struct gspca_dev *gspca_dev, s32 val)923{924 struct sd *sd = (struct sd *) gspca_dev;925 926 if (sd->sensor == SENSOR_OV767x) {927 if (val < 0)928 val = 0x80 - val;929 sccb_reg_write(gspca_dev, 0x55, val); /* bright */930 } else {931 sccb_reg_write(gspca_dev, 0x9b, val);932 }933}934 935static void setcontrast(struct gspca_dev *gspca_dev, s32 val)936{937 struct sd *sd = (struct sd *) gspca_dev;938 939 if (sd->sensor == SENSOR_OV767x)940 sccb_reg_write(gspca_dev, 0x56, val); /* contras */941 else942 sccb_reg_write(gspca_dev, 0x9c, val);943}944 945static void setgain(struct gspca_dev *gspca_dev, s32 val)946{947 switch (val & 0x30) {948 case 0x00:949 val &= 0x0f;950 break;951 case 0x10:952 val &= 0x0f;953 val |= 0x30;954 break;955 case 0x20:956 val &= 0x0f;957 val |= 0x70;958 break;959 default:960/* case 0x30: */961 val &= 0x0f;962 val |= 0xf0;963 break;964 }965 sccb_reg_write(gspca_dev, 0x00, val);966}967 968static s32 getgain(struct gspca_dev *gspca_dev)969{970 return sccb_reg_read(gspca_dev, 0x00);971}972 973static void setexposure(struct gspca_dev *gspca_dev, s32 val)974{975 struct sd *sd = (struct sd *) gspca_dev;976 977 if (sd->sensor == SENSOR_OV767x) {978 979 /* set only aec[9:2] */980 sccb_reg_write(gspca_dev, 0x10, val); /* aech */981 } else {982 983 /* 'val' is one byte and represents half of the exposure value984 * we are going to set into registers, a two bytes value:985 *986 * MSB: ((u16) val << 1) >> 8 == val >> 7987 * LSB: ((u16) val << 1) & 0xff == val << 1988 */989 sccb_reg_write(gspca_dev, 0x08, val >> 7);990 sccb_reg_write(gspca_dev, 0x10, val << 1);991 }992}993 994static s32 getexposure(struct gspca_dev *gspca_dev)995{996 struct sd *sd = (struct sd *) gspca_dev;997 998 if (sd->sensor == SENSOR_OV767x) {999 /* get only aec[9:2] */1000 return sccb_reg_read(gspca_dev, 0x10); /* aech */1001 } else {1002 u8 hi = sccb_reg_read(gspca_dev, 0x08);1003 u8 lo = sccb_reg_read(gspca_dev, 0x10);1004 return (hi << 8 | lo) >> 1;1005 }1006}1007 1008static void setagc(struct gspca_dev *gspca_dev, s32 val)1009{1010 if (val) {1011 sccb_reg_write(gspca_dev, 0x13,1012 sccb_reg_read(gspca_dev, 0x13) | 0x04);1013 sccb_reg_write(gspca_dev, 0x64,1014 sccb_reg_read(gspca_dev, 0x64) | 0x03);1015 } else {1016 sccb_reg_write(gspca_dev, 0x13,1017 sccb_reg_read(gspca_dev, 0x13) & ~0x04);1018 sccb_reg_write(gspca_dev, 0x64,1019 sccb_reg_read(gspca_dev, 0x64) & ~0x03);1020 }1021}1022 1023static void setawb(struct gspca_dev *gspca_dev, s32 val)1024{1025 struct sd *sd = (struct sd *) gspca_dev;1026 1027 if (val) {1028 sccb_reg_write(gspca_dev, 0x13,1029 sccb_reg_read(gspca_dev, 0x13) | 0x02);1030 if (sd->sensor == SENSOR_OV772x)1031 sccb_reg_write(gspca_dev, 0x63,1032 sccb_reg_read(gspca_dev, 0x63) | 0xc0);1033 } else {1034 sccb_reg_write(gspca_dev, 0x13,1035 sccb_reg_read(gspca_dev, 0x13) & ~0x02);1036 if (sd->sensor == SENSOR_OV772x)1037 sccb_reg_write(gspca_dev, 0x63,1038 sccb_reg_read(gspca_dev, 0x63) & ~0xc0);1039 }1040}1041 1042static void setaec(struct gspca_dev *gspca_dev, s32 val)1043{1044 struct sd *sd = (struct sd *) gspca_dev;1045 u8 data;1046 1047 data = sd->sensor == SENSOR_OV767x ?1048 0x05 : /* agc + aec */1049 0x01; /* agc */1050 switch (val) {1051 case V4L2_EXPOSURE_AUTO:1052 sccb_reg_write(gspca_dev, 0x13,1053 sccb_reg_read(gspca_dev, 0x13) | data);1054 break;1055 case V4L2_EXPOSURE_MANUAL:1056 sccb_reg_write(gspca_dev, 0x13,1057 sccb_reg_read(gspca_dev, 0x13) & ~data);1058 break;1059 }1060}1061 1062static void setsharpness(struct gspca_dev *gspca_dev, s32 val)1063{1064 sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */1065 sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */1066}1067 1068static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)1069{1070 struct sd *sd = (struct sd *) gspca_dev;1071 u8 val;1072 1073 if (sd->sensor == SENSOR_OV767x) {1074 val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */1075 val &= ~0x30;1076 if (hflip)1077 val |= 0x20;1078 if (vflip)1079 val |= 0x10;1080 sccb_reg_write(gspca_dev, 0x1e, val);1081 } else {1082 val = sccb_reg_read(gspca_dev, 0x0c);1083 val &= ~0xc0;1084 if (hflip == 0)1085 val |= 0x40;1086 if (vflip == 0)1087 val |= 0x80;1088 sccb_reg_write(gspca_dev, 0x0c, val);1089 }1090}1091 1092static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)1093{1094 struct sd *sd = (struct sd *) gspca_dev;1095 1096 val = val ? 0x9e : 0x00;1097 if (sd->sensor == SENSOR_OV767x) {1098 sccb_reg_write(gspca_dev, 0x2a, 0x00);1099 if (val)1100 val = 0x9d; /* insert dummy to 25fps for 50Hz */1101 }1102 sccb_reg_write(gspca_dev, 0x2b, val);1103}1104 1105 1106/* this function is called at probe time */1107static int sd_config(struct gspca_dev *gspca_dev,1108 const struct usb_device_id *id)1109{1110 struct sd *sd = (struct sd *) gspca_dev;1111 struct cam *cam;1112 1113 cam = &gspca_dev->cam;1114 1115 cam->cam_mode = ov772x_mode;1116 cam->nmodes = ARRAY_SIZE(ov772x_mode);1117 1118 sd->frame_rate = DEFAULT_FRAME_RATE;1119 1120 return 0;1121}1122 1123static int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl)1124{1125 struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler);1126 struct gspca_dev *gspca_dev = &sd->gspca_dev;1127 1128 switch (ctrl->id) {1129 case V4L2_CID_AUTOGAIN:1130 gspca_dev->usb_err = 0;1131 if (ctrl->val && sd->gain && gspca_dev->streaming)1132 sd->gain->val = getgain(gspca_dev);1133 return gspca_dev->usb_err;1134 1135 case V4L2_CID_EXPOSURE_AUTO:1136 gspca_dev->usb_err = 0;1137 if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure &&1138 gspca_dev->streaming)1139 sd->exposure->val = getexposure(gspca_dev);1140 return gspca_dev->usb_err;1141 }1142 return -EINVAL;1143}1144 1145static int ov534_s_ctrl(struct v4l2_ctrl *ctrl)1146{1147 struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler);1148 struct gspca_dev *gspca_dev = &sd->gspca_dev;1149 1150 gspca_dev->usb_err = 0;1151 if (!gspca_dev->streaming)1152 return 0;1153 1154 switch (ctrl->id) {1155 case V4L2_CID_HUE:1156 sethue(gspca_dev, ctrl->val);1157 break;1158 case V4L2_CID_SATURATION:1159 setsaturation(gspca_dev, ctrl->val);1160 break;1161 case V4L2_CID_BRIGHTNESS:1162 setbrightness(gspca_dev, ctrl->val);1163 break;1164 case V4L2_CID_CONTRAST:1165 setcontrast(gspca_dev, ctrl->val);1166 break;1167 case V4L2_CID_AUTOGAIN:1168 /* case V4L2_CID_GAIN: */1169 setagc(gspca_dev, ctrl->val);1170 if (!gspca_dev->usb_err && !ctrl->val && sd->gain)1171 setgain(gspca_dev, sd->gain->val);1172 break;1173 case V4L2_CID_AUTO_WHITE_BALANCE:1174 setawb(gspca_dev, ctrl->val);1175 break;1176 case V4L2_CID_EXPOSURE_AUTO:1177 /* case V4L2_CID_EXPOSURE: */1178 setaec(gspca_dev, ctrl->val);1179 if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL &&1180 sd->exposure)1181 setexposure(gspca_dev, sd->exposure->val);1182 break;1183 case V4L2_CID_SHARPNESS:1184 setsharpness(gspca_dev, ctrl->val);1185 break;1186 case V4L2_CID_HFLIP:1187 sethvflip(gspca_dev, ctrl->val, sd->vflip->val);1188 break;1189 case V4L2_CID_VFLIP:1190 sethvflip(gspca_dev, sd->hflip->val, ctrl->val);1191 break;1192 case V4L2_CID_POWER_LINE_FREQUENCY:1193 setlightfreq(gspca_dev, ctrl->val);1194 break;1195 }1196 return gspca_dev->usb_err;1197}1198 1199static const struct v4l2_ctrl_ops ov534_ctrl_ops = {1200 .g_volatile_ctrl = ov534_g_volatile_ctrl,1201 .s_ctrl = ov534_s_ctrl,1202};1203 1204static int sd_init_controls(struct gspca_dev *gspca_dev)1205{1206 struct sd *sd = (struct sd *) gspca_dev;1207 struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler;1208 /* parameters with different values between the supported sensors */1209 int saturation_min;1210 int saturation_max;1211 int saturation_def;1212 int brightness_min;1213 int brightness_max;1214 int brightness_def;1215 int contrast_max;1216 int contrast_def;1217 int exposure_min;1218 int exposure_max;1219 int exposure_def;1220 int hflip_def;1221 1222 if (sd->sensor == SENSOR_OV767x) {1223 saturation_min = 0;1224 saturation_max = 6;1225 saturation_def = 3;1226 brightness_min = -127;1227 brightness_max = 127;1228 brightness_def = 0;1229 contrast_max = 0x80;1230 contrast_def = 0x40;1231 exposure_min = 0x08;1232 exposure_max = 0x60;1233 exposure_def = 0x13;1234 hflip_def = 1;1235 } else {1236 saturation_min = 0;1237 saturation_max = 255;1238 saturation_def = 64;1239 brightness_min = 0;1240 brightness_max = 255;1241 brightness_def = 0;1242 contrast_max = 255;1243 contrast_def = 32;1244 exposure_min = 0;1245 exposure_max = 255;1246 exposure_def = 120;1247 hflip_def = 0;1248 }1249 1250 gspca_dev->vdev.ctrl_handler = hdl;1251 1252 v4l2_ctrl_handler_init(hdl, 13);1253 1254 if (sd->sensor == SENSOR_OV772x)1255 sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1256 V4L2_CID_HUE, -90, 90, 1, 0);1257 1258 sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1259 V4L2_CID_SATURATION, saturation_min, saturation_max, 1,1260 saturation_def);1261 sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1262 V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1,1263 brightness_def);1264 sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1265 V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def);1266 1267 if (sd->sensor == SENSOR_OV772x) {1268 sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1269 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);1270 sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1271 V4L2_CID_GAIN, 0, 63, 1, 20);1272 }1273 1274 sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops,1275 V4L2_CID_EXPOSURE_AUTO,1276 V4L2_EXPOSURE_MANUAL, 0,1277 V4L2_EXPOSURE_AUTO);1278 sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1279 V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1,1280 exposure_def);1281 1282 sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1283 V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);1284 1285 if (sd->sensor == SENSOR_OV772x)1286 sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1287 V4L2_CID_SHARPNESS, 0, 63, 1, 0);1288 1289 sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1290 V4L2_CID_HFLIP, 0, 1, 1, hflip_def);1291 sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,1292 V4L2_CID_VFLIP, 0, 1, 1, 0);1293 sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops,1294 V4L2_CID_POWER_LINE_FREQUENCY,1295 V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0,1296 V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);1297 1298 if (hdl->error) {1299 pr_err("Could not initialize controls\n");1300 return hdl->error;1301 }1302 1303 if (sd->sensor == SENSOR_OV772x)1304 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true);1305 1306 v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL,1307 true);1308 1309 return 0;1310}1311 1312/* this function is called at probe and resume time */1313static int sd_init(struct gspca_dev *gspca_dev)1314{1315 struct sd *sd = (struct sd *) gspca_dev;1316 u16 sensor_id;1317 static const struct reg_array bridge_init[NSENSORS] = {1318 [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)},1319 [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)},1320 };1321 static const struct reg_array sensor_init[NSENSORS] = {1322 [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)},1323 [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)},1324 };1325 1326 /* reset bridge */1327 ov534_reg_write(gspca_dev, 0xe7, 0x3a);1328 ov534_reg_write(gspca_dev, 0xe0, 0x08);1329 msleep(100);1330 1331 /* initialize the sensor address */1332 ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42);1333 1334 /* reset sensor */1335 sccb_reg_write(gspca_dev, 0x12, 0x80);1336 usleep_range(10000, 20000);1337 1338 /* probe the sensor */1339 sccb_reg_read(gspca_dev, 0x0a);1340 sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8;1341 sccb_reg_read(gspca_dev, 0x0b);1342 sensor_id |= sccb_reg_read(gspca_dev, 0x0b);1343 gspca_dbg(gspca_dev, D_PROBE, "Sensor ID: %04x\n", sensor_id);1344 1345 if ((sensor_id & 0xfff0) == 0x7670) {1346 sd->sensor = SENSOR_OV767x;1347 gspca_dev->cam.cam_mode = ov767x_mode;1348 gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode);1349 } else {1350 sd->sensor = SENSOR_OV772x;1351 gspca_dev->cam.bulk = 1;1352 gspca_dev->cam.bulk_size = 16384;1353 gspca_dev->cam.bulk_nurbs = 2;1354 gspca_dev->cam.mode_framerates = ov772x_framerates;1355 }1356 1357 /* initialize */1358 reg_w_array(gspca_dev, bridge_init[sd->sensor].val,1359 bridge_init[sd->sensor].len);1360 ov534_set_led(gspca_dev, 1);1361 sccb_w_array(gspca_dev, sensor_init[sd->sensor].val,1362 sensor_init[sd->sensor].len);1363 1364 sd_stopN(gspca_dev);1365/* set_frame_rate(gspca_dev); */1366 1367 return gspca_dev->usb_err;1368}1369 1370static int sd_start(struct gspca_dev *gspca_dev)1371{1372 struct sd *sd = (struct sd *) gspca_dev;1373 int mode;1374 static const struct reg_array bridge_start[NSENSORS][4] = {1375 [SENSOR_OV767x] = {{bridge_start_qvga_767x,1376 ARRAY_SIZE(bridge_start_qvga_767x)},1377 {bridge_start_vga_767x,1378 ARRAY_SIZE(bridge_start_vga_767x)}},1379 [SENSOR_OV772x] = {{bridge_start_qvga_yuyv_772x,1380 ARRAY_SIZE(bridge_start_qvga_yuyv_772x)},1381 {bridge_start_vga_yuyv_772x,1382 ARRAY_SIZE(bridge_start_vga_yuyv_772x)},1383 {bridge_start_qvga_gbrg_772x,1384 ARRAY_SIZE(bridge_start_qvga_gbrg_772x)},1385 {bridge_start_vga_gbrg_772x,1386 ARRAY_SIZE(bridge_start_vga_gbrg_772x)} },1387 };1388 static const struct reg_array sensor_start[NSENSORS][4] = {1389 [SENSOR_OV767x] = {{sensor_start_qvga_767x,1390 ARRAY_SIZE(sensor_start_qvga_767x)},1391 {sensor_start_vga_767x,1392 ARRAY_SIZE(sensor_start_vga_767x)}},1393 [SENSOR_OV772x] = {{sensor_start_qvga_yuyv_772x,1394 ARRAY_SIZE(sensor_start_qvga_yuyv_772x)},1395 {sensor_start_vga_yuyv_772x,1396 ARRAY_SIZE(sensor_start_vga_yuyv_772x)},1397 {sensor_start_qvga_gbrg_772x,1398 ARRAY_SIZE(sensor_start_qvga_gbrg_772x)},1399 {sensor_start_vga_gbrg_772x,1400 ARRAY_SIZE(sensor_start_vga_gbrg_772x)} },1401 };1402 1403 /* (from ms-win trace) */1404 if (sd->sensor == SENSOR_OV767x)1405 sccb_reg_write(gspca_dev, 0x1e, 0x04);1406 /* black sun enable ? */1407 1408 mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */1409 reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val,1410 bridge_start[sd->sensor][mode].len);1411 sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val,1412 sensor_start[sd->sensor][mode].len);1413 1414 set_frame_rate(gspca_dev);1415 1416 if (sd->hue)1417 sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue));1418 setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation));1419 if (sd->autogain)1420 setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));1421 setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance));1422 setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure));1423 if (sd->gain)1424 setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));1425 setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));1426 setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness));1427 setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));1428 if (sd->sharpness)1429 setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));1430 sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),1431 v4l2_ctrl_g_ctrl(sd->vflip));1432 setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq));1433 1434 ov534_set_led(gspca_dev, 1);1435 ov534_reg_write(gspca_dev, 0xe0, 0x00);1436 return gspca_dev->usb_err;1437}1438 1439static void sd_stopN(struct gspca_dev *gspca_dev)1440{1441 ov534_reg_write(gspca_dev, 0xe0, 0x09);1442 ov534_set_led(gspca_dev, 0);1443}1444 1445/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */1446#define UVC_STREAM_EOH (1 << 7)1447#define UVC_STREAM_ERR (1 << 6)1448#define UVC_STREAM_STI (1 << 5)1449#define UVC_STREAM_RES (1 << 4)1450#define UVC_STREAM_SCR (1 << 3)1451#define UVC_STREAM_PTS (1 << 2)1452#define UVC_STREAM_EOF (1 << 1)1453#define UVC_STREAM_FID (1 << 0)1454 1455static void sd_pkt_scan(struct gspca_dev *gspca_dev,1456 u8 *data, int len)1457{1458 struct sd *sd = (struct sd *) gspca_dev;1459 __u32 this_pts;1460 u16 this_fid;1461 int remaining_len = len;1462 int payload_len;1463 1464 payload_len = gspca_dev->cam.bulk ? 2048 : 2040;1465 do {1466 len = min(remaining_len, payload_len);1467 1468 /* Payloads are prefixed with a UVC-style header. We1469 consider a frame to start when the FID toggles, or the PTS1470 changes. A frame ends when EOF is set, and we've received1471 the correct number of bytes. */1472 1473 /* Verify UVC header. Header length is always 12 */1474 if (data[0] != 12 || len < 12) {1475 gspca_dbg(gspca_dev, D_PACK, "bad header\n");1476 goto discard;1477 }1478 1479 /* Check errors */1480 if (data[1] & UVC_STREAM_ERR) {1481 gspca_dbg(gspca_dev, D_PACK, "payload error\n");1482 goto discard;1483 }1484 1485 /* Extract PTS and FID */1486 if (!(data[1] & UVC_STREAM_PTS)) {1487 gspca_dbg(gspca_dev, D_PACK, "PTS not present\n");1488 goto discard;1489 }1490 this_pts = (data[5] << 24) | (data[4] << 16)1491 | (data[3] << 8) | data[2];1492 this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;1493 1494 /* If PTS or FID has changed, start a new frame. */1495 if (this_pts != sd->last_pts || this_fid != sd->last_fid) {1496 if (gspca_dev->last_packet_type == INTER_PACKET)1497 gspca_frame_add(gspca_dev, LAST_PACKET,1498 NULL, 0);1499 sd->last_pts = this_pts;1500 sd->last_fid = this_fid;1501 gspca_frame_add(gspca_dev, FIRST_PACKET,1502 data + 12, len - 12);1503 /* If this packet is marked as EOF, end the frame */1504 } else if (data[1] & UVC_STREAM_EOF) {1505 sd->last_pts = 0;1506 if (gspca_dev->pixfmt.pixelformat != V4L2_PIX_FMT_JPEG1507 && gspca_dev->image_len + len - 12 !=1508 gspca_dev->pixfmt.sizeimage) {1509 gspca_dbg(gspca_dev, D_PACK, "wrong sized frame\n");1510 goto discard;1511 }1512 gspca_frame_add(gspca_dev, LAST_PACKET,1513 data + 12, len - 12);1514 } else {1515 1516 /* Add the data from this payload */1517 gspca_frame_add(gspca_dev, INTER_PACKET,1518 data + 12, len - 12);1519 }1520 1521 /* Done this payload */1522 goto scan_next;1523 1524discard:1525 /* Discard data until a new frame starts. */1526 gspca_dev->last_packet_type = DISCARD_PACKET;1527 1528scan_next:1529 remaining_len -= len;1530 data += len;1531 } while (remaining_len > 0);1532}1533 1534/* get stream parameters (framerate) */1535static void sd_get_streamparm(struct gspca_dev *gspca_dev,1536 struct v4l2_streamparm *parm)1537{1538 struct v4l2_captureparm *cp = &parm->parm.capture;1539 struct v4l2_fract *tpf = &cp->timeperframe;1540 struct sd *sd = (struct sd *) gspca_dev;1541 1542 tpf->numerator = 1;1543 tpf->denominator = sd->frame_rate;1544}1545 1546/* set stream parameters (framerate) */1547static void sd_set_streamparm(struct gspca_dev *gspca_dev,1548 struct v4l2_streamparm *parm)1549{1550 struct v4l2_captureparm *cp = &parm->parm.capture;1551 struct v4l2_fract *tpf = &cp->timeperframe;1552 struct sd *sd = (struct sd *) gspca_dev;1553 1554 if (tpf->numerator == 0 || tpf->denominator == 0)1555 sd->frame_rate = DEFAULT_FRAME_RATE;1556 else1557 sd->frame_rate = tpf->denominator / tpf->numerator;1558 1559 if (gspca_dev->streaming)1560 set_frame_rate(gspca_dev);1561 1562 /* Return the actual framerate */1563 tpf->numerator = 1;1564 tpf->denominator = sd->frame_rate;1565}1566 1567/* sub-driver description */1568static const struct sd_desc sd_desc = {1569 .name = MODULE_NAME,1570 .config = sd_config,1571 .init = sd_init,1572 .init_controls = sd_init_controls,1573 .start = sd_start,1574 .stopN = sd_stopN,1575 .pkt_scan = sd_pkt_scan,1576 .get_streamparm = sd_get_streamparm,1577 .set_streamparm = sd_set_streamparm,1578};1579 1580/* -- module initialisation -- */1581static const struct usb_device_id device_table[] = {1582 {USB_DEVICE(0x1415, 0x2000)},1583 {USB_DEVICE(0x06f8, 0x3002)},1584 {}1585};1586 1587MODULE_DEVICE_TABLE(usb, device_table);1588 1589/* -- device connect -- */1590static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)1591{1592 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),1593 THIS_MODULE);1594}1595 1596static struct usb_driver sd_driver = {1597 .name = MODULE_NAME,1598 .id_table = device_table,1599 .probe = sd_probe,1600 .disconnect = gspca_disconnect,1601#ifdef CONFIG_PM1602 .suspend = gspca_suspend,1603 .resume = gspca_resume,1604 .reset_resume = gspca_resume,1605#endif1606};1607 1608module_usb_driver(sd_driver);1609