1/*
2 * SN9C2028 library
3 *
4 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#define MODULE_NAME "sn9c2028"
24
25#include "gspca.h"
26
27MODULE_AUTHOR("Theodore Kilgore");
28MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33	struct gspca_dev gspca_dev;  /* !! must be the first item */
34	u8 sof_read;
35	u16 model;
36};
37
38struct init_command {
39	unsigned char instruction[6];
40	unsigned char to_read; /* length to read. 0 means no reply requested */
41};
42
43/* How to change the resolution of any of the VGA cams is unknown */
44static const struct v4l2_pix_format vga_mode[] = {
45	{640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
46		.bytesperline = 640,
47		.sizeimage = 640 * 480 * 3 / 4,
48		.colorspace = V4L2_COLORSPACE_SRGB,
49		.priv = 0},
50};
51
52/* No way to change the resolution of the CIF cams is known */
53static const struct v4l2_pix_format cif_mode[] = {
54	{352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
55		.bytesperline = 352,
56		.sizeimage = 352 * 288 * 3 / 4,
57		.colorspace = V4L2_COLORSPACE_SRGB,
58		.priv = 0},
59};
60
61/* the bytes to write are in gspca_dev->usb_buf */
62static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
63{
64	int rc;
65
66	PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0],
67	       command[1], command[2], command[3], command[4], command[5]);
68
69	memcpy(gspca_dev->usb_buf, command, 6);
70	rc = usb_control_msg(gspca_dev->dev,
71			usb_sndctrlpipe(gspca_dev->dev, 0),
72			USB_REQ_GET_CONFIGURATION,
73			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
74			2, 0, gspca_dev->usb_buf, 6, 500);
75	if (rc < 0) {
76		pr_err("command write [%02x] error %d\n",
77		       gspca_dev->usb_buf[0], rc);
78		return rc;
79	}
80
81	return 0;
82}
83
84static int sn9c2028_read1(struct gspca_dev *gspca_dev)
85{
86	int rc;
87
88	rc = usb_control_msg(gspca_dev->dev,
89			usb_rcvctrlpipe(gspca_dev->dev, 0),
90			USB_REQ_GET_STATUS,
91			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
92			1, 0, gspca_dev->usb_buf, 1, 500);
93	if (rc != 1) {
94		pr_err("read1 error %d\n", rc);
95		return (rc < 0) ? rc : -EIO;
96	}
97	PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);
98	return gspca_dev->usb_buf[0];
99}
100
101static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
102{
103	int rc;
104	rc = usb_control_msg(gspca_dev->dev,
105			usb_rcvctrlpipe(gspca_dev->dev, 0),
106			USB_REQ_GET_STATUS,
107			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
108			4, 0, gspca_dev->usb_buf, 4, 500);
109	if (rc != 4) {
110		pr_err("read4 error %d\n", rc);
111		return (rc < 0) ? rc : -EIO;
112	}
113	memcpy(reading, gspca_dev->usb_buf, 4);
114	PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0],
115	       reading[1], reading[2], reading[3]);
116	return rc;
117}
118
119static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
120{
121	int i, status;
122	__u8 reading[4];
123
124	status = sn9c2028_command(gspca_dev, command);
125	if (status < 0)
126		return status;
127
128	status = -1;
129	for (i = 0; i < 256 && status < 2; i++)
130		status = sn9c2028_read1(gspca_dev);
131	if (status != 2) {
132		pr_err("long command status read error %d\n", status);
133		return (status < 0) ? status : -EIO;
134	}
135
136	memset(reading, 0, 4);
137	status = sn9c2028_read4(gspca_dev, reading);
138	if (status < 0)
139		return status;
140
141	/* in general, the first byte of the response is the first byte of
142	 * the command, or'ed with 8 */
143	status = sn9c2028_read1(gspca_dev);
144	if (status < 0)
145		return status;
146
147	return 0;
148}
149
150static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)
151{
152	int err_code;
153
154	err_code = sn9c2028_command(gspca_dev, command);
155	if (err_code < 0)
156		return err_code;
157
158	err_code = sn9c2028_read1(gspca_dev);
159	if (err_code < 0)
160		return err_code;
161
162	return 0;
163}
164
165/* this function is called at probe time */
166static int sd_config(struct gspca_dev *gspca_dev,
167		     const struct usb_device_id *id)
168{
169	struct sd *sd = (struct sd *) gspca_dev;
170	struct cam *cam = &gspca_dev->cam;
171
172	PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)",
173	       id->idVendor, id->idProduct);
174
175	sd->model = id->idProduct;
176
177	switch (sd->model) {
178	case 0x7005:
179		PDEBUG(D_PROBE, "Genius Smart 300 camera");
180		break;
181	case 0x8000:
182		PDEBUG(D_PROBE, "DC31VC");
183		break;
184	case 0x8001:
185		PDEBUG(D_PROBE, "Spy camera");
186		break;
187	case 0x8003:
188		PDEBUG(D_PROBE, "CIF camera");
189		break;
190	case 0x8008:
191		PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera");
192		break;
193	case 0x800a:
194		PDEBUG(D_PROBE, "Vivitar 3350b type camera");
195		cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;
196		break;
197	}
198
199	switch (sd->model) {
200	case 0x8000:
201	case 0x8001:
202	case 0x8003:
203		cam->cam_mode = cif_mode;
204		cam->nmodes = ARRAY_SIZE(cif_mode);
205		break;
206	default:
207		cam->cam_mode = vga_mode;
208		cam->nmodes = ARRAY_SIZE(vga_mode);
209	}
210	return 0;
211}
212
213/* this function is called at probe and resume time */
214static int sd_init(struct gspca_dev *gspca_dev)
215{
216	int status = -1;
217
218	sn9c2028_read1(gspca_dev);
219	sn9c2028_read1(gspca_dev);
220	status = sn9c2028_read1(gspca_dev);
221
222	return (status < 0) ? status : 0;
223}
224
225static int run_start_commands(struct gspca_dev *gspca_dev,
226			      struct init_command *cam_commands, int n)
227{
228	int i, err_code = -1;
229
230	for (i = 0; i < n; i++) {
231		switch (cam_commands[i].to_read) {
232		case 4:
233			err_code = sn9c2028_long_command(gspca_dev,
234					cam_commands[i].instruction);
235			break;
236		case 1:
237			err_code = sn9c2028_short_command(gspca_dev,
238					cam_commands[i].instruction);
239			break;
240		case 0:
241			err_code = sn9c2028_command(gspca_dev,
242					cam_commands[i].instruction);
243			break;
244		}
245		if (err_code < 0)
246			return err_code;
247	}
248	return 0;
249}
250
251static int start_spy_cam(struct gspca_dev *gspca_dev)
252{
253	struct init_command spy_start_commands[] = {
254		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
255		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
256		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
257		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
258		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
259		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
260		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width  352 */
261		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */
262		/* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */
263		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},
264		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/
265		/* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */
266		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
267		/* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */
268		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
269		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
270		/* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */
271		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
272		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
273		/* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */
274		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
275		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
276		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
277		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
278		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
279		{{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},
280		{{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/
281		/*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
282		{{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
283		/*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */
284		{{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
285		{{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */
286		{{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},
287		/*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
288		{{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},
289		{{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},
290		{{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},
291		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
292		{{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},
293		{{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},
294		{{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},
295		/* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */
296		/* brightness or gain. 0 is default. 4 is good
297		 * indoors at night with incandescent lighting */
298		{{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},
299		{{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/
300		{{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},
301		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
302		{{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},
303		{{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},
304		/* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */
305		{{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */
306		/* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */
307		{{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},
308		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */
309		/* Camera should start to capture now. */
310	};
311
312	return run_start_commands(gspca_dev, spy_start_commands,
313				  ARRAY_SIZE(spy_start_commands));
314}
315
316static int start_cif_cam(struct gspca_dev *gspca_dev)
317{
318	struct init_command cif_start_commands[] = {
319		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
320		/* The entire sequence below seems redundant */
321		/* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
322		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
323		{{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},
324		{{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},
325		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
326		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?
327		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?
328		{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
329		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
330		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
331		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
332		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
333		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
334		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
335		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
336		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
337		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
338		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
339		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/
340		{{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},
341		{{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},
342		{{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},
343		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
344		{{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},
345		{{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},
346		{{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},
347		{{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},
348		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
349		{{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},
350		{{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},
351		{{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},
352		{{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},
353		{{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},
354		{{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},
355		{{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},
356		{{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},
357		{{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},
358		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
359		{{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},
360		{{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},
361		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
362		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */
363		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */
364		/* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
365		 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing
366		 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */
367		/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
368		 * causes subsampling
369		 * but not a change in the resolution setting! */
370		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
371		{{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},
372		{{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},
373		{{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},
374		{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
375		{{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},
376		{{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},
377		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
378		{{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},
379		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
380		{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
381		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
382		{{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},
383		{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
384		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
385		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */
386		/* Camera should start to capture now. */
387	};
388
389	return run_start_commands(gspca_dev, cif_start_commands,
390				  ARRAY_SIZE(cif_start_commands));
391}
392
393static int start_ms350_cam(struct gspca_dev *gspca_dev)
394{
395	struct init_command ms350_start_commands[] = {
396		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
397		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
398		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
399		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
400		{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
401		{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
402		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
403		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
404		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
405		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
406		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},
407		{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
408		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
409		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
410		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
411		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
412		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
413		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
414		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
415		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
416		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
417		{{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},
418		{{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},
419		{{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},
420		{{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},
421		{{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},
422		{{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},
423		{{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},
424		{{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},
425		{{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},
426		{{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},
427		{{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},
428		{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
429		{{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},
430		{{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},
431		{{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},
432		{{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},
433		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
434		{{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},
435		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
436		{{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},
437		{{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},
438		{{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},
439		{{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},
440		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width  */
441		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */
442		{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */
443		{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
444		{{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */
445		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
446		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
447		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
448		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
449		{{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},
450		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
451		{{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},
452		{{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},
453		{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},
454		/* Camera should start to capture now. */
455	};
456
457	return run_start_commands(gspca_dev, ms350_start_commands,
458				  ARRAY_SIZE(ms350_start_commands));
459}
460
461static int start_genius_cam(struct gspca_dev *gspca_dev)
462{
463	struct init_command genius_start_commands[] = {
464		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
465		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
466		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
467		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
468		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
469		/* "preliminary" width and height settings */
470		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
471		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
472		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
473		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
474		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
475		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
476		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
477		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
478		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
479		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
480		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
481		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
482		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
483		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
484		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
485		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
486		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
487		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
488		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
489		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
490		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
491		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
492		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
493		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
494		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
495		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
496		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
497		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
498		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
499		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
500		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
501		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
502		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */
503		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */
504		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
505		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
506		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
507		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
508		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
509		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
510		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
511		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
512		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
513		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
514		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
515		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
516		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
517		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
518		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
519		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
520		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
521		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
522		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
523		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
524		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
525		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}
526		/* Camera should start to capture now. */
527	};
528
529	return run_start_commands(gspca_dev, genius_start_commands,
530				  ARRAY_SIZE(genius_start_commands));
531}
532
533static int start_vivitar_cam(struct gspca_dev *gspca_dev)
534{
535	struct init_command vivitar_start_commands[] = {
536		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
537		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
538		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
539		{{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},
540		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
541		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
542		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
543		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
544		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
545		{{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},
546		/*
547		 * Above is changed from OEM 0x0b. Fixes Bayer tiling.
548		 * Presumably gives a vertical shift of one row.
549		 */
550		{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
551		/* Above seems to do horizontal shift. */
552		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
553		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
554		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
555		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
556		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
557		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
558		/* Above three commands seem to relate to brightness. */
559		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
560		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
561		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
562		{{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},
563		{{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},
564		{{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},
565		{{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},
566		{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
567		{{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},
568		{{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},
569		{{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},
570		{{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},
571		{{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},
572		{{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},
573		{{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},
574		{{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},
575		{{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
576		{{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},
577		{{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},
578		{{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},
579		{{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},
580		{{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},
581		{{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},
582		{{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},
583		{{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},
584		{{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},
585		{{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},
586		{{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},
587		{{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},
588		{{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},
589		{{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},
590		{{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},
591		{{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},
592		{{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},
593		{{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},
594		{{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},
595		{{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},
596		/* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
597		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
598		{{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */
599		{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
600		{{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},
601		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
602		{{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},
603		{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
604		{{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},
605		/* Above is brightness; OEM driver setting is 0x10 */
606		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
607		{{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
608		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}
609	};
610
611	return run_start_commands(gspca_dev, vivitar_start_commands,
612				  ARRAY_SIZE(vivitar_start_commands));
613}
614
615static int sd_start(struct gspca_dev *gspca_dev)
616{
617	struct sd *sd = (struct sd *) gspca_dev;
618	int err_code;
619
620	sd->sof_read = 0;
621
622	switch (sd->model) {
623	case 0x7005:
624		err_code = start_genius_cam(gspca_dev);
625		break;
626	case 0x8001:
627		err_code = start_spy_cam(gspca_dev);
628		break;
629	case 0x8003:
630		err_code = start_cif_cam(gspca_dev);
631		break;
632	case 0x8008:
633		err_code = start_ms350_cam(gspca_dev);
634		break;
635	case 0x800a:
636		err_code = start_vivitar_cam(gspca_dev);
637		break;
638	default:
639		pr_err("Starting unknown camera, please report this\n");
640		return -ENXIO;
641	}
642
643	return err_code;
644}
645
646static void sd_stopN(struct gspca_dev *gspca_dev)
647{
648	int result;
649	__u8 data[6];
650
651	result = sn9c2028_read1(gspca_dev);
652	if (result < 0)
653		PERR("Camera Stop read failed");
654
655	memset(data, 0, 6);
656	data[0] = 0x14;
657	result = sn9c2028_command(gspca_dev, data);
658	if (result < 0)
659		PERR("Camera Stop command failed");
660}
661
662/* Include sn9c2028 sof detection functions */
663#include "sn9c2028.h"
664
665static void sd_pkt_scan(struct gspca_dev *gspca_dev,
666			__u8 *data,			/* isoc packet */
667			int len)			/* iso packet length */
668{
669	unsigned char *sof;
670
671	sof = sn9c2028_find_sof(gspca_dev, data, len);
672	if (sof) {
673		int n;
674
675		/* finish decoding current frame */
676		n = sof - data;
677		if (n > sizeof sn9c2028_sof_marker)
678			n -= sizeof sn9c2028_sof_marker;
679		else
680			n = 0;
681		gspca_frame_add(gspca_dev, LAST_PACKET, data, n);
682		/* Start next frame. */
683		gspca_frame_add(gspca_dev, FIRST_PACKET,
684			sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);
685		len -= sof - data;
686		data = sof;
687	}
688	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
689}
690
691/* sub-driver description */
692static const struct sd_desc sd_desc = {
693	.name = MODULE_NAME,
694	.config = sd_config,
695	.init = sd_init,
696	.start = sd_start,
697	.stopN = sd_stopN,
698	.pkt_scan = sd_pkt_scan,
699};
700
701/* -- module initialisation -- */
702static const struct usb_device_id device_table[] = {
703	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
704	/* The Genius Smart is untested. I can't find an owner ! */
705	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
706	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
707	{USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */
708	/* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */
709	{USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */
710	{USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */
711	{}
712};
713MODULE_DEVICE_TABLE(usb, device_table);
714
715/* -- device connect -- */
716static int sd_probe(struct usb_interface *intf,
717			const struct usb_device_id *id)
718{
719	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
720			       THIS_MODULE);
721}
722
723static struct usb_driver sd_driver = {
724	.name = MODULE_NAME,
725	.id_table = device_table,
726	.probe = sd_probe,
727	.disconnect = gspca_disconnect,
728#ifdef CONFIG_PM
729	.suspend = gspca_suspend,
730	.resume = gspca_resume,
731	.reset_resume = gspca_resume,
732#endif
733};
734
735module_usb_driver(sd_driver);
736