1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#define MODULE_NAME "sunplus"
21
22#include "gspca.h"
23#include "jpeg.h"
24
25MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
26MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
27MODULE_LICENSE("GPL");
28
29#define QUALITY 85
30
31
32struct sd {
33 struct gspca_dev gspca_dev;
34
35 bool autogain;
36
37 u8 bridge;
38#define BRIDGE_SPCA504 0
39#define BRIDGE_SPCA504B 1
40#define BRIDGE_SPCA504C 2
41#define BRIDGE_SPCA533 3
42#define BRIDGE_SPCA536 4
43 u8 subtype;
44#define AiptekMiniPenCam13 1
45#define LogitechClickSmart420 2
46#define LogitechClickSmart820 3
47#define MegapixV4 4
48#define MegaImageVI 5
49
50 u8 jpeg_hdr[JPEG_HDR_SZ];
51};
52
53static const struct v4l2_pix_format vga_mode[] = {
54 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
55 .bytesperline = 320,
56 .sizeimage = 320 * 240 * 3 / 8 + 590,
57 .colorspace = V4L2_COLORSPACE_JPEG,
58 .priv = 2},
59 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
60 .bytesperline = 640,
61 .sizeimage = 640 * 480 * 3 / 8 + 590,
62 .colorspace = V4L2_COLORSPACE_JPEG,
63 .priv = 1},
64};
65
66static const struct v4l2_pix_format custom_mode[] = {
67 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
68 .bytesperline = 320,
69 .sizeimage = 320 * 240 * 3 / 8 + 590,
70 .colorspace = V4L2_COLORSPACE_JPEG,
71 .priv = 2},
72 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
73 .bytesperline = 464,
74 .sizeimage = 464 * 480 * 3 / 8 + 590,
75 .colorspace = V4L2_COLORSPACE_JPEG,
76 .priv = 1},
77};
78
79static const struct v4l2_pix_format vga_mode2[] = {
80 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
81 .bytesperline = 176,
82 .sizeimage = 176 * 144 * 3 / 8 + 590,
83 .colorspace = V4L2_COLORSPACE_JPEG,
84 .priv = 4},
85 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
86 .bytesperline = 320,
87 .sizeimage = 320 * 240 * 3 / 8 + 590,
88 .colorspace = V4L2_COLORSPACE_JPEG,
89 .priv = 3},
90 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
91 .bytesperline = 352,
92 .sizeimage = 352 * 288 * 3 / 8 + 590,
93 .colorspace = V4L2_COLORSPACE_JPEG,
94 .priv = 2},
95 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
96 .bytesperline = 640,
97 .sizeimage = 640 * 480 * 3 / 8 + 590,
98 .colorspace = V4L2_COLORSPACE_JPEG,
99 .priv = 1},
100};
101
102#define SPCA50X_OFFSET_DATA 10
103#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
104#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
105#define SPCA504_PCCAM600_OFFSET_MODE 5
106#define SPCA504_PCCAM600_OFFSET_DATA 14
107
108#define SPCA533_OFFSET_DATA 16
109#define SPCA533_OFFSET_FRAMSEQ 15
110
111#define SPCA536_OFFSET_DATA 4
112#define SPCA536_OFFSET_FRAMSEQ 1
113
114struct cmd {
115 u8 req;
116 u16 val;
117 u16 idx;
118};
119
120
121static const struct cmd spca504_pccam600_init_data[] = {
122
123 {0x00, 0x0000, 0x2000},
124 {0x00, 0x0013, 0x2301},
125 {0x00, 0x0003, 0x2000},
126 {0x00, 0x0001, 0x21ac},
127 {0x00, 0x0001, 0x21a6},
128 {0x00, 0x0000, 0x21a7},
129 {0x00, 0x0020, 0x21a8},
130 {0x00, 0x0001, 0x21ac},
131 {0x00, 0x0000, 0x21ad},
132 {0x00, 0x001a, 0x21ae},
133 {0x00, 0x0002, 0x21a3},
134 {0x30, 0x0154, 0x0008},
135 {0x30, 0x0004, 0x0006},
136 {0x30, 0x0258, 0x0009},
137 {0x30, 0x0004, 0x0000},
138 {0x30, 0x0093, 0x0004},
139 {0x30, 0x0066, 0x0005},
140 {0x00, 0x0000, 0x2000},
141 {0x00, 0x0013, 0x2301},
142 {0x00, 0x0003, 0x2000},
143 {0x00, 0x0013, 0x2301},
144 {0x00, 0x0003, 0x2000},
145};
146
147
148
149
150static const struct cmd spca504_pccam600_open_data[] = {
151 {0x00, 0x0001, 0x2501},
152 {0x20, 0x0500, 0x0001},
153 {0x00, 0x0003, 0x2880},
154 {0x00, 0x0001, 0x2881},
155};
156
157
158static const struct cmd spca504A_clicksmart420_init_data[] = {
159
160 {0x00, 0x0000, 0x2000},
161 {0x00, 0x0013, 0x2301},
162 {0x00, 0x0003, 0x2000},
163 {0x00, 0x0001, 0x21ac},
164 {0x00, 0x0001, 0x21a6},
165 {0x00, 0x0000, 0x21a7},
166 {0x00, 0x0020, 0x21a8},
167 {0x00, 0x0001, 0x21ac},
168 {0x00, 0x0000, 0x21ad},
169 {0x00, 0x001a, 0x21ae},
170 {0x00, 0x0002, 0x21a3},
171 {0x30, 0x0004, 0x000a},
172 {0xb0, 0x0001, 0x0000},
173
174 {0xa1, 0x0080, 0x0001},
175 {0x30, 0x0049, 0x0000},
176 {0x30, 0x0060, 0x0005},
177 {0x0c, 0x0004, 0x0000},
178 {0x00, 0x0000, 0x0000},
179 {0x00, 0x0000, 0x2000},
180 {0x00, 0x0013, 0x2301},
181 {0x00, 0x0003, 0x2000},
182};
183
184
185static const struct cmd spca504A_clicksmart420_open_data[] = {
186 {0x00, 0x0001, 0x2501},
187 {0x20, 0x0502, 0x0000},
188 {0x06, 0x0000, 0x0000},
189 {0x00, 0x0004, 0x2880},
190 {0x00, 0x0001, 0x2881},
191
192 {0xa0, 0x0000, 0x0503},
193};
194
195static const u8 qtable_creative_pccam[2][64] = {
196 {
197 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
198 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
199 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
200 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
201 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
202 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
203 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
204 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
205 {
206 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
207 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
208 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
209 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
210 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
211 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
212 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
213 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
214};
215
216
217
218
219
220static const u8 qtable_spca504_default[2][64] = {
221 {
222 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
223 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
224 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
225 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
226 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
227 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
228 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
229 0x16, 0x1c, 0x1d, 0x1d, 0x1d , 0x1e, 0x1f, 0x1e,
230 },
231 {
232 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
233 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
234 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
235 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
236 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
237 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
238 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
239 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
240};
241
242
243static void reg_r(struct gspca_dev *gspca_dev,
244 u8 req,
245 u16 index,
246 u16 len)
247{
248 int ret;
249
250 if (len > USB_BUF_SZ) {
251 gspca_err(gspca_dev, "reg_r: buffer overflow\n");
252 return;
253 }
254 if (gspca_dev->usb_err < 0)
255 return;
256 ret = usb_control_msg(gspca_dev->dev,
257 usb_rcvctrlpipe(gspca_dev->dev, 0),
258 req,
259 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
260 0,
261 index,
262 len ? gspca_dev->usb_buf : NULL, len,
263 500);
264 if (ret < 0) {
265 pr_err("reg_r err %d\n", ret);
266 gspca_dev->usb_err = ret;
267 }
268}
269
270
271static void reg_w_1(struct gspca_dev *gspca_dev,
272 u8 req,
273 u16 value,
274 u16 index,
275 u16 byte)
276{
277 int ret;
278
279 if (gspca_dev->usb_err < 0)
280 return;
281 gspca_dev->usb_buf[0] = byte;
282 ret = usb_control_msg(gspca_dev->dev,
283 usb_sndctrlpipe(gspca_dev->dev, 0),
284 req,
285 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
286 value, index,
287 gspca_dev->usb_buf, 1,
288 500);
289 if (ret < 0) {
290 pr_err("reg_w_1 err %d\n", ret);
291 gspca_dev->usb_err = ret;
292 }
293}
294
295
296static void reg_w_riv(struct gspca_dev *gspca_dev,
297 u8 req, u16 index, u16 value)
298{
299 struct usb_device *dev = gspca_dev->dev;
300 int ret;
301
302 if (gspca_dev->usb_err < 0)
303 return;
304 ret = usb_control_msg(dev,
305 usb_sndctrlpipe(dev, 0),
306 req,
307 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
308 value, index, NULL, 0, 500);
309 if (ret < 0) {
310 pr_err("reg_w_riv err %d\n", ret);
311 gspca_dev->usb_err = ret;
312 return;
313 }
314 gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n",
315 req, index, value);
316}
317
318static void write_vector(struct gspca_dev *gspca_dev,
319 const struct cmd *data, int ncmds)
320{
321 while (--ncmds >= 0) {
322 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
323 data++;
324 }
325}
326
327static void setup_qtable(struct gspca_dev *gspca_dev,
328 const u8 qtable[2][64])
329{
330 int i;
331
332
333 for (i = 0; i < 64; i++)
334 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
335
336
337 for (i = 0; i < 64; i++)
338 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
339}
340
341static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
342 u8 req, u16 idx, u16 val)
343{
344 reg_w_riv(gspca_dev, req, idx, val);
345 reg_r(gspca_dev, 0x01, 0x0001, 1);
346 gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n",
347 gspca_dev->usb_buf[0]);
348 reg_w_riv(gspca_dev, req, idx, val);
349
350 msleep(200);
351 reg_r(gspca_dev, 0x01, 0x0001, 1);
352 gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n",
353 gspca_dev->usb_buf[0]);
354}
355
356static void spca504_read_info(struct gspca_dev *gspca_dev)
357{
358 int i;
359 u8 info[6];
360
361 if (gspca_debug < D_STREAM)
362 return;
363
364 for (i = 0; i < 6; i++) {
365 reg_r(gspca_dev, 0, i, 1);
366 info[i] = gspca_dev->usb_buf[0];
367 }
368 gspca_dbg(gspca_dev, D_STREAM,
369 "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n",
370 info[0], info[1], info[2],
371 info[3], info[4], info[5]);
372}
373
374static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
375 u8 req,
376 u16 idx, u16 val, u8 endcode, u8 count)
377{
378 u16 status;
379
380 reg_w_riv(gspca_dev, req, idx, val);
381 reg_r(gspca_dev, 0x01, 0x0001, 1);
382 if (gspca_dev->usb_err < 0)
383 return;
384 gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n",
385 gspca_dev->usb_buf[0], endcode);
386 if (!count)
387 return;
388 count = 200;
389 while (--count > 0) {
390 msleep(10);
391
392
393 reg_r(gspca_dev, 0x01, 0x0001, 1);
394 status = gspca_dev->usb_buf[0];
395 if (status == endcode) {
396 gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n",
397 status, 200 - count);
398 break;
399 }
400 }
401}
402
403static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
404{
405 int count = 10;
406
407 while (--count > 0) {
408 reg_r(gspca_dev, 0x21, 0, 1);
409 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
410 break;
411 msleep(10);
412 }
413}
414
415static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
416{
417 int count = 50;
418
419 while (--count > 0) {
420 reg_r(gspca_dev, 0x21, 1, 1);
421 if (gspca_dev->usb_buf[0] != 0) {
422 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
423 reg_r(gspca_dev, 0x21, 1, 1);
424 spca504B_PollingDataReady(gspca_dev);
425 break;
426 }
427 msleep(10);
428 }
429}
430
431static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
432{
433 u8 *data;
434
435 if (gspca_debug < D_STREAM)
436 return;
437
438 data = gspca_dev->usb_buf;
439 reg_r(gspca_dev, 0x20, 0, 5);
440 gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n",
441 data[0], data[1], data[2], data[3], data[4]);
442 reg_r(gspca_dev, 0x23, 0, 64);
443 reg_r(gspca_dev, 0x23, 1, 64);
444}
445
446static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
447{
448 struct sd *sd = (struct sd *) gspca_dev;
449 u8 Size;
450
451 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
452 switch (sd->bridge) {
453 case BRIDGE_SPCA533:
454 reg_w_riv(gspca_dev, 0x31, 0, 0);
455 spca504B_WaitCmdStatus(gspca_dev);
456 spca504B_PollingDataReady(gspca_dev);
457 spca50x_GetFirmware(gspca_dev);
458
459 reg_w_1(gspca_dev, 0x24, 0, 8, 2);
460 reg_r(gspca_dev, 0x24, 8, 1);
461
462 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
463 reg_r(gspca_dev, 0x25, 4, 1);
464 spca504B_PollingDataReady(gspca_dev);
465
466
467 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
468 spca504B_WaitCmdStatus(gspca_dev);
469 spca504B_PollingDataReady(gspca_dev);
470 break;
471 default:
472
473
474 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
475 reg_r(gspca_dev, 0x25, 4, 1);
476 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
477 reg_r(gspca_dev, 0x27, 0, 1);
478 spca504B_PollingDataReady(gspca_dev);
479 break;
480 case BRIDGE_SPCA504:
481 Size += 3;
482 if (sd->subtype == AiptekMiniPenCam13) {
483
484 spca504A_acknowledged_command(gspca_dev,
485 0x08, Size, 0,
486 0x80 | (Size & 0x0f), 1);
487 spca504A_acknowledged_command(gspca_dev,
488 1, 3, 0, 0x9f, 0);
489 } else {
490 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
491 }
492 break;
493 case BRIDGE_SPCA504C:
494
495 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
496 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
497 break;
498 }
499}
500
501static void spca504_wait_status(struct gspca_dev *gspca_dev)
502{
503 int cnt;
504
505 cnt = 256;
506 while (--cnt > 0) {
507
508 reg_r(gspca_dev, 0x06, 0x00, 1);
509 if (gspca_dev->usb_buf[0] == 0)
510 return;
511 msleep(10);
512 }
513}
514
515static void spca504B_setQtable(struct gspca_dev *gspca_dev)
516{
517 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
518 reg_r(gspca_dev, 0x26, 0, 1);
519 spca504B_PollingDataReady(gspca_dev);
520}
521
522static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
523{
524 struct sd *sd = (struct sd *) gspca_dev;
525 u16 reg;
526
527 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
528 reg_w_riv(gspca_dev, 0x00, reg, val);
529}
530
531static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
532{
533 struct sd *sd = (struct sd *) gspca_dev;
534 u16 reg;
535
536 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
537 reg_w_riv(gspca_dev, 0x00, reg, val);
538}
539
540static void setcolors(struct gspca_dev *gspca_dev, s32 val)
541{
542 struct sd *sd = (struct sd *) gspca_dev;
543 u16 reg;
544
545 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
546 reg_w_riv(gspca_dev, 0x00, reg, val);
547}
548
549static void init_ctl_reg(struct gspca_dev *gspca_dev)
550{
551 struct sd *sd = (struct sd *) gspca_dev;
552 int pollreg = 1;
553
554 switch (sd->bridge) {
555 case BRIDGE_SPCA504:
556 case BRIDGE_SPCA504C:
557 pollreg = 0;
558
559 default:
560
561
562 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);
563 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);
564 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);
565 break;
566 case BRIDGE_SPCA536:
567 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
568 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
569 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
570 break;
571 }
572 if (pollreg)
573 spca504B_PollingDataReady(gspca_dev);
574}
575
576
577static int sd_config(struct gspca_dev *gspca_dev,
578 const struct usb_device_id *id)
579{
580 struct sd *sd = (struct sd *) gspca_dev;
581 struct cam *cam;
582
583 cam = &gspca_dev->cam;
584
585 sd->bridge = id->driver_info >> 8;
586 sd->subtype = id->driver_info;
587
588 if (sd->subtype == AiptekMiniPenCam13) {
589
590
591
592 reg_r(gspca_dev, 0x20, 0, 1);
593 switch (gspca_dev->usb_buf[0]) {
594 case 1:
595 break;
596 case 2:
597 sd->bridge = BRIDGE_SPCA504B;
598 sd->subtype = 0;
599 break;
600 default:
601 return -ENODEV;
602 }
603 }
604
605 switch (sd->bridge) {
606 default:
607
608
609
610 cam->cam_mode = vga_mode;
611 cam->nmodes = ARRAY_SIZE(vga_mode);
612 break;
613 case BRIDGE_SPCA533:
614 cam->cam_mode = custom_mode;
615 if (sd->subtype == MegaImageVI)
616 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
617 else
618 cam->nmodes = ARRAY_SIZE(custom_mode);
619 break;
620 case BRIDGE_SPCA504C:
621 cam->cam_mode = vga_mode2;
622 cam->nmodes = ARRAY_SIZE(vga_mode2);
623 break;
624 }
625 return 0;
626}
627
628
629static int sd_init(struct gspca_dev *gspca_dev)
630{
631 struct sd *sd = (struct sd *) gspca_dev;
632
633 switch (sd->bridge) {
634 case BRIDGE_SPCA504B:
635 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
636 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
637 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
638 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
639 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
640 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
641
642 case BRIDGE_SPCA533:
643 spca504B_PollingDataReady(gspca_dev);
644 spca50x_GetFirmware(gspca_dev);
645 break;
646 case BRIDGE_SPCA536:
647 spca50x_GetFirmware(gspca_dev);
648 reg_r(gspca_dev, 0x00, 0x5002, 1);
649 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
650 reg_r(gspca_dev, 0x24, 0, 1);
651 spca504B_PollingDataReady(gspca_dev);
652 reg_w_riv(gspca_dev, 0x34, 0, 0);
653 spca504B_WaitCmdStatus(gspca_dev);
654 break;
655 case BRIDGE_SPCA504C:
656 gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n");
657 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
658 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);
659 spca504_wait_status(gspca_dev);
660 if (sd->subtype == LogitechClickSmart420)
661 write_vector(gspca_dev,
662 spca504A_clicksmart420_open_data,
663 ARRAY_SIZE(spca504A_clicksmart420_open_data));
664 else
665 write_vector(gspca_dev, spca504_pccam600_open_data,
666 ARRAY_SIZE(spca504_pccam600_open_data));
667 setup_qtable(gspca_dev, qtable_creative_pccam);
668 break;
669 default:
670
671 gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n");
672 if (sd->subtype == AiptekMiniPenCam13) {
673 spca504_read_info(gspca_dev);
674
675
676 spca504A_acknowledged_command(gspca_dev, 0x24,
677 8, 3, 0x9e, 1);
678
679 spca504A_acknowledged_command(gspca_dev, 0x24,
680 8, 3, 0x9e, 0);
681
682 spca504A_acknowledged_command(gspca_dev, 0x24,
683 0, 0, 0x9d, 1);
684
685
686 spca504A_acknowledged_command(gspca_dev, 0x08,
687 6, 0, 0x86, 1);
688
689
690
691
692
693
694 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
695
696 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
697 spca504A_acknowledged_command(gspca_dev, 0x01,
698 0x0f, 0, 0xff, 0);
699 }
700
701 reg_w_riv(gspca_dev, 0, 0x2000, 0);
702 reg_w_riv(gspca_dev, 0, 0x2883, 1);
703 setup_qtable(gspca_dev, qtable_spca504_default);
704 break;
705 }
706 return gspca_dev->usb_err;
707}
708
709static int sd_start(struct gspca_dev *gspca_dev)
710{
711 struct sd *sd = (struct sd *) gspca_dev;
712 int enable;
713
714
715 jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
716 gspca_dev->pixfmt.width,
717 0x22);
718 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
719
720 if (sd->bridge == BRIDGE_SPCA504B)
721 spca504B_setQtable(gspca_dev);
722 spca504B_SetSizeType(gspca_dev);
723 switch (sd->bridge) {
724 default:
725
726
727
728 switch (sd->subtype) {
729 case MegapixV4:
730 case LogitechClickSmart820:
731 case MegaImageVI:
732 reg_w_riv(gspca_dev, 0xf0, 0, 0);
733 spca504B_WaitCmdStatus(gspca_dev);
734 reg_r(gspca_dev, 0xf0, 4, 0);
735 spca504B_WaitCmdStatus(gspca_dev);
736 break;
737 default:
738 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
739 spca504B_WaitCmdStatus(gspca_dev);
740 spca504B_PollingDataReady(gspca_dev);
741 break;
742 }
743 break;
744 case BRIDGE_SPCA504:
745 if (sd->subtype == AiptekMiniPenCam13) {
746 spca504_read_info(gspca_dev);
747
748
749 spca504A_acknowledged_command(gspca_dev, 0x24,
750 8, 3, 0x9e, 1);
751
752 spca504A_acknowledged_command(gspca_dev, 0x24,
753 8, 3, 0x9e, 0);
754 spca504A_acknowledged_command(gspca_dev, 0x24,
755 0, 0, 0x9d, 1);
756 } else {
757 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
758 spca504_read_info(gspca_dev);
759 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
760 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
761 }
762 spca504B_SetSizeType(gspca_dev);
763 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
764
765 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
766 break;
767 case BRIDGE_SPCA504C:
768 if (sd->subtype == LogitechClickSmart420) {
769 write_vector(gspca_dev,
770 spca504A_clicksmart420_init_data,
771 ARRAY_SIZE(spca504A_clicksmart420_init_data));
772 } else {
773 write_vector(gspca_dev, spca504_pccam600_init_data,
774 ARRAY_SIZE(spca504_pccam600_init_data));
775 }
776 enable = (sd->autogain ? 0x04 : 0x01);
777 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
778
779 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
780
781
782
783 reg_w_riv(gspca_dev, 0x30, 0x0001, 800);
784 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
785 spca504B_SetSizeType(gspca_dev);
786 break;
787 }
788 init_ctl_reg(gspca_dev);
789 return gspca_dev->usb_err;
790}
791
792static void sd_stopN(struct gspca_dev *gspca_dev)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795
796 switch (sd->bridge) {
797 default:
798
799
800
801 reg_w_riv(gspca_dev, 0x31, 0, 0);
802 spca504B_WaitCmdStatus(gspca_dev);
803 spca504B_PollingDataReady(gspca_dev);
804 break;
805 case BRIDGE_SPCA504:
806 case BRIDGE_SPCA504C:
807 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
808
809 if (sd->subtype == AiptekMiniPenCam13) {
810
811
812
813 spca504A_acknowledged_command(gspca_dev, 0x24,
814 0x00, 0x00, 0x9d, 1);
815 spca504A_acknowledged_command(gspca_dev, 0x01,
816 0x0f, 0x00, 0xff, 1);
817 } else {
818 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
819 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
820 }
821 break;
822 }
823}
824
825static void sd_pkt_scan(struct gspca_dev *gspca_dev,
826 u8 *data,
827 int len)
828{
829 struct sd *sd = (struct sd *) gspca_dev;
830 int i, sof = 0;
831 static u8 ffd9[] = {0xff, 0xd9};
832
833
834 switch (sd->bridge) {
835 case BRIDGE_SPCA533:
836 if (data[0] == 0xff) {
837 if (data[1] != 0x01) {
838
839 return;
840 }
841 sof = 1;
842 data += SPCA533_OFFSET_DATA;
843 len -= SPCA533_OFFSET_DATA;
844 } else {
845 data += 1;
846 len -= 1;
847 }
848 break;
849 case BRIDGE_SPCA536:
850 if (data[0] == 0xff) {
851 sof = 1;
852 data += SPCA536_OFFSET_DATA;
853 len -= SPCA536_OFFSET_DATA;
854 } else {
855 data += 2;
856 len -= 2;
857 }
858 break;
859 default:
860
861
862 switch (data[0]) {
863 case 0xfe:
864 sof = 1;
865 data += SPCA50X_OFFSET_DATA;
866 len -= SPCA50X_OFFSET_DATA;
867 break;
868 case 0xff:
869
870 return;
871 default:
872 data += 1;
873 len -= 1;
874 break;
875 }
876 break;
877 case BRIDGE_SPCA504C:
878 switch (data[0]) {
879 case 0xfe:
880 sof = 1;
881 data += SPCA504_PCCAM600_OFFSET_DATA;
882 len -= SPCA504_PCCAM600_OFFSET_DATA;
883 break;
884 case 0xff:
885
886 return;
887 default:
888 data += 1;
889 len -= 1;
890 break;
891 }
892 break;
893 }
894 if (sof) {
895 gspca_frame_add(gspca_dev, LAST_PACKET,
896 ffd9, 2);
897
898
899 gspca_frame_add(gspca_dev, FIRST_PACKET,
900 sd->jpeg_hdr, JPEG_HDR_SZ);
901 }
902
903
904 i = 0;
905 do {
906 if (data[i] == 0xff) {
907 gspca_frame_add(gspca_dev, INTER_PACKET,
908 data, i + 1);
909 len -= i;
910 data += i;
911 *data = 0x00;
912 i = 0;
913 }
914 i++;
915 } while (i < len);
916 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
917}
918
919static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
920{
921 struct gspca_dev *gspca_dev =
922 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
923 struct sd *sd = (struct sd *)gspca_dev;
924
925 gspca_dev->usb_err = 0;
926
927 if (!gspca_dev->streaming)
928 return 0;
929
930 switch (ctrl->id) {
931 case V4L2_CID_BRIGHTNESS:
932 setbrightness(gspca_dev, ctrl->val);
933 break;
934 case V4L2_CID_CONTRAST:
935 setcontrast(gspca_dev, ctrl->val);
936 break;
937 case V4L2_CID_SATURATION:
938 setcolors(gspca_dev, ctrl->val);
939 break;
940 case V4L2_CID_AUTOGAIN:
941 sd->autogain = ctrl->val;
942 break;
943 }
944 return gspca_dev->usb_err;
945}
946
947static const struct v4l2_ctrl_ops sd_ctrl_ops = {
948 .s_ctrl = sd_s_ctrl,
949};
950
951static int sd_init_controls(struct gspca_dev *gspca_dev)
952{
953 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
954
955 gspca_dev->vdev.ctrl_handler = hdl;
956 v4l2_ctrl_handler_init(hdl, 4);
957 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
958 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
959 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
960 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
961 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
963 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
964 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
965
966 if (hdl->error) {
967 pr_err("Could not initialize controls\n");
968 return hdl->error;
969 }
970 return 0;
971}
972
973
974static const struct sd_desc sd_desc = {
975 .name = MODULE_NAME,
976 .config = sd_config,
977 .init = sd_init,
978 .init_controls = sd_init_controls,
979 .start = sd_start,
980 .stopN = sd_stopN,
981 .pkt_scan = sd_pkt_scan,
982};
983
984
985#define BS(bridge, subtype) \
986 .driver_info = (BRIDGE_ ## bridge << 8) \
987 | (subtype)
988static const struct usb_device_id device_table[] = {
989 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
990 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
991 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
992 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
993 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
994 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
995 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
996 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
997 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
998 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
999 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1000 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1001 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1002 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1003 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1004 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1005 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1006 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1007 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1008 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1009 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1010 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1011 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1012 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1013 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1014 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1015 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1016 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1017 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1018 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1019 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1020 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1021 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1022 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1023 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1024 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1025 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1026 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1027 {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1028 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1029 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1030 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1031 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1032 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1033 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1034 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1035 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1036 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1037 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1038 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1039 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1040 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1041 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1042 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1043 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1044 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1045 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1047 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1048 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1049 {}
1050};
1051MODULE_DEVICE_TABLE(usb, device_table);
1052
1053
1054static int sd_probe(struct usb_interface *intf,
1055 const struct usb_device_id *id)
1056{
1057 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1058 THIS_MODULE);
1059}
1060
1061static struct usb_driver sd_driver = {
1062 .name = MODULE_NAME,
1063 .id_table = device_table,
1064 .probe = sd_probe,
1065 .disconnect = gspca_disconnect,
1066#ifdef CONFIG_PM
1067 .suspend = gspca_suspend,
1068 .resume = gspca_resume,
1069 .reset_resume = gspca_resume,
1070#endif
1071};
1072
1073module_usb_driver(sd_driver);
1074