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