blob: e9481fa77749ace1c0d5d5fad55af1cf3c661d88 [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
Johannes Goerneraf5f88c2009-07-09 03:28:46 -030055#define MegaImageVI 5
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030056
57 u8 *jpeg_hdr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030058};
59
60/* V4L2 controls supported by the driver */
61static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
63static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
69
70static struct ctrl sd_ctrls[] = {
71#define SD_BRIGHTNESS 0
72 {
73 {
74 .id = V4L2_CID_BRIGHTNESS,
75 .type = V4L2_CTRL_TYPE_INTEGER,
76 .name = "Brightness",
77 .minimum = 0,
78 .maximum = 0xff,
79 .step = 1,
80 .default_value = 0,
81 },
82 .set = sd_setbrightness,
83 .get = sd_getbrightness,
84 },
85#define SD_CONTRAST 1
86 {
87 {
88 .id = V4L2_CID_CONTRAST,
89 .type = V4L2_CTRL_TYPE_INTEGER,
90 .name = "Contrast",
91 .minimum = 0,
92 .maximum = 0xff,
93 .step = 1,
94 .default_value = 0x20,
95 },
96 .set = sd_setcontrast,
97 .get = sd_getcontrast,
98 },
99#define SD_COLOR 2
100 {
101 {
102 .id = V4L2_CID_SATURATION,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "Color",
105 .minimum = 0,
106 .maximum = 0xff,
107 .step = 1,
108 .default_value = 0x1a,
109 },
110 .set = sd_setcolors,
111 .get = sd_getcolors,
112 },
113#define SD_AUTOGAIN 3
114 {
115 {
116 .id = V4L2_CID_AUTOGAIN,
117 .type = V4L2_CTRL_TYPE_BOOLEAN,
118 .name = "Auto Gain",
119 .minimum = 0,
120 .maximum = 1,
121 .step = 1,
122 .default_value = 1,
123 },
124 .set = sd_setautogain,
125 .get = sd_getautogain,
126 },
127};
128
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300129static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300130 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .bytesperline = 320,
132 .sizeimage = 320 * 240 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
134 .priv = 2},
135 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
136 .bytesperline = 640,
137 .sizeimage = 640 * 480 * 3 / 8 + 590,
138 .colorspace = V4L2_COLORSPACE_JPEG,
139 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300140};
141
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300142static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300143 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
144 .bytesperline = 320,
145 .sizeimage = 320 * 240 * 3 / 8 + 590,
146 .colorspace = V4L2_COLORSPACE_JPEG,
147 .priv = 2},
148 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
149 .bytesperline = 464,
150 .sizeimage = 464 * 480 * 3 / 8 + 590,
151 .colorspace = V4L2_COLORSPACE_JPEG,
152 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300153};
154
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300155static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300156 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
157 .bytesperline = 176,
158 .sizeimage = 176 * 144 * 3 / 8 + 590,
159 .colorspace = V4L2_COLORSPACE_JPEG,
160 .priv = 4},
161 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
162 .bytesperline = 320,
163 .sizeimage = 320 * 240 * 3 / 8 + 590,
164 .colorspace = V4L2_COLORSPACE_JPEG,
165 .priv = 3},
166 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
167 .bytesperline = 352,
168 .sizeimage = 352 * 288 * 3 / 8 + 590,
169 .colorspace = V4L2_COLORSPACE_JPEG,
170 .priv = 2},
171 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
172 .bytesperline = 640,
173 .sizeimage = 640 * 480 * 3 / 8 + 590,
174 .colorspace = V4L2_COLORSPACE_JPEG,
175 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300176};
177
178#define SPCA50X_OFFSET_DATA 10
179#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
180#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
181#define SPCA504_PCCAM600_OFFSET_MODE 5
182#define SPCA504_PCCAM600_OFFSET_DATA 14
183 /* Frame packet header offsets for the spca533 */
184#define SPCA533_OFFSET_DATA 16
185#define SPCA533_OFFSET_FRAMSEQ 15
186/* Frame packet header offsets for the spca536 */
187#define SPCA536_OFFSET_DATA 4
188#define SPCA536_OFFSET_FRAMSEQ 1
189
190/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300191static const __u16 spca504_pccam600_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300192/* {0xa0, 0x0000, 0x0503}, * capture mode */
193 {0x00, 0x0000, 0x2000},
194 {0x00, 0x0013, 0x2301},
195 {0x00, 0x0003, 0x2000},
196 {0x00, 0x0001, 0x21ac},
197 {0x00, 0x0001, 0x21a6},
198 {0x00, 0x0000, 0x21a7}, /* brightness */
199 {0x00, 0x0020, 0x21a8}, /* contrast */
200 {0x00, 0x0001, 0x21ac}, /* sat/hue */
201 {0x00, 0x0000, 0x21ad}, /* hue */
202 {0x00, 0x001a, 0x21ae}, /* saturation */
203 {0x00, 0x0002, 0x21a3}, /* gamma */
204 {0x30, 0x0154, 0x0008},
205 {0x30, 0x0004, 0x0006},
206 {0x30, 0x0258, 0x0009},
207 {0x30, 0x0004, 0x0000},
208 {0x30, 0x0093, 0x0004},
209 {0x30, 0x0066, 0x0005},
210 {0x00, 0x0000, 0x2000},
211 {0x00, 0x0013, 0x2301},
212 {0x00, 0x0003, 0x2000},
213 {0x00, 0x0013, 0x2301},
214 {0x00, 0x0003, 0x2000},
215 {}
216};
217
218/* Creative PC-CAM 600 specific open data, sent before using the
219 * generic initialisation data from spca504_open_data.
220 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300221static const __u16 spca504_pccam600_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300222 {0x00, 0x0001, 0x2501},
223 {0x20, 0x0500, 0x0001}, /* snapshot mode */
224 {0x00, 0x0003, 0x2880},
225 {0x00, 0x0001, 0x2881},
226 {}
227};
228
229/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300230static const __u16 spca504A_clicksmart420_init_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231/* {0xa0, 0x0000, 0x0503}, * capture mode */
232 {0x00, 0x0000, 0x2000},
233 {0x00, 0x0013, 0x2301},
234 {0x00, 0x0003, 0x2000},
235 {0x00, 0x0001, 0x21ac},
236 {0x00, 0x0001, 0x21a6},
237 {0x00, 0x0000, 0x21a7}, /* brightness */
238 {0x00, 0x0020, 0x21a8}, /* contrast */
239 {0x00, 0x0001, 0x21ac}, /* sat/hue */
240 {0x00, 0x0000, 0x21ad}, /* hue */
241 {0x00, 0x001a, 0x21ae}, /* saturation */
242 {0x00, 0x0002, 0x21a3}, /* gamma */
243 {0x30, 0x0004, 0x000a},
244 {0xb0, 0x0001, 0x0000},
245
246
247 {0x0a1, 0x0080, 0x0001},
248 {0x30, 0x0049, 0x0000},
249 {0x30, 0x0060, 0x0005},
250 {0x0c, 0x0004, 0x0000},
251 {0x00, 0x0000, 0x0000},
252 {0x00, 0x0000, 0x2000},
253 {0x00, 0x0013, 0x2301},
254 {0x00, 0x0003, 0x2000},
255 {0x00, 0x0000, 0x2000},
256
257 {}
258};
259
260/* clicksmart 420 open data ? */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300261static const __u16 spca504A_clicksmart420_open_data[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300262 {0x00, 0x0001, 0x2501},
263 {0x20, 0x0502, 0x0000},
264 {0x06, 0x0000, 0x0000},
265 {0x00, 0x0004, 0x2880},
266 {0x00, 0x0001, 0x2881},
267/* look like setting a qTable */
268 {0x00, 0x0006, 0x2800},
269 {0x00, 0x0004, 0x2801},
270 {0x00, 0x0004, 0x2802},
271 {0x00, 0x0006, 0x2803},
272 {0x00, 0x000a, 0x2804},
273 {0x00, 0x0010, 0x2805},
274 {0x00, 0x0014, 0x2806},
275 {0x00, 0x0018, 0x2807},
276 {0x00, 0x0005, 0x2808},
277 {0x00, 0x0005, 0x2809},
278 {0x00, 0x0006, 0x280a},
279 {0x00, 0x0008, 0x280b},
280 {0x00, 0x000a, 0x280c},
281 {0x00, 0x0017, 0x280d},
282 {0x00, 0x0018, 0x280e},
283 {0x00, 0x0016, 0x280f},
284
285 {0x00, 0x0006, 0x2810},
286 {0x00, 0x0005, 0x2811},
287 {0x00, 0x0006, 0x2812},
288 {0x00, 0x000a, 0x2813},
289 {0x00, 0x0010, 0x2814},
290 {0x00, 0x0017, 0x2815},
291 {0x00, 0x001c, 0x2816},
292 {0x00, 0x0016, 0x2817},
293 {0x00, 0x0006, 0x2818},
294 {0x00, 0x0007, 0x2819},
295 {0x00, 0x0009, 0x281a},
296 {0x00, 0x000c, 0x281b},
297 {0x00, 0x0014, 0x281c},
298 {0x00, 0x0023, 0x281d},
299 {0x00, 0x0020, 0x281e},
300 {0x00, 0x0019, 0x281f},
301
302 {0x00, 0x0007, 0x2820},
303 {0x00, 0x0009, 0x2821},
304 {0x00, 0x000f, 0x2822},
305 {0x00, 0x0016, 0x2823},
306 {0x00, 0x001b, 0x2824},
307 {0x00, 0x002c, 0x2825},
308 {0x00, 0x0029, 0x2826},
309 {0x00, 0x001f, 0x2827},
310 {0x00, 0x000a, 0x2828},
311 {0x00, 0x000e, 0x2829},
312 {0x00, 0x0016, 0x282a},
313 {0x00, 0x001a, 0x282b},
314 {0x00, 0x0020, 0x282c},
315 {0x00, 0x002a, 0x282d},
316 {0x00, 0x002d, 0x282e},
317 {0x00, 0x0025, 0x282f},
318
319 {0x00, 0x0014, 0x2830},
320 {0x00, 0x001a, 0x2831},
321 {0x00, 0x001f, 0x2832},
322 {0x00, 0x0023, 0x2833},
323 {0x00, 0x0029, 0x2834},
324 {0x00, 0x0030, 0x2835},
325 {0x00, 0x0030, 0x2836},
326 {0x00, 0x0028, 0x2837},
327 {0x00, 0x001d, 0x2838},
328 {0x00, 0x0025, 0x2839},
329 {0x00, 0x0026, 0x283a},
330 {0x00, 0x0027, 0x283b},
331 {0x00, 0x002d, 0x283c},
332 {0x00, 0x0028, 0x283d},
333 {0x00, 0x0029, 0x283e},
334 {0x00, 0x0028, 0x283f},
335
336 {0x00, 0x0007, 0x2840},
337 {0x00, 0x0007, 0x2841},
338 {0x00, 0x000a, 0x2842},
339 {0x00, 0x0013, 0x2843},
340 {0x00, 0x0028, 0x2844},
341 {0x00, 0x0028, 0x2845},
342 {0x00, 0x0028, 0x2846},
343 {0x00, 0x0028, 0x2847},
344 {0x00, 0x0007, 0x2848},
345 {0x00, 0x0008, 0x2849},
346 {0x00, 0x000a, 0x284a},
347 {0x00, 0x001a, 0x284b},
348 {0x00, 0x0028, 0x284c},
349 {0x00, 0x0028, 0x284d},
350 {0x00, 0x0028, 0x284e},
351 {0x00, 0x0028, 0x284f},
352
353 {0x00, 0x000a, 0x2850},
354 {0x00, 0x000a, 0x2851},
355 {0x00, 0x0016, 0x2852},
356 {0x00, 0x0028, 0x2853},
357 {0x00, 0x0028, 0x2854},
358 {0x00, 0x0028, 0x2855},
359 {0x00, 0x0028, 0x2856},
360 {0x00, 0x0028, 0x2857},
361 {0x00, 0x0013, 0x2858},
362 {0x00, 0x001a, 0x2859},
363 {0x00, 0x0028, 0x285a},
364 {0x00, 0x0028, 0x285b},
365 {0x00, 0x0028, 0x285c},
366 {0x00, 0x0028, 0x285d},
367 {0x00, 0x0028, 0x285e},
368 {0x00, 0x0028, 0x285f},
369
370 {0x00, 0x0028, 0x2860},
371 {0x00, 0x0028, 0x2861},
372 {0x00, 0x0028, 0x2862},
373 {0x00, 0x0028, 0x2863},
374 {0x00, 0x0028, 0x2864},
375 {0x00, 0x0028, 0x2865},
376 {0x00, 0x0028, 0x2866},
377 {0x00, 0x0028, 0x2867},
378 {0x00, 0x0028, 0x2868},
379 {0x00, 0x0028, 0x2869},
380 {0x00, 0x0028, 0x286a},
381 {0x00, 0x0028, 0x286b},
382 {0x00, 0x0028, 0x286c},
383 {0x00, 0x0028, 0x286d},
384 {0x00, 0x0028, 0x286e},
385 {0x00, 0x0028, 0x286f},
386
387 {0x00, 0x0028, 0x2870},
388 {0x00, 0x0028, 0x2871},
389 {0x00, 0x0028, 0x2872},
390 {0x00, 0x0028, 0x2873},
391 {0x00, 0x0028, 0x2874},
392 {0x00, 0x0028, 0x2875},
393 {0x00, 0x0028, 0x2876},
394 {0x00, 0x0028, 0x2877},
395 {0x00, 0x0028, 0x2878},
396 {0x00, 0x0028, 0x2879},
397 {0x00, 0x0028, 0x287a},
398 {0x00, 0x0028, 0x287b},
399 {0x00, 0x0028, 0x287c},
400 {0x00, 0x0028, 0x287d},
401 {0x00, 0x0028, 0x287e},
402 {0x00, 0x0028, 0x287f},
403
404 {0xa0, 0x0000, 0x0503},
405 {}
406};
407
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300408static const __u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 { /* Q-table Y-components */
410 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
411 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
412 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
413 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
414 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
415 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
416 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
417 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
418 { /* Q-table C-components */
419 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
420 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
421 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
422 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
427};
428
429/* FIXME: This Q-table is identical to the Creative PC-CAM one,
430 * except for one byte. Possibly a typo?
431 * NWG: 18/05/2003.
432 */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300433static const __u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300434 { /* Q-table Y-components */
435 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
436 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
437 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
438 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
439 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
440 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
441 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
442 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
443 },
444 { /* Q-table C-components */
445 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
446 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
447 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
448 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
453};
454
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300455/* read <len> bytes to gspca_dev->usb_buf */
456static void reg_r(struct gspca_dev *gspca_dev,
457 __u16 req,
458 __u16 index,
459 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300461#ifdef GSPCA_DEBUG
462 if (len > USB_BUF_SZ) {
463 err("reg_r: buffer overflow");
464 return;
465 }
466#endif
467 usb_control_msg(gspca_dev->dev,
468 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 req,
470 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
471 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300472 index,
473 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 500);
475}
476
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300477/* write <len> bytes from gspca_dev->usb_buf */
478static void reg_w(struct gspca_dev *gspca_dev,
479 __u16 req,
480 __u16 value,
481 __u16 index,
482 __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300484#ifdef GSPCA_DEBUG
485 if (len > USB_BUF_SZ) {
486 err("reg_w: buffer overflow");
487 return;
488 }
489#endif
490 usb_control_msg(gspca_dev->dev,
491 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492 req,
493 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300494 value, index,
495 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496 500);
497}
498
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300499/* write req / index / value */
500static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 __u16 req, __u16 index, __u16 value)
502{
503 int ret;
504
505 ret = usb_control_msg(dev,
506 usb_sndctrlpipe(dev, 0),
507 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300508 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300510 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300511 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300512 if (ret < 0)
513 PDEBUG(D_ERR, "reg write: error %d", ret);
514 return ret;
515}
516
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300517/* read 1 byte */
518static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 __u16 value) /* wValue */
520{
521 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300523 ret = usb_control_msg(gspca_dev->dev,
524 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525 0x20, /* request */
526 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
527 value,
528 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 500); /* timeout */
531 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 return 0;
534 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300536}
537
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538/* read 1 or 2 bytes - returns < 0 if error */
539static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 __u16 req, /* bRequest */
541 __u16 index, /* wIndex */
542 __u16 length) /* wLength (1 or 2 only) */
543{
544 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300546 gspca_dev->usb_buf[1] = 0;
547 ret = usb_control_msg(gspca_dev->dev,
548 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549 req,
550 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
551 0, /* value */
552 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 500);
555 if (ret < 0) {
556 PDEBUG(D_ERR, "reg_read err %d", ret);
557 return -1;
558 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300559 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300560}
561
562static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300563 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564{
565 struct usb_device *dev = gspca_dev->dev;
566 int ret, i = 0;
567
568 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300569 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570 if (ret < 0) {
571 PDEBUG(D_ERR,
572 "Register write failed for 0x%x,0x%x,0x%x",
573 data[i][0], data[i][1], data[i][2]);
574 return ret;
575 }
576 i++;
577 }
578 return 0;
579}
580
581static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
582 unsigned int request,
583 unsigned int ybase,
584 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300585 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586{
587 struct usb_device *dev = gspca_dev->dev;
588 int i, err;
589
590 /* loop over y components */
591 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300592 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 if (err < 0)
594 return err;
595 }
596
597 /* loop over c components */
598 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300599 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300600 if (err < 0)
601 return err;
602 }
603 return 0;
604}
605
606static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
607 __u16 req, __u16 idx, __u16 val)
608{
609 struct usb_device *dev = gspca_dev->dev;
610 __u8 notdone;
611
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300612 reg_w_riv(dev, req, idx, val);
613 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
614 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615
616 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
617
618 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300619 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
621}
622
623static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
624 __u16 req,
625 __u16 idx, __u16 val, __u8 stat, __u8 count)
626{
627 struct usb_device *dev = gspca_dev->dev;
628 __u8 status;
629 __u8 endcode;
630
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300631 reg_w_riv(dev, req, idx, val);
632 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633 endcode = stat;
634 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
635 if (!count)
636 return;
637 count = 200;
638 while (--count > 0) {
639 msleep(10);
640 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300641/* reg_w_riv(dev, req, idx, val); */
642 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300643 if (status == endcode) {
644 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
645 status, 200 - count);
646 break;
647 }
648 }
649}
650
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300651static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653 int count = 10;
654
655 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300656 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300657 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658 break;
659 msleep(10);
660 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300661 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300662}
663
664static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
665{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666 int count = 50;
667
668 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300669 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300670 if (gspca_dev->usb_buf[0] != 0) {
671 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300672 reg_w(gspca_dev, 0x21, 0, 1, 1);
673 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300674 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300675 break;
676 }
677 msleep(10);
678 }
679}
680
681static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
682{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300683 __u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300684
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300685 data = gspca_dev->usb_buf;
686 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300688 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300689 reg_r(gspca_dev, 0x23, 0, 64);
690 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691}
692
693static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
694{
695 struct sd *sd = (struct sd *) gspca_dev;
696 struct usb_device *dev = gspca_dev->dev;
697 __u8 Size;
698 __u8 Type;
699 int rc;
700
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300701 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702 Type = 0;
703 switch (sd->bridge) {
704 case BRIDGE_SPCA533:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300705 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300707 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300708 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300709 gspca_dev->usb_buf[0] = 2; /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300710 reg_w(gspca_dev, 0x24, 0, 8, 1);
711 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300713 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300714 reg_w(gspca_dev, 0x25, 0, 4, 1);
715 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300716 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717
718 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300719 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300721 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 break;
723 default:
724/* case BRIDGE_SPCA504B: */
725/* case BRIDGE_SPCA536: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300726 gspca_dev->usb_buf[0] = Size;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300727 reg_w(gspca_dev, 0x25, 0, 4, 1);
728 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729 Type = 6;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300730 gspca_dev->usb_buf[0] = Type;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300731 reg_w(gspca_dev, 0x27, 0, 0, 1);
732 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300733 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300734 break;
735 case BRIDGE_SPCA504:
736 Size += 3;
737 if (sd->subtype == AiptekMiniPenCam13) {
738 /* spca504a aiptek */
739 spca504A_acknowledged_command(gspca_dev,
740 0x08, Size, 0,
741 0x80 | (Size & 0x0f), 1);
742 spca504A_acknowledged_command(gspca_dev,
743 1, 3, 0, 0x9f, 0);
744 } else {
745 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
746 }
747 break;
748 case BRIDGE_SPCA504C:
749 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300750 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
751 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300752 break;
753 }
754}
755
756static void spca504_wait_status(struct gspca_dev *gspca_dev)
757{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300758 int cnt;
759
760 cnt = 256;
761 while (--cnt > 0) {
762 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300763 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300764 return;
765 msleep(10);
766 }
767}
768
769static void spca504B_setQtable(struct gspca_dev *gspca_dev)
770{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300771 gspca_dev->usb_buf[0] = 3;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300772 reg_w(gspca_dev, 0x26, 0, 0, 1);
773 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300774 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775}
776
777static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
778{
779 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300780 int pollreg = 1;
781
782 switch (sd->bridge) {
783 case BRIDGE_SPCA504:
784 case BRIDGE_SPCA504C:
785 pollreg = 0;
786 /* fall thru */
787 default:
788/* case BRIDGE_SPCA533: */
789/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300790 reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
791 reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
792 reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
793 reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
794 reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
795 reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796 break;
797 case BRIDGE_SPCA536:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300798 reg_w(gspca_dev, 0, 0, 0x20f0, 0);
799 reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
800 reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
801 reg_w(gspca_dev, 0, 1, 0x20f4, 0);
802 reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
803 reg_w(gspca_dev, 0, 0, 0x2089, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 break;
805 }
806 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300807 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808}
809
810/* this function is called at probe time */
811static int sd_config(struct gspca_dev *gspca_dev,
812 const struct usb_device_id *id)
813{
814 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816
817 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300819 sd->bridge = id->driver_info >> 8;
820 sd->subtype = id->driver_info;
821
822 if (sd->subtype == AiptekMiniPenCam13) {
823/* try to get the firmware as some cam answer 2.0.1.2.2
824 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300825 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300826 switch (gspca_dev->usb_buf[0]) {
827 case 1:
828 break; /* (right bridge/subtype) */
829 case 2:
830 sd->bridge = BRIDGE_SPCA504B;
831 sd->subtype = 0;
832 break;
833 default:
834 return -ENODEV;
835 }
836 }
837
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 switch (sd->bridge) {
839 default:
840/* case BRIDGE_SPCA504B: */
841/* case BRIDGE_SPCA504: */
842/* case BRIDGE_SPCA536: */
843 cam->cam_mode = vga_mode;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300844 cam->nmodes =ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300845 break;
846 case BRIDGE_SPCA533:
847 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300848 if (sd->subtype == MegaImageVI) /* 320x240 only */
849 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
850 else
851 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300852 break;
853 case BRIDGE_SPCA504C:
854 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300855 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 break;
857 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
859 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
860 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300861 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862 return 0;
863}
864
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300865/* this function is called at probe and resume time */
866static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867{
868 struct sd *sd = (struct sd *) gspca_dev;
869 struct usb_device *dev = gspca_dev->dev;
870 int rc;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 __u8 i;
872 __u8 info[6];
873 int err_code;
874
875 switch (sd->bridge) {
876 case BRIDGE_SPCA504B:
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300877 reg_w(gspca_dev, 0x1d, 0, 0, 0);
878 reg_w(gspca_dev, 0, 1, 0x2306, 0);
879 reg_w(gspca_dev, 0, 0, 0x0d04, 0);
880 reg_w(gspca_dev, 0, 0, 0x2000, 0);
881 reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
882 reg_w(gspca_dev, 0, 0, 0x2306, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300883 /* fall thru */
884 case BRIDGE_SPCA533:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300885 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 spca50x_GetFirmware(gspca_dev);
887 break;
888 case BRIDGE_SPCA536:
889 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300890 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300891 gspca_dev->usb_buf[0] = 0;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300892 reg_w(gspca_dev, 0x24, 0, 0, 1);
893 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300894 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300895 reg_w(gspca_dev, 0x34, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896 spca504B_WaitCmdStatus(gspca_dev);
897 break;
898 case BRIDGE_SPCA504C: /* pccam600 */
899 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300900 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
901 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 spca504_wait_status(gspca_dev);
903 if (sd->subtype == LogitechClickSmart420)
904 write_vector(gspca_dev,
905 spca504A_clicksmart420_open_data);
906 else
907 write_vector(gspca_dev, spca504_pccam600_open_data);
908 err_code = spca50x_setup_qtable(gspca_dev,
909 0x00, 0x2800,
910 0x2840, qtable_creative_pccam);
911 if (err_code < 0) {
912 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
913 return err_code;
914 }
915 break;
916 default:
917/* case BRIDGE_SPCA504: */
918 PDEBUG(D_STREAM, "Opening SPCA504");
919 if (sd->subtype == AiptekMiniPenCam13) {
920 /*****************************/
921 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300922 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300923 PDEBUG(D_STREAM,
924 "Read info: %d %d %d %d %d %d."
925 " Should be 1,0,2,2,0,0",
926 info[0], info[1], info[2],
927 info[3], info[4], info[5]);
928 /* spca504a aiptek */
929 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
930 spca504A_acknowledged_command(gspca_dev, 0x24,
931 8, 3, 0x9e, 1);
932 /* Twice sequencial need status 0xff->0x9e->0x9d */
933 spca504A_acknowledged_command(gspca_dev, 0x24,
934 8, 3, 0x9e, 0);
935
936 spca504A_acknowledged_command(gspca_dev, 0x24,
937 0, 0, 0x9d, 1);
938 /******************************/
939 /* spca504a aiptek */
940 spca504A_acknowledged_command(gspca_dev, 0x08,
941 6, 0, 0x86, 1);
942/* reg_write (dev, 0, 0x2000, 0); */
943/* reg_write (dev, 0, 0x2883, 1); */
944/* spca504A_acknowledged_command (gspca_dev, 0x08,
945 6, 0, 0x86, 1); */
946/* spca504A_acknowledged_command (gspca_dev, 0x24,
947 0, 0, 0x9D, 1); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300948 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
949 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300950 spca504A_acknowledged_command(gspca_dev, 0x01,
951 0x0f, 0, 0xff, 0);
952 }
953 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300954 reg_w_riv(dev, 0, 0x2000, 0);
955 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300956 err_code = spca50x_setup_qtable(gspca_dev,
957 0x00, 0x2800,
958 0x2840,
959 qtable_spca504_default);
960 if (err_code < 0) {
961 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
962 return err_code;
963 }
964 break;
965 }
966 return 0;
967}
968
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300969static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300970{
971 struct sd *sd = (struct sd *) gspca_dev;
972 struct usb_device *dev = gspca_dev->dev;
973 int rc;
974 int enable;
975 __u8 i;
976 __u8 info[6];
977
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300978 /* create the JPEG header */
979 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
Julia Lawall3eb02372009-07-19 07:09:32 -0300980 if (!sd->jpeg_hdr)
981 return -ENOMEM;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300982 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
983 0x22); /* JPEG 411 */
984 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
985
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300986 if (sd->bridge == BRIDGE_SPCA504B)
987 spca504B_setQtable(gspca_dev);
988 spca504B_SetSizeType(gspca_dev);
989 switch (sd->bridge) {
990 default:
991/* case BRIDGE_SPCA504B: */
992/* case BRIDGE_SPCA533: */
993/* case BRIDGE_SPCA536: */
994 if (sd->subtype == MegapixV4 ||
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300995 sd->subtype == LogitechClickSmart820 ||
996 sd->subtype == MegaImageVI) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300997 reg_w(gspca_dev, 0xf0, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300999 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001000 spca504B_WaitCmdStatus(gspca_dev);
1001 } else {
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001002 reg_w(gspca_dev, 0x31, 0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001003 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001004 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001005 }
1006 break;
1007 case BRIDGE_SPCA504:
1008 if (sd->subtype == AiptekMiniPenCam13) {
1009 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001010 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011 PDEBUG(D_STREAM,
1012 "Read info: %d %d %d %d %d %d."
1013 " Should be 1,0,2,2,0,0",
1014 info[0], info[1], info[2],
1015 info[3], info[4], info[5]);
1016 /* spca504a aiptek */
1017 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1018 spca504A_acknowledged_command(gspca_dev, 0x24,
1019 8, 3, 0x9e, 1);
1020 /* Twice sequencial need status 0xff->0x9e->0x9d */
1021 spca504A_acknowledged_command(gspca_dev, 0x24,
1022 8, 3, 0x9e, 0);
1023 spca504A_acknowledged_command(gspca_dev, 0x24,
1024 0, 0, 0x9d, 1);
1025 } else {
1026 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1027 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001028 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001029 PDEBUG(D_STREAM,
1030 "Read info: %d %d %d %d %d %d."
1031 " Should be 1,0,2,2,0,0",
1032 info[0], info[1], info[2],
1033 info[3], info[4], info[5]);
1034 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1035 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1036 }
1037 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001038 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1039 reg_w_riv(dev, 0x0, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001040 break;
1041 case BRIDGE_SPCA504C:
1042 if (sd->subtype == LogitechClickSmart420) {
1043 write_vector(gspca_dev,
1044 spca504A_clicksmart420_init_data);
1045 } else {
1046 write_vector(gspca_dev, spca504_pccam600_init_data);
1047 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001048 enable = (sd->autogain ? 0x04 : 0x01);
1049 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1050 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001051
1052 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001053 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1054 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001055 spca504B_SetSizeType(gspca_dev);
1056 break;
1057 }
1058 sp5xx_initContBrigHueRegisters(gspca_dev);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -03001059 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001060}
1061
1062static void sd_stopN(struct gspca_dev *gspca_dev)
1063{
1064 struct sd *sd = (struct sd *) gspca_dev;
1065 struct usb_device *dev = gspca_dev->dev;
1066
1067 switch (sd->bridge) {
1068 default:
1069/* case BRIDGE_SPCA533: */
1070/* case BRIDGE_SPCA536: */
1071/* case BRIDGE_SPCA504B: */
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001072 reg_w(gspca_dev, 0x31, 0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001073 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001074 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075 break;
1076 case BRIDGE_SPCA504:
1077 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001078 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001079
1080 if (sd->subtype == AiptekMiniPenCam13) {
1081 /* spca504a aiptek */
1082/* spca504A_acknowledged_command(gspca_dev, 0x08,
1083 6, 0, 0x86, 1); */
1084 spca504A_acknowledged_command(gspca_dev, 0x24,
1085 0x00, 0x00, 0x9d, 1);
1086 spca504A_acknowledged_command(gspca_dev, 0x01,
1087 0x0f, 0x00, 0xff, 1);
1088 } else {
1089 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001090 reg_w_riv(dev, 0x01, 0x000f, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001091 }
1092 break;
1093 }
1094}
1095
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001096static void sd_stop0(struct gspca_dev *gspca_dev)
1097{
1098 struct sd *sd = (struct sd *) gspca_dev;
1099
1100 kfree(sd->jpeg_hdr);
1101}
1102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001103static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1104 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001105 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001106 int len) /* iso packet length */
1107{
1108 struct sd *sd = (struct sd *) gspca_dev;
1109 int i, sof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001110 static unsigned char ffd9[] = {0xff, 0xd9};
1111
1112/* frames are jpeg 4.1.1 without 0xff escape */
1113 switch (sd->bridge) {
1114 case BRIDGE_SPCA533:
1115 if (data[0] == 0xff) {
1116 if (data[1] != 0x01) { /* drop packet */
1117/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1118 return;
1119 }
1120 sof = 1;
1121 data += SPCA533_OFFSET_DATA;
1122 len -= SPCA533_OFFSET_DATA;
1123 } else {
1124 data += 1;
1125 len -= 1;
1126 }
1127 break;
1128 case BRIDGE_SPCA536:
1129 if (data[0] == 0xff) {
1130 sof = 1;
1131 data += SPCA536_OFFSET_DATA;
1132 len -= SPCA536_OFFSET_DATA;
1133 } else {
1134 data += 2;
1135 len -= 2;
1136 }
1137 break;
1138 default:
1139/* case BRIDGE_SPCA504: */
1140/* case BRIDGE_SPCA504B: */
1141 switch (data[0]) {
1142 case 0xfe: /* start of frame */
1143 sof = 1;
1144 data += SPCA50X_OFFSET_DATA;
1145 len -= SPCA50X_OFFSET_DATA;
1146 break;
1147 case 0xff: /* drop packet */
1148/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1149 return;
1150 default:
1151 data += 1;
1152 len -= 1;
1153 break;
1154 }
1155 break;
1156 case BRIDGE_SPCA504C:
1157 switch (data[0]) {
1158 case 0xfe: /* start of frame */
1159 sof = 1;
1160 data += SPCA504_PCCAM600_OFFSET_DATA;
1161 len -= SPCA504_PCCAM600_OFFSET_DATA;
1162 break;
1163 case 0xff: /* drop packet */
1164/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1165 return;
1166 default:
1167 data += 1;
1168 len -= 1;
1169 break;
1170 }
1171 break;
1172 }
1173 if (sof) { /* start of frame */
1174 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1175 ffd9, 2);
1176
1177 /* put the JPEG header in the new frame */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001178 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
1179 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001180 }
1181
1182 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001183 i = 0;
1184 do {
1185 if (data[i] == 0xff) {
1186 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1187 data, i + 1);
1188 len -= i;
1189 data += i;
1190 *data = 0x00;
1191 i = 0;
1192 }
1193 i++;
1194 } while (i < len);
1195 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001196}
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)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001392 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001393 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1394 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1395 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1396 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1397 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1398 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1399 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1400 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1401 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1402 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1403 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1404 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1405 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1406 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1407 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1408 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1409 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1410 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1411 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1412 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1413 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1414 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1415 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1416 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1417 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1418 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1419 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1420 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1421 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1422 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1423 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1424 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1425 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1426 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1427 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1428 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1429 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1430 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001431 {}
1432};
1433MODULE_DEVICE_TABLE(usb, device_table);
1434
1435/* -- device connect -- */
1436static int sd_probe(struct usb_interface *intf,
1437 const struct usb_device_id *id)
1438{
1439 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1440 THIS_MODULE);
1441}
1442
1443static struct usb_driver sd_driver = {
1444 .name = MODULE_NAME,
1445 .id_table = device_table,
1446 .probe = sd_probe,
1447 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001448#ifdef CONFIG_PM
1449 .suspend = gspca_suspend,
1450 .resume = gspca_resume,
1451#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001452};
1453
1454/* -- module insert / remove -- */
1455static int __init sd_mod_init(void)
1456{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001457 int ret;
1458 ret = usb_register(&sd_driver);
1459 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001460 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001461 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001462 return 0;
1463}
1464static void __exit sd_mod_exit(void)
1465{
1466 usb_deregister(&sd_driver);
1467 PDEBUG(D_PROBE, "deregistered");
1468}
1469
1470module_init(sd_mod_init);
1471module_exit(sd_mod_exit);