blob: 9623f294bdac1aada92418a7b58f0cbf80a21819 [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 Moine6a7eba22008-06-30 15:50:11 -030035 unsigned char brightness;
36 unsigned char contrast;
37 unsigned char colors;
38 unsigned char autogain;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030039 u8 quality;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -030040#define QUALITY_MIN 70
41#define QUALITY_MAX 95
42#define QUALITY_DEF 85
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030043
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030044 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
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030055
56 u8 *jpeg_hdr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030057};
58
59/* V4L2 controls supported by the driver */
60static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
62static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
64static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
66static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
67static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
68
69static struct ctrl sd_ctrls[] = {
70#define SD_BRIGHTNESS 0
71 {
72 {
73 .id = V4L2_CID_BRIGHTNESS,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Brightness",
76 .minimum = 0,
77 .maximum = 0xff,
78 .step = 1,
79 .default_value = 0,
80 },
81 .set = sd_setbrightness,
82 .get = sd_getbrightness,
83 },
84#define SD_CONTRAST 1
85 {
86 {
87 .id = V4L2_CID_CONTRAST,
88 .type = V4L2_CTRL_TYPE_INTEGER,
89 .name = "Contrast",
90 .minimum = 0,
91 .maximum = 0xff,
92 .step = 1,
93 .default_value = 0x20,
94 },
95 .set = sd_setcontrast,
96 .get = sd_getcontrast,
97 },
98#define SD_COLOR 2
99 {
100 {
101 .id = V4L2_CID_SATURATION,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Color",
104 .minimum = 0,
105 .maximum = 0xff,
106 .step = 1,
107 .default_value = 0x1a,
108 },
109 .set = sd_setcolors,
110 .get = sd_getcolors,
111 },
112#define SD_AUTOGAIN 3
113 {
114 {
115 .id = V4L2_CID_AUTOGAIN,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Auto Gain",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
121 .default_value = 1,
122 },
123 .set = sd_setautogain,
124 .get = sd_getautogain,
125 },
126};
127
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300128static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300129 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
130 .bytesperline = 320,
131 .sizeimage = 320 * 240 * 3 / 8 + 590,
132 .colorspace = V4L2_COLORSPACE_JPEG,
133 .priv = 2},
134 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
135 .bytesperline = 640,
136 .sizeimage = 640 * 480 * 3 / 8 + 590,
137 .colorspace = V4L2_COLORSPACE_JPEG,
138 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300139};
140
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300141static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300142 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
143 .bytesperline = 320,
144 .sizeimage = 320 * 240 * 3 / 8 + 590,
145 .colorspace = V4L2_COLORSPACE_JPEG,
146 .priv = 2},
147 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
148 .bytesperline = 464,
149 .sizeimage = 464 * 480 * 3 / 8 + 590,
150 .colorspace = V4L2_COLORSPACE_JPEG,
151 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152};
153
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300154static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300155 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
156 .bytesperline = 176,
157 .sizeimage = 176 * 144 * 3 / 8 + 590,
158 .colorspace = V4L2_COLORSPACE_JPEG,
159 .priv = 4},
160 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
161 .bytesperline = 320,
162 .sizeimage = 320 * 240 * 3 / 8 + 590,
163 .colorspace = V4L2_COLORSPACE_JPEG,
164 .priv = 3},
165 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
166 .bytesperline = 352,
167 .sizeimage = 352 * 288 * 3 / 8 + 590,
168 .colorspace = V4L2_COLORSPACE_JPEG,
169 .priv = 2},
170 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
171 .bytesperline = 640,
172 .sizeimage = 640 * 480 * 3 / 8 + 590,
173 .colorspace = V4L2_COLORSPACE_JPEG,
174 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300175};
176
177#define SPCA50X_OFFSET_DATA 10
178#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
179#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
180#define SPCA504_PCCAM600_OFFSET_MODE 5
181#define SPCA504_PCCAM600_OFFSET_DATA 14
182 /* Frame packet header offsets for the spca533 */
183#define SPCA533_OFFSET_DATA 16
184#define SPCA533_OFFSET_FRAMSEQ 15
185/* Frame packet header offsets for the spca536 */
186#define SPCA536_OFFSET_DATA 4
187#define SPCA536_OFFSET_FRAMSEQ 1
188
189/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300190static const __u16 spca504_pccam600_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300191/* {0xa0, 0x0000, 0x0503}, * capture mode */
192 {0x00, 0x0000, 0x2000},
193 {0x00, 0x0013, 0x2301},
194 {0x00, 0x0003, 0x2000},
195 {0x00, 0x0001, 0x21ac},
196 {0x00, 0x0001, 0x21a6},
197 {0x00, 0x0000, 0x21a7}, /* brightness */
198 {0x00, 0x0020, 0x21a8}, /* contrast */
199 {0x00, 0x0001, 0x21ac}, /* sat/hue */
200 {0x00, 0x0000, 0x21ad}, /* hue */
201 {0x00, 0x001a, 0x21ae}, /* saturation */
202 {0x00, 0x0002, 0x21a3}, /* gamma */
203 {0x30, 0x0154, 0x0008},
204 {0x30, 0x0004, 0x0006},
205 {0x30, 0x0258, 0x0009},
206 {0x30, 0x0004, 0x0000},
207 {0x30, 0x0093, 0x0004},
208 {0x30, 0x0066, 0x0005},
209 {0x00, 0x0000, 0x2000},
210 {0x00, 0x0013, 0x2301},
211 {0x00, 0x0003, 0x2000},
212 {0x00, 0x0013, 0x2301},
213 {0x00, 0x0003, 0x2000},
214 {}
215};
216
217/* Creative PC-CAM 600 specific open data, sent before using the
218 * generic initialisation data from spca504_open_data.
219 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300220static const __u16 spca504_pccam600_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300221 {0x00, 0x0001, 0x2501},
222 {0x20, 0x0500, 0x0001}, /* snapshot mode */
223 {0x00, 0x0003, 0x2880},
224 {0x00, 0x0001, 0x2881},
225 {}
226};
227
228/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300229static const __u16 spca504A_clicksmart420_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300230/* {0xa0, 0x0000, 0x0503}, * capture mode */
231 {0x00, 0x0000, 0x2000},
232 {0x00, 0x0013, 0x2301},
233 {0x00, 0x0003, 0x2000},
234 {0x00, 0x0001, 0x21ac},
235 {0x00, 0x0001, 0x21a6},
236 {0x00, 0x0000, 0x21a7}, /* brightness */
237 {0x00, 0x0020, 0x21a8}, /* contrast */
238 {0x00, 0x0001, 0x21ac}, /* sat/hue */
239 {0x00, 0x0000, 0x21ad}, /* hue */
240 {0x00, 0x001a, 0x21ae}, /* saturation */
241 {0x00, 0x0002, 0x21a3}, /* gamma */
242 {0x30, 0x0004, 0x000a},
243 {0xb0, 0x0001, 0x0000},
244
245
246 {0x0a1, 0x0080, 0x0001},
247 {0x30, 0x0049, 0x0000},
248 {0x30, 0x0060, 0x0005},
249 {0x0c, 0x0004, 0x0000},
250 {0x00, 0x0000, 0x0000},
251 {0x00, 0x0000, 0x2000},
252 {0x00, 0x0013, 0x2301},
253 {0x00, 0x0003, 0x2000},
254 {0x00, 0x0000, 0x2000},
255
256 {}
257};
258
259/* clicksmart 420 open data ? */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300260static const __u16 spca504A_clicksmart420_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300261 {0x00, 0x0001, 0x2501},
262 {0x20, 0x0502, 0x0000},
263 {0x06, 0x0000, 0x0000},
264 {0x00, 0x0004, 0x2880},
265 {0x00, 0x0001, 0x2881},
266/* look like setting a qTable */
267 {0x00, 0x0006, 0x2800},
268 {0x00, 0x0004, 0x2801},
269 {0x00, 0x0004, 0x2802},
270 {0x00, 0x0006, 0x2803},
271 {0x00, 0x000a, 0x2804},
272 {0x00, 0x0010, 0x2805},
273 {0x00, 0x0014, 0x2806},
274 {0x00, 0x0018, 0x2807},
275 {0x00, 0x0005, 0x2808},
276 {0x00, 0x0005, 0x2809},
277 {0x00, 0x0006, 0x280a},
278 {0x00, 0x0008, 0x280b},
279 {0x00, 0x000a, 0x280c},
280 {0x00, 0x0017, 0x280d},
281 {0x00, 0x0018, 0x280e},
282 {0x00, 0x0016, 0x280f},
283
284 {0x00, 0x0006, 0x2810},
285 {0x00, 0x0005, 0x2811},
286 {0x00, 0x0006, 0x2812},
287 {0x00, 0x000a, 0x2813},
288 {0x00, 0x0010, 0x2814},
289 {0x00, 0x0017, 0x2815},
290 {0x00, 0x001c, 0x2816},
291 {0x00, 0x0016, 0x2817},
292 {0x00, 0x0006, 0x2818},
293 {0x00, 0x0007, 0x2819},
294 {0x00, 0x0009, 0x281a},
295 {0x00, 0x000c, 0x281b},
296 {0x00, 0x0014, 0x281c},
297 {0x00, 0x0023, 0x281d},
298 {0x00, 0x0020, 0x281e},
299 {0x00, 0x0019, 0x281f},
300
301 {0x00, 0x0007, 0x2820},
302 {0x00, 0x0009, 0x2821},
303 {0x00, 0x000f, 0x2822},
304 {0x00, 0x0016, 0x2823},
305 {0x00, 0x001b, 0x2824},
306 {0x00, 0x002c, 0x2825},
307 {0x00, 0x0029, 0x2826},
308 {0x00, 0x001f, 0x2827},
309 {0x00, 0x000a, 0x2828},
310 {0x00, 0x000e, 0x2829},
311 {0x00, 0x0016, 0x282a},
312 {0x00, 0x001a, 0x282b},
313 {0x00, 0x0020, 0x282c},
314 {0x00, 0x002a, 0x282d},
315 {0x00, 0x002d, 0x282e},
316 {0x00, 0x0025, 0x282f},
317
318 {0x00, 0x0014, 0x2830},
319 {0x00, 0x001a, 0x2831},
320 {0x00, 0x001f, 0x2832},
321 {0x00, 0x0023, 0x2833},
322 {0x00, 0x0029, 0x2834},
323 {0x00, 0x0030, 0x2835},
324 {0x00, 0x0030, 0x2836},
325 {0x00, 0x0028, 0x2837},
326 {0x00, 0x001d, 0x2838},
327 {0x00, 0x0025, 0x2839},
328 {0x00, 0x0026, 0x283a},
329 {0x00, 0x0027, 0x283b},
330 {0x00, 0x002d, 0x283c},
331 {0x00, 0x0028, 0x283d},
332 {0x00, 0x0029, 0x283e},
333 {0x00, 0x0028, 0x283f},
334
335 {0x00, 0x0007, 0x2840},
336 {0x00, 0x0007, 0x2841},
337 {0x00, 0x000a, 0x2842},
338 {0x00, 0x0013, 0x2843},
339 {0x00, 0x0028, 0x2844},
340 {0x00, 0x0028, 0x2845},
341 {0x00, 0x0028, 0x2846},
342 {0x00, 0x0028, 0x2847},
343 {0x00, 0x0007, 0x2848},
344 {0x00, 0x0008, 0x2849},
345 {0x00, 0x000a, 0x284a},
346 {0x00, 0x001a, 0x284b},
347 {0x00, 0x0028, 0x284c},
348 {0x00, 0x0028, 0x284d},
349 {0x00, 0x0028, 0x284e},
350 {0x00, 0x0028, 0x284f},
351
352 {0x00, 0x000a, 0x2850},
353 {0x00, 0x000a, 0x2851},
354 {0x00, 0x0016, 0x2852},
355 {0x00, 0x0028, 0x2853},
356 {0x00, 0x0028, 0x2854},
357 {0x00, 0x0028, 0x2855},
358 {0x00, 0x0028, 0x2856},
359 {0x00, 0x0028, 0x2857},
360 {0x00, 0x0013, 0x2858},
361 {0x00, 0x001a, 0x2859},
362 {0x00, 0x0028, 0x285a},
363 {0x00, 0x0028, 0x285b},
364 {0x00, 0x0028, 0x285c},
365 {0x00, 0x0028, 0x285d},
366 {0x00, 0x0028, 0x285e},
367 {0x00, 0x0028, 0x285f},
368
369 {0x00, 0x0028, 0x2860},
370 {0x00, 0x0028, 0x2861},
371 {0x00, 0x0028, 0x2862},
372 {0x00, 0x0028, 0x2863},
373 {0x00, 0x0028, 0x2864},
374 {0x00, 0x0028, 0x2865},
375 {0x00, 0x0028, 0x2866},
376 {0x00, 0x0028, 0x2867},
377 {0x00, 0x0028, 0x2868},
378 {0x00, 0x0028, 0x2869},
379 {0x00, 0x0028, 0x286a},
380 {0x00, 0x0028, 0x286b},
381 {0x00, 0x0028, 0x286c},
382 {0x00, 0x0028, 0x286d},
383 {0x00, 0x0028, 0x286e},
384 {0x00, 0x0028, 0x286f},
385
386 {0x00, 0x0028, 0x2870},
387 {0x00, 0x0028, 0x2871},
388 {0x00, 0x0028, 0x2872},
389 {0x00, 0x0028, 0x2873},
390 {0x00, 0x0028, 0x2874},
391 {0x00, 0x0028, 0x2875},
392 {0x00, 0x0028, 0x2876},
393 {0x00, 0x0028, 0x2877},
394 {0x00, 0x0028, 0x2878},
395 {0x00, 0x0028, 0x2879},
396 {0x00, 0x0028, 0x287a},
397 {0x00, 0x0028, 0x287b},
398 {0x00, 0x0028, 0x287c},
399 {0x00, 0x0028, 0x287d},
400 {0x00, 0x0028, 0x287e},
401 {0x00, 0x0028, 0x287f},
402
403 {0xa0, 0x0000, 0x0503},
404 {}
405};
406
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300407static const __u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408 { /* Q-table Y-components */
409 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
410 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
411 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
412 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
413 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
414 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
415 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
416 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
417 { /* Q-table C-components */
418 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
419 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
420 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
421 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
425 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
426};
427
428/* FIXME: This Q-table is identical to the Creative PC-CAM one,
429 * except for one byte. Possibly a typo?
430 * NWG: 18/05/2003.
431 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300432static const __u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300433 { /* Q-table Y-components */
434 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
435 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
436 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
437 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
438 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
439 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
440 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
441 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
442 },
443 { /* Q-table C-components */
444 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
445 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
446 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
447 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
451 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
452};
453
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300454/* read <len> bytes to gspca_dev->usb_buf */
455static void reg_r(struct gspca_dev *gspca_dev,
456 __u16 req,
457 __u16 index,
458 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300459{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300460#ifdef GSPCA_DEBUG
461 if (len > USB_BUF_SZ) {
462 err("reg_r: buffer overflow");
463 return;
464 }
465#endif
466 usb_control_msg(gspca_dev->dev,
467 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468 req,
469 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
470 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300471 index,
472 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 500);
474}
475
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300476/* write <len> bytes from gspca_dev->usb_buf */
477static void reg_w(struct gspca_dev *gspca_dev,
478 __u16 req,
479 __u16 value,
480 __u16 index,
481 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300483#ifdef GSPCA_DEBUG
484 if (len > USB_BUF_SZ) {
485 err("reg_w: buffer overflow");
486 return;
487 }
488#endif
489 usb_control_msg(gspca_dev->dev,
490 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 req,
492 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300493 value, index,
494 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 500);
496}
497
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300498/* write req / index / value */
499static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 __u16 req, __u16 index, __u16 value)
501{
502 int ret;
503
504 ret = usb_control_msg(dev,
505 usb_sndctrlpipe(dev, 0),
506 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300507 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300509 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300510 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 if (ret < 0)
512 PDEBUG(D_ERR, "reg write: error %d", ret);
513 return ret;
514}
515
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516/* read 1 byte */
517static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300518 __u16 value) /* wValue */
519{
520 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 ret = usb_control_msg(gspca_dev->dev,
523 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 0x20, /* request */
525 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
526 value,
527 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300528 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 500); /* timeout */
530 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 return 0;
533 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535}
536
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300537/* read 1 or 2 bytes - returns < 0 if error */
538static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 __u16 req, /* bRequest */
540 __u16 index, /* wIndex */
541 __u16 length) /* wLength (1 or 2 only) */
542{
543 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300545 gspca_dev->usb_buf[1] = 0;
546 ret = usb_control_msg(gspca_dev->dev,
547 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 req,
549 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
550 0, /* value */
551 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300552 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300553 500);
554 if (ret < 0) {
555 PDEBUG(D_ERR, "reg_read err %d", ret);
556 return -1;
557 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300558 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300559}
560
561static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300562 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300563{
564 struct usb_device *dev = gspca_dev->dev;
565 int ret, i = 0;
566
567 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300568 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569 if (ret < 0) {
570 PDEBUG(D_ERR,
571 "Register write failed for 0x%x,0x%x,0x%x",
572 data[i][0], data[i][1], data[i][2]);
573 return ret;
574 }
575 i++;
576 }
577 return 0;
578}
579
580static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
581 unsigned int request,
582 unsigned int ybase,
583 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300584 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300585{
586 struct usb_device *dev = gspca_dev->dev;
587 int i, err;
588
589 /* loop over y components */
590 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300591 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 if (err < 0)
593 return err;
594 }
595
596 /* loop over c components */
597 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300598 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300599 if (err < 0)
600 return err;
601 }
602 return 0;
603}
604
605static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
606 __u16 req, __u16 idx, __u16 val)
607{
608 struct usb_device *dev = gspca_dev->dev;
609 __u8 notdone;
610
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300611 reg_w_riv(dev, req, idx, val);
612 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
613 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300614
615 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
616
617 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300618 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
620}
621
622static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
623 __u16 req,
624 __u16 idx, __u16 val, __u8 stat, __u8 count)
625{
626 struct usb_device *dev = gspca_dev->dev;
627 __u8 status;
628 __u8 endcode;
629
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300630 reg_w_riv(dev, req, idx, val);
631 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300632 endcode = stat;
633 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
634 if (!count)
635 return;
636 count = 200;
637 while (--count > 0) {
638 msleep(10);
639 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300640/* reg_w_riv(dev, req, idx, val); */
641 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300642 if (status == endcode) {
643 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
644 status, 200 - count);
645 break;
646 }
647 }
648}
649
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300650static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652 int count = 10;
653
654 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300655 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300656 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657 break;
658 msleep(10);
659 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300660 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661}
662
663static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
664{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300665 int count = 50;
666
667 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300668 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300669 if (gspca_dev->usb_buf[0] != 0) {
670 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300671 reg_w(gspca_dev, 0x21, 0, 1, 1);
672 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300673 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 break;
675 }
676 msleep(10);
677 }
678}
679
680static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
681{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300682 __u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300684 data = gspca_dev->usb_buf;
685 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300687 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300688 reg_r(gspca_dev, 0x23, 0, 64);
689 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690}
691
692static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
693{
694 struct sd *sd = (struct sd *) gspca_dev;
695 struct usb_device *dev = gspca_dev->dev;
696 __u8 Size;
697 __u8 Type;
698 int rc;
699
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300700 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701 Type = 0;
702 switch (sd->bridge) {
703 case BRIDGE_SPCA533:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300704 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300706 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300708 gspca_dev->usb_buf[0] = 2; /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300709 reg_w(gspca_dev, 0x24, 0, 8, 1);
710 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300712 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300713 reg_w(gspca_dev, 0x25, 0, 4, 1);
714 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300715 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300716
717 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300718 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300720 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721 break;
722 default:
723/* case BRIDGE_SPCA504B: */
724/* case BRIDGE_SPCA536: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300725 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300726 reg_w(gspca_dev, 0x25, 0, 4, 1);
727 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728 Type = 6;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300729 gspca_dev->usb_buf[0] = Type;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300730 reg_w(gspca_dev, 0x27, 0, 0, 1);
731 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300732 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733 break;
734 case BRIDGE_SPCA504:
735 Size += 3;
736 if (sd->subtype == AiptekMiniPenCam13) {
737 /* spca504a aiptek */
738 spca504A_acknowledged_command(gspca_dev,
739 0x08, Size, 0,
740 0x80 | (Size & 0x0f), 1);
741 spca504A_acknowledged_command(gspca_dev,
742 1, 3, 0, 0x9f, 0);
743 } else {
744 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
745 }
746 break;
747 case BRIDGE_SPCA504C:
748 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300749 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
750 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 break;
752 }
753}
754
755static void spca504_wait_status(struct gspca_dev *gspca_dev)
756{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757 int cnt;
758
759 cnt = 256;
760 while (--cnt > 0) {
761 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300762 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763 return;
764 msleep(10);
765 }
766}
767
768static void spca504B_setQtable(struct gspca_dev *gspca_dev)
769{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300770 gspca_dev->usb_buf[0] = 3;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300771 reg_w(gspca_dev, 0x26, 0, 0, 1);
772 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300773 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300774}
775
776static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
777{
778 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300779 int pollreg = 1;
780
781 switch (sd->bridge) {
782 case BRIDGE_SPCA504:
783 case BRIDGE_SPCA504C:
784 pollreg = 0;
785 /* fall thru */
786 default:
787/* case BRIDGE_SPCA533: */
788/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300789 reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
790 reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
791 reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
792 reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
793 reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
794 reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795 break;
796 case BRIDGE_SPCA536:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300797 reg_w(gspca_dev, 0, 0, 0x20f0, 0);
798 reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
799 reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
800 reg_w(gspca_dev, 0, 1, 0x20f4, 0);
801 reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
802 reg_w(gspca_dev, 0, 0, 0x2089, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803 break;
804 }
805 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300806 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807}
808
809/* this function is called at probe time */
810static int sd_config(struct gspca_dev *gspca_dev,
811 const struct usb_device_id *id)
812{
813 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815
816 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300818 sd->bridge = id->driver_info >> 8;
819 sd->subtype = id->driver_info;
820
821 if (sd->subtype == AiptekMiniPenCam13) {
822/* try to get the firmware as some cam answer 2.0.1.2.2
823 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300824 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300825 switch (gspca_dev->usb_buf[0]) {
826 case 1:
827 break; /* (right bridge/subtype) */
828 case 2:
829 sd->bridge = BRIDGE_SPCA504B;
830 sd->subtype = 0;
831 break;
832 default:
833 return -ENODEV;
834 }
835 }
836
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300837 switch (sd->bridge) {
838 default:
839/* case BRIDGE_SPCA504B: */
840/* case BRIDGE_SPCA504: */
841/* case BRIDGE_SPCA536: */
842 cam->cam_mode = vga_mode;
843 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
844 break;
845 case BRIDGE_SPCA533:
846 cam->cam_mode = custom_mode;
847 cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
848 break;
849 case BRIDGE_SPCA504C:
850 cam->cam_mode = vga_mode2;
851 cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
852 break;
853 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 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;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300857 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 return 0;
859}
860
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300861/* this function is called at probe and resume time */
862static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863{
864 struct sd *sd = (struct sd *) gspca_dev;
865 struct usb_device *dev = gspca_dev->dev;
866 int rc;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 __u8 i;
868 __u8 info[6];
869 int err_code;
870
871 switch (sd->bridge) {
872 case BRIDGE_SPCA504B:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300873 reg_w(gspca_dev, 0x1d, 0, 0, 0);
874 reg_w(gspca_dev, 0, 1, 0x2306, 0);
875 reg_w(gspca_dev, 0, 0, 0x0d04, 0);
876 reg_w(gspca_dev, 0, 0, 0x2000, 0);
877 reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
878 reg_w(gspca_dev, 0, 0, 0x2306, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300879 /* fall thru */
880 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300881 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 spca50x_GetFirmware(gspca_dev);
883 break;
884 case BRIDGE_SPCA536:
885 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300886 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300887 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300888 reg_w(gspca_dev, 0x24, 0, 0, 1);
889 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300890 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300891 reg_w(gspca_dev, 0x34, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300892 spca504B_WaitCmdStatus(gspca_dev);
893 break;
894 case BRIDGE_SPCA504C: /* pccam600 */
895 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300896 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
897 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 spca504_wait_status(gspca_dev);
899 if (sd->subtype == LogitechClickSmart420)
900 write_vector(gspca_dev,
901 spca504A_clicksmart420_open_data);
902 else
903 write_vector(gspca_dev, spca504_pccam600_open_data);
904 err_code = spca50x_setup_qtable(gspca_dev,
905 0x00, 0x2800,
906 0x2840, qtable_creative_pccam);
907 if (err_code < 0) {
908 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
909 return err_code;
910 }
911 break;
912 default:
913/* case BRIDGE_SPCA504: */
914 PDEBUG(D_STREAM, "Opening SPCA504");
915 if (sd->subtype == AiptekMiniPenCam13) {
916 /*****************************/
917 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300918 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300919 PDEBUG(D_STREAM,
920 "Read info: %d %d %d %d %d %d."
921 " Should be 1,0,2,2,0,0",
922 info[0], info[1], info[2],
923 info[3], info[4], info[5]);
924 /* spca504a aiptek */
925 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
926 spca504A_acknowledged_command(gspca_dev, 0x24,
927 8, 3, 0x9e, 1);
928 /* Twice sequencial need status 0xff->0x9e->0x9d */
929 spca504A_acknowledged_command(gspca_dev, 0x24,
930 8, 3, 0x9e, 0);
931
932 spca504A_acknowledged_command(gspca_dev, 0x24,
933 0, 0, 0x9d, 1);
934 /******************************/
935 /* spca504a aiptek */
936 spca504A_acknowledged_command(gspca_dev, 0x08,
937 6, 0, 0x86, 1);
938/* reg_write (dev, 0, 0x2000, 0); */
939/* reg_write (dev, 0, 0x2883, 1); */
940/* spca504A_acknowledged_command (gspca_dev, 0x08,
941 6, 0, 0x86, 1); */
942/* spca504A_acknowledged_command (gspca_dev, 0x24,
943 0, 0, 0x9D, 1); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300944 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
945 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300946 spca504A_acknowledged_command(gspca_dev, 0x01,
947 0x0f, 0, 0xff, 0);
948 }
949 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300950 reg_w_riv(dev, 0, 0x2000, 0);
951 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300952 err_code = spca50x_setup_qtable(gspca_dev,
953 0x00, 0x2800,
954 0x2840,
955 qtable_spca504_default);
956 if (err_code < 0) {
957 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
958 return err_code;
959 }
960 break;
961 }
962 return 0;
963}
964
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300965static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300966{
967 struct sd *sd = (struct sd *) gspca_dev;
968 struct usb_device *dev = gspca_dev->dev;
969 int rc;
970 int enable;
971 __u8 i;
972 __u8 info[6];
973
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300974 /* create the JPEG header */
975 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
976 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
977 0x22); /* JPEG 411 */
978 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
979
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300980 if (sd->bridge == BRIDGE_SPCA504B)
981 spca504B_setQtable(gspca_dev);
982 spca504B_SetSizeType(gspca_dev);
983 switch (sd->bridge) {
984 default:
985/* case BRIDGE_SPCA504B: */
986/* case BRIDGE_SPCA533: */
987/* case BRIDGE_SPCA536: */
988 if (sd->subtype == MegapixV4 ||
989 sd->subtype == LogitechClickSmart820) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300990 reg_w(gspca_dev, 0xf0, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300991 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300992 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 spca504B_WaitCmdStatus(gspca_dev);
994 } else {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300995 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300997 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 }
999 break;
1000 case BRIDGE_SPCA504:
1001 if (sd->subtype == AiptekMiniPenCam13) {
1002 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001003 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001004 PDEBUG(D_STREAM,
1005 "Read info: %d %d %d %d %d %d."
1006 " Should be 1,0,2,2,0,0",
1007 info[0], info[1], info[2],
1008 info[3], info[4], info[5]);
1009 /* spca504a aiptek */
1010 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1011 spca504A_acknowledged_command(gspca_dev, 0x24,
1012 8, 3, 0x9e, 1);
1013 /* Twice sequencial need status 0xff->0x9e->0x9d */
1014 spca504A_acknowledged_command(gspca_dev, 0x24,
1015 8, 3, 0x9e, 0);
1016 spca504A_acknowledged_command(gspca_dev, 0x24,
1017 0, 0, 0x9d, 1);
1018 } else {
1019 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1020 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001021 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001022 PDEBUG(D_STREAM,
1023 "Read info: %d %d %d %d %d %d."
1024 " Should be 1,0,2,2,0,0",
1025 info[0], info[1], info[2],
1026 info[3], info[4], info[5]);
1027 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1028 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1029 }
1030 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001031 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1032 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001033 break;
1034 case BRIDGE_SPCA504C:
1035 if (sd->subtype == LogitechClickSmart420) {
1036 write_vector(gspca_dev,
1037 spca504A_clicksmart420_init_data);
1038 } else {
1039 write_vector(gspca_dev, spca504_pccam600_init_data);
1040 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001041 enable = (sd->autogain ? 0x04 : 0x01);
1042 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1043 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001044
1045 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001046 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1047 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001048 spca504B_SetSizeType(gspca_dev);
1049 break;
1050 }
1051 sp5xx_initContBrigHueRegisters(gspca_dev);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -03001052 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001053}
1054
1055static void sd_stopN(struct gspca_dev *gspca_dev)
1056{
1057 struct sd *sd = (struct sd *) gspca_dev;
1058 struct usb_device *dev = gspca_dev->dev;
1059
1060 switch (sd->bridge) {
1061 default:
1062/* case BRIDGE_SPCA533: */
1063/* case BRIDGE_SPCA536: */
1064/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001065 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001066 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001067 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001068 break;
1069 case BRIDGE_SPCA504:
1070 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001071 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001072
1073 if (sd->subtype == AiptekMiniPenCam13) {
1074 /* spca504a aiptek */
1075/* spca504A_acknowledged_command(gspca_dev, 0x08,
1076 6, 0, 0x86, 1); */
1077 spca504A_acknowledged_command(gspca_dev, 0x24,
1078 0x00, 0x00, 0x9d, 1);
1079 spca504A_acknowledged_command(gspca_dev, 0x01,
1080 0x0f, 0x00, 0xff, 1);
1081 } else {
1082 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001083 reg_w_riv(dev, 0x01, 0x000f, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001084 }
1085 break;
1086 }
1087}
1088
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001089static void sd_stop0(struct gspca_dev *gspca_dev)
1090{
1091 struct sd *sd = (struct sd *) gspca_dev;
1092
1093 kfree(sd->jpeg_hdr);
1094}
1095
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001096static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1097 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001098 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 int len) /* iso packet length */
1100{
1101 struct sd *sd = (struct sd *) gspca_dev;
1102 int i, sof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103 static unsigned char ffd9[] = {0xff, 0xd9};
1104
1105/* frames are jpeg 4.1.1 without 0xff escape */
1106 switch (sd->bridge) {
1107 case BRIDGE_SPCA533:
1108 if (data[0] == 0xff) {
1109 if (data[1] != 0x01) { /* drop packet */
1110/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1111 return;
1112 }
1113 sof = 1;
1114 data += SPCA533_OFFSET_DATA;
1115 len -= SPCA533_OFFSET_DATA;
1116 } else {
1117 data += 1;
1118 len -= 1;
1119 }
1120 break;
1121 case BRIDGE_SPCA536:
1122 if (data[0] == 0xff) {
1123 sof = 1;
1124 data += SPCA536_OFFSET_DATA;
1125 len -= SPCA536_OFFSET_DATA;
1126 } else {
1127 data += 2;
1128 len -= 2;
1129 }
1130 break;
1131 default:
1132/* case BRIDGE_SPCA504: */
1133/* case BRIDGE_SPCA504B: */
1134 switch (data[0]) {
1135 case 0xfe: /* start of frame */
1136 sof = 1;
1137 data += SPCA50X_OFFSET_DATA;
1138 len -= SPCA50X_OFFSET_DATA;
1139 break;
1140 case 0xff: /* drop packet */
1141/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1142 return;
1143 default:
1144 data += 1;
1145 len -= 1;
1146 break;
1147 }
1148 break;
1149 case BRIDGE_SPCA504C:
1150 switch (data[0]) {
1151 case 0xfe: /* start of frame */
1152 sof = 1;
1153 data += SPCA504_PCCAM600_OFFSET_DATA;
1154 len -= SPCA504_PCCAM600_OFFSET_DATA;
1155 break;
1156 case 0xff: /* drop packet */
1157/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1158 return;
1159 default:
1160 data += 1;
1161 len -= 1;
1162 break;
1163 }
1164 break;
1165 }
1166 if (sof) { /* start of frame */
1167 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1168 ffd9, 2);
1169
1170 /* put the JPEG header in the new frame */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001171 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
1172 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001173 }
1174
1175 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001176 i = 0;
1177 do {
1178 if (data[i] == 0xff) {
1179 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1180 data, i + 1);
1181 len -= i;
1182 data += i;
1183 *data = 0x00;
1184 i = 0;
1185 }
1186 i++;
1187 } while (i < len);
1188 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001189}
1190
1191static void setbrightness(struct gspca_dev *gspca_dev)
1192{
1193 struct sd *sd = (struct sd *) gspca_dev;
1194 struct usb_device *dev = gspca_dev->dev;
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 reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001203 break;
1204 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001205 reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001206 break;
1207 }
1208}
1209
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001210static void setcontrast(struct gspca_dev *gspca_dev)
1211{
1212 struct sd *sd = (struct sd *) gspca_dev;
1213 struct usb_device *dev = gspca_dev->dev;
1214
1215 switch (sd->bridge) {
1216 default:
1217/* case BRIDGE_SPCA533: */
1218/* case BRIDGE_SPCA504B: */
1219/* case BRIDGE_SPCA504: */
1220/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001221 reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001222 break;
1223 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001224 reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001225 break;
1226 }
1227}
1228
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001229static void setcolors(struct gspca_dev *gspca_dev)
1230{
1231 struct sd *sd = (struct sd *) gspca_dev;
1232 struct usb_device *dev = gspca_dev->dev;
1233
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 reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001241 break;
1242 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001243 reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244 break;
1245 }
1246}
1247
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001248static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1249{
1250 struct sd *sd = (struct sd *) gspca_dev;
1251
1252 sd->brightness = val;
1253 if (gspca_dev->streaming)
1254 setbrightness(gspca_dev);
1255 return 0;
1256}
1257
1258static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1259{
1260 struct sd *sd = (struct sd *) gspca_dev;
1261
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001262 *val = sd->brightness;
1263 return 0;
1264}
1265
1266static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1267{
1268 struct sd *sd = (struct sd *) gspca_dev;
1269
1270 sd->contrast = val;
1271 if (gspca_dev->streaming)
1272 setcontrast(gspca_dev);
1273 return 0;
1274}
1275
1276static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1277{
1278 struct sd *sd = (struct sd *) gspca_dev;
1279
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001280 *val = sd->contrast;
1281 return 0;
1282}
1283
1284static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1285{
1286 struct sd *sd = (struct sd *) gspca_dev;
1287
1288 sd->colors = val;
1289 if (gspca_dev->streaming)
1290 setcolors(gspca_dev);
1291 return 0;
1292}
1293
1294static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1295{
1296 struct sd *sd = (struct sd *) gspca_dev;
1297
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001298 *val = sd->colors;
1299 return 0;
1300}
1301
1302static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1303{
1304 struct sd *sd = (struct sd *) gspca_dev;
1305
1306 sd->autogain = val;
1307 return 0;
1308}
1309
1310static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1311{
1312 struct sd *sd = (struct sd *) gspca_dev;
1313
1314 *val = sd->autogain;
1315 return 0;
1316}
1317
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001318static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1319 struct v4l2_jpegcompression *jcomp)
1320{
1321 struct sd *sd = (struct sd *) gspca_dev;
1322
1323 if (jcomp->quality < QUALITY_MIN)
1324 sd->quality = QUALITY_MIN;
1325 else if (jcomp->quality > QUALITY_MAX)
1326 sd->quality = QUALITY_MAX;
1327 else
1328 sd->quality = jcomp->quality;
1329 if (gspca_dev->streaming)
1330 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1331 return 0;
1332}
1333
1334static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1335 struct v4l2_jpegcompression *jcomp)
1336{
1337 struct sd *sd = (struct sd *) gspca_dev;
1338
1339 memset(jcomp, 0, sizeof *jcomp);
1340 jcomp->quality = sd->quality;
1341 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1342 | V4L2_JPEG_MARKER_DQT;
1343 return 0;
1344}
1345
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001346/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001347static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001348 .name = MODULE_NAME,
1349 .ctrls = sd_ctrls,
1350 .nctrls = ARRAY_SIZE(sd_ctrls),
1351 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001352 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001353 .start = sd_start,
1354 .stopN = sd_stopN,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001355 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001356 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001357 .get_jcomp = sd_get_jcomp,
1358 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001359};
1360
1361/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001362#define BS(bridge, subtype) \
1363 .driver_info = (BRIDGE_ ## bridge << 8) \
1364 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001365static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001366 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1367 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1368 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1369 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1370 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1371 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1372 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1373 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1374 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1375 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1376 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1377 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1378 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1379 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1380 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1381 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1382 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1383 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1384 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1385 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1386 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1387 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1388 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1389 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1390 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1391 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1392 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1393 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1394 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1395 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1396 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1397 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1398 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1399 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1400 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1401 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1402 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1403 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1404 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1405 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1406 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1407 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1408 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1409 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1410 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1411 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1412 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1413 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1414 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1415 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1416 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1417 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1418 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1419 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1420 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1421 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1422 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001423 {}
1424};
1425MODULE_DEVICE_TABLE(usb, device_table);
1426
1427/* -- device connect -- */
1428static int sd_probe(struct usb_interface *intf,
1429 const struct usb_device_id *id)
1430{
1431 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1432 THIS_MODULE);
1433}
1434
1435static struct usb_driver sd_driver = {
1436 .name = MODULE_NAME,
1437 .id_table = device_table,
1438 .probe = sd_probe,
1439 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001440#ifdef CONFIG_PM
1441 .suspend = gspca_suspend,
1442 .resume = gspca_resume,
1443#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001444};
1445
1446/* -- module insert / remove -- */
1447static int __init sd_mod_init(void)
1448{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001449 int ret;
1450 ret = usb_register(&sd_driver);
1451 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001452 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001453 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001454 return 0;
1455}
1456static void __exit sd_mod_exit(void)
1457{
1458 usb_deregister(&sd_driver);
1459 PDEBUG(D_PROBE, "deregistered");
1460}
1461
1462module_init(sd_mod_init);
1463module_exit(sd_mod_exit);