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(dev: 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 | value: 2, index: 0, data: gspca_dev->usb_buf, size: 6, timeout: 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(dev: 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 | value: 1, index: 0, data: gspca_dev->usb_buf, size: 1, timeout: 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(dev: 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 | value: 4, index: 0, data: gspca_dev->usb_buf, size: 4, timeout: 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 | command: cam_commands[i].instruction); |
237 | break; |
238 | case 1: |
239 | err_code = sn9c2028_short_command(gspca_dev, |
240 | command: cam_commands[i].instruction); |
241 | break; |
242 | case 0: |
243 | err_code = sn9c2028_command(gspca_dev, |
244 | command: 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, cam_commands: 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, g: ctrl->val); |
290 | break; |
291 | /* autogain */ |
292 | case V4L2_CID_AUTOGAIN: |
293 | set_gain(gspca_dev, g: 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, ops: &sd_ctrl_ops, |
315 | V4L2_CID_GAIN, min: 0, max: 20, step: 1, def: 0); |
316 | sd->autogain = v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops, |
317 | V4L2_CID_AUTOGAIN, min: 0, max: 1, step: 1, def: 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, cam_commands: 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, cam_commands: 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, cam_commands: 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, cam_commands: 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, cam_commands: 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, g: v4l2_ctrl_g_ctrl(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, cam_commands: 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, command: 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(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(ctrl: sd->gain, val: 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(ctrl: sd->gain, val: 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(ctrl: sd->autogain)) |
882 | return; |
883 | |
884 | do_autogain(gspca_dev, avg_lum: 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, m: 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, packet_type: LAST_PACKET, data, len: n); |
907 | /* Start next frame. */ |
908 | gspca_frame_add(gspca_dev, packet_type: FIRST_PACKET, |
909 | data: sn9c2028_sof_marker, len: sizeof sn9c2028_sof_marker); |
910 | len -= sof - data; |
911 | data = sof; |
912 | } |
913 | gspca_frame_add(gspca_dev, packet_type: 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: &sd_desc, dev_size: 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 | |