blob: 1cfcc6c4955874ab0bb05da32ef387136967c701 [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 Moine8295d992008-09-03 17:12:19 -0300452/* read <len> bytes to gspca_dev->usb_buf */
453static void reg_r(struct gspca_dev *gspca_dev,
454 __u16 req,
455 __u16 index,
456 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300458#ifdef GSPCA_DEBUG
459 if (len > USB_BUF_SZ) {
460 err("reg_r: buffer overflow");
461 return;
462 }
463#endif
464 usb_control_msg(gspca_dev->dev,
465 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466 req,
467 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
468 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300469 index,
470 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 500);
472}
473
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300474/* write <len> bytes from gspca_dev->usb_buf */
475static void reg_w(struct gspca_dev *gspca_dev,
476 __u16 req,
477 __u16 value,
478 __u16 index,
479 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300480{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300481#ifdef GSPCA_DEBUG
482 if (len > USB_BUF_SZ) {
483 err("reg_w: buffer overflow");
484 return;
485 }
486#endif
487 usb_control_msg(gspca_dev->dev,
488 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 req,
490 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300491 value, index,
492 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 500);
494}
495
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300496/* write req / index / value */
497static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498 __u16 req, __u16 index, __u16 value)
499{
500 int ret;
501
502 ret = usb_control_msg(dev,
503 usb_sndctrlpipe(dev, 0),
504 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300505 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300507 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300508 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 if (ret < 0)
510 PDEBUG(D_ERR, "reg write: error %d", ret);
511 return ret;
512}
513
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300514/* read 1 byte */
515static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300516 __u16 value) /* wValue */
517{
518 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300520 ret = usb_control_msg(gspca_dev->dev,
521 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522 0x20, /* request */
523 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
524 value,
525 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 500); /* timeout */
528 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 return 0;
531 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533}
534
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535/* read 1 or 2 bytes - returns < 0 if error */
536static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 __u16 req, /* bRequest */
538 __u16 index, /* wIndex */
539 __u16 length) /* wLength (1 or 2 only) */
540{
541 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 gspca_dev->usb_buf[1] = 0;
544 ret = usb_control_msg(gspca_dev->dev,
545 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 req,
547 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
548 0, /* value */
549 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 500);
552 if (ret < 0) {
553 PDEBUG(D_ERR, "reg_read err %d", ret);
554 return -1;
555 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300556 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557}
558
559static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300560 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561{
562 struct usb_device *dev = gspca_dev->dev;
563 int ret, i = 0;
564
565 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300566 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567 if (ret < 0) {
568 PDEBUG(D_ERR,
569 "Register write failed for 0x%x,0x%x,0x%x",
570 data[i][0], data[i][1], data[i][2]);
571 return ret;
572 }
573 i++;
574 }
575 return 0;
576}
577
578static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
579 unsigned int request,
580 unsigned int ybase,
581 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300582 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300583{
584 struct usb_device *dev = gspca_dev->dev;
585 int i, err;
586
587 /* loop over y components */
588 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300589 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590 if (err < 0)
591 return err;
592 }
593
594 /* loop over c components */
595 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300596 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597 if (err < 0)
598 return err;
599 }
600 return 0;
601}
602
603static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
604 __u16 req, __u16 idx, __u16 val)
605{
606 struct usb_device *dev = gspca_dev->dev;
607 __u8 notdone;
608
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300609 reg_w_riv(dev, req, idx, val);
610 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
611 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612
613 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
614
615 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300616 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
618}
619
620static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
621 __u16 req,
622 __u16 idx, __u16 val, __u8 stat, __u8 count)
623{
624 struct usb_device *dev = gspca_dev->dev;
625 __u8 status;
626 __u8 endcode;
627
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_w_riv(dev, req, idx, val);
629 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630 endcode = stat;
631 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
632 if (!count)
633 return;
634 count = 200;
635 while (--count > 0) {
636 msleep(10);
637 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300638/* reg_w_riv(dev, req, idx, val); */
639 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300640 if (status == endcode) {
641 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
642 status, 200 - count);
643 break;
644 }
645 }
646}
647
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300648static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300649{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300650 int count = 10;
651
652 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300653 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300654 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300655 break;
656 msleep(10);
657 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300658 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300659}
660
661static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
662{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300663 int count = 50;
664
665 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300666 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300667 if (gspca_dev->usb_buf[0] != 0) {
668 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300669 reg_w(gspca_dev, 0x21, 0, 1, 1);
670 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300671 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672 break;
673 }
674 msleep(10);
675 }
676}
677
678static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
679{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300680 __u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300681
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300682 data = gspca_dev->usb_buf;
683 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300684 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300685 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300686 reg_r(gspca_dev, 0x23, 0, 64);
687 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688}
689
690static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
691{
692 struct sd *sd = (struct sd *) gspca_dev;
693 struct usb_device *dev = gspca_dev->dev;
694 __u8 Size;
695 __u8 Type;
696 int rc;
697
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300698 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699 Type = 0;
700 switch (sd->bridge) {
701 case BRIDGE_SPCA533:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300702 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300703 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300704 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300706 gspca_dev->usb_buf[0] = 2; /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300707 reg_w(gspca_dev, 0x24, 0, 8, 1);
708 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300709
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300710 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300711 reg_w(gspca_dev, 0x25, 0, 4, 1);
712 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300713 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300714
715 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300716 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300718 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 break;
720 default:
721/* case BRIDGE_SPCA504B: */
722/* case BRIDGE_SPCA536: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300723 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300724 reg_w(gspca_dev, 0x25, 0, 4, 1);
725 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726 Type = 6;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300727 gspca_dev->usb_buf[0] = Type;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300728 reg_w(gspca_dev, 0x27, 0, 0, 1);
729 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300730 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731 break;
732 case BRIDGE_SPCA504:
733 Size += 3;
734 if (sd->subtype == AiptekMiniPenCam13) {
735 /* spca504a aiptek */
736 spca504A_acknowledged_command(gspca_dev,
737 0x08, Size, 0,
738 0x80 | (Size & 0x0f), 1);
739 spca504A_acknowledged_command(gspca_dev,
740 1, 3, 0, 0x9f, 0);
741 } else {
742 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
743 }
744 break;
745 case BRIDGE_SPCA504C:
746 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300747 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
748 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749 break;
750 }
751}
752
753static void spca504_wait_status(struct gspca_dev *gspca_dev)
754{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300755 int cnt;
756
757 cnt = 256;
758 while (--cnt > 0) {
759 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300760 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761 return;
762 msleep(10);
763 }
764}
765
766static void spca504B_setQtable(struct gspca_dev *gspca_dev)
767{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300768 gspca_dev->usb_buf[0] = 3;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300769 reg_w(gspca_dev, 0x26, 0, 0, 1);
770 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300771 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772}
773
774static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
775{
776 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300777 int pollreg = 1;
778
779 switch (sd->bridge) {
780 case BRIDGE_SPCA504:
781 case BRIDGE_SPCA504C:
782 pollreg = 0;
783 /* fall thru */
784 default:
785/* case BRIDGE_SPCA533: */
786/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300787 reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
788 reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
789 reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
790 reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
791 reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
792 reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300793 break;
794 case BRIDGE_SPCA536:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300795 reg_w(gspca_dev, 0, 0, 0x20f0, 0);
796 reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
797 reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
798 reg_w(gspca_dev, 0, 1, 0x20f4, 0);
799 reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
800 reg_w(gspca_dev, 0, 0, 0x2089, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 break;
802 }
803 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300804 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300805}
806
807/* this function is called at probe time */
808static int sd_config(struct gspca_dev *gspca_dev,
809 const struct usb_device_id *id)
810{
811 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300812 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813
814 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 cam->epaddr = 0x01;
816
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300817 sd->bridge = id->driver_info >> 8;
818 sd->subtype = id->driver_info;
819
820 if (sd->subtype == AiptekMiniPenCam13) {
821/* try to get the firmware as some cam answer 2.0.1.2.2
822 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300823 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300824 switch (gspca_dev->usb_buf[0]) {
825 case 1:
826 break; /* (right bridge/subtype) */
827 case 2:
828 sd->bridge = BRIDGE_SPCA504B;
829 sd->subtype = 0;
830 break;
831 default:
832 return -ENODEV;
833 }
834 }
835
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 switch (sd->bridge) {
837 default:
838/* case BRIDGE_SPCA504B: */
839/* case BRIDGE_SPCA504: */
840/* case BRIDGE_SPCA536: */
841 cam->cam_mode = vga_mode;
842 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
843 break;
844 case BRIDGE_SPCA533:
845 cam->cam_mode = custom_mode;
846 cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
847 break;
848 case BRIDGE_SPCA504C:
849 cam->cam_mode = vga_mode2;
850 cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
851 break;
852 }
853 sd->qindex = 5; /* set the quantization table */
854 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
855 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
856 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
857 return 0;
858}
859
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300860/* this function is called at probe and resume time */
861static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862{
863 struct sd *sd = (struct sd *) gspca_dev;
864 struct usb_device *dev = gspca_dev->dev;
865 int rc;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866 __u8 i;
867 __u8 info[6];
868 int err_code;
869
870 switch (sd->bridge) {
871 case BRIDGE_SPCA504B:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300872 reg_w(gspca_dev, 0x1d, 0, 0, 0);
873 reg_w(gspca_dev, 0, 1, 0x2306, 0);
874 reg_w(gspca_dev, 0, 0, 0x0d04, 0);
875 reg_w(gspca_dev, 0, 0, 0x2000, 0);
876 reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
877 reg_w(gspca_dev, 0, 0, 0x2306, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878 /* fall thru */
879 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300880 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881 spca50x_GetFirmware(gspca_dev);
882 break;
883 case BRIDGE_SPCA536:
884 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300885 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300886 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300887 reg_w(gspca_dev, 0x24, 0, 0, 1);
888 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300889 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300890 reg_w(gspca_dev, 0x34, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300891 spca504B_WaitCmdStatus(gspca_dev);
892 break;
893 case BRIDGE_SPCA504C: /* pccam600 */
894 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300895 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
896 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300897 spca504_wait_status(gspca_dev);
898 if (sd->subtype == LogitechClickSmart420)
899 write_vector(gspca_dev,
900 spca504A_clicksmart420_open_data);
901 else
902 write_vector(gspca_dev, spca504_pccam600_open_data);
903 err_code = spca50x_setup_qtable(gspca_dev,
904 0x00, 0x2800,
905 0x2840, qtable_creative_pccam);
906 if (err_code < 0) {
907 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
908 return err_code;
909 }
910 break;
911 default:
912/* case BRIDGE_SPCA504: */
913 PDEBUG(D_STREAM, "Opening SPCA504");
914 if (sd->subtype == AiptekMiniPenCam13) {
915 /*****************************/
916 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300917 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 PDEBUG(D_STREAM,
919 "Read info: %d %d %d %d %d %d."
920 " Should be 1,0,2,2,0,0",
921 info[0], info[1], info[2],
922 info[3], info[4], info[5]);
923 /* spca504a aiptek */
924 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
925 spca504A_acknowledged_command(gspca_dev, 0x24,
926 8, 3, 0x9e, 1);
927 /* Twice sequencial need status 0xff->0x9e->0x9d */
928 spca504A_acknowledged_command(gspca_dev, 0x24,
929 8, 3, 0x9e, 0);
930
931 spca504A_acknowledged_command(gspca_dev, 0x24,
932 0, 0, 0x9d, 1);
933 /******************************/
934 /* spca504a aiptek */
935 spca504A_acknowledged_command(gspca_dev, 0x08,
936 6, 0, 0x86, 1);
937/* reg_write (dev, 0, 0x2000, 0); */
938/* reg_write (dev, 0, 0x2883, 1); */
939/* spca504A_acknowledged_command (gspca_dev, 0x08,
940 6, 0, 0x86, 1); */
941/* spca504A_acknowledged_command (gspca_dev, 0x24,
942 0, 0, 0x9D, 1); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300943 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
944 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300945 spca504A_acknowledged_command(gspca_dev, 0x01,
946 0x0f, 0, 0xff, 0);
947 }
948 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300949 reg_w_riv(dev, 0, 0x2000, 0);
950 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300951 err_code = spca50x_setup_qtable(gspca_dev,
952 0x00, 0x2800,
953 0x2840,
954 qtable_spca504_default);
955 if (err_code < 0) {
956 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
957 return err_code;
958 }
959 break;
960 }
961 return 0;
962}
963
964static void sd_start(struct gspca_dev *gspca_dev)
965{
966 struct sd *sd = (struct sd *) gspca_dev;
967 struct usb_device *dev = gspca_dev->dev;
968 int rc;
969 int enable;
970 __u8 i;
971 __u8 info[6];
972
973 if (sd->bridge == BRIDGE_SPCA504B)
974 spca504B_setQtable(gspca_dev);
975 spca504B_SetSizeType(gspca_dev);
976 switch (sd->bridge) {
977 default:
978/* case BRIDGE_SPCA504B: */
979/* case BRIDGE_SPCA533: */
980/* case BRIDGE_SPCA536: */
981 if (sd->subtype == MegapixV4 ||
982 sd->subtype == LogitechClickSmart820) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300983 reg_w(gspca_dev, 0xf0, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300985 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300986 spca504B_WaitCmdStatus(gspca_dev);
987 } else {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300988 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300989 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300990 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 }
992 break;
993 case BRIDGE_SPCA504:
994 if (sd->subtype == AiptekMiniPenCam13) {
995 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300996 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300997 PDEBUG(D_STREAM,
998 "Read info: %d %d %d %d %d %d."
999 " Should be 1,0,2,2,0,0",
1000 info[0], info[1], info[2],
1001 info[3], info[4], info[5]);
1002 /* spca504a aiptek */
1003 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1004 spca504A_acknowledged_command(gspca_dev, 0x24,
1005 8, 3, 0x9e, 1);
1006 /* Twice sequencial need status 0xff->0x9e->0x9d */
1007 spca504A_acknowledged_command(gspca_dev, 0x24,
1008 8, 3, 0x9e, 0);
1009 spca504A_acknowledged_command(gspca_dev, 0x24,
1010 0, 0, 0x9d, 1);
1011 } else {
1012 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1013 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001014 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 PDEBUG(D_STREAM,
1016 "Read info: %d %d %d %d %d %d."
1017 " Should be 1,0,2,2,0,0",
1018 info[0], info[1], info[2],
1019 info[3], info[4], info[5]);
1020 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1021 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1022 }
1023 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001024 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1025 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001026 break;
1027 case BRIDGE_SPCA504C:
1028 if (sd->subtype == LogitechClickSmart420) {
1029 write_vector(gspca_dev,
1030 spca504A_clicksmart420_init_data);
1031 } else {
1032 write_vector(gspca_dev, spca504_pccam600_init_data);
1033 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001034 enable = (sd->autogain ? 0x04 : 0x01);
1035 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1036 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001037
1038 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001039 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1040 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041 spca504B_SetSizeType(gspca_dev);
1042 break;
1043 }
1044 sp5xx_initContBrigHueRegisters(gspca_dev);
1045}
1046
1047static void sd_stopN(struct gspca_dev *gspca_dev)
1048{
1049 struct sd *sd = (struct sd *) gspca_dev;
1050 struct usb_device *dev = gspca_dev->dev;
1051
1052 switch (sd->bridge) {
1053 default:
1054/* case BRIDGE_SPCA533: */
1055/* case BRIDGE_SPCA536: */
1056/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001057 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001058 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001059 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001060 break;
1061 case BRIDGE_SPCA504:
1062 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001063 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001064
1065 if (sd->subtype == AiptekMiniPenCam13) {
1066 /* spca504a aiptek */
1067/* spca504A_acknowledged_command(gspca_dev, 0x08,
1068 6, 0, 0x86, 1); */
1069 spca504A_acknowledged_command(gspca_dev, 0x24,
1070 0x00, 0x00, 0x9d, 1);
1071 spca504A_acknowledged_command(gspca_dev, 0x01,
1072 0x0f, 0x00, 0xff, 1);
1073 } else {
1074 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001075 reg_w_riv(dev, 0x01, 0x000f, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001076 }
1077 break;
1078 }
1079}
1080
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1082 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001083 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001084 int len) /* iso packet length */
1085{
1086 struct sd *sd = (struct sd *) gspca_dev;
1087 int i, sof = 0;
1088 unsigned char *s, *d;
1089 static unsigned char ffd9[] = {0xff, 0xd9};
1090
1091/* frames are jpeg 4.1.1 without 0xff escape */
1092 switch (sd->bridge) {
1093 case BRIDGE_SPCA533:
1094 if (data[0] == 0xff) {
1095 if (data[1] != 0x01) { /* drop packet */
1096/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1097 return;
1098 }
1099 sof = 1;
1100 data += SPCA533_OFFSET_DATA;
1101 len -= SPCA533_OFFSET_DATA;
1102 } else {
1103 data += 1;
1104 len -= 1;
1105 }
1106 break;
1107 case BRIDGE_SPCA536:
1108 if (data[0] == 0xff) {
1109 sof = 1;
1110 data += SPCA536_OFFSET_DATA;
1111 len -= SPCA536_OFFSET_DATA;
1112 } else {
1113 data += 2;
1114 len -= 2;
1115 }
1116 break;
1117 default:
1118/* case BRIDGE_SPCA504: */
1119/* case BRIDGE_SPCA504B: */
1120 switch (data[0]) {
1121 case 0xfe: /* start of frame */
1122 sof = 1;
1123 data += SPCA50X_OFFSET_DATA;
1124 len -= SPCA50X_OFFSET_DATA;
1125 break;
1126 case 0xff: /* drop packet */
1127/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1128 return;
1129 default:
1130 data += 1;
1131 len -= 1;
1132 break;
1133 }
1134 break;
1135 case BRIDGE_SPCA504C:
1136 switch (data[0]) {
1137 case 0xfe: /* start of frame */
1138 sof = 1;
1139 data += SPCA504_PCCAM600_OFFSET_DATA;
1140 len -= SPCA504_PCCAM600_OFFSET_DATA;
1141 break;
1142 case 0xff: /* drop packet */
1143/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1144 return;
1145 default:
1146 data += 1;
1147 len -= 1;
1148 break;
1149 }
1150 break;
1151 }
1152 if (sof) { /* start of frame */
1153 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1154 ffd9, 2);
1155
1156 /* put the JPEG header in the new frame */
1157 jpeg_put_header(gspca_dev, frame,
1158 ((struct sd *) gspca_dev)->qindex,
1159 0x22);
1160 }
1161
1162 /* add 0x00 after 0xff */
1163 for (i = len; --i >= 0; )
1164 if (data[i] == 0xff)
1165 break;
1166 if (i < 0) { /* no 0xff */
1167 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1168 return;
1169 }
1170 s = data;
1171 d = sd->packet;
1172 for (i = 0; i < len; i++) {
1173 *d++ = *s++;
1174 if (s[-1] == 0xff)
1175 *d++ = 0x00;
1176 }
1177 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1178 sd->packet, d - sd->packet);
1179}
1180
1181static void setbrightness(struct gspca_dev *gspca_dev)
1182{
1183 struct sd *sd = (struct sd *) gspca_dev;
1184 struct usb_device *dev = gspca_dev->dev;
1185
1186 switch (sd->bridge) {
1187 default:
1188/* case BRIDGE_SPCA533: */
1189/* case BRIDGE_SPCA504B: */
1190/* case BRIDGE_SPCA504: */
1191/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001192 reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001193 break;
1194 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001195 reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001196 break;
1197 }
1198}
1199
1200static void getbrightness(struct gspca_dev *gspca_dev)
1201{
1202 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001203 __u16 brightness = 0;
1204
1205 switch (sd->bridge) {
1206 default:
1207/* case BRIDGE_SPCA533: */
1208/* case BRIDGE_SPCA504B: */
1209/* case BRIDGE_SPCA504: */
1210/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001211 brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001212 break;
1213 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001214 brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001215 break;
1216 }
1217 sd->brightness = ((brightness & 0xff) - 128) % 255;
1218}
1219
1220static void setcontrast(struct gspca_dev *gspca_dev)
1221{
1222 struct sd *sd = (struct sd *) gspca_dev;
1223 struct usb_device *dev = gspca_dev->dev;
1224
1225 switch (sd->bridge) {
1226 default:
1227/* case BRIDGE_SPCA533: */
1228/* case BRIDGE_SPCA504B: */
1229/* case BRIDGE_SPCA504: */
1230/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001231 reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001232 break;
1233 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001234 reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001235 break;
1236 }
1237}
1238
1239static void getcontrast(struct gspca_dev *gspca_dev)
1240{
1241 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001242
1243 switch (sd->bridge) {
1244 default:
1245/* case BRIDGE_SPCA533: */
1246/* case BRIDGE_SPCA504B: */
1247/* case BRIDGE_SPCA504: */
1248/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001249 sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001250 break;
1251 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001252 sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001253 break;
1254 }
1255}
1256
1257static void setcolors(struct gspca_dev *gspca_dev)
1258{
1259 struct sd *sd = (struct sd *) gspca_dev;
1260 struct usb_device *dev = gspca_dev->dev;
1261
1262 switch (sd->bridge) {
1263 default:
1264/* case BRIDGE_SPCA533: */
1265/* case BRIDGE_SPCA504B: */
1266/* case BRIDGE_SPCA504: */
1267/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001268 reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001269 break;
1270 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001271 reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001272 break;
1273 }
1274}
1275
1276static void getcolors(struct gspca_dev *gspca_dev)
1277{
1278 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001279
1280 switch (sd->bridge) {
1281 default:
1282/* case BRIDGE_SPCA533: */
1283/* case BRIDGE_SPCA504B: */
1284/* case BRIDGE_SPCA504: */
1285/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001286 sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001287 break;
1288 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001289 sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001290 break;
1291 }
1292}
1293
1294static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1295{
1296 struct sd *sd = (struct sd *) gspca_dev;
1297
1298 sd->brightness = val;
1299 if (gspca_dev->streaming)
1300 setbrightness(gspca_dev);
1301 return 0;
1302}
1303
1304static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1305{
1306 struct sd *sd = (struct sd *) gspca_dev;
1307
1308 getbrightness(gspca_dev);
1309 *val = sd->brightness;
1310 return 0;
1311}
1312
1313static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1314{
1315 struct sd *sd = (struct sd *) gspca_dev;
1316
1317 sd->contrast = val;
1318 if (gspca_dev->streaming)
1319 setcontrast(gspca_dev);
1320 return 0;
1321}
1322
1323static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1324{
1325 struct sd *sd = (struct sd *) gspca_dev;
1326
1327 getcontrast(gspca_dev);
1328 *val = sd->contrast;
1329 return 0;
1330}
1331
1332static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1333{
1334 struct sd *sd = (struct sd *) gspca_dev;
1335
1336 sd->colors = val;
1337 if (gspca_dev->streaming)
1338 setcolors(gspca_dev);
1339 return 0;
1340}
1341
1342static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1343{
1344 struct sd *sd = (struct sd *) gspca_dev;
1345
1346 getcolors(gspca_dev);
1347 *val = sd->colors;
1348 return 0;
1349}
1350
1351static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1352{
1353 struct sd *sd = (struct sd *) gspca_dev;
1354
1355 sd->autogain = val;
1356 return 0;
1357}
1358
1359static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1360{
1361 struct sd *sd = (struct sd *) gspca_dev;
1362
1363 *val = sd->autogain;
1364 return 0;
1365}
1366
1367/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001368static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001369 .name = MODULE_NAME,
1370 .ctrls = sd_ctrls,
1371 .nctrls = ARRAY_SIZE(sd_ctrls),
1372 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001373 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001374 .start = sd_start,
1375 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001376 .pkt_scan = sd_pkt_scan,
1377};
1378
1379/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001380#define BS(bridge, subtype) \
1381 .driver_info = (BRIDGE_ ## bridge << 8) \
1382 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001383static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001384 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1385 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1386 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1387 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1388 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1389 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1390 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1391 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1392 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1393 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1394 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1395 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1396 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1397 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1398 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1399 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1400 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1401 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1402 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1403 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1404 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1405 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1406 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1407 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1408 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1409 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1410 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1411 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1412 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1413 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1414 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1415 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1416 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1417 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1418 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1419 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1420 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1421 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1422 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1423 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1424 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1425 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1426 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1427 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1428 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1429 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1430 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1431 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1432 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1433 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1434 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1435 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1436 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1437 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1438 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1439 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1440 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001441 {}
1442};
1443MODULE_DEVICE_TABLE(usb, device_table);
1444
1445/* -- device connect -- */
1446static int sd_probe(struct usb_interface *intf,
1447 const struct usb_device_id *id)
1448{
1449 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1450 THIS_MODULE);
1451}
1452
1453static struct usb_driver sd_driver = {
1454 .name = MODULE_NAME,
1455 .id_table = device_table,
1456 .probe = sd_probe,
1457 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001458#ifdef CONFIG_PM
1459 .suspend = gspca_suspend,
1460 .resume = gspca_resume,
1461#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001462};
1463
1464/* -- module insert / remove -- */
1465static int __init sd_mod_init(void)
1466{
1467 if (usb_register(&sd_driver) < 0)
1468 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001469 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001470 return 0;
1471}
1472static void __exit sd_mod_exit(void)
1473{
1474 usb_deregister(&sd_driver);
1475 PDEBUG(D_PROBE, "deregistered");
1476}
1477
1478module_init(sd_mod_init);
1479module_exit(sd_mod_exit);