blob: bddf73360c252248d8e275e63fcc0c4d40a44d47 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
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
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_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
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030035 __u8 packet[ISO_MAX_SIZE + 128];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030036 /* !! no more than 128 ff in an ISO packet */
37
38 unsigned char brightness;
39 unsigned char contrast;
40 unsigned char colors;
41 unsigned char autogain;
42
43 char qindex;
44 char 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 char subtype;
51#define AiptekMiniPenCam13 1
52#define LogitechClickSmart420 2
53#define LogitechClickSmart820 3
54#define MegapixV4 4
55};
56
57/* V4L2 controls supported by the driver */
58static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
59static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
60static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
62static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
64static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
66
67static struct ctrl sd_ctrls[] = {
68#define SD_BRIGHTNESS 0
69 {
70 {
71 .id = V4L2_CID_BRIGHTNESS,
72 .type = V4L2_CTRL_TYPE_INTEGER,
73 .name = "Brightness",
74 .minimum = 0,
75 .maximum = 0xff,
76 .step = 1,
77 .default_value = 0,
78 },
79 .set = sd_setbrightness,
80 .get = sd_getbrightness,
81 },
82#define SD_CONTRAST 1
83 {
84 {
85 .id = V4L2_CID_CONTRAST,
86 .type = V4L2_CTRL_TYPE_INTEGER,
87 .name = "Contrast",
88 .minimum = 0,
89 .maximum = 0xff,
90 .step = 1,
91 .default_value = 0x20,
92 },
93 .set = sd_setcontrast,
94 .get = sd_getcontrast,
95 },
96#define SD_COLOR 2
97 {
98 {
99 .id = V4L2_CID_SATURATION,
100 .type = V4L2_CTRL_TYPE_INTEGER,
101 .name = "Color",
102 .minimum = 0,
103 .maximum = 0xff,
104 .step = 1,
105 .default_value = 0x1a,
106 },
107 .set = sd_setcolors,
108 .get = sd_getcolors,
109 },
110#define SD_AUTOGAIN 3
111 {
112 {
113 .id = V4L2_CID_AUTOGAIN,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 .name = "Auto Gain",
116 .minimum = 0,
117 .maximum = 1,
118 .step = 1,
119 .default_value = 1,
120 },
121 .set = sd_setautogain,
122 .get = sd_getautogain,
123 },
124};
125
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300126static struct v4l2_pix_format vga_mode[] = {
127 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
128 .bytesperline = 320,
129 .sizeimage = 320 * 240 * 3 / 8 + 590,
130 .colorspace = V4L2_COLORSPACE_JPEG,
131 .priv = 2},
132 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133 .bytesperline = 640,
134 .sizeimage = 640 * 480 * 3 / 8 + 590,
135 .colorspace = V4L2_COLORSPACE_JPEG,
136 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300137};
138
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300139static struct v4l2_pix_format custom_mode[] = {
140 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
141 .bytesperline = 320,
142 .sizeimage = 320 * 240 * 3 / 8 + 590,
143 .colorspace = V4L2_COLORSPACE_JPEG,
144 .priv = 2},
145 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
146 .bytesperline = 464,
147 .sizeimage = 464 * 480 * 3 / 8 + 590,
148 .colorspace = V4L2_COLORSPACE_JPEG,
149 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300150};
151
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300152static struct v4l2_pix_format vga_mode2[] = {
153 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
154 .bytesperline = 176,
155 .sizeimage = 176 * 144 * 3 / 8 + 590,
156 .colorspace = V4L2_COLORSPACE_JPEG,
157 .priv = 4},
158 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
159 .bytesperline = 320,
160 .sizeimage = 320 * 240 * 3 / 8 + 590,
161 .colorspace = V4L2_COLORSPACE_JPEG,
162 .priv = 3},
163 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
164 .bytesperline = 352,
165 .sizeimage = 352 * 288 * 3 / 8 + 590,
166 .colorspace = V4L2_COLORSPACE_JPEG,
167 .priv = 2},
168 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
169 .bytesperline = 640,
170 .sizeimage = 640 * 480 * 3 / 8 + 590,
171 .colorspace = V4L2_COLORSPACE_JPEG,
172 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300173};
174
175#define SPCA50X_OFFSET_DATA 10
176#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
177#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
178#define SPCA504_PCCAM600_OFFSET_MODE 5
179#define SPCA504_PCCAM600_OFFSET_DATA 14
180 /* Frame packet header offsets for the spca533 */
181#define SPCA533_OFFSET_DATA 16
182#define SPCA533_OFFSET_FRAMSEQ 15
183/* Frame packet header offsets for the spca536 */
184#define SPCA536_OFFSET_DATA 4
185#define SPCA536_OFFSET_FRAMSEQ 1
186
187/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300188static const __u16 spca504_pccam600_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300189/* {0xa0, 0x0000, 0x0503}, * capture mode */
190 {0x00, 0x0000, 0x2000},
191 {0x00, 0x0013, 0x2301},
192 {0x00, 0x0003, 0x2000},
193 {0x00, 0x0001, 0x21ac},
194 {0x00, 0x0001, 0x21a6},
195 {0x00, 0x0000, 0x21a7}, /* brightness */
196 {0x00, 0x0020, 0x21a8}, /* contrast */
197 {0x00, 0x0001, 0x21ac}, /* sat/hue */
198 {0x00, 0x0000, 0x21ad}, /* hue */
199 {0x00, 0x001a, 0x21ae}, /* saturation */
200 {0x00, 0x0002, 0x21a3}, /* gamma */
201 {0x30, 0x0154, 0x0008},
202 {0x30, 0x0004, 0x0006},
203 {0x30, 0x0258, 0x0009},
204 {0x30, 0x0004, 0x0000},
205 {0x30, 0x0093, 0x0004},
206 {0x30, 0x0066, 0x0005},
207 {0x00, 0x0000, 0x2000},
208 {0x00, 0x0013, 0x2301},
209 {0x00, 0x0003, 0x2000},
210 {0x00, 0x0013, 0x2301},
211 {0x00, 0x0003, 0x2000},
212 {}
213};
214
215/* Creative PC-CAM 600 specific open data, sent before using the
216 * generic initialisation data from spca504_open_data.
217 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300218static const __u16 spca504_pccam600_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219 {0x00, 0x0001, 0x2501},
220 {0x20, 0x0500, 0x0001}, /* snapshot mode */
221 {0x00, 0x0003, 0x2880},
222 {0x00, 0x0001, 0x2881},
223 {}
224};
225
226/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300227static const __u16 spca504A_clicksmart420_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228/* {0xa0, 0x0000, 0x0503}, * capture mode */
229 {0x00, 0x0000, 0x2000},
230 {0x00, 0x0013, 0x2301},
231 {0x00, 0x0003, 0x2000},
232 {0x00, 0x0001, 0x21ac},
233 {0x00, 0x0001, 0x21a6},
234 {0x00, 0x0000, 0x21a7}, /* brightness */
235 {0x00, 0x0020, 0x21a8}, /* contrast */
236 {0x00, 0x0001, 0x21ac}, /* sat/hue */
237 {0x00, 0x0000, 0x21ad}, /* hue */
238 {0x00, 0x001a, 0x21ae}, /* saturation */
239 {0x00, 0x0002, 0x21a3}, /* gamma */
240 {0x30, 0x0004, 0x000a},
241 {0xb0, 0x0001, 0x0000},
242
243
244 {0x0a1, 0x0080, 0x0001},
245 {0x30, 0x0049, 0x0000},
246 {0x30, 0x0060, 0x0005},
247 {0x0c, 0x0004, 0x0000},
248 {0x00, 0x0000, 0x0000},
249 {0x00, 0x0000, 0x2000},
250 {0x00, 0x0013, 0x2301},
251 {0x00, 0x0003, 0x2000},
252 {0x00, 0x0000, 0x2000},
253
254 {}
255};
256
257/* clicksmart 420 open data ? */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300258static const __u16 spca504A_clicksmart420_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300259 {0x00, 0x0001, 0x2501},
260 {0x20, 0x0502, 0x0000},
261 {0x06, 0x0000, 0x0000},
262 {0x00, 0x0004, 0x2880},
263 {0x00, 0x0001, 0x2881},
264/* look like setting a qTable */
265 {0x00, 0x0006, 0x2800},
266 {0x00, 0x0004, 0x2801},
267 {0x00, 0x0004, 0x2802},
268 {0x00, 0x0006, 0x2803},
269 {0x00, 0x000a, 0x2804},
270 {0x00, 0x0010, 0x2805},
271 {0x00, 0x0014, 0x2806},
272 {0x00, 0x0018, 0x2807},
273 {0x00, 0x0005, 0x2808},
274 {0x00, 0x0005, 0x2809},
275 {0x00, 0x0006, 0x280a},
276 {0x00, 0x0008, 0x280b},
277 {0x00, 0x000a, 0x280c},
278 {0x00, 0x0017, 0x280d},
279 {0x00, 0x0018, 0x280e},
280 {0x00, 0x0016, 0x280f},
281
282 {0x00, 0x0006, 0x2810},
283 {0x00, 0x0005, 0x2811},
284 {0x00, 0x0006, 0x2812},
285 {0x00, 0x000a, 0x2813},
286 {0x00, 0x0010, 0x2814},
287 {0x00, 0x0017, 0x2815},
288 {0x00, 0x001c, 0x2816},
289 {0x00, 0x0016, 0x2817},
290 {0x00, 0x0006, 0x2818},
291 {0x00, 0x0007, 0x2819},
292 {0x00, 0x0009, 0x281a},
293 {0x00, 0x000c, 0x281b},
294 {0x00, 0x0014, 0x281c},
295 {0x00, 0x0023, 0x281d},
296 {0x00, 0x0020, 0x281e},
297 {0x00, 0x0019, 0x281f},
298
299 {0x00, 0x0007, 0x2820},
300 {0x00, 0x0009, 0x2821},
301 {0x00, 0x000f, 0x2822},
302 {0x00, 0x0016, 0x2823},
303 {0x00, 0x001b, 0x2824},
304 {0x00, 0x002c, 0x2825},
305 {0x00, 0x0029, 0x2826},
306 {0x00, 0x001f, 0x2827},
307 {0x00, 0x000a, 0x2828},
308 {0x00, 0x000e, 0x2829},
309 {0x00, 0x0016, 0x282a},
310 {0x00, 0x001a, 0x282b},
311 {0x00, 0x0020, 0x282c},
312 {0x00, 0x002a, 0x282d},
313 {0x00, 0x002d, 0x282e},
314 {0x00, 0x0025, 0x282f},
315
316 {0x00, 0x0014, 0x2830},
317 {0x00, 0x001a, 0x2831},
318 {0x00, 0x001f, 0x2832},
319 {0x00, 0x0023, 0x2833},
320 {0x00, 0x0029, 0x2834},
321 {0x00, 0x0030, 0x2835},
322 {0x00, 0x0030, 0x2836},
323 {0x00, 0x0028, 0x2837},
324 {0x00, 0x001d, 0x2838},
325 {0x00, 0x0025, 0x2839},
326 {0x00, 0x0026, 0x283a},
327 {0x00, 0x0027, 0x283b},
328 {0x00, 0x002d, 0x283c},
329 {0x00, 0x0028, 0x283d},
330 {0x00, 0x0029, 0x283e},
331 {0x00, 0x0028, 0x283f},
332
333 {0x00, 0x0007, 0x2840},
334 {0x00, 0x0007, 0x2841},
335 {0x00, 0x000a, 0x2842},
336 {0x00, 0x0013, 0x2843},
337 {0x00, 0x0028, 0x2844},
338 {0x00, 0x0028, 0x2845},
339 {0x00, 0x0028, 0x2846},
340 {0x00, 0x0028, 0x2847},
341 {0x00, 0x0007, 0x2848},
342 {0x00, 0x0008, 0x2849},
343 {0x00, 0x000a, 0x284a},
344 {0x00, 0x001a, 0x284b},
345 {0x00, 0x0028, 0x284c},
346 {0x00, 0x0028, 0x284d},
347 {0x00, 0x0028, 0x284e},
348 {0x00, 0x0028, 0x284f},
349
350 {0x00, 0x000a, 0x2850},
351 {0x00, 0x000a, 0x2851},
352 {0x00, 0x0016, 0x2852},
353 {0x00, 0x0028, 0x2853},
354 {0x00, 0x0028, 0x2854},
355 {0x00, 0x0028, 0x2855},
356 {0x00, 0x0028, 0x2856},
357 {0x00, 0x0028, 0x2857},
358 {0x00, 0x0013, 0x2858},
359 {0x00, 0x001a, 0x2859},
360 {0x00, 0x0028, 0x285a},
361 {0x00, 0x0028, 0x285b},
362 {0x00, 0x0028, 0x285c},
363 {0x00, 0x0028, 0x285d},
364 {0x00, 0x0028, 0x285e},
365 {0x00, 0x0028, 0x285f},
366
367 {0x00, 0x0028, 0x2860},
368 {0x00, 0x0028, 0x2861},
369 {0x00, 0x0028, 0x2862},
370 {0x00, 0x0028, 0x2863},
371 {0x00, 0x0028, 0x2864},
372 {0x00, 0x0028, 0x2865},
373 {0x00, 0x0028, 0x2866},
374 {0x00, 0x0028, 0x2867},
375 {0x00, 0x0028, 0x2868},
376 {0x00, 0x0028, 0x2869},
377 {0x00, 0x0028, 0x286a},
378 {0x00, 0x0028, 0x286b},
379 {0x00, 0x0028, 0x286c},
380 {0x00, 0x0028, 0x286d},
381 {0x00, 0x0028, 0x286e},
382 {0x00, 0x0028, 0x286f},
383
384 {0x00, 0x0028, 0x2870},
385 {0x00, 0x0028, 0x2871},
386 {0x00, 0x0028, 0x2872},
387 {0x00, 0x0028, 0x2873},
388 {0x00, 0x0028, 0x2874},
389 {0x00, 0x0028, 0x2875},
390 {0x00, 0x0028, 0x2876},
391 {0x00, 0x0028, 0x2877},
392 {0x00, 0x0028, 0x2878},
393 {0x00, 0x0028, 0x2879},
394 {0x00, 0x0028, 0x287a},
395 {0x00, 0x0028, 0x287b},
396 {0x00, 0x0028, 0x287c},
397 {0x00, 0x0028, 0x287d},
398 {0x00, 0x0028, 0x287e},
399 {0x00, 0x0028, 0x287f},
400
401 {0xa0, 0x0000, 0x0503},
402 {}
403};
404
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300405static const __u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406 { /* Q-table Y-components */
407 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
408 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
409 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
410 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
411 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
412 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
413 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
414 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
415 { /* Q-table C-components */
416 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
417 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
418 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
419 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
420 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
421 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
422 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
423 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
424};
425
426/* FIXME: This Q-table is identical to the Creative PC-CAM one,
427 * except for one byte. Possibly a typo?
428 * NWG: 18/05/2003.
429 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300430static const __u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300431 { /* Q-table Y-components */
432 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
433 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
434 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
435 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
436 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
437 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
438 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
439 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
440 },
441 { /* Q-table C-components */
442 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
443 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
444 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
445 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
446 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
447 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
448 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
449 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
450};
451
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300452static void reg_r(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453 __u16 req,
454 __u16 index,
455 __u8 *buffer, __u16 length)
456{
457 usb_control_msg(dev,
458 usb_rcvctrlpipe(dev, 0),
459 req,
460 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
461 0, /* value */
462 index, buffer, length,
463 500);
464}
465
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300466static void reg_w(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467 __u16 req,
468 __u16 value,
469 __u16 index,
470 __u8 *buffer, __u16 length)
471{
472 usb_control_msg(dev,
473 usb_sndctrlpipe(dev, 0),
474 req,
475 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
476 value, index, buffer, length,
477 500);
478}
479
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300480/* write req / index / value */
481static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 __u16 req, __u16 index, __u16 value)
483{
484 int ret;
485
486 ret = usb_control_msg(dev,
487 usb_sndctrlpipe(dev, 0),
488 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300489 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300490 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300491 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300492 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 if (ret < 0)
494 PDEBUG(D_ERR, "reg write: error %d", ret);
495 return ret;
496}
497
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300498/* read 1 byte */
499static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 __u16 value) /* wValue */
501{
502 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300504 ret = usb_control_msg(gspca_dev->dev,
505 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 0x20, /* request */
507 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
508 value,
509 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300510 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 500); /* timeout */
512 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 return 0;
515 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517}
518
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300519/* read 1 or 2 bytes - returns < 0 if error */
520static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 __u16 req, /* bRequest */
522 __u16 index, /* wIndex */
523 __u16 length) /* wLength (1 or 2 only) */
524{
525 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 gspca_dev->usb_buf[1] = 0;
528 ret = usb_control_msg(gspca_dev->dev,
529 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 req,
531 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
532 0, /* value */
533 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 500);
536 if (ret < 0) {
537 PDEBUG(D_ERR, "reg_read err %d", ret);
538 return -1;
539 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300540 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541}
542
543static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300544 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545{
546 struct usb_device *dev = gspca_dev->dev;
547 int ret, i = 0;
548
549 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 if (ret < 0) {
552 PDEBUG(D_ERR,
553 "Register write failed for 0x%x,0x%x,0x%x",
554 data[i][0], data[i][1], data[i][2]);
555 return ret;
556 }
557 i++;
558 }
559 return 0;
560}
561
562static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
563 unsigned int request,
564 unsigned int ybase,
565 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300566 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567{
568 struct usb_device *dev = gspca_dev->dev;
569 int i, err;
570
571 /* loop over y components */
572 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300573 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574 if (err < 0)
575 return err;
576 }
577
578 /* loop over c components */
579 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300580 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 if (err < 0)
582 return err;
583 }
584 return 0;
585}
586
587static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
588 __u16 req, __u16 idx, __u16 val)
589{
590 struct usb_device *dev = gspca_dev->dev;
591 __u8 notdone;
592
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300593 reg_w_riv(dev, req, idx, val);
594 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
595 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300596
597 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
598
599 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300600 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300601 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
602}
603
604static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
605 __u16 req,
606 __u16 idx, __u16 val, __u8 stat, __u8 count)
607{
608 struct usb_device *dev = gspca_dev->dev;
609 __u8 status;
610 __u8 endcode;
611
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300612 reg_w_riv(dev, req, idx, val);
613 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300614 endcode = stat;
615 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
616 if (!count)
617 return;
618 count = 200;
619 while (--count > 0) {
620 msleep(10);
621 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300622/* reg_w_riv(dev, req, idx, val); */
623 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624 if (status == endcode) {
625 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
626 status, 200 - count);
627 break;
628 }
629 }
630}
631
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300632static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300634 int count = 10;
635
636 while (--count > 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300637 reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
638 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639 break;
640 msleep(10);
641 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300642 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300643}
644
645static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
646{
647 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300648 int count = 50;
649
650 while (--count > 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300651 reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
652 if (gspca_dev->usb_buf[0] != 0) {
653 gspca_dev->usb_buf[0] = 0;
654 reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
655 reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
656 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657 break;
658 }
659 msleep(10);
660 }
661}
662
663static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
664{
665 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300666 __u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300668 data = kmalloc(64, GFP_KERNEL);
669 reg_r(dev, 0x20, 0, data, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300671 data[0], data[1], data[2], data[3], data[4]);
672 reg_r(dev, 0x23, 0, data, 64);
673 reg_r(dev, 0x23, 1, data, 64);
674 kfree(data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300675}
676
677static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
678{
679 struct sd *sd = (struct sd *) gspca_dev;
680 struct usb_device *dev = gspca_dev->dev;
681 __u8 Size;
682 __u8 Type;
683 int rc;
684
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300685 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686 Type = 0;
687 switch (sd->bridge) {
688 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300689 reg_w(dev, 0x31, 0, 0, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300691 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300693 gspca_dev->usb_buf[0] = 2; /* type */
694 reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
695 reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300696
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300697 gspca_dev->usb_buf[0] = Size;
698 reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
699 reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
700 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701
702 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 reg_w(dev, 0x31, 0, 4, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300705 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 break;
707 default:
708/* case BRIDGE_SPCA504B: */
709/* case BRIDGE_SPCA536: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300710 gspca_dev->usb_buf[0] = Size;
711 reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
712 reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713 Type = 6;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300714 gspca_dev->usb_buf[0] = Type;
715 reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
716 reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */
717 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718 break;
719 case BRIDGE_SPCA504:
720 Size += 3;
721 if (sd->subtype == AiptekMiniPenCam13) {
722 /* spca504a aiptek */
723 spca504A_acknowledged_command(gspca_dev,
724 0x08, Size, 0,
725 0x80 | (Size & 0x0f), 1);
726 spca504A_acknowledged_command(gspca_dev,
727 1, 3, 0, 0x9f, 0);
728 } else {
729 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
730 }
731 break;
732 case BRIDGE_SPCA504C:
733 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300734 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
735 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 break;
737 }
738}
739
740static void spca504_wait_status(struct gspca_dev *gspca_dev)
741{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 int cnt;
743
744 cnt = 256;
745 while (--cnt > 0) {
746 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300747 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300748 return;
749 msleep(10);
750 }
751}
752
753static void spca504B_setQtable(struct gspca_dev *gspca_dev)
754{
755 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300757 gspca_dev->usb_buf[0] = 3;
758 reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
759 reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
760 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761}
762
763static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
764{
765 struct sd *sd = (struct sd *) gspca_dev;
766 struct usb_device *dev = gspca_dev->dev;
767 int pollreg = 1;
768
769 switch (sd->bridge) {
770 case BRIDGE_SPCA504:
771 case BRIDGE_SPCA504C:
772 pollreg = 0;
773 /* fall thru */
774 default:
775/* case BRIDGE_SPCA533: */
776/* case BRIDGE_SPCA504B: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300777 reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */
778 reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */
779 reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */
780 reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */
781 reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */
782 reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 break;
784 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300785 reg_w(dev, 0, 0, 0x20f0, NULL, 0);
786 reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
787 reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
788 reg_w(dev, 0, 1, 0x20f4, NULL, 0);
789 reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
790 reg_w(dev, 0, 0, 0x2089, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791 break;
792 }
793 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300794 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795}
796
797/* this function is called at probe time */
798static int sd_config(struct gspca_dev *gspca_dev,
799 const struct usb_device_id *id)
800{
801 struct sd *sd = (struct sd *) gspca_dev;
802 struct usb_device *dev = gspca_dev->dev;
803 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804
805 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 cam->epaddr = 0x01;
807
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300808 sd->bridge = id->driver_info >> 8;
809 sd->subtype = id->driver_info;
810
811 if (sd->subtype == AiptekMiniPenCam13) {
812/* try to get the firmware as some cam answer 2.0.1.2.2
813 * and should be a spca504b then overwrite that setting */
814 reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
815 switch (gspca_dev->usb_buf[0]) {
816 case 1:
817 break; /* (right bridge/subtype) */
818 case 2:
819 sd->bridge = BRIDGE_SPCA504B;
820 sd->subtype = 0;
821 break;
822 default:
823 return -ENODEV;
824 }
825 }
826
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 switch (sd->bridge) {
828 default:
829/* case BRIDGE_SPCA504B: */
830/* case BRIDGE_SPCA504: */
831/* case BRIDGE_SPCA536: */
832 cam->cam_mode = vga_mode;
833 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
834 break;
835 case BRIDGE_SPCA533:
836 cam->cam_mode = custom_mode;
837 cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
838 break;
839 case BRIDGE_SPCA504C:
840 cam->cam_mode = vga_mode2;
841 cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
842 break;
843 }
844 sd->qindex = 5; /* set the quantization table */
845 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
846 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
847 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
848 return 0;
849}
850
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300851/* this function is called at probe and resume time */
852static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300853{
854 struct sd *sd = (struct sd *) gspca_dev;
855 struct usb_device *dev = gspca_dev->dev;
856 int rc;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 __u8 i;
858 __u8 info[6];
859 int err_code;
860
861 switch (sd->bridge) {
862 case BRIDGE_SPCA504B:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300863 reg_w(dev, 0x1d, 0, 0, NULL, 0);
864 reg_w(dev, 0, 1, 0x2306, NULL, 0);
865 reg_w(dev, 0, 0, 0x0d04, NULL, 0);
866 reg_w(dev, 0, 0, 0x2000, NULL, 0);
867 reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
868 reg_w(dev, 0, 0, 0x2306, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869 /* fall thru */
870 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300871 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 spca50x_GetFirmware(gspca_dev);
873 break;
874 case BRIDGE_SPCA536:
875 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300876 reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
877 gspca_dev->usb_buf[0] = 0;
878 reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
879 reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
880 rc = spca504B_PollingDataReady(gspca_dev);
881 reg_w(dev, 0x34, 0, 0, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 spca504B_WaitCmdStatus(gspca_dev);
883 break;
884 case BRIDGE_SPCA504C: /* pccam600 */
885 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300886 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
887 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888 spca504_wait_status(gspca_dev);
889 if (sd->subtype == LogitechClickSmart420)
890 write_vector(gspca_dev,
891 spca504A_clicksmart420_open_data);
892 else
893 write_vector(gspca_dev, spca504_pccam600_open_data);
894 err_code = spca50x_setup_qtable(gspca_dev,
895 0x00, 0x2800,
896 0x2840, qtable_creative_pccam);
897 if (err_code < 0) {
898 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
899 return err_code;
900 }
901 break;
902 default:
903/* case BRIDGE_SPCA504: */
904 PDEBUG(D_STREAM, "Opening SPCA504");
905 if (sd->subtype == AiptekMiniPenCam13) {
906 /*****************************/
907 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300908 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300909 PDEBUG(D_STREAM,
910 "Read info: %d %d %d %d %d %d."
911 " Should be 1,0,2,2,0,0",
912 info[0], info[1], info[2],
913 info[3], info[4], info[5]);
914 /* spca504a aiptek */
915 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
916 spca504A_acknowledged_command(gspca_dev, 0x24,
917 8, 3, 0x9e, 1);
918 /* Twice sequencial need status 0xff->0x9e->0x9d */
919 spca504A_acknowledged_command(gspca_dev, 0x24,
920 8, 3, 0x9e, 0);
921
922 spca504A_acknowledged_command(gspca_dev, 0x24,
923 0, 0, 0x9d, 1);
924 /******************************/
925 /* spca504a aiptek */
926 spca504A_acknowledged_command(gspca_dev, 0x08,
927 6, 0, 0x86, 1);
928/* reg_write (dev, 0, 0x2000, 0); */
929/* reg_write (dev, 0, 0x2883, 1); */
930/* spca504A_acknowledged_command (gspca_dev, 0x08,
931 6, 0, 0x86, 1); */
932/* spca504A_acknowledged_command (gspca_dev, 0x24,
933 0, 0, 0x9D, 1); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300934 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
935 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936 spca504A_acknowledged_command(gspca_dev, 0x01,
937 0x0f, 0, 0xff, 0);
938 }
939 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300940 reg_w_riv(dev, 0, 0x2000, 0);
941 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300942 err_code = spca50x_setup_qtable(gspca_dev,
943 0x00, 0x2800,
944 0x2840,
945 qtable_spca504_default);
946 if (err_code < 0) {
947 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
948 return err_code;
949 }
950 break;
951 }
952 return 0;
953}
954
955static void sd_start(struct gspca_dev *gspca_dev)
956{
957 struct sd *sd = (struct sd *) gspca_dev;
958 struct usb_device *dev = gspca_dev->dev;
959 int rc;
960 int enable;
961 __u8 i;
962 __u8 info[6];
963
964 if (sd->bridge == BRIDGE_SPCA504B)
965 spca504B_setQtable(gspca_dev);
966 spca504B_SetSizeType(gspca_dev);
967 switch (sd->bridge) {
968 default:
969/* case BRIDGE_SPCA504B: */
970/* case BRIDGE_SPCA533: */
971/* case BRIDGE_SPCA536: */
972 if (sd->subtype == MegapixV4 ||
973 sd->subtype == LogitechClickSmart820) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300974 reg_w(dev, 0xf0, 0, 0, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300975 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300976 reg_r(dev, 0xf0, 4, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977 spca504B_WaitCmdStatus(gspca_dev);
978 } else {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300979 reg_w(dev, 0x31, 0, 4, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300981 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982 }
983 break;
984 case BRIDGE_SPCA504:
985 if (sd->subtype == AiptekMiniPenCam13) {
986 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300987 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988 PDEBUG(D_STREAM,
989 "Read info: %d %d %d %d %d %d."
990 " Should be 1,0,2,2,0,0",
991 info[0], info[1], info[2],
992 info[3], info[4], info[5]);
993 /* spca504a aiptek */
994 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
995 spca504A_acknowledged_command(gspca_dev, 0x24,
996 8, 3, 0x9e, 1);
997 /* Twice sequencial need status 0xff->0x9e->0x9d */
998 spca504A_acknowledged_command(gspca_dev, 0x24,
999 8, 3, 0x9e, 0);
1000 spca504A_acknowledged_command(gspca_dev, 0x24,
1001 0, 0, 0x9d, 1);
1002 } else {
1003 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1004 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001005 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001006 PDEBUG(D_STREAM,
1007 "Read info: %d %d %d %d %d %d."
1008 " Should be 1,0,2,2,0,0",
1009 info[0], info[1], info[2],
1010 info[3], info[4], info[5]);
1011 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1012 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1013 }
1014 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001015 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1016 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017 break;
1018 case BRIDGE_SPCA504C:
1019 if (sd->subtype == LogitechClickSmart420) {
1020 write_vector(gspca_dev,
1021 spca504A_clicksmart420_init_data);
1022 } else {
1023 write_vector(gspca_dev, spca504_pccam600_init_data);
1024 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001025 enable = (sd->autogain ? 0x04 : 0x01);
1026 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1027 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001028
1029 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001030 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1031 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001032 spca504B_SetSizeType(gspca_dev);
1033 break;
1034 }
1035 sp5xx_initContBrigHueRegisters(gspca_dev);
1036}
1037
1038static void sd_stopN(struct gspca_dev *gspca_dev)
1039{
1040 struct sd *sd = (struct sd *) gspca_dev;
1041 struct usb_device *dev = gspca_dev->dev;
1042
1043 switch (sd->bridge) {
1044 default:
1045/* case BRIDGE_SPCA533: */
1046/* case BRIDGE_SPCA536: */
1047/* case BRIDGE_SPCA504B: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001048 reg_w(dev, 0x31, 0, 0, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001049 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001050 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001051 break;
1052 case BRIDGE_SPCA504:
1053 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001054 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055
1056 if (sd->subtype == AiptekMiniPenCam13) {
1057 /* spca504a aiptek */
1058/* spca504A_acknowledged_command(gspca_dev, 0x08,
1059 6, 0, 0x86, 1); */
1060 spca504A_acknowledged_command(gspca_dev, 0x24,
1061 0x00, 0x00, 0x9d, 1);
1062 spca504A_acknowledged_command(gspca_dev, 0x01,
1063 0x0f, 0x00, 0xff, 1);
1064 } else {
1065 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001066 reg_w_riv(dev, 0x01, 0x000f, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001067 }
1068 break;
1069 }
1070}
1071
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001072static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1073 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001074 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075 int len) /* iso packet length */
1076{
1077 struct sd *sd = (struct sd *) gspca_dev;
1078 int i, sof = 0;
1079 unsigned char *s, *d;
1080 static unsigned char ffd9[] = {0xff, 0xd9};
1081
1082/* frames are jpeg 4.1.1 without 0xff escape */
1083 switch (sd->bridge) {
1084 case BRIDGE_SPCA533:
1085 if (data[0] == 0xff) {
1086 if (data[1] != 0x01) { /* drop packet */
1087/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1088 return;
1089 }
1090 sof = 1;
1091 data += SPCA533_OFFSET_DATA;
1092 len -= SPCA533_OFFSET_DATA;
1093 } else {
1094 data += 1;
1095 len -= 1;
1096 }
1097 break;
1098 case BRIDGE_SPCA536:
1099 if (data[0] == 0xff) {
1100 sof = 1;
1101 data += SPCA536_OFFSET_DATA;
1102 len -= SPCA536_OFFSET_DATA;
1103 } else {
1104 data += 2;
1105 len -= 2;
1106 }
1107 break;
1108 default:
1109/* case BRIDGE_SPCA504: */
1110/* case BRIDGE_SPCA504B: */
1111 switch (data[0]) {
1112 case 0xfe: /* start of frame */
1113 sof = 1;
1114 data += SPCA50X_OFFSET_DATA;
1115 len -= SPCA50X_OFFSET_DATA;
1116 break;
1117 case 0xff: /* drop packet */
1118/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1119 return;
1120 default:
1121 data += 1;
1122 len -= 1;
1123 break;
1124 }
1125 break;
1126 case BRIDGE_SPCA504C:
1127 switch (data[0]) {
1128 case 0xfe: /* start of frame */
1129 sof = 1;
1130 data += SPCA504_PCCAM600_OFFSET_DATA;
1131 len -= SPCA504_PCCAM600_OFFSET_DATA;
1132 break;
1133 case 0xff: /* drop packet */
1134/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1135 return;
1136 default:
1137 data += 1;
1138 len -= 1;
1139 break;
1140 }
1141 break;
1142 }
1143 if (sof) { /* start of frame */
1144 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1145 ffd9, 2);
1146
1147 /* put the JPEG header in the new frame */
1148 jpeg_put_header(gspca_dev, frame,
1149 ((struct sd *) gspca_dev)->qindex,
1150 0x22);
1151 }
1152
1153 /* add 0x00 after 0xff */
1154 for (i = len; --i >= 0; )
1155 if (data[i] == 0xff)
1156 break;
1157 if (i < 0) { /* no 0xff */
1158 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1159 return;
1160 }
1161 s = data;
1162 d = sd->packet;
1163 for (i = 0; i < len; i++) {
1164 *d++ = *s++;
1165 if (s[-1] == 0xff)
1166 *d++ = 0x00;
1167 }
1168 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1169 sd->packet, d - sd->packet);
1170}
1171
1172static void setbrightness(struct gspca_dev *gspca_dev)
1173{
1174 struct sd *sd = (struct sd *) gspca_dev;
1175 struct usb_device *dev = gspca_dev->dev;
1176
1177 switch (sd->bridge) {
1178 default:
1179/* case BRIDGE_SPCA533: */
1180/* case BRIDGE_SPCA504B: */
1181/* case BRIDGE_SPCA504: */
1182/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001183 reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001184 break;
1185 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001186 reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001187 break;
1188 }
1189}
1190
1191static void getbrightness(struct gspca_dev *gspca_dev)
1192{
1193 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001194 __u16 brightness = 0;
1195
1196 switch (sd->bridge) {
1197 default:
1198/* case BRIDGE_SPCA533: */
1199/* case BRIDGE_SPCA504B: */
1200/* case BRIDGE_SPCA504: */
1201/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001202 brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001203 break;
1204 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001205 brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001206 break;
1207 }
1208 sd->brightness = ((brightness & 0xff) - 128) % 255;
1209}
1210
1211static void setcontrast(struct gspca_dev *gspca_dev)
1212{
1213 struct sd *sd = (struct sd *) gspca_dev;
1214 struct usb_device *dev = gspca_dev->dev;
1215
1216 switch (sd->bridge) {
1217 default:
1218/* case BRIDGE_SPCA533: */
1219/* case BRIDGE_SPCA504B: */
1220/* case BRIDGE_SPCA504: */
1221/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001222 reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001223 break;
1224 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001225 reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226 break;
1227 }
1228}
1229
1230static void getcontrast(struct gspca_dev *gspca_dev)
1231{
1232 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001233
1234 switch (sd->bridge) {
1235 default:
1236/* case BRIDGE_SPCA533: */
1237/* case BRIDGE_SPCA504B: */
1238/* case BRIDGE_SPCA504: */
1239/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001240 sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001241 break;
1242 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001243 sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244 break;
1245 }
1246}
1247
1248static void setcolors(struct gspca_dev *gspca_dev)
1249{
1250 struct sd *sd = (struct sd *) gspca_dev;
1251 struct usb_device *dev = gspca_dev->dev;
1252
1253 switch (sd->bridge) {
1254 default:
1255/* case BRIDGE_SPCA533: */
1256/* case BRIDGE_SPCA504B: */
1257/* case BRIDGE_SPCA504: */
1258/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001259 reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001260 break;
1261 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001262 reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001263 break;
1264 }
1265}
1266
1267static void getcolors(struct gspca_dev *gspca_dev)
1268{
1269 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001270
1271 switch (sd->bridge) {
1272 default:
1273/* case BRIDGE_SPCA533: */
1274/* case BRIDGE_SPCA504B: */
1275/* case BRIDGE_SPCA504: */
1276/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001277 sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001278 break;
1279 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001280 sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001281 break;
1282 }
1283}
1284
1285static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1286{
1287 struct sd *sd = (struct sd *) gspca_dev;
1288
1289 sd->brightness = val;
1290 if (gspca_dev->streaming)
1291 setbrightness(gspca_dev);
1292 return 0;
1293}
1294
1295static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1296{
1297 struct sd *sd = (struct sd *) gspca_dev;
1298
1299 getbrightness(gspca_dev);
1300 *val = sd->brightness;
1301 return 0;
1302}
1303
1304static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1305{
1306 struct sd *sd = (struct sd *) gspca_dev;
1307
1308 sd->contrast = val;
1309 if (gspca_dev->streaming)
1310 setcontrast(gspca_dev);
1311 return 0;
1312}
1313
1314static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1315{
1316 struct sd *sd = (struct sd *) gspca_dev;
1317
1318 getcontrast(gspca_dev);
1319 *val = sd->contrast;
1320 return 0;
1321}
1322
1323static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1324{
1325 struct sd *sd = (struct sd *) gspca_dev;
1326
1327 sd->colors = val;
1328 if (gspca_dev->streaming)
1329 setcolors(gspca_dev);
1330 return 0;
1331}
1332
1333static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1334{
1335 struct sd *sd = (struct sd *) gspca_dev;
1336
1337 getcolors(gspca_dev);
1338 *val = sd->colors;
1339 return 0;
1340}
1341
1342static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1343{
1344 struct sd *sd = (struct sd *) gspca_dev;
1345
1346 sd->autogain = val;
1347 return 0;
1348}
1349
1350static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1351{
1352 struct sd *sd = (struct sd *) gspca_dev;
1353
1354 *val = sd->autogain;
1355 return 0;
1356}
1357
1358/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001359static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001360 .name = MODULE_NAME,
1361 .ctrls = sd_ctrls,
1362 .nctrls = ARRAY_SIZE(sd_ctrls),
1363 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001364 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001365 .start = sd_start,
1366 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001367 .pkt_scan = sd_pkt_scan,
1368};
1369
1370/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001371#define BS(bridge, subtype) \
1372 .driver_info = (BRIDGE_ ## bridge << 8) \
1373 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001374static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001375 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1376 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1377 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1378 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1379 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1380 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1381 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1382 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1383 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1384 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1385 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1386 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1387 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1388 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1389 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1390 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1391 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1392 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1393 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1394 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1395 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1396 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1397 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1398 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1399 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1400 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1401 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1402 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1403 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1404 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1405 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1406 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1407 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1408 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1409 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1410 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1411 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1412 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1413 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1414 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1415 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1416 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1417 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1418 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1419 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1420 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1421 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1422 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1423 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1424 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1425 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1426 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1427 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1428 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1429 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1430 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1431 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001432 {}
1433};
1434MODULE_DEVICE_TABLE(usb, device_table);
1435
1436/* -- device connect -- */
1437static int sd_probe(struct usb_interface *intf,
1438 const struct usb_device_id *id)
1439{
1440 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1441 THIS_MODULE);
1442}
1443
1444static struct usb_driver sd_driver = {
1445 .name = MODULE_NAME,
1446 .id_table = device_table,
1447 .probe = sd_probe,
1448 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001449#ifdef CONFIG_PM
1450 .suspend = gspca_suspend,
1451 .resume = gspca_resume,
1452#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001453};
1454
1455/* -- module insert / remove -- */
1456static int __init sd_mod_init(void)
1457{
1458 if (usb_register(&sd_driver) < 0)
1459 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001460 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001461 return 0;
1462}
1463static void __exit sd_mod_exit(void)
1464{
1465 usb_deregister(&sd_driver);
1466 PDEBUG(D_PROBE, "deregistered");
1467}
1468
1469module_init(sd_mod_init);
1470module_exit(sd_mod_exit);