xref: /openbmc/linux/drivers/media/usb/gspca/sn9c2028.c (revision 46f28427)
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 
14 MODULE_AUTHOR("Theodore Kilgore");
15 MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
16 MODULE_LICENSE("GPL");
17 
18 /* specific webcam descriptor */
19 struct 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 
35 struct 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 */
41 static 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 */
50 static 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 */
59 static 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 
82 static 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 
100 static 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 
118 static 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 
149 static 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 */
165 static 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 */
216 static 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 
227 static 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 
253 static 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 
275 static 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 
299 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
300 	.s_ctrl = sd_s_ctrl,
301 };
302 
303 
304 static 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 }
325 static 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 
390 static 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 
467 static 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 
535 static 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 
607 static 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 
720 static 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 
802 static 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 
838 static 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 
854 static 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 
877 static 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 
890 static 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 */
917 static 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 -- */
929 static 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 };
941 MODULE_DEVICE_TABLE(usb, device_table);
942 
943 /* -- device connect -- */
944 static 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 
951 static 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 
963 module_usb_driver(sd_driver);
964