1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#define MODULE_NAME "mars"
23
24#include "gspca.h"
25#include "jpeg.h"
26
27MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31
32enum e_ctrl {
33 BRIGHTNESS,
34 COLORS,
35 GAMMA,
36 SHARPNESS,
37 ILLUM_TOP,
38 ILLUM_BOT,
39 NCTRLS
40};
41
42
43struct sd {
44 struct gspca_dev gspca_dev;
45
46 struct gspca_ctrl ctrls[NCTRLS];
47
48 u8 quality;
49#define QUALITY_MIN 40
50#define QUALITY_MAX 70
51#define QUALITY_DEF 50
52
53 u8 jpeg_hdr[JPEG_HDR_SZ];
54};
55
56
57static void setbrightness(struct gspca_dev *gspca_dev);
58static void setcolors(struct gspca_dev *gspca_dev);
59static void setgamma(struct gspca_dev *gspca_dev);
60static void setsharpness(struct gspca_dev *gspca_dev);
61static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
63
64static const struct ctrl sd_ctrls[NCTRLS] = {
65[BRIGHTNESS] = {
66 {
67 .id = V4L2_CID_BRIGHTNESS,
68 .type = V4L2_CTRL_TYPE_INTEGER,
69 .name = "Brightness",
70 .minimum = 0,
71 .maximum = 30,
72 .step = 1,
73 .default_value = 15,
74 },
75 .set_control = setbrightness
76 },
77[COLORS] = {
78 {
79 .id = V4L2_CID_SATURATION,
80 .type = V4L2_CTRL_TYPE_INTEGER,
81 .name = "Color",
82 .minimum = 1,
83 .maximum = 255,
84 .step = 1,
85 .default_value = 200,
86 },
87 .set_control = setcolors
88 },
89[GAMMA] = {
90 {
91 .id = V4L2_CID_GAMMA,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "Gamma",
94 .minimum = 0,
95 .maximum = 3,
96 .step = 1,
97 .default_value = 1,
98 },
99 .set_control = setgamma
100 },
101[SHARPNESS] = {
102 {
103 .id = V4L2_CID_SHARPNESS,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "Sharpness",
106 .minimum = 0,
107 .maximum = 2,
108 .step = 1,
109 .default_value = 1,
110 },
111 .set_control = setsharpness
112 },
113[ILLUM_TOP] = {
114 {
115 .id = V4L2_CID_ILLUMINATORS_1,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Top illuminator",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
121 .default_value = 0,
122 .flags = V4L2_CTRL_FLAG_UPDATE,
123 },
124 .set = sd_setilluminator1
125 },
126[ILLUM_BOT] = {
127 {
128 .id = V4L2_CID_ILLUMINATORS_2,
129 .type = V4L2_CTRL_TYPE_BOOLEAN,
130 .name = "Bottom illuminator",
131 .minimum = 0,
132 .maximum = 1,
133 .step = 1,
134 .default_value = 0,
135 .flags = V4L2_CTRL_FLAG_UPDATE,
136 },
137 .set = sd_setilluminator2
138 },
139};
140
141static const struct v4l2_pix_format vga_mode[] = {
142 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
143 .bytesperline = 320,
144 .sizeimage = 320 * 240 * 3 / 8 + 590,
145 .colorspace = V4L2_COLORSPACE_JPEG,
146 .priv = 2},
147 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
148 .bytesperline = 640,
149 .sizeimage = 640 * 480 * 3 / 8 + 590,
150 .colorspace = V4L2_COLORSPACE_JPEG,
151 .priv = 1},
152};
153
154static const __u8 mi_data[0x20] = {
155
156 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
157
158 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
159
160 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
161
162 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
163};
164
165
166static void reg_w(struct gspca_dev *gspca_dev,
167 int len)
168{
169 int alen, ret;
170
171 if (gspca_dev->usb_err < 0)
172 return;
173
174 ret = usb_bulk_msg(gspca_dev->dev,
175 usb_sndbulkpipe(gspca_dev->dev, 4),
176 gspca_dev->usb_buf,
177 len,
178 &alen,
179 500);
180 if (ret < 0) {
181 err("reg write [%02x] error %d",
182 gspca_dev->usb_buf[0], ret);
183 gspca_dev->usb_err = ret;
184 }
185}
186
187static void mi_w(struct gspca_dev *gspca_dev,
188 u8 addr,
189 u8 value)
190{
191 gspca_dev->usb_buf[0] = 0x1f;
192 gspca_dev->usb_buf[1] = 0;
193 gspca_dev->usb_buf[2] = addr;
194 gspca_dev->usb_buf[3] = value;
195
196 reg_w(gspca_dev, 4);
197}
198
199static void setbrightness(struct gspca_dev *gspca_dev)
200{
201 struct sd *sd = (struct sd *) gspca_dev;
202
203 gspca_dev->usb_buf[0] = 0x61;
204 gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
205 reg_w(gspca_dev, 2);
206}
207
208static void setcolors(struct gspca_dev *gspca_dev)
209{
210 struct sd *sd = (struct sd *) gspca_dev;
211 s16 val;
212
213 val = sd->ctrls[COLORS].val;
214 gspca_dev->usb_buf[0] = 0x5f;
215 gspca_dev->usb_buf[1] = val << 3;
216 gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
217 reg_w(gspca_dev, 3);
218}
219
220static void setgamma(struct gspca_dev *gspca_dev)
221{
222 struct sd *sd = (struct sd *) gspca_dev;
223
224 gspca_dev->usb_buf[0] = 0x06;
225 gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
226 reg_w(gspca_dev, 2);
227}
228
229static void setsharpness(struct gspca_dev *gspca_dev)
230{
231 struct sd *sd = (struct sd *) gspca_dev;
232
233 gspca_dev->usb_buf[0] = 0x67;
234 gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
235 reg_w(gspca_dev, 2);
236}
237
238static void setilluminators(struct gspca_dev *gspca_dev)
239{
240 struct sd *sd = (struct sd *) gspca_dev;
241
242 gspca_dev->usb_buf[0] = 0x22;
243 if (sd->ctrls[ILLUM_TOP].val)
244 gspca_dev->usb_buf[1] = 0x76;
245 else if (sd->ctrls[ILLUM_BOT].val)
246 gspca_dev->usb_buf[1] = 0x7a;
247 else
248 gspca_dev->usb_buf[1] = 0x7e;
249 reg_w(gspca_dev, 2);
250}
251
252
253static int sd_config(struct gspca_dev *gspca_dev,
254 const struct usb_device_id *id)
255{
256 struct sd *sd = (struct sd *) gspca_dev;
257 struct cam *cam;
258
259 cam = &gspca_dev->cam;
260 cam->cam_mode = vga_mode;
261 cam->nmodes = ARRAY_SIZE(vga_mode);
262 cam->ctrls = sd->ctrls;
263 sd->quality = QUALITY_DEF;
264 gspca_dev->nbalt = 9;
265 return 0;
266}
267
268
269static int sd_init(struct gspca_dev *gspca_dev)
270{
271 gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
272 return 0;
273}
274
275static int sd_start(struct gspca_dev *gspca_dev)
276{
277 struct sd *sd = (struct sd *) gspca_dev;
278 u8 *data;
279 int i;
280
281
282 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
283 0x21);
284 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
285
286 data = gspca_dev->usb_buf;
287
288 data[0] = 0x01;
289 data[1] = 0x01;
290 reg_w(gspca_dev, 2);
291
292
293
294
295 data[0] = 0x00;
296 data[1] = 0x0c | 0x01;
297 data[2] = 0x01;
298 data[3] = gspca_dev->width / 8;
299 data[4] = gspca_dev->height / 8;
300 data[5] = 0x30;
301
302 data[6] = 0x02;
303 data[7] = sd->ctrls[GAMMA].val * 0x40;
304 data[8] = 0x01;
305
306
307
308 data[9] = 0x52;
309
310 data[10] = 0x18;
311
312 reg_w(gspca_dev, 11);
313
314 data[0] = 0x23;
315 data[1] = 0x09;
316
317 reg_w(gspca_dev, 2);
318
319 data[0] = 0x3c;
320
321
322
323
324 data[1] = 50;
325
326 reg_w(gspca_dev, 2);
327
328
329 data[0] = 0x5e;
330 data[1] = 0;
331
332
333
334
335 data[2] = sd->ctrls[COLORS].val << 3;
336 data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
337 data[4] = sd->ctrls[BRIGHTNESS].val;
338 data[5] = 0x00;
339
340 reg_w(gspca_dev, 6);
341
342 data[0] = 0x67;
343
344 data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
345 data[2] = 0x14;
346 reg_w(gspca_dev, 3);
347
348 data[0] = 0x69;
349 data[1] = 0x2f;
350 data[2] = 0x28;
351 data[3] = 0x42;
352 reg_w(gspca_dev, 4);
353
354 data[0] = 0x63;
355 data[1] = 0x07;
356 reg_w(gspca_dev, 2);
357
358
359
360 for (i = 0; i < sizeof mi_data; i++)
361 mi_w(gspca_dev, i + 1, mi_data[i]);
362
363 data[0] = 0x00;
364 data[1] = 0x4d;
365 reg_w(gspca_dev, 2);
366
367 gspca_dev->ctrl_inac = 0;
368 return gspca_dev->usb_err;
369}
370
371static void sd_stopN(struct gspca_dev *gspca_dev)
372{
373 struct sd *sd = (struct sd *) gspca_dev;
374
375 gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
376 if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
377 sd->ctrls[ILLUM_TOP].val = 0;
378 sd->ctrls[ILLUM_BOT].val = 0;
379 setilluminators(gspca_dev);
380 msleep(20);
381 }
382
383 gspca_dev->usb_buf[0] = 1;
384 gspca_dev->usb_buf[1] = 0;
385 reg_w(gspca_dev, 2);
386}
387
388static void sd_pkt_scan(struct gspca_dev *gspca_dev,
389 u8 *data,
390 int len)
391{
392 struct sd *sd = (struct sd *) gspca_dev;
393 int p;
394
395 if (len < 6) {
396
397 return;
398 }
399 for (p = 0; p < len - 6; p++) {
400 if (data[0 + p] == 0xff
401 && data[1 + p] == 0xff
402 && data[2 + p] == 0x00
403 && data[3 + p] == 0xff
404 && data[4 + p] == 0x96) {
405 if (data[5 + p] == 0x64
406 || data[5 + p] == 0x65
407 || data[5 + p] == 0x66
408 || data[5 + p] == 0x67) {
409 PDEBUG(D_PACK, "sof offset: %d len: %d",
410 p, len);
411 gspca_frame_add(gspca_dev, LAST_PACKET,
412 data, p);
413
414
415 gspca_frame_add(gspca_dev, FIRST_PACKET,
416 sd->jpeg_hdr, JPEG_HDR_SZ);
417 data += p + 16;
418 len -= p + 16;
419 break;
420 }
421 }
422 }
423 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
424}
425
426static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
427{
428 struct sd *sd = (struct sd *) gspca_dev;
429
430
431 sd->ctrls[ILLUM_TOP].val = val;
432 if (val)
433 sd->ctrls[ILLUM_BOT].val = 0;
434 setilluminators(gspca_dev);
435 return gspca_dev->usb_err;
436}
437
438static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
439{
440 struct sd *sd = (struct sd *) gspca_dev;
441
442
443 sd->ctrls[ILLUM_BOT].val = val;
444 if (val)
445 sd->ctrls[ILLUM_TOP].val = 0;
446 setilluminators(gspca_dev);
447 return gspca_dev->usb_err;
448}
449
450static int sd_set_jcomp(struct gspca_dev *gspca_dev,
451 struct v4l2_jpegcompression *jcomp)
452{
453 struct sd *sd = (struct sd *) gspca_dev;
454
455 if (jcomp->quality < QUALITY_MIN)
456 sd->quality = QUALITY_MIN;
457 else if (jcomp->quality > QUALITY_MAX)
458 sd->quality = QUALITY_MAX;
459 else
460 sd->quality = jcomp->quality;
461 if (gspca_dev->streaming)
462 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
463 return 0;
464}
465
466static int sd_get_jcomp(struct gspca_dev *gspca_dev,
467 struct v4l2_jpegcompression *jcomp)
468{
469 struct sd *sd = (struct sd *) gspca_dev;
470
471 memset(jcomp, 0, sizeof *jcomp);
472 jcomp->quality = sd->quality;
473 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
474 | V4L2_JPEG_MARKER_DQT;
475 return 0;
476}
477
478
479static const struct sd_desc sd_desc = {
480 .name = MODULE_NAME,
481 .ctrls = sd_ctrls,
482 .nctrls = NCTRLS,
483 .config = sd_config,
484 .init = sd_init,
485 .start = sd_start,
486 .stopN = sd_stopN,
487 .pkt_scan = sd_pkt_scan,
488 .get_jcomp = sd_get_jcomp,
489 .set_jcomp = sd_set_jcomp,
490};
491
492
493static const struct usb_device_id device_table[] = {
494 {USB_DEVICE(0x093a, 0x050f)},
495 {}
496};
497MODULE_DEVICE_TABLE(usb, device_table);
498
499
500static int sd_probe(struct usb_interface *intf,
501 const struct usb_device_id *id)
502{
503 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
504 THIS_MODULE);
505}
506
507static struct usb_driver sd_driver = {
508 .name = MODULE_NAME,
509 .id_table = device_table,
510 .probe = sd_probe,
511 .disconnect = gspca_disconnect,
512#ifdef CONFIG_PM
513 .suspend = gspca_suspend,
514 .resume = gspca_resume,
515#endif
516};
517
518
519static int __init sd_mod_init(void)
520{
521 return usb_register(&sd_driver);
522}
523static void __exit sd_mod_exit(void)
524{
525 usb_deregister(&sd_driver);
526}
527
528module_init(sd_mod_init);
529module_exit(sd_mod_exit);
530