xref: /linux/drivers/media/usb/gspca/sn9c2028.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25bdd00b9STheodore Kilgore /*
35bdd00b9STheodore Kilgore  * SN9C2028 library
45bdd00b9STheodore Kilgore  *
55bdd00b9STheodore Kilgore  * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
65bdd00b9STheodore Kilgore  */
75bdd00b9STheodore Kilgore 
8133a9fe9SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9133a9fe9SJoe Perches 
105bdd00b9STheodore Kilgore #define MODULE_NAME "sn9c2028"
115bdd00b9STheodore Kilgore 
125bdd00b9STheodore Kilgore #include "gspca.h"
135bdd00b9STheodore Kilgore 
145bdd00b9STheodore Kilgore MODULE_AUTHOR("Theodore Kilgore");
155bdd00b9STheodore Kilgore MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
165bdd00b9STheodore Kilgore MODULE_LICENSE("GPL");
175bdd00b9STheodore Kilgore 
185bdd00b9STheodore Kilgore /* specific webcam descriptor */
195bdd00b9STheodore Kilgore struct sd {
205bdd00b9STheodore Kilgore 	struct gspca_dev gspca_dev;  /* !! must be the first item */
215bdd00b9STheodore Kilgore 	u8 sof_read;
225bdd00b9STheodore Kilgore 	u16 model;
23d8fd9f56SVasily Khoruzhick 
24d8fd9f56SVasily Khoruzhick #define MIN_AVG_LUM 8500
25d8fd9f56SVasily Khoruzhick #define MAX_AVG_LUM 10000
26d8fd9f56SVasily Khoruzhick 	int avg_lum;
27d8fd9f56SVasily Khoruzhick 	u8 avg_lum_l;
28d8fd9f56SVasily Khoruzhick 
29d8fd9f56SVasily Khoruzhick 	struct { /* autogain and gain control cluster */
30d8fd9f56SVasily Khoruzhick 		struct v4l2_ctrl *autogain;
31d8fd9f56SVasily Khoruzhick 		struct v4l2_ctrl *gain;
32d8fd9f56SVasily Khoruzhick 	};
335bdd00b9STheodore Kilgore };
345bdd00b9STheodore Kilgore 
355bdd00b9STheodore Kilgore struct init_command {
365bdd00b9STheodore Kilgore 	unsigned char instruction[6];
375bdd00b9STheodore Kilgore 	unsigned char to_read; /* length to read. 0 means no reply requested */
385bdd00b9STheodore Kilgore };
395bdd00b9STheodore Kilgore 
405bdd00b9STheodore Kilgore /* How to change the resolution of any of the VGA cams is unknown */
415bdd00b9STheodore Kilgore static const struct v4l2_pix_format vga_mode[] = {
425bdd00b9STheodore Kilgore 	{640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
435bdd00b9STheodore Kilgore 		.bytesperline = 640,
445bdd00b9STheodore Kilgore 		.sizeimage = 640 * 480 * 3 / 4,
455bdd00b9STheodore Kilgore 		.colorspace = V4L2_COLORSPACE_SRGB,
465bdd00b9STheodore Kilgore 		.priv = 0},
475bdd00b9STheodore Kilgore };
485bdd00b9STheodore Kilgore 
495bdd00b9STheodore Kilgore /* No way to change the resolution of the CIF cams is known */
505bdd00b9STheodore Kilgore static const struct v4l2_pix_format cif_mode[] = {
515bdd00b9STheodore Kilgore 	{352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
525bdd00b9STheodore Kilgore 		.bytesperline = 352,
535bdd00b9STheodore Kilgore 		.sizeimage = 352 * 288 * 3 / 4,
545bdd00b9STheodore Kilgore 		.colorspace = V4L2_COLORSPACE_SRGB,
555bdd00b9STheodore Kilgore 		.priv = 0},
565bdd00b9STheodore Kilgore };
575bdd00b9STheodore Kilgore 
585bdd00b9STheodore Kilgore /* the bytes to write are in gspca_dev->usb_buf */
595bdd00b9STheodore Kilgore static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
605bdd00b9STheodore Kilgore {
615bdd00b9STheodore Kilgore 	int rc;
625bdd00b9STheodore Kilgore 
6337d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_USBO, "sending command %02x%02x%02x%02x%02x%02x\n",
6437d5efb0SJoe Perches 		  command[0], command[1], command[2],
6537d5efb0SJoe Perches 		  command[3], command[4], command[5]);
665bdd00b9STheodore Kilgore 
675bdd00b9STheodore Kilgore 	memcpy(gspca_dev->usb_buf, command, 6);
685bdd00b9STheodore Kilgore 	rc = usb_control_msg(gspca_dev->dev,
695bdd00b9STheodore Kilgore 			usb_sndctrlpipe(gspca_dev->dev, 0),
705bdd00b9STheodore Kilgore 			USB_REQ_GET_CONFIGURATION,
715bdd00b9STheodore Kilgore 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
725bdd00b9STheodore Kilgore 			2, 0, gspca_dev->usb_buf, 6, 500);
735bdd00b9STheodore Kilgore 	if (rc < 0) {
74133a9fe9SJoe Perches 		pr_err("command write [%02x] error %d\n",
755bdd00b9STheodore Kilgore 		       gspca_dev->usb_buf[0], rc);
765bdd00b9STheodore Kilgore 		return rc;
775bdd00b9STheodore Kilgore 	}
785bdd00b9STheodore Kilgore 
795bdd00b9STheodore Kilgore 	return 0;
805bdd00b9STheodore Kilgore }
815bdd00b9STheodore Kilgore 
825bdd00b9STheodore Kilgore static int sn9c2028_read1(struct gspca_dev *gspca_dev)
835bdd00b9STheodore Kilgore {
845bdd00b9STheodore Kilgore 	int rc;
855bdd00b9STheodore Kilgore 
865bdd00b9STheodore Kilgore 	rc = usb_control_msg(gspca_dev->dev,
875bdd00b9STheodore Kilgore 			usb_rcvctrlpipe(gspca_dev->dev, 0),
885bdd00b9STheodore Kilgore 			USB_REQ_GET_STATUS,
895bdd00b9STheodore Kilgore 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
905bdd00b9STheodore Kilgore 			1, 0, gspca_dev->usb_buf, 1, 500);
915bdd00b9STheodore Kilgore 	if (rc != 1) {
92133a9fe9SJoe Perches 		pr_err("read1 error %d\n", rc);
935bdd00b9STheodore Kilgore 		return (rc < 0) ? rc : -EIO;
945bdd00b9STheodore Kilgore 	}
9537d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_USBI, "read1 response %02x\n",
9637d5efb0SJoe Perches 		  gspca_dev->usb_buf[0]);
975bdd00b9STheodore Kilgore 	return gspca_dev->usb_buf[0];
985bdd00b9STheodore Kilgore }
995bdd00b9STheodore Kilgore 
1005bdd00b9STheodore Kilgore static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
1015bdd00b9STheodore Kilgore {
1025bdd00b9STheodore Kilgore 	int rc;
1035bdd00b9STheodore Kilgore 	rc = usb_control_msg(gspca_dev->dev,
1045bdd00b9STheodore Kilgore 			usb_rcvctrlpipe(gspca_dev->dev, 0),
1055bdd00b9STheodore Kilgore 			USB_REQ_GET_STATUS,
1065bdd00b9STheodore Kilgore 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1075bdd00b9STheodore Kilgore 			4, 0, gspca_dev->usb_buf, 4, 500);
1085bdd00b9STheodore Kilgore 	if (rc != 4) {
109133a9fe9SJoe Perches 		pr_err("read4 error %d\n", rc);
1105bdd00b9STheodore Kilgore 		return (rc < 0) ? rc : -EIO;
1115bdd00b9STheodore Kilgore 	}
1125bdd00b9STheodore Kilgore 	memcpy(reading, gspca_dev->usb_buf, 4);
11337d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_USBI, "read4 response %02x%02x%02x%02x\n",
11437d5efb0SJoe Perches 		  reading[0], reading[1], reading[2], reading[3]);
1155bdd00b9STheodore Kilgore 	return rc;
1165bdd00b9STheodore Kilgore }
1175bdd00b9STheodore Kilgore 
1185bdd00b9STheodore Kilgore static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
1195bdd00b9STheodore Kilgore {
1205bdd00b9STheodore Kilgore 	int i, status;
1215bdd00b9STheodore Kilgore 	__u8 reading[4];
1225bdd00b9STheodore Kilgore 
1235bdd00b9STheodore Kilgore 	status = sn9c2028_command(gspca_dev, command);
1245bdd00b9STheodore Kilgore 	if (status < 0)
1255bdd00b9STheodore Kilgore 		return status;
1265bdd00b9STheodore Kilgore 
1275bdd00b9STheodore Kilgore 	status = -1;
1285bdd00b9STheodore Kilgore 	for (i = 0; i < 256 && status < 2; i++)
1295bdd00b9STheodore Kilgore 		status = sn9c2028_read1(gspca_dev);
13048c291edSVasily Khoruzhick 	if (status < 0) {
131133a9fe9SJoe Perches 		pr_err("long command status read error %d\n", status);
1320a2a89c4SDan Carpenter 		return status;
1335bdd00b9STheodore Kilgore 	}
1345bdd00b9STheodore Kilgore 
1355bdd00b9STheodore Kilgore 	memset(reading, 0, 4);
1365bdd00b9STheodore Kilgore 	status = sn9c2028_read4(gspca_dev, reading);
1375bdd00b9STheodore Kilgore 	if (status < 0)
1385bdd00b9STheodore Kilgore 		return status;
1395bdd00b9STheodore Kilgore 
1405bdd00b9STheodore Kilgore 	/* in general, the first byte of the response is the first byte of
1415bdd00b9STheodore Kilgore 	 * the command, or'ed with 8 */
1425bdd00b9STheodore Kilgore 	status = sn9c2028_read1(gspca_dev);
1435bdd00b9STheodore Kilgore 	if (status < 0)
1445bdd00b9STheodore Kilgore 		return status;
1455bdd00b9STheodore Kilgore 
1465bdd00b9STheodore Kilgore 	return 0;
1475bdd00b9STheodore Kilgore }
1485bdd00b9STheodore Kilgore 
1495bdd00b9STheodore Kilgore static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)
1505bdd00b9STheodore Kilgore {
1515bdd00b9STheodore Kilgore 	int err_code;
1525bdd00b9STheodore Kilgore 
1535bdd00b9STheodore Kilgore 	err_code = sn9c2028_command(gspca_dev, command);
1545bdd00b9STheodore Kilgore 	if (err_code < 0)
1555bdd00b9STheodore Kilgore 		return err_code;
1565bdd00b9STheodore Kilgore 
1575bdd00b9STheodore Kilgore 	err_code = sn9c2028_read1(gspca_dev);
1585bdd00b9STheodore Kilgore 	if (err_code < 0)
1595bdd00b9STheodore Kilgore 		return err_code;
1605bdd00b9STheodore Kilgore 
1615bdd00b9STheodore Kilgore 	return 0;
1625bdd00b9STheodore Kilgore }
1635bdd00b9STheodore Kilgore 
1645bdd00b9STheodore Kilgore /* this function is called at probe time */
1655bdd00b9STheodore Kilgore static int sd_config(struct gspca_dev *gspca_dev,
1665bdd00b9STheodore Kilgore 		     const struct usb_device_id *id)
1675bdd00b9STheodore Kilgore {
1685bdd00b9STheodore Kilgore 	struct sd *sd = (struct sd *) gspca_dev;
1695bdd00b9STheodore Kilgore 	struct cam *cam = &gspca_dev->cam;
1705bdd00b9STheodore Kilgore 
17137d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)\n",
1725bdd00b9STheodore Kilgore 		  id->idVendor, id->idProduct);
1735bdd00b9STheodore Kilgore 
1745bdd00b9STheodore Kilgore 	sd->model = id->idProduct;
1755bdd00b9STheodore Kilgore 
1765bdd00b9STheodore Kilgore 	switch (sd->model) {
1775bdd00b9STheodore Kilgore 	case 0x7005:
17837d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Genius Smart 300 camera\n");
1795bdd00b9STheodore Kilgore 		break;
18048c291edSVasily Khoruzhick 	case 0x7003:
18137d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Genius Videocam Live v2\n");
18248c291edSVasily Khoruzhick 		break;
1835bdd00b9STheodore Kilgore 	case 0x8000:
18437d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "DC31VC\n");
1855bdd00b9STheodore Kilgore 		break;
1865bdd00b9STheodore Kilgore 	case 0x8001:
18737d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Spy camera\n");
1885bdd00b9STheodore Kilgore 		break;
1895bdd00b9STheodore Kilgore 	case 0x8003:
19037d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "CIF camera\n");
1915bdd00b9STheodore Kilgore 		break;
1925bdd00b9STheodore Kilgore 	case 0x8008:
19337d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Mini-Shotz ms-350 camera\n");
1945bdd00b9STheodore Kilgore 		break;
1955bdd00b9STheodore Kilgore 	case 0x800a:
19637d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Vivitar 3350b type camera\n");
1975bdd00b9STheodore Kilgore 		cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;
1985bdd00b9STheodore Kilgore 		break;
1995bdd00b9STheodore Kilgore 	}
2005bdd00b9STheodore Kilgore 
2015bdd00b9STheodore Kilgore 	switch (sd->model) {
2025bdd00b9STheodore Kilgore 	case 0x8000:
2035bdd00b9STheodore Kilgore 	case 0x8001:
2045bdd00b9STheodore Kilgore 	case 0x8003:
2055bdd00b9STheodore Kilgore 		cam->cam_mode = cif_mode;
2065bdd00b9STheodore Kilgore 		cam->nmodes = ARRAY_SIZE(cif_mode);
2075bdd00b9STheodore Kilgore 		break;
2085bdd00b9STheodore Kilgore 	default:
2095bdd00b9STheodore Kilgore 		cam->cam_mode = vga_mode;
2105bdd00b9STheodore Kilgore 		cam->nmodes = ARRAY_SIZE(vga_mode);
2115bdd00b9STheodore Kilgore 	}
2125bdd00b9STheodore Kilgore 	return 0;
2135bdd00b9STheodore Kilgore }
2145bdd00b9STheodore Kilgore 
2155bdd00b9STheodore Kilgore /* this function is called at probe and resume time */
2165bdd00b9STheodore Kilgore static int sd_init(struct gspca_dev *gspca_dev)
2175bdd00b9STheodore Kilgore {
218*77d7ceb1SColin Ian King 	int status;
2195bdd00b9STheodore Kilgore 
2205bdd00b9STheodore Kilgore 	sn9c2028_read1(gspca_dev);
2215bdd00b9STheodore Kilgore 	sn9c2028_read1(gspca_dev);
2225bdd00b9STheodore Kilgore 	status = sn9c2028_read1(gspca_dev);
2235bdd00b9STheodore Kilgore 
2245bdd00b9STheodore Kilgore 	return (status < 0) ? status : 0;
2255bdd00b9STheodore Kilgore }
2265bdd00b9STheodore Kilgore 
2275bdd00b9STheodore Kilgore static int run_start_commands(struct gspca_dev *gspca_dev,
2285bdd00b9STheodore Kilgore 			      struct init_command *cam_commands, int n)
2295bdd00b9STheodore Kilgore {
2305bdd00b9STheodore Kilgore 	int i, err_code = -1;
2315bdd00b9STheodore Kilgore 
2325bdd00b9STheodore Kilgore 	for (i = 0; i < n; i++) {
2335bdd00b9STheodore Kilgore 		switch (cam_commands[i].to_read) {
2345bdd00b9STheodore Kilgore 		case 4:
2355bdd00b9STheodore Kilgore 			err_code = sn9c2028_long_command(gspca_dev,
2365bdd00b9STheodore Kilgore 					cam_commands[i].instruction);
2375bdd00b9STheodore Kilgore 			break;
2385bdd00b9STheodore Kilgore 		case 1:
2395bdd00b9STheodore Kilgore 			err_code = sn9c2028_short_command(gspca_dev,
2405bdd00b9STheodore Kilgore 					cam_commands[i].instruction);
2415bdd00b9STheodore Kilgore 			break;
2425bdd00b9STheodore Kilgore 		case 0:
2435bdd00b9STheodore Kilgore 			err_code = sn9c2028_command(gspca_dev,
2445bdd00b9STheodore Kilgore 					cam_commands[i].instruction);
2455bdd00b9STheodore Kilgore 			break;
2465bdd00b9STheodore Kilgore 		}
2475bdd00b9STheodore Kilgore 		if (err_code < 0)
2485bdd00b9STheodore Kilgore 			return err_code;
2495bdd00b9STheodore Kilgore 	}
2505bdd00b9STheodore Kilgore 	return 0;
2515bdd00b9STheodore Kilgore }
2525bdd00b9STheodore Kilgore 
253d8fd9f56SVasily Khoruzhick static void set_gain(struct gspca_dev *gspca_dev, s32 g)
254d8fd9f56SVasily Khoruzhick {
255d8fd9f56SVasily Khoruzhick 	struct sd *sd = (struct sd *) gspca_dev;
256d8fd9f56SVasily Khoruzhick 
257d8fd9f56SVasily Khoruzhick 	struct init_command genius_vcam_live_gain_cmds[] = {
258d8fd9f56SVasily Khoruzhick 		{{0x1d, 0x25, 0x10 /* This byte is gain */,
259d8fd9f56SVasily Khoruzhick 		  0x20, 0xab, 0x00}, 0},
260d8fd9f56SVasily Khoruzhick 	};
261d8fd9f56SVasily Khoruzhick 	if (!gspca_dev->streaming)
262d8fd9f56SVasily Khoruzhick 		return;
263d8fd9f56SVasily Khoruzhick 
264d8fd9f56SVasily Khoruzhick 	switch (sd->model) {
265d8fd9f56SVasily Khoruzhick 	case 0x7003:
266d8fd9f56SVasily Khoruzhick 		genius_vcam_live_gain_cmds[0].instruction[2] = g;
267d8fd9f56SVasily Khoruzhick 		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
268d8fd9f56SVasily Khoruzhick 				   ARRAY_SIZE(genius_vcam_live_gain_cmds));
269d8fd9f56SVasily Khoruzhick 		break;
270d8fd9f56SVasily Khoruzhick 	default:
271d8fd9f56SVasily Khoruzhick 		break;
272d8fd9f56SVasily Khoruzhick 	}
273d8fd9f56SVasily Khoruzhick }
274d8fd9f56SVasily Khoruzhick 
275d8fd9f56SVasily Khoruzhick static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
276d8fd9f56SVasily Khoruzhick {
277d8fd9f56SVasily Khoruzhick 	struct gspca_dev *gspca_dev =
278d8fd9f56SVasily Khoruzhick 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
279d8fd9f56SVasily Khoruzhick 	struct sd *sd = (struct sd *)gspca_dev;
280d8fd9f56SVasily Khoruzhick 
281d8fd9f56SVasily Khoruzhick 	gspca_dev->usb_err = 0;
282d8fd9f56SVasily Khoruzhick 
283d8fd9f56SVasily Khoruzhick 	if (!gspca_dev->streaming)
284d8fd9f56SVasily Khoruzhick 		return 0;
285d8fd9f56SVasily Khoruzhick 
286d8fd9f56SVasily Khoruzhick 	switch (ctrl->id) {
287d8fd9f56SVasily Khoruzhick 	/* standalone gain control */
288d8fd9f56SVasily Khoruzhick 	case V4L2_CID_GAIN:
289d8fd9f56SVasily Khoruzhick 		set_gain(gspca_dev, ctrl->val);
290d8fd9f56SVasily Khoruzhick 		break;
291d8fd9f56SVasily Khoruzhick 	/* autogain */
292d8fd9f56SVasily Khoruzhick 	case V4L2_CID_AUTOGAIN:
293d8fd9f56SVasily Khoruzhick 		set_gain(gspca_dev, sd->gain->val);
294d8fd9f56SVasily Khoruzhick 		break;
295d8fd9f56SVasily Khoruzhick 	}
296d8fd9f56SVasily Khoruzhick 	return gspca_dev->usb_err;
297d8fd9f56SVasily Khoruzhick }
298d8fd9f56SVasily Khoruzhick 
299d8fd9f56SVasily Khoruzhick static const struct v4l2_ctrl_ops sd_ctrl_ops = {
300d8fd9f56SVasily Khoruzhick 	.s_ctrl = sd_s_ctrl,
301d8fd9f56SVasily Khoruzhick };
302d8fd9f56SVasily Khoruzhick 
303d8fd9f56SVasily Khoruzhick 
304d8fd9f56SVasily Khoruzhick static int sd_init_controls(struct gspca_dev *gspca_dev)
305d8fd9f56SVasily Khoruzhick {
306d8fd9f56SVasily Khoruzhick 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
307d8fd9f56SVasily Khoruzhick 	struct sd *sd = (struct sd *)gspca_dev;
308d8fd9f56SVasily Khoruzhick 
309d8fd9f56SVasily Khoruzhick 	gspca_dev->vdev.ctrl_handler = hdl;
310d8fd9f56SVasily Khoruzhick 	v4l2_ctrl_handler_init(hdl, 2);
311d8fd9f56SVasily Khoruzhick 
312d8fd9f56SVasily Khoruzhick 	switch (sd->model) {
313d8fd9f56SVasily Khoruzhick 	case 0x7003:
314d8fd9f56SVasily Khoruzhick 		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
315d8fd9f56SVasily Khoruzhick 			V4L2_CID_GAIN, 0, 20, 1, 0);
316d8fd9f56SVasily Khoruzhick 		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
317d8fd9f56SVasily Khoruzhick 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
318d8fd9f56SVasily Khoruzhick 		break;
319d8fd9f56SVasily Khoruzhick 	default:
320d8fd9f56SVasily Khoruzhick 		break;
321d8fd9f56SVasily Khoruzhick 	}
322d8fd9f56SVasily Khoruzhick 
323d8fd9f56SVasily Khoruzhick 	return 0;
324d8fd9f56SVasily Khoruzhick }
3255bdd00b9STheodore Kilgore static int start_spy_cam(struct gspca_dev *gspca_dev)
3265bdd00b9STheodore Kilgore {
3275bdd00b9STheodore Kilgore 	struct init_command spy_start_commands[] = {
3285bdd00b9STheodore Kilgore 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
3295bdd00b9STheodore Kilgore 		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
3305bdd00b9STheodore Kilgore 		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
3315bdd00b9STheodore Kilgore 		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
3325bdd00b9STheodore Kilgore 		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
3335bdd00b9STheodore Kilgore 		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
3345bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width  352 */
3355bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */
3365bdd00b9STheodore Kilgore 		/* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */
3375bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},
3385bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/
3395bdd00b9STheodore Kilgore 		/* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */
3405bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
3415bdd00b9STheodore Kilgore 		/* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */
3425bdd00b9STheodore Kilgore 		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
3435bdd00b9STheodore Kilgore 		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
3445bdd00b9STheodore Kilgore 		/* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */
3455bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
3465bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
3475bdd00b9STheodore Kilgore 		/* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */
3485bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
3495bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
3505bdd00b9STheodore Kilgore 		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
3515bdd00b9STheodore Kilgore 		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
3525bdd00b9STheodore Kilgore 		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
3535bdd00b9STheodore Kilgore 		{{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},
3545bdd00b9STheodore Kilgore 		{{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/
3555bdd00b9STheodore Kilgore 		/*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
3565bdd00b9STheodore Kilgore 		{{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
3575bdd00b9STheodore Kilgore 		/*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */
3585bdd00b9STheodore Kilgore 		{{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
3595bdd00b9STheodore Kilgore 		{{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */
3605bdd00b9STheodore Kilgore 		{{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},
3615bdd00b9STheodore Kilgore 		/*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
3625bdd00b9STheodore Kilgore 		{{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},
3635bdd00b9STheodore Kilgore 		{{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},
3645bdd00b9STheodore Kilgore 		{{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},
3655bdd00b9STheodore Kilgore 		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
3665bdd00b9STheodore Kilgore 		{{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},
3675bdd00b9STheodore Kilgore 		{{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},
3685bdd00b9STheodore Kilgore 		{{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},
3695bdd00b9STheodore Kilgore 		/* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */
3705bdd00b9STheodore Kilgore 		/* brightness or gain. 0 is default. 4 is good
3715bdd00b9STheodore Kilgore 		 * indoors at night with incandescent lighting */
3725bdd00b9STheodore Kilgore 		{{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},
3735bdd00b9STheodore Kilgore 		{{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/
3745bdd00b9STheodore Kilgore 		{{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},
3755bdd00b9STheodore Kilgore 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
3765bdd00b9STheodore Kilgore 		{{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},
3775bdd00b9STheodore Kilgore 		{{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},
3785bdd00b9STheodore Kilgore 		/* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */
3795bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */
3805bdd00b9STheodore Kilgore 		/* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */
3815bdd00b9STheodore Kilgore 		{{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},
3825bdd00b9STheodore Kilgore 		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */
3835bdd00b9STheodore Kilgore 		/* Camera should start to capture now. */
3845bdd00b9STheodore Kilgore 	};
3855bdd00b9STheodore Kilgore 
3865bdd00b9STheodore Kilgore 	return run_start_commands(gspca_dev, spy_start_commands,
3875bdd00b9STheodore Kilgore 				  ARRAY_SIZE(spy_start_commands));
3885bdd00b9STheodore Kilgore }
3895bdd00b9STheodore Kilgore 
3905bdd00b9STheodore Kilgore static int start_cif_cam(struct gspca_dev *gspca_dev)
3915bdd00b9STheodore Kilgore {
3925bdd00b9STheodore Kilgore 	struct init_command cif_start_commands[] = {
3935bdd00b9STheodore Kilgore 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
3945bdd00b9STheodore Kilgore 		/* The entire sequence below seems redundant */
3955bdd00b9STheodore Kilgore 		/* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
3965bdd00b9STheodore Kilgore 		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
3975bdd00b9STheodore Kilgore 		{{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},
3985bdd00b9STheodore Kilgore 		{{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},
3995bdd00b9STheodore Kilgore 		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
4005bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?
4015bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?
4025bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
4035bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
4045bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
4055bdd00b9STheodore Kilgore 		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
4065bdd00b9STheodore Kilgore 		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
4075bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4085bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
4095bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
4105bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
4115bdd00b9STheodore Kilgore 		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
4125bdd00b9STheodore Kilgore 		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
4135bdd00b9STheodore Kilgore 		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/
4145bdd00b9STheodore Kilgore 		{{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},
4155bdd00b9STheodore Kilgore 		{{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},
4165bdd00b9STheodore Kilgore 		{{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},
4175bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
4185bdd00b9STheodore Kilgore 		{{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},
4195bdd00b9STheodore Kilgore 		{{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},
4205bdd00b9STheodore Kilgore 		{{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},
4215bdd00b9STheodore Kilgore 		{{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},
4225bdd00b9STheodore Kilgore 		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
4235bdd00b9STheodore Kilgore 		{{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},
4245bdd00b9STheodore Kilgore 		{{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},
4255bdd00b9STheodore Kilgore 		{{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},
4265bdd00b9STheodore Kilgore 		{{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},
4275bdd00b9STheodore Kilgore 		{{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},
4285bdd00b9STheodore Kilgore 		{{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},
4295bdd00b9STheodore Kilgore 		{{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},
4305bdd00b9STheodore Kilgore 		{{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},
4315bdd00b9STheodore Kilgore 		{{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},
4325bdd00b9STheodore Kilgore 		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
4335bdd00b9STheodore Kilgore 		{{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},
4345bdd00b9STheodore Kilgore 		{{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},
4355bdd00b9STheodore Kilgore 		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
4365bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */
4375bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */
4385bdd00b9STheodore Kilgore 		/* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
4395bdd00b9STheodore Kilgore 		 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing
4405bdd00b9STheodore Kilgore 		 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */
4415bdd00b9STheodore Kilgore 		/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
4425bdd00b9STheodore Kilgore 		 * causes subsampling
4435bdd00b9STheodore Kilgore 		 * but not a change in the resolution setting! */
4445bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4455bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},
4465bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},
4475bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},
4485bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
4495bdd00b9STheodore Kilgore 		{{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},
4505bdd00b9STheodore Kilgore 		{{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},
4515bdd00b9STheodore Kilgore 		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
4525bdd00b9STheodore Kilgore 		{{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},
4535bdd00b9STheodore Kilgore 		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
4545bdd00b9STheodore Kilgore 		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
4555bdd00b9STheodore Kilgore 		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
4565bdd00b9STheodore Kilgore 		{{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},
4575bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
4585bdd00b9STheodore Kilgore 		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
4595bdd00b9STheodore Kilgore 		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */
4605bdd00b9STheodore Kilgore 		/* Camera should start to capture now. */
4615bdd00b9STheodore Kilgore 	};
4625bdd00b9STheodore Kilgore 
4635bdd00b9STheodore Kilgore 	return run_start_commands(gspca_dev, cif_start_commands,
4645bdd00b9STheodore Kilgore 				  ARRAY_SIZE(cif_start_commands));
4655bdd00b9STheodore Kilgore }
4665bdd00b9STheodore Kilgore 
4675bdd00b9STheodore Kilgore static int start_ms350_cam(struct gspca_dev *gspca_dev)
4685bdd00b9STheodore Kilgore {
4695bdd00b9STheodore Kilgore 	struct init_command ms350_start_commands[] = {
4705bdd00b9STheodore Kilgore 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
4715bdd00b9STheodore Kilgore 		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
4725bdd00b9STheodore Kilgore 		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
4735bdd00b9STheodore Kilgore 		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
4745bdd00b9STheodore Kilgore 		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
4755bdd00b9STheodore Kilgore 		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
4765bdd00b9STheodore Kilgore 		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
4775bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
4785bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
4795bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
4805bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},
4815bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
4825bdd00b9STheodore Kilgore 		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
4835bdd00b9STheodore Kilgore 		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
4845bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4855bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
4865bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
4875bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
4885bdd00b9STheodore Kilgore 		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
4895bdd00b9STheodore Kilgore 		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
4905bdd00b9STheodore Kilgore 		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
4915bdd00b9STheodore Kilgore 		{{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},
4925bdd00b9STheodore Kilgore 		{{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},
4935bdd00b9STheodore Kilgore 		{{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},
4945bdd00b9STheodore Kilgore 		{{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},
4955bdd00b9STheodore Kilgore 		{{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},
4965bdd00b9STheodore Kilgore 		{{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},
4975bdd00b9STheodore Kilgore 		{{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},
4985bdd00b9STheodore Kilgore 		{{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},
4995bdd00b9STheodore Kilgore 		{{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},
5005bdd00b9STheodore Kilgore 		{{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},
5015bdd00b9STheodore Kilgore 		{{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},
5025bdd00b9STheodore Kilgore 		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
5035bdd00b9STheodore Kilgore 		{{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},
5045bdd00b9STheodore Kilgore 		{{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},
5055bdd00b9STheodore Kilgore 		{{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},
5065bdd00b9STheodore Kilgore 		{{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},
5075bdd00b9STheodore Kilgore 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5085bdd00b9STheodore Kilgore 		{{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},
5095bdd00b9STheodore Kilgore 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5105bdd00b9STheodore Kilgore 		{{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},
5115bdd00b9STheodore Kilgore 		{{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},
5125bdd00b9STheodore Kilgore 		{{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},
5135bdd00b9STheodore Kilgore 		{{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},
5145bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width  */
5155bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */
5165bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */
5175bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
5185bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */
5195bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5205bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
5215bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
5225bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
5235bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},
5245bdd00b9STheodore Kilgore 		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
5255bdd00b9STheodore Kilgore 		{{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},
5265bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},
5275bdd00b9STheodore Kilgore 		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},
5285bdd00b9STheodore Kilgore 		/* Camera should start to capture now. */
5295bdd00b9STheodore Kilgore 	};
5305bdd00b9STheodore Kilgore 
5315bdd00b9STheodore Kilgore 	return run_start_commands(gspca_dev, ms350_start_commands,
5325bdd00b9STheodore Kilgore 				  ARRAY_SIZE(ms350_start_commands));
5335bdd00b9STheodore Kilgore }
5345bdd00b9STheodore Kilgore 
5355bdd00b9STheodore Kilgore static int start_genius_cam(struct gspca_dev *gspca_dev)
5365bdd00b9STheodore Kilgore {
5375bdd00b9STheodore Kilgore 	struct init_command genius_start_commands[] = {
5385bdd00b9STheodore Kilgore 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
5395bdd00b9STheodore Kilgore 		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
5405bdd00b9STheodore Kilgore 		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
5415bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
5425bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
5435bdd00b9STheodore Kilgore 		/* "preliminary" width and height settings */
5445bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
5455bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
5465bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
5475bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5485bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
5495bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
5505bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
5515bdd00b9STheodore Kilgore 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5525bdd00b9STheodore Kilgore 		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
5535bdd00b9STheodore Kilgore 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5545bdd00b9STheodore Kilgore 		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
5555bdd00b9STheodore Kilgore 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5565bdd00b9STheodore Kilgore 		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
5575bdd00b9STheodore Kilgore 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5585bdd00b9STheodore Kilgore 		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
5595bdd00b9STheodore Kilgore 		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
5605bdd00b9STheodore Kilgore 		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
5615bdd00b9STheodore Kilgore 		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
5625bdd00b9STheodore Kilgore 		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
5635bdd00b9STheodore Kilgore 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5645bdd00b9STheodore Kilgore 		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
5655bdd00b9STheodore Kilgore 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5665bdd00b9STheodore Kilgore 		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
5675bdd00b9STheodore Kilgore 		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
5685bdd00b9STheodore Kilgore 		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
5695bdd00b9STheodore Kilgore 		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
5705bdd00b9STheodore Kilgore 		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
5715bdd00b9STheodore Kilgore 		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
5725bdd00b9STheodore Kilgore 		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
5735bdd00b9STheodore Kilgore 		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
5745bdd00b9STheodore Kilgore 		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
5755bdd00b9STheodore Kilgore 		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
5765bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */
5775bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */
5785bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
5795bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
5805bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
5815bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5825bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
5835bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
5845bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
5855bdd00b9STheodore Kilgore 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5865bdd00b9STheodore Kilgore 		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
5875bdd00b9STheodore Kilgore 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5885bdd00b9STheodore Kilgore 		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
5895bdd00b9STheodore Kilgore 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5905bdd00b9STheodore Kilgore 		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
5915bdd00b9STheodore Kilgore 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5925bdd00b9STheodore Kilgore 		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
5935bdd00b9STheodore Kilgore 		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
5945bdd00b9STheodore Kilgore 		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
5955bdd00b9STheodore Kilgore 		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
5965bdd00b9STheodore Kilgore 		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
5975bdd00b9STheodore Kilgore 		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
5985bdd00b9STheodore Kilgore 		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
5995bdd00b9STheodore Kilgore 		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}
6005bdd00b9STheodore Kilgore 		/* Camera should start to capture now. */
6015bdd00b9STheodore Kilgore 	};
6025bdd00b9STheodore Kilgore 
6035bdd00b9STheodore Kilgore 	return run_start_commands(gspca_dev, genius_start_commands,
6045bdd00b9STheodore Kilgore 				  ARRAY_SIZE(genius_start_commands));
6055bdd00b9STheodore Kilgore }
6065bdd00b9STheodore Kilgore 
60748c291edSVasily Khoruzhick static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
60848c291edSVasily Khoruzhick {
60948c291edSVasily Khoruzhick 	int r;
61048c291edSVasily Khoruzhick 	struct sd *sd = (struct sd *) gspca_dev;
61148c291edSVasily Khoruzhick 	struct init_command genius_vcam_live_start_commands[] = {
61248c291edSVasily Khoruzhick 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},
61348c291edSVasily Khoruzhick 		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
61448c291edSVasily Khoruzhick 		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
61548c291edSVasily Khoruzhick 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
61648c291edSVasily Khoruzhick 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
61748c291edSVasily Khoruzhick 
61848c291edSVasily Khoruzhick 		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
61948c291edSVasily Khoruzhick 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
62048c291edSVasily Khoruzhick 		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
62148c291edSVasily Khoruzhick 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
62248c291edSVasily Khoruzhick 		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
62348c291edSVasily Khoruzhick 		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
62448c291edSVasily Khoruzhick 		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
62548c291edSVasily Khoruzhick 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
62648c291edSVasily Khoruzhick 		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
62748c291edSVasily Khoruzhick 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
62848c291edSVasily Khoruzhick 		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
62948c291edSVasily Khoruzhick 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
63048c291edSVasily Khoruzhick 		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
63148c291edSVasily Khoruzhick 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
63248c291edSVasily Khoruzhick 		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
63348c291edSVasily Khoruzhick 		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
63448c291edSVasily Khoruzhick 		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
63548c291edSVasily Khoruzhick 		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
63648c291edSVasily Khoruzhick 		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
63748c291edSVasily Khoruzhick 		{{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},
63848c291edSVasily Khoruzhick 		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
63948c291edSVasily Khoruzhick 		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
64048c291edSVasily Khoruzhick 		{{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},
64148c291edSVasily Khoruzhick 		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
64248c291edSVasily Khoruzhick 		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
64348c291edSVasily Khoruzhick 		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
64448c291edSVasily Khoruzhick 		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
64548c291edSVasily Khoruzhick 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
64648c291edSVasily Khoruzhick 		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
64748c291edSVasily Khoruzhick 		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
64848c291edSVasily Khoruzhick 		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
64948c291edSVasily Khoruzhick 		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
65048c291edSVasily Khoruzhick 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
65148c291edSVasily Khoruzhick 		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
65248c291edSVasily Khoruzhick 		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
65348c291edSVasily Khoruzhick 		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
65448c291edSVasily Khoruzhick 		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
65548c291edSVasily Khoruzhick 		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
65648c291edSVasily Khoruzhick 		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
65748c291edSVasily Khoruzhick 		{{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},
65848c291edSVasily Khoruzhick 		{{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},
65948c291edSVasily Khoruzhick 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
66048c291edSVasily Khoruzhick 		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
66148c291edSVasily Khoruzhick 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
66248c291edSVasily Khoruzhick 		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
66348c291edSVasily Khoruzhick 		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
66448c291edSVasily Khoruzhick 		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
66548c291edSVasily Khoruzhick 		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
66648c291edSVasily Khoruzhick 		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
66748c291edSVasily Khoruzhick 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
66848c291edSVasily Khoruzhick 		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
66948c291edSVasily Khoruzhick 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
67048c291edSVasily Khoruzhick 		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
67148c291edSVasily Khoruzhick 		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
67248c291edSVasily Khoruzhick 		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
67348c291edSVasily Khoruzhick 		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
67448c291edSVasily Khoruzhick 		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
67548c291edSVasily Khoruzhick 		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
67648c291edSVasily Khoruzhick 		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
67748c291edSVasily Khoruzhick 		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
67848c291edSVasily Khoruzhick 		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
67948c291edSVasily Khoruzhick 		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
68048c291edSVasily Khoruzhick 		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
68148c291edSVasily Khoruzhick 		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
68248c291edSVasily Khoruzhick 		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
68348c291edSVasily Khoruzhick 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
68448c291edSVasily Khoruzhick 		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
68548c291edSVasily Khoruzhick 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
68648c291edSVasily Khoruzhick 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
68748c291edSVasily Khoruzhick 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
68848c291edSVasily Khoruzhick 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
68948c291edSVasily Khoruzhick 		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
69048c291edSVasily Khoruzhick 		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
69148c291edSVasily Khoruzhick 		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
69248c291edSVasily Khoruzhick 		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
69348c291edSVasily Khoruzhick 		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
69448c291edSVasily Khoruzhick 		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
69548c291edSVasily Khoruzhick 		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
69648c291edSVasily Khoruzhick 		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
69748c291edSVasily Khoruzhick 		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
69848c291edSVasily Khoruzhick 		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
69948c291edSVasily Khoruzhick 		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
70048c291edSVasily Khoruzhick 		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
70148c291edSVasily Khoruzhick 		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
70248c291edSVasily Khoruzhick 		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},
70348c291edSVasily Khoruzhick 		/* Camera should start to capture now. */
70448c291edSVasily Khoruzhick 		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},
70548c291edSVasily Khoruzhick 		{{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},
70648c291edSVasily Khoruzhick 		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
70748c291edSVasily Khoruzhick 	};
70848c291edSVasily Khoruzhick 
70948c291edSVasily Khoruzhick 	r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,
71048c291edSVasily Khoruzhick 				  ARRAY_SIZE(genius_vcam_live_start_commands));
71148c291edSVasily Khoruzhick 	if (r < 0)
71248c291edSVasily Khoruzhick 		return r;
71348c291edSVasily Khoruzhick 
714d8fd9f56SVasily Khoruzhick 	if (sd->gain)
715d8fd9f56SVasily Khoruzhick 		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
716d8fd9f56SVasily Khoruzhick 
71748c291edSVasily Khoruzhick 	return r;
71848c291edSVasily Khoruzhick }
71948c291edSVasily Khoruzhick 
7205bdd00b9STheodore Kilgore static int start_vivitar_cam(struct gspca_dev *gspca_dev)
7215bdd00b9STheodore Kilgore {
7225bdd00b9STheodore Kilgore 	struct init_command vivitar_start_commands[] = {
7235bdd00b9STheodore Kilgore 		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
7245bdd00b9STheodore Kilgore 		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
7255bdd00b9STheodore Kilgore 		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
7265bdd00b9STheodore Kilgore 		{{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},
7275bdd00b9STheodore Kilgore 		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
7285bdd00b9STheodore Kilgore 		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
7295bdd00b9STheodore Kilgore 		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
7305bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
7315bdd00b9STheodore Kilgore 		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
7325bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},
7335bdd00b9STheodore Kilgore 		/*
7345bdd00b9STheodore Kilgore 		 * Above is changed from OEM 0x0b. Fixes Bayer tiling.
7355bdd00b9STheodore Kilgore 		 * Presumably gives a vertical shift of one row.
7365bdd00b9STheodore Kilgore 		 */
7375bdd00b9STheodore Kilgore 		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
7385bdd00b9STheodore Kilgore 		/* Above seems to do horizontal shift. */
7395bdd00b9STheodore Kilgore 		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
7405bdd00b9STheodore Kilgore 		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
7415bdd00b9STheodore Kilgore 		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
7425bdd00b9STheodore Kilgore 		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
7435bdd00b9STheodore Kilgore 		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
7445bdd00b9STheodore Kilgore 		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
7455bdd00b9STheodore Kilgore 		/* Above three commands seem to relate to brightness. */
7465bdd00b9STheodore Kilgore 		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
7475bdd00b9STheodore Kilgore 		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
7485bdd00b9STheodore Kilgore 		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
7495bdd00b9STheodore Kilgore 		{{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},
7505bdd00b9STheodore Kilgore 		{{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},
7515bdd00b9STheodore Kilgore 		{{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},
7525bdd00b9STheodore Kilgore 		{{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},
7535bdd00b9STheodore Kilgore 		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
7545bdd00b9STheodore Kilgore 		{{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},
7555bdd00b9STheodore Kilgore 		{{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},
7565bdd00b9STheodore Kilgore 		{{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},
7575bdd00b9STheodore Kilgore 		{{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},
7585bdd00b9STheodore Kilgore 		{{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},
7595bdd00b9STheodore Kilgore 		{{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},
7605bdd00b9STheodore Kilgore 		{{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},
7615bdd00b9STheodore Kilgore 		{{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},
7625bdd00b9STheodore Kilgore 		{{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
7635bdd00b9STheodore Kilgore 		{{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},
7645bdd00b9STheodore Kilgore 		{{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},
7655bdd00b9STheodore Kilgore 		{{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},
7665bdd00b9STheodore Kilgore 		{{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},
7675bdd00b9STheodore Kilgore 		{{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},
7685bdd00b9STheodore Kilgore 		{{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},
7695bdd00b9STheodore Kilgore 		{{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},
7705bdd00b9STheodore Kilgore 		{{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},
7715bdd00b9STheodore Kilgore 		{{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},
7725bdd00b9STheodore Kilgore 		{{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},
7735bdd00b9STheodore Kilgore 		{{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},
7745bdd00b9STheodore Kilgore 		{{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},
7755bdd00b9STheodore Kilgore 		{{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},
7765bdd00b9STheodore Kilgore 		{{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},
7775bdd00b9STheodore Kilgore 		{{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},
7785bdd00b9STheodore Kilgore 		{{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},
7795bdd00b9STheodore Kilgore 		{{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},
7805bdd00b9STheodore Kilgore 		{{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},
7815bdd00b9STheodore Kilgore 		{{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},
7825bdd00b9STheodore Kilgore 		{{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},
7835bdd00b9STheodore Kilgore 		/* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
7845bdd00b9STheodore Kilgore 		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
7855bdd00b9STheodore Kilgore 		{{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */
7865bdd00b9STheodore Kilgore 		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
7875bdd00b9STheodore Kilgore 		{{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},
7885bdd00b9STheodore Kilgore 		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
7895bdd00b9STheodore Kilgore 		{{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},
7905bdd00b9STheodore Kilgore 		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
7915bdd00b9STheodore Kilgore 		{{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},
7925bdd00b9STheodore Kilgore 		/* Above is brightness; OEM driver setting is 0x10 */
7935bdd00b9STheodore Kilgore 		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
7945bdd00b9STheodore Kilgore 		{{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
7955bdd00b9STheodore Kilgore 		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}
7965bdd00b9STheodore Kilgore 	};
7975bdd00b9STheodore Kilgore 
7985bdd00b9STheodore Kilgore 	return run_start_commands(gspca_dev, vivitar_start_commands,
7995bdd00b9STheodore Kilgore 				  ARRAY_SIZE(vivitar_start_commands));
8005bdd00b9STheodore Kilgore }
8015bdd00b9STheodore Kilgore 
8025bdd00b9STheodore Kilgore static int sd_start(struct gspca_dev *gspca_dev)
8035bdd00b9STheodore Kilgore {
8045bdd00b9STheodore Kilgore 	struct sd *sd = (struct sd *) gspca_dev;
8055bdd00b9STheodore Kilgore 	int err_code;
8065bdd00b9STheodore Kilgore 
8075bdd00b9STheodore Kilgore 	sd->sof_read = 0;
8085bdd00b9STheodore Kilgore 
8095bdd00b9STheodore Kilgore 	switch (sd->model) {
8105bdd00b9STheodore Kilgore 	case 0x7005:
8115bdd00b9STheodore Kilgore 		err_code = start_genius_cam(gspca_dev);
8125bdd00b9STheodore Kilgore 		break;
81348c291edSVasily Khoruzhick 	case 0x7003:
81448c291edSVasily Khoruzhick 		err_code = start_genius_videocam_live(gspca_dev);
81548c291edSVasily Khoruzhick 		break;
8165bdd00b9STheodore Kilgore 	case 0x8001:
8175bdd00b9STheodore Kilgore 		err_code = start_spy_cam(gspca_dev);
8185bdd00b9STheodore Kilgore 		break;
8195bdd00b9STheodore Kilgore 	case 0x8003:
8205bdd00b9STheodore Kilgore 		err_code = start_cif_cam(gspca_dev);
8215bdd00b9STheodore Kilgore 		break;
8225bdd00b9STheodore Kilgore 	case 0x8008:
8235bdd00b9STheodore Kilgore 		err_code = start_ms350_cam(gspca_dev);
8245bdd00b9STheodore Kilgore 		break;
8255bdd00b9STheodore Kilgore 	case 0x800a:
8265bdd00b9STheodore Kilgore 		err_code = start_vivitar_cam(gspca_dev);
8275bdd00b9STheodore Kilgore 		break;
8285bdd00b9STheodore Kilgore 	default:
829133a9fe9SJoe Perches 		pr_err("Starting unknown camera, please report this\n");
8305bdd00b9STheodore Kilgore 		return -ENXIO;
8315bdd00b9STheodore Kilgore 	}
8325bdd00b9STheodore Kilgore 
833d8fd9f56SVasily Khoruzhick 	sd->avg_lum = -1;
834d8fd9f56SVasily Khoruzhick 
8355bdd00b9STheodore Kilgore 	return err_code;
8365bdd00b9STheodore Kilgore }
8375bdd00b9STheodore Kilgore 
8385bdd00b9STheodore Kilgore static void sd_stopN(struct gspca_dev *gspca_dev)
8395bdd00b9STheodore Kilgore {
8405bdd00b9STheodore Kilgore 	int result;
8415bdd00b9STheodore Kilgore 	__u8 data[6];
8425bdd00b9STheodore Kilgore 
8435bdd00b9STheodore Kilgore 	result = sn9c2028_read1(gspca_dev);
8445bdd00b9STheodore Kilgore 	if (result < 0)
84552173c5fSJoe Perches 		gspca_err(gspca_dev, "Camera Stop read failed\n");
8465bdd00b9STheodore Kilgore 
8475bdd00b9STheodore Kilgore 	memset(data, 0, 6);
8485bdd00b9STheodore Kilgore 	data[0] = 0x14;
8495bdd00b9STheodore Kilgore 	result = sn9c2028_command(gspca_dev, data);
8505bdd00b9STheodore Kilgore 	if (result < 0)
85152173c5fSJoe Perches 		gspca_err(gspca_dev, "Camera Stop command failed\n");
8525bdd00b9STheodore Kilgore }
8535bdd00b9STheodore Kilgore 
854d8fd9f56SVasily Khoruzhick static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
855d8fd9f56SVasily Khoruzhick {
856d8fd9f56SVasily Khoruzhick 	struct sd *sd = (struct sd *) gspca_dev;
857d8fd9f56SVasily Khoruzhick 	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
858d8fd9f56SVasily Khoruzhick 
859d8fd9f56SVasily Khoruzhick 	if (avg_lum == -1)
860d8fd9f56SVasily Khoruzhick 		return;
861d8fd9f56SVasily Khoruzhick 
862d8fd9f56SVasily Khoruzhick 	if (avg_lum < MIN_AVG_LUM) {
863d8fd9f56SVasily Khoruzhick 		if (cur_gain == sd->gain->maximum)
864d8fd9f56SVasily Khoruzhick 			return;
865d8fd9f56SVasily Khoruzhick 		cur_gain++;
866d8fd9f56SVasily Khoruzhick 		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
867d8fd9f56SVasily Khoruzhick 	}
868d8fd9f56SVasily Khoruzhick 	if (avg_lum > MAX_AVG_LUM) {
869d8fd9f56SVasily Khoruzhick 		if (cur_gain == sd->gain->minimum)
870d8fd9f56SVasily Khoruzhick 			return;
871d8fd9f56SVasily Khoruzhick 		cur_gain--;
872d8fd9f56SVasily Khoruzhick 		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
873d8fd9f56SVasily Khoruzhick 	}
874d8fd9f56SVasily Khoruzhick 
875d8fd9f56SVasily Khoruzhick }
876d8fd9f56SVasily Khoruzhick 
877d8fd9f56SVasily Khoruzhick static void sd_dqcallback(struct gspca_dev *gspca_dev)
878d8fd9f56SVasily Khoruzhick {
879d8fd9f56SVasily Khoruzhick 	struct sd *sd = (struct sd *) gspca_dev;
880d8fd9f56SVasily Khoruzhick 
881d8fd9f56SVasily Khoruzhick 	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
882d8fd9f56SVasily Khoruzhick 		return;
883d8fd9f56SVasily Khoruzhick 
884d8fd9f56SVasily Khoruzhick 	do_autogain(gspca_dev, sd->avg_lum);
885d8fd9f56SVasily Khoruzhick }
886d8fd9f56SVasily Khoruzhick 
8875bdd00b9STheodore Kilgore /* Include sn9c2028 sof detection functions */
8885bdd00b9STheodore Kilgore #include "sn9c2028.h"
8895bdd00b9STheodore Kilgore 
8905bdd00b9STheodore Kilgore static void sd_pkt_scan(struct gspca_dev *gspca_dev,
8915bdd00b9STheodore Kilgore 			__u8 *data,			/* isoc packet */
8925bdd00b9STheodore Kilgore 			int len)			/* iso packet length */
8935bdd00b9STheodore Kilgore {
8945bdd00b9STheodore Kilgore 	unsigned char *sof;
8955bdd00b9STheodore Kilgore 
8965bdd00b9STheodore Kilgore 	sof = sn9c2028_find_sof(gspca_dev, data, len);
8975bdd00b9STheodore Kilgore 	if (sof) {
8985bdd00b9STheodore Kilgore 		int n;
8995bdd00b9STheodore Kilgore 
9005bdd00b9STheodore Kilgore 		/* finish decoding current frame */
9015bdd00b9STheodore Kilgore 		n = sof - data;
9025bdd00b9STheodore Kilgore 		if (n > sizeof sn9c2028_sof_marker)
9035bdd00b9STheodore Kilgore 			n -= sizeof sn9c2028_sof_marker;
9045bdd00b9STheodore Kilgore 		else
9055bdd00b9STheodore Kilgore 			n = 0;
9065bdd00b9STheodore Kilgore 		gspca_frame_add(gspca_dev, LAST_PACKET, data, n);
9075bdd00b9STheodore Kilgore 		/* Start next frame. */
9085bdd00b9STheodore Kilgore 		gspca_frame_add(gspca_dev, FIRST_PACKET,
9095bdd00b9STheodore Kilgore 			sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);
9105bdd00b9STheodore Kilgore 		len -= sof - data;
9115bdd00b9STheodore Kilgore 		data = sof;
9125bdd00b9STheodore Kilgore 	}
9135bdd00b9STheodore Kilgore 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
9145bdd00b9STheodore Kilgore }
9155bdd00b9STheodore Kilgore 
9165bdd00b9STheodore Kilgore /* sub-driver description */
9175bdd00b9STheodore Kilgore static const struct sd_desc sd_desc = {
9185bdd00b9STheodore Kilgore 	.name = MODULE_NAME,
9195bdd00b9STheodore Kilgore 	.config = sd_config,
9205bdd00b9STheodore Kilgore 	.init = sd_init,
921d8fd9f56SVasily Khoruzhick 	.init_controls = sd_init_controls,
9225bdd00b9STheodore Kilgore 	.start = sd_start,
9235bdd00b9STheodore Kilgore 	.stopN = sd_stopN,
924d8fd9f56SVasily Khoruzhick 	.dq_callback = sd_dqcallback,
9255bdd00b9STheodore Kilgore 	.pkt_scan = sd_pkt_scan,
9265bdd00b9STheodore Kilgore };
9275bdd00b9STheodore Kilgore 
9285bdd00b9STheodore Kilgore /* -- module initialisation -- */
92995c967c1SJean-François Moine static const struct usb_device_id device_table[] = {
9305bdd00b9STheodore Kilgore 	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
93148c291edSVasily Khoruzhick 	{USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2  */
9325bdd00b9STheodore Kilgore 	/* The Genius Smart is untested. I can't find an owner ! */
9335bdd00b9STheodore Kilgore 	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
9345bdd00b9STheodore Kilgore 	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
9355bdd00b9STheodore Kilgore 	{USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */
9365bdd00b9STheodore Kilgore 	/* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */
9375bdd00b9STheodore Kilgore 	{USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */
9385bdd00b9STheodore Kilgore 	{USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */
9395bdd00b9STheodore Kilgore 	{}
9405bdd00b9STheodore Kilgore };
9415bdd00b9STheodore Kilgore MODULE_DEVICE_TABLE(usb, device_table);
9425bdd00b9STheodore Kilgore 
9435bdd00b9STheodore Kilgore /* -- device connect -- */
9445bdd00b9STheodore Kilgore static int sd_probe(struct usb_interface *intf,
9455bdd00b9STheodore Kilgore 			const struct usb_device_id *id)
9465bdd00b9STheodore Kilgore {
9475bdd00b9STheodore Kilgore 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
9485bdd00b9STheodore Kilgore 			       THIS_MODULE);
9495bdd00b9STheodore Kilgore }
9505bdd00b9STheodore Kilgore 
9515bdd00b9STheodore Kilgore static struct usb_driver sd_driver = {
9525bdd00b9STheodore Kilgore 	.name = MODULE_NAME,
9535bdd00b9STheodore Kilgore 	.id_table = device_table,
9545bdd00b9STheodore Kilgore 	.probe = sd_probe,
9555bdd00b9STheodore Kilgore 	.disconnect = gspca_disconnect,
9565bdd00b9STheodore Kilgore #ifdef CONFIG_PM
9575bdd00b9STheodore Kilgore 	.suspend = gspca_suspend,
9585bdd00b9STheodore Kilgore 	.resume = gspca_resume,
9598bb58964SHans de Goede 	.reset_resume = gspca_resume,
9605bdd00b9STheodore Kilgore #endif
9615bdd00b9STheodore Kilgore };
9625bdd00b9STheodore Kilgore 
963ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver);
964