cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sn9c2028.c (31928B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * SN9C2028 library
      4 *
      5 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     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 8500
     25#define MAX_AVG_LUM 10000
     26	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 of
    141	 * 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 good
    371		 * 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 nothing
    440		 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */
    441		/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
    442		 * causes subsampling
    443		 * 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		else
    905			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_PM
    957	.suspend = gspca_suspend,
    958	.resume = gspca_resume,
    959	.reset_resume = gspca_resume,
    960#endif
    961};
    962
    963module_usb_driver(sd_driver);