aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/sunplus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/sunplus.c')
-rw-r--r--drivers/media/video/gspca/sunplus.c1223
1 files changed, 1223 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
new file mode 100644
index 00000000000..6ec23290218
--- /dev/null
+++ b/drivers/media/video/gspca/sunplus.c
@@ -0,0 +1,1223 @@
1/*
2 * Sunplus spca504(abc) spca533 spca536 library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
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
10 * any later version.
11 *
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.
16 *
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
20 */
21
22#define MODULE_NAME "sunplus"
23
24#include "gspca.h"
25#include "jpeg.h"
26
27MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
35 s8 brightness;
36 u8 contrast;
37 u8 colors;
38 u8 autogain;
39 u8 quality;
40#define QUALITY_MIN 70
41#define QUALITY_MAX 95
42#define QUALITY_DEF 85
43
44 u8 bridge;
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
50 u8 subtype;
51#define AiptekMiniPenCam13 1
52#define LogitechClickSmart420 2
53#define LogitechClickSmart820 3
54#define MegapixV4 4
55#define MegaImageVI 5
56
57 u8 jpeg_hdr[JPEG_HDR_SZ];
58};
59
60/* V4L2 controls supported by the driver */
61static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
63static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
69
70static const struct ctrl sd_ctrls[] = {
71 {
72 {
73 .id = V4L2_CID_BRIGHTNESS,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Brightness",
76 .minimum = -128,
77 .maximum = 127,
78 .step = 1,
79#define BRIGHTNESS_DEF 0
80 .default_value = BRIGHTNESS_DEF,
81 },
82 .set = sd_setbrightness,
83 .get = sd_getbrightness,
84 },
85 {
86 {
87 .id = V4L2_CID_CONTRAST,
88 .type = V4L2_CTRL_TYPE_INTEGER,
89 .name = "Contrast",
90 .minimum = 0,
91 .maximum = 0xff,
92 .step = 1,
93#define CONTRAST_DEF 0x20
94 .default_value = CONTRAST_DEF,
95 },
96 .set = sd_setcontrast,
97 .get = sd_getcontrast,
98 },
99 {
100 {
101 .id = V4L2_CID_SATURATION,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Color",
104 .minimum = 0,
105 .maximum = 0xff,
106 .step = 1,
107#define COLOR_DEF 0x1a
108 .default_value = COLOR_DEF,
109 },
110 .set = sd_setcolors,
111 .get = sd_getcolors,
112 },
113 {
114 {
115 .id = V4L2_CID_AUTOGAIN,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Auto Gain",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
121#define AUTOGAIN_DEF 1
122 .default_value = AUTOGAIN_DEF,
123 },
124 .set = sd_setautogain,
125 .get = sd_getautogain,
126 },
127};
128
129static const struct v4l2_pix_format vga_mode[] = {
130 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .bytesperline = 320,
132 .sizeimage = 320 * 240 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
134 .priv = 2},
135 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
136 .bytesperline = 640,
137 .sizeimage = 640 * 480 * 3 / 8 + 590,
138 .colorspace = V4L2_COLORSPACE_JPEG,
139 .priv = 1},
140};
141
142static const struct v4l2_pix_format custom_mode[] = {
143 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
144 .bytesperline = 320,
145 .sizeimage = 320 * 240 * 3 / 8 + 590,
146 .colorspace = V4L2_COLORSPACE_JPEG,
147 .priv = 2},
148 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
149 .bytesperline = 464,
150 .sizeimage = 464 * 480 * 3 / 8 + 590,
151 .colorspace = V4L2_COLORSPACE_JPEG,
152 .priv = 1},
153};
154
155static const struct v4l2_pix_format vga_mode2[] = {
156 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
157 .bytesperline = 176,
158 .sizeimage = 176 * 144 * 3 / 8 + 590,
159 .colorspace = V4L2_COLORSPACE_JPEG,
160 .priv = 4},
161 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
162 .bytesperline = 320,
163 .sizeimage = 320 * 240 * 3 / 8 + 590,
164 .colorspace = V4L2_COLORSPACE_JPEG,
165 .priv = 3},
166 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
167 .bytesperline = 352,
168 .sizeimage = 352 * 288 * 3 / 8 + 590,
169 .colorspace = V4L2_COLORSPACE_JPEG,
170 .priv = 2},
171 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
172 .bytesperline = 640,
173 .sizeimage = 640 * 480 * 3 / 8 + 590,
174 .colorspace = V4L2_COLORSPACE_JPEG,
175 .priv = 1},
176};
177
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
189
190struct cmd {
191 u8 req;
192 u16 val;
193 u16 idx;
194};
195
196/* Initialisation data for the Creative PC-CAM 600 */
197static 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},
221};
222
223/* Creative PC-CAM 600 specific open data, sent before using the
224 * generic initialisation data from spca504_open_data.
225 */
226static 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},
231};
232
233/* Initialisation data for the logitech clicksmart 420 */
234static 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},
249
250 {0xa1, 0x0080, 0x0001},
251 {0x30, 0x0049, 0x0000},
252 {0x30, 0x0060, 0x0005},
253 {0x0c, 0x0004, 0x0000},
254 {0x00, 0x0000, 0x0000},
255 {0x00, 0x0000, 0x2000},
256 {0x00, 0x0013, 0x2301},
257 {0x00, 0x0003, 0x2000},
258};
259
260/* clicksmart 420 open data ? */
261static const struct cmd spca504A_clicksmart420_open_data[] = {
262 {0x00, 0x0001, 0x2501},
263 {0x20, 0x0502, 0x0000},
264 {0x06, 0x0000, 0x0000},
265 {0x00, 0x0004, 0x2880},
266 {0x00, 0x0001, 0x2881},
267
268 {0xa0, 0x0000, 0x0503},
269};
270
271static const u8 qtable_creative_pccam[2][64] = {
272 { /* Q-table Y-components */
273 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
274 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
275 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
276 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
277 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
278 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
279 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
280 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
281 { /* Q-table C-components */
282 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
283 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
284 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
285 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
286 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
287 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
288 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
289 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
290};
291
292/* FIXME: This Q-table is identical to the Creative PC-CAM one,
293 * except for one byte. Possibly a typo?
294 * NWG: 18/05/2003.
295 */
296static const u8 qtable_spca504_default[2][64] = {
297 { /* Q-table Y-components */
298 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
299 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
300 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
301 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
302 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
303 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
304 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
305 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
306 },
307 { /* Q-table C-components */
308 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
309 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
310 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
311 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
312 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
313 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
314 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
315 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
316};
317
318/* read <len> bytes to gspca_dev->usb_buf */
319static void reg_r(struct gspca_dev *gspca_dev,
320 u8 req,
321 u16 index,
322 u16 len)
323{
324 int ret;
325
326#ifdef GSPCA_DEBUG
327 if (len > USB_BUF_SZ) {
328 err("reg_r: buffer overflow");
329 return;
330 }
331#endif
332 if (gspca_dev->usb_err < 0)
333 return;
334 ret = usb_control_msg(gspca_dev->dev,
335 usb_rcvctrlpipe(gspca_dev->dev, 0),
336 req,
337 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
338 0, /* value */
339 index,
340 len ? gspca_dev->usb_buf : NULL, len,
341 500);
342 if (ret < 0) {
343 err("reg_r err %d", ret);
344 gspca_dev->usb_err = ret;
345 }
346}
347
348/* write one byte */
349static void reg_w_1(struct gspca_dev *gspca_dev,
350 u8 req,
351 u16 value,
352 u16 index,
353 u16 byte)
354{
355 int ret;
356
357 if (gspca_dev->usb_err < 0)
358 return;
359 gspca_dev->usb_buf[0] = byte;
360 ret = usb_control_msg(gspca_dev->dev,
361 usb_sndctrlpipe(gspca_dev->dev, 0),
362 req,
363 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
364 value, index,
365 gspca_dev->usb_buf, 1,
366 500);
367 if (ret < 0) {
368 err("reg_w_1 err %d", ret);
369 gspca_dev->usb_err = ret;
370 }
371}
372
373/* write req / index / value */
374static void reg_w_riv(struct gspca_dev *gspca_dev,
375 u8 req, u16 index, u16 value)
376{
377 struct usb_device *dev = gspca_dev->dev;
378 int ret;
379
380 if (gspca_dev->usb_err < 0)
381 return;
382 ret = usb_control_msg(dev,
383 usb_sndctrlpipe(dev, 0),
384 req,
385 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
386 value, index, NULL, 0, 500);
387 if (ret < 0) {
388 err("reg_w_riv err %d", ret);
389 gspca_dev->usb_err = ret;
390 return;
391 }
392 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
393 req, index, value);
394}
395
396static void write_vector(struct gspca_dev *gspca_dev,
397 const struct cmd *data, int ncmds)
398{
399 while (--ncmds >= 0) {
400 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
401 data++;
402 }
403}
404
405static void setup_qtable(struct gspca_dev *gspca_dev,
406 const u8 qtable[2][64])
407{
408 int i;
409
410 /* loop over y components */
411 for (i = 0; i < 64; i++)
412 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
413
414 /* loop over c components */
415 for (i = 0; i < 64; i++)
416 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
417}
418
419static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
420 u8 req, u16 idx, u16 val)
421{
422 reg_w_riv(gspca_dev, req, idx, val);
423 reg_r(gspca_dev, 0x01, 0x0001, 1);
424 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
425 reg_w_riv(gspca_dev, req, idx, val);
426
427 msleep(200);
428 reg_r(gspca_dev, 0x01, 0x0001, 1);
429 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
430}
431
432#ifdef GSPCA_DEBUG
433static void spca504_read_info(struct gspca_dev *gspca_dev)
434{
435 int i;
436 u8 info[6];
437
438 for (i = 0; i < 6; i++) {
439 reg_r(gspca_dev, 0, i, 1);
440 info[i] = gspca_dev->usb_buf[0];
441 }
442 PDEBUG(D_STREAM,
443 "Read info: %d %d %d %d %d %d."
444 " Should be 1,0,2,2,0,0",
445 info[0], info[1], info[2],
446 info[3], info[4], info[5]);
447}
448#endif
449
450static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
451 u8 req,
452 u16 idx, u16 val, u8 endcode, u8 count)
453{
454 u16 status;
455
456 reg_w_riv(gspca_dev, req, idx, val);
457 reg_r(gspca_dev, 0x01, 0x0001, 1);
458 if (gspca_dev->usb_err < 0)
459 return;
460 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
461 gspca_dev->usb_buf[0], endcode);
462 if (!count)
463 return;
464 count = 200;
465 while (--count > 0) {
466 msleep(10);
467 /* gsmart mini2 write a each wait setting 1 ms is enough */
468/* reg_w_riv(gspca_dev, req, idx, val); */
469 reg_r(gspca_dev, 0x01, 0x0001, 1);
470 status = gspca_dev->usb_buf[0];
471 if (status == endcode) {
472 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
473 status, 200 - count);
474 break;
475 }
476 }
477}
478
479static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
480{
481 int count = 10;
482
483 while (--count > 0) {
484 reg_r(gspca_dev, 0x21, 0, 1);
485 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
486 break;
487 msleep(10);
488 }
489}
490
491static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
492{
493 int count = 50;
494
495 while (--count > 0) {
496 reg_r(gspca_dev, 0x21, 1, 1);
497 if (gspca_dev->usb_buf[0] != 0) {
498 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
499 reg_r(gspca_dev, 0x21, 1, 1);
500 spca504B_PollingDataReady(gspca_dev);
501 break;
502 }
503 msleep(10);
504 }
505}
506
507#ifdef GSPCA_DEBUG
508static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
509{
510 u8 *data;
511
512 data = gspca_dev->usb_buf;
513 reg_r(gspca_dev, 0x20, 0, 5);
514 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
515 data[0], data[1], data[2], data[3], data[4]);
516 reg_r(gspca_dev, 0x23, 0, 64);
517 reg_r(gspca_dev, 0x23, 1, 64);
518}
519#endif
520
521static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
522{
523 struct sd *sd = (struct sd *) gspca_dev;
524 u8 Size;
525
526 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
527 switch (sd->bridge) {
528 case BRIDGE_SPCA533:
529 reg_w_riv(gspca_dev, 0x31, 0, 0);
530 spca504B_WaitCmdStatus(gspca_dev);
531 spca504B_PollingDataReady(gspca_dev);
532#ifdef GSPCA_DEBUG
533 spca50x_GetFirmware(gspca_dev);
534#endif
535 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
536 reg_r(gspca_dev, 0x24, 8, 1);
537
538 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
539 reg_r(gspca_dev, 0x25, 4, 1); /* size */
540 spca504B_PollingDataReady(gspca_dev);
541
542 /* Init the cam width height with some values get on init ? */
543 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
544 spca504B_WaitCmdStatus(gspca_dev);
545 spca504B_PollingDataReady(gspca_dev);
546 break;
547 default:
548/* case BRIDGE_SPCA504B: */
549/* case BRIDGE_SPCA536: */
550 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
551 reg_r(gspca_dev, 0x25, 4, 1); /* size */
552 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
553 reg_r(gspca_dev, 0x27, 0, 1); /* type */
554 spca504B_PollingDataReady(gspca_dev);
555 break;
556 case BRIDGE_SPCA504:
557 Size += 3;
558 if (sd->subtype == AiptekMiniPenCam13) {
559 /* spca504a aiptek */
560 spca504A_acknowledged_command(gspca_dev,
561 0x08, Size, 0,
562 0x80 | (Size & 0x0f), 1);
563 spca504A_acknowledged_command(gspca_dev,
564 1, 3, 0, 0x9f, 0);
565 } else {
566 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
567 }
568 break;
569 case BRIDGE_SPCA504C:
570 /* capture mode */
571 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
572 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
573 break;
574 }
575}
576
577static void spca504_wait_status(struct gspca_dev *gspca_dev)
578{
579 int cnt;
580
581 cnt = 256;
582 while (--cnt > 0) {
583 /* With this we get the status, when return 0 it's all ok */
584 reg_r(gspca_dev, 0x06, 0x00, 1);
585 if (gspca_dev->usb_buf[0] == 0)
586 return;
587 msleep(10);
588 }
589}
590
591static void spca504B_setQtable(struct gspca_dev *gspca_dev)
592{
593 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
594 reg_r(gspca_dev, 0x26, 0, 1);
595 spca504B_PollingDataReady(gspca_dev);
596}
597
598static void setbrightness(struct gspca_dev *gspca_dev)
599{
600 struct sd *sd = (struct sd *) gspca_dev;
601 u16 reg;
602
603 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
604 reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
605}
606
607static void setcontrast(struct gspca_dev *gspca_dev)
608{
609 struct sd *sd = (struct sd *) gspca_dev;
610 u16 reg;
611
612 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
613 reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
614}
615
616static void setcolors(struct gspca_dev *gspca_dev)
617{
618 struct sd *sd = (struct sd *) gspca_dev;
619 u16 reg;
620
621 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
622 reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
623}
624
625static void init_ctl_reg(struct gspca_dev *gspca_dev)
626{
627 struct sd *sd = (struct sd *) gspca_dev;
628 int pollreg = 1;
629
630 setbrightness(gspca_dev);
631 setcontrast(gspca_dev);
632 setcolors(gspca_dev);
633
634 switch (sd->bridge) {
635 case BRIDGE_SPCA504:
636 case BRIDGE_SPCA504C:
637 pollreg = 0;
638 /* fall thru */
639 default:
640/* case BRIDGE_SPCA533: */
641/* case BRIDGE_SPCA504B: */
642 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
643 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
644 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
645 break;
646 case BRIDGE_SPCA536:
647 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
648 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
649 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
650 break;
651 }
652 if (pollreg)
653 spca504B_PollingDataReady(gspca_dev);
654}
655
656/* this function is called at probe time */
657static int sd_config(struct gspca_dev *gspca_dev,
658 const struct usb_device_id *id)
659{
660 struct sd *sd = (struct sd *) gspca_dev;
661 struct cam *cam;
662
663 cam = &gspca_dev->cam;
664
665 sd->bridge = id->driver_info >> 8;
666 sd->subtype = id->driver_info;
667
668 if (sd->subtype == AiptekMiniPenCam13) {
669
670 /* try to get the firmware as some cam answer 2.0.1.2.2
671 * and should be a spca504b then overwrite that setting */
672 reg_r(gspca_dev, 0x20, 0, 1);
673 switch (gspca_dev->usb_buf[0]) {
674 case 1:
675 break; /* (right bridge/subtype) */
676 case 2:
677 sd->bridge = BRIDGE_SPCA504B;
678 sd->subtype = 0;
679 break;
680 default:
681 return -ENODEV;
682 }
683 }
684
685 switch (sd->bridge) {
686 default:
687/* case BRIDGE_SPCA504B: */
688/* case BRIDGE_SPCA504: */
689/* case BRIDGE_SPCA536: */
690 cam->cam_mode = vga_mode;
691 cam->nmodes = ARRAY_SIZE(vga_mode);
692 break;
693 case BRIDGE_SPCA533:
694 cam->cam_mode = custom_mode;
695 if (sd->subtype == MegaImageVI) /* 320x240 only */
696 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
697 else
698 cam->nmodes = ARRAY_SIZE(custom_mode);
699 break;
700 case BRIDGE_SPCA504C:
701 cam->cam_mode = vga_mode2;
702 cam->nmodes = ARRAY_SIZE(vga_mode2);
703 break;
704 }
705 sd->brightness = BRIGHTNESS_DEF;
706 sd->contrast = CONTRAST_DEF;
707 sd->colors = COLOR_DEF;
708 sd->autogain = AUTOGAIN_DEF;
709 sd->quality = QUALITY_DEF;
710 return 0;
711}
712
713/* this function is called at probe and resume time */
714static int sd_init(struct gspca_dev *gspca_dev)
715{
716 struct sd *sd = (struct sd *) gspca_dev;
717
718 switch (sd->bridge) {
719 case BRIDGE_SPCA504B:
720 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
721 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
722 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
723 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
724 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
725 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
726 /* fall thru */
727 case BRIDGE_SPCA533:
728 spca504B_PollingDataReady(gspca_dev);
729#ifdef GSPCA_DEBUG
730 spca50x_GetFirmware(gspca_dev);
731#endif
732 break;
733 case BRIDGE_SPCA536:
734#ifdef GSPCA_DEBUG
735 spca50x_GetFirmware(gspca_dev);
736#endif
737 reg_r(gspca_dev, 0x00, 0x5002, 1);
738 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
739 reg_r(gspca_dev, 0x24, 0, 1);
740 spca504B_PollingDataReady(gspca_dev);
741 reg_w_riv(gspca_dev, 0x34, 0, 0);
742 spca504B_WaitCmdStatus(gspca_dev);
743 break;
744 case BRIDGE_SPCA504C: /* pccam600 */
745 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
746 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
747 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
748 spca504_wait_status(gspca_dev);
749 if (sd->subtype == LogitechClickSmart420)
750 write_vector(gspca_dev,
751 spca504A_clicksmart420_open_data,
752 ARRAY_SIZE(spca504A_clicksmart420_open_data));
753 else
754 write_vector(gspca_dev, spca504_pccam600_open_data,
755 ARRAY_SIZE(spca504_pccam600_open_data));
756 setup_qtable(gspca_dev, qtable_creative_pccam);
757 break;
758 default:
759/* case BRIDGE_SPCA504: */
760 PDEBUG(D_STREAM, "Opening SPCA504");
761 if (sd->subtype == AiptekMiniPenCam13) {
762#ifdef GSPCA_DEBUG
763 spca504_read_info(gspca_dev);
764#endif
765
766 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
767 spca504A_acknowledged_command(gspca_dev, 0x24,
768 8, 3, 0x9e, 1);
769 /* Twice sequential need status 0xff->0x9e->0x9d */
770 spca504A_acknowledged_command(gspca_dev, 0x24,
771 8, 3, 0x9e, 0);
772
773 spca504A_acknowledged_command(gspca_dev, 0x24,
774 0, 0, 0x9d, 1);
775 /******************************/
776 /* spca504a aiptek */
777 spca504A_acknowledged_command(gspca_dev, 0x08,
778 6, 0, 0x86, 1);
779/* reg_write (dev, 0, 0x2000, 0); */
780/* reg_write (dev, 0, 0x2883, 1); */
781/* spca504A_acknowledged_command (gspca_dev, 0x08,
782 6, 0, 0x86, 1); */
783/* spca504A_acknowledged_command (gspca_dev, 0x24,
784 0, 0, 0x9D, 1); */
785 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
786 /* L92 sno1t.txt */
787 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
788 spca504A_acknowledged_command(gspca_dev, 0x01,
789 0x0f, 0, 0xff, 0);
790 }
791 /* setup qtable */
792 reg_w_riv(gspca_dev, 0, 0x2000, 0);
793 reg_w_riv(gspca_dev, 0, 0x2883, 1);
794 setup_qtable(gspca_dev, qtable_spca504_default);
795 break;
796 }
797 return gspca_dev->usb_err;
798}
799
800static int sd_start(struct gspca_dev *gspca_dev)
801{
802 struct sd *sd = (struct sd *) gspca_dev;
803 int enable;
804
805 /* create the JPEG header */
806 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
807 0x22); /* JPEG 411 */
808 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
809
810 if (sd->bridge == BRIDGE_SPCA504B)
811 spca504B_setQtable(gspca_dev);
812 spca504B_SetSizeType(gspca_dev);
813 switch (sd->bridge) {
814 default:
815/* case BRIDGE_SPCA504B: */
816/* case BRIDGE_SPCA533: */
817/* case BRIDGE_SPCA536: */
818 switch (sd->subtype) {
819 case MegapixV4:
820 case LogitechClickSmart820:
821 case MegaImageVI:
822 reg_w_riv(gspca_dev, 0xf0, 0, 0);
823 spca504B_WaitCmdStatus(gspca_dev);
824 reg_r(gspca_dev, 0xf0, 4, 0);
825 spca504B_WaitCmdStatus(gspca_dev);
826 break;
827 default:
828 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
829 spca504B_WaitCmdStatus(gspca_dev);
830 spca504B_PollingDataReady(gspca_dev);
831 break;
832 }
833 break;
834 case BRIDGE_SPCA504:
835 if (sd->subtype == AiptekMiniPenCam13) {
836#ifdef GSPCA_DEBUG
837 spca504_read_info(gspca_dev);
838#endif
839
840 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
841 spca504A_acknowledged_command(gspca_dev, 0x24,
842 8, 3, 0x9e, 1);
843 /* Twice sequential need status 0xff->0x9e->0x9d */
844 spca504A_acknowledged_command(gspca_dev, 0x24,
845 8, 3, 0x9e, 0);
846 spca504A_acknowledged_command(gspca_dev, 0x24,
847 0, 0, 0x9d, 1);
848 } else {
849 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
850#ifdef GSPCA_DEBUG
851 spca504_read_info(gspca_dev);
852#endif
853 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
854 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
855 }
856 spca504B_SetSizeType(gspca_dev);
857 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
858 /* L92 sno1t.txt */
859 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
860 break;
861 case BRIDGE_SPCA504C:
862 if (sd->subtype == LogitechClickSmart420) {
863 write_vector(gspca_dev,
864 spca504A_clicksmart420_init_data,
865 ARRAY_SIZE(spca504A_clicksmart420_init_data));
866 } else {
867 write_vector(gspca_dev, spca504_pccam600_init_data,
868 ARRAY_SIZE(spca504_pccam600_init_data));
869 }
870 enable = (sd->autogain ? 0x04 : 0x01);
871 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
872 /* auto exposure */
873 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
874 /* auto whiteness */
875
876 /* set default exposure compensation and whiteness balance */
877 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
878 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
879 spca504B_SetSizeType(gspca_dev);
880 break;
881 }
882 init_ctl_reg(gspca_dev);
883 return gspca_dev->usb_err;
884}
885
886static void sd_stopN(struct gspca_dev *gspca_dev)
887{
888 struct sd *sd = (struct sd *) gspca_dev;
889
890 switch (sd->bridge) {
891 default:
892/* case BRIDGE_SPCA533: */
893/* case BRIDGE_SPCA536: */
894/* case BRIDGE_SPCA504B: */
895 reg_w_riv(gspca_dev, 0x31, 0, 0);
896 spca504B_WaitCmdStatus(gspca_dev);
897 spca504B_PollingDataReady(gspca_dev);
898 break;
899 case BRIDGE_SPCA504:
900 case BRIDGE_SPCA504C:
901 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
902
903 if (sd->subtype == AiptekMiniPenCam13) {
904 /* spca504a aiptek */
905/* spca504A_acknowledged_command(gspca_dev, 0x08,
906 6, 0, 0x86, 1); */
907 spca504A_acknowledged_command(gspca_dev, 0x24,
908 0x00, 0x00, 0x9d, 1);
909 spca504A_acknowledged_command(gspca_dev, 0x01,
910 0x0f, 0x00, 0xff, 1);
911 } else {
912 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
913 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
914 }
915 break;
916 }
917}
918
919static void sd_pkt_scan(struct gspca_dev *gspca_dev,
920 u8 *data, /* isoc packet */
921 int len) /* iso packet length */
922{
923 struct sd *sd = (struct sd *) gspca_dev;
924 int i, sof = 0;
925 static u8 ffd9[] = {0xff, 0xd9};
926
927/* frames are jpeg 4.1.1 without 0xff escape */
928 switch (sd->bridge) {
929 case BRIDGE_SPCA533:
930 if (data[0] == 0xff) {
931 if (data[1] != 0x01) { /* drop packet */
932/* gspca_dev->last_packet_type = DISCARD_PACKET; */
933 return;
934 }
935 sof = 1;
936 data += SPCA533_OFFSET_DATA;
937 len -= SPCA533_OFFSET_DATA;
938 } else {
939 data += 1;
940 len -= 1;
941 }
942 break;
943 case BRIDGE_SPCA536:
944 if (data[0] == 0xff) {
945 sof = 1;
946 data += SPCA536_OFFSET_DATA;
947 len -= SPCA536_OFFSET_DATA;
948 } else {
949 data += 2;
950 len -= 2;
951 }
952 break;
953 default:
954/* case BRIDGE_SPCA504: */
955/* case BRIDGE_SPCA504B: */
956 switch (data[0]) {
957 case 0xfe: /* start of frame */
958 sof = 1;
959 data += SPCA50X_OFFSET_DATA;
960 len -= SPCA50X_OFFSET_DATA;
961 break;
962 case 0xff: /* drop packet */
963/* gspca_dev->last_packet_type = DISCARD_PACKET; */
964 return;
965 default:
966 data += 1;
967 len -= 1;
968 break;
969 }
970 break;
971 case BRIDGE_SPCA504C:
972 switch (data[0]) {
973 case 0xfe: /* start of frame */
974 sof = 1;
975 data += SPCA504_PCCAM600_OFFSET_DATA;
976 len -= SPCA504_PCCAM600_OFFSET_DATA;
977 break;
978 case 0xff: /* drop packet */
979/* gspca_dev->last_packet_type = DISCARD_PACKET; */
980 return;
981 default:
982 data += 1;
983 len -= 1;
984 break;
985 }
986 break;
987 }
988 if (sof) { /* start of frame */
989 gspca_frame_add(gspca_dev, LAST_PACKET,
990 ffd9, 2);
991
992 /* put the JPEG header in the new frame */
993 gspca_frame_add(gspca_dev, FIRST_PACKET,
994 sd->jpeg_hdr, JPEG_HDR_SZ);
995 }
996
997 /* add 0x00 after 0xff */
998 i = 0;
999 do {
1000 if (data[i] == 0xff) {
1001 gspca_frame_add(gspca_dev, INTER_PACKET,
1002 data, i + 1);
1003 len -= i;
1004 data += i;
1005 *data = 0x00;
1006 i = 0;
1007 }
1008 i++;
1009 } while (i < len);
1010 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1011}
1012
1013static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1014{
1015 struct sd *sd = (struct sd *) gspca_dev;
1016
1017 sd->brightness = val;
1018 if (gspca_dev->streaming)
1019 setbrightness(gspca_dev);
1020 return gspca_dev->usb_err;
1021}
1022
1023static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
1026
1027 *val = sd->brightness;
1028 return 0;
1029}
1030
1031static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1032{
1033 struct sd *sd = (struct sd *) gspca_dev;
1034
1035 sd->contrast = val;
1036 if (gspca_dev->streaming)
1037 setcontrast(gspca_dev);
1038 return gspca_dev->usb_err;
1039}
1040
1041static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1042{
1043 struct sd *sd = (struct sd *) gspca_dev;
1044
1045 *val = sd->contrast;
1046 return 0;
1047}
1048
1049static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1050{
1051 struct sd *sd = (struct sd *) gspca_dev;
1052
1053 sd->colors = val;
1054 if (gspca_dev->streaming)
1055 setcolors(gspca_dev);
1056 return gspca_dev->usb_err;
1057}
1058
1059static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1060{
1061 struct sd *sd = (struct sd *) gspca_dev;
1062
1063 *val = sd->colors;
1064 return 0;
1065}
1066
1067static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1068{
1069 struct sd *sd = (struct sd *) gspca_dev;
1070
1071 sd->autogain = val;
1072 return 0;
1073}
1074
1075static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1076{
1077 struct sd *sd = (struct sd *) gspca_dev;
1078
1079 *val = sd->autogain;
1080 return 0;
1081}
1082
1083static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1084 struct v4l2_jpegcompression *jcomp)
1085{
1086 struct sd *sd = (struct sd *) gspca_dev;
1087
1088 if (jcomp->quality < QUALITY_MIN)
1089 sd->quality = QUALITY_MIN;
1090 else if (jcomp->quality > QUALITY_MAX)
1091 sd->quality = QUALITY_MAX;
1092 else
1093 sd->quality = jcomp->quality;
1094 if (gspca_dev->streaming)
1095 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1096 return gspca_dev->usb_err;
1097}
1098
1099static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1100 struct v4l2_jpegcompression *jcomp)
1101{
1102 struct sd *sd = (struct sd *) gspca_dev;
1103
1104 memset(jcomp, 0, sizeof *jcomp);
1105 jcomp->quality = sd->quality;
1106 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1107 | V4L2_JPEG_MARKER_DQT;
1108 return 0;
1109}
1110
1111/* sub-driver description */
1112static const struct sd_desc sd_desc = {
1113 .name = MODULE_NAME,
1114 .ctrls = sd_ctrls,
1115 .nctrls = ARRAY_SIZE(sd_ctrls),
1116 .config = sd_config,
1117 .init = sd_init,
1118 .start = sd_start,
1119 .stopN = sd_stopN,
1120 .pkt_scan = sd_pkt_scan,
1121 .get_jcomp = sd_get_jcomp,
1122 .set_jcomp = sd_set_jcomp,
1123};
1124
1125/* -- module initialisation -- */
1126#define BS(bridge, subtype) \
1127 .driver_info = (BRIDGE_ ## bridge << 8) \
1128 | (subtype)
1129static const struct usb_device_id device_table[] = {
1130 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1131 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1132 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1133 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1134 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1135 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1136 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1137 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1138 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1139 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1140 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1141 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1142 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1143 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1144 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1145 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1146 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1147 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1148 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1149 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1150 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1151 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1152 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1153 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1154 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1155 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1156 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1157 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1158 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1159 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1160 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1161 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1162 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1163 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1164 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1165 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1166 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1167 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1168 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1169 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1170 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1171 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1172 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1173 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1174 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1175 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1176 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1177 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1178 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1179 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1180 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1181 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1182 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1183 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1184 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1185 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1186 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1187 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1188 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1189 {}
1190};
1191MODULE_DEVICE_TABLE(usb, device_table);
1192
1193/* -- device connect -- */
1194static int sd_probe(struct usb_interface *intf,
1195 const struct usb_device_id *id)
1196{
1197 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1198 THIS_MODULE);
1199}
1200
1201static struct usb_driver sd_driver = {
1202 .name = MODULE_NAME,
1203 .id_table = device_table,
1204 .probe = sd_probe,
1205 .disconnect = gspca_disconnect,
1206#ifdef CONFIG_PM
1207 .suspend = gspca_suspend,
1208 .resume = gspca_resume,
1209#endif
1210};
1211
1212/* -- module insert / remove -- */
1213static int __init sd_mod_init(void)
1214{
1215 return usb_register(&sd_driver);
1216}
1217static void __exit sd_mod_exit(void)
1218{
1219 usb_deregister(&sd_driver);
1220}
1221
1222module_init(sd_mod_init);
1223module_exit(sd_mod_exit);