brintos

brintos / linux-shallow public Read only

0
0
Text · 31.2 KiB · dbd1d6d Raw
964 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * SN9C2028 library4 *5 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#define MODULE_NAME "sn9c2028"11 12#include "gspca.h"13 14MODULE_AUTHOR("Theodore Kilgore");15MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");16MODULE_LICENSE("GPL");17 18/* specific webcam descriptor */19struct sd {20	struct gspca_dev gspca_dev;  /* !! must be the first item */21	u8 sof_read;22	u16 model;23 24#define MIN_AVG_LUM 850025#define MAX_AVG_LUM 1000026	int avg_lum;27	u8 avg_lum_l;28 29	struct { /* autogain and gain control cluster */30		struct v4l2_ctrl *autogain;31		struct v4l2_ctrl *gain;32	};33};34 35struct init_command {36	unsigned char instruction[6];37	unsigned char to_read; /* length to read. 0 means no reply requested */38};39 40/* How to change the resolution of any of the VGA cams is unknown */41static const struct v4l2_pix_format vga_mode[] = {42	{640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,43		.bytesperline = 640,44		.sizeimage = 640 * 480 * 3 / 4,45		.colorspace = V4L2_COLORSPACE_SRGB,46		.priv = 0},47};48 49/* No way to change the resolution of the CIF cams is known */50static const struct v4l2_pix_format cif_mode[] = {51	{352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,52		.bytesperline = 352,53		.sizeimage = 352 * 288 * 3 / 4,54		.colorspace = V4L2_COLORSPACE_SRGB,55		.priv = 0},56};57 58/* the bytes to write are in gspca_dev->usb_buf */59static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)60{61	int rc;62 63	gspca_dbg(gspca_dev, D_USBO, "sending command %02x%02x%02x%02x%02x%02x\n",64		  command[0], command[1], command[2],65		  command[3], command[4], command[5]);66 67	memcpy(gspca_dev->usb_buf, command, 6);68	rc = usb_control_msg(gspca_dev->dev,69			usb_sndctrlpipe(gspca_dev->dev, 0),70			USB_REQ_GET_CONFIGURATION,71			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,72			2, 0, gspca_dev->usb_buf, 6, 500);73	if (rc < 0) {74		pr_err("command write [%02x] error %d\n",75		       gspca_dev->usb_buf[0], rc);76		return rc;77	}78 79	return 0;80}81 82static int sn9c2028_read1(struct gspca_dev *gspca_dev)83{84	int rc;85 86	rc = usb_control_msg(gspca_dev->dev,87			usb_rcvctrlpipe(gspca_dev->dev, 0),88			USB_REQ_GET_STATUS,89			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,90			1, 0, gspca_dev->usb_buf, 1, 500);91	if (rc != 1) {92		pr_err("read1 error %d\n", rc);93		return (rc < 0) ? rc : -EIO;94	}95	gspca_dbg(gspca_dev, D_USBI, "read1 response %02x\n",96		  gspca_dev->usb_buf[0]);97	return gspca_dev->usb_buf[0];98}99 100static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)101{102	int rc;103	rc = usb_control_msg(gspca_dev->dev,104			usb_rcvctrlpipe(gspca_dev->dev, 0),105			USB_REQ_GET_STATUS,106			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,107			4, 0, gspca_dev->usb_buf, 4, 500);108	if (rc != 4) {109		pr_err("read4 error %d\n", rc);110		return (rc < 0) ? rc : -EIO;111	}112	memcpy(reading, gspca_dev->usb_buf, 4);113	gspca_dbg(gspca_dev, D_USBI, "read4 response %02x%02x%02x%02x\n",114		  reading[0], reading[1], reading[2], reading[3]);115	return rc;116}117 118static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)119{120	int i, status;121	__u8 reading[4];122 123	status = sn9c2028_command(gspca_dev, command);124	if (status < 0)125		return status;126 127	status = -1;128	for (i = 0; i < 256 && status < 2; i++)129		status = sn9c2028_read1(gspca_dev);130	if (status < 0) {131		pr_err("long command status read error %d\n", status);132		return status;133	}134 135	memset(reading, 0, 4);136	status = sn9c2028_read4(gspca_dev, reading);137	if (status < 0)138		return status;139 140	/* in general, the first byte of the response is the first byte of141	 * the command, or'ed with 8 */142	status = sn9c2028_read1(gspca_dev);143	if (status < 0)144		return status;145 146	return 0;147}148 149static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)150{151	int err_code;152 153	err_code = sn9c2028_command(gspca_dev, command);154	if (err_code < 0)155		return err_code;156 157	err_code = sn9c2028_read1(gspca_dev);158	if (err_code < 0)159		return err_code;160 161	return 0;162}163 164/* this function is called at probe time */165static int sd_config(struct gspca_dev *gspca_dev,166		     const struct usb_device_id *id)167{168	struct sd *sd = (struct sd *) gspca_dev;169	struct cam *cam = &gspca_dev->cam;170 171	gspca_dbg(gspca_dev, D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)\n",172		  id->idVendor, id->idProduct);173 174	sd->model = id->idProduct;175 176	switch (sd->model) {177	case 0x7005:178		gspca_dbg(gspca_dev, D_PROBE, "Genius Smart 300 camera\n");179		break;180	case 0x7003:181		gspca_dbg(gspca_dev, D_PROBE, "Genius Videocam Live v2\n");182		break;183	case 0x8000:184		gspca_dbg(gspca_dev, D_PROBE, "DC31VC\n");185		break;186	case 0x8001:187		gspca_dbg(gspca_dev, D_PROBE, "Spy camera\n");188		break;189	case 0x8003:190		gspca_dbg(gspca_dev, D_PROBE, "CIF camera\n");191		break;192	case 0x8008:193		gspca_dbg(gspca_dev, D_PROBE, "Mini-Shotz ms-350 camera\n");194		break;195	case 0x800a:196		gspca_dbg(gspca_dev, D_PROBE, "Vivitar 3350b type camera\n");197		cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;198		break;199	}200 201	switch (sd->model) {202	case 0x8000:203	case 0x8001:204	case 0x8003:205		cam->cam_mode = cif_mode;206		cam->nmodes = ARRAY_SIZE(cif_mode);207		break;208	default:209		cam->cam_mode = vga_mode;210		cam->nmodes = ARRAY_SIZE(vga_mode);211	}212	return 0;213}214 215/* this function is called at probe and resume time */216static int sd_init(struct gspca_dev *gspca_dev)217{218	int status;219 220	sn9c2028_read1(gspca_dev);221	sn9c2028_read1(gspca_dev);222	status = sn9c2028_read1(gspca_dev);223 224	return (status < 0) ? status : 0;225}226 227static int run_start_commands(struct gspca_dev *gspca_dev,228			      struct init_command *cam_commands, int n)229{230	int i, err_code = -1;231 232	for (i = 0; i < n; i++) {233		switch (cam_commands[i].to_read) {234		case 4:235			err_code = sn9c2028_long_command(gspca_dev,236					cam_commands[i].instruction);237			break;238		case 1:239			err_code = sn9c2028_short_command(gspca_dev,240					cam_commands[i].instruction);241			break;242		case 0:243			err_code = sn9c2028_command(gspca_dev,244					cam_commands[i].instruction);245			break;246		}247		if (err_code < 0)248			return err_code;249	}250	return 0;251}252 253static void set_gain(struct gspca_dev *gspca_dev, s32 g)254{255	struct sd *sd = (struct sd *) gspca_dev;256 257	struct init_command genius_vcam_live_gain_cmds[] = {258		{{0x1d, 0x25, 0x10 /* This byte is gain */,259		  0x20, 0xab, 0x00}, 0},260	};261	if (!gspca_dev->streaming)262		return;263 264	switch (sd->model) {265	case 0x7003:266		genius_vcam_live_gain_cmds[0].instruction[2] = g;267		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,268				   ARRAY_SIZE(genius_vcam_live_gain_cmds));269		break;270	default:271		break;272	}273}274 275static int sd_s_ctrl(struct v4l2_ctrl *ctrl)276{277	struct gspca_dev *gspca_dev =278		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);279	struct sd *sd = (struct sd *)gspca_dev;280 281	gspca_dev->usb_err = 0;282 283	if (!gspca_dev->streaming)284		return 0;285 286	switch (ctrl->id) {287	/* standalone gain control */288	case V4L2_CID_GAIN:289		set_gain(gspca_dev, ctrl->val);290		break;291	/* autogain */292	case V4L2_CID_AUTOGAIN:293		set_gain(gspca_dev, sd->gain->val);294		break;295	}296	return gspca_dev->usb_err;297}298 299static const struct v4l2_ctrl_ops sd_ctrl_ops = {300	.s_ctrl = sd_s_ctrl,301};302 303 304static int sd_init_controls(struct gspca_dev *gspca_dev)305{306	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;307	struct sd *sd = (struct sd *)gspca_dev;308 309	gspca_dev->vdev.ctrl_handler = hdl;310	v4l2_ctrl_handler_init(hdl, 2);311 312	switch (sd->model) {313	case 0x7003:314		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,315			V4L2_CID_GAIN, 0, 20, 1, 0);316		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,317			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);318		break;319	default:320		break;321	}322 323	return 0;324}325static int start_spy_cam(struct gspca_dev *gspca_dev)326{327	struct init_command spy_start_commands[] = {328		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},329		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},330		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},331		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},332		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},333		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},334		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width  352 */335		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */336		/* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */337		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},338		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/339		/* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */340		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},341		/* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */342		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},343		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},344		/* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */345		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},346		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},347		/* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */348		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},349		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},350		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},351		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},352		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},353		{{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},354		{{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/355		/*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */356		{{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */357		/*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */358		{{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */359		{{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */360		{{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},361		/*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */362		{{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},363		{{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},364		{{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},365		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},366		{{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},367		{{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},368		{{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},369		/* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */370		/* brightness or gain. 0 is default. 4 is good371		 * indoors at night with incandescent lighting */372		{{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},373		{{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/374		{{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},375		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},376		{{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},377		{{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},378		/* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */379		{{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */380		/* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */381		{{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},382		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */383		/* Camera should start to capture now. */384	};385 386	return run_start_commands(gspca_dev, spy_start_commands,387				  ARRAY_SIZE(spy_start_commands));388}389 390static int start_cif_cam(struct gspca_dev *gspca_dev)391{392	struct init_command cif_start_commands[] = {393		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},394		/* The entire sequence below seems redundant */395		/* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},396		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},397		{{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},398		{{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},399		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},400		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?401		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?402		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?403		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},404		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},405		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},406		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},407		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},408		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},409		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},410		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},411		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},412		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},413		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/414		{{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},415		{{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},416		{{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},417		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},418		{{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},419		{{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},420		{{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},421		{{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},422		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},423		{{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},424		{{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},425		{{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},426		{{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},427		{{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},428		{{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},429		{{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},430		{{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},431		{{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},432		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},433		{{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},434		{{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},435		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},436		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */437		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */438		/* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?439		 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing440		 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */441		/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},442		 * causes subsampling443		 * but not a change in the resolution setting! */444		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},445		{{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},446		{{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},447		{{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},448		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},449		{{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},450		{{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},451		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},452		{{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},453		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},454		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},455		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},456		{{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},457		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},458		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},459		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */460		/* Camera should start to capture now. */461	};462 463	return run_start_commands(gspca_dev, cif_start_commands,464				  ARRAY_SIZE(cif_start_commands));465}466 467static int start_ms350_cam(struct gspca_dev *gspca_dev)468{469	struct init_command ms350_start_commands[] = {470		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},471		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},472		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},473		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},474		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},475		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},476		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},477		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},478		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},479		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},480		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},481		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},482		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},483		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},484		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},485		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},486		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},487		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},488		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},489		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},490		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},491		{{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},492		{{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},493		{{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},494		{{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},495		{{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},496		{{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},497		{{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},498		{{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},499		{{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},500		{{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},501		{{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},502		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},503		{{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},504		{{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},505		{{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},506		{{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},507		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},508		{{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},509		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},510		{{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},511		{{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},512		{{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},513		{{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},514		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width  */515		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */516		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */517		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},518		{{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */519		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},520		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},521		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},522		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},523		{{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},524		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},525		{{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},526		{{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},527		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},528		/* Camera should start to capture now. */529	};530 531	return run_start_commands(gspca_dev, ms350_start_commands,532				  ARRAY_SIZE(ms350_start_commands));533}534 535static int start_genius_cam(struct gspca_dev *gspca_dev)536{537	struct init_command genius_start_commands[] = {538		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},539		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},540		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},541		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},542		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},543		/* "preliminary" width and height settings */544		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},545		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},546		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},547		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},548		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},549		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},550		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},551		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},552		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},553		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},554		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},555		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},556		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},557		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},558		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},559		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},560		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},561		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},562		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},563		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},564		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},565		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},566		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},567		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},568		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},569		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},570		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},571		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},572		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},573		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},574		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},575		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},576		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */577		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */578		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},579		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},580		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},581		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},582		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},583		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},584		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},585		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},586		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},587		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},588		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},589		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},590		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},591		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},592		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},593		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},594		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},595		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},596		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},597		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},598		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},599		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}600		/* Camera should start to capture now. */601	};602 603	return run_start_commands(gspca_dev, genius_start_commands,604				  ARRAY_SIZE(genius_start_commands));605}606 607static int start_genius_videocam_live(struct gspca_dev *gspca_dev)608{609	int r;610	struct sd *sd = (struct sd *) gspca_dev;611	struct init_command genius_vcam_live_start_commands[] = {612		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},613		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},614		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},615		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},616		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},617 618		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},619		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},620		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},621		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},622		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},623		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},624		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},625		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},626		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},627		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},628		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},629		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},630		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},631		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},632		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},633		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},634		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},635		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},636		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},637		{{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},638		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},639		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},640		{{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},641		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},642		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},643		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},644		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},645		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},646		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},647		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},648		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},649		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},650		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},651		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},652		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},653		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},654		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},655		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},656		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},657		{{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},658		{{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},659		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},660		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},661		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},662		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},663		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},664		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},665		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},666		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},667		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},668		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},669		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},670		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},671		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},672		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},673		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},674		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},675		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},676		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},677		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},678		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},679		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},680		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},681		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},682		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},683		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},684		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},685		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},686		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},687		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},688		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},689		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},690		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},691		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},692		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},693		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},694		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},695		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},696		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},697		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},698		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},699		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},700		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},701		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},702		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},703		/* Camera should start to capture now. */704		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},705		{{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},706		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},707	};708 709	r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,710				  ARRAY_SIZE(genius_vcam_live_start_commands));711	if (r < 0)712		return r;713 714	if (sd->gain)715		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));716 717	return r;718}719 720static int start_vivitar_cam(struct gspca_dev *gspca_dev)721{722	struct init_command vivitar_start_commands[] = {723		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},724		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},725		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},726		{{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},727		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},728		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},729		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},730		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},731		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},732		{{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},733		/*734		 * Above is changed from OEM 0x0b. Fixes Bayer tiling.735		 * Presumably gives a vertical shift of one row.736		 */737		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},738		/* Above seems to do horizontal shift. */739		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},740		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},741		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},742		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},743		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},744		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},745		/* Above three commands seem to relate to brightness. */746		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},747		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},748		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},749		{{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},750		{{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},751		{{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},752		{{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},753		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},754		{{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},755		{{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},756		{{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},757		{{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},758		{{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},759		{{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},760		{{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},761		{{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},762		{{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},763		{{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},764		{{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},765		{{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},766		{{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},767		{{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},768		{{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},769		{{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},770		{{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},771		{{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},772		{{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},773		{{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},774		{{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},775		{{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},776		{{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},777		{{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},778		{{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},779		{{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},780		{{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},781		{{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},782		{{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},783		/* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},784		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},785		{{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */786		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},787		{{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},788		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},789		{{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},790		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},791		{{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},792		/* Above is brightness; OEM driver setting is 0x10 */793		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},794		{{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},795		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}796	};797 798	return run_start_commands(gspca_dev, vivitar_start_commands,799				  ARRAY_SIZE(vivitar_start_commands));800}801 802static int sd_start(struct gspca_dev *gspca_dev)803{804	struct sd *sd = (struct sd *) gspca_dev;805	int err_code;806 807	sd->sof_read = 0;808 809	switch (sd->model) {810	case 0x7005:811		err_code = start_genius_cam(gspca_dev);812		break;813	case 0x7003:814		err_code = start_genius_videocam_live(gspca_dev);815		break;816	case 0x8001:817		err_code = start_spy_cam(gspca_dev);818		break;819	case 0x8003:820		err_code = start_cif_cam(gspca_dev);821		break;822	case 0x8008:823		err_code = start_ms350_cam(gspca_dev);824		break;825	case 0x800a:826		err_code = start_vivitar_cam(gspca_dev);827		break;828	default:829		pr_err("Starting unknown camera, please report this\n");830		return -ENXIO;831	}832 833	sd->avg_lum = -1;834 835	return err_code;836}837 838static void sd_stopN(struct gspca_dev *gspca_dev)839{840	int result;841	__u8 data[6];842 843	result = sn9c2028_read1(gspca_dev);844	if (result < 0)845		gspca_err(gspca_dev, "Camera Stop read failed\n");846 847	memset(data, 0, 6);848	data[0] = 0x14;849	result = sn9c2028_command(gspca_dev, data);850	if (result < 0)851		gspca_err(gspca_dev, "Camera Stop command failed\n");852}853 854static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)855{856	struct sd *sd = (struct sd *) gspca_dev;857	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);858 859	if (avg_lum == -1)860		return;861 862	if (avg_lum < MIN_AVG_LUM) {863		if (cur_gain == sd->gain->maximum)864			return;865		cur_gain++;866		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);867	}868	if (avg_lum > MAX_AVG_LUM) {869		if (cur_gain == sd->gain->minimum)870			return;871		cur_gain--;872		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);873	}874 875}876 877static void sd_dqcallback(struct gspca_dev *gspca_dev)878{879	struct sd *sd = (struct sd *) gspca_dev;880 881	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))882		return;883 884	do_autogain(gspca_dev, sd->avg_lum);885}886 887/* Include sn9c2028 sof detection functions */888#include "sn9c2028.h"889 890static void sd_pkt_scan(struct gspca_dev *gspca_dev,891			__u8 *data,			/* isoc packet */892			int len)			/* iso packet length */893{894	unsigned char *sof;895 896	sof = sn9c2028_find_sof(gspca_dev, data, len);897	if (sof) {898		int n;899 900		/* finish decoding current frame */901		n = sof - data;902		if (n > sizeof sn9c2028_sof_marker)903			n -= sizeof sn9c2028_sof_marker;904		else905			n = 0;906		gspca_frame_add(gspca_dev, LAST_PACKET, data, n);907		/* Start next frame. */908		gspca_frame_add(gspca_dev, FIRST_PACKET,909			sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);910		len -= sof - data;911		data = sof;912	}913	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);914}915 916/* sub-driver description */917static const struct sd_desc sd_desc = {918	.name = MODULE_NAME,919	.config = sd_config,920	.init = sd_init,921	.init_controls = sd_init_controls,922	.start = sd_start,923	.stopN = sd_stopN,924	.dq_callback = sd_dqcallback,925	.pkt_scan = sd_pkt_scan,926};927 928/* -- module initialisation -- */929static const struct usb_device_id device_table[] = {930	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */931	{USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2  */932	/* The Genius Smart is untested. I can't find an owner ! */933	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */934	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */935	{USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */936	/* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */937	{USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */938	{USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */939	{}940};941MODULE_DEVICE_TABLE(usb, device_table);942 943/* -- device connect -- */944static int sd_probe(struct usb_interface *intf,945			const struct usb_device_id *id)946{947	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),948			       THIS_MODULE);949}950 951static struct usb_driver sd_driver = {952	.name = MODULE_NAME,953	.id_table = device_table,954	.probe = sd_probe,955	.disconnect = gspca_disconnect,956#ifdef CONFIG_PM957	.suspend = gspca_suspend,958	.resume = gspca_resume,959	.reset_resume = gspca_resume,960#endif961};962 963module_usb_driver(sd_driver);964