0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #define MODULE_NAME "sunplus"
0012
0013 #include "gspca.h"
0014 #include "jpeg.h"
0015
0016 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
0017 MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
0018 MODULE_LICENSE("GPL");
0019
0020 #define QUALITY 85
0021
0022
0023 struct sd {
0024 struct gspca_dev gspca_dev;
0025
0026 bool autogain;
0027
0028 u8 bridge;
0029 #define BRIDGE_SPCA504 0
0030 #define BRIDGE_SPCA504B 1
0031 #define BRIDGE_SPCA504C 2
0032 #define BRIDGE_SPCA533 3
0033 #define BRIDGE_SPCA536 4
0034 u8 subtype;
0035 #define AiptekMiniPenCam13 1
0036 #define LogitechClickSmart420 2
0037 #define LogitechClickSmart820 3
0038 #define MegapixV4 4
0039 #define MegaImageVI 5
0040
0041 u8 jpeg_hdr[JPEG_HDR_SZ];
0042 };
0043
0044 static const struct v4l2_pix_format vga_mode[] = {
0045 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0046 .bytesperline = 320,
0047 .sizeimage = 320 * 240 * 3 / 8 + 590,
0048 .colorspace = V4L2_COLORSPACE_JPEG,
0049 .priv = 2},
0050 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0051 .bytesperline = 640,
0052 .sizeimage = 640 * 480 * 3 / 8 + 590,
0053 .colorspace = V4L2_COLORSPACE_JPEG,
0054 .priv = 1},
0055 };
0056
0057 static const struct v4l2_pix_format custom_mode[] = {
0058 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0059 .bytesperline = 320,
0060 .sizeimage = 320 * 240 * 3 / 8 + 590,
0061 .colorspace = V4L2_COLORSPACE_JPEG,
0062 .priv = 2},
0063 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0064 .bytesperline = 464,
0065 .sizeimage = 464 * 480 * 3 / 8 + 590,
0066 .colorspace = V4L2_COLORSPACE_JPEG,
0067 .priv = 1},
0068 };
0069
0070 static const struct v4l2_pix_format vga_mode2[] = {
0071 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0072 .bytesperline = 176,
0073 .sizeimage = 176 * 144 * 3 / 8 + 590,
0074 .colorspace = V4L2_COLORSPACE_JPEG,
0075 .priv = 4},
0076 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0077 .bytesperline = 320,
0078 .sizeimage = 320 * 240 * 3 / 8 + 590,
0079 .colorspace = V4L2_COLORSPACE_JPEG,
0080 .priv = 3},
0081 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0082 .bytesperline = 352,
0083 .sizeimage = 352 * 288 * 3 / 8 + 590,
0084 .colorspace = V4L2_COLORSPACE_JPEG,
0085 .priv = 2},
0086 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0087 .bytesperline = 640,
0088 .sizeimage = 640 * 480 * 3 / 8 + 590,
0089 .colorspace = V4L2_COLORSPACE_JPEG,
0090 .priv = 1},
0091 };
0092
0093 #define SPCA50X_OFFSET_DATA 10
0094 #define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
0095 #define SPCA504_PCCAM600_OFFSET_COMPRESS 4
0096 #define SPCA504_PCCAM600_OFFSET_MODE 5
0097 #define SPCA504_PCCAM600_OFFSET_DATA 14
0098
0099 #define SPCA533_OFFSET_DATA 16
0100 #define SPCA533_OFFSET_FRAMSEQ 15
0101
0102 #define SPCA536_OFFSET_DATA 4
0103 #define SPCA536_OFFSET_FRAMSEQ 1
0104
0105 struct cmd {
0106 u8 req;
0107 u16 val;
0108 u16 idx;
0109 };
0110
0111
0112 static const struct cmd spca504_pccam600_init_data[] = {
0113
0114 {0x00, 0x0000, 0x2000},
0115 {0x00, 0x0013, 0x2301},
0116 {0x00, 0x0003, 0x2000},
0117 {0x00, 0x0001, 0x21ac},
0118 {0x00, 0x0001, 0x21a6},
0119 {0x00, 0x0000, 0x21a7},
0120 {0x00, 0x0020, 0x21a8},
0121 {0x00, 0x0001, 0x21ac},
0122 {0x00, 0x0000, 0x21ad},
0123 {0x00, 0x001a, 0x21ae},
0124 {0x00, 0x0002, 0x21a3},
0125 {0x30, 0x0154, 0x0008},
0126 {0x30, 0x0004, 0x0006},
0127 {0x30, 0x0258, 0x0009},
0128 {0x30, 0x0004, 0x0000},
0129 {0x30, 0x0093, 0x0004},
0130 {0x30, 0x0066, 0x0005},
0131 {0x00, 0x0000, 0x2000},
0132 {0x00, 0x0013, 0x2301},
0133 {0x00, 0x0003, 0x2000},
0134 {0x00, 0x0013, 0x2301},
0135 {0x00, 0x0003, 0x2000},
0136 };
0137
0138
0139
0140
0141 static const struct cmd spca504_pccam600_open_data[] = {
0142 {0x00, 0x0001, 0x2501},
0143 {0x20, 0x0500, 0x0001},
0144 {0x00, 0x0003, 0x2880},
0145 {0x00, 0x0001, 0x2881},
0146 };
0147
0148
0149 static const struct cmd spca504A_clicksmart420_init_data[] = {
0150
0151 {0x00, 0x0000, 0x2000},
0152 {0x00, 0x0013, 0x2301},
0153 {0x00, 0x0003, 0x2000},
0154 {0x00, 0x0001, 0x21ac},
0155 {0x00, 0x0001, 0x21a6},
0156 {0x00, 0x0000, 0x21a7},
0157 {0x00, 0x0020, 0x21a8},
0158 {0x00, 0x0001, 0x21ac},
0159 {0x00, 0x0000, 0x21ad},
0160 {0x00, 0x001a, 0x21ae},
0161 {0x00, 0x0002, 0x21a3},
0162 {0x30, 0x0004, 0x000a},
0163 {0xb0, 0x0001, 0x0000},
0164
0165 {0xa1, 0x0080, 0x0001},
0166 {0x30, 0x0049, 0x0000},
0167 {0x30, 0x0060, 0x0005},
0168 {0x0c, 0x0004, 0x0000},
0169 {0x00, 0x0000, 0x0000},
0170 {0x00, 0x0000, 0x2000},
0171 {0x00, 0x0013, 0x2301},
0172 {0x00, 0x0003, 0x2000},
0173 };
0174
0175
0176 static const struct cmd spca504A_clicksmart420_open_data[] = {
0177 {0x00, 0x0001, 0x2501},
0178 {0x20, 0x0502, 0x0000},
0179 {0x06, 0x0000, 0x0000},
0180 {0x00, 0x0004, 0x2880},
0181 {0x00, 0x0001, 0x2881},
0182
0183 {0xa0, 0x0000, 0x0503},
0184 };
0185
0186 static const u8 qtable_creative_pccam[2][64] = {
0187 {
0188 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0189 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
0190 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
0191 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
0192 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
0193 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
0194 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
0195 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
0196 {
0197 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
0198 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
0199 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0200 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0201 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0202 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0203 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0204 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
0205 };
0206
0207
0208
0209
0210
0211 static const u8 qtable_spca504_default[2][64] = {
0212 {
0213 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0214 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
0215 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
0216 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
0217 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
0218 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
0219 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
0220 0x16, 0x1c, 0x1d, 0x1d, 0x1d , 0x1e, 0x1f, 0x1e,
0221 },
0222 {
0223 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
0224 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
0225 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0226 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0227 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0228 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0229 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0230 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
0231 };
0232
0233
0234 static void reg_r(struct gspca_dev *gspca_dev,
0235 u8 req,
0236 u16 index,
0237 u16 len)
0238 {
0239 int ret;
0240
0241 if (len > USB_BUF_SZ) {
0242 gspca_err(gspca_dev, "reg_r: buffer overflow\n");
0243 return;
0244 }
0245 if (len == 0) {
0246 gspca_err(gspca_dev, "reg_r: zero-length read\n");
0247 return;
0248 }
0249 if (gspca_dev->usb_err < 0)
0250 return;
0251 ret = usb_control_msg(gspca_dev->dev,
0252 usb_rcvctrlpipe(gspca_dev->dev, 0),
0253 req,
0254 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0255 0,
0256 index,
0257 gspca_dev->usb_buf, len,
0258 500);
0259 if (ret < 0) {
0260 pr_err("reg_r err %d\n", ret);
0261 gspca_dev->usb_err = ret;
0262
0263
0264
0265
0266 memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
0267 }
0268 }
0269
0270
0271 static void reg_w_1(struct gspca_dev *gspca_dev,
0272 u8 req,
0273 u16 value,
0274 u16 index,
0275 u16 byte)
0276 {
0277 int ret;
0278
0279 if (gspca_dev->usb_err < 0)
0280 return;
0281 gspca_dev->usb_buf[0] = byte;
0282 ret = usb_control_msg(gspca_dev->dev,
0283 usb_sndctrlpipe(gspca_dev->dev, 0),
0284 req,
0285 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0286 value, index,
0287 gspca_dev->usb_buf, 1,
0288 500);
0289 if (ret < 0) {
0290 pr_err("reg_w_1 err %d\n", ret);
0291 gspca_dev->usb_err = ret;
0292 }
0293 }
0294
0295
0296 static void reg_w_riv(struct gspca_dev *gspca_dev,
0297 u8 req, u16 index, u16 value)
0298 {
0299 struct usb_device *dev = gspca_dev->dev;
0300 int ret;
0301
0302 if (gspca_dev->usb_err < 0)
0303 return;
0304 ret = usb_control_msg(dev,
0305 usb_sndctrlpipe(dev, 0),
0306 req,
0307 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0308 value, index, NULL, 0, 500);
0309 if (ret < 0) {
0310 pr_err("reg_w_riv err %d\n", ret);
0311 gspca_dev->usb_err = ret;
0312 return;
0313 }
0314 gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n",
0315 req, index, value);
0316 }
0317
0318 static void write_vector(struct gspca_dev *gspca_dev,
0319 const struct cmd *data, int ncmds)
0320 {
0321 while (--ncmds >= 0) {
0322 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
0323 data++;
0324 }
0325 }
0326
0327 static void setup_qtable(struct gspca_dev *gspca_dev,
0328 const u8 qtable[2][64])
0329 {
0330 int i;
0331
0332
0333 for (i = 0; i < 64; i++)
0334 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
0335
0336
0337 for (i = 0; i < 64; i++)
0338 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
0339 }
0340
0341 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
0342 u8 req, u16 idx, u16 val)
0343 {
0344 reg_w_riv(gspca_dev, req, idx, val);
0345 reg_r(gspca_dev, 0x01, 0x0001, 1);
0346 gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n",
0347 gspca_dev->usb_buf[0]);
0348 reg_w_riv(gspca_dev, req, idx, val);
0349
0350 msleep(200);
0351 reg_r(gspca_dev, 0x01, 0x0001, 1);
0352 gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n",
0353 gspca_dev->usb_buf[0]);
0354 }
0355
0356 static void spca504_read_info(struct gspca_dev *gspca_dev)
0357 {
0358 int i;
0359 u8 info[6];
0360
0361 if (gspca_debug < D_STREAM)
0362 return;
0363
0364 for (i = 0; i < 6; i++) {
0365 reg_r(gspca_dev, 0, i, 1);
0366 info[i] = gspca_dev->usb_buf[0];
0367 }
0368 gspca_dbg(gspca_dev, D_STREAM,
0369 "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n",
0370 info[0], info[1], info[2],
0371 info[3], info[4], info[5]);
0372 }
0373
0374 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
0375 u8 req,
0376 u16 idx, u16 val, u8 endcode, u8 count)
0377 {
0378 u16 status;
0379
0380 reg_w_riv(gspca_dev, req, idx, val);
0381 reg_r(gspca_dev, 0x01, 0x0001, 1);
0382 if (gspca_dev->usb_err < 0)
0383 return;
0384 gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n",
0385 gspca_dev->usb_buf[0], endcode);
0386 if (!count)
0387 return;
0388 count = 200;
0389 while (--count > 0) {
0390 msleep(10);
0391
0392
0393 reg_r(gspca_dev, 0x01, 0x0001, 1);
0394 status = gspca_dev->usb_buf[0];
0395 if (status == endcode) {
0396 gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n",
0397 status, 200 - count);
0398 break;
0399 }
0400 }
0401 }
0402
0403 static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
0404 {
0405 int count = 10;
0406
0407 while (--count > 0) {
0408 reg_r(gspca_dev, 0x21, 0, 1);
0409 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
0410 break;
0411 msleep(10);
0412 }
0413 }
0414
0415 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
0416 {
0417 int count = 50;
0418
0419 while (--count > 0) {
0420 reg_r(gspca_dev, 0x21, 1, 1);
0421 if (gspca_dev->usb_buf[0] != 0) {
0422 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
0423 reg_r(gspca_dev, 0x21, 1, 1);
0424 spca504B_PollingDataReady(gspca_dev);
0425 break;
0426 }
0427 msleep(10);
0428 }
0429 }
0430
0431 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
0432 {
0433 u8 *data;
0434
0435 if (gspca_debug < D_STREAM)
0436 return;
0437
0438 data = gspca_dev->usb_buf;
0439 reg_r(gspca_dev, 0x20, 0, 5);
0440 gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n",
0441 data[0], data[1], data[2], data[3], data[4]);
0442 reg_r(gspca_dev, 0x23, 0, 64);
0443 reg_r(gspca_dev, 0x23, 1, 64);
0444 }
0445
0446 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
0447 {
0448 struct sd *sd = (struct sd *) gspca_dev;
0449 u8 Size;
0450
0451 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
0452 switch (sd->bridge) {
0453 case BRIDGE_SPCA533:
0454 reg_w_riv(gspca_dev, 0x31, 0, 0);
0455 spca504B_WaitCmdStatus(gspca_dev);
0456 spca504B_PollingDataReady(gspca_dev);
0457 spca50x_GetFirmware(gspca_dev);
0458
0459 reg_w_1(gspca_dev, 0x24, 0, 8, 2);
0460 reg_r(gspca_dev, 0x24, 8, 1);
0461
0462 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
0463 reg_r(gspca_dev, 0x25, 4, 1);
0464 spca504B_PollingDataReady(gspca_dev);
0465
0466
0467 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
0468 spca504B_WaitCmdStatus(gspca_dev);
0469 spca504B_PollingDataReady(gspca_dev);
0470 break;
0471 default:
0472
0473
0474 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
0475 reg_r(gspca_dev, 0x25, 4, 1);
0476 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
0477 reg_r(gspca_dev, 0x27, 0, 1);
0478 spca504B_PollingDataReady(gspca_dev);
0479 break;
0480 case BRIDGE_SPCA504:
0481 Size += 3;
0482 if (sd->subtype == AiptekMiniPenCam13) {
0483
0484 spca504A_acknowledged_command(gspca_dev,
0485 0x08, Size, 0,
0486 0x80 | (Size & 0x0f), 1);
0487 spca504A_acknowledged_command(gspca_dev,
0488 1, 3, 0, 0x9f, 0);
0489 } else {
0490 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
0491 }
0492 break;
0493 case BRIDGE_SPCA504C:
0494
0495 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
0496 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
0497 break;
0498 }
0499 }
0500
0501 static void spca504_wait_status(struct gspca_dev *gspca_dev)
0502 {
0503 int cnt;
0504
0505 cnt = 256;
0506 while (--cnt > 0) {
0507
0508 reg_r(gspca_dev, 0x06, 0x00, 1);
0509 if (gspca_dev->usb_buf[0] == 0)
0510 return;
0511 msleep(10);
0512 }
0513 }
0514
0515 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
0516 {
0517 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
0518 reg_r(gspca_dev, 0x26, 0, 1);
0519 spca504B_PollingDataReady(gspca_dev);
0520 }
0521
0522 static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
0523 {
0524 struct sd *sd = (struct sd *) gspca_dev;
0525 u16 reg;
0526
0527 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
0528 reg_w_riv(gspca_dev, 0x00, reg, val);
0529 }
0530
0531 static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
0532 {
0533 struct sd *sd = (struct sd *) gspca_dev;
0534 u16 reg;
0535
0536 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
0537 reg_w_riv(gspca_dev, 0x00, reg, val);
0538 }
0539
0540 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
0541 {
0542 struct sd *sd = (struct sd *) gspca_dev;
0543 u16 reg;
0544
0545 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
0546 reg_w_riv(gspca_dev, 0x00, reg, val);
0547 }
0548
0549 static void init_ctl_reg(struct gspca_dev *gspca_dev)
0550 {
0551 struct sd *sd = (struct sd *) gspca_dev;
0552 int pollreg = 1;
0553
0554 switch (sd->bridge) {
0555 case BRIDGE_SPCA504:
0556 case BRIDGE_SPCA504C:
0557 pollreg = 0;
0558 fallthrough;
0559 default:
0560
0561
0562 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);
0563 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);
0564 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);
0565 break;
0566 case BRIDGE_SPCA536:
0567 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
0568 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
0569 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
0570 break;
0571 }
0572 if (pollreg)
0573 spca504B_PollingDataReady(gspca_dev);
0574 }
0575
0576
0577 static int sd_config(struct gspca_dev *gspca_dev,
0578 const struct usb_device_id *id)
0579 {
0580 struct sd *sd = (struct sd *) gspca_dev;
0581 struct cam *cam;
0582
0583 cam = &gspca_dev->cam;
0584
0585 sd->bridge = id->driver_info >> 8;
0586 sd->subtype = id->driver_info;
0587
0588 if (sd->subtype == AiptekMiniPenCam13) {
0589
0590
0591
0592 reg_r(gspca_dev, 0x20, 0, 1);
0593 switch (gspca_dev->usb_buf[0]) {
0594 case 1:
0595 break;
0596 case 2:
0597 sd->bridge = BRIDGE_SPCA504B;
0598 sd->subtype = 0;
0599 break;
0600 default:
0601 return -ENODEV;
0602 }
0603 }
0604
0605 switch (sd->bridge) {
0606 default:
0607
0608
0609
0610 cam->cam_mode = vga_mode;
0611 cam->nmodes = ARRAY_SIZE(vga_mode);
0612 break;
0613 case BRIDGE_SPCA533:
0614 cam->cam_mode = custom_mode;
0615 if (sd->subtype == MegaImageVI)
0616 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
0617 else
0618 cam->nmodes = ARRAY_SIZE(custom_mode);
0619 break;
0620 case BRIDGE_SPCA504C:
0621 cam->cam_mode = vga_mode2;
0622 cam->nmodes = ARRAY_SIZE(vga_mode2);
0623 break;
0624 }
0625 return 0;
0626 }
0627
0628
0629 static int sd_init(struct gspca_dev *gspca_dev)
0630 {
0631 struct sd *sd = (struct sd *) gspca_dev;
0632
0633 switch (sd->bridge) {
0634 case BRIDGE_SPCA504B:
0635 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
0636 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
0637 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
0638 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
0639 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
0640 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
0641 fallthrough;
0642 case BRIDGE_SPCA533:
0643 spca504B_PollingDataReady(gspca_dev);
0644 spca50x_GetFirmware(gspca_dev);
0645 break;
0646 case BRIDGE_SPCA536:
0647 spca50x_GetFirmware(gspca_dev);
0648 reg_r(gspca_dev, 0x00, 0x5002, 1);
0649 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
0650 reg_r(gspca_dev, 0x24, 0, 1);
0651 spca504B_PollingDataReady(gspca_dev);
0652 reg_w_riv(gspca_dev, 0x34, 0, 0);
0653 spca504B_WaitCmdStatus(gspca_dev);
0654 break;
0655 case BRIDGE_SPCA504C:
0656 gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n");
0657 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
0658 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);
0659 spca504_wait_status(gspca_dev);
0660 if (sd->subtype == LogitechClickSmart420)
0661 write_vector(gspca_dev,
0662 spca504A_clicksmart420_open_data,
0663 ARRAY_SIZE(spca504A_clicksmart420_open_data));
0664 else
0665 write_vector(gspca_dev, spca504_pccam600_open_data,
0666 ARRAY_SIZE(spca504_pccam600_open_data));
0667 setup_qtable(gspca_dev, qtable_creative_pccam);
0668 break;
0669 default:
0670
0671 gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n");
0672 if (sd->subtype == AiptekMiniPenCam13) {
0673 spca504_read_info(gspca_dev);
0674
0675
0676 spca504A_acknowledged_command(gspca_dev, 0x24,
0677 8, 3, 0x9e, 1);
0678
0679 spca504A_acknowledged_command(gspca_dev, 0x24,
0680 8, 3, 0x9e, 0);
0681
0682 spca504A_acknowledged_command(gspca_dev, 0x24,
0683 0, 0, 0x9d, 1);
0684
0685
0686 spca504A_acknowledged_command(gspca_dev, 0x08,
0687 6, 0, 0x86, 1);
0688
0689
0690
0691
0692
0693
0694 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
0695
0696 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
0697 spca504A_acknowledged_command(gspca_dev, 0x01,
0698 0x0f, 0, 0xff, 0);
0699 }
0700
0701 reg_w_riv(gspca_dev, 0, 0x2000, 0);
0702 reg_w_riv(gspca_dev, 0, 0x2883, 1);
0703 setup_qtable(gspca_dev, qtable_spca504_default);
0704 break;
0705 }
0706 return gspca_dev->usb_err;
0707 }
0708
0709 static int sd_start(struct gspca_dev *gspca_dev)
0710 {
0711 struct sd *sd = (struct sd *) gspca_dev;
0712 int enable;
0713
0714
0715 jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
0716 gspca_dev->pixfmt.width,
0717 0x22);
0718 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
0719
0720 if (sd->bridge == BRIDGE_SPCA504B)
0721 spca504B_setQtable(gspca_dev);
0722 spca504B_SetSizeType(gspca_dev);
0723 switch (sd->bridge) {
0724 default:
0725
0726
0727
0728 switch (sd->subtype) {
0729 case MegapixV4:
0730 case LogitechClickSmart820:
0731 case MegaImageVI:
0732 reg_w_riv(gspca_dev, 0xf0, 0, 0);
0733 spca504B_WaitCmdStatus(gspca_dev);
0734 reg_w_riv(gspca_dev, 0xf0, 4, 0);
0735 spca504B_WaitCmdStatus(gspca_dev);
0736 break;
0737 default:
0738 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
0739 spca504B_WaitCmdStatus(gspca_dev);
0740 spca504B_PollingDataReady(gspca_dev);
0741 break;
0742 }
0743 break;
0744 case BRIDGE_SPCA504:
0745 if (sd->subtype == AiptekMiniPenCam13) {
0746 spca504_read_info(gspca_dev);
0747
0748
0749 spca504A_acknowledged_command(gspca_dev, 0x24,
0750 8, 3, 0x9e, 1);
0751
0752 spca504A_acknowledged_command(gspca_dev, 0x24,
0753 8, 3, 0x9e, 0);
0754 spca504A_acknowledged_command(gspca_dev, 0x24,
0755 0, 0, 0x9d, 1);
0756 } else {
0757 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
0758 spca504_read_info(gspca_dev);
0759 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
0760 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
0761 }
0762 spca504B_SetSizeType(gspca_dev);
0763 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
0764
0765 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
0766 break;
0767 case BRIDGE_SPCA504C:
0768 if (sd->subtype == LogitechClickSmart420) {
0769 write_vector(gspca_dev,
0770 spca504A_clicksmart420_init_data,
0771 ARRAY_SIZE(spca504A_clicksmart420_init_data));
0772 } else {
0773 write_vector(gspca_dev, spca504_pccam600_init_data,
0774 ARRAY_SIZE(spca504_pccam600_init_data));
0775 }
0776 enable = (sd->autogain ? 0x04 : 0x01);
0777 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
0778
0779 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
0780
0781
0782
0783 reg_w_riv(gspca_dev, 0x30, 0x0001, 800);
0784 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
0785 spca504B_SetSizeType(gspca_dev);
0786 break;
0787 }
0788 init_ctl_reg(gspca_dev);
0789 return gspca_dev->usb_err;
0790 }
0791
0792 static void sd_stopN(struct gspca_dev *gspca_dev)
0793 {
0794 struct sd *sd = (struct sd *) gspca_dev;
0795
0796 switch (sd->bridge) {
0797 default:
0798
0799
0800
0801 reg_w_riv(gspca_dev, 0x31, 0, 0);
0802 spca504B_WaitCmdStatus(gspca_dev);
0803 spca504B_PollingDataReady(gspca_dev);
0804 break;
0805 case BRIDGE_SPCA504:
0806 case BRIDGE_SPCA504C:
0807 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
0808
0809 if (sd->subtype == AiptekMiniPenCam13) {
0810
0811
0812
0813 spca504A_acknowledged_command(gspca_dev, 0x24,
0814 0x00, 0x00, 0x9d, 1);
0815 spca504A_acknowledged_command(gspca_dev, 0x01,
0816 0x0f, 0x00, 0xff, 1);
0817 } else {
0818 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
0819 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
0820 }
0821 break;
0822 }
0823 }
0824
0825 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
0826 u8 *data,
0827 int len)
0828 {
0829 struct sd *sd = (struct sd *) gspca_dev;
0830 int i, sof = 0;
0831 static u8 ffd9[] = {0xff, 0xd9};
0832
0833
0834 switch (sd->bridge) {
0835 case BRIDGE_SPCA533:
0836 if (data[0] == 0xff) {
0837 if (data[1] != 0x01) {
0838
0839 return;
0840 }
0841 sof = 1;
0842 data += SPCA533_OFFSET_DATA;
0843 len -= SPCA533_OFFSET_DATA;
0844 } else {
0845 data += 1;
0846 len -= 1;
0847 }
0848 break;
0849 case BRIDGE_SPCA536:
0850 if (data[0] == 0xff) {
0851 sof = 1;
0852 data += SPCA536_OFFSET_DATA;
0853 len -= SPCA536_OFFSET_DATA;
0854 } else {
0855 data += 2;
0856 len -= 2;
0857 }
0858 break;
0859 default:
0860
0861
0862 switch (data[0]) {
0863 case 0xfe:
0864 sof = 1;
0865 data += SPCA50X_OFFSET_DATA;
0866 len -= SPCA50X_OFFSET_DATA;
0867 break;
0868 case 0xff:
0869
0870 return;
0871 default:
0872 data += 1;
0873 len -= 1;
0874 break;
0875 }
0876 break;
0877 case BRIDGE_SPCA504C:
0878 switch (data[0]) {
0879 case 0xfe:
0880 sof = 1;
0881 data += SPCA504_PCCAM600_OFFSET_DATA;
0882 len -= SPCA504_PCCAM600_OFFSET_DATA;
0883 break;
0884 case 0xff:
0885
0886 return;
0887 default:
0888 data += 1;
0889 len -= 1;
0890 break;
0891 }
0892 break;
0893 }
0894 if (sof) {
0895 gspca_frame_add(gspca_dev, LAST_PACKET,
0896 ffd9, 2);
0897
0898
0899 gspca_frame_add(gspca_dev, FIRST_PACKET,
0900 sd->jpeg_hdr, JPEG_HDR_SZ);
0901 }
0902
0903
0904 i = 0;
0905 do {
0906 if (data[i] == 0xff) {
0907 gspca_frame_add(gspca_dev, INTER_PACKET,
0908 data, i + 1);
0909 len -= i;
0910 data += i;
0911 *data = 0x00;
0912 i = 0;
0913 }
0914 i++;
0915 } while (i < len);
0916 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
0917 }
0918
0919 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
0920 {
0921 struct gspca_dev *gspca_dev =
0922 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
0923 struct sd *sd = (struct sd *)gspca_dev;
0924
0925 gspca_dev->usb_err = 0;
0926
0927 if (!gspca_dev->streaming)
0928 return 0;
0929
0930 switch (ctrl->id) {
0931 case V4L2_CID_BRIGHTNESS:
0932 setbrightness(gspca_dev, ctrl->val);
0933 break;
0934 case V4L2_CID_CONTRAST:
0935 setcontrast(gspca_dev, ctrl->val);
0936 break;
0937 case V4L2_CID_SATURATION:
0938 setcolors(gspca_dev, ctrl->val);
0939 break;
0940 case V4L2_CID_AUTOGAIN:
0941 sd->autogain = ctrl->val;
0942 break;
0943 }
0944 return gspca_dev->usb_err;
0945 }
0946
0947 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
0948 .s_ctrl = sd_s_ctrl,
0949 };
0950
0951 static int sd_init_controls(struct gspca_dev *gspca_dev)
0952 {
0953 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
0954
0955 gspca_dev->vdev.ctrl_handler = hdl;
0956 v4l2_ctrl_handler_init(hdl, 4);
0957 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0958 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
0959 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0960 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
0961 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0962 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
0963 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0964 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
0965
0966 if (hdl->error) {
0967 pr_err("Could not initialize controls\n");
0968 return hdl->error;
0969 }
0970 return 0;
0971 }
0972
0973
0974 static const struct sd_desc sd_desc = {
0975 .name = MODULE_NAME,
0976 .config = sd_config,
0977 .init = sd_init,
0978 .init_controls = sd_init_controls,
0979 .start = sd_start,
0980 .stopN = sd_stopN,
0981 .pkt_scan = sd_pkt_scan,
0982 };
0983
0984
0985 #define BS(bridge, subtype) \
0986 .driver_info = (BRIDGE_ ## bridge << 8) \
0987 | (subtype)
0988 static const struct usb_device_id device_table[] = {
0989 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
0990 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
0991 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
0992 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
0993 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
0994 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
0995 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
0996 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
0997 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
0998 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
0999 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1000 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1001 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1002 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1003 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1004 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1005 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1006 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1007 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1008 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1009 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1010 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1011 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1012 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1013 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1014 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1015 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1016 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1017 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1018 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1019 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1020 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1021 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1022 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1023 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1024 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1025 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1026 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1027 {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1028 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1029 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1030 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1031 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1032 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1033 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1034 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1035 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1036 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1037 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1038 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1039 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1040 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1041 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1042 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1043 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1044 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1045 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1047 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1048 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1049 {}
1050 };
1051 MODULE_DEVICE_TABLE(usb, device_table);
1052
1053
1054 static int sd_probe(struct usb_interface *intf,
1055 const struct usb_device_id *id)
1056 {
1057 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1058 THIS_MODULE);
1059 }
1060
1061 static struct usb_driver sd_driver = {
1062 .name = MODULE_NAME,
1063 .id_table = device_table,
1064 .probe = sd_probe,
1065 .disconnect = gspca_disconnect,
1066 #ifdef CONFIG_PM
1067 .suspend = gspca_suspend,
1068 .resume = gspca_resume,
1069 .reset_resume = gspca_resume,
1070 #endif
1071 };
1072
1073 module_usb_driver(sd_driver);