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