2 * Sunplus spca504(abc) spca533 spca536 library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20 #define MODULE_NAME "sunplus"
25 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
26 MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
27 MODULE_LICENSE("GPL");
31 /* specific webcam descriptor */
33 struct gspca_dev gspca_dev; /* !! must be the first item */
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
44 #define AiptekMiniPenCam13 1
45 #define LogitechClickSmart420 2
46 #define LogitechClickSmart820 3
50 u8 jpeg_hdr[JPEG_HDR_SZ];
53 static const struct v4l2_pix_format vga_mode[] = {
54 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
56 .sizeimage = 320 * 240 * 3 / 8 + 590,
57 .colorspace = V4L2_COLORSPACE_JPEG,
59 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
61 .sizeimage = 640 * 480 * 3 / 8 + 590,
62 .colorspace = V4L2_COLORSPACE_JPEG,
66 static const struct v4l2_pix_format custom_mode[] = {
67 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
69 .sizeimage = 320 * 240 * 3 / 8 + 590,
70 .colorspace = V4L2_COLORSPACE_JPEG,
72 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
74 .sizeimage = 464 * 480 * 3 / 8 + 590,
75 .colorspace = V4L2_COLORSPACE_JPEG,
79 static const struct v4l2_pix_format vga_mode2[] = {
80 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
82 .sizeimage = 176 * 144 * 3 / 8 + 590,
83 .colorspace = V4L2_COLORSPACE_JPEG,
85 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
87 .sizeimage = 320 * 240 * 3 / 8 + 590,
88 .colorspace = V4L2_COLORSPACE_JPEG,
90 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
92 .sizeimage = 352 * 288 * 3 / 8 + 590,
93 .colorspace = V4L2_COLORSPACE_JPEG,
95 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
97 .sizeimage = 640 * 480 * 3 / 8 + 590,
98 .colorspace = V4L2_COLORSPACE_JPEG,
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 /* Frame packet header offsets for the spca533 */
108 #define SPCA533_OFFSET_DATA 16
109 #define SPCA533_OFFSET_FRAMSEQ 15
110 /* Frame packet header offsets for the spca536 */
111 #define SPCA536_OFFSET_DATA 4
112 #define SPCA536_OFFSET_FRAMSEQ 1
120 /* Initialisation data for the Creative PC-CAM 600 */
121 static const struct cmd spca504_pccam600_init_data[] = {
122 /* {0xa0, 0x0000, 0x0503}, * capture mode */
123 {0x00, 0x0000, 0x2000},
124 {0x00, 0x0013, 0x2301},
125 {0x00, 0x0003, 0x2000},
126 {0x00, 0x0001, 0x21ac},
127 {0x00, 0x0001, 0x21a6},
128 {0x00, 0x0000, 0x21a7}, /* brightness */
129 {0x00, 0x0020, 0x21a8}, /* contrast */
130 {0x00, 0x0001, 0x21ac}, /* sat/hue */
131 {0x00, 0x0000, 0x21ad}, /* hue */
132 {0x00, 0x001a, 0x21ae}, /* saturation */
133 {0x00, 0x0002, 0x21a3}, /* gamma */
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},
147 /* Creative PC-CAM 600 specific open data, sent before using the
148 * generic initialisation data from spca504_open_data.
150 static const struct cmd spca504_pccam600_open_data[] = {
151 {0x00, 0x0001, 0x2501},
152 {0x20, 0x0500, 0x0001}, /* snapshot mode */
153 {0x00, 0x0003, 0x2880},
154 {0x00, 0x0001, 0x2881},
157 /* Initialisation data for the logitech clicksmart 420 */
158 static const struct cmd spca504A_clicksmart420_init_data[] = {
159 /* {0xa0, 0x0000, 0x0503}, * capture mode */
160 {0x00, 0x0000, 0x2000},
161 {0x00, 0x0013, 0x2301},
162 {0x00, 0x0003, 0x2000},
163 {0x00, 0x0001, 0x21ac},
164 {0x00, 0x0001, 0x21a6},
165 {0x00, 0x0000, 0x21a7}, /* brightness */
166 {0x00, 0x0020, 0x21a8}, /* contrast */
167 {0x00, 0x0001, 0x21ac}, /* sat/hue */
168 {0x00, 0x0000, 0x21ad}, /* hue */
169 {0x00, 0x001a, 0x21ae}, /* saturation */
170 {0x00, 0x0002, 0x21a3}, /* gamma */
171 {0x30, 0x0004, 0x000a},
172 {0xb0, 0x0001, 0x0000},
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},
184 /* clicksmart 420 open data ? */
185 static 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},
192 {0xa0, 0x0000, 0x0503},
195 static const u8 qtable_creative_pccam[2][64] = {
196 { /* Q-table Y-components */
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 { /* Q-table C-components */
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}
216 /* FIXME: This Q-table is identical to the Creative PC-CAM one,
217 * except for one byte. Possibly a typo?
220 static const u8 qtable_spca504_default[2][64] = {
221 { /* Q-table Y-components */
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 /* 0x22 */ , 0x1e, 0x1f, 0x1e,
231 { /* Q-table C-components */
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}
242 /* read <len> bytes to gspca_dev->usb_buf */
243 static void reg_r(struct gspca_dev *gspca_dev,
250 if (len > USB_BUF_SZ) {
251 PERR("reg_r: buffer overflow\n");
254 if (gspca_dev->usb_err < 0)
256 ret = usb_control_msg(gspca_dev->dev,
257 usb_rcvctrlpipe(gspca_dev->dev, 0),
259 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
262 len ? gspca_dev->usb_buf : NULL, len,
265 pr_err("reg_r err %d\n", ret);
266 gspca_dev->usb_err = ret;
271 static void reg_w_1(struct gspca_dev *gspca_dev,
279 if (gspca_dev->usb_err < 0)
281 gspca_dev->usb_buf[0] = byte;
282 ret = usb_control_msg(gspca_dev->dev,
283 usb_sndctrlpipe(gspca_dev->dev, 0),
285 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
287 gspca_dev->usb_buf, 1,
290 pr_err("reg_w_1 err %d\n", ret);
291 gspca_dev->usb_err = ret;
295 /* write req / index / value */
296 static void reg_w_riv(struct gspca_dev *gspca_dev,
297 u8 req, u16 index, u16 value)
299 struct usb_device *dev = gspca_dev->dev;
302 if (gspca_dev->usb_err < 0)
304 ret = usb_control_msg(dev,
305 usb_sndctrlpipe(dev, 0),
307 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
308 value, index, NULL, 0, 500);
310 pr_err("reg_w_riv err %d\n", ret);
311 gspca_dev->usb_err = ret;
314 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
318 static void write_vector(struct gspca_dev *gspca_dev,
319 const struct cmd *data, int ncmds)
321 while (--ncmds >= 0) {
322 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
327 static void setup_qtable(struct gspca_dev *gspca_dev,
328 const u8 qtable[2][64])
332 /* loop over y components */
333 for (i = 0; i < 64; i++)
334 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
336 /* loop over c components */
337 for (i = 0; i < 64; i++)
338 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
341 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
342 u8 req, u16 idx, u16 val)
344 reg_w_riv(gspca_dev, req, idx, val);
345 reg_r(gspca_dev, 0x01, 0x0001, 1);
346 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
347 reg_w_riv(gspca_dev, req, idx, val);
350 reg_r(gspca_dev, 0x01, 0x0001, 1);
351 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
354 static void spca504_read_info(struct gspca_dev *gspca_dev)
359 if (gspca_debug < D_STREAM)
362 for (i = 0; i < 6; i++) {
363 reg_r(gspca_dev, 0, i, 1);
364 info[i] = gspca_dev->usb_buf[0];
367 "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0",
368 info[0], info[1], info[2],
369 info[3], info[4], info[5]);
372 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
374 u16 idx, u16 val, u8 endcode, u8 count)
378 reg_w_riv(gspca_dev, req, idx, val);
379 reg_r(gspca_dev, 0x01, 0x0001, 1);
380 if (gspca_dev->usb_err < 0)
382 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
383 gspca_dev->usb_buf[0], endcode);
387 while (--count > 0) {
389 /* gsmart mini2 write a each wait setting 1 ms is enough */
390 /* reg_w_riv(gspca_dev, req, idx, val); */
391 reg_r(gspca_dev, 0x01, 0x0001, 1);
392 status = gspca_dev->usb_buf[0];
393 if (status == endcode) {
394 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
395 status, 200 - count);
401 static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
405 while (--count > 0) {
406 reg_r(gspca_dev, 0x21, 0, 1);
407 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
413 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
417 while (--count > 0) {
418 reg_r(gspca_dev, 0x21, 1, 1);
419 if (gspca_dev->usb_buf[0] != 0) {
420 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
421 reg_r(gspca_dev, 0x21, 1, 1);
422 spca504B_PollingDataReady(gspca_dev);
429 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
433 if (gspca_debug < D_STREAM)
436 data = gspca_dev->usb_buf;
437 reg_r(gspca_dev, 0x20, 0, 5);
438 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
439 data[0], data[1], data[2], data[3], data[4]);
440 reg_r(gspca_dev, 0x23, 0, 64);
441 reg_r(gspca_dev, 0x23, 1, 64);
444 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
446 struct sd *sd = (struct sd *) gspca_dev;
449 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
450 switch (sd->bridge) {
452 reg_w_riv(gspca_dev, 0x31, 0, 0);
453 spca504B_WaitCmdStatus(gspca_dev);
454 spca504B_PollingDataReady(gspca_dev);
455 spca50x_GetFirmware(gspca_dev);
457 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
458 reg_r(gspca_dev, 0x24, 8, 1);
460 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
461 reg_r(gspca_dev, 0x25, 4, 1); /* size */
462 spca504B_PollingDataReady(gspca_dev);
464 /* Init the cam width height with some values get on init ? */
465 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
466 spca504B_WaitCmdStatus(gspca_dev);
467 spca504B_PollingDataReady(gspca_dev);
470 /* case BRIDGE_SPCA504B: */
471 /* case BRIDGE_SPCA536: */
472 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
473 reg_r(gspca_dev, 0x25, 4, 1); /* size */
474 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
475 reg_r(gspca_dev, 0x27, 0, 1); /* type */
476 spca504B_PollingDataReady(gspca_dev);
480 if (sd->subtype == AiptekMiniPenCam13) {
481 /* spca504a aiptek */
482 spca504A_acknowledged_command(gspca_dev,
484 0x80 | (Size & 0x0f), 1);
485 spca504A_acknowledged_command(gspca_dev,
488 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
491 case BRIDGE_SPCA504C:
493 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
494 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
499 static void spca504_wait_status(struct gspca_dev *gspca_dev)
505 /* With this we get the status, when return 0 it's all ok */
506 reg_r(gspca_dev, 0x06, 0x00, 1);
507 if (gspca_dev->usb_buf[0] == 0)
513 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
515 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
516 reg_r(gspca_dev, 0x26, 0, 1);
517 spca504B_PollingDataReady(gspca_dev);
520 static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
522 struct sd *sd = (struct sd *) gspca_dev;
525 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
526 reg_w_riv(gspca_dev, 0x00, reg, val);
529 static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
531 struct sd *sd = (struct sd *) gspca_dev;
534 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
535 reg_w_riv(gspca_dev, 0x00, reg, val);
538 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
540 struct sd *sd = (struct sd *) gspca_dev;
543 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
544 reg_w_riv(gspca_dev, 0x00, reg, val);
547 static void init_ctl_reg(struct gspca_dev *gspca_dev)
549 struct sd *sd = (struct sd *) gspca_dev;
552 switch (sd->bridge) {
554 case BRIDGE_SPCA504C:
558 /* case BRIDGE_SPCA533: */
559 /* case BRIDGE_SPCA504B: */
560 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
561 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
562 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
565 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
566 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
567 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
571 spca504B_PollingDataReady(gspca_dev);
574 /* this function is called at probe time */
575 static int sd_config(struct gspca_dev *gspca_dev,
576 const struct usb_device_id *id)
578 struct sd *sd = (struct sd *) gspca_dev;
581 cam = &gspca_dev->cam;
583 sd->bridge = id->driver_info >> 8;
584 sd->subtype = id->driver_info;
586 if (sd->subtype == AiptekMiniPenCam13) {
588 /* try to get the firmware as some cam answer 2.0.1.2.2
589 * and should be a spca504b then overwrite that setting */
590 reg_r(gspca_dev, 0x20, 0, 1);
591 switch (gspca_dev->usb_buf[0]) {
593 break; /* (right bridge/subtype) */
595 sd->bridge = BRIDGE_SPCA504B;
603 switch (sd->bridge) {
605 /* case BRIDGE_SPCA504B: */
606 /* case BRIDGE_SPCA504: */
607 /* case BRIDGE_SPCA536: */
608 cam->cam_mode = vga_mode;
609 cam->nmodes = ARRAY_SIZE(vga_mode);
612 cam->cam_mode = custom_mode;
613 if (sd->subtype == MegaImageVI) /* 320x240 only */
614 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
616 cam->nmodes = ARRAY_SIZE(custom_mode);
618 case BRIDGE_SPCA504C:
619 cam->cam_mode = vga_mode2;
620 cam->nmodes = ARRAY_SIZE(vga_mode2);
626 /* this function is called at probe and resume time */
627 static int sd_init(struct gspca_dev *gspca_dev)
629 struct sd *sd = (struct sd *) gspca_dev;
631 switch (sd->bridge) {
632 case BRIDGE_SPCA504B:
633 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
634 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
635 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
636 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
637 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
638 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
641 spca504B_PollingDataReady(gspca_dev);
642 spca50x_GetFirmware(gspca_dev);
645 spca50x_GetFirmware(gspca_dev);
646 reg_r(gspca_dev, 0x00, 0x5002, 1);
647 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
648 reg_r(gspca_dev, 0x24, 0, 1);
649 spca504B_PollingDataReady(gspca_dev);
650 reg_w_riv(gspca_dev, 0x34, 0, 0);
651 spca504B_WaitCmdStatus(gspca_dev);
653 case BRIDGE_SPCA504C: /* pccam600 */
654 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
655 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
656 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
657 spca504_wait_status(gspca_dev);
658 if (sd->subtype == LogitechClickSmart420)
659 write_vector(gspca_dev,
660 spca504A_clicksmart420_open_data,
661 ARRAY_SIZE(spca504A_clicksmart420_open_data));
663 write_vector(gspca_dev, spca504_pccam600_open_data,
664 ARRAY_SIZE(spca504_pccam600_open_data));
665 setup_qtable(gspca_dev, qtable_creative_pccam);
668 /* case BRIDGE_SPCA504: */
669 PDEBUG(D_STREAM, "Opening SPCA504");
670 if (sd->subtype == AiptekMiniPenCam13) {
671 spca504_read_info(gspca_dev);
673 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
674 spca504A_acknowledged_command(gspca_dev, 0x24,
676 /* Twice sequential need status 0xff->0x9e->0x9d */
677 spca504A_acknowledged_command(gspca_dev, 0x24,
680 spca504A_acknowledged_command(gspca_dev, 0x24,
682 /******************************/
683 /* spca504a aiptek */
684 spca504A_acknowledged_command(gspca_dev, 0x08,
686 /* reg_write (dev, 0, 0x2000, 0); */
687 /* reg_write (dev, 0, 0x2883, 1); */
688 /* spca504A_acknowledged_command (gspca_dev, 0x08,
690 /* spca504A_acknowledged_command (gspca_dev, 0x24,
692 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
694 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
695 spca504A_acknowledged_command(gspca_dev, 0x01,
699 reg_w_riv(gspca_dev, 0, 0x2000, 0);
700 reg_w_riv(gspca_dev, 0, 0x2883, 1);
701 setup_qtable(gspca_dev, qtable_spca504_default);
704 return gspca_dev->usb_err;
707 static int sd_start(struct gspca_dev *gspca_dev)
709 struct sd *sd = (struct sd *) gspca_dev;
712 /* create the JPEG header */
713 jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
714 gspca_dev->pixfmt.width,
715 0x22); /* JPEG 411 */
716 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
718 if (sd->bridge == BRIDGE_SPCA504B)
719 spca504B_setQtable(gspca_dev);
720 spca504B_SetSizeType(gspca_dev);
721 switch (sd->bridge) {
723 /* case BRIDGE_SPCA504B: */
724 /* case BRIDGE_SPCA533: */
725 /* case BRIDGE_SPCA536: */
726 switch (sd->subtype) {
728 case LogitechClickSmart820:
730 reg_w_riv(gspca_dev, 0xf0, 0, 0);
731 spca504B_WaitCmdStatus(gspca_dev);
732 reg_r(gspca_dev, 0xf0, 4, 0);
733 spca504B_WaitCmdStatus(gspca_dev);
736 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
737 spca504B_WaitCmdStatus(gspca_dev);
738 spca504B_PollingDataReady(gspca_dev);
743 if (sd->subtype == AiptekMiniPenCam13) {
744 spca504_read_info(gspca_dev);
746 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
747 spca504A_acknowledged_command(gspca_dev, 0x24,
749 /* Twice sequential need status 0xff->0x9e->0x9d */
750 spca504A_acknowledged_command(gspca_dev, 0x24,
752 spca504A_acknowledged_command(gspca_dev, 0x24,
755 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
756 spca504_read_info(gspca_dev);
757 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
758 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
760 spca504B_SetSizeType(gspca_dev);
761 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
763 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
765 case BRIDGE_SPCA504C:
766 if (sd->subtype == LogitechClickSmart420) {
767 write_vector(gspca_dev,
768 spca504A_clicksmart420_init_data,
769 ARRAY_SIZE(spca504A_clicksmart420_init_data));
771 write_vector(gspca_dev, spca504_pccam600_init_data,
772 ARRAY_SIZE(spca504_pccam600_init_data));
774 enable = (sd->autogain ? 0x04 : 0x01);
775 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
777 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
780 /* set default exposure compensation and whiteness balance */
781 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
782 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
783 spca504B_SetSizeType(gspca_dev);
786 init_ctl_reg(gspca_dev);
787 return gspca_dev->usb_err;
790 static void sd_stopN(struct gspca_dev *gspca_dev)
792 struct sd *sd = (struct sd *) gspca_dev;
794 switch (sd->bridge) {
796 /* case BRIDGE_SPCA533: */
797 /* case BRIDGE_SPCA536: */
798 /* case BRIDGE_SPCA504B: */
799 reg_w_riv(gspca_dev, 0x31, 0, 0);
800 spca504B_WaitCmdStatus(gspca_dev);
801 spca504B_PollingDataReady(gspca_dev);
804 case BRIDGE_SPCA504C:
805 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
807 if (sd->subtype == AiptekMiniPenCam13) {
808 /* spca504a aiptek */
809 /* spca504A_acknowledged_command(gspca_dev, 0x08,
811 spca504A_acknowledged_command(gspca_dev, 0x24,
812 0x00, 0x00, 0x9d, 1);
813 spca504A_acknowledged_command(gspca_dev, 0x01,
814 0x0f, 0x00, 0xff, 1);
816 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
817 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
823 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
824 u8 *data, /* isoc packet */
825 int len) /* iso packet length */
827 struct sd *sd = (struct sd *) gspca_dev;
829 static u8 ffd9[] = {0xff, 0xd9};
831 /* frames are jpeg 4.1.1 without 0xff escape */
832 switch (sd->bridge) {
834 if (data[0] == 0xff) {
835 if (data[1] != 0x01) { /* drop packet */
836 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
840 data += SPCA533_OFFSET_DATA;
841 len -= SPCA533_OFFSET_DATA;
848 if (data[0] == 0xff) {
850 data += SPCA536_OFFSET_DATA;
851 len -= SPCA536_OFFSET_DATA;
858 /* case BRIDGE_SPCA504: */
859 /* case BRIDGE_SPCA504B: */
861 case 0xfe: /* start of frame */
863 data += SPCA50X_OFFSET_DATA;
864 len -= SPCA50X_OFFSET_DATA;
866 case 0xff: /* drop packet */
867 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
875 case BRIDGE_SPCA504C:
877 case 0xfe: /* start of frame */
879 data += SPCA504_PCCAM600_OFFSET_DATA;
880 len -= SPCA504_PCCAM600_OFFSET_DATA;
882 case 0xff: /* drop packet */
883 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
892 if (sof) { /* start of frame */
893 gspca_frame_add(gspca_dev, LAST_PACKET,
896 /* put the JPEG header in the new frame */
897 gspca_frame_add(gspca_dev, FIRST_PACKET,
898 sd->jpeg_hdr, JPEG_HDR_SZ);
901 /* add 0x00 after 0xff */
904 if (data[i] == 0xff) {
905 gspca_frame_add(gspca_dev, INTER_PACKET,
914 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
917 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
919 struct gspca_dev *gspca_dev =
920 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
921 struct sd *sd = (struct sd *)gspca_dev;
923 gspca_dev->usb_err = 0;
925 if (!gspca_dev->streaming)
929 case V4L2_CID_BRIGHTNESS:
930 setbrightness(gspca_dev, ctrl->val);
932 case V4L2_CID_CONTRAST:
933 setcontrast(gspca_dev, ctrl->val);
935 case V4L2_CID_SATURATION:
936 setcolors(gspca_dev, ctrl->val);
938 case V4L2_CID_AUTOGAIN:
939 sd->autogain = ctrl->val;
942 return gspca_dev->usb_err;
945 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
949 static int sd_init_controls(struct gspca_dev *gspca_dev)
951 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
953 gspca_dev->vdev.ctrl_handler = hdl;
954 v4l2_ctrl_handler_init(hdl, 4);
955 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
956 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
957 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
958 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
959 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
960 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
961 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
965 pr_err("Could not initialize controls\n");
971 /* sub-driver description */
972 static const struct sd_desc sd_desc = {
976 .init_controls = sd_init_controls,
979 .pkt_scan = sd_pkt_scan,
982 /* -- module initialisation -- */
983 #define BS(bridge, subtype) \
984 .driver_info = (BRIDGE_ ## bridge << 8) \
986 static const struct usb_device_id device_table[] = {
987 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
988 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
989 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
990 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
991 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
992 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
993 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
994 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
995 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
996 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
997 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
998 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
999 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1000 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1001 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1002 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1003 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1004 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1005 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1006 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1007 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1008 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1009 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1010 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1011 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1012 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1013 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1014 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1015 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1016 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1017 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1018 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1019 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1020 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1021 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1022 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1023 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1024 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1025 {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1026 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1027 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1028 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1029 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1030 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1031 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1032 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1033 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1034 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1035 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1036 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1037 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1038 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1039 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1040 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1041 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1042 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1043 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1044 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1045 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1049 MODULE_DEVICE_TABLE(usb, device_table);
1051 /* -- device connect -- */
1052 static int sd_probe(struct usb_interface *intf,
1053 const struct usb_device_id *id)
1055 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1059 static struct usb_driver sd_driver = {
1060 .name = MODULE_NAME,
1061 .id_table = device_table,
1063 .disconnect = gspca_disconnect,
1065 .suspend = gspca_suspend,
1066 .resume = gspca_resume,
1067 .reset_resume = gspca_resume,
1071 module_usb_driver(sd_driver);