]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/media/video/gspca/sunplus.c
V4L/DVB (11035): mt9t031 bugfix
[mirror_ubuntu-zesty-kernel.git] / drivers / media / video / gspca / sunplus.c
CommitLineData
6a7eba24
JFM
1/*
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"
36e819db 25#define QUANT_VAL 5 /* quantization table */
6a7eba24
JFM
26#include "jpeg.h"
27
6a7eba24
JFM
28MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
29MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
30MODULE_LICENSE("GPL");
31
32/* specific webcam descriptor */
33struct sd {
34 struct gspca_dev gspca_dev; /* !! must be the first item */
35
a5ae2062 36 __u8 packet[ISO_MAX_SIZE + 128];
6a7eba24
JFM
37 /* !! no more than 128 ff in an ISO packet */
38
39 unsigned char brightness;
40 unsigned char contrast;
41 unsigned char colors;
42 unsigned char autogain;
43
6a7eba24
JFM
44 char bridge;
45#define BRIDGE_SPCA504 0
46#define BRIDGE_SPCA504B 1
47#define BRIDGE_SPCA504C 2
48#define BRIDGE_SPCA533 3
49#define BRIDGE_SPCA536 4
50 char subtype;
51#define AiptekMiniPenCam13 1
52#define LogitechClickSmart420 2
53#define LogitechClickSmart820 3
54#define MegapixV4 4
55};
56
57/* V4L2 controls supported by the driver */
58static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
59static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
60static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
62static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
64static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
66
67static struct ctrl sd_ctrls[] = {
68#define SD_BRIGHTNESS 0
69 {
70 {
71 .id = V4L2_CID_BRIGHTNESS,
72 .type = V4L2_CTRL_TYPE_INTEGER,
73 .name = "Brightness",
74 .minimum = 0,
75 .maximum = 0xff,
76 .step = 1,
77 .default_value = 0,
78 },
79 .set = sd_setbrightness,
80 .get = sd_getbrightness,
81 },
82#define SD_CONTRAST 1
83 {
84 {
85 .id = V4L2_CID_CONTRAST,
86 .type = V4L2_CTRL_TYPE_INTEGER,
87 .name = "Contrast",
88 .minimum = 0,
89 .maximum = 0xff,
90 .step = 1,
91 .default_value = 0x20,
92 },
93 .set = sd_setcontrast,
94 .get = sd_getcontrast,
95 },
96#define SD_COLOR 2
97 {
98 {
99 .id = V4L2_CID_SATURATION,
100 .type = V4L2_CTRL_TYPE_INTEGER,
101 .name = "Color",
102 .minimum = 0,
103 .maximum = 0xff,
104 .step = 1,
105 .default_value = 0x1a,
106 },
107 .set = sd_setcolors,
108 .get = sd_getcolors,
109 },
110#define SD_AUTOGAIN 3
111 {
112 {
113 .id = V4L2_CID_AUTOGAIN,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 .name = "Auto Gain",
116 .minimum = 0,
117 .maximum = 1,
118 .step = 1,
119 .default_value = 1,
120 },
121 .set = sd_setautogain,
122 .get = sd_getautogain,
123 },
124};
125
cc611b8a 126static const struct v4l2_pix_format vga_mode[] = {
c2446b3e
JFM
127 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
128 .bytesperline = 320,
129 .sizeimage = 320 * 240 * 3 / 8 + 590,
130 .colorspace = V4L2_COLORSPACE_JPEG,
131 .priv = 2},
132 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133 .bytesperline = 640,
134 .sizeimage = 640 * 480 * 3 / 8 + 590,
135 .colorspace = V4L2_COLORSPACE_JPEG,
136 .priv = 1},
6a7eba24
JFM
137};
138
cc611b8a 139static const struct v4l2_pix_format custom_mode[] = {
c2446b3e
JFM
140 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
141 .bytesperline = 320,
142 .sizeimage = 320 * 240 * 3 / 8 + 590,
143 .colorspace = V4L2_COLORSPACE_JPEG,
144 .priv = 2},
145 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
146 .bytesperline = 464,
147 .sizeimage = 464 * 480 * 3 / 8 + 590,
148 .colorspace = V4L2_COLORSPACE_JPEG,
149 .priv = 1},
6a7eba24
JFM
150};
151
cc611b8a 152static const struct v4l2_pix_format vga_mode2[] = {
c2446b3e
JFM
153 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
154 .bytesperline = 176,
155 .sizeimage = 176 * 144 * 3 / 8 + 590,
156 .colorspace = V4L2_COLORSPACE_JPEG,
157 .priv = 4},
158 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
159 .bytesperline = 320,
160 .sizeimage = 320 * 240 * 3 / 8 + 590,
161 .colorspace = V4L2_COLORSPACE_JPEG,
162 .priv = 3},
163 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
164 .bytesperline = 352,
165 .sizeimage = 352 * 288 * 3 / 8 + 590,
166 .colorspace = V4L2_COLORSPACE_JPEG,
167 .priv = 2},
168 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
169 .bytesperline = 640,
170 .sizeimage = 640 * 480 * 3 / 8 + 590,
171 .colorspace = V4L2_COLORSPACE_JPEG,
172 .priv = 1},
6a7eba24
JFM
173};
174
175#define SPCA50X_OFFSET_DATA 10
176#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
177#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
178#define SPCA504_PCCAM600_OFFSET_MODE 5
179#define SPCA504_PCCAM600_OFFSET_DATA 14
180 /* Frame packet header offsets for the spca533 */
181#define SPCA533_OFFSET_DATA 16
182#define SPCA533_OFFSET_FRAMSEQ 15
183/* Frame packet header offsets for the spca536 */
184#define SPCA536_OFFSET_DATA 4
185#define SPCA536_OFFSET_FRAMSEQ 1
186
187/* Initialisation data for the Creative PC-CAM 600 */
a5ae2062 188static const __u16 spca504_pccam600_init_data[][3] = {
6a7eba24
JFM
189/* {0xa0, 0x0000, 0x0503}, * capture mode */
190 {0x00, 0x0000, 0x2000},
191 {0x00, 0x0013, 0x2301},
192 {0x00, 0x0003, 0x2000},
193 {0x00, 0x0001, 0x21ac},
194 {0x00, 0x0001, 0x21a6},
195 {0x00, 0x0000, 0x21a7}, /* brightness */
196 {0x00, 0x0020, 0x21a8}, /* contrast */
197 {0x00, 0x0001, 0x21ac}, /* sat/hue */
198 {0x00, 0x0000, 0x21ad}, /* hue */
199 {0x00, 0x001a, 0x21ae}, /* saturation */
200 {0x00, 0x0002, 0x21a3}, /* gamma */
201 {0x30, 0x0154, 0x0008},
202 {0x30, 0x0004, 0x0006},
203 {0x30, 0x0258, 0x0009},
204 {0x30, 0x0004, 0x0000},
205 {0x30, 0x0093, 0x0004},
206 {0x30, 0x0066, 0x0005},
207 {0x00, 0x0000, 0x2000},
208 {0x00, 0x0013, 0x2301},
209 {0x00, 0x0003, 0x2000},
210 {0x00, 0x0013, 0x2301},
211 {0x00, 0x0003, 0x2000},
212 {}
213};
214
215/* Creative PC-CAM 600 specific open data, sent before using the
216 * generic initialisation data from spca504_open_data.
217 */
a5ae2062 218static const __u16 spca504_pccam600_open_data[][3] = {
6a7eba24
JFM
219 {0x00, 0x0001, 0x2501},
220 {0x20, 0x0500, 0x0001}, /* snapshot mode */
221 {0x00, 0x0003, 0x2880},
222 {0x00, 0x0001, 0x2881},
223 {}
224};
225
226/* Initialisation data for the logitech clicksmart 420 */
a5ae2062 227static const __u16 spca504A_clicksmart420_init_data[][3] = {
6a7eba24
JFM
228/* {0xa0, 0x0000, 0x0503}, * capture mode */
229 {0x00, 0x0000, 0x2000},
230 {0x00, 0x0013, 0x2301},
231 {0x00, 0x0003, 0x2000},
232 {0x00, 0x0001, 0x21ac},
233 {0x00, 0x0001, 0x21a6},
234 {0x00, 0x0000, 0x21a7}, /* brightness */
235 {0x00, 0x0020, 0x21a8}, /* contrast */
236 {0x00, 0x0001, 0x21ac}, /* sat/hue */
237 {0x00, 0x0000, 0x21ad}, /* hue */
238 {0x00, 0x001a, 0x21ae}, /* saturation */
239 {0x00, 0x0002, 0x21a3}, /* gamma */
240 {0x30, 0x0004, 0x000a},
241 {0xb0, 0x0001, 0x0000},
242
243
244 {0x0a1, 0x0080, 0x0001},
245 {0x30, 0x0049, 0x0000},
246 {0x30, 0x0060, 0x0005},
247 {0x0c, 0x0004, 0x0000},
248 {0x00, 0x0000, 0x0000},
249 {0x00, 0x0000, 0x2000},
250 {0x00, 0x0013, 0x2301},
251 {0x00, 0x0003, 0x2000},
252 {0x00, 0x0000, 0x2000},
253
254 {}
255};
256
257/* clicksmart 420 open data ? */
a5ae2062 258static const __u16 spca504A_clicksmart420_open_data[][3] = {
6a7eba24
JFM
259 {0x00, 0x0001, 0x2501},
260 {0x20, 0x0502, 0x0000},
261 {0x06, 0x0000, 0x0000},
262 {0x00, 0x0004, 0x2880},
263 {0x00, 0x0001, 0x2881},
264/* look like setting a qTable */
265 {0x00, 0x0006, 0x2800},
266 {0x00, 0x0004, 0x2801},
267 {0x00, 0x0004, 0x2802},
268 {0x00, 0x0006, 0x2803},
269 {0x00, 0x000a, 0x2804},
270 {0x00, 0x0010, 0x2805},
271 {0x00, 0x0014, 0x2806},
272 {0x00, 0x0018, 0x2807},
273 {0x00, 0x0005, 0x2808},
274 {0x00, 0x0005, 0x2809},
275 {0x00, 0x0006, 0x280a},
276 {0x00, 0x0008, 0x280b},
277 {0x00, 0x000a, 0x280c},
278 {0x00, 0x0017, 0x280d},
279 {0x00, 0x0018, 0x280e},
280 {0x00, 0x0016, 0x280f},
281
282 {0x00, 0x0006, 0x2810},
283 {0x00, 0x0005, 0x2811},
284 {0x00, 0x0006, 0x2812},
285 {0x00, 0x000a, 0x2813},
286 {0x00, 0x0010, 0x2814},
287 {0x00, 0x0017, 0x2815},
288 {0x00, 0x001c, 0x2816},
289 {0x00, 0x0016, 0x2817},
290 {0x00, 0x0006, 0x2818},
291 {0x00, 0x0007, 0x2819},
292 {0x00, 0x0009, 0x281a},
293 {0x00, 0x000c, 0x281b},
294 {0x00, 0x0014, 0x281c},
295 {0x00, 0x0023, 0x281d},
296 {0x00, 0x0020, 0x281e},
297 {0x00, 0x0019, 0x281f},
298
299 {0x00, 0x0007, 0x2820},
300 {0x00, 0x0009, 0x2821},
301 {0x00, 0x000f, 0x2822},
302 {0x00, 0x0016, 0x2823},
303 {0x00, 0x001b, 0x2824},
304 {0x00, 0x002c, 0x2825},
305 {0x00, 0x0029, 0x2826},
306 {0x00, 0x001f, 0x2827},
307 {0x00, 0x000a, 0x2828},
308 {0x00, 0x000e, 0x2829},
309 {0x00, 0x0016, 0x282a},
310 {0x00, 0x001a, 0x282b},
311 {0x00, 0x0020, 0x282c},
312 {0x00, 0x002a, 0x282d},
313 {0x00, 0x002d, 0x282e},
314 {0x00, 0x0025, 0x282f},
315
316 {0x00, 0x0014, 0x2830},
317 {0x00, 0x001a, 0x2831},
318 {0x00, 0x001f, 0x2832},
319 {0x00, 0x0023, 0x2833},
320 {0x00, 0x0029, 0x2834},
321 {0x00, 0x0030, 0x2835},
322 {0x00, 0x0030, 0x2836},
323 {0x00, 0x0028, 0x2837},
324 {0x00, 0x001d, 0x2838},
325 {0x00, 0x0025, 0x2839},
326 {0x00, 0x0026, 0x283a},
327 {0x00, 0x0027, 0x283b},
328 {0x00, 0x002d, 0x283c},
329 {0x00, 0x0028, 0x283d},
330 {0x00, 0x0029, 0x283e},
331 {0x00, 0x0028, 0x283f},
332
333 {0x00, 0x0007, 0x2840},
334 {0x00, 0x0007, 0x2841},
335 {0x00, 0x000a, 0x2842},
336 {0x00, 0x0013, 0x2843},
337 {0x00, 0x0028, 0x2844},
338 {0x00, 0x0028, 0x2845},
339 {0x00, 0x0028, 0x2846},
340 {0x00, 0x0028, 0x2847},
341 {0x00, 0x0007, 0x2848},
342 {0x00, 0x0008, 0x2849},
343 {0x00, 0x000a, 0x284a},
344 {0x00, 0x001a, 0x284b},
345 {0x00, 0x0028, 0x284c},
346 {0x00, 0x0028, 0x284d},
347 {0x00, 0x0028, 0x284e},
348 {0x00, 0x0028, 0x284f},
349
350 {0x00, 0x000a, 0x2850},
351 {0x00, 0x000a, 0x2851},
352 {0x00, 0x0016, 0x2852},
353 {0x00, 0x0028, 0x2853},
354 {0x00, 0x0028, 0x2854},
355 {0x00, 0x0028, 0x2855},
356 {0x00, 0x0028, 0x2856},
357 {0x00, 0x0028, 0x2857},
358 {0x00, 0x0013, 0x2858},
359 {0x00, 0x001a, 0x2859},
360 {0x00, 0x0028, 0x285a},
361 {0x00, 0x0028, 0x285b},
362 {0x00, 0x0028, 0x285c},
363 {0x00, 0x0028, 0x285d},
364 {0x00, 0x0028, 0x285e},
365 {0x00, 0x0028, 0x285f},
366
367 {0x00, 0x0028, 0x2860},
368 {0x00, 0x0028, 0x2861},
369 {0x00, 0x0028, 0x2862},
370 {0x00, 0x0028, 0x2863},
371 {0x00, 0x0028, 0x2864},
372 {0x00, 0x0028, 0x2865},
373 {0x00, 0x0028, 0x2866},
374 {0x00, 0x0028, 0x2867},
375 {0x00, 0x0028, 0x2868},
376 {0x00, 0x0028, 0x2869},
377 {0x00, 0x0028, 0x286a},
378 {0x00, 0x0028, 0x286b},
379 {0x00, 0x0028, 0x286c},
380 {0x00, 0x0028, 0x286d},
381 {0x00, 0x0028, 0x286e},
382 {0x00, 0x0028, 0x286f},
383
384 {0x00, 0x0028, 0x2870},
385 {0x00, 0x0028, 0x2871},
386 {0x00, 0x0028, 0x2872},
387 {0x00, 0x0028, 0x2873},
388 {0x00, 0x0028, 0x2874},
389 {0x00, 0x0028, 0x2875},
390 {0x00, 0x0028, 0x2876},
391 {0x00, 0x0028, 0x2877},
392 {0x00, 0x0028, 0x2878},
393 {0x00, 0x0028, 0x2879},
394 {0x00, 0x0028, 0x287a},
395 {0x00, 0x0028, 0x287b},
396 {0x00, 0x0028, 0x287c},
397 {0x00, 0x0028, 0x287d},
398 {0x00, 0x0028, 0x287e},
399 {0x00, 0x0028, 0x287f},
400
401 {0xa0, 0x0000, 0x0503},
402 {}
403};
404
a5ae2062 405static const __u8 qtable_creative_pccam[2][64] = {
6a7eba24
JFM
406 { /* Q-table Y-components */
407 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
408 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
409 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
410 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
411 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
412 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
413 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
414 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
415 { /* Q-table C-components */
416 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
417 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
418 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
419 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
420 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
421 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
422 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
423 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
424};
425
426/* FIXME: This Q-table is identical to the Creative PC-CAM one,
427 * except for one byte. Possibly a typo?
428 * NWG: 18/05/2003.
429 */
a5ae2062 430static const __u8 qtable_spca504_default[2][64] = {
6a7eba24
JFM
431 { /* Q-table Y-components */
432 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
433 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
434 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
435 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
436 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
437 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
438 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
439 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
440 },
441 { /* Q-table C-components */
442 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
443 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
444 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
445 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
446 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
447 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
448 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
449 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
450};
451
8295d99e
JFM
452/* read <len> bytes to gspca_dev->usb_buf */
453static void reg_r(struct gspca_dev *gspca_dev,
454 __u16 req,
455 __u16 index,
456 __u16 len)
6a7eba24 457{
8295d99e
JFM
458#ifdef GSPCA_DEBUG
459 if (len > USB_BUF_SZ) {
460 err("reg_r: buffer overflow");
461 return;
462 }
463#endif
464 usb_control_msg(gspca_dev->dev,
465 usb_rcvctrlpipe(gspca_dev->dev, 0),
6a7eba24
JFM
466 req,
467 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
468 0, /* value */
8295d99e
JFM
469 index,
470 len ? gspca_dev->usb_buf : NULL, len,
6a7eba24
JFM
471 500);
472}
473
8295d99e
JFM
474/* write <len> bytes from gspca_dev->usb_buf */
475static void reg_w(struct gspca_dev *gspca_dev,
476 __u16 req,
477 __u16 value,
478 __u16 index,
479 __u16 len)
6a7eba24 480{
8295d99e
JFM
481#ifdef GSPCA_DEBUG
482 if (len > USB_BUF_SZ) {
483 err("reg_w: buffer overflow");
484 return;
485 }
486#endif
487 usb_control_msg(gspca_dev->dev,
488 usb_sndctrlpipe(gspca_dev->dev, 0),
6a7eba24
JFM
489 req,
490 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
8295d99e
JFM
491 value, index,
492 len ? gspca_dev->usb_buf : NULL, len,
6a7eba24
JFM
493 500);
494}
495
739570bb
JFM
496/* write req / index / value */
497static int reg_w_riv(struct usb_device *dev,
6a7eba24
JFM
498 __u16 req, __u16 index, __u16 value)
499{
500 int ret;
501
502 ret = usb_control_msg(dev,
503 usb_sndctrlpipe(dev, 0),
504 req,
bf7f0b98 505 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
6a7eba24 506 value, index, NULL, 0, 500);
739570bb 507 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
956e42d2 508 req, index, value, ret);
6a7eba24
JFM
509 if (ret < 0)
510 PDEBUG(D_ERR, "reg write: error %d", ret);
511 return ret;
512}
513
739570bb
JFM
514/* read 1 byte */
515static int reg_r_1(struct gspca_dev *gspca_dev,
6a7eba24
JFM
516 __u16 value) /* wValue */
517{
518 int ret;
6a7eba24 519
739570bb
JFM
520 ret = usb_control_msg(gspca_dev->dev,
521 usb_rcvctrlpipe(gspca_dev->dev, 0),
6a7eba24
JFM
522 0x20, /* request */
523 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
524 value,
525 0, /* index */
739570bb 526 gspca_dev->usb_buf, 1,
6a7eba24
JFM
527 500); /* timeout */
528 if (ret < 0) {
739570bb 529 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
6a7eba24
JFM
530 return 0;
531 }
739570bb 532 return gspca_dev->usb_buf[0];
6a7eba24
JFM
533}
534
739570bb
JFM
535/* read 1 or 2 bytes - returns < 0 if error */
536static int reg_r_12(struct gspca_dev *gspca_dev,
6a7eba24
JFM
537 __u16 req, /* bRequest */
538 __u16 index, /* wIndex */
539 __u16 length) /* wLength (1 or 2 only) */
540{
541 int ret;
6a7eba24 542
739570bb
JFM
543 gspca_dev->usb_buf[1] = 0;
544 ret = usb_control_msg(gspca_dev->dev,
545 usb_rcvctrlpipe(gspca_dev->dev, 0),
6a7eba24
JFM
546 req,
547 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
548 0, /* value */
549 index,
739570bb 550 gspca_dev->usb_buf, length,
6a7eba24
JFM
551 500);
552 if (ret < 0) {
553 PDEBUG(D_ERR, "reg_read err %d", ret);
554 return -1;
555 }
739570bb 556 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
6a7eba24
JFM
557}
558
559static int write_vector(struct gspca_dev *gspca_dev,
a5ae2062 560 const __u16 data[][3])
6a7eba24
JFM
561{
562 struct usb_device *dev = gspca_dev->dev;
563 int ret, i = 0;
564
565 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
739570bb 566 ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
6a7eba24
JFM
567 if (ret < 0) {
568 PDEBUG(D_ERR,
569 "Register write failed for 0x%x,0x%x,0x%x",
570 data[i][0], data[i][1], data[i][2]);
571 return ret;
572 }
573 i++;
574 }
575 return 0;
576}
577
578static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
579 unsigned int request,
580 unsigned int ybase,
581 unsigned int cbase,
a5ae2062 582 const __u8 qtable[2][64])
6a7eba24
JFM
583{
584 struct usb_device *dev = gspca_dev->dev;
585 int i, err;
586
587 /* loop over y components */
588 for (i = 0; i < 64; i++) {
739570bb 589 err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
6a7eba24
JFM
590 if (err < 0)
591 return err;
592 }
593
594 /* loop over c components */
595 for (i = 0; i < 64; i++) {
739570bb 596 err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
6a7eba24
JFM
597 if (err < 0)
598 return err;
599 }
600 return 0;
601}
602
603static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
604 __u16 req, __u16 idx, __u16 val)
605{
606 struct usb_device *dev = gspca_dev->dev;
607 __u8 notdone;
608
739570bb
JFM
609 reg_w_riv(dev, req, idx, val);
610 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
611 reg_w_riv(dev, req, idx, val);
6a7eba24
JFM
612
613 PDEBUG(D_FRAM, "before wait 0x%x", notdone);
614
615 msleep(200);
739570bb 616 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
6a7eba24
JFM
617 PDEBUG(D_FRAM, "after wait 0x%x", notdone);
618}
619
620static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
621 __u16 req,
622 __u16 idx, __u16 val, __u8 stat, __u8 count)
623{
624 struct usb_device *dev = gspca_dev->dev;
625 __u8 status;
626 __u8 endcode;
627
739570bb
JFM
628 reg_w_riv(dev, req, idx, val);
629 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
6a7eba24
JFM
630 endcode = stat;
631 PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
632 if (!count)
633 return;
634 count = 200;
635 while (--count > 0) {
636 msleep(10);
637 /* gsmart mini2 write a each wait setting 1 ms is enought */
739570bb
JFM
638/* reg_w_riv(dev, req, idx, val); */
639 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
6a7eba24
JFM
640 if (status == endcode) {
641 PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
642 status, 200 - count);
643 break;
644 }
645 }
646}
647
739570bb 648static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
6a7eba24 649{
6a7eba24
JFM
650 int count = 10;
651
652 while (--count > 0) {
8295d99e 653 reg_r(gspca_dev, 0x21, 0, 1);
739570bb 654 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
6a7eba24
JFM
655 break;
656 msleep(10);
657 }
739570bb 658 return gspca_dev->usb_buf[0];
6a7eba24
JFM
659}
660
661static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
662{
6a7eba24
JFM
663 int count = 50;
664
665 while (--count > 0) {
8295d99e 666 reg_r(gspca_dev, 0x21, 1, 1);
739570bb
JFM
667 if (gspca_dev->usb_buf[0] != 0) {
668 gspca_dev->usb_buf[0] = 0;
8295d99e
JFM
669 reg_w(gspca_dev, 0x21, 0, 1, 1);
670 reg_r(gspca_dev, 0x21, 1, 1);
739570bb 671 spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
672 break;
673 }
674 msleep(10);
675 }
676}
677
678static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
679{
739570bb 680 __u8 *data;
6a7eba24 681
8295d99e
JFM
682 data = gspca_dev->usb_buf;
683 reg_r(gspca_dev, 0x20, 0, 5);
6a7eba24 684 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
739570bb 685 data[0], data[1], data[2], data[3], data[4]);
8295d99e
JFM
686 reg_r(gspca_dev, 0x23, 0, 64);
687 reg_r(gspca_dev, 0x23, 1, 64);
6a7eba24
JFM
688}
689
690static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
691{
692 struct sd *sd = (struct sd *) gspca_dev;
693 struct usb_device *dev = gspca_dev->dev;
694 __u8 Size;
695 __u8 Type;
696 int rc;
697
c2446b3e 698 Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
6a7eba24
JFM
699 Type = 0;
700 switch (sd->bridge) {
701 case BRIDGE_SPCA533:
8295d99e 702 reg_w(gspca_dev, 0x31, 0, 0, 0);
6a7eba24 703 spca504B_WaitCmdStatus(gspca_dev);
739570bb 704 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24 705 spca50x_GetFirmware(gspca_dev);
739570bb 706 gspca_dev->usb_buf[0] = 2; /* type */
8295d99e
JFM
707 reg_w(gspca_dev, 0x24, 0, 8, 1);
708 reg_r(gspca_dev, 0x24, 8, 1);
6a7eba24 709
739570bb 710 gspca_dev->usb_buf[0] = Size;
8295d99e
JFM
711 reg_w(gspca_dev, 0x25, 0, 4, 1);
712 reg_r(gspca_dev, 0x25, 4, 1); /* size */
739570bb 713 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
714
715 /* Init the cam width height with some values get on init ? */
8295d99e 716 reg_w(gspca_dev, 0x31, 0, 4, 0);
6a7eba24 717 spca504B_WaitCmdStatus(gspca_dev);
739570bb 718 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
719 break;
720 default:
721/* case BRIDGE_SPCA504B: */
722/* case BRIDGE_SPCA536: */
739570bb 723 gspca_dev->usb_buf[0] = Size;
8295d99e
JFM
724 reg_w(gspca_dev, 0x25, 0, 4, 1);
725 reg_r(gspca_dev, 0x25, 4, 1); /* size */
6a7eba24 726 Type = 6;
739570bb 727 gspca_dev->usb_buf[0] = Type;
8295d99e
JFM
728 reg_w(gspca_dev, 0x27, 0, 0, 1);
729 reg_r(gspca_dev, 0x27, 0, 1); /* type */
739570bb 730 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
731 break;
732 case BRIDGE_SPCA504:
733 Size += 3;
734 if (sd->subtype == AiptekMiniPenCam13) {
735 /* spca504a aiptek */
736 spca504A_acknowledged_command(gspca_dev,
737 0x08, Size, 0,
738 0x80 | (Size & 0x0f), 1);
739 spca504A_acknowledged_command(gspca_dev,
740 1, 3, 0, 0x9f, 0);
741 } else {
742 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
743 }
744 break;
745 case BRIDGE_SPCA504C:
746 /* capture mode */
739570bb
JFM
747 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
748 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
6a7eba24
JFM
749 break;
750 }
751}
752
753static void spca504_wait_status(struct gspca_dev *gspca_dev)
754{
6a7eba24
JFM
755 int cnt;
756
757 cnt = 256;
758 while (--cnt > 0) {
759 /* With this we get the status, when return 0 it's all ok */
739570bb 760 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
6a7eba24
JFM
761 return;
762 msleep(10);
763 }
764}
765
766static void spca504B_setQtable(struct gspca_dev *gspca_dev)
767{
739570bb 768 gspca_dev->usb_buf[0] = 3;
8295d99e
JFM
769 reg_w(gspca_dev, 0x26, 0, 0, 1);
770 reg_r(gspca_dev, 0x26, 0, 1);
739570bb 771 spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
772}
773
774static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
775{
776 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24
JFM
777 int pollreg = 1;
778
779 switch (sd->bridge) {
780 case BRIDGE_SPCA504:
781 case BRIDGE_SPCA504C:
782 pollreg = 0;
783 /* fall thru */
784 default:
785/* case BRIDGE_SPCA533: */
786/* case BRIDGE_SPCA504B: */
8295d99e
JFM
787 reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
788 reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
789 reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
790 reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
791 reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
792 reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
6a7eba24
JFM
793 break;
794 case BRIDGE_SPCA536:
8295d99e
JFM
795 reg_w(gspca_dev, 0, 0, 0x20f0, 0);
796 reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
797 reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
798 reg_w(gspca_dev, 0, 1, 0x20f4, 0);
799 reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
800 reg_w(gspca_dev, 0, 0, 0x2089, 0);
6a7eba24
JFM
801 break;
802 }
803 if (pollreg)
739570bb 804 spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
805}
806
807/* this function is called at probe time */
808static int sd_config(struct gspca_dev *gspca_dev,
809 const struct usb_device_id *id)
810{
811 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24 812 struct cam *cam;
9d64fdb1
JFM
813
814 cam = &gspca_dev->cam;
9d64fdb1
JFM
815
816 sd->bridge = id->driver_info >> 8;
817 sd->subtype = id->driver_info;
818
819 if (sd->subtype == AiptekMiniPenCam13) {
6a7eba24
JFM
820/* try to get the firmware as some cam answer 2.0.1.2.2
821 * and should be a spca504b then overwrite that setting */
8295d99e 822 reg_r(gspca_dev, 0x20, 0, 1);
9d64fdb1
JFM
823 switch (gspca_dev->usb_buf[0]) {
824 case 1:
825 break; /* (right bridge/subtype) */
826 case 2:
6a7eba24 827 sd->bridge = BRIDGE_SPCA504B;
9d64fdb1 828 sd->subtype = 0;
6a7eba24 829 break;
9d64fdb1
JFM
830 default:
831 return -ENODEV;
6a7eba24 832 }
6a7eba24
JFM
833 }
834
6a7eba24
JFM
835 switch (sd->bridge) {
836 default:
837/* case BRIDGE_SPCA504B: */
838/* case BRIDGE_SPCA504: */
839/* case BRIDGE_SPCA536: */
840 cam->cam_mode = vga_mode;
841 cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
842 break;
843 case BRIDGE_SPCA533:
844 cam->cam_mode = custom_mode;
845 cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
846 break;
847 case BRIDGE_SPCA504C:
848 cam->cam_mode = vga_mode2;
849 cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
850 break;
851 }
6a7eba24
JFM
852 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
853 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
854 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
855 return 0;
856}
857
012d6b02
JFM
858/* this function is called at probe and resume time */
859static int sd_init(struct gspca_dev *gspca_dev)
6a7eba24
JFM
860{
861 struct sd *sd = (struct sd *) gspca_dev;
862 struct usb_device *dev = gspca_dev->dev;
863 int rc;
6a7eba24
JFM
864 __u8 i;
865 __u8 info[6];
866 int err_code;
867
868 switch (sd->bridge) {
869 case BRIDGE_SPCA504B:
8295d99e
JFM
870 reg_w(gspca_dev, 0x1d, 0, 0, 0);
871 reg_w(gspca_dev, 0, 1, 0x2306, 0);
872 reg_w(gspca_dev, 0, 0, 0x0d04, 0);
873 reg_w(gspca_dev, 0, 0, 0x2000, 0);
874 reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
875 reg_w(gspca_dev, 0, 0, 0x2306, 0);
6a7eba24
JFM
876 /* fall thru */
877 case BRIDGE_SPCA533:
739570bb 878 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
879 spca50x_GetFirmware(gspca_dev);
880 break;
881 case BRIDGE_SPCA536:
882 spca50x_GetFirmware(gspca_dev);
8295d99e 883 reg_r(gspca_dev, 0x00, 0x5002, 1);
739570bb 884 gspca_dev->usb_buf[0] = 0;
8295d99e
JFM
885 reg_w(gspca_dev, 0x24, 0, 0, 1);
886 reg_r(gspca_dev, 0x24, 0, 1);
739570bb 887 rc = spca504B_PollingDataReady(gspca_dev);
8295d99e 888 reg_w(gspca_dev, 0x34, 0, 0, 0);
6a7eba24
JFM
889 spca504B_WaitCmdStatus(gspca_dev);
890 break;
891 case BRIDGE_SPCA504C: /* pccam600 */
892 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
739570bb
JFM
893 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
894 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
6a7eba24
JFM
895 spca504_wait_status(gspca_dev);
896 if (sd->subtype == LogitechClickSmart420)
897 write_vector(gspca_dev,
898 spca504A_clicksmart420_open_data);
899 else
900 write_vector(gspca_dev, spca504_pccam600_open_data);
901 err_code = spca50x_setup_qtable(gspca_dev,
902 0x00, 0x2800,
903 0x2840, qtable_creative_pccam);
904 if (err_code < 0) {
905 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
906 return err_code;
907 }
908 break;
909 default:
910/* case BRIDGE_SPCA504: */
911 PDEBUG(D_STREAM, "Opening SPCA504");
912 if (sd->subtype == AiptekMiniPenCam13) {
913 /*****************************/
914 for (i = 0; i < 6; i++)
739570bb 915 info[i] = reg_r_1(gspca_dev, i);
6a7eba24
JFM
916 PDEBUG(D_STREAM,
917 "Read info: %d %d %d %d %d %d."
918 " Should be 1,0,2,2,0,0",
919 info[0], info[1], info[2],
920 info[3], info[4], info[5]);
921 /* spca504a aiptek */
922 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
923 spca504A_acknowledged_command(gspca_dev, 0x24,
924 8, 3, 0x9e, 1);
925 /* Twice sequencial need status 0xff->0x9e->0x9d */
926 spca504A_acknowledged_command(gspca_dev, 0x24,
927 8, 3, 0x9e, 0);
928
929 spca504A_acknowledged_command(gspca_dev, 0x24,
930 0, 0, 0x9d, 1);
931 /******************************/
932 /* spca504a aiptek */
933 spca504A_acknowledged_command(gspca_dev, 0x08,
934 6, 0, 0x86, 1);
935/* reg_write (dev, 0, 0x2000, 0); */
936/* reg_write (dev, 0, 0x2883, 1); */
937/* spca504A_acknowledged_command (gspca_dev, 0x08,
938 6, 0, 0x86, 1); */
939/* spca504A_acknowledged_command (gspca_dev, 0x24,
940 0, 0, 0x9D, 1); */
739570bb
JFM
941 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
942 reg_w_riv(dev, 0x0, 0x2310, 0x05);
6a7eba24
JFM
943 spca504A_acknowledged_command(gspca_dev, 0x01,
944 0x0f, 0, 0xff, 0);
945 }
946 /* setup qtable */
739570bb
JFM
947 reg_w_riv(dev, 0, 0x2000, 0);
948 reg_w_riv(dev, 0, 0x2883, 1);
6a7eba24
JFM
949 err_code = spca50x_setup_qtable(gspca_dev,
950 0x00, 0x2800,
951 0x2840,
952 qtable_spca504_default);
953 if (err_code < 0) {
954 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
955 return err_code;
956 }
957 break;
958 }
959 return 0;
960}
961
72ab97ce 962static int sd_start(struct gspca_dev *gspca_dev)
6a7eba24
JFM
963{
964 struct sd *sd = (struct sd *) gspca_dev;
965 struct usb_device *dev = gspca_dev->dev;
966 int rc;
967 int enable;
968 __u8 i;
969 __u8 info[6];
970
971 if (sd->bridge == BRIDGE_SPCA504B)
972 spca504B_setQtable(gspca_dev);
973 spca504B_SetSizeType(gspca_dev);
974 switch (sd->bridge) {
975 default:
976/* case BRIDGE_SPCA504B: */
977/* case BRIDGE_SPCA533: */
978/* case BRIDGE_SPCA536: */
979 if (sd->subtype == MegapixV4 ||
980 sd->subtype == LogitechClickSmart820) {
8295d99e 981 reg_w(gspca_dev, 0xf0, 0, 0, 0);
6a7eba24 982 spca504B_WaitCmdStatus(gspca_dev);
8295d99e 983 reg_r(gspca_dev, 0xf0, 4, 0);
6a7eba24
JFM
984 spca504B_WaitCmdStatus(gspca_dev);
985 } else {
8295d99e 986 reg_w(gspca_dev, 0x31, 0, 4, 0);
6a7eba24 987 spca504B_WaitCmdStatus(gspca_dev);
739570bb 988 rc = spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
989 }
990 break;
991 case BRIDGE_SPCA504:
992 if (sd->subtype == AiptekMiniPenCam13) {
993 for (i = 0; i < 6; i++)
739570bb 994 info[i] = reg_r_1(gspca_dev, i);
6a7eba24
JFM
995 PDEBUG(D_STREAM,
996 "Read info: %d %d %d %d %d %d."
997 " Should be 1,0,2,2,0,0",
998 info[0], info[1], info[2],
999 info[3], info[4], info[5]);
1000 /* spca504a aiptek */
1001 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1002 spca504A_acknowledged_command(gspca_dev, 0x24,
1003 8, 3, 0x9e, 1);
1004 /* Twice sequencial need status 0xff->0x9e->0x9d */
1005 spca504A_acknowledged_command(gspca_dev, 0x24,
1006 8, 3, 0x9e, 0);
1007 spca504A_acknowledged_command(gspca_dev, 0x24,
1008 0, 0, 0x9d, 1);
1009 } else {
1010 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1011 for (i = 0; i < 6; i++)
739570bb 1012 info[i] = reg_r_1(gspca_dev, i);
6a7eba24
JFM
1013 PDEBUG(D_STREAM,
1014 "Read info: %d %d %d %d %d %d."
1015 " Should be 1,0,2,2,0,0",
1016 info[0], info[1], info[2],
1017 info[3], info[4], info[5]);
1018 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1019 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1020 }
1021 spca504B_SetSizeType(gspca_dev);
739570bb
JFM
1022 reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
1023 reg_w_riv(dev, 0x0, 0x2310, 0x05);
6a7eba24
JFM
1024 break;
1025 case BRIDGE_SPCA504C:
1026 if (sd->subtype == LogitechClickSmart420) {
1027 write_vector(gspca_dev,
1028 spca504A_clicksmart420_init_data);
1029 } else {
1030 write_vector(gspca_dev, spca504_pccam600_init_data);
1031 }
739570bb
JFM
1032 enable = (sd->autogain ? 0x04 : 0x01);
1033 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1034 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
6a7eba24
JFM
1035
1036 /* set default exposure compensation and whiteness balance */
739570bb
JFM
1037 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1038 reg_w_riv(dev, 0x30, 0x0002, 1600);
6a7eba24
JFM
1039 spca504B_SetSizeType(gspca_dev);
1040 break;
1041 }
1042 sp5xx_initContBrigHueRegisters(gspca_dev);
72ab97ce 1043 return 0;
6a7eba24
JFM
1044}
1045
1046static void sd_stopN(struct gspca_dev *gspca_dev)
1047{
1048 struct sd *sd = (struct sd *) gspca_dev;
1049 struct usb_device *dev = gspca_dev->dev;
1050
1051 switch (sd->bridge) {
1052 default:
1053/* case BRIDGE_SPCA533: */
1054/* case BRIDGE_SPCA536: */
1055/* case BRIDGE_SPCA504B: */
8295d99e 1056 reg_w(gspca_dev, 0x31, 0, 0, 0);
6a7eba24 1057 spca504B_WaitCmdStatus(gspca_dev);
739570bb 1058 spca504B_PollingDataReady(gspca_dev);
6a7eba24
JFM
1059 break;
1060 case BRIDGE_SPCA504:
1061 case BRIDGE_SPCA504C:
739570bb 1062 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
6a7eba24
JFM
1063
1064 if (sd->subtype == AiptekMiniPenCam13) {
1065 /* spca504a aiptek */
1066/* spca504A_acknowledged_command(gspca_dev, 0x08,
1067 6, 0, 0x86, 1); */
1068 spca504A_acknowledged_command(gspca_dev, 0x24,
1069 0x00, 0x00, 0x9d, 1);
1070 spca504A_acknowledged_command(gspca_dev, 0x01,
1071 0x0f, 0x00, 0xff, 1);
1072 } else {
1073 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
739570bb 1074 reg_w_riv(dev, 0x01, 0x000f, 0x00);
6a7eba24
JFM
1075 }
1076 break;
1077 }
1078}
1079
6a7eba24
JFM
1080static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1081 struct gspca_frame *frame, /* target */
a5ae2062 1082 __u8 *data, /* isoc packet */
6a7eba24
JFM
1083 int len) /* iso packet length */
1084{
1085 struct sd *sd = (struct sd *) gspca_dev;
1086 int i, sof = 0;
1087 unsigned char *s, *d;
1088 static unsigned char ffd9[] = {0xff, 0xd9};
1089
1090/* frames are jpeg 4.1.1 without 0xff escape */
1091 switch (sd->bridge) {
1092 case BRIDGE_SPCA533:
1093 if (data[0] == 0xff) {
1094 if (data[1] != 0x01) { /* drop packet */
1095/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1096 return;
1097 }
1098 sof = 1;
1099 data += SPCA533_OFFSET_DATA;
1100 len -= SPCA533_OFFSET_DATA;
1101 } else {
1102 data += 1;
1103 len -= 1;
1104 }
1105 break;
1106 case BRIDGE_SPCA536:
1107 if (data[0] == 0xff) {
1108 sof = 1;
1109 data += SPCA536_OFFSET_DATA;
1110 len -= SPCA536_OFFSET_DATA;
1111 } else {
1112 data += 2;
1113 len -= 2;
1114 }
1115 break;
1116 default:
1117/* case BRIDGE_SPCA504: */
1118/* case BRIDGE_SPCA504B: */
1119 switch (data[0]) {
1120 case 0xfe: /* start of frame */
1121 sof = 1;
1122 data += SPCA50X_OFFSET_DATA;
1123 len -= SPCA50X_OFFSET_DATA;
1124 break;
1125 case 0xff: /* drop packet */
1126/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1127 return;
1128 default:
1129 data += 1;
1130 len -= 1;
1131 break;
1132 }
1133 break;
1134 case BRIDGE_SPCA504C:
1135 switch (data[0]) {
1136 case 0xfe: /* start of frame */
1137 sof = 1;
1138 data += SPCA504_PCCAM600_OFFSET_DATA;
1139 len -= SPCA504_PCCAM600_OFFSET_DATA;
1140 break;
1141 case 0xff: /* drop packet */
1142/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1143 return;
1144 default:
1145 data += 1;
1146 len -= 1;
1147 break;
1148 }
1149 break;
1150 }
1151 if (sof) { /* start of frame */
1152 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
1153 ffd9, 2);
1154
1155 /* put the JPEG header in the new frame */
36e819db 1156 jpeg_put_header(gspca_dev, frame, 0x22);
6a7eba24
JFM
1157 }
1158
1159 /* add 0x00 after 0xff */
1160 for (i = len; --i >= 0; )
1161 if (data[i] == 0xff)
1162 break;
1163 if (i < 0) { /* no 0xff */
1164 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1165 return;
1166 }
1167 s = data;
1168 d = sd->packet;
1169 for (i = 0; i < len; i++) {
1170 *d++ = *s++;
1171 if (s[-1] == 0xff)
1172 *d++ = 0x00;
1173 }
1174 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
1175 sd->packet, d - sd->packet);
1176}
1177
1178static void setbrightness(struct gspca_dev *gspca_dev)
1179{
1180 struct sd *sd = (struct sd *) gspca_dev;
1181 struct usb_device *dev = gspca_dev->dev;
1182
1183 switch (sd->bridge) {
1184 default:
1185/* case BRIDGE_SPCA533: */
1186/* case BRIDGE_SPCA504B: */
1187/* case BRIDGE_SPCA504: */
1188/* case BRIDGE_SPCA504C: */
739570bb 1189 reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
6a7eba24
JFM
1190 break;
1191 case BRIDGE_SPCA536:
739570bb 1192 reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
6a7eba24
JFM
1193 break;
1194 }
1195}
1196
6a7eba24
JFM
1197static void setcontrast(struct gspca_dev *gspca_dev)
1198{
1199 struct sd *sd = (struct sd *) gspca_dev;
1200 struct usb_device *dev = gspca_dev->dev;
1201
1202 switch (sd->bridge) {
1203 default:
1204/* case BRIDGE_SPCA533: */
1205/* case BRIDGE_SPCA504B: */
1206/* case BRIDGE_SPCA504: */
1207/* case BRIDGE_SPCA504C: */
739570bb 1208 reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
6a7eba24
JFM
1209 break;
1210 case BRIDGE_SPCA536:
739570bb 1211 reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
6a7eba24
JFM
1212 break;
1213 }
1214}
1215
6a7eba24
JFM
1216static void setcolors(struct gspca_dev *gspca_dev)
1217{
1218 struct sd *sd = (struct sd *) gspca_dev;
1219 struct usb_device *dev = gspca_dev->dev;
1220
1221 switch (sd->bridge) {
1222 default:
1223/* case BRIDGE_SPCA533: */
1224/* case BRIDGE_SPCA504B: */
1225/* case BRIDGE_SPCA504: */
1226/* case BRIDGE_SPCA504C: */
739570bb 1227 reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
6a7eba24
JFM
1228 break;
1229 case BRIDGE_SPCA536:
739570bb 1230 reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
6a7eba24
JFM
1231 break;
1232 }
1233}
1234
6a7eba24
JFM
1235static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1236{
1237 struct sd *sd = (struct sd *) gspca_dev;
1238
1239 sd->brightness = val;
1240 if (gspca_dev->streaming)
1241 setbrightness(gspca_dev);
1242 return 0;
1243}
1244
1245static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1246{
1247 struct sd *sd = (struct sd *) gspca_dev;
1248
6a7eba24
JFM
1249 *val = sd->brightness;
1250 return 0;
1251}
1252
1253static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1254{
1255 struct sd *sd = (struct sd *) gspca_dev;
1256
1257 sd->contrast = val;
1258 if (gspca_dev->streaming)
1259 setcontrast(gspca_dev);
1260 return 0;
1261}
1262
1263static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1264{
1265 struct sd *sd = (struct sd *) gspca_dev;
1266
6a7eba24
JFM
1267 *val = sd->contrast;
1268 return 0;
1269}
1270
1271static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1272{
1273 struct sd *sd = (struct sd *) gspca_dev;
1274
1275 sd->colors = val;
1276 if (gspca_dev->streaming)
1277 setcolors(gspca_dev);
1278 return 0;
1279}
1280
1281static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1282{
1283 struct sd *sd = (struct sd *) gspca_dev;
1284
6a7eba24
JFM
1285 *val = sd->colors;
1286 return 0;
1287}
1288
1289static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1290{
1291 struct sd *sd = (struct sd *) gspca_dev;
1292
1293 sd->autogain = val;
1294 return 0;
1295}
1296
1297static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1298{
1299 struct sd *sd = (struct sd *) gspca_dev;
1300
1301 *val = sd->autogain;
1302 return 0;
1303}
1304
1305/* sub-driver description */
a5ae2062 1306static const struct sd_desc sd_desc = {
6a7eba24
JFM
1307 .name = MODULE_NAME,
1308 .ctrls = sd_ctrls,
1309 .nctrls = ARRAY_SIZE(sd_ctrls),
1310 .config = sd_config,
012d6b02 1311 .init = sd_init,
6a7eba24
JFM
1312 .start = sd_start,
1313 .stopN = sd_stopN,
6a7eba24
JFM
1314 .pkt_scan = sd_pkt_scan,
1315};
1316
1317/* -- module initialisation -- */
9d64fdb1
JFM
1318#define BS(bridge, subtype) \
1319 .driver_info = (BRIDGE_ ## bridge << 8) \
1320 | (subtype)
a5ae2062 1321static const __devinitdata struct usb_device_id device_table[] = {
9d64fdb1
JFM
1322 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1323 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1324 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1325 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1326 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1327 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1328 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1329 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1330 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1331 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1332 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1333 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1334 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1335 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1336 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1337 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1338 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1339 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1340 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1341 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1342 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1343 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1344 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1345 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1346 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1347 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1348 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1349 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1350 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1351 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1352 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1353 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1354 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1355 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1356 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1357 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1358 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1359 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1360 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1361 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1362 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1363 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1364 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1365 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1366 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1367 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1368 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1369 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1370 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1371 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1372 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1373 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1374 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1375 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1376 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1377 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1378 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
6a7eba24
JFM
1379 {}
1380};
1381MODULE_DEVICE_TABLE(usb, device_table);
1382
1383/* -- device connect -- */
1384static int sd_probe(struct usb_interface *intf,
1385 const struct usb_device_id *id)
1386{
1387 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1388 THIS_MODULE);
1389}
1390
1391static struct usb_driver sd_driver = {
1392 .name = MODULE_NAME,
1393 .id_table = device_table,
1394 .probe = sd_probe,
1395 .disconnect = gspca_disconnect,
6a709749
JFM
1396#ifdef CONFIG_PM
1397 .suspend = gspca_suspend,
1398 .resume = gspca_resume,
1399#endif
6a7eba24
JFM
1400};
1401
1402/* -- module insert / remove -- */
1403static int __init sd_mod_init(void)
1404{
f69e9529
AK
1405 int ret;
1406 ret = usb_register(&sd_driver);
1407 if (ret < 0)
e6b14849 1408 return ret;
10b0e96e 1409 PDEBUG(D_PROBE, "registered");
6a7eba24
JFM
1410 return 0;
1411}
1412static void __exit sd_mod_exit(void)
1413{
1414 usb_deregister(&sd_driver);
1415 PDEBUG(D_PROBE, "deregistered");
1416}
1417
1418module_init(sd_mod_init);
1419module_exit(sd_mod_exit);