blob: c2b8c10c075add3bc79f5e83c4a36b2fd8cd5125 [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;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030042 u8 quality;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -030043#define QUALITY_MIN 70
44#define QUALITY_MAX 95
45#define QUALITY_DEF 85
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030046
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047 char bridge;
48#define BRIDGE_SPCA504 0
49#define BRIDGE_SPCA504B 1
50#define BRIDGE_SPCA504C 2
51#define BRIDGE_SPCA533 3
52#define BRIDGE_SPCA536 4
53 char subtype;
54#define AiptekMiniPenCam13 1
55#define LogitechClickSmart420 2
56#define LogitechClickSmart820 3
57#define MegapixV4 4
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030058
59 u8 *jpeg_hdr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060};
61
62/* V4L2 controls supported by the driver */
63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
71
72static struct ctrl sd_ctrls[] = {
73#define SD_BRIGHTNESS 0
74 {
75 {
76 .id = V4L2_CID_BRIGHTNESS,
77 .type = V4L2_CTRL_TYPE_INTEGER,
78 .name = "Brightness",
79 .minimum = 0,
80 .maximum = 0xff,
81 .step = 1,
82 .default_value = 0,
83 },
84 .set = sd_setbrightness,
85 .get = sd_getbrightness,
86 },
87#define SD_CONTRAST 1
88 {
89 {
90 .id = V4L2_CID_CONTRAST,
91 .type = V4L2_CTRL_TYPE_INTEGER,
92 .name = "Contrast",
93 .minimum = 0,
94 .maximum = 0xff,
95 .step = 1,
96 .default_value = 0x20,
97 },
98 .set = sd_setcontrast,
99 .get = sd_getcontrast,
100 },
101#define SD_COLOR 2
102 {
103 {
104 .id = V4L2_CID_SATURATION,
105 .type = V4L2_CTRL_TYPE_INTEGER,
106 .name = "Color",
107 .minimum = 0,
108 .maximum = 0xff,
109 .step = 1,
110 .default_value = 0x1a,
111 },
112 .set = sd_setcolors,
113 .get = sd_getcolors,
114 },
115#define SD_AUTOGAIN 3
116 {
117 {
118 .id = V4L2_CID_AUTOGAIN,
119 .type = V4L2_CTRL_TYPE_BOOLEAN,
120 .name = "Auto Gain",
121 .minimum = 0,
122 .maximum = 1,
123 .step = 1,
124 .default_value = 1,
125 },
126 .set = sd_setautogain,
127 .get = sd_getautogain,
128 },
129};
130
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300131static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300132 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133 .bytesperline = 320,
134 .sizeimage = 320 * 240 * 3 / 8 + 590,
135 .colorspace = V4L2_COLORSPACE_JPEG,
136 .priv = 2},
137 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
138 .bytesperline = 640,
139 .sizeimage = 640 * 480 * 3 / 8 + 590,
140 .colorspace = V4L2_COLORSPACE_JPEG,
141 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142};
143
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300144static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300145 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
146 .bytesperline = 320,
147 .sizeimage = 320 * 240 * 3 / 8 + 590,
148 .colorspace = V4L2_COLORSPACE_JPEG,
149 .priv = 2},
150 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
151 .bytesperline = 464,
152 .sizeimage = 464 * 480 * 3 / 8 + 590,
153 .colorspace = V4L2_COLORSPACE_JPEG,
154 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155};
156
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300157static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300158 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
159 .bytesperline = 176,
160 .sizeimage = 176 * 144 * 3 / 8 + 590,
161 .colorspace = V4L2_COLORSPACE_JPEG,
162 .priv = 4},
163 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
164 .bytesperline = 320,
165 .sizeimage = 320 * 240 * 3 / 8 + 590,
166 .colorspace = V4L2_COLORSPACE_JPEG,
167 .priv = 3},
168 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
169 .bytesperline = 352,
170 .sizeimage = 352 * 288 * 3 / 8 + 590,
171 .colorspace = V4L2_COLORSPACE_JPEG,
172 .priv = 2},
173 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
174 .bytesperline = 640,
175 .sizeimage = 640 * 480 * 3 / 8 + 590,
176 .colorspace = V4L2_COLORSPACE_JPEG,
177 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300178};
179
180#define SPCA50X_OFFSET_DATA 10
181#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
182#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
183#define SPCA504_PCCAM600_OFFSET_MODE 5
184#define SPCA504_PCCAM600_OFFSET_DATA 14
185 /* Frame packet header offsets for the spca533 */
186#define SPCA533_OFFSET_DATA 16
187#define SPCA533_OFFSET_FRAMSEQ 15
188/* Frame packet header offsets for the spca536 */
189#define SPCA536_OFFSET_DATA 4
190#define SPCA536_OFFSET_FRAMSEQ 1
191
192/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300193static const __u16 spca504_pccam600_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300194/* {0xa0, 0x0000, 0x0503}, * capture mode */
195 {0x00, 0x0000, 0x2000},
196 {0x00, 0x0013, 0x2301},
197 {0x00, 0x0003, 0x2000},
198 {0x00, 0x0001, 0x21ac},
199 {0x00, 0x0001, 0x21a6},
200 {0x00, 0x0000, 0x21a7}, /* brightness */
201 {0x00, 0x0020, 0x21a8}, /* contrast */
202 {0x00, 0x0001, 0x21ac}, /* sat/hue */
203 {0x00, 0x0000, 0x21ad}, /* hue */
204 {0x00, 0x001a, 0x21ae}, /* saturation */
205 {0x00, 0x0002, 0x21a3}, /* gamma */
206 {0x30, 0x0154, 0x0008},
207 {0x30, 0x0004, 0x0006},
208 {0x30, 0x0258, 0x0009},
209 {0x30, 0x0004, 0x0000},
210 {0x30, 0x0093, 0x0004},
211 {0x30, 0x0066, 0x0005},
212 {0x00, 0x0000, 0x2000},
213 {0x00, 0x0013, 0x2301},
214 {0x00, 0x0003, 0x2000},
215 {0x00, 0x0013, 0x2301},
216 {0x00, 0x0003, 0x2000},
217 {}
218};
219
220/* Creative PC-CAM 600 specific open data, sent before using the
221 * generic initialisation data from spca504_open_data.
222 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300223static const __u16 spca504_pccam600_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 {0x00, 0x0001, 0x2501},
225 {0x20, 0x0500, 0x0001}, /* snapshot mode */
226 {0x00, 0x0003, 0x2880},
227 {0x00, 0x0001, 0x2881},
228 {}
229};
230
231/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300232static const __u16 spca504A_clicksmart420_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233/* {0xa0, 0x0000, 0x0503}, * capture mode */
234 {0x00, 0x0000, 0x2000},
235 {0x00, 0x0013, 0x2301},
236 {0x00, 0x0003, 0x2000},
237 {0x00, 0x0001, 0x21ac},
238 {0x00, 0x0001, 0x21a6},
239 {0x00, 0x0000, 0x21a7}, /* brightness */
240 {0x00, 0x0020, 0x21a8}, /* contrast */
241 {0x00, 0x0001, 0x21ac}, /* sat/hue */
242 {0x00, 0x0000, 0x21ad}, /* hue */
243 {0x00, 0x001a, 0x21ae}, /* saturation */
244 {0x00, 0x0002, 0x21a3}, /* gamma */
245 {0x30, 0x0004, 0x000a},
246 {0xb0, 0x0001, 0x0000},
247
248
249 {0x0a1, 0x0080, 0x0001},
250 {0x30, 0x0049, 0x0000},
251 {0x30, 0x0060, 0x0005},
252 {0x0c, 0x0004, 0x0000},
253 {0x00, 0x0000, 0x0000},
254 {0x00, 0x0000, 0x2000},
255 {0x00, 0x0013, 0x2301},
256 {0x00, 0x0003, 0x2000},
257 {0x00, 0x0000, 0x2000},
258
259 {}
260};
261
262/* clicksmart 420 open data ? */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300263static const __u16 spca504A_clicksmart420_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264 {0x00, 0x0001, 0x2501},
265 {0x20, 0x0502, 0x0000},
266 {0x06, 0x0000, 0x0000},
267 {0x00, 0x0004, 0x2880},
268 {0x00, 0x0001, 0x2881},
269/* look like setting a qTable */
270 {0x00, 0x0006, 0x2800},
271 {0x00, 0x0004, 0x2801},
272 {0x00, 0x0004, 0x2802},
273 {0x00, 0x0006, 0x2803},
274 {0x00, 0x000a, 0x2804},
275 {0x00, 0x0010, 0x2805},
276 {0x00, 0x0014, 0x2806},
277 {0x00, 0x0018, 0x2807},
278 {0x00, 0x0005, 0x2808},
279 {0x00, 0x0005, 0x2809},
280 {0x00, 0x0006, 0x280a},
281 {0x00, 0x0008, 0x280b},
282 {0x00, 0x000a, 0x280c},
283 {0x00, 0x0017, 0x280d},
284 {0x00, 0x0018, 0x280e},
285 {0x00, 0x0016, 0x280f},
286
287 {0x00, 0x0006, 0x2810},
288 {0x00, 0x0005, 0x2811},
289 {0x00, 0x0006, 0x2812},
290 {0x00, 0x000a, 0x2813},
291 {0x00, 0x0010, 0x2814},
292 {0x00, 0x0017, 0x2815},
293 {0x00, 0x001c, 0x2816},
294 {0x00, 0x0016, 0x2817},
295 {0x00, 0x0006, 0x2818},
296 {0x00, 0x0007, 0x2819},
297 {0x00, 0x0009, 0x281a},
298 {0x00, 0x000c, 0x281b},
299 {0x00, 0x0014, 0x281c},
300 {0x00, 0x0023, 0x281d},
301 {0x00, 0x0020, 0x281e},
302 {0x00, 0x0019, 0x281f},
303
304 {0x00, 0x0007, 0x2820},
305 {0x00, 0x0009, 0x2821},
306 {0x00, 0x000f, 0x2822},
307 {0x00, 0x0016, 0x2823},
308 {0x00, 0x001b, 0x2824},
309 {0x00, 0x002c, 0x2825},
310 {0x00, 0x0029, 0x2826},
311 {0x00, 0x001f, 0x2827},
312 {0x00, 0x000a, 0x2828},
313 {0x00, 0x000e, 0x2829},
314 {0x00, 0x0016, 0x282a},
315 {0x00, 0x001a, 0x282b},
316 {0x00, 0x0020, 0x282c},
317 {0x00, 0x002a, 0x282d},
318 {0x00, 0x002d, 0x282e},
319 {0x00, 0x0025, 0x282f},
320
321 {0x00, 0x0014, 0x2830},
322 {0x00, 0x001a, 0x2831},
323 {0x00, 0x001f, 0x2832},
324 {0x00, 0x0023, 0x2833},
325 {0x00, 0x0029, 0x2834},
326 {0x00, 0x0030, 0x2835},
327 {0x00, 0x0030, 0x2836},
328 {0x00, 0x0028, 0x2837},
329 {0x00, 0x001d, 0x2838},
330 {0x00, 0x0025, 0x2839},
331 {0x00, 0x0026, 0x283a},
332 {0x00, 0x0027, 0x283b},
333 {0x00, 0x002d, 0x283c},
334 {0x00, 0x0028, 0x283d},
335 {0x00, 0x0029, 0x283e},
336 {0x00, 0x0028, 0x283f},
337
338 {0x00, 0x0007, 0x2840},
339 {0x00, 0x0007, 0x2841},
340 {0x00, 0x000a, 0x2842},
341 {0x00, 0x0013, 0x2843},
342 {0x00, 0x0028, 0x2844},
343 {0x00, 0x0028, 0x2845},
344 {0x00, 0x0028, 0x2846},
345 {0x00, 0x0028, 0x2847},
346 {0x00, 0x0007, 0x2848},
347 {0x00, 0x0008, 0x2849},
348 {0x00, 0x000a, 0x284a},
349 {0x00, 0x001a, 0x284b},
350 {0x00, 0x0028, 0x284c},
351 {0x00, 0x0028, 0x284d},
352 {0x00, 0x0028, 0x284e},
353 {0x00, 0x0028, 0x284f},
354
355 {0x00, 0x000a, 0x2850},
356 {0x00, 0x000a, 0x2851},
357 {0x00, 0x0016, 0x2852},
358 {0x00, 0x0028, 0x2853},
359 {0x00, 0x0028, 0x2854},
360 {0x00, 0x0028, 0x2855},
361 {0x00, 0x0028, 0x2856},
362 {0x00, 0x0028, 0x2857},
363 {0x00, 0x0013, 0x2858},
364 {0x00, 0x001a, 0x2859},
365 {0x00, 0x0028, 0x285a},
366 {0x00, 0x0028, 0x285b},
367 {0x00, 0x0028, 0x285c},
368 {0x00, 0x0028, 0x285d},
369 {0x00, 0x0028, 0x285e},
370 {0x00, 0x0028, 0x285f},
371
372 {0x00, 0x0028, 0x2860},
373 {0x00, 0x0028, 0x2861},
374 {0x00, 0x0028, 0x2862},
375 {0x00, 0x0028, 0x2863},
376 {0x00, 0x0028, 0x2864},
377 {0x00, 0x0028, 0x2865},
378 {0x00, 0x0028, 0x2866},
379 {0x00, 0x0028, 0x2867},
380 {0x00, 0x0028, 0x2868},
381 {0x00, 0x0028, 0x2869},
382 {0x00, 0x0028, 0x286a},
383 {0x00, 0x0028, 0x286b},
384 {0x00, 0x0028, 0x286c},
385 {0x00, 0x0028, 0x286d},
386 {0x00, 0x0028, 0x286e},
387 {0x00, 0x0028, 0x286f},
388
389 {0x00, 0x0028, 0x2870},
390 {0x00, 0x0028, 0x2871},
391 {0x00, 0x0028, 0x2872},
392 {0x00, 0x0028, 0x2873},
393 {0x00, 0x0028, 0x2874},
394 {0x00, 0x0028, 0x2875},
395 {0x00, 0x0028, 0x2876},
396 {0x00, 0x0028, 0x2877},
397 {0x00, 0x0028, 0x2878},
398 {0x00, 0x0028, 0x2879},
399 {0x00, 0x0028, 0x287a},
400 {0x00, 0x0028, 0x287b},
401 {0x00, 0x0028, 0x287c},
402 {0x00, 0x0028, 0x287d},
403 {0x00, 0x0028, 0x287e},
404 {0x00, 0x0028, 0x287f},
405
406 {0xa0, 0x0000, 0x0503},
407 {}
408};
409
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300410static const __u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411 { /* Q-table Y-components */
412 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
413 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
414 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
415 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
416 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
417 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
418 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
419 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
420 { /* Q-table C-components */
421 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
422 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
423 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
424 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
425 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
426 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
427 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
428 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
429};
430
431/* FIXME: This Q-table is identical to the Creative PC-CAM one,
432 * except for one byte. Possibly a typo?
433 * NWG: 18/05/2003.
434 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300435static const __u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300436 { /* Q-table Y-components */
437 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
438 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
439 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
440 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
441 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
442 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
443 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
444 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
445 },
446 { /* Q-table C-components */
447 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
448 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
449 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
450 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
451 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
452 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
453 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
454 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
455};
456
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300457/* read <len> bytes to gspca_dev->usb_buf */
458static void reg_r(struct gspca_dev *gspca_dev,
459 __u16 req,
460 __u16 index,
461 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300463#ifdef GSPCA_DEBUG
464 if (len > USB_BUF_SZ) {
465 err("reg_r: buffer overflow");
466 return;
467 }
468#endif
469 usb_control_msg(gspca_dev->dev,
470 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 req,
472 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
473 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300474 index,
475 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 500);
477}
478
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300479/* write <len> bytes from gspca_dev->usb_buf */
480static void reg_w(struct gspca_dev *gspca_dev,
481 __u16 req,
482 __u16 value,
483 __u16 index,
484 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300486#ifdef GSPCA_DEBUG
487 if (len > USB_BUF_SZ) {
488 err("reg_w: buffer overflow");
489 return;
490 }
491#endif
492 usb_control_msg(gspca_dev->dev,
493 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494 req,
495 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300496 value, index,
497 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498 500);
499}
500
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300501/* write req / index / value */
502static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 __u16 req, __u16 index, __u16 value)
504{
505 int ret;
506
507 ret = usb_control_msg(dev,
508 usb_sndctrlpipe(dev, 0),
509 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300510 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300513 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 if (ret < 0)
515 PDEBUG(D_ERR, "reg write: error %d", ret);
516 return ret;
517}
518
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300519/* read 1 byte */
520static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 __u16 value) /* wValue */
522{
523 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525 ret = usb_control_msg(gspca_dev->dev,
526 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 0x20, /* request */
528 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
529 value,
530 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 500); /* timeout */
533 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 return 0;
536 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300537 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538}
539
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300540/* read 1 or 2 bytes - returns < 0 if error */
541static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542 __u16 req, /* bRequest */
543 __u16 index, /* wIndex */
544 __u16 length) /* wLength (1 or 2 only) */
545{
546 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300548 gspca_dev->usb_buf[1] = 0;
549 ret = usb_control_msg(gspca_dev->dev,
550 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 req,
552 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
553 0, /* value */
554 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300555 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300556 500);
557 if (ret < 0) {
558 PDEBUG(D_ERR, "reg_read err %d", ret);
559 return -1;
560 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300561 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300562}
563
564static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300565 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300566{
567 struct usb_device *dev = gspca_dev->dev;
568 int ret, i = 0;
569
570 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300571 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572 if (ret < 0) {
573 PDEBUG(D_ERR,
574 "Register write failed for 0x%x,0x%x,0x%x",
575 data[i][0], data[i][1], data[i][2]);
576 return ret;
577 }
578 i++;
579 }
580 return 0;
581}
582
583static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
584 unsigned int request,
585 unsigned int ybase,
586 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300587 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588{
589 struct usb_device *dev = gspca_dev->dev;
590 int i, err;
591
592 /* loop over y components */
593 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595 if (err < 0)
596 return err;
597 }
598
599 /* loop over c components */
600 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300601 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602 if (err < 0)
603 return err;
604 }
605 return 0;
606}
607
608static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
609 __u16 req, __u16 idx, __u16 val)
610{
611 struct usb_device *dev = gspca_dev->dev;
612 __u8 notdone;
613
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300614 reg_w_riv(dev, req, idx, val);
615 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
616 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617
618 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
619
620 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300621 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300622 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
623}
624
625static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
626 __u16 req,
627 __u16 idx, __u16 val, __u8 stat, __u8 count)
628{
629 struct usb_device *dev = gspca_dev->dev;
630 __u8 status;
631 __u8 endcode;
632
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300633 reg_w_riv(dev, req, idx, val);
634 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300635 endcode = stat;
636 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
637 if (!count)
638 return;
639 count = 200;
640 while (--count > 0) {
641 msleep(10);
642 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300643/* reg_w_riv(dev, req, idx, val); */
644 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300645 if (status == endcode) {
646 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
647 status, 200 - count);
648 break;
649 }
650 }
651}
652
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300653static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300655 int count = 10;
656
657 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300658 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300659 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300660 break;
661 msleep(10);
662 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300663 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664}
665
666static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
667{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300668 int count = 50;
669
670 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300671 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300672 if (gspca_dev->usb_buf[0] != 0) {
673 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300674 reg_w(gspca_dev, 0x21, 0, 1, 1);
675 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300676 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300677 break;
678 }
679 msleep(10);
680 }
681}
682
683static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
684{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300685 __u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300687 data = gspca_dev->usb_buf;
688 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300690 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300691 reg_r(gspca_dev, 0x23, 0, 64);
692 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693}
694
695static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
696{
697 struct sd *sd = (struct sd *) gspca_dev;
698 struct usb_device *dev = gspca_dev->dev;
699 __u8 Size;
700 __u8 Type;
701 int rc;
702
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300703 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 Type = 0;
705 switch (sd->bridge) {
706 case BRIDGE_SPCA533:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300707 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300708 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300709 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300711 gspca_dev->usb_buf[0] = 2; /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300712 reg_w(gspca_dev, 0x24, 0, 8, 1);
713 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300714
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300715 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300716 reg_w(gspca_dev, 0x25, 0, 4, 1);
717 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300718 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719
720 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300721 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300723 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724 break;
725 default:
726/* case BRIDGE_SPCA504B: */
727/* case BRIDGE_SPCA536: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300728 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300729 reg_w(gspca_dev, 0x25, 0, 4, 1);
730 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731 Type = 6;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300732 gspca_dev->usb_buf[0] = Type;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300733 reg_w(gspca_dev, 0x27, 0, 0, 1);
734 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300735 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 break;
737 case BRIDGE_SPCA504:
738 Size += 3;
739 if (sd->subtype == AiptekMiniPenCam13) {
740 /* spca504a aiptek */
741 spca504A_acknowledged_command(gspca_dev,
742 0x08, Size, 0,
743 0x80 | (Size & 0x0f), 1);
744 spca504A_acknowledged_command(gspca_dev,
745 1, 3, 0, 0x9f, 0);
746 } else {
747 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
748 }
749 break;
750 case BRIDGE_SPCA504C:
751 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300752 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
753 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754 break;
755 }
756}
757
758static void spca504_wait_status(struct gspca_dev *gspca_dev)
759{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300760 int cnt;
761
762 cnt = 256;
763 while (--cnt > 0) {
764 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300765 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300766 return;
767 msleep(10);
768 }
769}
770
771static void spca504B_setQtable(struct gspca_dev *gspca_dev)
772{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300773 gspca_dev->usb_buf[0] = 3;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300774 reg_w(gspca_dev, 0x26, 0, 0, 1);
775 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300776 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300777}
778
779static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
780{
781 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782 int pollreg = 1;
783
784 switch (sd->bridge) {
785 case BRIDGE_SPCA504:
786 case BRIDGE_SPCA504C:
787 pollreg = 0;
788 /* fall thru */
789 default:
790/* case BRIDGE_SPCA533: */
791/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300792 reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
793 reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
794 reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
795 reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
796 reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
797 reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300798 break;
799 case BRIDGE_SPCA536:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300800 reg_w(gspca_dev, 0, 0, 0x20f0, 0);
801 reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
802 reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
803 reg_w(gspca_dev, 0, 1, 0x20f4, 0);
804 reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
805 reg_w(gspca_dev, 0, 0, 0x2089, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 break;
807 }
808 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300809 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300810}
811
812/* this function is called at probe time */
813static int sd_config(struct gspca_dev *gspca_dev,
814 const struct usb_device_id *id)
815{
816 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818
819 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300821 sd->bridge = id->driver_info >> 8;
822 sd->subtype = id->driver_info;
823
824 if (sd->subtype == AiptekMiniPenCam13) {
825/* try to get the firmware as some cam answer 2.0.1.2.2
826 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300827 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300828 switch (gspca_dev->usb_buf[0]) {
829 case 1:
830 break; /* (right bridge/subtype) */
831 case 2:
832 sd->bridge = BRIDGE_SPCA504B;
833 sd->subtype = 0;
834 break;
835 default:
836 return -ENODEV;
837 }
838 }
839
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 switch (sd->bridge) {
841 default:
842/* case BRIDGE_SPCA504B: */
843/* case BRIDGE_SPCA504: */
844/* case BRIDGE_SPCA536: */
845 cam->cam_mode = vga_mode;
846 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
847 break;
848 case BRIDGE_SPCA533:
849 cam->cam_mode = custom_mode;
850 cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
851 break;
852 case BRIDGE_SPCA504C:
853 cam->cam_mode = vga_mode2;
854 cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
855 break;
856 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300857 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
858 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
859 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300860 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300861 return 0;
862}
863
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300864/* this function is called at probe and resume time */
865static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866{
867 struct sd *sd = (struct sd *) gspca_dev;
868 struct usb_device *dev = gspca_dev->dev;
869 int rc;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870 __u8 i;
871 __u8 info[6];
872 int err_code;
873
874 switch (sd->bridge) {
875 case BRIDGE_SPCA504B:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300876 reg_w(gspca_dev, 0x1d, 0, 0, 0);
877 reg_w(gspca_dev, 0, 1, 0x2306, 0);
878 reg_w(gspca_dev, 0, 0, 0x0d04, 0);
879 reg_w(gspca_dev, 0, 0, 0x2000, 0);
880 reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
881 reg_w(gspca_dev, 0, 0, 0x2306, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 /* fall thru */
883 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300884 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300885 spca50x_GetFirmware(gspca_dev);
886 break;
887 case BRIDGE_SPCA536:
888 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300889 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300890 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300891 reg_w(gspca_dev, 0x24, 0, 0, 1);
892 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300893 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300894 reg_w(gspca_dev, 0x34, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 spca504B_WaitCmdStatus(gspca_dev);
896 break;
897 case BRIDGE_SPCA504C: /* pccam600 */
898 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300899 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
900 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300901 spca504_wait_status(gspca_dev);
902 if (sd->subtype == LogitechClickSmart420)
903 write_vector(gspca_dev,
904 spca504A_clicksmart420_open_data);
905 else
906 write_vector(gspca_dev, spca504_pccam600_open_data);
907 err_code = spca50x_setup_qtable(gspca_dev,
908 0x00, 0x2800,
909 0x2840, qtable_creative_pccam);
910 if (err_code < 0) {
911 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
912 return err_code;
913 }
914 break;
915 default:
916/* case BRIDGE_SPCA504: */
917 PDEBUG(D_STREAM, "Opening SPCA504");
918 if (sd->subtype == AiptekMiniPenCam13) {
919 /*****************************/
920 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300921 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 PDEBUG(D_STREAM,
923 "Read info: %d %d %d %d %d %d."
924 " Should be 1,0,2,2,0,0",
925 info[0], info[1], info[2],
926 info[3], info[4], info[5]);
927 /* spca504a aiptek */
928 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
929 spca504A_acknowledged_command(gspca_dev, 0x24,
930 8, 3, 0x9e, 1);
931 /* Twice sequencial need status 0xff->0x9e->0x9d */
932 spca504A_acknowledged_command(gspca_dev, 0x24,
933 8, 3, 0x9e, 0);
934
935 spca504A_acknowledged_command(gspca_dev, 0x24,
936 0, 0, 0x9d, 1);
937 /******************************/
938 /* spca504a aiptek */
939 spca504A_acknowledged_command(gspca_dev, 0x08,
940 6, 0, 0x86, 1);
941/* reg_write (dev, 0, 0x2000, 0); */
942/* reg_write (dev, 0, 0x2883, 1); */
943/* spca504A_acknowledged_command (gspca_dev, 0x08,
944 6, 0, 0x86, 1); */
945/* spca504A_acknowledged_command (gspca_dev, 0x24,
946 0, 0, 0x9D, 1); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300947 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
948 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949 spca504A_acknowledged_command(gspca_dev, 0x01,
950 0x0f, 0, 0xff, 0);
951 }
952 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300953 reg_w_riv(dev, 0, 0x2000, 0);
954 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300955 err_code = spca50x_setup_qtable(gspca_dev,
956 0x00, 0x2800,
957 0x2840,
958 qtable_spca504_default);
959 if (err_code < 0) {
960 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
961 return err_code;
962 }
963 break;
964 }
965 return 0;
966}
967
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300968static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300969{
970 struct sd *sd = (struct sd *) gspca_dev;
971 struct usb_device *dev = gspca_dev->dev;
972 int rc;
973 int enable;
974 __u8 i;
975 __u8 info[6];
976
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300977 /* create the JPEG header */
978 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
979 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
980 0x22); /* JPEG 411 */
981 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
982
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300983 if (sd->bridge == BRIDGE_SPCA504B)
984 spca504B_setQtable(gspca_dev);
985 spca504B_SetSizeType(gspca_dev);
986 switch (sd->bridge) {
987 default:
988/* case BRIDGE_SPCA504B: */
989/* case BRIDGE_SPCA533: */
990/* case BRIDGE_SPCA536: */
991 if (sd->subtype == MegapixV4 ||
992 sd->subtype == LogitechClickSmart820) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300993 reg_w(gspca_dev, 0xf0, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300995 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 spca504B_WaitCmdStatus(gspca_dev);
997 } else {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300998 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300999 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001000 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001001 }
1002 break;
1003 case BRIDGE_SPCA504:
1004 if (sd->subtype == AiptekMiniPenCam13) {
1005 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001006 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007 PDEBUG(D_STREAM,
1008 "Read info: %d %d %d %d %d %d."
1009 " Should be 1,0,2,2,0,0",
1010 info[0], info[1], info[2],
1011 info[3], info[4], info[5]);
1012 /* spca504a aiptek */
1013 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1014 spca504A_acknowledged_command(gspca_dev, 0x24,
1015 8, 3, 0x9e, 1);
1016 /* Twice sequencial need status 0xff->0x9e->0x9d */
1017 spca504A_acknowledged_command(gspca_dev, 0x24,
1018 8, 3, 0x9e, 0);
1019 spca504A_acknowledged_command(gspca_dev, 0x24,
1020 0, 0, 0x9d, 1);
1021 } else {
1022 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1023 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001024 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001025 PDEBUG(D_STREAM,
1026 "Read info: %d %d %d %d %d %d."
1027 " Should be 1,0,2,2,0,0",
1028 info[0], info[1], info[2],
1029 info[3], info[4], info[5]);
1030 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1031 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1032 }
1033 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001034 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1035 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001036 break;
1037 case BRIDGE_SPCA504C:
1038 if (sd->subtype == LogitechClickSmart420) {
1039 write_vector(gspca_dev,
1040 spca504A_clicksmart420_init_data);
1041 } else {
1042 write_vector(gspca_dev, spca504_pccam600_init_data);
1043 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001044 enable = (sd->autogain ? 0x04 : 0x01);
1045 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1046 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047
1048 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001049 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1050 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001051 spca504B_SetSizeType(gspca_dev);
1052 break;
1053 }
1054 sp5xx_initContBrigHueRegisters(gspca_dev);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -03001055 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056}
1057
1058static void sd_stopN(struct gspca_dev *gspca_dev)
1059{
1060 struct sd *sd = (struct sd *) gspca_dev;
1061 struct usb_device *dev = gspca_dev->dev;
1062
1063 switch (sd->bridge) {
1064 default:
1065/* case BRIDGE_SPCA533: */
1066/* case BRIDGE_SPCA536: */
1067/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001068 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001070 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001071 break;
1072 case BRIDGE_SPCA504:
1073 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001074 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075
1076 if (sd->subtype == AiptekMiniPenCam13) {
1077 /* spca504a aiptek */
1078/* spca504A_acknowledged_command(gspca_dev, 0x08,
1079 6, 0, 0x86, 1); */
1080 spca504A_acknowledged_command(gspca_dev, 0x24,
1081 0x00, 0x00, 0x9d, 1);
1082 spca504A_acknowledged_command(gspca_dev, 0x01,
1083 0x0f, 0x00, 0xff, 1);
1084 } else {
1085 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001086 reg_w_riv(dev, 0x01, 0x000f, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001087 }
1088 break;
1089 }
1090}
1091
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001092static void sd_stop0(struct gspca_dev *gspca_dev)
1093{
1094 struct sd *sd = (struct sd *) gspca_dev;
1095
1096 kfree(sd->jpeg_hdr);
1097}
1098
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1100 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001101 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001102 int len) /* iso packet length */
1103{
1104 struct sd *sd = (struct sd *) gspca_dev;
1105 int i, sof = 0;
1106 unsigned char *s, *d;
1107 static unsigned char ffd9[] = {0xff, 0xd9};
1108
1109/* frames are jpeg 4.1.1 without 0xff escape */
1110 switch (sd->bridge) {
1111 case BRIDGE_SPCA533:
1112 if (data[0] == 0xff) {
1113 if (data[1] != 0x01) { /* drop packet */
1114/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1115 return;
1116 }
1117 sof = 1;
1118 data += SPCA533_OFFSET_DATA;
1119 len -= SPCA533_OFFSET_DATA;
1120 } else {
1121 data += 1;
1122 len -= 1;
1123 }
1124 break;
1125 case BRIDGE_SPCA536:
1126 if (data[0] == 0xff) {
1127 sof = 1;
1128 data += SPCA536_OFFSET_DATA;
1129 len -= SPCA536_OFFSET_DATA;
1130 } else {
1131 data += 2;
1132 len -= 2;
1133 }
1134 break;
1135 default:
1136/* case BRIDGE_SPCA504: */
1137/* case BRIDGE_SPCA504B: */
1138 switch (data[0]) {
1139 case 0xfe: /* start of frame */
1140 sof = 1;
1141 data += SPCA50X_OFFSET_DATA;
1142 len -= SPCA50X_OFFSET_DATA;
1143 break;
1144 case 0xff: /* drop packet */
1145/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1146 return;
1147 default:
1148 data += 1;
1149 len -= 1;
1150 break;
1151 }
1152 break;
1153 case BRIDGE_SPCA504C:
1154 switch (data[0]) {
1155 case 0xfe: /* start of frame */
1156 sof = 1;
1157 data += SPCA504_PCCAM600_OFFSET_DATA;
1158 len -= SPCA504_PCCAM600_OFFSET_DATA;
1159 break;
1160 case 0xff: /* drop packet */
1161/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1162 return;
1163 default:
1164 data += 1;
1165 len -= 1;
1166 break;
1167 }
1168 break;
1169 }
1170 if (sof) { /* start of frame */
1171 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1172 ffd9, 2);
1173
1174 /* put the JPEG header in the new frame */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001175 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
1176 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001177 }
1178
1179 /* add 0x00 after 0xff */
1180 for (i = len; --i >= 0; )
1181 if (data[i] == 0xff)
1182 break;
1183 if (i < 0) { /* no 0xff */
1184 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1185 return;
1186 }
1187 s = data;
1188 d = sd->packet;
1189 for (i = 0; i < len; i++) {
1190 *d++ = *s++;
1191 if (s[-1] == 0xff)
1192 *d++ = 0x00;
1193 }
1194 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1195 sd->packet, d - sd->packet);
1196}
1197
1198static void setbrightness(struct gspca_dev *gspca_dev)
1199{
1200 struct sd *sd = (struct sd *) gspca_dev;
1201 struct usb_device *dev = gspca_dev->dev;
1202
1203 switch (sd->bridge) {
1204 default:
1205/* case BRIDGE_SPCA533: */
1206/* case BRIDGE_SPCA504B: */
1207/* case BRIDGE_SPCA504: */
1208/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001209 reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001210 break;
1211 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001212 reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001213 break;
1214 }
1215}
1216
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001217static void setcontrast(struct gspca_dev *gspca_dev)
1218{
1219 struct sd *sd = (struct sd *) gspca_dev;
1220 struct usb_device *dev = gspca_dev->dev;
1221
1222 switch (sd->bridge) {
1223 default:
1224/* case BRIDGE_SPCA533: */
1225/* case BRIDGE_SPCA504B: */
1226/* case BRIDGE_SPCA504: */
1227/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001228 reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001229 break;
1230 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001231 reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001232 break;
1233 }
1234}
1235
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001236static void setcolors(struct gspca_dev *gspca_dev)
1237{
1238 struct sd *sd = (struct sd *) gspca_dev;
1239 struct usb_device *dev = gspca_dev->dev;
1240
1241 switch (sd->bridge) {
1242 default:
1243/* case BRIDGE_SPCA533: */
1244/* case BRIDGE_SPCA504B: */
1245/* case BRIDGE_SPCA504: */
1246/* case BRIDGE_SPCA504C: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001247 reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001248 break;
1249 case BRIDGE_SPCA536:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001250 reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001251 break;
1252 }
1253}
1254
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001255static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1256{
1257 struct sd *sd = (struct sd *) gspca_dev;
1258
1259 sd->brightness = val;
1260 if (gspca_dev->streaming)
1261 setbrightness(gspca_dev);
1262 return 0;
1263}
1264
1265static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1266{
1267 struct sd *sd = (struct sd *) gspca_dev;
1268
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001269 *val = sd->brightness;
1270 return 0;
1271}
1272
1273static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1274{
1275 struct sd *sd = (struct sd *) gspca_dev;
1276
1277 sd->contrast = val;
1278 if (gspca_dev->streaming)
1279 setcontrast(gspca_dev);
1280 return 0;
1281}
1282
1283static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1284{
1285 struct sd *sd = (struct sd *) gspca_dev;
1286
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001287 *val = sd->contrast;
1288 return 0;
1289}
1290
1291static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1292{
1293 struct sd *sd = (struct sd *) gspca_dev;
1294
1295 sd->colors = val;
1296 if (gspca_dev->streaming)
1297 setcolors(gspca_dev);
1298 return 0;
1299}
1300
1301static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1302{
1303 struct sd *sd = (struct sd *) gspca_dev;
1304
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001305 *val = sd->colors;
1306 return 0;
1307}
1308
1309static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1310{
1311 struct sd *sd = (struct sd *) gspca_dev;
1312
1313 sd->autogain = val;
1314 return 0;
1315}
1316
1317static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1318{
1319 struct sd *sd = (struct sd *) gspca_dev;
1320
1321 *val = sd->autogain;
1322 return 0;
1323}
1324
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001325static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1326 struct v4l2_jpegcompression *jcomp)
1327{
1328 struct sd *sd = (struct sd *) gspca_dev;
1329
1330 if (jcomp->quality < QUALITY_MIN)
1331 sd->quality = QUALITY_MIN;
1332 else if (jcomp->quality > QUALITY_MAX)
1333 sd->quality = QUALITY_MAX;
1334 else
1335 sd->quality = jcomp->quality;
1336 if (gspca_dev->streaming)
1337 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1338 return 0;
1339}
1340
1341static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1342 struct v4l2_jpegcompression *jcomp)
1343{
1344 struct sd *sd = (struct sd *) gspca_dev;
1345
1346 memset(jcomp, 0, sizeof *jcomp);
1347 jcomp->quality = sd->quality;
1348 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1349 | V4L2_JPEG_MARKER_DQT;
1350 return 0;
1351}
1352
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001353/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001354static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001355 .name = MODULE_NAME,
1356 .ctrls = sd_ctrls,
1357 .nctrls = ARRAY_SIZE(sd_ctrls),
1358 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001359 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001360 .start = sd_start,
1361 .stopN = sd_stopN,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001362 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001363 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001364 .get_jcomp = sd_get_jcomp,
1365 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001366};
1367
1368/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001369#define BS(bridge, subtype) \
1370 .driver_info = (BRIDGE_ ## bridge << 8) \
1371 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001372static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001373 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1374 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1375 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1376 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1377 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1378 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1379 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1380 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1381 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1382 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1383 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1384 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1385 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1386 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1387 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1388 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1389 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1390 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1391 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1392 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1393 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1394 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1395 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1396 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1397 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1398 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1399 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1400 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1401 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1402 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1403 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1404 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1405 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1406 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1407 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1408 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1409 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1410 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1411 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1412 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1413 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1414 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1415 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1416 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1417 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1418 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1419 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1420 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1421 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1422 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1423 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1424 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1425 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1426 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1427 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1428 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1429 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001430 {}
1431};
1432MODULE_DEVICE_TABLE(usb, device_table);
1433
1434/* -- device connect -- */
1435static int sd_probe(struct usb_interface *intf,
1436 const struct usb_device_id *id)
1437{
1438 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1439 THIS_MODULE);
1440}
1441
1442static struct usb_driver sd_driver = {
1443 .name = MODULE_NAME,
1444 .id_table = device_table,
1445 .probe = sd_probe,
1446 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001447#ifdef CONFIG_PM
1448 .suspend = gspca_suspend,
1449 .resume = gspca_resume,
1450#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001451};
1452
1453/* -- module insert / remove -- */
1454static int __init sd_mod_init(void)
1455{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001456 int ret;
1457 ret = usb_register(&sd_driver);
1458 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001459 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001460 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001461 return 0;
1462}
1463static void __exit sd_mod_exit(void)
1464{
1465 usb_deregister(&sd_driver);
1466 PDEBUG(D_PROBE, "deregistered");
1467}
1468
1469module_init(sd_mod_init);
1470module_exit(sd_mod_exit);