touptek.c (21062B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * ToupTek UCMOS / AmScope MU series camera driver 4 * TODO: contrast with ScopeTek / AmScope MDC cameras 5 * 6 * Copyright (C) 2012-2014 John McMaster <JohnDMcMaster@gmail.com> 7 * 8 * Special thanks to Bushing for helping with the decrypt algorithm and 9 * Sean O'Sullivan / the Rensselaer Center for Open Source 10 * Software (RCOS) for helping me learn kernel development 11 */ 12 13#include "gspca.h" 14 15#define MODULE_NAME "touptek" 16 17MODULE_AUTHOR("John McMaster"); 18MODULE_DESCRIPTION("ToupTek UCMOS / Amscope MU microscope camera driver"); 19MODULE_LICENSE("GPL"); 20 21/* 22 * Exposure reg is linear with exposure time 23 * Exposure (sec), E (reg) 24 * 0.000400, 0x0002 25 * 0.001000, 0x0005 26 * 0.005000, 0x0019 27 * 0.020000, 0x0064 28 * 0.080000, 0x0190 29 * 0.400000, 0x07D0 30 * 1.000000, 0x1388 31 * 2.000000, 0x2710 32 * 33 * Three gain stages 34 * 0x1000: master channel enable bit 35 * 0x007F: low gain bits 36 * 0x0080: medium gain bit 37 * 0x0100: high gain bit 38 * gain = enable * (1 + regH) * (1 + regM) * z * regL 39 * 40 * Gain implementation 41 * Want to do something similar to mt9v011.c's set_balance 42 * 43 * Gain does not vary with resolution (checked 640x480 vs 1600x1200) 44 * 45 * Constant derivation: 46 * 47 * Raw data: 48 * Gain, GTOP, B, R, GBOT 49 * 1.00, 0x105C, 0x1068, 0x10C8, 0x105C 50 * 1.20, 0x106E, 0x107E, 0x10D6, 0x106E 51 * 1.40, 0x10C0, 0x10CA, 0x10E5, 0x10C0 52 * 1.60, 0x10C9, 0x10D4, 0x10F3, 0x10C9 53 * 1.80, 0x10D2, 0x10DE, 0x11C1, 0x10D2 54 * 2.00, 0x10DC, 0x10E9, 0x11C8, 0x10DC 55 * 2.20, 0x10E5, 0x10F3, 0x11CF, 0x10E5 56 * 2.40, 0x10EE, 0x10FE, 0x11D7, 0x10EE 57 * 2.60, 0x10F7, 0x11C4, 0x11DE, 0x10F7 58 * 2.80, 0x11C0, 0x11CA, 0x11E5, 0x11C0 59 * 3.00, 0x11C5, 0x11CF, 0x11ED, 0x11C5 60 * 61 * zR = 0.0069605943152454778 62 * about 3/431 = 0.0069605568445475635 63 * zB = 0.0095695970695970703 64 * about 6/627 = 0.0095693779904306216 65 * zG = 0.010889328063241107 66 * about 6/551 = 0.010889292196007259 67 * about 10 bits for constant + 7 bits for value => at least 17 bit 68 * intermediate with 32 bit ints should be fine for overflow etc 69 * Essentially gains are in range 0-0x001FF 70 * 71 * However, V4L expects a main gain channel + R and B balance 72 * To keep things simple for now saturate the values of balance is too high/low 73 * This isn't really ideal but easy way to fit the Linux model 74 * 75 * Converted using gain model turns out to be quite linear: 76 * Gain, GTOP, B, R, GBOT 77 * 1.00, 92, 104, 144, 92 78 * 1.20, 110, 126, 172, 110 79 * 1.40, 128, 148, 202, 128 80 * 1.60, 146, 168, 230, 146 81 * 1.80, 164, 188, 260, 164 82 * 2.00, 184, 210, 288, 184 83 * 2.20, 202, 230, 316, 202 84 * 2.40, 220, 252, 348, 220 85 * 2.60, 238, 272, 376, 238 86 * 2.80, 256, 296, 404, 256 87 * 3.00, 276, 316, 436, 276 88 * 89 * Maximum gain is 0x7FF * 2 * 2 => 0x1FFC (8188) 90 * or about 13 effective bits of gain 91 * The highest the commercial driver goes in my setup 436 92 * However, because could *maybe* damage circuits 93 * limit the gain until have a reason to go higher 94 * Solution: gain clipped and warning emitted 95 */ 96#define GAIN_MAX 511 97 98/* Frame sync is a short read */ 99#define BULK_SIZE 0x4000 100 101/* MT9E001 reg names to give a rough approximation */ 102#define REG_COARSE_INTEGRATION_TIME_ 0x3012 103#define REG_GROUPED_PARAMETER_HOLD_ 0x3022 104#define REG_MODE_SELECT 0x0100 105#define REG_OP_SYS_CLK_DIV 0x030A 106#define REG_VT_SYS_CLK_DIV 0x0302 107#define REG_PRE_PLL_CLK_DIV 0x0304 108#define REG_VT_PIX_CLK_DIV 0x0300 109#define REG_OP_PIX_CLK_DIV 0x0308 110#define REG_PLL_MULTIPLIER 0x0306 111#define REG_COARSE_INTEGRATION_TIME_ 0x3012 112#define REG_FRAME_LENGTH_LINES 0x0340 113#define REG_FRAME_LENGTH_LINES_ 0x300A 114#define REG_GREEN1_GAIN 0x3056 115#define REG_GREEN2_GAIN 0x305C 116#define REG_GROUPED_PARAMETER_HOLD 0x0104 117#define REG_LINE_LENGTH_PCK_ 0x300C 118#define REG_MODE_SELECT 0x0100 119#define REG_PLL_MULTIPLIER 0x0306 120#define REG_READ_MODE 0x3040 121#define REG_BLUE_GAIN 0x3058 122#define REG_RED_GAIN 0x305A 123#define REG_RESET_REGISTER 0x301A 124#define REG_SCALE_M 0x0404 125#define REG_SCALING_MODE 0x0400 126#define REG_SOFTWARE_RESET 0x0103 127#define REG_X_ADDR_END 0x0348 128#define REG_X_ADDR_START 0x0344 129#define REG_X_ADDR_START 0x0344 130#define REG_X_OUTPUT_SIZE 0x034C 131#define REG_Y_ADDR_END 0x034A 132#define REG_Y_ADDR_START 0x0346 133#define REG_Y_OUTPUT_SIZE 0x034E 134 135 136/* specific webcam descriptor */ 137struct sd { 138 struct gspca_dev gspca_dev; /* !! must be the first item */ 139 /* How many bytes this frame */ 140 unsigned int this_f; 141 142 /* 143 Device has separate gains for each Bayer quadrant 144 V4L supports master gain which is referenced to G1/G2 and supplies 145 individual balance controls for R/B 146 */ 147 struct v4l2_ctrl *blue; 148 struct v4l2_ctrl *red; 149}; 150 151/* Used to simplify reg write error handling */ 152struct cmd { 153 u16 value; 154 u16 index; 155}; 156 157static const struct v4l2_pix_format vga_mode[] = { 158 {800, 600, 159 V4L2_PIX_FMT_SGRBG8, 160 V4L2_FIELD_NONE, 161 .bytesperline = 800, 162 .sizeimage = 800 * 600, 163 .colorspace = V4L2_COLORSPACE_SRGB}, 164 {1600, 1200, 165 V4L2_PIX_FMT_SGRBG8, 166 V4L2_FIELD_NONE, 167 .bytesperline = 1600, 168 .sizeimage = 1600 * 1200, 169 .colorspace = V4L2_COLORSPACE_SRGB}, 170 {3264, 2448, 171 V4L2_PIX_FMT_SGRBG8, 172 V4L2_FIELD_NONE, 173 .bytesperline = 3264, 174 .sizeimage = 3264 * 2448, 175 .colorspace = V4L2_COLORSPACE_SRGB}, 176}; 177 178/* 179 * As there's no known frame sync, the only way to keep synced is to try hard 180 * to never miss any packets 181 */ 182#if MAX_NURBS < 4 183#error "Not enough URBs in the gspca table" 184#endif 185 186static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc) 187{ 188 if (rc < 0) { 189 gspca_err(gspca_dev, "reply has error %d\n", rc); 190 return -EIO; 191 } 192 if (rc != 1) { 193 gspca_err(gspca_dev, "Bad reply size %d\n", rc); 194 return -EIO; 195 } 196 if (reply[0] != 0x08) { 197 gspca_err(gspca_dev, "Bad reply 0x%02x\n", (int)reply[0]); 198 return -EIO; 199 } 200 return 0; 201} 202 203static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 204{ 205 char *buff = gspca_dev->usb_buf; 206 int rc; 207 208 gspca_dbg(gspca_dev, D_USBO, 209 "reg_w bReq=0x0B, bReqT=0xC0, wVal=0x%04X, wInd=0x%04X\n\n", 210 value, index); 211 rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 212 0x0B, 0xC0, value, index, buff, 1, 500); 213 gspca_dbg(gspca_dev, D_USBO, "rc=%d, ret={0x%02x}\n", rc, (int)buff[0]); 214 if (rc < 0) { 215 gspca_err(gspca_dev, "Failed reg_w(0x0B, 0xC0, 0x%04X, 0x%04X) w/ rc %d\n", 216 value, index, rc); 217 gspca_dev->usb_err = rc; 218 return; 219 } 220 if (val_reply(gspca_dev, buff, rc)) { 221 gspca_err(gspca_dev, "Bad reply to reg_w(0x0B, 0xC0, 0x%04X, 0x%04X\n", 222 value, index); 223 gspca_dev->usb_err = -EIO; 224 } 225} 226 227static void reg_w_buf(struct gspca_dev *gspca_dev, 228 const struct cmd *p, int l) 229{ 230 do { 231 reg_w(gspca_dev, p->value, p->index); 232 p++; 233 } while (--l > 0); 234} 235 236static void setexposure(struct gspca_dev *gspca_dev, s32 val) 237{ 238 u16 value; 239 unsigned int w = gspca_dev->pixfmt.width; 240 241 if (w == 800) 242 value = val * 5; 243 else if (w == 1600) 244 value = val * 3; 245 else if (w == 3264) 246 value = val * 3 / 2; 247 else { 248 gspca_err(gspca_dev, "Invalid width %u\n", w); 249 gspca_dev->usb_err = -EINVAL; 250 return; 251 } 252 gspca_dbg(gspca_dev, D_STREAM, "exposure: 0x%04X ms\n\n", value); 253 /* Wonder if there's a good reason for sending it twice */ 254 /* probably not but leave it in because...why not */ 255 reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); 256 reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); 257} 258 259static int gainify(int in) 260{ 261 /* 262 * TODO: check if there are any issues with corner cases 263 * 0x000 (0):0x07F (127): regL 264 * 0x080 (128) - 0x0FF (255): regM, regL 265 * 0x100 (256) - max: regH, regM, regL 266 */ 267 if (in <= 0x7F) 268 return 0x1000 | in; 269 else if (in <= 0xFF) 270 return 0x1080 | in / 2; 271 else 272 return 0x1180 | in / 4; 273} 274 275static void setggain(struct gspca_dev *gspca_dev, u16 global_gain) 276{ 277 u16 normalized; 278 279 normalized = gainify(global_gain); 280 gspca_dbg(gspca_dev, D_STREAM, "gain G1/G2 (0x%04X): 0x%04X (src 0x%04X)\n\n", 281 REG_GREEN1_GAIN, 282 normalized, global_gain); 283 284 reg_w(gspca_dev, normalized, REG_GREEN1_GAIN); 285 reg_w(gspca_dev, normalized, REG_GREEN2_GAIN); 286} 287 288static void setbgain(struct gspca_dev *gspca_dev, 289 u16 gain, u16 global_gain) 290{ 291 u16 normalized; 292 293 normalized = global_gain + 294 ((u32)global_gain) * gain / GAIN_MAX; 295 if (normalized > GAIN_MAX) { 296 gspca_dbg(gspca_dev, D_STREAM, "Truncating blue 0x%04X w/ value 0x%04X\n\n", 297 GAIN_MAX, normalized); 298 normalized = GAIN_MAX; 299 } 300 normalized = gainify(normalized); 301 gspca_dbg(gspca_dev, D_STREAM, "gain B (0x%04X): 0x%04X w/ source 0x%04X\n\n", 302 REG_BLUE_GAIN, normalized, gain); 303 304 reg_w(gspca_dev, normalized, REG_BLUE_GAIN); 305} 306 307static void setrgain(struct gspca_dev *gspca_dev, 308 u16 gain, u16 global_gain) 309{ 310 u16 normalized; 311 312 normalized = global_gain + 313 ((u32)global_gain) * gain / GAIN_MAX; 314 if (normalized > GAIN_MAX) { 315 gspca_dbg(gspca_dev, D_STREAM, "Truncating gain 0x%04X w/ value 0x%04X\n\n", 316 GAIN_MAX, normalized); 317 normalized = GAIN_MAX; 318 } 319 normalized = gainify(normalized); 320 gspca_dbg(gspca_dev, D_STREAM, "gain R (0x%04X): 0x%04X w / source 0x%04X\n\n", 321 REG_RED_GAIN, normalized, gain); 322 323 reg_w(gspca_dev, normalized, REG_RED_GAIN); 324} 325 326static void configure_wh(struct gspca_dev *gspca_dev) 327{ 328 unsigned int w = gspca_dev->pixfmt.width; 329 330 gspca_dbg(gspca_dev, D_STREAM, "configure_wh\n\n"); 331 332 if (w == 800) { 333 static const struct cmd reg_init_res[] = { 334 {0x0060, REG_X_ADDR_START}, 335 {0x0CD9, REG_X_ADDR_END}, 336 {0x0036, REG_Y_ADDR_START}, 337 {0x098F, REG_Y_ADDR_END}, 338 {0x07C7, REG_READ_MODE}, 339 }; 340 341 reg_w_buf(gspca_dev, 342 reg_init_res, ARRAY_SIZE(reg_init_res)); 343 } else if (w == 1600) { 344 static const struct cmd reg_init_res[] = { 345 {0x009C, REG_X_ADDR_START}, 346 {0x0D19, REG_X_ADDR_END}, 347 {0x0068, REG_Y_ADDR_START}, 348 {0x09C5, REG_Y_ADDR_END}, 349 {0x06C3, REG_READ_MODE}, 350 }; 351 352 reg_w_buf(gspca_dev, 353 reg_init_res, ARRAY_SIZE(reg_init_res)); 354 } else if (w == 3264) { 355 static const struct cmd reg_init_res[] = { 356 {0x00E8, REG_X_ADDR_START}, 357 {0x0DA7, REG_X_ADDR_END}, 358 {0x009E, REG_Y_ADDR_START}, 359 {0x0A2D, REG_Y_ADDR_END}, 360 {0x0241, REG_READ_MODE}, 361 }; 362 363 reg_w_buf(gspca_dev, 364 reg_init_res, ARRAY_SIZE(reg_init_res)); 365 } else { 366 gspca_err(gspca_dev, "bad width %u\n", w); 367 gspca_dev->usb_err = -EINVAL; 368 return; 369 } 370 371 reg_w(gspca_dev, 0x0000, REG_SCALING_MODE); 372 reg_w(gspca_dev, 0x0010, REG_SCALE_M); 373 reg_w(gspca_dev, w, REG_X_OUTPUT_SIZE); 374 reg_w(gspca_dev, gspca_dev->pixfmt.height, REG_Y_OUTPUT_SIZE); 375 376 if (w == 800) { 377 reg_w(gspca_dev, 0x0384, REG_FRAME_LENGTH_LINES_); 378 reg_w(gspca_dev, 0x0960, REG_LINE_LENGTH_PCK_); 379 } else if (w == 1600) { 380 reg_w(gspca_dev, 0x0640, REG_FRAME_LENGTH_LINES_); 381 reg_w(gspca_dev, 0x0FA0, REG_LINE_LENGTH_PCK_); 382 } else if (w == 3264) { 383 reg_w(gspca_dev, 0x0B4B, REG_FRAME_LENGTH_LINES_); 384 reg_w(gspca_dev, 0x1F40, REG_LINE_LENGTH_PCK_); 385 } else { 386 gspca_err(gspca_dev, "bad width %u\n", w); 387 gspca_dev->usb_err = -EINVAL; 388 return; 389 } 390} 391 392/* Packets that were encrypted, no idea if the grouping is significant */ 393static void configure_encrypted(struct gspca_dev *gspca_dev) 394{ 395 static const struct cmd reg_init_begin[] = { 396 {0x0100, REG_SOFTWARE_RESET}, 397 {0x0000, REG_MODE_SELECT}, 398 {0x0100, REG_GROUPED_PARAMETER_HOLD}, 399 {0x0004, REG_VT_PIX_CLK_DIV}, 400 {0x0001, REG_VT_SYS_CLK_DIV}, 401 {0x0008, REG_OP_PIX_CLK_DIV}, 402 {0x0001, REG_OP_SYS_CLK_DIV}, 403 {0x0004, REG_PRE_PLL_CLK_DIV}, 404 {0x0040, REG_PLL_MULTIPLIER}, 405 {0x0000, REG_GROUPED_PARAMETER_HOLD}, 406 {0x0100, REG_GROUPED_PARAMETER_HOLD}, 407 }; 408 static const struct cmd reg_init_end[] = { 409 {0x0000, REG_GROUPED_PARAMETER_HOLD}, 410 {0x0301, 0x31AE}, 411 {0x0805, 0x3064}, 412 {0x0071, 0x3170}, 413 {0x10DE, REG_RESET_REGISTER}, 414 {0x0000, REG_MODE_SELECT}, 415 {0x0010, REG_PLL_MULTIPLIER}, 416 {0x0100, REG_MODE_SELECT}, 417 }; 418 419 gspca_dbg(gspca_dev, D_STREAM, "Encrypted begin, w = %u\n\n", 420 gspca_dev->pixfmt.width); 421 reg_w_buf(gspca_dev, reg_init_begin, ARRAY_SIZE(reg_init_begin)); 422 configure_wh(gspca_dev); 423 reg_w_buf(gspca_dev, reg_init_end, ARRAY_SIZE(reg_init_end)); 424 reg_w(gspca_dev, 0x0100, REG_GROUPED_PARAMETER_HOLD); 425 reg_w(gspca_dev, 0x0000, REG_GROUPED_PARAMETER_HOLD); 426 427 gspca_dbg(gspca_dev, D_STREAM, "Encrypted end\n\n"); 428} 429 430static int configure(struct gspca_dev *gspca_dev) 431{ 432 int rc; 433 char *buff = gspca_dev->usb_buf; 434 435 gspca_dbg(gspca_dev, D_STREAM, "configure()\n\n"); 436 437 /* 438 * First driver sets a sort of encryption key 439 * A number of futur requests of this type have wValue and wIndex 440 * encrypted as follows: 441 * -Compute key = this wValue rotate left by 4 bits 442 * (decrypt.py rotates right because we are decrypting) 443 * -Later packets encrypt packets by XOR'ing with key 444 * XOR encrypt/decrypt is symmetrical 445 * wValue, and wIndex are encrypted 446 * bRequest is not and bRequestType is always 0xC0 447 * This allows resyncing if key is unknown? 448 * By setting 0 we XOR with 0 and the shifting and XOR drops out 449 */ 450 rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 451 0x16, 0xC0, 0x0000, 0x0000, buff, 2, 500); 452 if (val_reply(gspca_dev, buff, rc)) { 453 gspca_err(gspca_dev, "failed key req\n"); 454 return -EIO; 455 } 456 457 /* 458 * Next does some sort of 2 packet challenge / response 459 * evidence suggests its an Atmel I2C crypto part but nobody cares to 460 * look 461 * (to make sure its not cloned hardware?) 462 * Ignore: I want to work with their hardware, not clone it 463 * 16 bytes out challenge, requestType: 0x40 464 * 16 bytes in response, requestType: 0xC0 465 */ 466 467 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 468 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500); 469 if (rc < 0) { 470 gspca_err(gspca_dev, "failed to replay packet 176 w/ rc %d\n", 471 rc); 472 return rc; 473 } 474 475 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 476 0x01, 0x40, 0x0000, 0x000F, NULL, 0, 500); 477 if (rc < 0) { 478 gspca_err(gspca_dev, "failed to replay packet 178 w/ rc %d\n", 479 rc); 480 return rc; 481 } 482 483 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 484 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500); 485 if (rc < 0) { 486 gspca_err(gspca_dev, "failed to replay packet 180 w/ rc %d\n", 487 rc); 488 return rc; 489 } 490 491 /* 492 * Serial number? Doesn't seem to be required 493 * cam1: \xE6\x0D\x00\x00, cam2: \x70\x19\x00\x00 494 * rc = usb_control_msg(gspca_dev->dev, 495 * usb_rcvctrlpipe(gspca_dev->dev, 0), 496 * 0x20, 0xC0, 0x0000, 0x0000, buff, 4, 500); 497 */ 498 499 /* Large (EEPROM?) read, skip it since no idea what to do with it */ 500 gspca_dev->usb_err = 0; 501 configure_encrypted(gspca_dev); 502 if (gspca_dev->usb_err) 503 return gspca_dev->usb_err; 504 505 /* Omitted this by accident, does not work without it */ 506 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 507 0x01, 0x40, 0x0003, 0x000F, NULL, 0, 500); 508 if (rc < 0) { 509 gspca_err(gspca_dev, "failed to replay final packet w/ rc %d\n", 510 rc); 511 return rc; 512 } 513 514 gspca_dbg(gspca_dev, D_STREAM, "Configure complete\n\n"); 515 return 0; 516} 517 518static int sd_config(struct gspca_dev *gspca_dev, 519 const struct usb_device_id *id) 520{ 521 gspca_dev->cam.cam_mode = vga_mode; 522 gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); 523 524 /* Yes we want URBs and we want them now! */ 525 gspca_dev->cam.no_urb_create = 0; 526 gspca_dev->cam.bulk_nurbs = 4; 527 /* Largest size the windows driver uses */ 528 gspca_dev->cam.bulk_size = BULK_SIZE; 529 /* Def need to use bulk transfers */ 530 gspca_dev->cam.bulk = 1; 531 532 return 0; 533} 534 535static int sd_start(struct gspca_dev *gspca_dev) 536{ 537 struct sd *sd = (struct sd *) gspca_dev; 538 int rc; 539 540 sd->this_f = 0; 541 542 rc = configure(gspca_dev); 543 if (rc < 0) { 544 gspca_err(gspca_dev, "Failed configure\n"); 545 return rc; 546 } 547 /* First two frames have messed up gains 548 Drop them to avoid special cases in user apps? */ 549 return 0; 550} 551 552static void sd_pkt_scan(struct gspca_dev *gspca_dev, 553 u8 *data, /* isoc packet */ 554 int len) /* iso packet length */ 555{ 556 struct sd *sd = (struct sd *) gspca_dev; 557 558 if (len != BULK_SIZE) { 559 /* can we finish a frame? */ 560 if (sd->this_f + len == gspca_dev->pixfmt.sizeimage) { 561 gspca_frame_add(gspca_dev, LAST_PACKET, data, len); 562 gspca_dbg(gspca_dev, D_FRAM, "finish frame sz %u/%u w/ len %u\n\n", 563 sd->this_f, gspca_dev->pixfmt.sizeimage, len); 564 /* lost some data, discard the frame */ 565 } else { 566 gspca_frame_add(gspca_dev, DISCARD_PACKET, NULL, 0); 567 gspca_dbg(gspca_dev, D_FRAM, "abort frame sz %u/%u w/ len %u\n\n", 568 sd->this_f, gspca_dev->pixfmt.sizeimage, len); 569 } 570 sd->this_f = 0; 571 } else { 572 if (sd->this_f == 0) 573 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); 574 else 575 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 576 sd->this_f += len; 577 } 578} 579 580static int sd_init(struct gspca_dev *gspca_dev) 581{ 582 return 0; 583} 584 585static int sd_s_ctrl(struct v4l2_ctrl *ctrl) 586{ 587 struct gspca_dev *gspca_dev = 588 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 589 struct sd *sd = (struct sd *) gspca_dev; 590 591 gspca_dev->usb_err = 0; 592 593 if (!gspca_dev->streaming) 594 return 0; 595 596 switch (ctrl->id) { 597 case V4L2_CID_EXPOSURE: 598 setexposure(gspca_dev, ctrl->val); 599 break; 600 case V4L2_CID_GAIN: 601 /* gspca_dev->gain automatically updated */ 602 setggain(gspca_dev, gspca_dev->gain->val); 603 break; 604 case V4L2_CID_BLUE_BALANCE: 605 sd->blue->val = ctrl->val; 606 setbgain(gspca_dev, sd->blue->val, gspca_dev->gain->val); 607 break; 608 case V4L2_CID_RED_BALANCE: 609 sd->red->val = ctrl->val; 610 setrgain(gspca_dev, sd->red->val, gspca_dev->gain->val); 611 break; 612 } 613 return gspca_dev->usb_err; 614} 615 616static const struct v4l2_ctrl_ops sd_ctrl_ops = { 617 .s_ctrl = sd_s_ctrl, 618}; 619 620static int sd_init_controls(struct gspca_dev *gspca_dev) 621{ 622 struct sd *sd = (struct sd *) gspca_dev; 623 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 624 625 gspca_dev->vdev.ctrl_handler = hdl; 626 v4l2_ctrl_handler_init(hdl, 4); 627 628 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 629 /* Mostly limited by URB timeouts */ 630 /* XXX: make dynamic based on frame rate? */ 631 V4L2_CID_EXPOSURE, 0, 800, 1, 350); 632 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 633 V4L2_CID_GAIN, 0, 511, 1, 128); 634 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 635 V4L2_CID_BLUE_BALANCE, 0, 1023, 1, 80); 636 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 637 V4L2_CID_RED_BALANCE, 0, 1023, 1, 295); 638 639 if (hdl->error) { 640 gspca_err(gspca_dev, "Could not initialize controls\n"); 641 return hdl->error; 642 } 643 return 0; 644} 645 646/* sub-driver description */ 647static const struct sd_desc sd_desc = { 648 .name = MODULE_NAME, 649 .config = sd_config, 650 .init = sd_init, 651 .init_controls = sd_init_controls, 652 .start = sd_start, 653 .pkt_scan = sd_pkt_scan, 654}; 655 656/* Table of supported USB devices */ 657static const struct usb_device_id device_table[] = { 658 /* Commented out devices should be related */ 659 /* AS: AmScope, TT: ToupTek */ 660 /* { USB_DEVICE(0x0547, 0x6035) }, TT UCMOS00350KPA */ 661 /* { USB_DEVICE(0x0547, 0x6130) }, TT UCMOS01300KPA */ 662 /* { USB_DEVICE(0x0547, 0x6200) }, TT UCMOS02000KPA */ 663 /* { USB_DEVICE(0x0547, 0x6310) }, TT UCMOS03100KPA */ 664 /* { USB_DEVICE(0x0547, 0x6510) }, TT UCMOS05100KPA */ 665 /* { USB_DEVICE(0x0547, 0x6800) }, TT UCMOS08000KPA */ 666 /* { USB_DEVICE(0x0547, 0x6801) }, TT UCMOS08000KPB */ 667 { USB_DEVICE(0x0547, 0x6801) }, /* TT UCMOS08000KPB, AS MU800 */ 668 /* { USB_DEVICE(0x0547, 0x6900) }, TT UCMOS09000KPA */ 669 /* { USB_DEVICE(0x0547, 0x6901) }, TT UCMOS09000KPB */ 670 /* { USB_DEVICE(0x0547, 0x6010) }, TT UCMOS10000KPA */ 671 /* { USB_DEVICE(0x0547, 0x6014) }, TT UCMOS14000KPA */ 672 /* { USB_DEVICE(0x0547, 0x6131) }, TT UCMOS01300KMA */ 673 /* { USB_DEVICE(0x0547, 0x6511) }, TT UCMOS05100KMA */ 674 /* { USB_DEVICE(0x0547, 0x8080) }, TT UHCCD00800KPA */ 675 /* { USB_DEVICE(0x0547, 0x8140) }, TT UHCCD01400KPA */ 676 /* { USB_DEVICE(0x0547, 0x8141) }, TT EXCCD01400KPA */ 677 /* { USB_DEVICE(0x0547, 0x8200) }, TT UHCCD02000KPA */ 678 /* { USB_DEVICE(0x0547, 0x8201) }, TT UHCCD02000KPB */ 679 /* { USB_DEVICE(0x0547, 0x8310) }, TT UHCCD03100KPA */ 680 /* { USB_DEVICE(0x0547, 0x8500) }, TT UHCCD05000KPA */ 681 /* { USB_DEVICE(0x0547, 0x8510) }, TT UHCCD05100KPA */ 682 /* { USB_DEVICE(0x0547, 0x8600) }, TT UHCCD06000KPA */ 683 /* { USB_DEVICE(0x0547, 0x8800) }, TT UHCCD08000KPA */ 684 /* { USB_DEVICE(0x0547, 0x8315) }, TT UHCCD03150KPA */ 685 /* { USB_DEVICE(0x0547, 0x7800) }, TT UHCCD00800KMA */ 686 /* { USB_DEVICE(0x0547, 0x7140) }, TT UHCCD01400KMA */ 687 /* { USB_DEVICE(0x0547, 0x7141) }, TT UHCCD01400KMB */ 688 /* { USB_DEVICE(0x0547, 0x7200) }, TT UHCCD02000KMA */ 689 /* { USB_DEVICE(0x0547, 0x7315) }, TT UHCCD03150KMA */ 690 { } 691}; 692MODULE_DEVICE_TABLE(usb, device_table); 693 694static int sd_probe(struct usb_interface *intf, 695 const struct usb_device_id *id) 696{ 697 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 698 THIS_MODULE); 699} 700 701static struct usb_driver sd_driver = { 702 .name = MODULE_NAME, 703 .id_table = device_table, 704 .probe = sd_probe, 705 .disconnect = gspca_disconnect, 706#ifdef CONFIG_PM 707 .suspend = gspca_suspend, 708 .resume = gspca_resume, 709#endif 710}; 711 712static int __init sd_mod_init(void) 713{ 714 int ret; 715 716 ret = usb_register(&sd_driver); 717 if (ret < 0) 718 return ret; 719 return 0; 720} 721static void __exit sd_mod_exit(void) 722{ 723 usb_deregister(&sd_driver); 724} 725 726module_init(sd_mod_init); 727module_exit(sd_mod_exit);