18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SN9C2028 library
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define MODULE_NAME "sn9c2028"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "gspca.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Theodore Kilgore");
158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* specific webcam descriptor */
198c2ecf20Sopenharmony_cistruct sd {
208c2ecf20Sopenharmony_ci	struct gspca_dev gspca_dev;  /* !! must be the first item */
218c2ecf20Sopenharmony_ci	u8 sof_read;
228c2ecf20Sopenharmony_ci	u16 model;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define MIN_AVG_LUM 8500
258c2ecf20Sopenharmony_ci#define MAX_AVG_LUM 10000
268c2ecf20Sopenharmony_ci	int avg_lum;
278c2ecf20Sopenharmony_ci	u8 avg_lum_l;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	struct { /* autogain and gain control cluster */
308c2ecf20Sopenharmony_ci		struct v4l2_ctrl *autogain;
318c2ecf20Sopenharmony_ci		struct v4l2_ctrl *gain;
328c2ecf20Sopenharmony_ci	};
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct init_command {
368c2ecf20Sopenharmony_ci	unsigned char instruction[6];
378c2ecf20Sopenharmony_ci	unsigned char to_read; /* length to read. 0 means no reply requested */
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* How to change the resolution of any of the VGA cams is unknown */
418c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = {
428c2ecf20Sopenharmony_ci	{640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
438c2ecf20Sopenharmony_ci		.bytesperline = 640,
448c2ecf20Sopenharmony_ci		.sizeimage = 640 * 480 * 3 / 4,
458c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
468c2ecf20Sopenharmony_ci		.priv = 0},
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* No way to change the resolution of the CIF cams is known */
508c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format cif_mode[] = {
518c2ecf20Sopenharmony_ci	{352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
528c2ecf20Sopenharmony_ci		.bytesperline = 352,
538c2ecf20Sopenharmony_ci		.sizeimage = 352 * 288 * 3 / 4,
548c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
558c2ecf20Sopenharmony_ci		.priv = 0},
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* the bytes to write are in gspca_dev->usb_buf */
598c2ecf20Sopenharmony_cistatic int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	int rc;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_USBO, "sending command %02x%02x%02x%02x%02x%02x\n",
648c2ecf20Sopenharmony_ci		  command[0], command[1], command[2],
658c2ecf20Sopenharmony_ci		  command[3], command[4], command[5]);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	memcpy(gspca_dev->usb_buf, command, 6);
688c2ecf20Sopenharmony_ci	rc = usb_control_msg(gspca_dev->dev,
698c2ecf20Sopenharmony_ci			usb_sndctrlpipe(gspca_dev->dev, 0),
708c2ecf20Sopenharmony_ci			USB_REQ_GET_CONFIGURATION,
718c2ecf20Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
728c2ecf20Sopenharmony_ci			2, 0, gspca_dev->usb_buf, 6, 500);
738c2ecf20Sopenharmony_ci	if (rc < 0) {
748c2ecf20Sopenharmony_ci		pr_err("command write [%02x] error %d\n",
758c2ecf20Sopenharmony_ci		       gspca_dev->usb_buf[0], rc);
768c2ecf20Sopenharmony_ci		return rc;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int sn9c2028_read1(struct gspca_dev *gspca_dev)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int rc;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	rc = usb_control_msg(gspca_dev->dev,
878c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
888c2ecf20Sopenharmony_ci			USB_REQ_GET_STATUS,
898c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
908c2ecf20Sopenharmony_ci			1, 0, gspca_dev->usb_buf, 1, 500);
918c2ecf20Sopenharmony_ci	if (rc != 1) {
928c2ecf20Sopenharmony_ci		pr_err("read1 error %d\n", rc);
938c2ecf20Sopenharmony_ci		return (rc < 0) ? rc : -EIO;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_USBI, "read1 response %02x\n",
968c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0]);
978c2ecf20Sopenharmony_ci	return gspca_dev->usb_buf[0];
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int rc;
1038c2ecf20Sopenharmony_ci	rc = usb_control_msg(gspca_dev->dev,
1048c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
1058c2ecf20Sopenharmony_ci			USB_REQ_GET_STATUS,
1068c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1078c2ecf20Sopenharmony_ci			4, 0, gspca_dev->usb_buf, 4, 500);
1088c2ecf20Sopenharmony_ci	if (rc != 4) {
1098c2ecf20Sopenharmony_ci		pr_err("read4 error %d\n", rc);
1108c2ecf20Sopenharmony_ci		return (rc < 0) ? rc : -EIO;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	memcpy(reading, gspca_dev->usb_buf, 4);
1138c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_USBI, "read4 response %02x%02x%02x%02x\n",
1148c2ecf20Sopenharmony_ci		  reading[0], reading[1], reading[2], reading[3]);
1158c2ecf20Sopenharmony_ci	return rc;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int i, status;
1218c2ecf20Sopenharmony_ci	__u8 reading[4];
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	status = sn9c2028_command(gspca_dev, command);
1248c2ecf20Sopenharmony_ci	if (status < 0)
1258c2ecf20Sopenharmony_ci		return status;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	status = -1;
1288c2ecf20Sopenharmony_ci	for (i = 0; i < 256 && status < 2; i++)
1298c2ecf20Sopenharmony_ci		status = sn9c2028_read1(gspca_dev);
1308c2ecf20Sopenharmony_ci	if (status < 0) {
1318c2ecf20Sopenharmony_ci		pr_err("long command status read error %d\n", status);
1328c2ecf20Sopenharmony_ci		return status;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	memset(reading, 0, 4);
1368c2ecf20Sopenharmony_ci	status = sn9c2028_read4(gspca_dev, reading);
1378c2ecf20Sopenharmony_ci	if (status < 0)
1388c2ecf20Sopenharmony_ci		return status;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* in general, the first byte of the response is the first byte of
1418c2ecf20Sopenharmony_ci	 * the command, or'ed with 8 */
1428c2ecf20Sopenharmony_ci	status = sn9c2028_read1(gspca_dev);
1438c2ecf20Sopenharmony_ci	if (status < 0)
1448c2ecf20Sopenharmony_ci		return status;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	int err_code;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	err_code = sn9c2028_command(gspca_dev, command);
1548c2ecf20Sopenharmony_ci	if (err_code < 0)
1558c2ecf20Sopenharmony_ci		return err_code;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	err_code = sn9c2028_read1(gspca_dev);
1588c2ecf20Sopenharmony_ci	if (err_code < 0)
1598c2ecf20Sopenharmony_ci		return err_code;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* this function is called at probe time */
1658c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
1668c2ecf20Sopenharmony_ci		     const struct usb_device_id *id)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
1698c2ecf20Sopenharmony_ci	struct cam *cam = &gspca_dev->cam;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)\n",
1728c2ecf20Sopenharmony_ci		  id->idVendor, id->idProduct);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	sd->model = id->idProduct;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	switch (sd->model) {
1778c2ecf20Sopenharmony_ci	case 0x7005:
1788c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "Genius Smart 300 camera\n");
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	case 0x7003:
1818c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "Genius Videocam Live v2\n");
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	case 0x8000:
1848c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "DC31VC\n");
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case 0x8001:
1878c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "Spy camera\n");
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	case 0x8003:
1908c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "CIF camera\n");
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	case 0x8008:
1938c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "Mini-Shotz ms-350 camera\n");
1948c2ecf20Sopenharmony_ci		break;
1958c2ecf20Sopenharmony_ci	case 0x800a:
1968c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_PROBE, "Vivitar 3350b type camera\n");
1978c2ecf20Sopenharmony_ci		cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	switch (sd->model) {
2028c2ecf20Sopenharmony_ci	case 0x8000:
2038c2ecf20Sopenharmony_ci	case 0x8001:
2048c2ecf20Sopenharmony_ci	case 0x8003:
2058c2ecf20Sopenharmony_ci		cam->cam_mode = cif_mode;
2068c2ecf20Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(cif_mode);
2078c2ecf20Sopenharmony_ci		break;
2088c2ecf20Sopenharmony_ci	default:
2098c2ecf20Sopenharmony_ci		cam->cam_mode = vga_mode;
2108c2ecf20Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(vga_mode);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */
2168c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int status;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	sn9c2028_read1(gspca_dev);
2218c2ecf20Sopenharmony_ci	sn9c2028_read1(gspca_dev);
2228c2ecf20Sopenharmony_ci	status = sn9c2028_read1(gspca_dev);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return (status < 0) ? status : 0;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int run_start_commands(struct gspca_dev *gspca_dev,
2288c2ecf20Sopenharmony_ci			      struct init_command *cam_commands, int n)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	int i, err_code = -1;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
2338c2ecf20Sopenharmony_ci		switch (cam_commands[i].to_read) {
2348c2ecf20Sopenharmony_ci		case 4:
2358c2ecf20Sopenharmony_ci			err_code = sn9c2028_long_command(gspca_dev,
2368c2ecf20Sopenharmony_ci					cam_commands[i].instruction);
2378c2ecf20Sopenharmony_ci			break;
2388c2ecf20Sopenharmony_ci		case 1:
2398c2ecf20Sopenharmony_ci			err_code = sn9c2028_short_command(gspca_dev,
2408c2ecf20Sopenharmony_ci					cam_commands[i].instruction);
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci		case 0:
2438c2ecf20Sopenharmony_ci			err_code = sn9c2028_command(gspca_dev,
2448c2ecf20Sopenharmony_ci					cam_commands[i].instruction);
2458c2ecf20Sopenharmony_ci			break;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci		if (err_code < 0)
2488c2ecf20Sopenharmony_ci			return err_code;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	return 0;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic void set_gain(struct gspca_dev *gspca_dev, s32 g)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	struct init_command genius_vcam_live_gain_cmds[] = {
2588c2ecf20Sopenharmony_ci		{{0x1d, 0x25, 0x10 /* This byte is gain */,
2598c2ecf20Sopenharmony_ci		  0x20, 0xab, 0x00}, 0},
2608c2ecf20Sopenharmony_ci	};
2618c2ecf20Sopenharmony_ci	if (!gspca_dev->streaming)
2628c2ecf20Sopenharmony_ci		return;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	switch (sd->model) {
2658c2ecf20Sopenharmony_ci	case 0x7003:
2668c2ecf20Sopenharmony_ci		genius_vcam_live_gain_cmds[0].instruction[2] = g;
2678c2ecf20Sopenharmony_ci		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
2688c2ecf20Sopenharmony_ci				   ARRAY_SIZE(genius_vcam_live_gain_cmds));
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	default:
2718c2ecf20Sopenharmony_ci		break;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev =
2788c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
2798c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *)gspca_dev;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	gspca_dev->usb_err = 0;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!gspca_dev->streaming)
2848c2ecf20Sopenharmony_ci		return 0;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	switch (ctrl->id) {
2878c2ecf20Sopenharmony_ci	/* standalone gain control */
2888c2ecf20Sopenharmony_ci	case V4L2_CID_GAIN:
2898c2ecf20Sopenharmony_ci		set_gain(gspca_dev, ctrl->val);
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	/* autogain */
2928c2ecf20Sopenharmony_ci	case V4L2_CID_AUTOGAIN:
2938c2ecf20Sopenharmony_ci		set_gain(gspca_dev, sd->gain->val);
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci	return gspca_dev->usb_err;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = {
3008c2ecf20Sopenharmony_ci	.s_ctrl = sd_s_ctrl,
3018c2ecf20Sopenharmony_ci};
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
3078c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *)gspca_dev;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	gspca_dev->vdev.ctrl_handler = hdl;
3108c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 2);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	switch (sd->model) {
3138c2ecf20Sopenharmony_ci	case 0x7003:
3148c2ecf20Sopenharmony_ci		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
3158c2ecf20Sopenharmony_ci			V4L2_CID_GAIN, 0, 20, 1, 0);
3168c2ecf20Sopenharmony_ci		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
3178c2ecf20Sopenharmony_ci			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
3188c2ecf20Sopenharmony_ci		break;
3198c2ecf20Sopenharmony_ci	default:
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_cistatic int start_spy_cam(struct gspca_dev *gspca_dev)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct init_command spy_start_commands[] = {
3288c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
3298c2ecf20Sopenharmony_ci		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
3308c2ecf20Sopenharmony_ci		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
3318c2ecf20Sopenharmony_ci		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
3328c2ecf20Sopenharmony_ci		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
3338c2ecf20Sopenharmony_ci		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
3348c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width  352 */
3358c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */
3368c2ecf20Sopenharmony_ci		/* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */
3378c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},
3388c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/
3398c2ecf20Sopenharmony_ci		/* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */
3408c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
3418c2ecf20Sopenharmony_ci		/* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */
3428c2ecf20Sopenharmony_ci		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
3438c2ecf20Sopenharmony_ci		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
3448c2ecf20Sopenharmony_ci		/* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */
3458c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
3468c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
3478c2ecf20Sopenharmony_ci		/* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */
3488c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
3498c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
3508c2ecf20Sopenharmony_ci		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
3518c2ecf20Sopenharmony_ci		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
3528c2ecf20Sopenharmony_ci		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
3538c2ecf20Sopenharmony_ci		{{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},
3548c2ecf20Sopenharmony_ci		{{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/
3558c2ecf20Sopenharmony_ci		/*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
3568c2ecf20Sopenharmony_ci		{{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
3578c2ecf20Sopenharmony_ci		/*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */
3588c2ecf20Sopenharmony_ci		{{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
3598c2ecf20Sopenharmony_ci		{{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */
3608c2ecf20Sopenharmony_ci		{{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},
3618c2ecf20Sopenharmony_ci		/*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
3628c2ecf20Sopenharmony_ci		{{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},
3638c2ecf20Sopenharmony_ci		{{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},
3648c2ecf20Sopenharmony_ci		{{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},
3658c2ecf20Sopenharmony_ci		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
3668c2ecf20Sopenharmony_ci		{{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},
3678c2ecf20Sopenharmony_ci		{{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},
3688c2ecf20Sopenharmony_ci		{{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},
3698c2ecf20Sopenharmony_ci		/* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */
3708c2ecf20Sopenharmony_ci		/* brightness or gain. 0 is default. 4 is good
3718c2ecf20Sopenharmony_ci		 * indoors at night with incandescent lighting */
3728c2ecf20Sopenharmony_ci		{{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},
3738c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/
3748c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},
3758c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
3768c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},
3778c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},
3788c2ecf20Sopenharmony_ci		/* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */
3798c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */
3808c2ecf20Sopenharmony_ci		/* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */
3818c2ecf20Sopenharmony_ci		{{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},
3828c2ecf20Sopenharmony_ci		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */
3838c2ecf20Sopenharmony_ci		/* Camera should start to capture now. */
3848c2ecf20Sopenharmony_ci	};
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return run_start_commands(gspca_dev, spy_start_commands,
3878c2ecf20Sopenharmony_ci				  ARRAY_SIZE(spy_start_commands));
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int start_cif_cam(struct gspca_dev *gspca_dev)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct init_command cif_start_commands[] = {
3938c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
3948c2ecf20Sopenharmony_ci		/* The entire sequence below seems redundant */
3958c2ecf20Sopenharmony_ci		/* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
3968c2ecf20Sopenharmony_ci		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
3978c2ecf20Sopenharmony_ci		{{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},
3988c2ecf20Sopenharmony_ci		{{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},
3998c2ecf20Sopenharmony_ci		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
4008c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?
4018c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?
4028c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
4038c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
4048c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
4058c2ecf20Sopenharmony_ci		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
4068c2ecf20Sopenharmony_ci		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
4078c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4088c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
4098c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
4108c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
4118c2ecf20Sopenharmony_ci		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
4128c2ecf20Sopenharmony_ci		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
4138c2ecf20Sopenharmony_ci		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/
4148c2ecf20Sopenharmony_ci		{{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},
4158c2ecf20Sopenharmony_ci		{{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},
4168c2ecf20Sopenharmony_ci		{{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},
4178c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
4188c2ecf20Sopenharmony_ci		{{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},
4198c2ecf20Sopenharmony_ci		{{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},
4208c2ecf20Sopenharmony_ci		{{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},
4218c2ecf20Sopenharmony_ci		{{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},
4228c2ecf20Sopenharmony_ci		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
4238c2ecf20Sopenharmony_ci		{{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},
4248c2ecf20Sopenharmony_ci		{{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},
4258c2ecf20Sopenharmony_ci		{{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},
4268c2ecf20Sopenharmony_ci		{{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},
4278c2ecf20Sopenharmony_ci		{{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},
4288c2ecf20Sopenharmony_ci		{{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},
4298c2ecf20Sopenharmony_ci		{{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},
4308c2ecf20Sopenharmony_ci		{{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},
4318c2ecf20Sopenharmony_ci		{{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},
4328c2ecf20Sopenharmony_ci		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
4338c2ecf20Sopenharmony_ci		{{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},
4348c2ecf20Sopenharmony_ci		{{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},
4358c2ecf20Sopenharmony_ci		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
4368c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */
4378c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */
4388c2ecf20Sopenharmony_ci		/* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
4398c2ecf20Sopenharmony_ci		 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing
4408c2ecf20Sopenharmony_ci		 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */
4418c2ecf20Sopenharmony_ci		/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
4428c2ecf20Sopenharmony_ci		 * causes subsampling
4438c2ecf20Sopenharmony_ci		 * but not a change in the resolution setting! */
4448c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4458c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},
4468c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},
4478c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},
4488c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
4498c2ecf20Sopenharmony_ci		{{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},
4508c2ecf20Sopenharmony_ci		{{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},
4518c2ecf20Sopenharmony_ci		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
4528c2ecf20Sopenharmony_ci		{{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},
4538c2ecf20Sopenharmony_ci		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
4548c2ecf20Sopenharmony_ci		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
4558c2ecf20Sopenharmony_ci		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
4568c2ecf20Sopenharmony_ci		{{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},
4578c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
4588c2ecf20Sopenharmony_ci		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
4598c2ecf20Sopenharmony_ci		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */
4608c2ecf20Sopenharmony_ci		/* Camera should start to capture now. */
4618c2ecf20Sopenharmony_ci	};
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return run_start_commands(gspca_dev, cif_start_commands,
4648c2ecf20Sopenharmony_ci				  ARRAY_SIZE(cif_start_commands));
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic int start_ms350_cam(struct gspca_dev *gspca_dev)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct init_command ms350_start_commands[] = {
4708c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
4718c2ecf20Sopenharmony_ci		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
4728c2ecf20Sopenharmony_ci		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
4738c2ecf20Sopenharmony_ci		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
4748c2ecf20Sopenharmony_ci		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
4758c2ecf20Sopenharmony_ci		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
4768c2ecf20Sopenharmony_ci		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
4778c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
4788c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
4798c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
4808c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},
4818c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
4828c2ecf20Sopenharmony_ci		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
4838c2ecf20Sopenharmony_ci		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
4848c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
4858c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
4868c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
4878c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
4888c2ecf20Sopenharmony_ci		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
4898c2ecf20Sopenharmony_ci		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
4908c2ecf20Sopenharmony_ci		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
4918c2ecf20Sopenharmony_ci		{{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},
4928c2ecf20Sopenharmony_ci		{{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},
4938c2ecf20Sopenharmony_ci		{{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},
4948c2ecf20Sopenharmony_ci		{{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},
4958c2ecf20Sopenharmony_ci		{{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},
4968c2ecf20Sopenharmony_ci		{{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},
4978c2ecf20Sopenharmony_ci		{{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},
4988c2ecf20Sopenharmony_ci		{{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},
4998c2ecf20Sopenharmony_ci		{{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},
5008c2ecf20Sopenharmony_ci		{{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},
5018c2ecf20Sopenharmony_ci		{{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},
5028c2ecf20Sopenharmony_ci		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
5038c2ecf20Sopenharmony_ci		{{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},
5048c2ecf20Sopenharmony_ci		{{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},
5058c2ecf20Sopenharmony_ci		{{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},
5068c2ecf20Sopenharmony_ci		{{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},
5078c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5088c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},
5098c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5108c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},
5118c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},
5128c2ecf20Sopenharmony_ci		{{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},
5138c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},
5148c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width  */
5158c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */
5168c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */
5178c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
5188c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */
5198c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5208c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
5218c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
5228c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
5238c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},
5248c2ecf20Sopenharmony_ci		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
5258c2ecf20Sopenharmony_ci		{{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},
5268c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},
5278c2ecf20Sopenharmony_ci		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},
5288c2ecf20Sopenharmony_ci		/* Camera should start to capture now. */
5298c2ecf20Sopenharmony_ci	};
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return run_start_commands(gspca_dev, ms350_start_commands,
5328c2ecf20Sopenharmony_ci				  ARRAY_SIZE(ms350_start_commands));
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic int start_genius_cam(struct gspca_dev *gspca_dev)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct init_command genius_start_commands[] = {
5388c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
5398c2ecf20Sopenharmony_ci		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
5408c2ecf20Sopenharmony_ci		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
5418c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
5428c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
5438c2ecf20Sopenharmony_ci		/* "preliminary" width and height settings */
5448c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
5458c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
5468c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
5478c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5488c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
5498c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
5508c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
5518c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5528c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
5538c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5548c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
5558c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5568c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
5578c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5588c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
5598c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
5608c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
5618c2ecf20Sopenharmony_ci		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
5628c2ecf20Sopenharmony_ci		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
5638c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5648c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
5658c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5668c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
5678c2ecf20Sopenharmony_ci		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
5688c2ecf20Sopenharmony_ci		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
5698c2ecf20Sopenharmony_ci		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
5708c2ecf20Sopenharmony_ci		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
5718c2ecf20Sopenharmony_ci		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
5728c2ecf20Sopenharmony_ci		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
5738c2ecf20Sopenharmony_ci		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
5748c2ecf20Sopenharmony_ci		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
5758c2ecf20Sopenharmony_ci		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
5768c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */
5778c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */
5788c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
5798c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
5808c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
5818c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
5828c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
5838c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
5848c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
5858c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
5868c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
5878c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
5888c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
5898c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
5908c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
5918c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
5928c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
5938c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
5948c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
5958c2ecf20Sopenharmony_ci		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
5968c2ecf20Sopenharmony_ci		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
5978c2ecf20Sopenharmony_ci		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
5988c2ecf20Sopenharmony_ci		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
5998c2ecf20Sopenharmony_ci		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}
6008c2ecf20Sopenharmony_ci		/* Camera should start to capture now. */
6018c2ecf20Sopenharmony_ci	};
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return run_start_commands(gspca_dev, genius_start_commands,
6048c2ecf20Sopenharmony_ci				  ARRAY_SIZE(genius_start_commands));
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int start_genius_videocam_live(struct gspca_dev *gspca_dev)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	int r;
6108c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
6118c2ecf20Sopenharmony_ci	struct init_command genius_vcam_live_start_commands[] = {
6128c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},
6138c2ecf20Sopenharmony_ci		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
6148c2ecf20Sopenharmony_ci		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
6158c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
6168c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
6198c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
6208c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
6218c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
6228c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
6238c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
6248c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
6258c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
6268c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
6278c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
6288c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
6298c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
6308c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
6318c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
6328c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
6338c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
6348c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
6358c2ecf20Sopenharmony_ci		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
6368c2ecf20Sopenharmony_ci		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
6378c2ecf20Sopenharmony_ci		{{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},
6388c2ecf20Sopenharmony_ci		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
6398c2ecf20Sopenharmony_ci		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
6408c2ecf20Sopenharmony_ci		{{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},
6418c2ecf20Sopenharmony_ci		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
6428c2ecf20Sopenharmony_ci		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
6438c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
6448c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
6458c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
6468c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
6478c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
6488c2ecf20Sopenharmony_ci		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
6498c2ecf20Sopenharmony_ci		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
6508c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
6518c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
6528c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
6538c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
6548c2ecf20Sopenharmony_ci		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
6558c2ecf20Sopenharmony_ci		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
6568c2ecf20Sopenharmony_ci		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
6578c2ecf20Sopenharmony_ci		{{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},
6588c2ecf20Sopenharmony_ci		{{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},
6598c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
6608c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
6618c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
6628c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
6638c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
6648c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
6658c2ecf20Sopenharmony_ci		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
6668c2ecf20Sopenharmony_ci		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
6678c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
6688c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
6698c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
6708c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
6718c2ecf20Sopenharmony_ci		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
6728c2ecf20Sopenharmony_ci		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
6738c2ecf20Sopenharmony_ci		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
6748c2ecf20Sopenharmony_ci		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
6758c2ecf20Sopenharmony_ci		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
6768c2ecf20Sopenharmony_ci		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
6778c2ecf20Sopenharmony_ci		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
6788c2ecf20Sopenharmony_ci		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
6798c2ecf20Sopenharmony_ci		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
6808c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
6818c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
6828c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
6838c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
6848c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
6858c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
6868c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
6878c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
6888c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
6898c2ecf20Sopenharmony_ci		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
6908c2ecf20Sopenharmony_ci		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
6918c2ecf20Sopenharmony_ci		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
6928c2ecf20Sopenharmony_ci		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
6938c2ecf20Sopenharmony_ci		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
6948c2ecf20Sopenharmony_ci		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
6958c2ecf20Sopenharmony_ci		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
6968c2ecf20Sopenharmony_ci		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
6978c2ecf20Sopenharmony_ci		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
6988c2ecf20Sopenharmony_ci		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
6998c2ecf20Sopenharmony_ci		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
7008c2ecf20Sopenharmony_ci		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
7018c2ecf20Sopenharmony_ci		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
7028c2ecf20Sopenharmony_ci		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},
7038c2ecf20Sopenharmony_ci		/* Camera should start to capture now. */
7048c2ecf20Sopenharmony_ci		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},
7058c2ecf20Sopenharmony_ci		{{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},
7068c2ecf20Sopenharmony_ci		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
7078c2ecf20Sopenharmony_ci	};
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,
7108c2ecf20Sopenharmony_ci				  ARRAY_SIZE(genius_vcam_live_start_commands));
7118c2ecf20Sopenharmony_ci	if (r < 0)
7128c2ecf20Sopenharmony_ci		return r;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (sd->gain)
7158c2ecf20Sopenharmony_ci		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return r;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic int start_vivitar_cam(struct gspca_dev *gspca_dev)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct init_command vivitar_start_commands[] = {
7238c2ecf20Sopenharmony_ci		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
7248c2ecf20Sopenharmony_ci		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
7258c2ecf20Sopenharmony_ci		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
7268c2ecf20Sopenharmony_ci		{{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},
7278c2ecf20Sopenharmony_ci		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
7288c2ecf20Sopenharmony_ci		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
7298c2ecf20Sopenharmony_ci		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
7308c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
7318c2ecf20Sopenharmony_ci		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
7328c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},
7338c2ecf20Sopenharmony_ci		/*
7348c2ecf20Sopenharmony_ci		 * Above is changed from OEM 0x0b. Fixes Bayer tiling.
7358c2ecf20Sopenharmony_ci		 * Presumably gives a vertical shift of one row.
7368c2ecf20Sopenharmony_ci		 */
7378c2ecf20Sopenharmony_ci		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
7388c2ecf20Sopenharmony_ci		/* Above seems to do horizontal shift. */
7398c2ecf20Sopenharmony_ci		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
7408c2ecf20Sopenharmony_ci		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
7418c2ecf20Sopenharmony_ci		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
7428c2ecf20Sopenharmony_ci		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
7438c2ecf20Sopenharmony_ci		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
7448c2ecf20Sopenharmony_ci		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
7458c2ecf20Sopenharmony_ci		/* Above three commands seem to relate to brightness. */
7468c2ecf20Sopenharmony_ci		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
7478c2ecf20Sopenharmony_ci		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
7488c2ecf20Sopenharmony_ci		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
7498c2ecf20Sopenharmony_ci		{{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},
7508c2ecf20Sopenharmony_ci		{{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},
7518c2ecf20Sopenharmony_ci		{{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},
7528c2ecf20Sopenharmony_ci		{{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},
7538c2ecf20Sopenharmony_ci		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
7548c2ecf20Sopenharmony_ci		{{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},
7558c2ecf20Sopenharmony_ci		{{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},
7568c2ecf20Sopenharmony_ci		{{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},
7578c2ecf20Sopenharmony_ci		{{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},
7588c2ecf20Sopenharmony_ci		{{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},
7598c2ecf20Sopenharmony_ci		{{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},
7608c2ecf20Sopenharmony_ci		{{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},
7618c2ecf20Sopenharmony_ci		{{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},
7628c2ecf20Sopenharmony_ci		{{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
7638c2ecf20Sopenharmony_ci		{{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},
7648c2ecf20Sopenharmony_ci		{{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},
7658c2ecf20Sopenharmony_ci		{{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},
7668c2ecf20Sopenharmony_ci		{{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},
7678c2ecf20Sopenharmony_ci		{{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},
7688c2ecf20Sopenharmony_ci		{{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},
7698c2ecf20Sopenharmony_ci		{{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},
7708c2ecf20Sopenharmony_ci		{{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},
7718c2ecf20Sopenharmony_ci		{{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},
7728c2ecf20Sopenharmony_ci		{{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},
7738c2ecf20Sopenharmony_ci		{{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},
7748c2ecf20Sopenharmony_ci		{{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},
7758c2ecf20Sopenharmony_ci		{{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},
7768c2ecf20Sopenharmony_ci		{{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},
7778c2ecf20Sopenharmony_ci		{{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},
7788c2ecf20Sopenharmony_ci		{{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},
7798c2ecf20Sopenharmony_ci		{{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},
7808c2ecf20Sopenharmony_ci		{{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},
7818c2ecf20Sopenharmony_ci		{{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},
7828c2ecf20Sopenharmony_ci		{{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},
7838c2ecf20Sopenharmony_ci		/* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
7848c2ecf20Sopenharmony_ci		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
7858c2ecf20Sopenharmony_ci		{{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */
7868c2ecf20Sopenharmony_ci		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
7878c2ecf20Sopenharmony_ci		{{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},
7888c2ecf20Sopenharmony_ci		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
7898c2ecf20Sopenharmony_ci		{{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},
7908c2ecf20Sopenharmony_ci		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
7918c2ecf20Sopenharmony_ci		{{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},
7928c2ecf20Sopenharmony_ci		/* Above is brightness; OEM driver setting is 0x10 */
7938c2ecf20Sopenharmony_ci		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
7948c2ecf20Sopenharmony_ci		{{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
7958c2ecf20Sopenharmony_ci		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}
7968c2ecf20Sopenharmony_ci	};
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return run_start_commands(gspca_dev, vivitar_start_commands,
7998c2ecf20Sopenharmony_ci				  ARRAY_SIZE(vivitar_start_commands));
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
8058c2ecf20Sopenharmony_ci	int err_code;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	sd->sof_read = 0;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	switch (sd->model) {
8108c2ecf20Sopenharmony_ci	case 0x7005:
8118c2ecf20Sopenharmony_ci		err_code = start_genius_cam(gspca_dev);
8128c2ecf20Sopenharmony_ci		break;
8138c2ecf20Sopenharmony_ci	case 0x7003:
8148c2ecf20Sopenharmony_ci		err_code = start_genius_videocam_live(gspca_dev);
8158c2ecf20Sopenharmony_ci		break;
8168c2ecf20Sopenharmony_ci	case 0x8001:
8178c2ecf20Sopenharmony_ci		err_code = start_spy_cam(gspca_dev);
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci	case 0x8003:
8208c2ecf20Sopenharmony_ci		err_code = start_cif_cam(gspca_dev);
8218c2ecf20Sopenharmony_ci		break;
8228c2ecf20Sopenharmony_ci	case 0x8008:
8238c2ecf20Sopenharmony_ci		err_code = start_ms350_cam(gspca_dev);
8248c2ecf20Sopenharmony_ci		break;
8258c2ecf20Sopenharmony_ci	case 0x800a:
8268c2ecf20Sopenharmony_ci		err_code = start_vivitar_cam(gspca_dev);
8278c2ecf20Sopenharmony_ci		break;
8288c2ecf20Sopenharmony_ci	default:
8298c2ecf20Sopenharmony_ci		pr_err("Starting unknown camera, please report this\n");
8308c2ecf20Sopenharmony_ci		return -ENXIO;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	sd->avg_lum = -1;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	return err_code;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	int result;
8418c2ecf20Sopenharmony_ci	__u8 data[6];
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	result = sn9c2028_read1(gspca_dev);
8448c2ecf20Sopenharmony_ci	if (result < 0)
8458c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "Camera Stop read failed\n");
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	memset(data, 0, 6);
8488c2ecf20Sopenharmony_ci	data[0] = 0x14;
8498c2ecf20Sopenharmony_ci	result = sn9c2028_command(gspca_dev, data);
8508c2ecf20Sopenharmony_ci	if (result < 0)
8518c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "Camera Stop command failed\n");
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
8578c2ecf20Sopenharmony_ci	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (avg_lum == -1)
8608c2ecf20Sopenharmony_ci		return;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (avg_lum < MIN_AVG_LUM) {
8638c2ecf20Sopenharmony_ci		if (cur_gain == sd->gain->maximum)
8648c2ecf20Sopenharmony_ci			return;
8658c2ecf20Sopenharmony_ci		cur_gain++;
8668c2ecf20Sopenharmony_ci		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
8678c2ecf20Sopenharmony_ci	}
8688c2ecf20Sopenharmony_ci	if (avg_lum > MAX_AVG_LUM) {
8698c2ecf20Sopenharmony_ci		if (cur_gain == sd->gain->minimum)
8708c2ecf20Sopenharmony_ci			return;
8718c2ecf20Sopenharmony_ci		cur_gain--;
8728c2ecf20Sopenharmony_ci		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic void sd_dqcallback(struct gspca_dev *gspca_dev)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
8828c2ecf20Sopenharmony_ci		return;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	do_autogain(gspca_dev, sd->avg_lum);
8858c2ecf20Sopenharmony_ci}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci/* Include sn9c2028 sof detection functions */
8888c2ecf20Sopenharmony_ci#include "sn9c2028.h"
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev,
8918c2ecf20Sopenharmony_ci			__u8 *data,			/* isoc packet */
8928c2ecf20Sopenharmony_ci			int len)			/* iso packet length */
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	unsigned char *sof;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	sof = sn9c2028_find_sof(gspca_dev, data, len);
8978c2ecf20Sopenharmony_ci	if (sof) {
8988c2ecf20Sopenharmony_ci		int n;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci		/* finish decoding current frame */
9018c2ecf20Sopenharmony_ci		n = sof - data;
9028c2ecf20Sopenharmony_ci		if (n > sizeof sn9c2028_sof_marker)
9038c2ecf20Sopenharmony_ci			n -= sizeof sn9c2028_sof_marker;
9048c2ecf20Sopenharmony_ci		else
9058c2ecf20Sopenharmony_ci			n = 0;
9068c2ecf20Sopenharmony_ci		gspca_frame_add(gspca_dev, LAST_PACKET, data, n);
9078c2ecf20Sopenharmony_ci		/* Start next frame. */
9088c2ecf20Sopenharmony_ci		gspca_frame_add(gspca_dev, FIRST_PACKET,
9098c2ecf20Sopenharmony_ci			sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);
9108c2ecf20Sopenharmony_ci		len -= sof - data;
9118c2ecf20Sopenharmony_ci		data = sof;
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci/* sub-driver description */
9178c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = {
9188c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
9198c2ecf20Sopenharmony_ci	.config = sd_config,
9208c2ecf20Sopenharmony_ci	.init = sd_init,
9218c2ecf20Sopenharmony_ci	.init_controls = sd_init_controls,
9228c2ecf20Sopenharmony_ci	.start = sd_start,
9238c2ecf20Sopenharmony_ci	.stopN = sd_stopN,
9248c2ecf20Sopenharmony_ci	.dq_callback = sd_dqcallback,
9258c2ecf20Sopenharmony_ci	.pkt_scan = sd_pkt_scan,
9268c2ecf20Sopenharmony_ci};
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci/* -- module initialisation -- */
9298c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = {
9308c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
9318c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2  */
9328c2ecf20Sopenharmony_ci	/* The Genius Smart is untested. I can't find an owner ! */
9338c2ecf20Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
9348c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
9358c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */
9368c2ecf20Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */
9378c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */
9388c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */
9398c2ecf20Sopenharmony_ci	{}
9408c2ecf20Sopenharmony_ci};
9418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci/* -- device connect -- */
9448c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
9458c2ecf20Sopenharmony_ci			const struct usb_device_id *id)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
9488c2ecf20Sopenharmony_ci			       THIS_MODULE);
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = {
9528c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
9538c2ecf20Sopenharmony_ci	.id_table = device_table,
9548c2ecf20Sopenharmony_ci	.probe = sd_probe,
9558c2ecf20Sopenharmony_ci	.disconnect = gspca_disconnect,
9568c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
9578c2ecf20Sopenharmony_ci	.suspend = gspca_suspend,
9588c2ecf20Sopenharmony_ci	.resume = gspca_resume,
9598c2ecf20Sopenharmony_ci	.reset_resume = gspca_resume,
9608c2ecf20Sopenharmony_ci#endif
9618c2ecf20Sopenharmony_ci};
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver);
964