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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 #define MODULE_NAME "sunplus"
29 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
30 MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
31 MODULE_LICENSE("GPL");
35 /* specific webcam descriptor */
37 struct gspca_dev gspca_dev; /* !! must be the first item */
42 #define BRIDGE_SPCA504 0
43 #define BRIDGE_SPCA504B 1
44 #define BRIDGE_SPCA504C 2
45 #define BRIDGE_SPCA533 3
46 #define BRIDGE_SPCA536 4
48 #define AiptekMiniPenCam13 1
49 #define LogitechClickSmart420 2
50 #define LogitechClickSmart820 3
54 u8 jpeg_hdr[JPEG_HDR_SZ];
57 static const struct v4l2_pix_format vga_mode[] = {
58 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
60 .sizeimage = 320 * 240 * 3 / 8 + 590,
61 .colorspace = V4L2_COLORSPACE_JPEG,
63 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
65 .sizeimage = 640 * 480 * 3 / 8 + 590,
66 .colorspace = V4L2_COLORSPACE_JPEG,
70 static const struct v4l2_pix_format custom_mode[] = {
71 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
73 .sizeimage = 320 * 240 * 3 / 8 + 590,
74 .colorspace = V4L2_COLORSPACE_JPEG,
76 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
78 .sizeimage = 464 * 480 * 3 / 8 + 590,
79 .colorspace = V4L2_COLORSPACE_JPEG,
83 static const struct v4l2_pix_format vga_mode2[] = {
84 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
86 .sizeimage = 176 * 144 * 3 / 8 + 590,
87 .colorspace = V4L2_COLORSPACE_JPEG,
89 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
91 .sizeimage = 320 * 240 * 3 / 8 + 590,
92 .colorspace = V4L2_COLORSPACE_JPEG,
94 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
96 .sizeimage = 352 * 288 * 3 / 8 + 590,
97 .colorspace = V4L2_COLORSPACE_JPEG,
99 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
101 .sizeimage = 640 * 480 * 3 / 8 + 590,
102 .colorspace = V4L2_COLORSPACE_JPEG,
106 #define SPCA50X_OFFSET_DATA 10
107 #define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
108 #define SPCA504_PCCAM600_OFFSET_COMPRESS 4
109 #define SPCA504_PCCAM600_OFFSET_MODE 5
110 #define SPCA504_PCCAM600_OFFSET_DATA 14
111 /* Frame packet header offsets for the spca533 */
112 #define SPCA533_OFFSET_DATA 16
113 #define SPCA533_OFFSET_FRAMSEQ 15
114 /* Frame packet header offsets for the spca536 */
115 #define SPCA536_OFFSET_DATA 4
116 #define SPCA536_OFFSET_FRAMSEQ 1
124 /* Initialisation data for the Creative PC-CAM 600 */
125 static const struct cmd spca504_pccam600_init_data[] = {
126 /* {0xa0, 0x0000, 0x0503}, * capture mode */
127 {0x00, 0x0000, 0x2000},
128 {0x00, 0x0013, 0x2301},
129 {0x00, 0x0003, 0x2000},
130 {0x00, 0x0001, 0x21ac},
131 {0x00, 0x0001, 0x21a6},
132 {0x00, 0x0000, 0x21a7}, /* brightness */
133 {0x00, 0x0020, 0x21a8}, /* contrast */
134 {0x00, 0x0001, 0x21ac}, /* sat/hue */
135 {0x00, 0x0000, 0x21ad}, /* hue */
136 {0x00, 0x001a, 0x21ae}, /* saturation */
137 {0x00, 0x0002, 0x21a3}, /* gamma */
138 {0x30, 0x0154, 0x0008},
139 {0x30, 0x0004, 0x0006},
140 {0x30, 0x0258, 0x0009},
141 {0x30, 0x0004, 0x0000},
142 {0x30, 0x0093, 0x0004},
143 {0x30, 0x0066, 0x0005},
144 {0x00, 0x0000, 0x2000},
145 {0x00, 0x0013, 0x2301},
146 {0x00, 0x0003, 0x2000},
147 {0x00, 0x0013, 0x2301},
148 {0x00, 0x0003, 0x2000},
151 /* Creative PC-CAM 600 specific open data, sent before using the
152 * generic initialisation data from spca504_open_data.
154 static const struct cmd spca504_pccam600_open_data[] = {
155 {0x00, 0x0001, 0x2501},
156 {0x20, 0x0500, 0x0001}, /* snapshot mode */
157 {0x00, 0x0003, 0x2880},
158 {0x00, 0x0001, 0x2881},
161 /* Initialisation data for the logitech clicksmart 420 */
162 static const struct cmd spca504A_clicksmart420_init_data[] = {
163 /* {0xa0, 0x0000, 0x0503}, * capture mode */
164 {0x00, 0x0000, 0x2000},
165 {0x00, 0x0013, 0x2301},
166 {0x00, 0x0003, 0x2000},
167 {0x00, 0x0001, 0x21ac},
168 {0x00, 0x0001, 0x21a6},
169 {0x00, 0x0000, 0x21a7}, /* brightness */
170 {0x00, 0x0020, 0x21a8}, /* contrast */
171 {0x00, 0x0001, 0x21ac}, /* sat/hue */
172 {0x00, 0x0000, 0x21ad}, /* hue */
173 {0x00, 0x001a, 0x21ae}, /* saturation */
174 {0x00, 0x0002, 0x21a3}, /* gamma */
175 {0x30, 0x0004, 0x000a},
176 {0xb0, 0x0001, 0x0000},
178 {0xa1, 0x0080, 0x0001},
179 {0x30, 0x0049, 0x0000},
180 {0x30, 0x0060, 0x0005},
181 {0x0c, 0x0004, 0x0000},
182 {0x00, 0x0000, 0x0000},
183 {0x00, 0x0000, 0x2000},
184 {0x00, 0x0013, 0x2301},
185 {0x00, 0x0003, 0x2000},
188 /* clicksmart 420 open data ? */
189 static const struct cmd spca504A_clicksmart420_open_data[] = {
190 {0x00, 0x0001, 0x2501},
191 {0x20, 0x0502, 0x0000},
192 {0x06, 0x0000, 0x0000},
193 {0x00, 0x0004, 0x2880},
194 {0x00, 0x0001, 0x2881},
196 {0xa0, 0x0000, 0x0503},
199 static const u8 qtable_creative_pccam[2][64] = {
200 { /* Q-table Y-components */
201 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
202 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
203 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
204 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
205 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
206 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
207 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
208 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
209 { /* Q-table C-components */
210 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
211 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
212 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
213 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
214 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
215 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
216 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
217 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
220 /* FIXME: This Q-table is identical to the Creative PC-CAM one,
221 * except for one byte. Possibly a typo?
224 static const u8 qtable_spca504_default[2][64] = {
225 { /* Q-table Y-components */
226 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
227 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
228 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
229 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
230 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
231 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
232 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
233 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
235 { /* Q-table C-components */
236 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
237 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
238 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
239 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
240 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
241 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
242 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
243 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
246 /* read <len> bytes to gspca_dev->usb_buf */
247 static void reg_r(struct gspca_dev *gspca_dev,
254 if (len > USB_BUF_SZ) {
255 PERR("reg_r: buffer overflow\n");
259 PERR("reg_r: zero-length read\n");
262 if (gspca_dev->usb_err < 0)
264 ret = usb_control_msg(gspca_dev->dev,
265 usb_rcvctrlpipe(gspca_dev->dev, 0),
267 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
270 gspca_dev->usb_buf, len,
273 pr_err("reg_r err %d\n", ret);
274 gspca_dev->usb_err = ret;
276 * Make sure the buffer is zeroed to avoid uninitialized
279 memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
284 static void reg_w_1(struct gspca_dev *gspca_dev,
292 if (gspca_dev->usb_err < 0)
294 gspca_dev->usb_buf[0] = byte;
295 ret = usb_control_msg(gspca_dev->dev,
296 usb_sndctrlpipe(gspca_dev->dev, 0),
298 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
300 gspca_dev->usb_buf, 1,
303 pr_err("reg_w_1 err %d\n", ret);
304 gspca_dev->usb_err = ret;
308 /* write req / index / value */
309 static void reg_w_riv(struct gspca_dev *gspca_dev,
310 u8 req, u16 index, u16 value)
312 struct usb_device *dev = gspca_dev->dev;
315 if (gspca_dev->usb_err < 0)
317 ret = usb_control_msg(dev,
318 usb_sndctrlpipe(dev, 0),
320 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
321 value, index, NULL, 0, 500);
323 pr_err("reg_w_riv err %d\n", ret);
324 gspca_dev->usb_err = ret;
327 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
331 static void write_vector(struct gspca_dev *gspca_dev,
332 const struct cmd *data, int ncmds)
334 while (--ncmds >= 0) {
335 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
340 static void setup_qtable(struct gspca_dev *gspca_dev,
341 const u8 qtable[2][64])
345 /* loop over y components */
346 for (i = 0; i < 64; i++)
347 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
349 /* loop over c components */
350 for (i = 0; i < 64; i++)
351 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
354 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
355 u8 req, u16 idx, u16 val)
357 reg_w_riv(gspca_dev, req, idx, val);
358 reg_r(gspca_dev, 0x01, 0x0001, 1);
359 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
360 reg_w_riv(gspca_dev, req, idx, val);
363 reg_r(gspca_dev, 0x01, 0x0001, 1);
364 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
367 static void spca504_read_info(struct gspca_dev *gspca_dev)
372 if (gspca_debug < D_STREAM)
375 for (i = 0; i < 6; i++) {
376 reg_r(gspca_dev, 0, i, 1);
377 info[i] = gspca_dev->usb_buf[0];
380 "Read info: %d %d %d %d %d %d."
381 " Should be 1,0,2,2,0,0",
382 info[0], info[1], info[2],
383 info[3], info[4], info[5]);
386 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
388 u16 idx, u16 val, u8 endcode, u8 count)
392 reg_w_riv(gspca_dev, req, idx, val);
393 reg_r(gspca_dev, 0x01, 0x0001, 1);
394 if (gspca_dev->usb_err < 0)
396 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
397 gspca_dev->usb_buf[0], endcode);
401 while (--count > 0) {
403 /* gsmart mini2 write a each wait setting 1 ms is enough */
404 /* reg_w_riv(gspca_dev, req, idx, val); */
405 reg_r(gspca_dev, 0x01, 0x0001, 1);
406 status = gspca_dev->usb_buf[0];
407 if (status == endcode) {
408 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
409 status, 200 - count);
415 static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
419 while (--count > 0) {
420 reg_r(gspca_dev, 0x21, 0, 1);
421 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
427 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
431 while (--count > 0) {
432 reg_r(gspca_dev, 0x21, 1, 1);
433 if (gspca_dev->usb_buf[0] != 0) {
434 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
435 reg_r(gspca_dev, 0x21, 1, 1);
436 spca504B_PollingDataReady(gspca_dev);
443 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
447 if (gspca_debug < D_STREAM)
450 data = gspca_dev->usb_buf;
451 reg_r(gspca_dev, 0x20, 0, 5);
452 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
453 data[0], data[1], data[2], data[3], data[4]);
454 reg_r(gspca_dev, 0x23, 0, 64);
455 reg_r(gspca_dev, 0x23, 1, 64);
458 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
460 struct sd *sd = (struct sd *) gspca_dev;
463 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
464 switch (sd->bridge) {
466 reg_w_riv(gspca_dev, 0x31, 0, 0);
467 spca504B_WaitCmdStatus(gspca_dev);
468 spca504B_PollingDataReady(gspca_dev);
469 spca50x_GetFirmware(gspca_dev);
471 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
472 reg_r(gspca_dev, 0x24, 8, 1);
474 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
475 reg_r(gspca_dev, 0x25, 4, 1); /* size */
476 spca504B_PollingDataReady(gspca_dev);
478 /* Init the cam width height with some values get on init ? */
479 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
480 spca504B_WaitCmdStatus(gspca_dev);
481 spca504B_PollingDataReady(gspca_dev);
484 /* case BRIDGE_SPCA504B: */
485 /* case BRIDGE_SPCA536: */
486 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
487 reg_r(gspca_dev, 0x25, 4, 1); /* size */
488 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
489 reg_r(gspca_dev, 0x27, 0, 1); /* type */
490 spca504B_PollingDataReady(gspca_dev);
494 if (sd->subtype == AiptekMiniPenCam13) {
495 /* spca504a aiptek */
496 spca504A_acknowledged_command(gspca_dev,
498 0x80 | (Size & 0x0f), 1);
499 spca504A_acknowledged_command(gspca_dev,
502 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
505 case BRIDGE_SPCA504C:
507 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
508 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
513 static void spca504_wait_status(struct gspca_dev *gspca_dev)
519 /* With this we get the status, when return 0 it's all ok */
520 reg_r(gspca_dev, 0x06, 0x00, 1);
521 if (gspca_dev->usb_buf[0] == 0)
527 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
529 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
530 reg_r(gspca_dev, 0x26, 0, 1);
531 spca504B_PollingDataReady(gspca_dev);
534 static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
536 struct sd *sd = (struct sd *) gspca_dev;
539 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
540 reg_w_riv(gspca_dev, 0x00, reg, val);
543 static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
545 struct sd *sd = (struct sd *) gspca_dev;
548 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
549 reg_w_riv(gspca_dev, 0x00, reg, val);
552 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
554 struct sd *sd = (struct sd *) gspca_dev;
557 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
558 reg_w_riv(gspca_dev, 0x00, reg, val);
561 static void init_ctl_reg(struct gspca_dev *gspca_dev)
563 struct sd *sd = (struct sd *) gspca_dev;
566 switch (sd->bridge) {
568 case BRIDGE_SPCA504C:
572 /* case BRIDGE_SPCA533: */
573 /* case BRIDGE_SPCA504B: */
574 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
575 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
576 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
579 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
580 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
581 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
585 spca504B_PollingDataReady(gspca_dev);
588 /* this function is called at probe time */
589 static int sd_config(struct gspca_dev *gspca_dev,
590 const struct usb_device_id *id)
592 struct sd *sd = (struct sd *) gspca_dev;
595 cam = &gspca_dev->cam;
597 sd->bridge = id->driver_info >> 8;
598 sd->subtype = id->driver_info;
600 if (sd->subtype == AiptekMiniPenCam13) {
602 /* try to get the firmware as some cam answer 2.0.1.2.2
603 * and should be a spca504b then overwrite that setting */
604 reg_r(gspca_dev, 0x20, 0, 1);
605 switch (gspca_dev->usb_buf[0]) {
607 break; /* (right bridge/subtype) */
609 sd->bridge = BRIDGE_SPCA504B;
617 switch (sd->bridge) {
619 /* case BRIDGE_SPCA504B: */
620 /* case BRIDGE_SPCA504: */
621 /* case BRIDGE_SPCA536: */
622 cam->cam_mode = vga_mode;
623 cam->nmodes = ARRAY_SIZE(vga_mode);
626 cam->cam_mode = custom_mode;
627 if (sd->subtype == MegaImageVI) /* 320x240 only */
628 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
630 cam->nmodes = ARRAY_SIZE(custom_mode);
632 case BRIDGE_SPCA504C:
633 cam->cam_mode = vga_mode2;
634 cam->nmodes = ARRAY_SIZE(vga_mode2);
640 /* this function is called at probe and resume time */
641 static int sd_init(struct gspca_dev *gspca_dev)
643 struct sd *sd = (struct sd *) gspca_dev;
645 switch (sd->bridge) {
646 case BRIDGE_SPCA504B:
647 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
648 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
649 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
650 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
651 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
652 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
655 spca504B_PollingDataReady(gspca_dev);
656 spca50x_GetFirmware(gspca_dev);
659 spca50x_GetFirmware(gspca_dev);
660 reg_r(gspca_dev, 0x00, 0x5002, 1);
661 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
662 reg_r(gspca_dev, 0x24, 0, 1);
663 spca504B_PollingDataReady(gspca_dev);
664 reg_w_riv(gspca_dev, 0x34, 0, 0);
665 spca504B_WaitCmdStatus(gspca_dev);
667 case BRIDGE_SPCA504C: /* pccam600 */
668 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
669 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
670 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
671 spca504_wait_status(gspca_dev);
672 if (sd->subtype == LogitechClickSmart420)
673 write_vector(gspca_dev,
674 spca504A_clicksmart420_open_data,
675 ARRAY_SIZE(spca504A_clicksmart420_open_data));
677 write_vector(gspca_dev, spca504_pccam600_open_data,
678 ARRAY_SIZE(spca504_pccam600_open_data));
679 setup_qtable(gspca_dev, qtable_creative_pccam);
682 /* case BRIDGE_SPCA504: */
683 PDEBUG(D_STREAM, "Opening SPCA504");
684 if (sd->subtype == AiptekMiniPenCam13) {
685 spca504_read_info(gspca_dev);
687 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
688 spca504A_acknowledged_command(gspca_dev, 0x24,
690 /* Twice sequential need status 0xff->0x9e->0x9d */
691 spca504A_acknowledged_command(gspca_dev, 0x24,
694 spca504A_acknowledged_command(gspca_dev, 0x24,
696 /******************************/
697 /* spca504a aiptek */
698 spca504A_acknowledged_command(gspca_dev, 0x08,
700 /* reg_write (dev, 0, 0x2000, 0); */
701 /* reg_write (dev, 0, 0x2883, 1); */
702 /* spca504A_acknowledged_command (gspca_dev, 0x08,
704 /* spca504A_acknowledged_command (gspca_dev, 0x24,
706 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
708 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
709 spca504A_acknowledged_command(gspca_dev, 0x01,
713 reg_w_riv(gspca_dev, 0, 0x2000, 0);
714 reg_w_riv(gspca_dev, 0, 0x2883, 1);
715 setup_qtable(gspca_dev, qtable_spca504_default);
718 return gspca_dev->usb_err;
721 static int sd_start(struct gspca_dev *gspca_dev)
723 struct sd *sd = (struct sd *) gspca_dev;
726 /* create the JPEG header */
727 jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
728 gspca_dev->pixfmt.width,
729 0x22); /* JPEG 411 */
730 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
732 if (sd->bridge == BRIDGE_SPCA504B)
733 spca504B_setQtable(gspca_dev);
734 spca504B_SetSizeType(gspca_dev);
735 switch (sd->bridge) {
737 /* case BRIDGE_SPCA504B: */
738 /* case BRIDGE_SPCA533: */
739 /* case BRIDGE_SPCA536: */
740 switch (sd->subtype) {
742 case LogitechClickSmart820:
744 reg_w_riv(gspca_dev, 0xf0, 0, 0);
745 spca504B_WaitCmdStatus(gspca_dev);
746 reg_w_riv(gspca_dev, 0xf0, 4, 0);
747 spca504B_WaitCmdStatus(gspca_dev);
750 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
751 spca504B_WaitCmdStatus(gspca_dev);
752 spca504B_PollingDataReady(gspca_dev);
757 if (sd->subtype == AiptekMiniPenCam13) {
758 spca504_read_info(gspca_dev);
760 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
761 spca504A_acknowledged_command(gspca_dev, 0x24,
763 /* Twice sequential need status 0xff->0x9e->0x9d */
764 spca504A_acknowledged_command(gspca_dev, 0x24,
766 spca504A_acknowledged_command(gspca_dev, 0x24,
769 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
770 spca504_read_info(gspca_dev);
771 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
772 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
774 spca504B_SetSizeType(gspca_dev);
775 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
777 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
779 case BRIDGE_SPCA504C:
780 if (sd->subtype == LogitechClickSmart420) {
781 write_vector(gspca_dev,
782 spca504A_clicksmart420_init_data,
783 ARRAY_SIZE(spca504A_clicksmart420_init_data));
785 write_vector(gspca_dev, spca504_pccam600_init_data,
786 ARRAY_SIZE(spca504_pccam600_init_data));
788 enable = (sd->autogain ? 0x04 : 0x01);
789 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
791 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
794 /* set default exposure compensation and whiteness balance */
795 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
796 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
797 spca504B_SetSizeType(gspca_dev);
800 init_ctl_reg(gspca_dev);
801 return gspca_dev->usb_err;
804 static void sd_stopN(struct gspca_dev *gspca_dev)
806 struct sd *sd = (struct sd *) gspca_dev;
808 switch (sd->bridge) {
810 /* case BRIDGE_SPCA533: */
811 /* case BRIDGE_SPCA536: */
812 /* case BRIDGE_SPCA504B: */
813 reg_w_riv(gspca_dev, 0x31, 0, 0);
814 spca504B_WaitCmdStatus(gspca_dev);
815 spca504B_PollingDataReady(gspca_dev);
818 case BRIDGE_SPCA504C:
819 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
821 if (sd->subtype == AiptekMiniPenCam13) {
822 /* spca504a aiptek */
823 /* spca504A_acknowledged_command(gspca_dev, 0x08,
825 spca504A_acknowledged_command(gspca_dev, 0x24,
826 0x00, 0x00, 0x9d, 1);
827 spca504A_acknowledged_command(gspca_dev, 0x01,
828 0x0f, 0x00, 0xff, 1);
830 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
831 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
837 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
838 u8 *data, /* isoc packet */
839 int len) /* iso packet length */
841 struct sd *sd = (struct sd *) gspca_dev;
843 static u8 ffd9[] = {0xff, 0xd9};
845 /* frames are jpeg 4.1.1 without 0xff escape */
846 switch (sd->bridge) {
848 if (data[0] == 0xff) {
849 if (data[1] != 0x01) { /* drop packet */
850 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
854 data += SPCA533_OFFSET_DATA;
855 len -= SPCA533_OFFSET_DATA;
862 if (data[0] == 0xff) {
864 data += SPCA536_OFFSET_DATA;
865 len -= SPCA536_OFFSET_DATA;
872 /* case BRIDGE_SPCA504: */
873 /* case BRIDGE_SPCA504B: */
875 case 0xfe: /* start of frame */
877 data += SPCA50X_OFFSET_DATA;
878 len -= SPCA50X_OFFSET_DATA;
880 case 0xff: /* drop packet */
881 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
889 case BRIDGE_SPCA504C:
891 case 0xfe: /* start of frame */
893 data += SPCA504_PCCAM600_OFFSET_DATA;
894 len -= SPCA504_PCCAM600_OFFSET_DATA;
896 case 0xff: /* drop packet */
897 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
906 if (sof) { /* start of frame */
907 gspca_frame_add(gspca_dev, LAST_PACKET,
910 /* put the JPEG header in the new frame */
911 gspca_frame_add(gspca_dev, FIRST_PACKET,
912 sd->jpeg_hdr, JPEG_HDR_SZ);
915 /* add 0x00 after 0xff */
918 if (data[i] == 0xff) {
919 gspca_frame_add(gspca_dev, INTER_PACKET,
928 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
931 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
933 struct gspca_dev *gspca_dev =
934 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
935 struct sd *sd = (struct sd *)gspca_dev;
937 gspca_dev->usb_err = 0;
939 if (!gspca_dev->streaming)
943 case V4L2_CID_BRIGHTNESS:
944 setbrightness(gspca_dev, ctrl->val);
946 case V4L2_CID_CONTRAST:
947 setcontrast(gspca_dev, ctrl->val);
949 case V4L2_CID_SATURATION:
950 setcolors(gspca_dev, ctrl->val);
952 case V4L2_CID_AUTOGAIN:
953 sd->autogain = ctrl->val;
956 return gspca_dev->usb_err;
959 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
963 static int sd_init_controls(struct gspca_dev *gspca_dev)
965 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
967 gspca_dev->vdev.ctrl_handler = hdl;
968 v4l2_ctrl_handler_init(hdl, 4);
969 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
970 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
971 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
972 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
973 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
974 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
975 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
976 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
979 pr_err("Could not initialize controls\n");
985 /* sub-driver description */
986 static const struct sd_desc sd_desc = {
990 .init_controls = sd_init_controls,
993 .pkt_scan = sd_pkt_scan,
996 /* -- module initialisation -- */
997 #define BS(bridge, subtype) \
998 .driver_info = (BRIDGE_ ## bridge << 8) \
1000 static const struct usb_device_id device_table[] = {
1001 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1002 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1003 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1004 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1005 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1006 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1007 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1008 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1009 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1010 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1011 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1012 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1013 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1014 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1015 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1016 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1017 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1018 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1019 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1020 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1021 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1022 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1023 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1024 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1025 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1026 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1027 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1028 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1029 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1030 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1031 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1032 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1033 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1034 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1035 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1036 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1037 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1038 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1039 {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1040 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1041 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1042 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1043 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1044 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1045 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1047 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1048 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1049 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1050 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1051 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1052 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1053 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1054 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1055 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1056 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1057 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1058 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1059 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1060 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1063 MODULE_DEVICE_TABLE(usb, device_table);
1065 /* -- device connect -- */
1066 static int sd_probe(struct usb_interface *intf,
1067 const struct usb_device_id *id)
1069 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1073 static struct usb_driver sd_driver = {
1074 .name = MODULE_NAME,
1075 .id_table = device_table,
1077 .disconnect = gspca_disconnect,
1079 .suspend = gspca_suspend,
1080 .resume = gspca_resume,
1081 .reset_resume = gspca_resume,
1085 module_usb_driver(sd_driver);