r5u870.c (78268B)
1 /* 2 * Driver for Ricoh R5U870-based Custom OEM Webcams 3 * Copyright (c) 2007 Sam Revitch <samr7@cs.washington.edu> 4 * Copyright (c) 2008 Alexander Hixon <hixon.alexander@mediati.org> 5 * 6 * Check out README for additional credits. 7 * Version 0.11.2 8 * 9 * This driver is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This driver is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this driver; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 /* 25 * This driver supports certain custom OEM webcams based on the Ricoh 26 * R5U870 / Micro Vision M25U870 controller chip. These tend to be 27 * built in to certain models of laptop computers and claim USB vendor 28 * ID 0x05CA (Ricoh). 29 * 30 * All Ricoh webcams support common microcode upload, reset, and query 31 * version commands. 32 * 33 * Each distinct piece of hardware requires a different microcode blob, 34 * which is uploaded to the device the first time the device is probed 35 * after power-on. The microcode blob is tailored to the attached 36 * image sensor and the desired type of USB interface. Some microcode 37 * blobs are created to work with the Ricoh proprietary USB interface. 38 * Others behave as UVC devices, but use the common Ricoh vendor 39 * commands to set certain controls. Some devices, in particular the 40 * 1810 and 1870 HP Pavilion Webcam devices, appear to be identical in 41 * hardware, and differ only by USB descriptor tables, and the 42 * microcode blobs implement the different USB personalities. 43 * 44 * This driver supports basic UVC descriptor table parsing to determine 45 * available controls and resolutions, and enough UVC commands to 46 * support the UVC interface style of the Ricoh webcams. 47 */ 48 49 #define USBCAM_DEBUG_DEFAULT 0 50 51 #include <linux/kernel.h> 52 #include <linux/module.h> 53 #include <linux/init.h> 54 #include <linux/usb.h> 55 #include <linux/firmware.h> 56 #include <linux/dmi.h> 57 #include <linux/ctype.h> 58 59 #include "usbcam/usbcam.h" 60 61 62 #define USBCAM_DBG_R5U_INIT (USBCAM_DBGBIT_MD_START + 0) 63 #define USBCAM_DBG_R5U_FRAME (USBCAM_DBGBIT_MD_START + 1) 64 #define USBCAM_DBG_R5U_MDINTF (USBCAM_DBGBIT_MD_START + 2) 65 #define USBCAM_DBG_R5U_CTRL (USBCAM_DBGBIT_MD_START + 3) 66 67 68 #define r5u_info(RV, FMT...) usbcam_info((RV)->vh_parent, FMT) 69 #define r5u_err(RV, FMT...) usbcam_err((RV)->vh_parent, FMT) 70 #define r5u_dbg(RV, SUBSYS, FMT...) usbcam_dbg((RV)->vh_parent, SUBSYS, FMT) 71 72 #define R5U870_VERSION KERNEL_VERSION(0,11,2) 73 #define R5U870_VERSION_EXTRA "" 74 75 76 struct r5u870_resolution { 77 int rw_width; 78 int rw_height; 79 int rw_reqbw; 80 int rw_interval; 81 int rw_frameidx; 82 }; 83 84 struct r5u870_pix_fmt { 85 struct usbcam_pix_fmt base; 86 int rp_formatidx; 87 const struct r5u870_resolution *rp_restbl; 88 int rp_restbl_alloc; 89 }; 90 91 struct r5u870_ctrl { 92 struct usbcam_ctrl base; 93 int reg; 94 u8 unit; 95 u8 info; 96 u8 size; 97 u8 is_auto; 98 int auto_offset; 99 int val_offset; 100 int value; 101 }; 102 103 struct r5u870_model { 104 char *rm_name; 105 const char *rm_ucode_file; 106 const struct r5u870_resolution *rm_res; 107 const int *rm_wdm_ctrlids; 108 const struct r5u870_pix_fmt *rm_pixfmts; 109 int rm_npixfmts; 110 u16 rm_ucode_version; 111 unsigned int rm_uvc : 1, 112 rm_no_ctrl_reload : 1, 113 rm_no_first_auto_suppress : 1; 114 }; 115 116 struct r5u870_ctx { 117 struct usbcam_dev *vh_parent; 118 struct usbcam_urbstream vh_iso; 119 120 const struct r5u870_model *vh_model; 121 const struct r5u870_pix_fmt *vh_pixfmts; 122 int vh_npixfmts; 123 124 int vh_dyn_pixfmts : 1, 125 vh_configured : 1, 126 vh_ctrl_reg_enable : 1, 127 vh_ctrl_sync : 1, 128 vh_ctrl_auto_suppress : 1; 129 130 const struct r5u870_pix_fmt *vh_fmt; 131 const struct r5u870_resolution *vh_res; 132 133 int vh_timeout; 134 int vh_firstframe; 135 int vh_emptypkts; 136 int vh_frame_accum; 137 138 int vh_framebuf_offset; 139 140 int vh_ctrl_ifnum; 141 int vh_iso_ep; 142 int vh_iso_ifnum; 143 int vh_iso_minpacket; 144 int vh_act_altsetting; 145 146 int (*vh_set_fmt)(struct r5u870_ctx *, 147 const struct r5u870_pix_fmt *fmtp, 148 const struct r5u870_resolution *resp); 149 int (*vh_cap_stop)(struct r5u870_ctx *); 150 int (*vh_decide_pkt)(struct r5u870_ctx *, int st, int len, 151 const u8 *pktdata, int *start); 152 153 /* Auto settings */ 154 int vh_auto_wb; 155 int vh_aec; 156 int vh_agc; 157 }; 158 159 #define udp_r5u870(UDP) ((struct r5u870_ctx *)((UDP)->ud_minidrv_data)) 160 #define r5u870_dev(RV) ((RV)->vh_parent->ud_dev) 161 162 /* 163 * USB control message with kmalloc'd buffer helper 164 */ 165 166 static int r5u870_control_msg(struct r5u870_ctx *vhp, int write, int class, 167 u8 request, u16 value, u16 index, void *data, 168 u16 size) 169 { 170 char *dbuf = NULL; 171 int res; 172 173 if (size) { 174 dbuf = kmalloc(size, GFP_KERNEL); 175 if (!dbuf) 176 return -ENOMEM; 177 if (write) 178 memcpy(dbuf, data, size); 179 } 180 181 res = usb_control_msg(r5u870_dev(vhp), 182 write 183 ? usb_sndctrlpipe(r5u870_dev(vhp), 0) 184 : usb_rcvctrlpipe(r5u870_dev(vhp), 0), 185 request, 186 (write ? USB_DIR_OUT : USB_DIR_IN) | 187 (class 188 ? (USB_TYPE_CLASS | USB_RECIP_INTERFACE) 189 : (USB_TYPE_VENDOR | USB_RECIP_DEVICE)), 190 value, index, dbuf, size, 191 vhp->vh_timeout); 192 193 if (dbuf) { 194 if (!write) 195 memcpy(data, dbuf, size); 196 kfree(dbuf); 197 } 198 return res; 199 } 200 201 202 /* 203 * Controls 204 * 205 * For this driver, there is only one get function, which retrieves the 206 * value for the control stored in the r5u870_ctx structure. Each style 207 * of control -- WDM/UVC -- have separate set functions. 208 * 209 * There are query functions for setting the disabled flag on manual 210 * white balance controls when auto white balance is enabled. 211 */ 212 213 enum { 214 V4L2_CID_R5U870_SHARPNESS = (V4L2_CID_PRIVATE_BASE + 0), 215 V4L2_CID_R5U870_GREEN_BALANCE, 216 V4L2_CID_R5U870_AUTOEXPOSURE, 217 V4L2_CID_R5U870_POWERLINE, 218 V4L2_CID_R5U870_BACKLIGHT, 219 V4L2_CID_R5U870_PRIVACY, 220 V4L2_CID_R5U870_NIGHT_MODE, 221 }; 222 223 static int r5u870_get_ctrl(struct usbcam_dev *udp, 224 const struct usbcam_ctrl *basep, 225 struct v4l2_ext_control *c) 226 { 227 struct r5u870_ctrl *ctrlp = container_of(basep, struct r5u870_ctrl, 228 base); 229 c->value = ctrlp->value; 230 return 0; 231 } 232 233 static int r5u870_query_ctrl(struct usbcam_dev *udp, 234 const struct usbcam_ctrl *basep, 235 struct v4l2_queryctrl *c) 236 { 237 struct r5u870_ctx *vhp = udp_r5u870(udp); 238 struct r5u870_ctrl *ctrlp = container_of(basep, struct r5u870_ctrl, 239 base); 240 int auto_ctrl = 0; 241 242 if (ctrlp->auto_offset) { 243 auto_ctrl = *(int *) (((char *) vhp) + ctrlp->auto_offset); 244 if (auto_ctrl) 245 c->flags |= V4L2_CTRL_FLAG_INACTIVE; 246 } 247 return 0; 248 } 249 250 static int r5u870_set_controls(struct r5u870_ctx *vhp, int dflt) 251 { 252 const struct r5u870_ctrl *ctrlp; 253 struct v4l2_ext_control cv; 254 int res; 255 256 res = 0; 257 list_for_each_entry(ctrlp, &vhp->vh_parent->ud_ctrl_list, 258 base.uc_links) { 259 cv.id = ctrlp->base.uc_v4l.id; 260 261 if (dflt) 262 cv.value = ctrlp->base.uc_v4l.default_value; 263 else 264 cv.value = ctrlp->value; 265 266 res = ctrlp->base.set_fn(vhp->vh_parent, 267 &ctrlp->base, 268 &cv); 269 if (res) 270 break; 271 } 272 273 if (vhp->vh_ctrl_reg_enable && 274 !vhp->vh_ctrl_auto_suppress && 275 vhp->vh_model->rm_no_first_auto_suppress) 276 vhp->vh_ctrl_auto_suppress = 1; 277 278 return res; 279 } 280 281 282 /* 283 * Microcode management and device initialization functions follow 284 */ 285 286 static int r5u870_set_gen_reg(struct r5u870_ctx *vhp, 287 int cmd, int reg, int val) 288 { 289 int res; 290 res = r5u870_control_msg(vhp, 1, 0, cmd, val, reg, NULL, 0); 291 if (res < 0) { 292 r5u_err(vhp, "set_gen_reg %04x/%04x/%04x failed: %d", 293 cmd, reg, val, res); 294 // XXX: Only commented for debugging. UNCOMMENT BEFORE RELEASE! 295 //return res; 296 } 297 return 0; 298 } 299 300 /* 301 * Send the power-up init sequence, in case it is needed. 302 */ 303 static int r5u870_microcode_upload(struct r5u870_ctx *vhp) 304 { 305 const struct firmware *fws; 306 char *pgbuf; 307 const u8 *dptr; 308 int tolerance = 3; 309 int i, rem, addr, len, res = 0; 310 311 pgbuf = (char *) kmalloc(64, GFP_KERNEL); 312 if (!pgbuf) 313 return -ENOMEM; 314 315 r5u_dbg(vhp, R5U_INIT, "loading microcode file \"%s\"", 316 vhp->vh_model->rm_ucode_file); 317 318 res = request_firmware(&fws, 319 vhp->vh_model->rm_ucode_file, 320 &vhp->vh_parent->ud_dev->dev); 321 322 if (res) { 323 r5u_err(vhp, "Microcode file \"%s\" is missing", 324 vhp->vh_model->rm_ucode_file); 325 r5u_err(vhp, "Please see http://wiki.mediati.org/r5u870/Microcode"); 326 kfree(pgbuf); 327 return res; 328 } 329 330 i = 0; 331 dptr = fws->data; 332 rem = fws->size; 333 while (rem) { 334 if (rem < 3) { 335 r5u_err(vhp, "Microcode file msg %d is incomplete", i); 336 res = -EINVAL; 337 break; 338 } 339 340 len = dptr[0]; 341 addr = dptr[1] | (dptr[2] << 8); 342 dptr += 3; 343 rem -= 3; 344 345 if ((rem < len) || (len > 64)) { 346 r5u_err(vhp, "Microcode file msg %d has bad length %d", 347 i, len); 348 res = -EINVAL; 349 break; 350 } 351 352 /* 353 * The USB stack has issues with the initseq data if 354 * initseq points into the vmalloc arena. This is 355 * the case for microcode embedded in a module, or 356 * data loaded by request_firmware(). 357 * 358 * As a workaround, we memcpy() into a kmalloc page. 359 */ 360 memcpy(pgbuf, dptr, len); 361 dptr += len; 362 rem -= len; 363 364 retry: 365 /* TODO: Maybe make this use r5u870_control_msg or similar? */ 366 res = usb_control_msg(r5u870_dev(vhp), 367 usb_sndctrlpipe(r5u870_dev(vhp), 0), 368 0xa0, 369 USB_DIR_OUT | USB_TYPE_VENDOR | 370 USB_RECIP_DEVICE, 371 addr, 0, pgbuf, len, vhp->vh_timeout); 372 373 if (res < 0) { 374 if (tolerance--) 375 goto retry; 376 r5u_err(vhp, "command a0[%d] failed: %d", 377 i, res); 378 break; 379 } 380 if (res != len) { 381 r5u_err(vhp, "command a0[%d] failed: %d (exp %d)", 382 i, res, len); 383 res = -EIO; 384 break; 385 } 386 387 i++; 388 } 389 390 release_firmware(fws); 391 kfree(pgbuf); 392 return res; 393 } 394 395 static int r5u870_microcode_get_state(struct r5u870_ctx *vhp) 396 { 397 char buf[1]; 398 int res; 399 r5u_dbg(vhp, R5U_INIT, "requesting microcode state"); 400 res = r5u870_control_msg(vhp, 0, 0, 0xa4, 0, 0, buf, 1); 401 if ((res != 1) || ((buf[0] != 0) && (buf[0] != 1))) { 402 r5u_err(vhp, "command 0xa4 failed: %d", res); 403 return res < 0 ? res : -EIO; 404 } 405 406 r5u_dbg(vhp, R5U_INIT, "camera reports %s microcode state", 407 buf[0] ? "positive" : "negative"); 408 409 return (buf[0] == 0) ? -ENOENT : 0; 410 } 411 412 static int r5u870_microcode_get_ver(struct r5u870_ctx *vhp, int *verp) 413 { 414 char buf[2]; 415 int res; 416 417 r5u_dbg(vhp, R5U_INIT, "requesting microcode version"); 418 res = r5u870_control_msg(vhp, 0, 0, 0xc3, 0, 0x0e, buf, 2); 419 if (res != 2) { 420 r5u_err(vhp, "command 0xa3 failed: %d", res); 421 return res < 0 ? res : -EIO; 422 } 423 424 res = le16_to_cpup((__le16 *) buf); 425 r5u_dbg(vhp, R5U_INIT, "camera reports version %04x", res); 426 *verp = res; 427 return 0; 428 } 429 430 static int r5u870_microcode_enable(struct r5u870_ctx *vhp) 431 { 432 char buf[1]; 433 int res; 434 435 r5u_dbg(vhp, R5U_INIT, "enabling microcode"); 436 buf[0] = 1; 437 res = r5u870_control_msg(vhp, 1, 0, 0xa1, 0, 0, buf, 1); 438 if (res != 1) { 439 r5u_err(vhp, "command 0xa1 failed: %d", res); 440 return res < 0 ? res : -EIO; 441 } 442 443 return 0; 444 } 445 446 static int r5u870_microcode_reset(struct r5u870_ctx *vhp) 447 { 448 int res; 449 r5u_dbg(vhp, R5U_INIT, "sending microcode reset command"); 450 msleep(100); /* The Windows driver waits 1sec */ 451 res = r5u870_set_gen_reg(vhp, 0xa6, 0, 0); 452 if (!res) 453 msleep(200); 454 return res; 455 } 456 457 /* 458 * Initialize the camera after it is detected. 459 */ 460 static int r5u870_dev_init(struct r5u870_ctx *vhp) 461 { 462 int mcver; 463 int res; 464 465 if (!vhp->vh_model->rm_ucode_file) 466 return 0; 467 468 res = r5u870_microcode_get_state(vhp); 469 if (res && (res != -ENOENT)) 470 return res; 471 472 if (!res) { 473 res = r5u870_microcode_get_ver(vhp, &mcver); 474 if (res) 475 return res; 476 477 if (mcver != vhp->vh_model->rm_ucode_version) { 478 res = r5u870_microcode_reset(vhp); 479 if (res) 480 return res; 481 res = -ENOENT; 482 } 483 } 484 485 486 if (res == -ENOENT) { 487 res = r5u870_microcode_upload(vhp); 488 if (res < 0) 489 return res; 490 491 res = r5u870_microcode_enable(vhp); 492 if (res) 493 return res; 494 495 res = r5u870_microcode_get_ver(vhp, &mcver); 496 if (res) 497 return res; 498 } 499 500 if (mcver != vhp->vh_model->rm_ucode_version) 501 r5u_err(vhp, "Unexpected microcode version " 502 "(exp:%04x got:%04x)", 503 vhp->vh_model->rm_ucode_version, mcver); 504 505 /* Halt capture in case it's running (broken driver?) */ 506 res = vhp->vh_cap_stop(vhp); 507 if (res < 0) 508 return res; 509 510 return 0; 511 } 512 513 /* 514 * WDM Device Registers are listed below. 515 * 516 * To set: use r5u870_set_reg_wdm(). 517 * 518 * No information is given about how to retrieve values from these 519 * registers. 520 * 521 * Note that some register IDs are overloaded. The Sony cam drivers 522 * seem to use 0x36 for backlight compensation and 0x37 for gain, 523 * whereas the HP drivers use 0x36 for color enable and 0x37 for frame 524 * rate. 525 */ 526 enum { 527 /* Brightness: [0,127] D:63 */ 528 R5U870_REG_BRIGHTNESS = 0x02, 529 530 /* Contrast: [0,127] D:63 */ 531 R5U870_REG_CONTRAST = 0x04, 532 533 /* Hue: [-180,180] D:0 (16-bit 2's complement) */ 534 R5U870_REG_HUE = 0x34, 535 536 /* Saturation: [0,127] D:63 */ 537 R5U870_REG_SATURATION = 0x05, 538 539 /* Sharpness: [0,127] D:63 */ 540 R5U870_REG_SHARPNESS = 0x03, 541 542 /* Gamma correction: [1,500] D:100 */ 543 R5U870_REG_GAMMA = 0x35, 544 545 /* Registers with unknown usage */ 546 R5U870_REG_COLOR_ENABLE = 0x36, 547 548 /* White balance: [0,127] D:63 */ 549 R5U870_REG_WHITE_BALANCE = 0x1, 550 551 /* Frame Rate: D:30 */ 552 R5U870_REG_FRAME_RATE = 0x37, 553 554 /* Registers with unknown usage */ 555 R5U870_REG_BRIGHTNESS_EX = 0x20, 556 R5U870_REG_CONTRAST_EX = 0x21, 557 R5U870_REG_HUE_EX = 0x22, 558 R5U870_REG_SATURATION_EX = 0x23, 559 R5U870_REG_SHARPNESS_EX = 0x24, 560 R5U870_REG_GAMMA_EX = 0x25, 561 562 /* White balance red value: [0,255] D:127 */ 563 R5U870_REG_WB_RED_EX = 0x26, 564 565 /* White balance green value: [0,255] D:127 */ 566 R5U870_REG_WB_GREEN_EX = 0x27, 567 568 /* White balance blue value: [0,255] D:127 */ 569 R5U870_REG_WB_BLUE_EX = 0x28, 570 571 /* Auto white balance: [0,1] D:1 */ 572 R5U870_REG_WB_AUTO_EX = 0x29, 573 574 /* Exposure Control: [0,255] D:255 */ 575 R5U870_REG_EXPOSURE_EX = 0x2a, 576 577 /* Auto Exposure Control: [0,1] D:1 */ 578 R5U870_REG_AEC_EX = 0x2b, 579 580 /* Gain: [0,127] D:63 */ 581 R5U870_REG_GAIN_EX = 0x2c, 582 583 /* Auto Gain: [0,1] D:0 */ 584 R5U870_REG_AGC_EX = 0x2d, 585 586 /* Light source flicker compensation: see R5U870_POWERLINE */ 587 R5U870_REG_POWERLINE_EX = 0x2e, 588 589 /* Registers with unknown usage */ 590 R5U870_REG_SCENE_EX = 0x2f, 591 592 /* Vertical flip: [0,1] D:0 */ 593 R5U870_REG_VFLIP_EX = 0x30, 594 595 /* Horizontal flip: [0,1] D:0 */ 596 R5U870_REG_HFLIP_EX = 0x31, 597 598 /* Blank image: [0,1] D:0 */ 599 R5U870_REG_PRIVACY_EX = 0x32, 600 601 /* Night mode: [0,1] D:0 */ 602 R5U870_REG_NIGHT_MODE_EX = 0x33, 603 604 /* Backlight compensation: [0,500] D:1 */ 605 R5U870_REG_BACKLIGHT_COMP = 0x36, 606 607 /* Registers with unknown usage */ 608 R5U870_REG_GAIN = 0x37, 609 610 /* Backlight compensation for 1834 device: [0,2] D:1 */ 611 R5U870_REG_BACKLIGHT_COMP_2 = 0x39, 612 613 614 /* Values for R5U870_REG_POWERLINE flicker compensation */ 615 R5U870_POWERLINE_OFF = 0, 616 R5U870_POWERLINE_50HZ = 1, 617 R5U870_POWERLINE_60HZ = 2, 618 619 /* Number of empty packets between frames */ 620 R5U870_EMPTYPKT_FRAME_DELIM = 10, 621 622 /* Number of empty packets before declaring the device dead (.5sec) */ 623 R5U870_EMPTYPKT_GIVE_UP = 4000, 624 }; 625 626 static int r5u870_set_reg_wdm(struct r5u870_ctx *vhp, int reg, int val) 627 { 628 return r5u870_set_gen_reg(vhp, 0xc2, reg, val); 629 } 630 631 /* 632 * Set the frame size and data format. 633 * Do not call this function with the isochronous stream active. 634 */ 635 static int r5u870_set_fmt_wdm(struct r5u870_ctx *vhp, 636 const struct r5u870_pix_fmt *fmtp, 637 const struct r5u870_resolution *resp) 638 { 639 int res; 640 641 msleep(1); 642 res = r5u870_set_gen_reg(vhp, 0xc5, 2, fmtp->rp_formatidx); 643 if (res) 644 return res; 645 msleep(1); 646 res = r5u870_set_gen_reg(vhp, 0xc5, 0, resp->rw_width); 647 if (res) 648 return res; 649 msleep(1); 650 res = r5u870_set_gen_reg(vhp, 0xc5, 1, resp->rw_height); 651 if (res) 652 return res; 653 msleep(5); 654 return 0; 655 } 656 657 658 /* 659 * Turn frame grabbing on or off (WDM). 660 * This will also turn on or off the LED. 661 */ 662 static int r5u870_set_cap_state_wdm(struct r5u870_ctx *vhp, int val) 663 { 664 return r5u870_set_gen_reg(vhp, 0xc4, val, 0); 665 } 666 667 static int r5u870_cap_stop_wdm(struct r5u870_ctx *vhp) 668 { 669 return r5u870_set_cap_state_wdm(vhp, 0); 670 } 671 672 /* 673 * r5u870_decide_pkt_wdm 674 * 675 * Based on the size of an isochronous data packet, this function 676 * decides whether to copy the packet into the frame buffer and possibly 677 * complete the frame, or to discard both the packet and the frame. 678 * 679 * Returns: 680 * 0 Frame is done 681 * -EAGAIN Append packet to frame, frame is not done 682 * -EPIPE Discard frame and packet 683 * -EIO The device is nonresponsive, abort 684 */ 685 static int r5u870_decide_pkt_wdm(struct r5u870_ctx *vhp, int pktstatus, 686 int pktlen, const u8 *pktdata, int *start) 687 { 688 int ret = -EAGAIN; 689 690 *start = 0; 691 692 if (pktstatus) { 693 /* Abort current frame */ 694 r5u_dbg(vhp, R5U_FRAME, "frame abort: packet status %d", 695 pktstatus); 696 vhp->vh_frame_accum = -1; 697 vhp->vh_emptypkts = 0; 698 ret = -EPIPE; 699 700 } else if (!pktlen) { 701 if (++vhp->vh_emptypkts == R5U870_EMPTYPKT_FRAME_DELIM) { 702 if (vhp->vh_frame_accum == -1) { 703 /* Frame was previously aborted */ 704 ret = -EPIPE; 705 } else if (vhp->vh_frame_accum == 706 vhp->vh_parent->ud_format.sizeimage) { 707 /* Complete frame */ 708 ret = 0; 709 } else { 710 /* Not enough data in frame sequence */ 711 r5u_dbg(vhp, R5U_FRAME, "frame abort: " 712 "Frame seq too short (exp:%d got:%d)", 713 vhp->vh_parent->ud_format.sizeimage, 714 vhp->vh_frame_accum); 715 ret = -EPIPE; 716 } 717 718 if (!vhp->vh_firstframe) { 719 /* Always reject the first frame */ 720 vhp->vh_firstframe = 1; 721 vhp->vh_frame_accum = -1; 722 ret = -EPIPE; 723 } else { 724 vhp->vh_frame_accum = 0; 725 } 726 } 727 728 else if (vhp->vh_emptypkts >= R5U870_EMPTYPKT_GIVE_UP) { 729 r5u_dbg(vhp, R5U_FRAME, "%d empty packets, giving up", 730 vhp->vh_emptypkts); 731 ret = -EIO; 732 } 733 734 } else { 735 vhp->vh_emptypkts = 0; 736 if (vhp->vh_frame_accum == -1) { 737 /* Frame was previously aborted */ 738 ret = -EPIPE; 739 } else if ((vhp->vh_frame_accum + pktlen) <= 740 vhp->vh_parent->ud_format.sizeimage) { 741 /* Append this data */ 742 vhp->vh_frame_accum += pktlen; 743 } else { 744 /* Oversized frame, abort */ 745 r5u_dbg(vhp, R5U_FRAME, "frame abort: " 746 "Frame seq too long"); 747 vhp->vh_frame_accum = -1; 748 ret = -EPIPE; 749 } 750 } 751 752 return ret; 753 } 754 755 static int r5u870_set_manual_ctrls_wdm(struct r5u870_ctx *vhp, int auto_offset) 756 { 757 const struct r5u870_ctrl *ctrlp; 758 int val, res; 759 760 res = 0; 761 list_for_each_entry(ctrlp, &vhp->vh_parent->ud_ctrl_list, 762 base.uc_links) { 763 if (ctrlp->auto_offset != auto_offset) 764 continue; 765 if (!vhp->vh_ctrl_reg_enable) { 766 vhp->vh_ctrl_sync = 0; 767 continue; 768 } 769 770 val = ctrlp->value; 771 772 r5u_dbg(vhp, R5U_CTRL, "control %s/wdm %02x <= %d [manual]", 773 ctrlp->base.uc_v4l.name, ctrlp->reg, val); 774 res = r5u870_set_reg_wdm(vhp, ctrlp->reg, val); 775 if (res) 776 break; 777 } 778 return res; 779 } 780 781 static int r5u870_set_ctrl_wdm(struct usbcam_dev *udp, 782 const struct usbcam_ctrl *basep, 783 const struct v4l2_ext_control *c) 784 { 785 struct r5u870_ctx *vhp = udp_r5u870(udp); 786 struct r5u870_ctrl *ctrlp = container_of(basep, struct r5u870_ctrl, 787 base); 788 int res = 0; 789 int auto_ctrl = 0; 790 791 if (ctrlp->auto_offset) 792 auto_ctrl = *(int *) (((char *) vhp) + ctrlp->auto_offset); 793 794 if (auto_ctrl && vhp->vh_ctrl_auto_suppress) { 795 r5u_dbg(vhp, R5U_CTRL, "control %s <= %d [auto suppress]", 796 ctrlp->base.uc_v4l.name, c->value); 797 798 } else if (!vhp->vh_ctrl_reg_enable) { 799 r5u_dbg(vhp, R5U_CTRL, "control %s <= %d [capture off]", 800 ctrlp->base.uc_v4l.name, c->value); 801 vhp->vh_ctrl_sync = 0; 802 803 } else { 804 r5u_dbg(vhp, R5U_CTRL, "control %s/wdm %02x <= %d", 805 ctrlp->base.uc_v4l.name, ctrlp->reg, c->value); 806 res = r5u870_set_reg_wdm(vhp, ctrlp->reg, c->value); 807 if (res) 808 return res; 809 } 810 811 ctrlp->value = c->value; 812 813 if (ctrlp->val_offset) 814 *(int *) (((char *) vhp) + ctrlp->val_offset) = c->value; 815 816 if (ctrlp->is_auto && !c->value) 817 res = r5u870_set_manual_ctrls_wdm(vhp, ctrlp->val_offset); 818 819 return res; 820 } 821 822 /* 823 * WDM control templates follow 824 * 825 * Each device has an array of integer control IDs, which refer to an 826 * element in the control template array. When the device is detected, 827 * we build the control array out of the element list and the templates, 828 * by r5u870_wdm_add_ctrls(). 829 */ 830 831 enum { 832 R5U870_WDM_CTRL_BRIGHTNESS, 833 R5U870_WDM_CTRL_CONTRAST, 834 R5U870_WDM_CTRL_SATURATION, 835 R5U870_WDM_CTRL_SHARPNESS, 836 R5U870_WDM_CTRL_HUE, 837 R5U870_WDM_CTRL_GAMMA, 838 R5U870_WDM_CTRL_BACKLIGHT_COMP_500, 839 R5U870_WDM_CTRL_BACKLIGHT_COMP_500_DEF1, 840 R5U870_WDM_CTRL_BACKLIGHT_COMP_X1834, 841 R5U870_WDM_CTRL_WB_RED, 842 R5U870_WDM_CTRL_WB_GREEN, 843 R5U870_WDM_CTRL_WB_BLUE, 844 R5U870_WDM_CTRL_WB_AUTO, 845 R5U870_WDM_CTRL_AUTO_EXPOSURE, 846 R5U870_WDM_CTRL_EXPOSURE, 847 R5U870_WDM_CTRL_AUTO_GAIN, 848 R5U870_WDM_CTRL_GAIN, 849 R5U870_WDM_CTRL_POWERLINE, 850 R5U870_WDM_CTRL_VFLIP, 851 R5U870_WDM_CTRL_VFLIP_DEFAULTON, 852 R5U870_WDM_CTRL_HFLIP, 853 R5U870_WDM_CTRL_PRIVACY, 854 R5U870_WDM_CTRL_NIGHTMODE, 855 856 R5U870_WDM_CTRL_LAST = 0xffff, 857 }; 858 859 /* TODO: Merge these into V4L API. */ 860 861 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) 862 #define V4L2_CID_GREEN_BALANCE (V4L2_CID_BASE+24) 863 #define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_BASE+25) 864 #define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+26) 865 #define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+27) 866 #define V4L2_CID_PRIVACY (V4L2_CID_BASE+28) 867 #define V4L2_CID_NIGHT_MODE (V4L2_CID_BASE+29) 868 #define V4L2_CID_SHARPNESS (V4L2_CID_BASE+30) 869 #define V4L2_CID_LASTP1 (V4L2_CID_BASE+31) /* last CID + 1 */ 870 #else 871 #define V4L2_CID_GREEN_BALANCE (V4L2_CID_BASE+31) 872 #define V4L2_CID_PRIVACY (V4L2_CID_BASE+32) 873 #define V4L2_CID_NIGHT_MODE (V4L2_CID_BASE+33) 874 #define V4L2_CID_LASTP1 (V4L2_CID_BASE+34) /* last CID + 1 */ 875 #endif 876 877 /* 2007-09-09 TJ Ensure names are identical to uvcvideo, 878 * so user applications aren't confused by differing results for UVC queries */ 879 static const char *r5u870_powerline_names[] = { "Disabled", "50 Hz", "60 Hz" }; 880 881 /* TODO: Use our own internal control IDs, instead of crap unmerged ones. */ 882 static struct r5u870_ctrl r5u870_wdm_ctrls[] = { 883 884 [R5U870_WDM_CTRL_BRIGHTNESS] = { 885 .base = { .uc_v4l = { .id = V4L2_CID_BRIGHTNESS, 886 .type = V4L2_CTRL_TYPE_INTEGER, 887 .name = "Brightness", 888 .minimum = 0, 889 .maximum = 127, 890 .step = 1, 891 .default_value = 63, 892 .flags = V4L2_CTRL_FLAG_SLIDER }, 893 .get_fn = r5u870_get_ctrl, 894 .set_fn = r5u870_set_ctrl_wdm }, 895 .reg = R5U870_REG_BRIGHTNESS, 896 }, 897 [R5U870_WDM_CTRL_CONTRAST] = { 898 .base = { .uc_v4l = { .id = V4L2_CID_CONTRAST, 899 .type = V4L2_CTRL_TYPE_INTEGER, 900 .name = "Contrast", 901 .minimum = 0, 902 .maximum = 127, 903 .step = 1, 904 .default_value = 63, 905 .flags = V4L2_CTRL_FLAG_SLIDER }, 906 .get_fn = r5u870_get_ctrl, 907 .set_fn = r5u870_set_ctrl_wdm }, 908 .reg = R5U870_REG_CONTRAST, 909 }, 910 [R5U870_WDM_CTRL_SATURATION] = { 911 .base = { .uc_v4l = { .id = V4L2_CID_SATURATION, 912 .type = V4L2_CTRL_TYPE_INTEGER, 913 .name = "Saturation", 914 .minimum = 0, 915 .maximum = 127, 916 .step = 1, 917 .default_value = 63, 918 .flags = V4L2_CTRL_FLAG_SLIDER }, 919 .get_fn = r5u870_get_ctrl, 920 .set_fn = r5u870_set_ctrl_wdm }, 921 .reg = R5U870_REG_SATURATION, 922 }, 923 [R5U870_WDM_CTRL_SHARPNESS] = { 924 .base = { .uc_v4l = { .id = V4L2_CID_SHARPNESS, 925 .type = V4L2_CTRL_TYPE_INTEGER, 926 .name = "Sharpness", 927 .minimum = 0, 928 .maximum = 127, 929 .step = 1, 930 .default_value = 63, 931 .flags = V4L2_CTRL_FLAG_SLIDER }, 932 .get_fn = r5u870_get_ctrl, 933 .set_fn = r5u870_set_ctrl_wdm }, 934 .reg = R5U870_REG_SHARPNESS, 935 }, 936 [R5U870_WDM_CTRL_HUE] = { 937 .base = { .uc_v4l = { .id = V4L2_CID_HUE, 938 .type = V4L2_CTRL_TYPE_INTEGER, 939 .name = "Hue", 940 .minimum = -180, 941 .maximum = 180, 942 .step = 1, 943 .default_value = 0, 944 .flags = V4L2_CTRL_FLAG_SLIDER }, 945 .get_fn = r5u870_get_ctrl, 946 .set_fn = r5u870_set_ctrl_wdm }, 947 .reg = R5U870_REG_HUE, 948 }, 949 [R5U870_WDM_CTRL_GAMMA] = { 950 .base = { .uc_v4l = { .id = V4L2_CID_GAMMA, 951 .type = V4L2_CTRL_TYPE_INTEGER, 952 .name = "Gamma", 953 .minimum = 0, 954 .maximum = 500, 955 .step = 1, 956 .default_value = 100, 957 .flags = V4L2_CTRL_FLAG_SLIDER }, 958 .get_fn = r5u870_get_ctrl, 959 .set_fn = r5u870_set_ctrl_wdm }, 960 .reg = R5U870_REG_GAMMA, 961 }, 962 [R5U870_WDM_CTRL_BACKLIGHT_COMP_500] = { 963 .base = { .uc_v4l = { .id = V4L2_CID_BACKLIGHT_COMPENSATION, 964 .type = V4L2_CTRL_TYPE_INTEGER, 965 .name = "Backlight Compensation", 966 .minimum = 0, 967 .maximum = 500, 968 .step = 1, 969 .default_value = 250, 970 .flags = V4L2_CTRL_FLAG_SLIDER }, 971 .get_fn = r5u870_get_ctrl, 972 .set_fn = r5u870_set_ctrl_wdm }, 973 .reg = R5U870_REG_BACKLIGHT_COMP, 974 }, 975 [R5U870_WDM_CTRL_BACKLIGHT_COMP_500_DEF1] = { 976 .base = { .uc_v4l = { .id = V4L2_CID_BACKLIGHT_COMPENSATION, 977 .type = V4L2_CTRL_TYPE_INTEGER, 978 .name = "Backlight Compensation", 979 .minimum = 0, 980 .maximum = 500, 981 .step = 1, 982 .default_value = 1, 983 .flags = V4L2_CTRL_FLAG_SLIDER }, 984 .get_fn = r5u870_get_ctrl, 985 .set_fn = r5u870_set_ctrl_wdm }, 986 .reg = R5U870_REG_BACKLIGHT_COMP, 987 }, 988 [R5U870_WDM_CTRL_BACKLIGHT_COMP_X1834] = { 989 .base = { .uc_v4l = { .id = V4L2_CID_BACKLIGHT_COMPENSATION, 990 .type = V4L2_CTRL_TYPE_INTEGER, 991 .name = "Backlight Compensation", 992 .minimum = 0, 993 .maximum = 2, 994 .step = 1, 995 .default_value = 1, 996 .flags = V4L2_CTRL_FLAG_SLIDER }, 997 .get_fn = r5u870_get_ctrl, 998 .set_fn = r5u870_set_ctrl_wdm }, 999 .reg = R5U870_REG_BACKLIGHT_COMP_2, 1000 }, 1001 [R5U870_WDM_CTRL_WB_RED] = { 1002 .base = { .uc_v4l = { .id = V4L2_CID_RED_BALANCE, 1003 .type = V4L2_CTRL_TYPE_INTEGER, 1004 .name = "White Balance Red", 1005 .minimum = 0, 1006 .maximum = 255, 1007 .step = 1, 1008 .default_value = 127, 1009 .flags = 0 }, 1010 .query_fn = r5u870_query_ctrl, 1011 .get_fn = r5u870_get_ctrl, 1012 .set_fn = r5u870_set_ctrl_wdm }, 1013 .reg = R5U870_REG_WB_RED_EX, 1014 .auto_offset = offsetof(struct r5u870_ctx, vh_auto_wb) 1015 }, 1016 [R5U870_WDM_CTRL_WB_GREEN] = { 1017 .base = { .uc_v4l = { .id = V4L2_CID_GREEN_BALANCE, 1018 .type = V4L2_CTRL_TYPE_INTEGER, 1019 .name = "White Balance Green", 1020 .minimum = 0, 1021 .maximum = 255, 1022 .step = 1, 1023 .default_value = 127, 1024 .flags = 0 }, 1025 .query_fn = r5u870_query_ctrl, 1026 .get_fn = r5u870_get_ctrl, 1027 .set_fn = r5u870_set_ctrl_wdm }, 1028 .reg = R5U870_REG_WB_GREEN_EX, 1029 .auto_offset = offsetof(struct r5u870_ctx, vh_auto_wb) 1030 }, 1031 [R5U870_WDM_CTRL_WB_BLUE] = { 1032 .base = { .uc_v4l = { .id = V4L2_CID_BLUE_BALANCE, 1033 .type = V4L2_CTRL_TYPE_INTEGER, 1034 .name = "White Balance Blue", 1035 .minimum = 0, 1036 .maximum = 255, 1037 .step = 1, 1038 .default_value = 127, 1039 .flags = 0 }, 1040 .query_fn = r5u870_query_ctrl, 1041 .get_fn = r5u870_get_ctrl, 1042 .set_fn = r5u870_set_ctrl_wdm }, 1043 .reg = R5U870_REG_WB_BLUE_EX, 1044 .auto_offset = offsetof(struct r5u870_ctx, vh_auto_wb) 1045 }, 1046 [R5U870_WDM_CTRL_WB_AUTO] = { 1047 .base = { .uc_v4l = { .id = V4L2_CID_AUTO_WHITE_BALANCE, 1048 .type = V4L2_CTRL_TYPE_BOOLEAN, 1049 .name = "Auto White Balance", 1050 .minimum = 0, 1051 .maximum = 1, 1052 .step = 1, 1053 .default_value = 1, 1054 .flags = V4L2_CTRL_FLAG_UPDATE }, 1055 .get_fn = r5u870_get_ctrl, 1056 .set_fn = r5u870_set_ctrl_wdm }, 1057 .reg = R5U870_REG_WB_AUTO_EX, 1058 .is_auto = 1, 1059 .val_offset = offsetof(struct r5u870_ctx, vh_auto_wb) 1060 }, 1061 [R5U870_WDM_CTRL_AUTO_EXPOSURE] = { 1062 .base = { .uc_v4l = { .id = V4L2_CID_EXPOSURE_AUTO, 1063 .type = V4L2_CTRL_TYPE_BOOLEAN, 1064 .name = "Auto Exposure Control", 1065 .minimum = 0, 1066 .maximum = 1, 1067 .step = 1, 1068 .default_value = 1, 1069 .flags = 0 }, 1070 .get_fn = r5u870_get_ctrl, 1071 .set_fn = r5u870_set_ctrl_wdm }, 1072 .reg = R5U870_REG_AEC_EX, 1073 .is_auto = 1, 1074 .val_offset = offsetof(struct r5u870_ctx, vh_aec) 1075 }, 1076 [R5U870_WDM_CTRL_EXPOSURE] = { 1077 .base = { .uc_v4l = { .id = V4L2_CID_EXPOSURE, 1078 .type = V4L2_CTRL_TYPE_INTEGER, 1079 .name = "Exposure", 1080 .minimum = 0, 1081 .maximum = 511, 1082 .step = 1, 1083 .default_value = 255, 1084 .flags = 0 }, 1085 .query_fn = r5u870_query_ctrl, 1086 .get_fn = r5u870_get_ctrl, 1087 .set_fn = r5u870_set_ctrl_wdm }, 1088 .reg = R5U870_REG_EXPOSURE_EX, 1089 .auto_offset = offsetof(struct r5u870_ctx, vh_aec) 1090 }, 1091 [R5U870_WDM_CTRL_AUTO_GAIN] = { 1092 .base = { .uc_v4l = { .id = V4L2_CID_AUTOGAIN, 1093 .type = V4L2_CTRL_TYPE_BOOLEAN, 1094 .name = "Auto Gain Control", 1095 .minimum = 0, 1096 .maximum = 1, 1097 .step = 1, 1098 .default_value = 1, 1099 .flags = 0 }, 1100 .get_fn = r5u870_get_ctrl, 1101 .set_fn = r5u870_set_ctrl_wdm }, 1102 .reg = R5U870_REG_AGC_EX, 1103 .is_auto = 1, 1104 .val_offset = offsetof(struct r5u870_ctx, vh_agc) 1105 }, 1106 [R5U870_WDM_CTRL_GAIN] = { 1107 .base = { .uc_v4l = { .id = V4L2_CID_GAIN, 1108 .type = V4L2_CTRL_TYPE_INTEGER, 1109 .name = "Gain", 1110 .minimum = 0, 1111 .maximum = 127, 1112 .step = 1, 1113 .default_value = 63, 1114 .flags = 0 }, 1115 .query_fn = r5u870_query_ctrl, 1116 .get_fn = r5u870_get_ctrl, 1117 .set_fn = r5u870_set_ctrl_wdm }, 1118 .reg = R5U870_REG_GAIN_EX, 1119 .auto_offset = offsetof(struct r5u870_ctx, vh_agc) 1120 }, 1121 [R5U870_WDM_CTRL_POWERLINE] = { 1122 .base = { .uc_v4l = { .id = V4L2_CID_POWER_LINE_FREQUENCY, 1123 .type = V4L2_CTRL_TYPE_MENU, 1124 .name = "Power Line Frequency", 1125 .minimum = 0, 1126 .maximum = 2, 1127 .step = 1, 1128 .default_value = 0, 1129 .flags = 0 }, 1130 .uc_menu_names = r5u870_powerline_names, 1131 .get_fn = r5u870_get_ctrl, 1132 .set_fn = r5u870_set_ctrl_wdm }, 1133 .reg = R5U870_REG_POWERLINE_EX, 1134 }, 1135 [R5U870_WDM_CTRL_VFLIP] = { 1136 .base = { .uc_v4l = { .id = V4L2_CID_VFLIP, 1137 .type = V4L2_CTRL_TYPE_BOOLEAN, 1138 .name = "V-Flip", 1139 .minimum = 0, 1140 .maximum = 1, 1141 .step = 1, 1142 .default_value = 0, 1143 .flags = 0 }, 1144 .get_fn = r5u870_get_ctrl, 1145 .set_fn = r5u870_set_ctrl_wdm }, 1146 .reg = R5U870_REG_VFLIP_EX, 1147 }, 1148 [R5U870_WDM_CTRL_VFLIP_DEFAULTON] = { 1149 .base = { .uc_v4l = { .id = V4L2_CID_VFLIP, 1150 .type = V4L2_CTRL_TYPE_BOOLEAN, 1151 .name = "V-Flip", 1152 .minimum = 0, 1153 .maximum = 1, 1154 .step = 1, 1155 .default_value = 1, 1156 .flags = 0 }, 1157 .get_fn = r5u870_get_ctrl, 1158 .set_fn = r5u870_set_ctrl_wdm }, 1159 .reg = R5U870_REG_VFLIP_EX, 1160 }, 1161 [R5U870_WDM_CTRL_HFLIP] = { 1162 .base = { .uc_v4l = { .id = V4L2_CID_HFLIP, 1163 .type = V4L2_CTRL_TYPE_BOOLEAN, 1164 .name = "H-Flip", 1165 .minimum = 0, 1166 .maximum = 1, 1167 .step = 1, 1168 .default_value = 0, 1169 .flags = 0 }, 1170 .get_fn = r5u870_get_ctrl, 1171 .set_fn = r5u870_set_ctrl_wdm }, 1172 .reg = R5U870_REG_HFLIP_EX, 1173 }, 1174 [R5U870_WDM_CTRL_PRIVACY] = { 1175 .base = { .uc_v4l = { .id = V4L2_CID_PRIVACY, 1176 .type = V4L2_CTRL_TYPE_BOOLEAN, 1177 .name = "Privacy", 1178 .minimum = 0, 1179 .maximum = 1, 1180 .step = 1, 1181 .default_value = 0, 1182 .flags = 0 }, 1183 .get_fn = r5u870_get_ctrl, 1184 .set_fn = r5u870_set_ctrl_wdm }, 1185 .reg = R5U870_REG_PRIVACY_EX, 1186 }, 1187 [R5U870_WDM_CTRL_NIGHTMODE] = { 1188 .base = { .uc_v4l = { .id = V4L2_CID_NIGHT_MODE, 1189 .type = V4L2_CTRL_TYPE_BOOLEAN, 1190 .name = "Night Mode", 1191 .minimum = 0, 1192 .maximum = 1, 1193 .step = 1, 1194 .default_value = 0, 1195 .flags = 0 }, 1196 /* 2007-09-09 TJ Add missing IOCTL query */ 1197 .query_fn = r5u870_query_ctrl, 1198 .get_fn = r5u870_get_ctrl, 1199 .set_fn = r5u870_set_ctrl_wdm }, 1200 .reg = R5U870_REG_NIGHT_MODE_EX, 1201 }, 1202 }; 1203 1204 static int r5u870_wdm_add_ctrls(struct r5u870_ctx *vhp, const int *ctrlarray) 1205 { 1206 struct r5u870_ctrl *ncp; 1207 int i; 1208 1209 for (i = 0; ctrlarray[i] != R5U870_WDM_CTRL_LAST; i++) { 1210 ncp = (struct r5u870_ctrl *) 1211 usbcam_ctrl_add_tmpl(vhp->vh_parent, 1212 &r5u870_wdm_ctrls[ctrlarray[i]].base, 1213 sizeof(*ncp)); 1214 if (!ncp) 1215 return -ENOMEM; 1216 } 1217 r5u_dbg(vhp, R5U_CTRL, "Added %d WDM controls", i); 1218 return 0; 1219 } 1220 1221 1222 1223 /* 1224 * UVC related code follows 1225 */ 1226 1227 enum { 1228 UVC_SC_VIDEOCONTROL = 1, 1229 UVC_SC_VIDEOSTREAMING = 1, 1230 1231 UVC_VC_HEADER = 1, 1232 UVC_VC_INPUT_TERMINAL = 2, 1233 UVC_VC_OUTPUT_TERMINAL = 3, 1234 UVC_VC_SELECTOR_UNIT = 4, 1235 UVC_VC_PROCESSING_UNIT = 5, 1236 UVC_VC_EXTENSION_UNIT = 6, 1237 1238 UVC_VC_REQUEST_ERROR_CODE_CONTROL = 0x02, 1239 1240 UVC_VS_INPUT_HEADER = 0x01, 1241 UVC_VS_FORMAT_UNCOMPRESSED = 0x04, 1242 UVC_VS_FRAME_UNCOMPRESSED = 0x05, 1243 1244 UVC_SET_CUR = 0x01, 1245 UVC_GET_CUR = 0x81, 1246 UVC_GET_MIN = 0x82, 1247 UVC_GET_MAX = 0x83, 1248 UVC_GET_RES = 0x84, 1249 UVC_GET_LEN = 0x85, 1250 UVC_GET_INFO = 0x86, 1251 UVC_GET_DEF = 0x87, 1252 1253 UVC_PU_BACKLIGHT_COMPENSATION_CONTROL = 0x01, 1254 UVC_PU_BRIGHTNESS_CONTROL = 0x02, 1255 UVC_PU_CONTRAST_CONTROL = 0x03, 1256 UVC_PU_POWER_LINE_FREQUENCY_CONTROL = 0x05, 1257 UVC_PU_HUE_CONTROL = 0x06, 1258 UVC_PU_SATURATION_CONTROL = 0x07, 1259 UVC_PU_SHARPNESS_CONTROL = 0x08, 1260 UVC_PU_GAMMA_CONTROL = 0x09, 1261 1262 UVC_VS_PROBE_CONTROL = 0x01, 1263 UVC_VS_COMMIT_CONTROL = 0x02, 1264 1265 }; 1266 1267 static int r5u870_uvc_req(struct r5u870_ctx *vhp, int cmd, 1268 u8 valhi, u8 vallow, u8 idxhi, u8 idxlow, 1269 u8 *buf, int len) 1270 { 1271 int out, res, stres; 1272 int tries = 5; 1273 u8 stbuf[1]; 1274 1275 out = (cmd == UVC_SET_CUR) ? 1 : 0; 1276 1277 retry: 1278 /* TODO: Base our other retry control message off this one. */ 1279 res = r5u870_control_msg(vhp, out, 1, cmd, 1280 (valhi << 8) | vallow, (idxhi << 8) | idxlow, 1281 buf, len); 1282 1283 if (res != -EPIPE) 1284 //r5u_err(vhp, "res != -EPIPE."); 1285 goto complete; 1286 1287 stres = r5u870_control_msg(vhp, 0, 1, UVC_GET_CUR, 1288 UVC_VC_REQUEST_ERROR_CODE_CONTROL << 8, 1289 vhp->vh_ctrl_ifnum, 1290 stbuf, sizeof(stbuf)); 1291 1292 if (((stres == -EPIPE) && --tries) || 1293 ((stres == 1) && (stbuf[0] == 1) && --tries)) { 1294 msleep(5); 1295 r5u_err(vhp, "uvc_req: retrying - EPIPE/stres error."); 1296 goto retry; 1297 } 1298 1299 if (stres != 1) { 1300 r5u_err(vhp, "uvc_req: status req failed: %d", stres); 1301 goto complete; 1302 1303 } else { 1304 r5u_err(vhp, "uvc_req: status %d", stbuf[0]); 1305 } 1306 1307 complete: 1308 if (res < 0) { 1309 r5u_err(vhp, "uvc_req %02x/%02x%02x/%02x%02x failed: %d", 1310 cmd, valhi, vallow, idxhi, idxlow, res); 1311 } 1312 1313 return res; 1314 } 1315 1316 static int r5u870_set_fmt_uvc(struct r5u870_ctx *vhp, 1317 const struct r5u870_pix_fmt *fmtp, 1318 const struct r5u870_resolution *resp) 1319 { 1320 unsigned char buf[26]; 1321 int res; 1322 1323 memset(buf, 0, sizeof(buf)); 1324 1325 buf[2] = fmtp->rp_formatidx; 1326 buf[3] = resp->rw_frameidx; 1327 *(__le32 *) &buf[4] = cpu_to_le32(resp->rw_interval); 1328 1329 r5u_dbg(vhp, R5U_FRAME, 1330 "set_format: fmtidx:%d frameidx:%d %dx%d ival:%d", 1331 fmtp->rp_formatidx, resp->rw_frameidx, 1332 resp->rw_width, resp->rw_height, resp->rw_interval); 1333 1334 res = r5u870_uvc_req(vhp, UVC_SET_CUR, UVC_VS_PROBE_CONTROL, 0, 1335 0, vhp->vh_iso_ifnum, buf, sizeof(buf)); 1336 if (res != sizeof(buf)) { 1337 r5u_err(vhp, "%s: probe_control set_cur1: short write %d", 1338 __FUNCTION__, res); 1339 1340 return -EIO; 1341 } 1342 1343 res = r5u870_uvc_req(vhp, UVC_GET_CUR, UVC_VS_PROBE_CONTROL, 0, 1344 0, vhp->vh_iso_ifnum, buf, sizeof(buf)); 1345 if (res != sizeof(buf)) { 1346 r5u_err(vhp, "%s: probe_control get_cur: short read %d", 1347 __FUNCTION__, res); 1348 return -EIO; 1349 } 1350 1351 if (buf[2] != fmtp->rp_formatidx) { 1352 r5u_err(vhp, "%s: probe_control get_cur: got fmt %d", 1353 __FUNCTION__, buf[2]); 1354 return -EIO; 1355 } 1356 1357 if (buf[3] != resp->rw_frameidx) { 1358 r5u_err(vhp, "%s: probe_control get_cur: got frame idx %d", 1359 __FUNCTION__, buf[3]); 1360 return -EIO; 1361 } 1362 1363 res = r5u870_uvc_req(vhp, UVC_SET_CUR, UVC_VS_COMMIT_CONTROL, 0, 1364 0, vhp->vh_iso_ifnum, buf, sizeof(buf)); 1365 if (res != sizeof(buf)) { 1366 r5u_err(vhp, "%s: commit_control set_cur2: short write %d", 1367 __FUNCTION__, res); 1368 return -EIO; 1369 } 1370 1371 vhp->vh_iso_minpacket = le32_to_cpup((__le32 *) &buf[22]); 1372 1373 return 0; 1374 } 1375 1376 static int r5u870_cap_stop_uvc(struct r5u870_ctx *vhp) 1377 { 1378 /* UVC capture is controlled by changing the altsetting */ 1379 return 0; 1380 } 1381 1382 static int r5u870_decide_pkt_uvc(struct r5u870_ctx *vhp, int pktstatus, 1383 int pktlen, const u8 *pktdata, int *start) 1384 { 1385 if (!pktlen) { 1386 vhp->vh_emptypkts++; 1387 if (vhp->vh_emptypkts >= R5U870_EMPTYPKT_GIVE_UP) { 1388 r5u_err(vhp, "capture abort: too many empty pkts"); 1389 return -EIO; 1390 } 1391 if (vhp->vh_frame_accum < 0) 1392 return -EPIPE; 1393 return -EAGAIN; 1394 } 1395 1396 vhp->vh_emptypkts = 0; 1397 if (vhp->vh_frame_accum < 0) { 1398 if (pktdata[1] & 2) 1399 vhp->vh_frame_accum = 0; 1400 return -EPIPE; 1401 } 1402 1403 if ((pktdata[0] < 2) || (pktdata[0] > pktlen)) { 1404 r5u_err(vhp, "capture abort: hdrlen=%d pktlen=%d", 1405 pktdata[0], pktlen); 1406 return -EIO; 1407 } 1408 vhp->vh_frame_accum += pktlen - pktdata[0]; 1409 if (vhp->vh_frame_accum > vhp->vh_parent->ud_format.sizeimage) { 1410 r5u_err(vhp, "frame abort: accum=%d", vhp->vh_frame_accum); 1411 vhp->vh_frame_accum = -1; 1412 return -EPIPE; 1413 } 1414 1415 *start = pktdata[0]; 1416 if (pktdata[1] & 2) { 1417 if (vhp->vh_frame_accum < 1418 vhp->vh_parent->ud_format.sizeimage) { 1419 r5u_err(vhp, "warning: short frame (exp:%d got:%d)", 1420 vhp->vh_parent->ud_format.sizeimage, 1421 vhp->vh_frame_accum); 1422 } 1423 vhp->vh_frame_accum = 0; 1424 return 0; 1425 } 1426 return -EAGAIN; 1427 } 1428 1429 1430 /* 1431 * Known video format GUIDs and V4L pixel format translations 1432 * 1433 * Only uncompressed formats are supported, as Ricoh webcams are too 1434 * minimal to do anything else. 1435 */ 1436 1437 static const struct r5u870_uvc_fmtinfo { 1438 const char *fi_name; 1439 int fi_v4l_id; 1440 u8 fi_guid[16]; 1441 1442 } r5u870_uvc_fmts[] = { 1443 { .fi_name = "YUY2 4:2:2", 1444 .fi_v4l_id = V4L2_PIX_FMT_YUYV, 1445 .fi_guid = { 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 1446 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } }, 1447 { } 1448 }; 1449 1450 static int r5u870_uvc_add_resolution(struct r5u870_ctx *vhp, 1451 struct r5u870_pix_fmt *fmtp, 1452 int width, int height, int reqbw, 1453 int frameidx, int interval) 1454 { 1455 int i; 1456 struct r5u870_resolution *resp; 1457 1458 if (!width || !height) { 1459 r5u_dbg(vhp, R5U_INIT, "invalid frame descriptor %d at %dx%d", 1460 frameidx, width, height); 1461 return -EINVAL; 1462 } 1463 1464 resp = NULL; 1465 for (i = 0; i < fmtp->rp_restbl_alloc; i++) { 1466 if (!fmtp->rp_restbl[i].rw_width) { 1467 resp = (struct r5u870_resolution *) 1468 &fmtp->rp_restbl[i]; 1469 break; 1470 } 1471 } 1472 1473 if (!resp) { 1474 r5u_dbg(vhp, R5U_INIT, 1475 "no space for frame descriptor %d at %dx%d", 1476 frameidx, width, height); 1477 return 0; 1478 } 1479 1480 resp->rw_width = width; 1481 resp->rw_height = height; 1482 resp->rw_frameidx = frameidx; 1483 resp->rw_reqbw = reqbw; 1484 resp->rw_interval = interval; 1485 1486 r5u_dbg(vhp, R5U_INIT, "Found resolution %d: %dx%d ival %d (%d B/s)", 1487 frameidx, width, height, interval, reqbw); 1488 1489 return 0; 1490 } 1491 1492 static int r5u870_uvc_add_fmt(struct r5u870_ctx *vhp, const u8 *guid, 1493 int fmtidx, int nresolutions, 1494 struct r5u870_pix_fmt **new_fmt) 1495 { 1496 const struct r5u870_uvc_fmtinfo *fip, *fmtarray = r5u870_uvc_fmts; 1497 struct r5u870_pix_fmt *nfp, *fmtp; 1498 int i; 1499 1500 fip = NULL; 1501 for (i = 0; fmtarray[i].fi_name != NULL; i++) { 1502 if (!memcmp(fmtarray[i].fi_guid, guid, 16)) { 1503 fip = &fmtarray[i]; 1504 break; 1505 } 1506 } 1507 1508 if (fip == NULL) { 1509 r5u_dbg(vhp, R5U_INIT, "unknown format " 1510 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" 1511 "%02x%02x%02x%02x%02x%02x", 1512 guid[0], guid[1], guid[2], guid[3], guid[4], guid[5], 1513 guid[6], guid[7], guid[8], guid[9], guid[10], 1514 guid[11], guid[12], guid[13], guid[14], guid[15]); 1515 return -ENOENT; 1516 } 1517 1518 nfp = (struct r5u870_pix_fmt *) 1519 kmalloc((1 + vhp->vh_npixfmts) * sizeof(*nfp), GFP_KERNEL); 1520 if (!nfp) 1521 return -ENOMEM; 1522 if (vhp->vh_npixfmts) 1523 memcpy(nfp, vhp->vh_pixfmts, vhp->vh_npixfmts * sizeof(*nfp)); 1524 1525 fmtp = &nfp[vhp->vh_npixfmts]; 1526 memset(fmtp, 0, sizeof(*fmtp)); 1527 strlcpy(fmtp->base.description, 1528 fip->fi_name, 1529 sizeof(fmtp->base.description)); 1530 fmtp->base.pixelformat = fip->fi_v4l_id; 1531 fmtp->rp_formatidx = fmtidx; 1532 fmtp->rp_restbl = (struct r5u870_resolution *) 1533 kmalloc((1 + nresolutions) * sizeof(*fmtp->rp_restbl), 1534 GFP_KERNEL); 1535 if (!fmtp->rp_restbl) { 1536 kfree(nfp); 1537 return -ENOMEM; 1538 } 1539 1540 memset((char *)fmtp->rp_restbl, 0, 1541 (1 + nresolutions) * sizeof(*fmtp->rp_restbl)); 1542 fmtp->rp_restbl_alloc = nresolutions; 1543 1544 if (vhp->vh_npixfmts && vhp->vh_dyn_pixfmts) 1545 kfree(vhp->vh_pixfmts); 1546 vhp->vh_pixfmts = nfp; 1547 vhp->vh_npixfmts++; 1548 1549 if (new_fmt) 1550 (*new_fmt) = fmtp; 1551 1552 r5u_dbg(vhp, R5U_INIT, "Found format %d: %c%c%c%c (%d frames)", 1553 fmtidx, 1554 fmtp->base.pixelformat & 0xff, 1555 (fmtp->base.pixelformat >> 8) & 0xff, 1556 (fmtp->base.pixelformat >> 16) & 0xff, 1557 (fmtp->base.pixelformat >> 24) & 0xff, 1558 nresolutions); 1559 1560 return 0; 1561 } 1562 1563 static int r5u870_uvc_parse_vs(struct r5u870_ctx *vhp, int ifnum) 1564 { 1565 struct usb_interface *intf; 1566 struct usb_host_interface *aintf; 1567 struct r5u870_pix_fmt *curfmt = NULL; 1568 u8 *desc; 1569 int dlen, rlen; 1570 int wid, hgt, reqbw, ival; 1571 int res; 1572 1573 intf = usb_ifnum_to_if(r5u870_dev(vhp), ifnum); 1574 if (!intf) 1575 return -EINVAL; 1576 1577 aintf = intf->cur_altsetting; 1578 1579 for (desc = aintf->extra, rlen = aintf->extralen; 1580 rlen > 2; 1581 rlen -= desc[0], desc += desc[0]) { 1582 1583 dlen = desc[0]; 1584 if (dlen < 2) 1585 return -EINVAL; 1586 if (desc[1] != USB_DT_CS_INTERFACE) 1587 continue; 1588 if (dlen < 3) 1589 return -EINVAL; 1590 1591 switch (desc[2]) { 1592 case UVC_VS_INPUT_HEADER: 1593 if (dlen < 7) { 1594 r5u_err(vhp, "VS_INPUT_HEADER too short " 1595 "at %d bytes", dlen); 1596 return -EINVAL; 1597 } 1598 vhp->vh_iso_ep = desc[6] & 0xf; 1599 break; 1600 1601 case UVC_VS_FORMAT_UNCOMPRESSED: 1602 if (dlen < 21) { 1603 r5u_err(vhp, "VS_FORMAT_UNCOMP too short " 1604 "at %d bytes", dlen); 1605 break; 1606 } 1607 res = r5u870_uvc_add_fmt(vhp, &desc[5], desc[3], 1608 desc[4], &curfmt); 1609 if (res) { 1610 if (res != -ENOENT) 1611 return res; 1612 curfmt = NULL; 1613 } 1614 break; 1615 1616 case UVC_VS_FRAME_UNCOMPRESSED: 1617 if (dlen < 26) { 1618 r5u_err(vhp, "VS_FRAME_UNCOMP too short " 1619 "at %d bytes", dlen); 1620 break; 1621 } 1622 if (!curfmt) { 1623 r5u_dbg(vhp, R5U_INIT, "VS_FRAME_UNCOMP " 1624 "not following VS_FORMAT_UNCOMP"); 1625 break; 1626 } 1627 1628 wid = desc[5] | (desc[6] << 8); 1629 hgt = desc[7] | (desc[8] << 8); 1630 reqbw = desc[13] | (desc[14] << 8) | 1631 (desc[15] << 16) | (desc[16] << 24); 1632 reqbw = (reqbw + 7) / 8; 1633 ival = le32_to_cpup((__le32 *) &desc[21]); 1634 1635 res = r5u870_uvc_add_resolution(vhp, curfmt, wid, hgt, 1636 reqbw, desc[3], ival); 1637 if (res) 1638 return res; 1639 break; 1640 } 1641 } 1642 1643 return 0; 1644 } 1645 1646 1647 /* 1648 * Known UVC controls for processing units 1649 * 1650 * Not all types of UVC controls are supported. We stick to simple 1651 * controls with one or two byte values, and don't do anything very 1652 * complicated. 1653 * 1654 * We don't support camera unit controls, or multiple processing units 1655 * with instances of the same control. We also don't check for 1656 * redefined control IDs, and let usbcam do this for us. 1657 */ 1658 1659 struct r5u870_uvc_ctrlinfo { 1660 const char *ci_name; 1661 u32 ci_v4l_id; 1662 int ci_v4l_type; 1663 int ci_v4l_flags; 1664 u8 ci_reg; 1665 u8 ci_size; 1666 u8 ci_bm_index; 1667 int ci_min, ci_max, ci_def; 1668 u8 ci_min_force, ci_max_force, ci_def_force; 1669 const char **ci_menu_names; 1670 int ci_val_offset; 1671 }; 1672 1673 static struct r5u870_uvc_ctrlinfo r5u870_uvc_proc_ctrls[] = { 1674 { .ci_name = "Brightness", 1675 .ci_v4l_id = V4L2_CID_BRIGHTNESS, 1676 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1677 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1678 .ci_reg = UVC_PU_BRIGHTNESS_CONTROL, 1679 .ci_size = 2, 1680 .ci_bm_index = 0 }, 1681 { .ci_name = "Contrast", 1682 .ci_v4l_id = V4L2_CID_CONTRAST, 1683 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1684 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1685 .ci_reg = UVC_PU_CONTRAST_CONTROL, 1686 .ci_size = 2, 1687 .ci_bm_index = 1 }, 1688 { .ci_name = "Hue", 1689 .ci_v4l_id = V4L2_CID_HUE, 1690 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1691 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1692 .ci_reg = UVC_PU_HUE_CONTROL, 1693 .ci_size = 2, 1694 .ci_min = -180, .ci_min_force = 1, 1695 .ci_max = 180, .ci_max_force = 1, 1696 .ci_def = 0, .ci_def_force = 1, 1697 .ci_bm_index = 2 }, 1698 { .ci_name = "Saturation", 1699 .ci_v4l_id = V4L2_CID_SATURATION, 1700 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1701 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1702 .ci_reg = UVC_PU_SATURATION_CONTROL, 1703 .ci_size = 2, 1704 .ci_bm_index = 3 }, 1705 { .ci_name = "Sharpness", 1706 .ci_v4l_id = V4L2_CID_SHARPNESS, 1707 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1708 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1709 .ci_reg = UVC_PU_SHARPNESS_CONTROL, 1710 .ci_size = 2, 1711 .ci_bm_index = 4 }, 1712 { .ci_name = "Gamma", 1713 .ci_v4l_id = V4L2_CID_GAMMA, 1714 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1715 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1716 .ci_reg = UVC_PU_GAMMA_CONTROL, 1717 .ci_size = 2, 1718 .ci_bm_index = 5 }, 1719 { .ci_name = "Backlight Compensation", 1720 .ci_v4l_id = V4L2_CID_BACKLIGHT_COMPENSATION, 1721 .ci_v4l_type = V4L2_CTRL_TYPE_INTEGER, 1722 .ci_v4l_flags = V4L2_CTRL_FLAG_SLIDER, 1723 .ci_reg = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, 1724 .ci_size = 2, 1725 .ci_bm_index = 8 }, 1726 { .ci_name = "Power Line Frequency", 1727 .ci_v4l_id = V4L2_CID_POWER_LINE_FREQUENCY, 1728 .ci_v4l_type = V4L2_CTRL_TYPE_MENU, 1729 .ci_reg = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, 1730 .ci_size = 1, 1731 .ci_bm_index = 10, 1732 .ci_min = 0, .ci_min_force = 1, 1733 .ci_max = 2, .ci_max_force = 1, 1734 .ci_menu_names = r5u870_powerline_names }, 1735 { } 1736 }; 1737 1738 static int r5u870_uvc_ctrl_req(struct r5u870_ctx *vhp, 1739 const struct r5u870_ctrl *ctrlp, 1740 int req, int *value) 1741 { 1742 u8 buf[4]; 1743 int size, i, val, res; 1744 1745 size = ctrlp->size; 1746 if (req == UVC_GET_INFO) 1747 size = 1; 1748 1749 if (size > sizeof(buf)) { 1750 r5u_err(vhp, "Control ID %d is too large, %d bytes", 1751 ctrlp->reg, size); 1752 return -EINVAL; 1753 } 1754 1755 memset(buf, 0, sizeof(buf)); 1756 1757 if (req != UVC_SET_CUR) { 1758 res = r5u870_uvc_req(vhp, req, ctrlp->reg, 0, 1759 ctrlp->unit, vhp->vh_ctrl_ifnum, 1760 buf, size); 1761 if (res < 0) 1762 return res; 1763 if (res != size) { 1764 r5u_err(vhp, "short read for UVC control %d", 1765 ctrlp->reg); 1766 return -EIO; 1767 } 1768 1769 val = 0; 1770 switch (size) { 1771 case 1: 1772 val = buf[0]; 1773 break; 1774 case 2: 1775 val = le16_to_cpu(*(__le16 *) buf); 1776 break; 1777 case 4: 1778 val = le32_to_cpu(*(__le32 *) buf); 1779 break; 1780 default: 1781 return -EINVAL; 1782 } 1783 1784 *value = val; 1785 return 0; 1786 } 1787 1788 val = *value; 1789 for (i = 0; i < size; i++, val >>= 8) 1790 buf[i] = val & 0xff; 1791 1792 res = r5u870_uvc_req(vhp, UVC_SET_CUR, ctrlp->reg, 0, 1793 ctrlp->unit, vhp->vh_ctrl_ifnum, 1794 buf, size); 1795 if (res < 0) 1796 return res; 1797 if (res != size) { 1798 r5u_err(vhp, "short write for UVC control %d", 1799 ctrlp->reg); 1800 return -EIO; 1801 } 1802 1803 return 0; 1804 } 1805 1806 static int r5u870_set_ctrl_uvc(struct usbcam_dev *udp, 1807 const struct usbcam_ctrl *basep, 1808 const struct v4l2_ext_control *c) 1809 { 1810 struct r5u870_ctx *vhp = udp_r5u870(udp); 1811 struct r5u870_ctrl *ctrlp = container_of(basep, struct r5u870_ctrl, 1812 base); 1813 int val; 1814 int res = 0; 1815 1816 if (!(ctrlp->info & 2)) { 1817 r5u_dbg(vhp, R5U_CTRL, "control %s <= %d [set not supported]", 1818 ctrlp->base.uc_v4l.name, c->value); 1819 return -EINVAL; 1820 } 1821 1822 r5u_dbg(vhp, R5U_CTRL, "control %s/uvc %02x <= %d", 1823 ctrlp->base.uc_v4l.name, ctrlp->reg, c->value); 1824 1825 val = c->value; 1826 res = r5u870_uvc_ctrl_req(vhp, ctrlp, UVC_SET_CUR, &val); 1827 if (res) 1828 return res; 1829 1830 ctrlp->value = c->value; 1831 1832 return res; 1833 } 1834 1835 /* 1836 * Initialize a r5u870_ctrl structure based on a UVC descriptor array, 1837 * and a bit within a supported control bitmap. 1838 */ 1839 static int r5u870_uvc_init_ctrl(struct r5u870_ctx *vhp, 1840 int unit, 1841 const struct r5u870_uvc_ctrlinfo *ci_array, 1842 int bit_offset) 1843 { 1844 const struct r5u870_uvc_ctrlinfo *cip = NULL; 1845 struct r5u870_ctrl *ctrlp; 1846 int i, res, val; 1847 1848 for (i = 0; ci_array[i].ci_name != NULL; i++) { 1849 if (ci_array[i].ci_bm_index == bit_offset) { 1850 cip = &ci_array[i]; 1851 break; 1852 } 1853 } 1854 1855 if (!cip) 1856 return -ENOENT; 1857 1858 ctrlp = (struct r5u870_ctrl *) usbcam_ctrl_alloc(sizeof(*ctrlp)); 1859 if (!ctrlp) 1860 return -ENOMEM; 1861 1862 ctrlp->base.uc_v4l.id = cip->ci_v4l_id; 1863 ctrlp->base.uc_v4l.type = cip->ci_v4l_type; 1864 strlcpy(ctrlp->base.uc_v4l.name, 1865 cip->ci_name, 1866 sizeof(ctrlp->base.uc_v4l.name)); 1867 ctrlp->base.uc_v4l.flags = cip->ci_v4l_flags; 1868 ctrlp->base.uc_v4l.step = 1; 1869 ctrlp->base.uc_menu_names = cip->ci_menu_names; 1870 ctrlp->base.get_fn = r5u870_get_ctrl; 1871 ctrlp->base.set_fn = r5u870_set_ctrl_uvc; 1872 ctrlp->base.query_fn = r5u870_query_ctrl; 1873 ctrlp->reg = cip->ci_reg; 1874 ctrlp->unit = unit; 1875 ctrlp->size = cip->ci_size; 1876 ctrlp->is_auto = 0; 1877 ctrlp->auto_offset = 0; 1878 1879 res = r5u870_uvc_ctrl_req(vhp, ctrlp, UVC_GET_INFO, &val); 1880 if (res) 1881 goto failed; 1882 ctrlp->info = val; 1883 1884 if (cip->ci_min_force) { 1885 ctrlp->base.uc_v4l.minimum = cip->ci_min; 1886 } else { 1887 res = r5u870_uvc_ctrl_req(vhp, ctrlp, UVC_GET_MIN, &val); 1888 if (res < 0) 1889 goto failed; 1890 ctrlp->base.uc_v4l.minimum = val; 1891 } 1892 if (cip->ci_max_force) { 1893 ctrlp->base.uc_v4l.maximum = cip->ci_max; 1894 } else { 1895 res = r5u870_uvc_ctrl_req(vhp, ctrlp, UVC_GET_MAX, &val); 1896 if (res < 0) 1897 goto failed; 1898 ctrlp->base.uc_v4l.maximum = val; 1899 } 1900 1901 if (cip->ci_def_force) { 1902 ctrlp->base.uc_v4l.default_value = cip->ci_def; 1903 } else { 1904 res = r5u870_uvc_ctrl_req(vhp, ctrlp, UVC_GET_DEF, &val); 1905 if (res) 1906 goto failed; 1907 return res; 1908 ctrlp->base.uc_v4l.default_value = val; 1909 } 1910 1911 res = usbcam_ctrl_add(vhp->vh_parent, &ctrlp->base); 1912 if (res) 1913 goto failed; 1914 1915 r5u_dbg(vhp, R5U_INIT, "Found UVC control %s [%d,%d] def:%d info:%02x", 1916 ctrlp->base.uc_v4l.name, ctrlp->base.uc_v4l.minimum, 1917 ctrlp->base.uc_v4l.maximum, ctrlp->base.uc_v4l.default_value, 1918 ctrlp->info); 1919 return 0; 1920 1921 failed: 1922 usbcam_ctrl_free(ctrlp); 1923 return res; 1924 } 1925 1926 static int r5u870_uvc_add_ctrls(struct r5u870_ctx *vhp, int unit, 1927 const struct r5u870_uvc_ctrlinfo *ci_array, 1928 const u8 *bits, int nbits) 1929 { 1930 int i, res; 1931 1932 for (i = 0; i < nbits; i++) { 1933 if (!test_bit(i, (const unsigned long *) bits)) 1934 continue; 1935 res = r5u870_uvc_init_ctrl(vhp, unit, ci_array, i); 1936 if (res == -ENOENT) { 1937 r5u_dbg(vhp, R5U_INIT, 1938 "unit %d ctrl %d not recognized", unit, i); 1939 } 1940 else if (res) 1941 return res; 1942 } 1943 1944 return 0; 1945 } 1946 1947 static int r5u870_uvc_parse_vc(struct r5u870_ctx *vhp) 1948 { 1949 struct usb_host_interface *aintf = 1950 vhp->vh_parent->ud_intf->cur_altsetting; 1951 u8 *desc; 1952 int dlen, rlen, count; 1953 int i, res; 1954 1955 vhp->vh_ctrl_ifnum = aintf->desc.bInterfaceNumber; 1956 1957 for (desc = aintf->extra, rlen = aintf->extralen; 1958 rlen > 2; 1959 rlen -= desc[0], desc += desc[0]) { 1960 1961 dlen = desc[0]; 1962 if (dlen < 2) 1963 return -EINVAL; 1964 if (desc[1] != USB_DT_CS_INTERFACE) 1965 continue; 1966 if (dlen < 3) 1967 return -EINVAL; 1968 1969 switch (desc[2]) { 1970 case UVC_VC_HEADER: 1971 count = (dlen < 12) ? 0 : desc[11]; 1972 if (dlen < (12 + count)) { 1973 r5u_err(vhp, "VC_HEADER too short at %d bytes", 1974 dlen); 1975 return -EINVAL; 1976 } 1977 1978 for (i = 0; i < count; i++) { 1979 res = usbcam_claim_interface(vhp->vh_parent, 1980 desc[12 + i]); 1981 if (res) 1982 r5u_err(vhp, "interface %d already " 1983 "claimed", desc[12 + i]); 1984 vhp->vh_iso_ifnum = desc[12 + i]; 1985 1986 res = r5u870_uvc_parse_vs(vhp, desc[12 + i]); 1987 if (res) 1988 return res; 1989 } 1990 break; 1991 1992 case UVC_VC_PROCESSING_UNIT: 1993 count = (dlen < 8) ? 0 : desc[7]; 1994 if (dlen < (8 + count)) { 1995 r5u_err(vhp, "VC_PROCESSING_UNIT too short " 1996 "at %d bytes", dlen); 1997 return -EINVAL; 1998 } 1999 2000 res = r5u870_uvc_add_ctrls(vhp, desc[3], 2001 r5u870_uvc_proc_ctrls, 2002 &desc[8], desc[7] * 8); 2003 if (res) 2004 return res; 2005 break; 2006 } 2007 } 2008 2009 return 0; 2010 } 2011 2012 2013 static void r5u870_do_stop(struct r5u870_ctx *vhp) 2014 { 2015 if (vhp->vh_parent->ud_capturing) { 2016 vhp->vh_parent->ud_capturing = 0; 2017 vhp->vh_ctrl_reg_enable = 0; 2018 2019 usbcam_urbstream_stop(&vhp->vh_iso, 0); 2020 usbcam_curframe_abortall(vhp->vh_parent); 2021 2022 if (!vhp->vh_parent->ud_disconnected) { 2023 usb_set_interface(r5u870_dev(vhp), 2024 vhp->vh_iso_ifnum, 2025 0); 2026 vhp->vh_cap_stop(vhp); 2027 } 2028 2029 usbcam_urbstream_cleanup(&vhp->vh_iso); 2030 } 2031 } 2032 2033 /* 2034 * As long as we are requested to capture, we keep the iso stream running. 2035 * If we are explicitly requested to stop, we halt. 2036 * If we run out of frame buffers to capture into, we halt. 2037 */ 2038 static void r5u870_iso_packet_done(struct usbcam_dev *udp, 2039 struct usbcam_urbstream *usp, 2040 const uint8_t *pktdata, 2041 int pktlen, int pktstatus) 2042 { 2043 struct r5u870_ctx *vhp = udp_r5u870(udp); 2044 struct usbcam_curframe cf; 2045 int res, start = 0; 2046 2047 res = vhp->vh_decide_pkt(vhp, pktstatus, pktlen, 2048 (u8 *) pktdata, &start); 2049 switch (res) { 2050 case -EPIPE: 2051 if (vhp->vh_framebuf_offset) { 2052 vhp->vh_framebuf_offset = 0; 2053 usbcam_curframe_testpattern(udp); 2054 usbcam_curframe_complete(udp); 2055 } 2056 break; 2057 2058 case 0: 2059 case -EAGAIN: 2060 if (pktlen) { 2061 if (usbcam_curframe_get(udp, &cf)) { 2062 /* 2063 * We have data, but there is no frame buffer 2064 * queued to accept it, so we stop. 2065 */ 2066 r5u870_do_stop(vhp); 2067 break; 2068 } 2069 2070 BUG_ON(pktlen - start + vhp->vh_framebuf_offset > 2071 cf.uf_size); 2072 2073 /* 2074 * This is our one and only memcpy. 2075 * It's kind of hard to get around doing this, as 2076 * we cannot predict into which isochronous 2077 * packets the camera will choose to return data. 2078 */ 2079 memcpy(cf.uf_base + vhp->vh_framebuf_offset, 2080 pktdata + start, 2081 pktlen - start); 2082 vhp->vh_framebuf_offset += (pktlen - start); 2083 } 2084 2085 if (!res) { 2086 vhp->vh_framebuf_offset = 0; 2087 usbcam_curframe_complete(udp); 2088 } 2089 break; 2090 2091 case -EIO: 2092 r5u870_do_stop(vhp); 2093 break; 2094 2095 default: 2096 BUG(); 2097 } 2098 } 2099 2100 static void r5u870_iso_submit_error(struct usbcam_dev *udp, 2101 struct usbcam_urbstream *usp, int status) 2102 { 2103 struct r5u870_ctx *vhp = udp_r5u870(udp); 2104 r5u_dbg(vhp, R5U_FRAME, "iso submit error: %d", status); 2105 r5u870_do_stop(vhp); 2106 } 2107 2108 static struct usbcam_urbstream_ops r5u870_urb_data_ops = { 2109 .packet_done = r5u870_iso_packet_done, 2110 .submit_error = r5u870_iso_submit_error, 2111 }; 2112 2113 2114 static void r5u870_usbcam_release(struct usbcam_dev *udp) 2115 { 2116 struct r5u870_ctx *vhp = udp_r5u870(udp); 2117 int i; 2118 2119 for (i = 0; i < vhp->vh_npixfmts; i++) { 2120 if (vhp->vh_pixfmts[i].rp_restbl_alloc) 2121 kfree(vhp->vh_pixfmts[i].rp_restbl); 2122 } 2123 } 2124 2125 2126 static const struct r5u870_model *r5u870_find_model(int driver_info); 2127 static int r5u870_usbcam_init(struct usbcam_dev *udp, 2128 const struct usb_device_id *devid) 2129 { 2130 struct r5u870_ctx *vhp; 2131 int model_info; 2132 int res; 2133 2134 model_info = devid->driver_info; 2135 2136 /* Initialize the private structure, don't use r5u_dbg() before this */ 2137 vhp = udp_r5u870(udp); 2138 memset(vhp, 0, sizeof(*vhp)); 2139 vhp->vh_parent = udp; 2140 vhp->vh_timeout = 1000; 2141 2142 vhp->vh_ctrl_ifnum = -1; 2143 vhp->vh_iso_ifnum = -1; 2144 vhp->vh_iso_minpacket = -1; 2145 2146 vhp->vh_model = r5u870_find_model(model_info); 2147 2148 if (!vhp->vh_model) { 2149 r5u_err(vhp, "no suitable model descriptor for %04x:%04x", 2150 le16_to_cpu(r5u870_dev(vhp)->descriptor.idVendor), 2151 le16_to_cpu(r5u870_dev(vhp)->descriptor.idProduct)); 2152 return -ENODEV; 2153 } 2154 2155 vhp->vh_pixfmts = vhp->vh_model->rm_pixfmts; 2156 vhp->vh_npixfmts = vhp->vh_model->rm_npixfmts; 2157 2158 if (vhp->vh_model->rm_uvc) { 2159 vhp->vh_set_fmt = r5u870_set_fmt_uvc; 2160 vhp->vh_cap_stop = r5u870_cap_stop_uvc; 2161 vhp->vh_decide_pkt = r5u870_decide_pkt_uvc; 2162 } else { 2163 vhp->vh_set_fmt = r5u870_set_fmt_wdm; 2164 vhp->vh_cap_stop = r5u870_cap_stop_wdm; 2165 vhp->vh_decide_pkt = r5u870_decide_pkt_wdm; 2166 } 2167 2168 r5u_info(vhp, "Detected %s", vhp->vh_model->rm_name); 2169 snprintf(vhp->vh_parent->ud_vdev.name, 2170 sizeof(vhp->vh_parent->ud_vdev.name), 2171 "%s #%d", 2172 vhp->vh_model->rm_name, vhp->vh_parent->ud_minidrv_id + 1); 2173 2174 res = r5u870_dev_init(vhp); 2175 if (res < 0) { 2176 r5u_err(vhp, "initialization failed: %d", res); 2177 goto out_failed; 2178 } 2179 2180 if (vhp->vh_model->rm_uvc) { 2181 /* 2182 * This appears to be a UVC VideoControl interface. 2183 * Claim all of the associated VideoStreaming interfaces 2184 * and configure the required endpoints and unit IDs 2185 */ 2186 res = r5u870_uvc_parse_vc(vhp); 2187 if (res < 0) { 2188 r5u_err(vhp, "UVC setup failed: %d", res); 2189 goto out_failed; 2190 } 2191 2192 } else { 2193 /* We are looking at a proprietary Ricoh interface */ 2194 vhp->vh_iso_ifnum = 2195 udp->ud_intf->altsetting->desc.bInterfaceNumber; 2196 vhp->vh_iso_ep = 6; 2197 } 2198 2199 if (vhp->vh_model->rm_wdm_ctrlids) { 2200 res = r5u870_wdm_add_ctrls(vhp, vhp->vh_model->rm_wdm_ctrlids); 2201 if (res < 0) { 2202 r5u_err(vhp, "Vendor control setup failed: %d", res); 2203 goto out_failed; 2204 } 2205 } 2206 2207 /* Configure the usbcam pixel format and control arrays */ 2208 if (!vhp->vh_npixfmts) { 2209 r5u_err(vhp, "No pixel formats detected"); 2210 res = -ENODEV; 2211 goto out_failed; 2212 } 2213 2214 udp->ud_fmt_array = &vhp->vh_pixfmts[0].base; 2215 udp->ud_fmt_array_elem_size = sizeof(vhp->vh_pixfmts[0]); 2216 udp->ud_fmt_array_len = vhp->vh_npixfmts; 2217 2218 if (!vhp->vh_model->rm_no_first_auto_suppress) 2219 vhp->vh_ctrl_auto_suppress = 1; 2220 2221 usbcam_urbstream_init(&vhp->vh_iso, udp, vhp->vh_iso_ep); 2222 2223 /* Set the default format */ 2224 vhp->vh_fmt = &vhp->vh_pixfmts[0]; 2225 vhp->vh_res = &vhp->vh_fmt->rp_restbl[0]; 2226 udp->ud_format.width = vhp->vh_res->rw_width; 2227 udp->ud_format.height = vhp->vh_res->rw_height; 2228 udp->ud_format.pixelformat = vhp->vh_fmt->base.pixelformat; 2229 udp->ud_format.field = V4L2_FIELD_INTERLACED; 2230 udp->ud_format.bytesperline = udp->ud_format.width * 2; 2231 udp->ud_format.sizeimage = (udp->ud_format.width * 2232 udp->ud_format.height * 2); 2233 udp->ud_format.colorspace = V4L2_COLORSPACE_SMPTE170M; 2234 2235 /* Configure default values for all controls */ 2236 res = r5u870_set_controls(vhp, 1); 2237 if (res < 0) { 2238 r5u_err(vhp, "set defaults failed: %d", res); 2239 goto out_failed; 2240 } 2241 2242 return 0; 2243 2244 out_failed: 2245 r5u870_usbcam_release(udp); 2246 return res; 2247 } 2248 2249 static void r5u870_usbcam_disconnect(struct usbcam_dev *udp) 2250 { 2251 struct r5u870_ctx *vhp = udp_r5u870(udp); 2252 r5u870_do_stop(vhp); 2253 } 2254 2255 2256 /* 2257 * The power management stuff doesn't quite work yet, so we don't 2258 * yet set the supports_autosuspend field in the ops structure. 2259 */ 2260 2261 static int r5u870_usbcam_suspend(struct usbcam_dev *udp, pm_message_t msg) 2262 { 2263 struct r5u870_ctx *vhp = udp_r5u870(udp); 2264 r5u870_do_stop(vhp); 2265 return 0; 2266 } 2267 2268 static int r5u870_usbcam_resume(struct usbcam_dev *udp) 2269 { 2270 struct r5u870_ctx *vhp = udp_r5u870(udp); 2271 int res; 2272 2273 res = r5u870_dev_init(vhp); 2274 if (res < 0) { 2275 r5u_err(vhp, "dev reinitialization failed: %d", res); 2276 return res; 2277 } 2278 2279 vhp->vh_configured = 0; 2280 2281 return 0; 2282 } 2283 2284 static int r5u870_try_format(struct usbcam_dev *udp, struct v4l2_pix_format *f, 2285 const struct r5u870_pix_fmt **fmt_out, 2286 const struct r5u870_resolution **res_out) 2287 { 2288 struct r5u870_ctx *vhp = udp_r5u870(udp); 2289 const struct r5u870_pix_fmt *fmt; 2290 const struct r5u870_resolution *res, *restbl; 2291 int i; 2292 2293 fmt = NULL; 2294 for (i = 0; i < vhp->vh_npixfmts; i++) { 2295 if (vhp->vh_pixfmts[i].base.pixelformat == f->pixelformat) { 2296 fmt = &vhp->vh_pixfmts[i]; 2297 break; 2298 } 2299 } 2300 if (fmt == NULL) 2301 return -EINVAL; 2302 2303 restbl = fmt->rp_restbl; 2304 if (!restbl || !restbl[0].rw_width) { 2305 r5u_err(vhp, "invalid resolution table"); 2306 return -EINVAL; 2307 } 2308 2309 /* Find the most acceptable resolution */ 2310 res = NULL; 2311 for (i = 0; restbl[i].rw_width > 0; i++) { 2312 if (!res) { 2313 res = &restbl[i]; 2314 } 2315 else if (res->rw_width > f->width) { 2316 if (restbl[i].rw_width < res->rw_width) 2317 res = &restbl[i]; 2318 } 2319 else if (res->rw_height > f->height) { 2320 if ((restbl[i].rw_width <= f->width) && 2321 (restbl[i].rw_height < res->rw_height)) 2322 res = &restbl[i]; 2323 } 2324 else if ((restbl[i].rw_width <= f->width) && 2325 (restbl[i].rw_height <= f->height) && 2326 ((restbl[i].rw_width > res->rw_width) || 2327 ((restbl[i].rw_width == res->rw_width) && 2328 (restbl[i].rw_height > res->rw_height)))) { 2329 res = &restbl[i]; 2330 } 2331 } 2332 2333 if ((f->width > 1) && (f->height > 1)) { 2334 r5u_dbg(vhp, R5U_INIT, "pix_fmt width: %d height: %d", f->width, f->height); 2335 r5u_dbg(vhp, R5U_INIT, "res width: %d height %d", res->rw_width, res->rw_height); 2336 2337 if (((res->rw_width > f->width) || (res->rw_height > f->height))) { 2338 r5u_dbg(vhp, R5U_INIT, "Bad size request. Returning -EINVAL."); 2339 return -EINVAL; 2340 } 2341 } 2342 2343 memset(f, 0, sizeof(*f)); 2344 f->width = res->rw_width; 2345 f->height = res->rw_height; 2346 f->pixelformat = fmt->base.pixelformat; 2347 f->bytesperline = f->width * 2; 2348 f->sizeimage = f->width * f->height * 2; 2349 f->field = V4L2_FIELD_INTERLACED; 2350 f->colorspace = V4L2_COLORSPACE_SMPTE170M; 2351 2352 r5u_dbg(vhp, R5U_INIT, "Settled on pixel format: %d (%s)", fmt->base.pixelformat, fmt->base.description); 2353 2354 if (fmt_out) 2355 (*fmt_out) = fmt; 2356 if (res_out) 2357 (*res_out) = res; 2358 2359 return 0; 2360 } 2361 2362 static int r5u870_usbcam_try_format(struct usbcam_dev *udp, 2363 struct v4l2_pix_format *f) 2364 { 2365 return r5u870_try_format(udp, f, NULL, NULL); 2366 } 2367 2368 static int r5u870_usbcam_set_format(struct usbcam_dev *udp, 2369 struct v4l2_pix_format *f) 2370 { 2371 struct r5u870_ctx *vhp = udp_r5u870(udp); 2372 const struct r5u870_pix_fmt *fmt_out; 2373 const struct r5u870_resolution *res_out; 2374 int res; 2375 2376 res = r5u870_try_format(udp, f, &fmt_out, &res_out); 2377 if (res) 2378 return res; 2379 2380 if ((udp->ud_format.width != f->width) || 2381 (udp->ud_format.height != f->height) || 2382 (udp->ud_format.pixelformat != f->pixelformat) || 2383 (udp->ud_format.sizeimage != f->sizeimage)) 2384 vhp->vh_configured = 0; 2385 2386 udp->ud_format = *f; 2387 vhp->vh_fmt = fmt_out; 2388 vhp->vh_res = res_out; 2389 return 0; 2390 } 2391 2392 static void r5u870_usbcam_cap_stop(struct usbcam_dev *udp) 2393 { 2394 struct r5u870_ctx *vhp = udp_r5u870(udp); 2395 r5u870_do_stop(vhp); 2396 } 2397 2398 static int r5u870_config_iso_ep(struct r5u870_ctx *vhp) 2399 { 2400 int res; 2401 2402 if (!vhp->vh_configured) { 2403 vhp->vh_ctrl_sync = 0; 2404 2405 res = usbcam_choose_altsetting(vhp->vh_parent, 2406 vhp->vh_iso_ifnum, 2407 usb_rcvisocpipe(r5u870_dev(vhp), 2408 vhp->vh_iso_ep), 2409 vhp->vh_res->rw_reqbw, 2410 vhp->vh_iso_minpacket, -1, 2411 &vhp->vh_act_altsetting); 2412 if (res) { 2413 r5u_err(vhp, "need %d B/s, no altsetting provides", 2414 vhp->vh_res->rw_reqbw); 2415 return res; 2416 } 2417 2418 r5u_dbg(vhp, R5U_FRAME, "using altsetting %d", 2419 vhp->vh_act_altsetting); 2420 } 2421 2422 res = usb_set_interface(r5u870_dev(vhp), vhp->vh_iso_ifnum, 2423 vhp->vh_act_altsetting); 2424 if (res) { 2425 r5u_err(vhp, "could not set altsetting: %d", res); 2426 return res; 2427 } 2428 2429 return 0; 2430 } 2431 2432 static int r5u870_usbcam_cap_start(struct usbcam_dev *udp) 2433 { 2434 struct r5u870_ctx *vhp = udp_r5u870(udp); 2435 int res; 2436 2437 if (vhp->vh_parent->ud_capturing) 2438 return 0; 2439 2440 if (!vhp->vh_model->rm_uvc) { 2441 res = r5u870_config_iso_ep(vhp); 2442 if (res) 2443 return res; 2444 } 2445 2446 vhp->vh_ctrl_reg_enable = 1; 2447 2448 if (!vhp->vh_configured) { 2449 r5u_dbg(vhp, R5U_MDINTF, "setting initial control values"); 2450 res = r5u870_set_controls(vhp, 0); 2451 if (res) 2452 goto out_set_idle; 2453 2454 res = vhp->vh_set_fmt(vhp, vhp->vh_fmt, vhp->vh_res); 2455 if (res) { 2456 r5u_err(vhp, "could not configure capture: %d", res); 2457 goto out_set_idle; 2458 } 2459 2460 if (vhp->vh_model->rm_no_ctrl_reload) 2461 vhp->vh_ctrl_sync = 1; 2462 } 2463 2464 if (vhp->vh_model->rm_uvc) { 2465 res = r5u870_config_iso_ep(vhp); 2466 if (res) 2467 goto out_set_idle; 2468 } 2469 2470 vhp->vh_configured = 1; 2471 2472 res = usbcam_urbstream_config_iso(&vhp->vh_iso, 2473 &r5u870_urb_data_ops, 2474 0, 0, 1, 0); 2475 if (res < 0) { 2476 r5u_err(vhp, "urbstream init failed: %d", res); 2477 goto out_set_idle; 2478 } 2479 2480 udp->ud_capturing = 1; 2481 2482 if (!vhp->vh_model->rm_uvc) { 2483 res = r5u870_set_cap_state_wdm(vhp, 1); 2484 if (res) 2485 goto out_cleanup_urbstream; 2486 } 2487 2488 if (!vhp->vh_ctrl_sync) { 2489 r5u_dbg(vhp, R5U_MDINTF, "reloading control values"); 2490 2491 /* Reload the control values after changing res/format */ 2492 res = r5u870_set_controls(vhp, 0); 2493 if (res) { 2494 r5u_err(vhp, "could not load control values: %d", res); 2495 goto out_stop_capture; 2496 } 2497 2498 vhp->vh_ctrl_sync = 1; 2499 } 2500 2501 if (res) 2502 goto out_failed; 2503 2504 r5u_dbg(vhp, R5U_MDINTF, "starting capture"); 2505 2506 vhp->vh_firstframe = 0; 2507 vhp->vh_frame_accum = -1; 2508 vhp->vh_framebuf_offset = 0; 2509 vhp->vh_emptypkts = R5U870_EMPTYPKT_FRAME_DELIM - 1; 2510 2511 res = usbcam_urbstream_start(&vhp->vh_iso); 2512 if (res) 2513 goto out_stop_capture; 2514 2515 return 0; 2516 2517 out_stop_capture: 2518 (void) vhp->vh_cap_stop(vhp); 2519 out_cleanup_urbstream: 2520 usbcam_urbstream_cleanup(&vhp->vh_iso); 2521 out_set_idle: 2522 (void) usb_set_interface(r5u870_dev(vhp), vhp->vh_iso_ifnum, 0); 2523 out_failed: 2524 vhp->vh_ctrl_reg_enable = 0; 2525 vhp->vh_parent->ud_capturing = 0; 2526 return res; 2527 } 2528 2529 static struct usbcam_dev_ops r5u870_usbcam_dev_ops = { 2530 .init = r5u870_usbcam_init, 2531 .disconnect = r5u870_usbcam_disconnect, 2532 .release = r5u870_usbcam_release, 2533 .suspend = r5u870_usbcam_suspend, 2534 .resume = r5u870_usbcam_resume, 2535 .try_format = r5u870_usbcam_try_format, 2536 .set_format = r5u870_usbcam_set_format, 2537 .cap_start = r5u870_usbcam_cap_start, 2538 .cap_stop = r5u870_usbcam_cap_stop, 2539 2540 /* .supports_autosuspend = 1, */ 2541 }; 2542 2543 2544 /* 2545 * Per-device hard coded vendor control lists follow 2546 */ 2547 2548 static const int r5u870_1830_ctrls[] = { 2549 R5U870_WDM_CTRL_BRIGHTNESS, 2550 R5U870_WDM_CTRL_CONTRAST, 2551 R5U870_WDM_CTRL_SATURATION, 2552 R5U870_WDM_CTRL_SHARPNESS, 2553 R5U870_WDM_CTRL_HUE, 2554 R5U870_WDM_CTRL_GAMMA, 2555 R5U870_WDM_CTRL_BACKLIGHT_COMP_500, 2556 R5U870_WDM_CTRL_WB_RED, 2557 R5U870_WDM_CTRL_WB_GREEN, 2558 R5U870_WDM_CTRL_WB_BLUE, 2559 R5U870_WDM_CTRL_WB_AUTO, 2560 R5U870_WDM_CTRL_GAIN, 2561 R5U870_WDM_CTRL_POWERLINE, 2562 R5U870_WDM_CTRL_VFLIP, 2563 R5U870_WDM_CTRL_HFLIP, 2564 R5U870_WDM_CTRL_PRIVACY, 2565 R5U870_WDM_CTRL_NIGHTMODE, 2566 R5U870_WDM_CTRL_LAST, 2567 }; 2568 static const int r5u870_1832_ctrls[] = { 2569 R5U870_WDM_CTRL_BRIGHTNESS, 2570 R5U870_WDM_CTRL_CONTRAST, 2571 R5U870_WDM_CTRL_HUE, 2572 R5U870_WDM_CTRL_SATURATION, 2573 R5U870_WDM_CTRL_BACKLIGHT_COMP_500_DEF1, 2574 R5U870_WDM_CTRL_POWERLINE, 2575 R5U870_WDM_CTRL_VFLIP, 2576 R5U870_WDM_CTRL_HFLIP, 2577 R5U870_WDM_CTRL_PRIVACY, 2578 R5U870_WDM_CTRL_NIGHTMODE, 2579 R5U870_WDM_CTRL_LAST, 2580 }; 2581 static const int r5u870_1833_ctrls[] = { 2582 R5U870_WDM_CTRL_BRIGHTNESS, 2583 R5U870_WDM_CTRL_CONTRAST, 2584 R5U870_WDM_CTRL_HUE, 2585 R5U870_WDM_CTRL_SATURATION, 2586 R5U870_WDM_CTRL_SHARPNESS, 2587 R5U870_WDM_CTRL_GAMMA, 2588 R5U870_WDM_CTRL_BACKLIGHT_COMP_500_DEF1, 2589 R5U870_WDM_CTRL_WB_RED, 2590 R5U870_WDM_CTRL_WB_GREEN, 2591 R5U870_WDM_CTRL_WB_BLUE, 2592 R5U870_WDM_CTRL_WB_AUTO, 2593 R5U870_WDM_CTRL_POWERLINE, 2594 R5U870_WDM_CTRL_VFLIP, 2595 R5U870_WDM_CTRL_HFLIP, 2596 R5U870_WDM_CTRL_PRIVACY, 2597 R5U870_WDM_CTRL_NIGHTMODE, 2598 R5U870_WDM_CTRL_LAST, 2599 }; 2600 static const int r5u870_1834_ctrls[] = { 2601 R5U870_WDM_CTRL_BRIGHTNESS, 2602 R5U870_WDM_CTRL_CONTRAST, 2603 R5U870_WDM_CTRL_HUE, 2604 R5U870_WDM_CTRL_SATURATION, 2605 R5U870_WDM_CTRL_SHARPNESS, 2606 R5U870_WDM_CTRL_GAMMA, 2607 R5U870_WDM_CTRL_BACKLIGHT_COMP_X1834, 2608 R5U870_WDM_CTRL_WB_AUTO, 2609 R5U870_WDM_CTRL_WB_RED, 2610 R5U870_WDM_CTRL_WB_BLUE, 2611 R5U870_WDM_CTRL_AUTO_EXPOSURE, 2612 R5U870_WDM_CTRL_EXPOSURE, 2613 R5U870_WDM_CTRL_AUTO_GAIN, 2614 R5U870_WDM_CTRL_GAIN, 2615 R5U870_WDM_CTRL_POWERLINE, 2616 R5U870_WDM_CTRL_VFLIP, 2617 R5U870_WDM_CTRL_HFLIP, 2618 R5U870_WDM_CTRL_PRIVACY, 2619 R5U870_WDM_CTRL_NIGHTMODE, 2620 R5U870_WDM_CTRL_LAST, 2621 }; 2622 static const int r5u870_1870_ctrls[] = { 2623 R5U870_WDM_CTRL_BRIGHTNESS, 2624 R5U870_WDM_CTRL_CONTRAST, 2625 R5U870_WDM_CTRL_HUE, 2626 R5U870_WDM_CTRL_SATURATION, 2627 R5U870_WDM_CTRL_SHARPNESS, 2628 R5U870_WDM_CTRL_GAMMA, 2629 R5U870_WDM_CTRL_WB_AUTO, 2630 R5U870_WDM_CTRL_WB_RED, 2631 R5U870_WDM_CTRL_WB_BLUE, 2632 R5U870_WDM_CTRL_AUTO_EXPOSURE, 2633 R5U870_WDM_CTRL_EXPOSURE, 2634 R5U870_WDM_CTRL_AUTO_GAIN, 2635 R5U870_WDM_CTRL_GAIN, 2636 R5U870_WDM_CTRL_POWERLINE, 2637 R5U870_WDM_CTRL_VFLIP, 2638 R5U870_WDM_CTRL_HFLIP, 2639 R5U870_WDM_CTRL_PRIVACY, 2640 R5U870_WDM_CTRL_NIGHTMODE, 2641 R5U870_WDM_CTRL_LAST, 2642 }; 2643 2644 /* 2645 * Even the UVC models do not express all of their controls in the UVC 2646 * descriptor tables, and get sets of hard-coded vendor controls 2647 */ 2648 2649 // FIXME: This device still has a bunch of unknown control IDs. 2650 static const int r5u870_1812_ctrls[] = { 2651 R5U870_WDM_CTRL_WB_RED, 2652 R5U870_WDM_CTRL_WB_GREEN, 2653 R5U870_WDM_CTRL_WB_BLUE, 2654 R5U870_WDM_CTRL_VFLIP, 2655 R5U870_WDM_CTRL_HFLIP, 2656 R5U870_WDM_CTRL_PRIVACY, 2657 R5U870_WDM_CTRL_LAST, 2658 }; 2659 static const int r5u870_1835_ctrls[] = { 2660 R5U870_WDM_CTRL_WB_RED, 2661 R5U870_WDM_CTRL_WB_GREEN, 2662 R5U870_WDM_CTRL_WB_BLUE, 2663 R5U870_WDM_CTRL_WB_AUTO, 2664 R5U870_WDM_CTRL_VFLIP, 2665 R5U870_WDM_CTRL_HFLIP, 2666 R5U870_WDM_CTRL_PRIVACY, 2667 R5U870_WDM_CTRL_LAST, 2668 }; 2669 static const int r5u870_1810_1836_ctrls[] = { 2670 R5U870_WDM_CTRL_WB_AUTO, 2671 R5U870_WDM_CTRL_WB_RED, 2672 R5U870_WDM_CTRL_WB_BLUE, 2673 R5U870_WDM_CTRL_AUTO_EXPOSURE, 2674 R5U870_WDM_CTRL_EXPOSURE, 2675 R5U870_WDM_CTRL_AUTO_GAIN, 2676 R5U870_WDM_CTRL_GAIN, 2677 R5U870_WDM_CTRL_VFLIP, 2678 R5U870_WDM_CTRL_HFLIP, 2679 R5U870_WDM_CTRL_PRIVACY, 2680 R5U870_WDM_CTRL_NIGHTMODE, 2681 R5U870_WDM_CTRL_LAST, 2682 }; 2683 static const int r5u870_1810_1837_ctrls[] = { 2684 R5U870_WDM_CTRL_WB_AUTO, 2685 R5U870_WDM_CTRL_WB_RED, 2686 R5U870_WDM_CTRL_WB_BLUE, 2687 R5U870_WDM_CTRL_AUTO_EXPOSURE, 2688 R5U870_WDM_CTRL_EXPOSURE, 2689 R5U870_WDM_CTRL_AUTO_GAIN, 2690 R5U870_WDM_CTRL_GAIN, 2691 R5U870_WDM_CTRL_VFLIP_DEFAULTON, 2692 R5U870_WDM_CTRL_HFLIP, 2693 R5U870_WDM_CTRL_PRIVACY, 2694 R5U870_WDM_CTRL_NIGHTMODE, 2695 R5U870_WDM_CTRL_LAST, 2696 }; 2697 static const int r5u870_1810_183a_ctrls[] = { 2698 R5U870_WDM_CTRL_WB_RED, 2699 R5U870_WDM_CTRL_WB_GREEN, 2700 R5U870_WDM_CTRL_WB_BLUE, 2701 R5U870_WDM_CTRL_WB_AUTO, 2702 R5U870_WDM_CTRL_VFLIP, 2703 R5U870_WDM_CTRL_HFLIP, 2704 R5U870_WDM_CTRL_PRIVACY, 2705 R5U870_WDM_CTRL_NIGHTMODE, 2706 R5U870_WDM_CTRL_LAST, 2707 }; 2708 static const int r5u870_1810_183b_ctrls[] = { 2709 /* TODO: Maybe there are more of these? I don't actually have a webcam 2710 to test against the different WDM controls. */ 2711 R5U870_WDM_CTRL_WB_RED, 2712 R5U870_WDM_CTRL_WB_GREEN, 2713 R5U870_WDM_CTRL_WB_BLUE, 2714 R5U870_WDM_CTRL_WB_AUTO, 2715 R5U870_WDM_CTRL_VFLIP, 2716 R5U870_WDM_CTRL_HFLIP, 2717 R5U870_WDM_CTRL_PRIVACY, 2718 R5U870_WDM_CTRL_NIGHTMODE, 2719 R5U870_WDM_CTRL_LAST, 2720 }; 2721 static const int r5u870_1810_183e_ctrls[] = { 2722 /* TODO: Maybe there are more of these? I don't actually have a webcam 2723 to test against the different WDM controls. */ 2724 R5U870_WDM_CTRL_WB_RED, 2725 R5U870_WDM_CTRL_WB_GREEN, 2726 R5U870_WDM_CTRL_WB_BLUE, 2727 R5U870_WDM_CTRL_WB_AUTO, 2728 R5U870_WDM_CTRL_VFLIP, 2729 R5U870_WDM_CTRL_HFLIP, 2730 R5U870_WDM_CTRL_PRIVACY, 2731 R5U870_WDM_CTRL_NIGHTMODE, 2732 R5U870_WDM_CTRL_LAST, 2733 }; 2734 static const int r5u870_1810_1839_ctrls[] = { 2735 /* TODO: Maybe there are more of these? I don't actually have a webcam 2736 to test against the different WDM controls. */ 2737 R5U870_WDM_CTRL_WB_RED, 2738 R5U870_WDM_CTRL_WB_GREEN, 2739 R5U870_WDM_CTRL_WB_BLUE, 2740 R5U870_WDM_CTRL_WB_AUTO, 2741 R5U870_WDM_CTRL_VFLIP, 2742 R5U870_WDM_CTRL_HFLIP, 2743 R5U870_WDM_CTRL_PRIVACY, 2744 R5U870_WDM_CTRL_LAST, 2745 }; 2746 2747 static const int r5u870_1841_ctrls[] = { 2748 /* TODO: Maybe there are more of these? I don't actually have a webcam 2749 to test against the different WDM controls. */ 2750 R5U870_WDM_CTRL_WB_RED, 2751 R5U870_WDM_CTRL_WB_GREEN, 2752 R5U870_WDM_CTRL_WB_BLUE, 2753 R5U870_WDM_CTRL_WB_AUTO, 2754 R5U870_WDM_CTRL_VFLIP, 2755 R5U870_WDM_CTRL_HFLIP, 2756 R5U870_WDM_CTRL_PRIVACY, 2757 R5U870_WDM_CTRL_LAST, 2758 }; 2759 2760 2761 /* 2762 * Standard resolution table for non-UVC cameras, 2763 * as UVC camera report back as to what resolutions 2764 * they support. 2765 * The Sony VGP-VCC2 Windows driver supports: 2766 * 160x120, 176x144, 320x240, 352x288, 640x480 2767 * The HP driver also supports 1280x1024 2768 */ 2769 static const struct r5u870_resolution r5u870_vga_wdm_res[] = { 2770 { 160, 120, 1152000 }, 2771 { 176, 144, 1520640 }, 2772 { 320, 240, 4608000 }, 2773 { 352, 288, 6082560 }, 2774 { 640, 480, 18432000 }, 2775 { } 2776 }; 2777 static const struct r5u870_resolution r5u870_sxga_wdm_res[] = { 2778 { 160, 120, 1152000 }, 2779 { 176, 144, 1520640 }, 2780 { 320, 240, 4608000 }, 2781 { 352, 288, 6082560 }, 2782 { 640, 480, 18432000 }, 2783 { 1280, 1024, 19660800 }, 2784 { } 2785 }; 2786 static struct r5u870_pix_fmt r5u870_vga_wdm_pixfmts[] = { 2787 { .base = { .description = "YUY2 4:2:2", 2788 .pixelformat = V4L2_PIX_FMT_YUYV, 2789 .flags = 0 }, 2790 .rp_formatidx = 0, 2791 .rp_restbl = r5u870_vga_wdm_res }, 2792 2793 { .base = { .description = "UYVY 4:2:2", 2794 .pixelformat = V4L2_PIX_FMT_UYVY, 2795 .flags = 0 }, 2796 .rp_formatidx = 1, 2797 .rp_restbl = r5u870_vga_wdm_res }, 2798 }; 2799 static struct r5u870_pix_fmt r5u870_sxga_wdm_pixfmts[] = { 2800 { .base = { .description = "YUY2 4:2:2", 2801 .pixelformat = V4L2_PIX_FMT_YUYV, 2802 .flags = 0 }, 2803 .rp_formatidx = 0, 2804 .rp_restbl = r5u870_sxga_wdm_res }, 2805 2806 { .base = { .description = "UYVY 4:2:2", 2807 .pixelformat = V4L2_PIX_FMT_UYVY, 2808 .flags = 0 }, 2809 .rp_formatidx = 1, 2810 .rp_restbl = r5u870_sxga_wdm_res }, 2811 }; 2812 2813 enum { 2814 R5U870_DI_INVALID, 2815 R5U870_DI_VGP_VCC2_SZ, 2816 R5U870_DI_VGP_VCC3, 2817 R5U870_DI_VGP_VCC2_AR1, 2818 R5U870_DI_VGP_VCC2_AR2, 2819 R5U870_DI_VGP_VCC5, 2820 R5U870_DI_VGP_VCC4, 2821 R5U870_DI_VGP_VCC4_VFLIP, 2822 R5U870_DI_VGP_VCC6, 2823 R5U870_DI_VGP_VCC7, 2824 R5U870_DI_VGP_VCC8, 2825 R5U870_DI_VGP_VCC9, 2826 R5U870_DI_HP_WEBCAM1K, 2827 R5U870_DI_HP_PAVWC_WDM, 2828 R5U870_DI_HP_PAVWC_UVC, 2829 R5U870_DI_HP_PAVWC_UVC_NOFW, 2830 R5U870_DI_GENERIC_UVC, 2831 R5U870_DI_FUJITSU, 2832 }; 2833 2834 static const struct r5u870_model r5u870_models[] = { 2835 [R5U870_DI_VGP_VCC2_SZ] = { 2836 .rm_name = "Sony VGP-VCC2 (VAIO SZ)", 2837 .rm_ucode_file = "r5u870_1830.fw", 2838 .rm_ucode_version = 0x0100, 2839 .rm_wdm_ctrlids = r5u870_1830_ctrls, 2840 .rm_pixfmts = r5u870_vga_wdm_pixfmts, 2841 .rm_npixfmts = ARRAY_SIZE(r5u870_vga_wdm_pixfmts), 2842 }, 2843 [R5U870_DI_VGP_VCC3] = { 2844 .rm_name = "Sony VGP-VCC3", 2845 .rm_ucode_file = "r5u870_1832.fw", 2846 .rm_ucode_version = 0x0100, 2847 .rm_wdm_ctrlids = r5u870_1832_ctrls, 2848 .rm_pixfmts = r5u870_vga_wdm_pixfmts, 2849 .rm_npixfmts = ARRAY_SIZE(r5u870_vga_wdm_pixfmts), 2850 .rm_no_ctrl_reload = 1, 2851 }, 2852 [R5U870_DI_VGP_VCC2_AR1] = { 2853 .rm_name = "Sony VGP-VCC2 (VAIO AR1)", 2854 .rm_ucode_file = "r5u870_1833.fw", 2855 .rm_ucode_version = 0x0100, 2856 .rm_wdm_ctrlids = r5u870_1833_ctrls, 2857 .rm_pixfmts = r5u870_vga_wdm_pixfmts, 2858 .rm_npixfmts = ARRAY_SIZE(r5u870_vga_wdm_pixfmts), 2859 }, 2860 [R5U870_DI_VGP_VCC2_AR2] = { 2861 .rm_name = "Sony VGP-VCC2 (VAIO AR)", 2862 .rm_ucode_file = "r5u870_1834.fw", 2863 .rm_ucode_version = 0x0111, 2864 .rm_wdm_ctrlids = r5u870_1834_ctrls, 2865 .rm_pixfmts = r5u870_vga_wdm_pixfmts, 2866 .rm_npixfmts = ARRAY_SIZE(r5u870_vga_wdm_pixfmts), 2867 }, 2868 [R5U870_DI_VGP_VCC5] = { 2869 .rm_name = "Sony VGP-VCC5", 2870 .rm_ucode_file = "r5u870_1835.fw", 2871 .rm_ucode_version = 0x0107, 2872 .rm_wdm_ctrlids = r5u870_1835_ctrls, 2873 .rm_uvc = 1, 2874 }, 2875 [R5U870_DI_VGP_VCC4] = { 2876 .rm_name = "Sony VGP-VCC4", 2877 .rm_ucode_file = "r5u870_1836.fw", 2878 .rm_ucode_version = 0x0115, 2879 .rm_wdm_ctrlids = r5u870_1810_1836_ctrls, 2880 .rm_uvc = 1, 2881 }, 2882 [R5U870_DI_VGP_VCC4_VFLIP] = { 2883 .rm_name = "Sony VGP-VCC4", 2884 .rm_ucode_file = "r5u870_1836.fw", 2885 .rm_ucode_version = 0x0115, 2886 .rm_wdm_ctrlids = r5u870_1810_1837_ctrls, 2887 .rm_uvc = 1, 2888 }, 2889 [R5U870_DI_VGP_VCC6] = { 2890 .rm_name = "Sony VGP-VCC6", 2891 .rm_ucode_file = "r5u870_1839.fw", 2892 .rm_ucode_version = 0x0113, 2893 .rm_wdm_ctrlids = r5u870_1810_1839_ctrls, 2894 .rm_uvc = 1, 2895 }, 2896 [R5U870_DI_VGP_VCC7] = { 2897 .rm_name = "Sony VGP-VCC7", 2898 .rm_ucode_file = "r5u870_183a.fw", 2899 .rm_ucode_version = 0x0111, 2900 .rm_wdm_ctrlids = r5u870_1810_183a_ctrls, 2901 .rm_uvc = 1, 2902 }, 2903 [R5U870_DI_VGP_VCC8] = { 2904 .rm_name = "Sony VGP-VCC8", 2905 .rm_ucode_file = "r5u870_183b.fw", 2906 .rm_ucode_version = 0x0131, 2907 .rm_wdm_ctrlids = r5u870_1810_183b_ctrls, 2908 .rm_uvc = 1, 2909 }, 2910 [R5U870_DI_VGP_VCC9] = { 2911 .rm_name = "Sony VGP-VCC9", 2912 .rm_ucode_file = "r5u870_183e.fw", 2913 .rm_ucode_version = 0x0100, 2914 .rm_wdm_ctrlids = r5u870_1810_183e_ctrls, 2915 .rm_uvc = 1, 2916 }, 2917 [R5U870_DI_FUJITSU] = { 2918 .rm_name = "Fujitsu F01", 2919 .rm_ucode_file = "r5u870_1841.fw", 2920 .rm_ucode_version = 0x0103, 2921 .rm_wdm_ctrlids = r5u870_1841_ctrls, 2922 .rm_uvc = 1, 2923 }, 2924 [R5U870_DI_HP_WEBCAM1K] = { 2925 .rm_name = "HP Webcam 1000", 2926 .rm_ucode_file = "r5u870_1870_1.fw", 2927 .rm_ucode_version = 0x0100, 2928 .rm_wdm_ctrlids = r5u870_1870_ctrls, 2929 .rm_pixfmts = r5u870_vga_wdm_pixfmts, 2930 .rm_npixfmts = ARRAY_SIZE(r5u870_vga_wdm_pixfmts), 2931 }, 2932 [R5U870_DI_HP_PAVWC_WDM] = { 2933 .rm_name = "HP Pavilion Webcam (WDM)", 2934 .rm_ucode_file = "r5u870_1870.fw", 2935 .rm_ucode_version = 0x0112, 2936 .rm_wdm_ctrlids = r5u870_1870_ctrls, 2937 .rm_pixfmts = r5u870_sxga_wdm_pixfmts, 2938 .rm_npixfmts = ARRAY_SIZE(r5u870_sxga_wdm_pixfmts), 2939 .rm_no_ctrl_reload = 1, 2940 }, 2941 [R5U870_DI_HP_PAVWC_UVC] = { 2942 .rm_name = "HP Pavilion Webcam (UVC)", 2943 .rm_ucode_file = "r5u870_1810.fw", 2944 .rm_ucode_version = 0x0115, 2945 .rm_wdm_ctrlids = r5u870_1810_1836_ctrls, 2946 .rm_uvc = 1, 2947 .rm_no_ctrl_reload = 1, 2948 }, 2949 [R5U870_DI_HP_PAVWC_UVC_NOFW] = { 2950 .rm_name = "HP Pavilion Webcam (UVC - NO FW)", 2951 .rm_wdm_ctrlids = r5u870_1812_ctrls, 2952 .rm_uvc = 1, 2953 .rm_no_ctrl_reload = 1, 2954 }, 2955 [R5U870_DI_GENERIC_UVC] = { 2956 .rm_name = "Generic UVC Webcam", 2957 .rm_uvc = 1, 2958 }, 2959 }; 2960 2961 /* 2962 * Someone clever at HP decided to use 05ca:1870 for two distinct devices. 2963 * The Pavilion dv1xxx machines all seem to have the less common of the 2964 * two. There is no known, working method to distinguish the devices 2965 * using USB commands only. We resort to reading the model number out 2966 * of DMI. 2967 */ 2968 static int dv1000 = 2; 2969 module_param(dv1000, int, S_IRUGO|S_IWUSR); 2970 MODULE_PARM_DESC(dv1000, "HP dv1000 detect mode (0=no,1=yes,2=DMI)"); 2971 2972 static int r5u870_check_hp_dv1000(void) 2973 { 2974 const char *prod_name; 2975 if (!dv1000) 2976 return 0; 2977 if (dv1000 == 1) 2978 return 1; 2979 prod_name = dmi_get_system_info(DMI_PRODUCT_NAME); 2980 if (!prod_name) 2981 printk(KERN_INFO "r5u870: No DMI model found\n"); 2982 else { 2983 printk(KERN_INFO "r5u870: Found DMI model: \"%s\"\n", 2984 prod_name); 2985 if (!strncmp(prod_name, "HP Pavilion dv1000", 18) && 2986 !isdigit(prod_name[18])) 2987 return 1; 2988 } 2989 return 0; 2990 } 2991 2992 static const struct r5u870_model *r5u870_find_model(int driver_info) 2993 { 2994 if (driver_info == R5U870_DI_HP_PAVWC_WDM) { 2995 if (r5u870_check_hp_dv1000()) 2996 driver_info = R5U870_DI_HP_WEBCAM1K; 2997 } 2998 if ((driver_info <= R5U870_DI_INVALID) || 2999 (driver_info >= ARRAY_SIZE(r5u870_models))) 3000 return NULL; 3001 if (!r5u870_models[driver_info].rm_name) 3002 return NULL; 3003 return &r5u870_models[driver_info]; 3004 } 3005 3006 3007 #define R5U870_DEVICE_UVC(VID, PID, DINFO) \ 3008 .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ 3009 | USB_DEVICE_ID_MATCH_INT_INFO, \ 3010 .idVendor = (VID), \ 3011 .idProduct = (PID), \ 3012 .bInterfaceClass = USB_CLASS_VIDEO, \ 3013 .bInterfaceSubClass = 1, \ 3014 .bInterfaceProtocol = 0, \ 3015 .driver_info = (DINFO) 3016 3017 static const struct usb_device_id id_table[] = { 3018 { USB_DEVICE(0x05CA, 0x1830), .driver_info = R5U870_DI_VGP_VCC2_SZ }, 3019 { USB_DEVICE(0x05CA, 0x1832), .driver_info = R5U870_DI_VGP_VCC3 }, 3020 { USB_DEVICE(0x05CA, 0x1833), .driver_info = R5U870_DI_VGP_VCC2_AR1 }, 3021 { USB_DEVICE(0x05CA, 0x1834), .driver_info = R5U870_DI_VGP_VCC2_AR2 }, 3022 { USB_DEVICE(0x05CA, 0x1870), .driver_info = R5U870_DI_HP_PAVWC_WDM }, 3023 3024 { R5U870_DEVICE_UVC(0x05CA, 0x1810, R5U870_DI_HP_PAVWC_UVC) }, 3025 { R5U870_DEVICE_UVC(0x05CA, 0x1812, R5U870_DI_HP_PAVWC_UVC_NOFW) }, 3026 { R5U870_DEVICE_UVC(0x05CA, 0x1835, R5U870_DI_VGP_VCC5) }, 3027 { R5U870_DEVICE_UVC(0x05CA, 0x1836, R5U870_DI_VGP_VCC4) }, 3028 { R5U870_DEVICE_UVC(0x05CA, 0x1837, R5U870_DI_VGP_VCC4_VFLIP) }, 3029 /* 0x1838 does not appear to have ever been released */ 3030 { R5U870_DEVICE_UVC(0x05CA, 0x1839, R5U870_DI_VGP_VCC6) }, 3031 { R5U870_DEVICE_UVC(0x05CA, 0x183a, R5U870_DI_VGP_VCC7) }, 3032 { R5U870_DEVICE_UVC(0x05CA, 0x183b, R5U870_DI_VGP_VCC8) }, 3033 { R5U870_DEVICE_UVC(0x05CA, 0x183e, R5U870_DI_VGP_VCC9) }, 3034 { R5U870_DEVICE_UVC(0x05CA, 0x1841, R5U870_DI_FUJITSU) }, 3035 { }, 3036 }; 3037 3038 3039 DEFINE_USBCAM_MINIDRV_MODULE(R5U870_VERSION, R5U870_VERSION_EXTRA, 3040 &r5u870_usbcam_dev_ops, 3041 sizeof(struct r5u870_ctx), 3042 id_table) 3043 3044 MODULE_DEVICE_TABLE(usb, id_table); 3045 MODULE_DESCRIPTION("Driver for Ricoh R5U870-based Webcams"); 3046 MODULE_AUTHOR("Sam Revitch <samr7@cs.washington.edu>"); 3047 MODULE_LICENSE("GPL");