r5u870

Ricoh R5U870 Linux Driver
git clone https://logand.com/git/r5u870.git/
Log | Files | Refs | README | LICENSE

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");