0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0081
0082 #include <linux/input.h>
0083 #include "gspca.h"
0084
0085 #include "pac_common.h"
0086
0087 #define PAC7302_RGB_BALANCE_MIN 0
0088 #define PAC7302_RGB_BALANCE_MAX 200
0089 #define PAC7302_RGB_BALANCE_DEFAULT 100
0090 #define PAC7302_GAIN_DEFAULT 15
0091 #define PAC7302_GAIN_KNEE 42
0092 #define PAC7302_EXPOSURE_DEFAULT 66
0093 #define PAC7302_EXPOSURE_KNEE 133
0094
0095 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, Thomas Kaiser thomas@kaiser-linux.li");
0096 MODULE_DESCRIPTION("Pixart PAC7302");
0097 MODULE_LICENSE("GPL");
0098
0099 struct sd {
0100 struct gspca_dev gspca_dev;
0101
0102 struct {
0103 struct v4l2_ctrl *brightness;
0104 struct v4l2_ctrl *contrast;
0105 };
0106 struct v4l2_ctrl *saturation;
0107 struct v4l2_ctrl *white_balance;
0108 struct v4l2_ctrl *red_balance;
0109 struct v4l2_ctrl *blue_balance;
0110 struct {
0111 struct v4l2_ctrl *hflip;
0112 struct v4l2_ctrl *vflip;
0113 };
0114 struct v4l2_ctrl *sharpness;
0115 u8 flags;
0116 #define FL_HFLIP 0x01
0117 #define FL_VFLIP 0x02
0118
0119 u8 sof_read;
0120 s8 autogain_ignore_frames;
0121
0122 atomic_t avg_lum;
0123 };
0124
0125 static const struct v4l2_pix_format vga_mode[] = {
0126 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
0127 .bytesperline = 640,
0128 .sizeimage = 640 * 480 * 3 / 8 + 590,
0129 .colorspace = V4L2_COLORSPACE_JPEG,
0130 },
0131 };
0132
0133 #define LOAD_PAGE3 255
0134 #define END_OF_SEQUENCE 0
0135
0136 static const u8 init_7302[] = {
0137
0138 0xff, 0x01,
0139 0x78, 0x00,
0140 0xff, 0x01,
0141 0x78, 0x40,
0142 };
0143 static const u8 start_7302[] = {
0144
0145 0xff, 1, 0x00,
0146 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
0147 0x00, 0x00, 0x00, 0x00,
0148 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
0149 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
0150 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
0151 0x26, 2, 0xaa, 0xaa,
0152 0x2e, 1, 0x31,
0153 0x38, 1, 0x01,
0154 0x3a, 3, 0x14, 0xff, 0x5a,
0155 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
0156 0x00, 0x54, 0x11,
0157 0x55, 1, 0x00,
0158 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
0159 0x6b, 1, 0x00,
0160 0x6e, 3, 0x08, 0x06, 0x00,
0161 0x72, 3, 0x00, 0xff, 0x00,
0162 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
0163 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
0164 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
0165 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
0166 0xd2, 0xeb,
0167 0xaf, 1, 0x02,
0168 0xb5, 2, 0x08, 0x08,
0169 0xb8, 2, 0x08, 0x88,
0170 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
0171 0xcc, 1, 0x00,
0172 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
0173 0xc1, 0xd7, 0xec,
0174 0xdc, 1, 0x01,
0175 0xff, 1, 0x01,
0176 0x12, 3, 0x02, 0x00, 0x01,
0177 0x3e, 2, 0x00, 0x00,
0178 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
0179 0x7c, 1, 0x00,
0180 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
0181 0x02, 0x00,
0182 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
0183 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
0184 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
0185 0xd8, 1, 0x01,
0186 0xdb, 2, 0x00, 0x01,
0187 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
0188 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
0189 0xeb, 1, 0x00,
0190 0xff, 1, 0x02,
0191 0x22, 1, 0x00,
0192 0xff, 1, 0x03,
0193 0, LOAD_PAGE3,
0194 0x11, 1, 0x01,
0195 0xff, 1, 0x02,
0196 0x13, 1, 0x00,
0197 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
0198 0x27, 2, 0x14, 0x0c,
0199 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
0200 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
0201 0x6e, 1, 0x08,
0202 0xff, 1, 0x01,
0203 0x78, 1, 0x00,
0204 0, END_OF_SEQUENCE
0205 };
0206
0207 #define SKIP 0xaa
0208
0209 static const u8 page3_7302[] = {
0210 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
0211 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
0212 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0213 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
0214 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
0215 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
0216 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
0217 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0218 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
0219 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
0220 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0221 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
0222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0223 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
0224 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
0225 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
0226 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
0227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0228 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
0229 0x00
0230 };
0231
0232 static void reg_w_buf(struct gspca_dev *gspca_dev,
0233 u8 index,
0234 const u8 *buffer, int len)
0235 {
0236 int ret;
0237
0238 if (gspca_dev->usb_err < 0)
0239 return;
0240 memcpy(gspca_dev->usb_buf, buffer, len);
0241 ret = usb_control_msg(gspca_dev->dev,
0242 usb_sndctrlpipe(gspca_dev->dev, 0),
0243 0,
0244 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0245 0,
0246 index, gspca_dev->usb_buf, len,
0247 500);
0248 if (ret < 0) {
0249 pr_err("reg_w_buf failed i: %02x error %d\n",
0250 index, ret);
0251 gspca_dev->usb_err = ret;
0252 }
0253 }
0254
0255
0256 static void reg_w(struct gspca_dev *gspca_dev,
0257 u8 index,
0258 u8 value)
0259 {
0260 int ret;
0261
0262 if (gspca_dev->usb_err < 0)
0263 return;
0264 gspca_dev->usb_buf[0] = value;
0265 ret = usb_control_msg(gspca_dev->dev,
0266 usb_sndctrlpipe(gspca_dev->dev, 0),
0267 0,
0268 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0269 0, index, gspca_dev->usb_buf, 1,
0270 500);
0271 if (ret < 0) {
0272 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
0273 index, value, ret);
0274 gspca_dev->usb_err = ret;
0275 }
0276 }
0277
0278 static void reg_w_seq(struct gspca_dev *gspca_dev,
0279 const u8 *seq, int len)
0280 {
0281 while (--len >= 0) {
0282 reg_w(gspca_dev, seq[0], seq[1]);
0283 seq += 2;
0284 }
0285 }
0286
0287
0288 static void reg_w_page(struct gspca_dev *gspca_dev,
0289 const u8 *page, int len)
0290 {
0291 int index;
0292 int ret = 0;
0293
0294 if (gspca_dev->usb_err < 0)
0295 return;
0296 for (index = 0; index < len; index++) {
0297 if (page[index] == SKIP)
0298 continue;
0299 gspca_dev->usb_buf[0] = page[index];
0300 ret = usb_control_msg(gspca_dev->dev,
0301 usb_sndctrlpipe(gspca_dev->dev, 0),
0302 0,
0303 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0304 0, index, gspca_dev->usb_buf, 1,
0305 500);
0306 if (ret < 0) {
0307 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
0308 index, page[index], ret);
0309 gspca_dev->usb_err = ret;
0310 break;
0311 }
0312 }
0313 }
0314
0315
0316 static void reg_w_var(struct gspca_dev *gspca_dev,
0317 const u8 *seq,
0318 const u8 *page3, unsigned int page3_len)
0319 {
0320 int index, len;
0321
0322 for (;;) {
0323 index = *seq++;
0324 len = *seq++;
0325 switch (len) {
0326 case END_OF_SEQUENCE:
0327 return;
0328 case LOAD_PAGE3:
0329 reg_w_page(gspca_dev, page3, page3_len);
0330 break;
0331 default:
0332 if (len > USB_BUF_SZ) {
0333 gspca_err(gspca_dev, "Incorrect variable sequence\n");
0334 return;
0335 }
0336 while (len > 0) {
0337 if (len < 8) {
0338 reg_w_buf(gspca_dev,
0339 index, seq, len);
0340 seq += len;
0341 break;
0342 }
0343 reg_w_buf(gspca_dev, index, seq, 8);
0344 seq += 8;
0345 index += 8;
0346 len -= 8;
0347 }
0348 }
0349 }
0350
0351 }
0352
0353
0354 static int sd_config(struct gspca_dev *gspca_dev,
0355 const struct usb_device_id *id)
0356 {
0357 struct sd *sd = (struct sd *) gspca_dev;
0358 struct cam *cam;
0359
0360 cam = &gspca_dev->cam;
0361
0362 cam->cam_mode = vga_mode;
0363 cam->nmodes = ARRAY_SIZE(vga_mode);
0364
0365 sd->flags = id->driver_info;
0366 return 0;
0367 }
0368
0369 static void setbrightcont(struct gspca_dev *gspca_dev)
0370 {
0371 struct sd *sd = (struct sd *) gspca_dev;
0372 int i, v;
0373 static const u8 max[10] =
0374 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
0375 0xd4, 0xec};
0376 static const u8 delta[10] =
0377 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
0378 0x11, 0x0b};
0379
0380 reg_w(gspca_dev, 0xff, 0x00);
0381 for (i = 0; i < 10; i++) {
0382 v = max[i];
0383 v += (sd->brightness->val - (s32)sd->brightness->maximum)
0384 * 150 / (s32)sd->brightness->maximum;
0385 v -= delta[i] * sd->contrast->val / (s32)sd->contrast->maximum;
0386 if (v < 0)
0387 v = 0;
0388 else if (v > 0xff)
0389 v = 0xff;
0390 reg_w(gspca_dev, 0xa2 + i, v);
0391 }
0392 reg_w(gspca_dev, 0xdc, 0x01);
0393 }
0394
0395 static void setcolors(struct gspca_dev *gspca_dev)
0396 {
0397 struct sd *sd = (struct sd *) gspca_dev;
0398 int i, v;
0399 static const int a[9] =
0400 {217, -212, 0, -101, 170, -67, -38, -315, 355};
0401 static const int b[9] =
0402 {19, 106, 0, 19, 106, 1, 19, 106, 1};
0403
0404 reg_w(gspca_dev, 0xff, 0x03);
0405 reg_w(gspca_dev, 0x11, 0x01);
0406 reg_w(gspca_dev, 0xff, 0x00);
0407 for (i = 0; i < 9; i++) {
0408 v = a[i] * sd->saturation->val / (s32)sd->saturation->maximum;
0409 v += b[i];
0410 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
0411 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
0412 }
0413 reg_w(gspca_dev, 0xdc, 0x01);
0414 }
0415
0416 static void setwhitebalance(struct gspca_dev *gspca_dev)
0417 {
0418 struct sd *sd = (struct sd *) gspca_dev;
0419
0420 reg_w(gspca_dev, 0xff, 0x00);
0421 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
0422
0423 reg_w(gspca_dev, 0xdc, 0x01);
0424 }
0425
0426 static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
0427 {
0428 const unsigned int k = 1000;
0429 unsigned int norm;
0430
0431
0432 norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
0433 / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
0434
0435 return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
0436
0437
0438
0439
0440
0441
0442 }
0443
0444 static void setredbalance(struct gspca_dev *gspca_dev)
0445 {
0446 struct sd *sd = (struct sd *) gspca_dev;
0447
0448 reg_w(gspca_dev, 0xff, 0x00);
0449 reg_w(gspca_dev, 0x01,
0450 rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
0451
0452 reg_w(gspca_dev, 0xdc, 0x01);
0453 }
0454
0455 static void setbluebalance(struct gspca_dev *gspca_dev)
0456 {
0457 struct sd *sd = (struct sd *) gspca_dev;
0458
0459 reg_w(gspca_dev, 0xff, 0x00);
0460 reg_w(gspca_dev, 0x03,
0461 rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
0462
0463 reg_w(gspca_dev, 0xdc, 0x01);
0464 }
0465
0466 static void setgain(struct gspca_dev *gspca_dev)
0467 {
0468 u8 reg10, reg12;
0469
0470 if (gspca_dev->gain->val < 32) {
0471 reg10 = gspca_dev->gain->val;
0472 reg12 = 0;
0473 } else {
0474 reg10 = 31;
0475 reg12 = gspca_dev->gain->val - 31;
0476 }
0477
0478 reg_w(gspca_dev, 0xff, 0x03);
0479 reg_w(gspca_dev, 0x10, reg10);
0480 reg_w(gspca_dev, 0x12, reg12);
0481
0482
0483 reg_w(gspca_dev, 0x11, 0x01);
0484 }
0485
0486 static void setexposure(struct gspca_dev *gspca_dev)
0487 {
0488 u8 clockdiv;
0489 u16 exposure;
0490
0491
0492
0493
0494
0495
0496 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
0497
0498
0499
0500
0501
0502
0503
0504 if (clockdiv < 6)
0505 clockdiv = 6;
0506 else if (clockdiv > 63)
0507 clockdiv = 63;
0508
0509
0510
0511
0512
0513
0514 if (clockdiv < 6 || clockdiv > 12)
0515 clockdiv = ((clockdiv + 2) / 3) * 3;
0516
0517
0518
0519
0520
0521 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
0522
0523 exposure = 448 - exposure;
0524
0525 reg_w(gspca_dev, 0xff, 0x03);
0526 reg_w(gspca_dev, 0x02, clockdiv);
0527 reg_w(gspca_dev, 0x0e, exposure & 0xff);
0528 reg_w(gspca_dev, 0x0f, exposure >> 8);
0529
0530
0531 reg_w(gspca_dev, 0x11, 0x01);
0532 }
0533
0534 static void sethvflip(struct gspca_dev *gspca_dev)
0535 {
0536 struct sd *sd = (struct sd *) gspca_dev;
0537 u8 data, hflip, vflip;
0538
0539 hflip = sd->hflip->val;
0540 if (sd->flags & FL_HFLIP)
0541 hflip = !hflip;
0542 vflip = sd->vflip->val;
0543 if (sd->flags & FL_VFLIP)
0544 vflip = !vflip;
0545
0546 reg_w(gspca_dev, 0xff, 0x03);
0547 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
0548 reg_w(gspca_dev, 0x21, data);
0549
0550
0551 reg_w(gspca_dev, 0x11, 0x01);
0552 }
0553
0554 static void setsharpness(struct gspca_dev *gspca_dev)
0555 {
0556 struct sd *sd = (struct sd *) gspca_dev;
0557
0558 reg_w(gspca_dev, 0xff, 0x00);
0559 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
0560
0561 reg_w(gspca_dev, 0xdc, 0x01);
0562 }
0563
0564
0565 static int sd_init(struct gspca_dev *gspca_dev)
0566 {
0567 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
0568 return gspca_dev->usb_err;
0569 }
0570
0571 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
0572 {
0573 struct gspca_dev *gspca_dev =
0574 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
0575 struct sd *sd = (struct sd *)gspca_dev;
0576
0577 gspca_dev->usb_err = 0;
0578
0579 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
0580
0581
0582
0583
0584 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
0585 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
0586 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
0587 }
0588
0589 if (!gspca_dev->streaming)
0590 return 0;
0591
0592 switch (ctrl->id) {
0593 case V4L2_CID_BRIGHTNESS:
0594 setbrightcont(gspca_dev);
0595 break;
0596 case V4L2_CID_SATURATION:
0597 setcolors(gspca_dev);
0598 break;
0599 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
0600 setwhitebalance(gspca_dev);
0601 break;
0602 case V4L2_CID_RED_BALANCE:
0603 setredbalance(gspca_dev);
0604 break;
0605 case V4L2_CID_BLUE_BALANCE:
0606 setbluebalance(gspca_dev);
0607 break;
0608 case V4L2_CID_AUTOGAIN:
0609 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
0610 setexposure(gspca_dev);
0611 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
0612 setgain(gspca_dev);
0613 break;
0614 case V4L2_CID_HFLIP:
0615 sethvflip(gspca_dev);
0616 break;
0617 case V4L2_CID_SHARPNESS:
0618 setsharpness(gspca_dev);
0619 break;
0620 default:
0621 return -EINVAL;
0622 }
0623 return gspca_dev->usb_err;
0624 }
0625
0626 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
0627 .s_ctrl = sd_s_ctrl,
0628 };
0629
0630
0631 static int sd_init_controls(struct gspca_dev *gspca_dev)
0632 {
0633 struct sd *sd = (struct sd *) gspca_dev;
0634 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
0635
0636 gspca_dev->vdev.ctrl_handler = hdl;
0637 v4l2_ctrl_handler_init(hdl, 12);
0638
0639 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0640 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
0641 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0642 V4L2_CID_CONTRAST, 0, 255, 1, 127);
0643
0644 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0645 V4L2_CID_SATURATION, 0, 255, 1, 127);
0646 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0647 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
0648 0, 255, 1, 55);
0649 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0650 V4L2_CID_RED_BALANCE,
0651 PAC7302_RGB_BALANCE_MIN,
0652 PAC7302_RGB_BALANCE_MAX,
0653 1, PAC7302_RGB_BALANCE_DEFAULT);
0654 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0655 V4L2_CID_BLUE_BALANCE,
0656 PAC7302_RGB_BALANCE_MIN,
0657 PAC7302_RGB_BALANCE_MAX,
0658 1, PAC7302_RGB_BALANCE_DEFAULT);
0659
0660 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0661 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
0662 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0663 V4L2_CID_EXPOSURE, 0, 1023, 1,
0664 PAC7302_EXPOSURE_DEFAULT);
0665 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0666 V4L2_CID_GAIN, 0, 62, 1,
0667 PAC7302_GAIN_DEFAULT);
0668
0669 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0670 V4L2_CID_HFLIP, 0, 1, 1, 0);
0671 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0672 V4L2_CID_VFLIP, 0, 1, 1, 0);
0673
0674 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0675 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
0676
0677 if (hdl->error) {
0678 pr_err("Could not initialize controls\n");
0679 return hdl->error;
0680 }
0681
0682 v4l2_ctrl_cluster(2, &sd->brightness);
0683 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
0684 v4l2_ctrl_cluster(2, &sd->hflip);
0685 return 0;
0686 }
0687
0688
0689 static int sd_start(struct gspca_dev *gspca_dev)
0690 {
0691 struct sd *sd = (struct sd *) gspca_dev;
0692
0693 reg_w_var(gspca_dev, start_7302,
0694 page3_7302, sizeof(page3_7302));
0695
0696 sd->sof_read = 0;
0697 sd->autogain_ignore_frames = 0;
0698 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
0699
0700
0701 reg_w(gspca_dev, 0xff, 0x01);
0702 reg_w(gspca_dev, 0x78, 0x01);
0703
0704 return gspca_dev->usb_err;
0705 }
0706
0707 static void sd_stopN(struct gspca_dev *gspca_dev)
0708 {
0709
0710
0711 reg_w(gspca_dev, 0xff, 0x01);
0712 reg_w(gspca_dev, 0x78, 0x00);
0713 }
0714
0715
0716 static void sd_stop0(struct gspca_dev *gspca_dev)
0717 {
0718 if (!gspca_dev->present)
0719 return;
0720 reg_w(gspca_dev, 0xff, 0x01);
0721 reg_w(gspca_dev, 0x78, 0x40);
0722 }
0723
0724 static void do_autogain(struct gspca_dev *gspca_dev)
0725 {
0726 struct sd *sd = (struct sd *) gspca_dev;
0727 int avg_lum = atomic_read(&sd->avg_lum);
0728 int desired_lum;
0729 const int deadzone = 30;
0730
0731 if (sd->autogain_ignore_frames < 0)
0732 return;
0733
0734 if (sd->autogain_ignore_frames > 0) {
0735 sd->autogain_ignore_frames--;
0736 } else {
0737 desired_lum = 270 + sd->brightness->val;
0738
0739 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
0740 deadzone, PAC7302_GAIN_KNEE,
0741 PAC7302_EXPOSURE_KNEE))
0742 sd->autogain_ignore_frames =
0743 PAC_AUTOGAIN_IGNORE_FRAMES;
0744 }
0745 }
0746
0747
0748 static const u8 jpeg_header[] = {
0749 0xff, 0xd8,
0750
0751 0xff, 0xc0,
0752 0x00, 0x11,
0753 0x08,
0754 0x02, 0x80,
0755 0x01, 0xe0,
0756 0x03,
0757 0x01, 0x21, 0x00,
0758 0x02, 0x11, 0x01,
0759 0x03, 0x11, 0x01,
0760
0761 0xff, 0xda,
0762 0x00, 0x0c,
0763 0x03,
0764 0x01, 0x00,
0765 0x02, 0x11,
0766 0x03, 0x11,
0767 0x00, 0x3f,
0768 0x00
0769 };
0770
0771
0772 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
0773 u8 *data,
0774 int len)
0775 {
0776 struct sd *sd = (struct sd *) gspca_dev;
0777 u8 *image;
0778 u8 *sof;
0779
0780 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
0781 if (sof) {
0782 int n, lum_offset, footer_length;
0783
0784
0785
0786
0787
0788
0789
0790 lum_offset = 61 + sizeof pac_sof_marker;
0791 footer_length = 74;
0792
0793
0794 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
0795 if (n < 0) {
0796 gspca_dev->image_len += n;
0797 } else {
0798 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
0799 }
0800
0801 image = gspca_dev->image;
0802 if (image != NULL
0803 && image[gspca_dev->image_len - 2] == 0xff
0804 && image[gspca_dev->image_len - 1] == 0xd9)
0805 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
0806
0807 n = sof - data;
0808 len -= n;
0809 data = sof;
0810
0811
0812 if (gspca_dev->last_packet_type == LAST_PACKET &&
0813 n >= lum_offset)
0814 atomic_set(&sd->avg_lum, data[-lum_offset] +
0815 data[-lum_offset + 1]);
0816
0817
0818
0819 gspca_frame_add(gspca_dev, FIRST_PACKET,
0820 jpeg_header, sizeof jpeg_header);
0821 }
0822 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
0823 }
0824
0825 #ifdef CONFIG_VIDEO_ADV_DEBUG
0826 static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
0827 const struct v4l2_dbg_register *reg)
0828 {
0829 u8 index;
0830 u8 value;
0831
0832
0833
0834
0835
0836 if (reg->match.addr == 0 &&
0837 (reg->reg < 0x000000ff) &&
0838 (reg->val <= 0x000000ff)
0839 ) {
0840
0841
0842 index = reg->reg;
0843 value = reg->val;
0844
0845
0846
0847
0848
0849
0850 reg_w(gspca_dev, 0xff, 0x00);
0851 reg_w(gspca_dev, index, value);
0852
0853 reg_w(gspca_dev, 0xdc, 0x01);
0854 }
0855 return gspca_dev->usb_err;
0856 }
0857 #endif
0858
0859 #if IS_ENABLED(CONFIG_INPUT)
0860 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
0861 u8 *data,
0862 int len)
0863 {
0864 int ret = -EINVAL;
0865 u8 data0, data1;
0866
0867 if (len == 2) {
0868 data0 = data[0];
0869 data1 = data[1];
0870 if ((data0 == 0x00 && data1 == 0x11) ||
0871 (data0 == 0x22 && data1 == 0x33) ||
0872 (data0 == 0x44 && data1 == 0x55) ||
0873 (data0 == 0x66 && data1 == 0x77) ||
0874 (data0 == 0x88 && data1 == 0x99) ||
0875 (data0 == 0xaa && data1 == 0xbb) ||
0876 (data0 == 0xcc && data1 == 0xdd) ||
0877 (data0 == 0xee && data1 == 0xff)) {
0878 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
0879 input_sync(gspca_dev->input_dev);
0880 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
0881 input_sync(gspca_dev->input_dev);
0882 ret = 0;
0883 }
0884 }
0885
0886 return ret;
0887 }
0888 #endif
0889
0890
0891 static const struct sd_desc sd_desc = {
0892 .name = KBUILD_MODNAME,
0893 .config = sd_config,
0894 .init = sd_init,
0895 .init_controls = sd_init_controls,
0896 .start = sd_start,
0897 .stopN = sd_stopN,
0898 .stop0 = sd_stop0,
0899 .pkt_scan = sd_pkt_scan,
0900 .dq_callback = do_autogain,
0901 #ifdef CONFIG_VIDEO_ADV_DEBUG
0902 .set_register = sd_dbg_s_register,
0903 #endif
0904 #if IS_ENABLED(CONFIG_INPUT)
0905 .int_pkt_scan = sd_int_pkt_scan,
0906 #endif
0907 };
0908
0909
0910 static const struct usb_device_id device_table[] = {
0911 {USB_DEVICE(0x06f8, 0x3009)},
0912 {USB_DEVICE(0x06f8, 0x301b)},
0913 {USB_DEVICE(0x093a, 0x2620)},
0914 {USB_DEVICE(0x093a, 0x2621)},
0915 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
0916 {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP},
0917 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
0918 {USB_DEVICE(0x093a, 0x2625)},
0919 {USB_DEVICE(0x093a, 0x2626)},
0920 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
0921 {USB_DEVICE(0x093a, 0x2628)},
0922 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
0923 {USB_DEVICE(0x093a, 0x262a)},
0924 {USB_DEVICE(0x093a, 0x262c)},
0925 {USB_DEVICE(0x145f, 0x013c)},
0926 {USB_DEVICE(0x1ae7, 0x2001)},
0927 {}
0928 };
0929 MODULE_DEVICE_TABLE(usb, device_table);
0930
0931
0932 static int sd_probe(struct usb_interface *intf,
0933 const struct usb_device_id *id)
0934 {
0935 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
0936 THIS_MODULE);
0937 }
0938
0939 static struct usb_driver sd_driver = {
0940 .name = KBUILD_MODNAME,
0941 .id_table = device_table,
0942 .probe = sd_probe,
0943 .disconnect = gspca_disconnect,
0944 #ifdef CONFIG_PM
0945 .suspend = gspca_suspend,
0946 .resume = gspca_resume,
0947 .reset_resume = gspca_resume,
0948 #endif
0949 };
0950
0951 module_usb_driver(sd_driver);