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 MODULE_NAME "sunplus"
27 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28 MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
29 MODULE_LICENSE("GPL");
31 /* specific webcam descriptor */
33 struct gspca_dev gspca_dev
; /* !! must be the first item */
40 #define QUALITY_MIN 70
41 #define QUALITY_MAX 95
42 #define QUALITY_DEF 85
45 #define BRIDGE_SPCA504 0
46 #define BRIDGE_SPCA504B 1
47 #define BRIDGE_SPCA504C 2
48 #define BRIDGE_SPCA533 3
49 #define BRIDGE_SPCA536 4
51 #define AiptekMiniPenCam13 1
52 #define LogitechClickSmart420 2
53 #define LogitechClickSmart820 3
57 u8 jpeg_hdr
[JPEG_HDR_SZ
];
60 /* V4L2 controls supported by the driver */
61 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
);
62 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
);
63 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
);
64 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
);
65 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
);
66 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
);
67 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
);
68 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
);
70 static const struct ctrl sd_ctrls
[] = {
73 .id
= V4L2_CID_BRIGHTNESS
,
74 .type
= V4L2_CTRL_TYPE_INTEGER
,
79 #define BRIGHTNESS_DEF 0
80 .default_value
= BRIGHTNESS_DEF
,
82 .set
= sd_setbrightness
,
83 .get
= sd_getbrightness
,
87 .id
= V4L2_CID_CONTRAST
,
88 .type
= V4L2_CTRL_TYPE_INTEGER
,
93 #define CONTRAST_DEF 0x20
94 .default_value
= CONTRAST_DEF
,
96 .set
= sd_setcontrast
,
97 .get
= sd_getcontrast
,
101 .id
= V4L2_CID_SATURATION
,
102 .type
= V4L2_CTRL_TYPE_INTEGER
,
107 #define COLOR_DEF 0x1a
108 .default_value
= COLOR_DEF
,
115 .id
= V4L2_CID_AUTOGAIN
,
116 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
121 #define AUTOGAIN_DEF 1
122 .default_value
= AUTOGAIN_DEF
,
124 .set
= sd_setautogain
,
125 .get
= sd_getautogain
,
129 static const struct v4l2_pix_format vga_mode
[] = {
130 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
132 .sizeimage
= 320 * 240 * 3 / 8 + 590,
133 .colorspace
= V4L2_COLORSPACE_JPEG
,
135 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
137 .sizeimage
= 640 * 480 * 3 / 8 + 590,
138 .colorspace
= V4L2_COLORSPACE_JPEG
,
142 static const struct v4l2_pix_format custom_mode
[] = {
143 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
145 .sizeimage
= 320 * 240 * 3 / 8 + 590,
146 .colorspace
= V4L2_COLORSPACE_JPEG
,
148 {464, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
150 .sizeimage
= 464 * 480 * 3 / 8 + 590,
151 .colorspace
= V4L2_COLORSPACE_JPEG
,
155 static const struct v4l2_pix_format vga_mode2
[] = {
156 {176, 144, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
158 .sizeimage
= 176 * 144 * 3 / 8 + 590,
159 .colorspace
= V4L2_COLORSPACE_JPEG
,
161 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
163 .sizeimage
= 320 * 240 * 3 / 8 + 590,
164 .colorspace
= V4L2_COLORSPACE_JPEG
,
166 {352, 288, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
168 .sizeimage
= 352 * 288 * 3 / 8 + 590,
169 .colorspace
= V4L2_COLORSPACE_JPEG
,
171 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
173 .sizeimage
= 640 * 480 * 3 / 8 + 590,
174 .colorspace
= V4L2_COLORSPACE_JPEG
,
178 #define SPCA50X_OFFSET_DATA 10
179 #define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
180 #define SPCA504_PCCAM600_OFFSET_COMPRESS 4
181 #define SPCA504_PCCAM600_OFFSET_MODE 5
182 #define SPCA504_PCCAM600_OFFSET_DATA 14
183 /* Frame packet header offsets for the spca533 */
184 #define SPCA533_OFFSET_DATA 16
185 #define SPCA533_OFFSET_FRAMSEQ 15
186 /* Frame packet header offsets for the spca536 */
187 #define SPCA536_OFFSET_DATA 4
188 #define SPCA536_OFFSET_FRAMSEQ 1
196 /* Initialisation data for the Creative PC-CAM 600 */
197 static const struct cmd spca504_pccam600_init_data
[] = {
198 /* {0xa0, 0x0000, 0x0503}, * capture mode */
199 {0x00, 0x0000, 0x2000},
200 {0x00, 0x0013, 0x2301},
201 {0x00, 0x0003, 0x2000},
202 {0x00, 0x0001, 0x21ac},
203 {0x00, 0x0001, 0x21a6},
204 {0x00, 0x0000, 0x21a7}, /* brightness */
205 {0x00, 0x0020, 0x21a8}, /* contrast */
206 {0x00, 0x0001, 0x21ac}, /* sat/hue */
207 {0x00, 0x0000, 0x21ad}, /* hue */
208 {0x00, 0x001a, 0x21ae}, /* saturation */
209 {0x00, 0x0002, 0x21a3}, /* gamma */
210 {0x30, 0x0154, 0x0008},
211 {0x30, 0x0004, 0x0006},
212 {0x30, 0x0258, 0x0009},
213 {0x30, 0x0004, 0x0000},
214 {0x30, 0x0093, 0x0004},
215 {0x30, 0x0066, 0x0005},
216 {0x00, 0x0000, 0x2000},
217 {0x00, 0x0013, 0x2301},
218 {0x00, 0x0003, 0x2000},
219 {0x00, 0x0013, 0x2301},
220 {0x00, 0x0003, 0x2000},
223 /* Creative PC-CAM 600 specific open data, sent before using the
224 * generic initialisation data from spca504_open_data.
226 static const struct cmd spca504_pccam600_open_data
[] = {
227 {0x00, 0x0001, 0x2501},
228 {0x20, 0x0500, 0x0001}, /* snapshot mode */
229 {0x00, 0x0003, 0x2880},
230 {0x00, 0x0001, 0x2881},
233 /* Initialisation data for the logitech clicksmart 420 */
234 static const struct cmd spca504A_clicksmart420_init_data
[] = {
235 /* {0xa0, 0x0000, 0x0503}, * capture mode */
236 {0x00, 0x0000, 0x2000},
237 {0x00, 0x0013, 0x2301},
238 {0x00, 0x0003, 0x2000},
239 {0x00, 0x0001, 0x21ac},
240 {0x00, 0x0001, 0x21a6},
241 {0x00, 0x0000, 0x21a7}, /* brightness */
242 {0x00, 0x0020, 0x21a8}, /* contrast */
243 {0x00, 0x0001, 0x21ac}, /* sat/hue */
244 {0x00, 0x0000, 0x21ad}, /* hue */
245 {0x00, 0x001a, 0x21ae}, /* saturation */
246 {0x00, 0x0002, 0x21a3}, /* gamma */
247 {0x30, 0x0004, 0x000a},
248 {0xb0, 0x0001, 0x0000},
251 {0xa1, 0x0080, 0x0001},
252 {0x30, 0x0049, 0x0000},
253 {0x30, 0x0060, 0x0005},
254 {0x0c, 0x0004, 0x0000},
255 {0x00, 0x0000, 0x0000},
256 {0x00, 0x0000, 0x2000},
257 {0x00, 0x0013, 0x2301},
258 {0x00, 0x0003, 0x2000},
259 {0x00, 0x0000, 0x2000},
263 /* clicksmart 420 open data ? */
264 static const struct cmd spca504A_clicksmart420_open_data
[] = {
265 {0x00, 0x0001, 0x2501},
266 {0x20, 0x0502, 0x0000},
267 {0x06, 0x0000, 0x0000},
268 {0x00, 0x0004, 0x2880},
269 {0x00, 0x0001, 0x2881},
271 {0xa0, 0x0000, 0x0503},
274 static const u8 qtable_creative_pccam
[2][64] = {
275 { /* Q-table Y-components */
276 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
277 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
278 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
279 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
280 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
281 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
282 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
283 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
284 { /* Q-table C-components */
285 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
286 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
287 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
288 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
289 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
290 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
291 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
292 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
295 /* FIXME: This Q-table is identical to the Creative PC-CAM one,
296 * except for one byte. Possibly a typo?
299 static const u8 qtable_spca504_default
[2][64] = {
300 { /* Q-table Y-components */
301 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
302 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
303 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
304 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
305 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
306 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
307 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
308 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
310 { /* Q-table C-components */
311 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
312 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
313 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
314 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
315 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
316 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
317 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
318 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
321 /* read <len> bytes to gspca_dev->usb_buf */
322 static void reg_r(struct gspca_dev
*gspca_dev
,
330 if (len
> USB_BUF_SZ
) {
331 err("reg_r: buffer overflow");
335 if (gspca_dev
->usb_err
< 0)
337 ret
= usb_control_msg(gspca_dev
->dev
,
338 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
340 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
343 len
? gspca_dev
->usb_buf
: NULL
, len
,
346 err("reg_r err %d", ret
);
347 gspca_dev
->usb_err
= ret
;
352 static void reg_w_1(struct gspca_dev
*gspca_dev
,
360 if (gspca_dev
->usb_err
< 0)
362 gspca_dev
->usb_buf
[0] = byte
;
363 ret
= usb_control_msg(gspca_dev
->dev
,
364 usb_sndctrlpipe(gspca_dev
->dev
, 0),
366 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
368 gspca_dev
->usb_buf
, 1,
371 err("reg_w_1 err %d", ret
);
372 gspca_dev
->usb_err
= ret
;
376 /* write req / index / value */
377 static void reg_w_riv(struct gspca_dev
*gspca_dev
,
378 u8 req
, u16 index
, u16 value
)
380 struct usb_device
*dev
= gspca_dev
->dev
;
383 if (gspca_dev
->usb_err
< 0)
385 ret
= usb_control_msg(dev
,
386 usb_sndctrlpipe(dev
, 0),
388 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
389 value
, index
, NULL
, 0, 500);
391 err("reg_w_riv err %d", ret
);
392 gspca_dev
->usb_err
= ret
;
395 PDEBUG(D_USBO
, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
400 static u8
reg_r_1(struct gspca_dev
*gspca_dev
,
401 u16 value
) /* wValue */
405 if (gspca_dev
->usb_err
< 0)
407 ret
= usb_control_msg(gspca_dev
->dev
,
408 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
410 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
413 gspca_dev
->usb_buf
, 1,
416 err("reg_r_1 err %d", ret
);
417 gspca_dev
->usb_err
= ret
;
420 return gspca_dev
->usb_buf
[0];
423 /* read 1 or 2 bytes */
424 static u16
reg_r_12(struct gspca_dev
*gspca_dev
,
425 u8 req
, /* bRequest */
426 u16 index
, /* wIndex */
427 u16 length
) /* wLength (1 or 2 only) */
431 if (gspca_dev
->usb_err
< 0)
433 gspca_dev
->usb_buf
[1] = 0;
434 ret
= usb_control_msg(gspca_dev
->dev
,
435 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
437 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
440 gspca_dev
->usb_buf
, length
,
443 err("reg_r_12 err %d", ret
);
444 gspca_dev
->usb_err
= ret
;
447 return (gspca_dev
->usb_buf
[1] << 8) + gspca_dev
->usb_buf
[0];
450 static void write_vector(struct gspca_dev
*gspca_dev
,
451 const struct cmd
*data
, int ncmds
)
453 while (--ncmds
>= 0) {
454 reg_w_riv(gspca_dev
, data
->req
, data
->idx
, data
->val
);
459 static void setup_qtable(struct gspca_dev
*gspca_dev
,
460 const u8 qtable
[2][64])
464 /* loop over y components */
465 for (i
= 0; i
< 64; i
++)
466 reg_w_riv(gspca_dev
, 0x00, 0x2800 + i
, qtable
[0][i
]);
468 /* loop over c components */
469 for (i
= 0; i
< 64; i
++)
470 reg_w_riv(gspca_dev
, 0x00, 0x2840 + i
, qtable
[1][i
]);
473 static void spca504_acknowledged_command(struct gspca_dev
*gspca_dev
,
474 u8 req
, u16 idx
, u16 val
)
478 reg_w_riv(gspca_dev
, req
, idx
, val
);
479 notdone
= reg_r_12(gspca_dev
, 0x01, 0x0001, 1);
480 reg_w_riv(gspca_dev
, req
, idx
, val
);
482 PDEBUG(D_FRAM
, "before wait 0x%04x", notdone
);
485 notdone
= reg_r_12(gspca_dev
, 0x01, 0x0001, 1);
486 PDEBUG(D_FRAM
, "after wait 0x%04x", notdone
);
489 static void spca504_read_info(struct gspca_dev
*gspca_dev
)
494 for (i
= 0; i
< 6; i
++)
495 info
[i
] = reg_r_1(gspca_dev
, i
);
497 "Read info: %d %d %d %d %d %d."
498 " Should be 1,0,2,2,0,0",
499 info
[0], info
[1], info
[2],
500 info
[3], info
[4], info
[5]);
503 static void spca504A_acknowledged_command(struct gspca_dev
*gspca_dev
,
505 u16 idx
, u16 val
, u16 endcode
, u8 count
)
509 reg_w_riv(gspca_dev
, req
, idx
, val
);
510 status
= reg_r_12(gspca_dev
, 0x01, 0x0001, 1);
511 if (gspca_dev
->usb_err
< 0)
513 PDEBUG(D_FRAM
, "Status 0x%04x Need 0x%04x", status
, endcode
);
517 while (--count
> 0) {
519 /* gsmart mini2 write a each wait setting 1 ms is enough */
520 /* reg_w_riv(gspca_dev, req, idx, val); */
521 status
= reg_r_12(gspca_dev
, 0x01, 0x0001, 1);
522 if (status
== endcode
) {
523 PDEBUG(D_FRAM
, "status 0x%04x after wait %d",
524 status
, 200 - count
);
530 static void spca504B_PollingDataReady(struct gspca_dev
*gspca_dev
)
534 while (--count
> 0) {
535 reg_r(gspca_dev
, 0x21, 0, 1);
536 if ((gspca_dev
->usb_buf
[0] & 0x01) == 0)
542 static void spca504B_WaitCmdStatus(struct gspca_dev
*gspca_dev
)
546 while (--count
> 0) {
547 reg_r(gspca_dev
, 0x21, 1, 1);
548 if (gspca_dev
->usb_buf
[0] != 0) {
549 reg_w_1(gspca_dev
, 0x21, 0, 1, 0);
550 reg_r(gspca_dev
, 0x21, 1, 1);
551 spca504B_PollingDataReady(gspca_dev
);
558 static void spca50x_GetFirmware(struct gspca_dev
*gspca_dev
)
562 data
= gspca_dev
->usb_buf
;
563 reg_r(gspca_dev
, 0x20, 0, 5);
564 PDEBUG(D_STREAM
, "FirmWare : %d %d %d %d %d ",
565 data
[0], data
[1], data
[2], data
[3], data
[4]);
566 reg_r(gspca_dev
, 0x23, 0, 64);
567 reg_r(gspca_dev
, 0x23, 1, 64);
570 static void spca504B_SetSizeType(struct gspca_dev
*gspca_dev
)
572 struct sd
*sd
= (struct sd
*) gspca_dev
;
575 Size
= gspca_dev
->cam
.cam_mode
[gspca_dev
->curr_mode
].priv
;
576 switch (sd
->bridge
) {
578 reg_w_riv(gspca_dev
, 0x31, 0, 0);
579 spca504B_WaitCmdStatus(gspca_dev
);
580 spca504B_PollingDataReady(gspca_dev
);
581 spca50x_GetFirmware(gspca_dev
);
582 reg_w_1(gspca_dev
, 0x24, 0, 8, 2); /* type */
583 reg_r(gspca_dev
, 0x24, 8, 1);
585 reg_w_1(gspca_dev
, 0x25, 0, 4, Size
);
586 reg_r(gspca_dev
, 0x25, 4, 1); /* size */
587 spca504B_PollingDataReady(gspca_dev
);
589 /* Init the cam width height with some values get on init ? */
590 reg_w_riv(gspca_dev
, 0x31, 0x0004, 0x00);
591 spca504B_WaitCmdStatus(gspca_dev
);
592 spca504B_PollingDataReady(gspca_dev
);
595 /* case BRIDGE_SPCA504B: */
596 /* case BRIDGE_SPCA536: */
597 reg_w_1(gspca_dev
, 0x25, 0, 4, Size
);
598 reg_r(gspca_dev
, 0x25, 4, 1); /* size */
599 reg_w_1(gspca_dev
, 0x27, 0, 0, 6);
600 reg_r(gspca_dev
, 0x27, 0, 1); /* type */
601 spca504B_PollingDataReady(gspca_dev
);
605 if (sd
->subtype
== AiptekMiniPenCam13
) {
606 /* spca504a aiptek */
607 spca504A_acknowledged_command(gspca_dev
,
609 0x80 | (Size
& 0x0f), 1);
610 spca504A_acknowledged_command(gspca_dev
,
613 spca504_acknowledged_command(gspca_dev
, 0x08, Size
, 0);
616 case BRIDGE_SPCA504C
:
618 reg_w_riv(gspca_dev
, 0xa0, (0x0500 | (Size
& 0x0f)), 0x00);
619 reg_w_riv(gspca_dev
, 0x20, 0x01, 0x0500 | (Size
& 0x0f));
624 static void spca504_wait_status(struct gspca_dev
*gspca_dev
)
630 /* With this we get the status, when return 0 it's all ok */
631 if (reg_r_12(gspca_dev
, 0x06, 0x00, 1) == 0)
637 static void spca504B_setQtable(struct gspca_dev
*gspca_dev
)
639 reg_w_1(gspca_dev
, 0x26, 0, 0, 3);
640 reg_r(gspca_dev
, 0x26, 0, 1);
641 spca504B_PollingDataReady(gspca_dev
);
644 static void setbrightness(struct gspca_dev
*gspca_dev
)
646 struct sd
*sd
= (struct sd
*) gspca_dev
;
649 reg
= sd
->bridge
== BRIDGE_SPCA536
? 0x20f0 : 0x21a7;
650 reg_w_riv(gspca_dev
, 0x00, reg
, sd
->brightness
);
653 static void setcontrast(struct gspca_dev
*gspca_dev
)
655 struct sd
*sd
= (struct sd
*) gspca_dev
;
658 reg
= sd
->bridge
== BRIDGE_SPCA536
? 0x20f1 : 0x21a8;
659 reg_w_riv(gspca_dev
, 0x00, reg
, sd
->contrast
);
662 static void setcolors(struct gspca_dev
*gspca_dev
)
664 struct sd
*sd
= (struct sd
*) gspca_dev
;
667 reg
= sd
->bridge
== BRIDGE_SPCA536
? 0x20f6 : 0x21ae;
668 reg_w_riv(gspca_dev
, 0x00, reg
, sd
->colors
);
671 static void init_ctl_reg(struct gspca_dev
*gspca_dev
)
673 struct sd
*sd
= (struct sd
*) gspca_dev
;
676 setbrightness(gspca_dev
);
677 setcontrast(gspca_dev
);
678 setcolors(gspca_dev
);
680 switch (sd
->bridge
) {
682 case BRIDGE_SPCA504C
:
686 /* case BRIDGE_SPCA533: */
687 /* case BRIDGE_SPCA504B: */
688 reg_w_riv(gspca_dev
, 0, 0x21ad, 0x00); /* hue */
689 reg_w_riv(gspca_dev
, 0, 0x21ac, 0x01); /* sat/hue */
690 reg_w_riv(gspca_dev
, 0, 0x21a3, 0x00); /* gamma */
693 reg_w_riv(gspca_dev
, 0, 0x20f5, 0x40);
694 reg_w_riv(gspca_dev
, 0, 0x20f4, 0x01);
695 reg_w_riv(gspca_dev
, 0, 0x2089, 0x00);
699 spca504B_PollingDataReady(gspca_dev
);
702 /* this function is called at probe time */
703 static int sd_config(struct gspca_dev
*gspca_dev
,
704 const struct usb_device_id
*id
)
706 struct sd
*sd
= (struct sd
*) gspca_dev
;
709 cam
= &gspca_dev
->cam
;
711 sd
->bridge
= id
->driver_info
>> 8;
712 sd
->subtype
= id
->driver_info
;
714 if (sd
->subtype
== AiptekMiniPenCam13
) {
716 /* try to get the firmware as some cam answer 2.0.1.2.2
717 * and should be a spca504b then overwrite that setting */
718 reg_r(gspca_dev
, 0x20, 0, 1);
719 switch (gspca_dev
->usb_buf
[0]) {
721 break; /* (right bridge/subtype) */
723 sd
->bridge
= BRIDGE_SPCA504B
;
731 switch (sd
->bridge
) {
733 /* case BRIDGE_SPCA504B: */
734 /* case BRIDGE_SPCA504: */
735 /* case BRIDGE_SPCA536: */
736 cam
->cam_mode
= vga_mode
;
737 cam
->nmodes
= ARRAY_SIZE(vga_mode
);
740 cam
->cam_mode
= custom_mode
;
741 if (sd
->subtype
== MegaImageVI
) /* 320x240 only */
742 cam
->nmodes
= ARRAY_SIZE(custom_mode
) - 1;
744 cam
->nmodes
= ARRAY_SIZE(custom_mode
);
746 case BRIDGE_SPCA504C
:
747 cam
->cam_mode
= vga_mode2
;
748 cam
->nmodes
= ARRAY_SIZE(vga_mode2
);
751 sd
->brightness
= BRIGHTNESS_DEF
;
752 sd
->contrast
= CONTRAST_DEF
;
753 sd
->colors
= COLOR_DEF
;
754 sd
->autogain
= AUTOGAIN_DEF
;
755 sd
->quality
= QUALITY_DEF
;
759 /* this function is called at probe and resume time */
760 static int sd_init(struct gspca_dev
*gspca_dev
)
762 struct sd
*sd
= (struct sd
*) gspca_dev
;
764 switch (sd
->bridge
) {
765 case BRIDGE_SPCA504B
:
766 reg_w_riv(gspca_dev
, 0x1d, 0x00, 0);
767 reg_w_riv(gspca_dev
, 0x00, 0x2306, 0x01);
768 reg_w_riv(gspca_dev
, 0x00, 0x0d04, 0x00);
769 reg_w_riv(gspca_dev
, 0x00, 0x2000, 0x00);
770 reg_w_riv(gspca_dev
, 0x00, 0x2301, 0x13);
771 reg_w_riv(gspca_dev
, 0x00, 0x2306, 0x00);
774 spca504B_PollingDataReady(gspca_dev
);
775 spca50x_GetFirmware(gspca_dev
);
778 spca50x_GetFirmware(gspca_dev
);
779 reg_r(gspca_dev
, 0x00, 0x5002, 1);
780 reg_w_1(gspca_dev
, 0x24, 0, 0, 0);
781 reg_r(gspca_dev
, 0x24, 0, 1);
782 spca504B_PollingDataReady(gspca_dev
);
783 reg_w_riv(gspca_dev
, 0x34, 0, 0);
784 spca504B_WaitCmdStatus(gspca_dev
);
786 case BRIDGE_SPCA504C
: /* pccam600 */
787 PDEBUG(D_STREAM
, "Opening SPCA504 (PC-CAM 600)");
788 reg_w_riv(gspca_dev
, 0xe0, 0x0000, 0x0000);
789 reg_w_riv(gspca_dev
, 0xe0, 0x0000, 0x0001); /* reset */
790 spca504_wait_status(gspca_dev
);
791 if (sd
->subtype
== LogitechClickSmart420
)
792 write_vector(gspca_dev
,
793 spca504A_clicksmart420_open_data
,
794 ARRAY_SIZE(spca504A_clicksmart420_open_data
));
796 write_vector(gspca_dev
, spca504_pccam600_open_data
,
797 ARRAY_SIZE(spca504_pccam600_open_data
));
798 setup_qtable(gspca_dev
, qtable_creative_pccam
);
801 /* case BRIDGE_SPCA504: */
802 PDEBUG(D_STREAM
, "Opening SPCA504");
803 if (sd
->subtype
== AiptekMiniPenCam13
) {
804 spca504_read_info(gspca_dev
);
806 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
807 spca504A_acknowledged_command(gspca_dev
, 0x24,
809 /* Twice sequential need status 0xff->0x9e->0x9d */
810 spca504A_acknowledged_command(gspca_dev
, 0x24,
813 spca504A_acknowledged_command(gspca_dev
, 0x24,
815 /******************************/
816 /* spca504a aiptek */
817 spca504A_acknowledged_command(gspca_dev
, 0x08,
819 /* reg_write (dev, 0, 0x2000, 0); */
820 /* reg_write (dev, 0, 0x2883, 1); */
821 /* spca504A_acknowledged_command (gspca_dev, 0x08,
823 /* spca504A_acknowledged_command (gspca_dev, 0x24,
825 reg_w_riv(gspca_dev
, 0x00, 0x270c, 0x05);
827 reg_w_riv(gspca_dev
, 0x00, 0x2310, 0x05);
828 spca504A_acknowledged_command(gspca_dev
, 0x01,
832 reg_w_riv(gspca_dev
, 0, 0x2000, 0);
833 reg_w_riv(gspca_dev
, 0, 0x2883, 1);
834 setup_qtable(gspca_dev
, qtable_spca504_default
);
837 return gspca_dev
->usb_err
;
840 static int sd_start(struct gspca_dev
*gspca_dev
)
842 struct sd
*sd
= (struct sd
*) gspca_dev
;
845 /* create the JPEG header */
846 jpeg_define(sd
->jpeg_hdr
, gspca_dev
->height
, gspca_dev
->width
,
847 0x22); /* JPEG 411 */
848 jpeg_set_qual(sd
->jpeg_hdr
, sd
->quality
);
850 if (sd
->bridge
== BRIDGE_SPCA504B
)
851 spca504B_setQtable(gspca_dev
);
852 spca504B_SetSizeType(gspca_dev
);
853 switch (sd
->bridge
) {
855 /* case BRIDGE_SPCA504B: */
856 /* case BRIDGE_SPCA533: */
857 /* case BRIDGE_SPCA536: */
858 switch (sd
->subtype
) {
860 case LogitechClickSmart820
:
862 reg_w_riv(gspca_dev
, 0xf0, 0, 0);
863 spca504B_WaitCmdStatus(gspca_dev
);
864 reg_r(gspca_dev
, 0xf0, 4, 0);
865 spca504B_WaitCmdStatus(gspca_dev
);
868 reg_w_riv(gspca_dev
, 0x31, 0x0004, 0x00);
869 spca504B_WaitCmdStatus(gspca_dev
);
870 spca504B_PollingDataReady(gspca_dev
);
875 if (sd
->subtype
== AiptekMiniPenCam13
) {
876 spca504_read_info(gspca_dev
);
878 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
879 spca504A_acknowledged_command(gspca_dev
, 0x24,
881 /* Twice sequential need status 0xff->0x9e->0x9d */
882 spca504A_acknowledged_command(gspca_dev
, 0x24,
884 spca504A_acknowledged_command(gspca_dev
, 0x24,
887 spca504_acknowledged_command(gspca_dev
, 0x24, 8, 3);
888 spca504_read_info(gspca_dev
);
889 spca504_acknowledged_command(gspca_dev
, 0x24, 8, 3);
890 spca504_acknowledged_command(gspca_dev
, 0x24, 0, 0);
892 spca504B_SetSizeType(gspca_dev
);
893 reg_w_riv(gspca_dev
, 0x00, 0x270c, 0x05);
895 reg_w_riv(gspca_dev
, 0x00, 0x2310, 0x05);
897 case BRIDGE_SPCA504C
:
898 if (sd
->subtype
== LogitechClickSmart420
) {
899 write_vector(gspca_dev
,
900 spca504A_clicksmart420_init_data
,
901 ARRAY_SIZE(spca504A_clicksmart420_init_data
));
903 write_vector(gspca_dev
, spca504_pccam600_init_data
,
904 ARRAY_SIZE(spca504_pccam600_init_data
));
906 enable
= (sd
->autogain
? 0x04 : 0x01);
907 reg_w_riv(gspca_dev
, 0x0c, 0x0000, enable
);
909 reg_w_riv(gspca_dev
, 0xb0, 0x0000, enable
);
912 /* set default exposure compensation and whiteness balance */
913 reg_w_riv(gspca_dev
, 0x30, 0x0001, 800); /* ~ 20 fps */
914 reg_w_riv(gspca_dev
, 0x30, 0x0002, 1600);
915 spca504B_SetSizeType(gspca_dev
);
918 init_ctl_reg(gspca_dev
);
919 return gspca_dev
->usb_err
;
922 static void sd_stopN(struct gspca_dev
*gspca_dev
)
924 struct sd
*sd
= (struct sd
*) gspca_dev
;
926 switch (sd
->bridge
) {
928 /* case BRIDGE_SPCA533: */
929 /* case BRIDGE_SPCA536: */
930 /* case BRIDGE_SPCA504B: */
931 reg_w_riv(gspca_dev
, 0x31, 0, 0);
932 spca504B_WaitCmdStatus(gspca_dev
);
933 spca504B_PollingDataReady(gspca_dev
);
936 case BRIDGE_SPCA504C
:
937 reg_w_riv(gspca_dev
, 0x00, 0x2000, 0x0000);
939 if (sd
->subtype
== AiptekMiniPenCam13
) {
940 /* spca504a aiptek */
941 /* spca504A_acknowledged_command(gspca_dev, 0x08,
943 spca504A_acknowledged_command(gspca_dev
, 0x24,
944 0x00, 0x00, 0x9d, 1);
945 spca504A_acknowledged_command(gspca_dev
, 0x01,
946 0x0f, 0x00, 0xff, 1);
948 spca504_acknowledged_command(gspca_dev
, 0x24, 0, 0);
949 reg_w_riv(gspca_dev
, 0x01, 0x000f, 0x0000);
955 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
956 u8
*data
, /* isoc packet */
957 int len
) /* iso packet length */
959 struct sd
*sd
= (struct sd
*) gspca_dev
;
961 static u8 ffd9
[] = {0xff, 0xd9};
963 /* frames are jpeg 4.1.1 without 0xff escape */
964 switch (sd
->bridge
) {
966 if (data
[0] == 0xff) {
967 if (data
[1] != 0x01) { /* drop packet */
968 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
972 data
+= SPCA533_OFFSET_DATA
;
973 len
-= SPCA533_OFFSET_DATA
;
980 if (data
[0] == 0xff) {
982 data
+= SPCA536_OFFSET_DATA
;
983 len
-= SPCA536_OFFSET_DATA
;
990 /* case BRIDGE_SPCA504: */
991 /* case BRIDGE_SPCA504B: */
993 case 0xfe: /* start of frame */
995 data
+= SPCA50X_OFFSET_DATA
;
996 len
-= SPCA50X_OFFSET_DATA
;
998 case 0xff: /* drop packet */
999 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
1007 case BRIDGE_SPCA504C
:
1009 case 0xfe: /* start of frame */
1011 data
+= SPCA504_PCCAM600_OFFSET_DATA
;
1012 len
-= SPCA504_PCCAM600_OFFSET_DATA
;
1014 case 0xff: /* drop packet */
1015 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
1024 if (sof
) { /* start of frame */
1025 gspca_frame_add(gspca_dev
, LAST_PACKET
,
1028 /* put the JPEG header in the new frame */
1029 gspca_frame_add(gspca_dev
, FIRST_PACKET
,
1030 sd
->jpeg_hdr
, JPEG_HDR_SZ
);
1033 /* add 0x00 after 0xff */
1036 if (data
[i
] == 0xff) {
1037 gspca_frame_add(gspca_dev
, INTER_PACKET
,
1046 gspca_frame_add(gspca_dev
, INTER_PACKET
, data
, len
);
1049 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
)
1051 struct sd
*sd
= (struct sd
*) gspca_dev
;
1053 sd
->brightness
= val
;
1054 if (gspca_dev
->streaming
)
1055 setbrightness(gspca_dev
);
1056 return gspca_dev
->usb_err
;
1059 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1061 struct sd
*sd
= (struct sd
*) gspca_dev
;
1063 *val
= sd
->brightness
;
1067 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
)
1069 struct sd
*sd
= (struct sd
*) gspca_dev
;
1072 if (gspca_dev
->streaming
)
1073 setcontrast(gspca_dev
);
1074 return gspca_dev
->usb_err
;
1077 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
)
1079 struct sd
*sd
= (struct sd
*) gspca_dev
;
1081 *val
= sd
->contrast
;
1085 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
)
1087 struct sd
*sd
= (struct sd
*) gspca_dev
;
1090 if (gspca_dev
->streaming
)
1091 setcolors(gspca_dev
);
1092 return gspca_dev
->usb_err
;
1095 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
)
1097 struct sd
*sd
= (struct sd
*) gspca_dev
;
1103 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
)
1105 struct sd
*sd
= (struct sd
*) gspca_dev
;
1111 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1113 struct sd
*sd
= (struct sd
*) gspca_dev
;
1115 *val
= sd
->autogain
;
1119 static int sd_set_jcomp(struct gspca_dev
*gspca_dev
,
1120 struct v4l2_jpegcompression
*jcomp
)
1122 struct sd
*sd
= (struct sd
*) gspca_dev
;
1124 if (jcomp
->quality
< QUALITY_MIN
)
1125 sd
->quality
= QUALITY_MIN
;
1126 else if (jcomp
->quality
> QUALITY_MAX
)
1127 sd
->quality
= QUALITY_MAX
;
1129 sd
->quality
= jcomp
->quality
;
1130 if (gspca_dev
->streaming
)
1131 jpeg_set_qual(sd
->jpeg_hdr
, sd
->quality
);
1132 return gspca_dev
->usb_err
;
1135 static int sd_get_jcomp(struct gspca_dev
*gspca_dev
,
1136 struct v4l2_jpegcompression
*jcomp
)
1138 struct sd
*sd
= (struct sd
*) gspca_dev
;
1140 memset(jcomp
, 0, sizeof *jcomp
);
1141 jcomp
->quality
= sd
->quality
;
1142 jcomp
->jpeg_markers
= V4L2_JPEG_MARKER_DHT
1143 | V4L2_JPEG_MARKER_DQT
;
1147 /* sub-driver description */
1148 static const struct sd_desc sd_desc
= {
1149 .name
= MODULE_NAME
,
1151 .nctrls
= ARRAY_SIZE(sd_ctrls
),
1152 .config
= sd_config
,
1156 .pkt_scan
= sd_pkt_scan
,
1157 .get_jcomp
= sd_get_jcomp
,
1158 .set_jcomp
= sd_set_jcomp
,
1161 /* -- module initialisation -- */
1162 #define BS(bridge, subtype) \
1163 .driver_info = (BRIDGE_ ## bridge << 8) \
1165 static const struct usb_device_id device_table
[] = {
1166 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C
, 0)},
1167 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C
, 0)},
1168 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C
, 0)},
1169 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B
, 0)},
1170 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533
, 0)},
1171 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533
, LogitechClickSmart820
)},
1172 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C
, LogitechClickSmart420
)},
1173 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B
, 0)},
1174 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B
, 0)},
1175 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533
, 0)},
1176 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533
, 0)},
1177 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B
, 0)},
1178 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B
, 0)},
1179 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504
, AiptekMiniPenCam13
)},
1180 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B
, 0)},
1181 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533
, 0)},
1182 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536
, 0)},
1183 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B
, 0)},
1184 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533
, MegapixV4
)},
1185 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533
, MegapixV4
)},
1186 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533
, MegaImageVI
)},
1187 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533
, 0)},
1188 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B
, 0)},
1189 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B
, 0)},
1190 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536
, 0)},
1191 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533
, 0)},
1192 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533
, 0)},
1193 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536
, 0)},
1194 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504
, 0)},
1195 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533
, 0)},
1196 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533
, 0)},
1197 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504
, 0)},
1198 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533
, 0)},
1199 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533
, 0)},
1200 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533
, 0)},
1201 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533
, 0)},
1202 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B
, 0)},
1203 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533
, 0)},
1204 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533
, 0)},
1205 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533
, 0)},
1206 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533
, 0)},
1207 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533
, 0)},
1208 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536
, 0)},
1209 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536
, 0)},
1210 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533
, 0)},
1211 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533
, 0)},
1212 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B
, 0)},
1213 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533
, 0)},
1214 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B
, 0)},
1215 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B
, 0)},
1216 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533
, 0)},
1217 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533
, 0)},
1218 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536
, 0)},
1219 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533
, 0)},
1220 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536
, 0)},
1221 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536
, 0)},
1222 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536
, 0)},
1223 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536
, 0)},
1224 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536
, 0)},
1227 MODULE_DEVICE_TABLE(usb
, device_table
);
1229 /* -- device connect -- */
1230 static int sd_probe(struct usb_interface
*intf
,
1231 const struct usb_device_id
*id
)
1233 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1237 static struct usb_driver sd_driver
= {
1238 .name
= MODULE_NAME
,
1239 .id_table
= device_table
,
1241 .disconnect
= gspca_disconnect
,
1243 .suspend
= gspca_suspend
,
1244 .resume
= gspca_resume
,
1248 /* -- module insert / remove -- */
1249 static int __init
sd_mod_init(void)
1251 return usb_register(&sd_driver
);
1253 static void __exit
sd_mod_exit(void)
1255 usb_deregister(&sd_driver
);
1258 module_init(sd_mod_init
);
1259 module_exit(sd_mod_exit
);