Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/gspca/sn9c2028.c
17681 views
1
/*
2
* SN9C2028 library
3
*
4
* Copyright (C) 2009 Theodore Kilgore <[email protected]>
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
25
MODULE_AUTHOR("Theodore Kilgore");
26
MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
27
MODULE_LICENSE("GPL");
28
29
/* specific webcam descriptor */
30
struct sd {
31
struct gspca_dev gspca_dev; /* !! must be the first item */
32
u8 sof_read;
33
u16 model;
34
};
35
36
struct 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 */
42
static const struct ctrl sd_ctrls[] = {
43
};
44
45
/* How to change the resolution of any of the VGA cams is unknown */
46
static 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 */
55
static 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 */
64
static 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) {
78
err("command write [%02x] error %d",
79
gspca_dev->usb_buf[0], rc);
80
return rc;
81
}
82
83
return 0;
84
}
85
86
static 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) {
96
err("read1 error %d", rc);
97
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
103
static 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) {
112
err("read4 error %d", rc);
113
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
121
static 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) {
134
err("long command status read error %d", status);
135
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
152
static 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 */
168
static 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 */
216
static 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
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 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
318
static 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
395
static 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
463
static 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
535
static 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
617
static 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:
641
err("Starting unknown camera, please report this");
642
return -ENXIO;
643
}
644
645
return err_code;
646
}
647
648
static 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
667
static 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 */
694
static 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 -- */
706
static const 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
};
717
MODULE_DEVICE_TABLE(usb, device_table);
718
719
/* -- device connect -- */
720
static 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
727
static 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 -- */
739
static int __init sd_mod_init(void)
740
{
741
return usb_register(&sd_driver);
742
}
743
744
static void __exit sd_mod_exit(void)
745
{
746
usb_deregister(&sd_driver);
747
}
748
749
module_init(sd_mod_init);
750
module_exit(sd_mod_exit);
751
752