blob: 716df6b15fc5a199105c8afa3584cb1eed29cbc1 [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 Moine760f2712009-09-02 06:04:14 -030035 s8 brightness;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030036 u8 contrast;
37 u8 colors;
38 u8 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 Moine2e1794b2009-08-31 06:15:22 -030044 u8 bridge;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045#define BRIDGE_SPCA504 0
46#define BRIDGE_SPCA504B 1
47#define BRIDGE_SPCA504C 2
48#define BRIDGE_SPCA533 3
49#define BRIDGE_SPCA536 4
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030050 u8 subtype;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#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[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 {
72 {
73 .id = V4L2_CID_BRIGHTNESS,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Brightness",
Jean-Francois Moine760f2712009-09-02 06:04:14 -030076 .minimum = -128,
77 .maximum = 127,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030079#define BRIGHTNESS_DEF 0
80 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081 },
82 .set = sd_setbrightness,
83 .get = sd_getbrightness,
84 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085 {
86 {
87 .id = V4L2_CID_CONTRAST,
88 .type = V4L2_CTRL_TYPE_INTEGER,
89 .name = "Contrast",
90 .minimum = 0,
91 .maximum = 0xff,
92 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030093#define CONTRAST_DEF 0x20
94 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030095 },
96 .set = sd_setcontrast,
97 .get = sd_getcontrast,
98 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 {
100 {
101 .id = V4L2_CID_SATURATION,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Color",
104 .minimum = 0,
105 .maximum = 0xff,
106 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300107#define COLOR_DEF 0x1a
108 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 },
110 .set = sd_setcolors,
111 .get = sd_getcolors,
112 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 {
114 {
115 .id = V4L2_CID_AUTOGAIN,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Auto Gain",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300121#define AUTOGAIN_DEF 1
122 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123 },
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 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300184#define SPCA533_OFFSET_DATA 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185#define SPCA533_OFFSET_FRAMSEQ 15
186/* Frame packet header offsets for the spca536 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300187#define SPCA536_OFFSET_DATA 4
188#define SPCA536_OFFSET_FRAMSEQ 1
189
190struct cmd {
191 u8 req;
192 u16 val;
193 u16 idx;
194};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300195
196/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300197static const struct cmd spca504_pccam600_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198/* {0xa0, 0x0000, 0x0503}, * capture mode */
199 {0x00, 0x0000, 0x2000},
200 {0x00, 0x0013, 0x2301},
201 {0x00, 0x0003, 0x2000},
202 {0x00, 0x0001, 0x21ac},
203 {0x00, 0x0001, 0x21a6},
204 {0x00, 0x0000, 0x21a7}, /* brightness */
205 {0x00, 0x0020, 0x21a8}, /* contrast */
206 {0x00, 0x0001, 0x21ac}, /* sat/hue */
207 {0x00, 0x0000, 0x21ad}, /* hue */
208 {0x00, 0x001a, 0x21ae}, /* saturation */
209 {0x00, 0x0002, 0x21a3}, /* gamma */
210 {0x30, 0x0154, 0x0008},
211 {0x30, 0x0004, 0x0006},
212 {0x30, 0x0258, 0x0009},
213 {0x30, 0x0004, 0x0000},
214 {0x30, 0x0093, 0x0004},
215 {0x30, 0x0066, 0x0005},
216 {0x00, 0x0000, 0x2000},
217 {0x00, 0x0013, 0x2301},
218 {0x00, 0x0003, 0x2000},
219 {0x00, 0x0013, 0x2301},
220 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300221};
222
223/* Creative PC-CAM 600 specific open data, sent before using the
224 * generic initialisation data from spca504_open_data.
225 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300226static const struct cmd spca504_pccam600_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 {0x00, 0x0001, 0x2501},
228 {0x20, 0x0500, 0x0001}, /* snapshot mode */
229 {0x00, 0x0003, 0x2880},
230 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231};
232
233/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300234static const struct cmd spca504A_clicksmart420_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235/* {0xa0, 0x0000, 0x0503}, * capture mode */
236 {0x00, 0x0000, 0x2000},
237 {0x00, 0x0013, 0x2301},
238 {0x00, 0x0003, 0x2000},
239 {0x00, 0x0001, 0x21ac},
240 {0x00, 0x0001, 0x21a6},
241 {0x00, 0x0000, 0x21a7}, /* brightness */
242 {0x00, 0x0020, 0x21a8}, /* contrast */
243 {0x00, 0x0001, 0x21ac}, /* sat/hue */
244 {0x00, 0x0000, 0x21ad}, /* hue */
245 {0x00, 0x001a, 0x21ae}, /* saturation */
246 {0x00, 0x0002, 0x21a3}, /* gamma */
247 {0x30, 0x0004, 0x000a},
248 {0xb0, 0x0001, 0x0000},
249
250
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300251 {0xa1, 0x0080, 0x0001},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252 {0x30, 0x0049, 0x0000},
253 {0x30, 0x0060, 0x0005},
254 {0x0c, 0x0004, 0x0000},
255 {0x00, 0x0000, 0x0000},
256 {0x00, 0x0000, 0x2000},
257 {0x00, 0x0013, 0x2301},
258 {0x00, 0x0003, 0x2000},
259 {0x00, 0x0000, 0x2000},
260
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300261};
262
263/* clicksmart 420 open data ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300264static const struct cmd spca504A_clicksmart420_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265 {0x00, 0x0001, 0x2501},
266 {0x20, 0x0502, 0x0000},
267 {0x06, 0x0000, 0x0000},
268 {0x00, 0x0004, 0x2880},
269 {0x00, 0x0001, 0x2881},
270/* look like setting a qTable */
271 {0x00, 0x0006, 0x2800},
272 {0x00, 0x0004, 0x2801},
273 {0x00, 0x0004, 0x2802},
274 {0x00, 0x0006, 0x2803},
275 {0x00, 0x000a, 0x2804},
276 {0x00, 0x0010, 0x2805},
277 {0x00, 0x0014, 0x2806},
278 {0x00, 0x0018, 0x2807},
279 {0x00, 0x0005, 0x2808},
280 {0x00, 0x0005, 0x2809},
281 {0x00, 0x0006, 0x280a},
282 {0x00, 0x0008, 0x280b},
283 {0x00, 0x000a, 0x280c},
284 {0x00, 0x0017, 0x280d},
285 {0x00, 0x0018, 0x280e},
286 {0x00, 0x0016, 0x280f},
287
288 {0x00, 0x0006, 0x2810},
289 {0x00, 0x0005, 0x2811},
290 {0x00, 0x0006, 0x2812},
291 {0x00, 0x000a, 0x2813},
292 {0x00, 0x0010, 0x2814},
293 {0x00, 0x0017, 0x2815},
294 {0x00, 0x001c, 0x2816},
295 {0x00, 0x0016, 0x2817},
296 {0x00, 0x0006, 0x2818},
297 {0x00, 0x0007, 0x2819},
298 {0x00, 0x0009, 0x281a},
299 {0x00, 0x000c, 0x281b},
300 {0x00, 0x0014, 0x281c},
301 {0x00, 0x0023, 0x281d},
302 {0x00, 0x0020, 0x281e},
303 {0x00, 0x0019, 0x281f},
304
305 {0x00, 0x0007, 0x2820},
306 {0x00, 0x0009, 0x2821},
307 {0x00, 0x000f, 0x2822},
308 {0x00, 0x0016, 0x2823},
309 {0x00, 0x001b, 0x2824},
310 {0x00, 0x002c, 0x2825},
311 {0x00, 0x0029, 0x2826},
312 {0x00, 0x001f, 0x2827},
313 {0x00, 0x000a, 0x2828},
314 {0x00, 0x000e, 0x2829},
315 {0x00, 0x0016, 0x282a},
316 {0x00, 0x001a, 0x282b},
317 {0x00, 0x0020, 0x282c},
318 {0x00, 0x002a, 0x282d},
319 {0x00, 0x002d, 0x282e},
320 {0x00, 0x0025, 0x282f},
321
322 {0x00, 0x0014, 0x2830},
323 {0x00, 0x001a, 0x2831},
324 {0x00, 0x001f, 0x2832},
325 {0x00, 0x0023, 0x2833},
326 {0x00, 0x0029, 0x2834},
327 {0x00, 0x0030, 0x2835},
328 {0x00, 0x0030, 0x2836},
329 {0x00, 0x0028, 0x2837},
330 {0x00, 0x001d, 0x2838},
331 {0x00, 0x0025, 0x2839},
332 {0x00, 0x0026, 0x283a},
333 {0x00, 0x0027, 0x283b},
334 {0x00, 0x002d, 0x283c},
335 {0x00, 0x0028, 0x283d},
336 {0x00, 0x0029, 0x283e},
337 {0x00, 0x0028, 0x283f},
338
339 {0x00, 0x0007, 0x2840},
340 {0x00, 0x0007, 0x2841},
341 {0x00, 0x000a, 0x2842},
342 {0x00, 0x0013, 0x2843},
343 {0x00, 0x0028, 0x2844},
344 {0x00, 0x0028, 0x2845},
345 {0x00, 0x0028, 0x2846},
346 {0x00, 0x0028, 0x2847},
347 {0x00, 0x0007, 0x2848},
348 {0x00, 0x0008, 0x2849},
349 {0x00, 0x000a, 0x284a},
350 {0x00, 0x001a, 0x284b},
351 {0x00, 0x0028, 0x284c},
352 {0x00, 0x0028, 0x284d},
353 {0x00, 0x0028, 0x284e},
354 {0x00, 0x0028, 0x284f},
355
356 {0x00, 0x000a, 0x2850},
357 {0x00, 0x000a, 0x2851},
358 {0x00, 0x0016, 0x2852},
359 {0x00, 0x0028, 0x2853},
360 {0x00, 0x0028, 0x2854},
361 {0x00, 0x0028, 0x2855},
362 {0x00, 0x0028, 0x2856},
363 {0x00, 0x0028, 0x2857},
364 {0x00, 0x0013, 0x2858},
365 {0x00, 0x001a, 0x2859},
366 {0x00, 0x0028, 0x285a},
367 {0x00, 0x0028, 0x285b},
368 {0x00, 0x0028, 0x285c},
369 {0x00, 0x0028, 0x285d},
370 {0x00, 0x0028, 0x285e},
371 {0x00, 0x0028, 0x285f},
372
373 {0x00, 0x0028, 0x2860},
374 {0x00, 0x0028, 0x2861},
375 {0x00, 0x0028, 0x2862},
376 {0x00, 0x0028, 0x2863},
377 {0x00, 0x0028, 0x2864},
378 {0x00, 0x0028, 0x2865},
379 {0x00, 0x0028, 0x2866},
380 {0x00, 0x0028, 0x2867},
381 {0x00, 0x0028, 0x2868},
382 {0x00, 0x0028, 0x2869},
383 {0x00, 0x0028, 0x286a},
384 {0x00, 0x0028, 0x286b},
385 {0x00, 0x0028, 0x286c},
386 {0x00, 0x0028, 0x286d},
387 {0x00, 0x0028, 0x286e},
388 {0x00, 0x0028, 0x286f},
389
390 {0x00, 0x0028, 0x2870},
391 {0x00, 0x0028, 0x2871},
392 {0x00, 0x0028, 0x2872},
393 {0x00, 0x0028, 0x2873},
394 {0x00, 0x0028, 0x2874},
395 {0x00, 0x0028, 0x2875},
396 {0x00, 0x0028, 0x2876},
397 {0x00, 0x0028, 0x2877},
398 {0x00, 0x0028, 0x2878},
399 {0x00, 0x0028, 0x2879},
400 {0x00, 0x0028, 0x287a},
401 {0x00, 0x0028, 0x287b},
402 {0x00, 0x0028, 0x287c},
403 {0x00, 0x0028, 0x287d},
404 {0x00, 0x0028, 0x287e},
405 {0x00, 0x0028, 0x287f},
406
407 {0xa0, 0x0000, 0x0503},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408};
409
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300410static const u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411 { /* Q-table Y-components */
412 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
413 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
414 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
415 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
416 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
417 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
418 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
419 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
420 { /* Q-table C-components */
421 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
422 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
423 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
424 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
425 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
426 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
427 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
428 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
429};
430
431/* FIXME: This Q-table is identical to the Creative PC-CAM one,
432 * except for one byte. Possibly a typo?
433 * NWG: 18/05/2003.
434 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300435static const u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300436 { /* Q-table Y-components */
437 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
438 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
439 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
440 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
441 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
442 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
443 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
444 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
445 },
446 { /* Q-table C-components */
447 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
448 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
449 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
450 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
451 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
452 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
453 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
454 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
455};
456
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300457/* read <len> bytes to gspca_dev->usb_buf */
458static void reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300459 u8 req,
460 u16 index,
461 u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300463 int ret;
464
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300465#ifdef GSPCA_DEBUG
466 if (len > USB_BUF_SZ) {
467 err("reg_r: buffer overflow");
468 return;
469 }
470#endif
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300471 if (gspca_dev->usb_err < 0)
472 return;
473 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300474 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 req,
476 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
477 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300478 index,
479 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300480 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300481 if (ret < 0) {
482 PDEBUG(D_ERR, "reg_r err %d", ret);
483 gspca_dev->usb_err = ret;
484 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485}
486
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300487/* write one byte */
488static void reg_w_1(struct gspca_dev *gspca_dev,
489 u8 req,
490 u16 value,
491 u16 index,
492 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300494 int ret;
495
496 if (gspca_dev->usb_err < 0)
497 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300498 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300499 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300500 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 req,
502 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300503 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300504 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300506 if (ret < 0) {
507 PDEBUG(D_ERR, "reg_w_1 err %d", ret);
508 gspca_dev->usb_err = ret;
509 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510}
511
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300513static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300514 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300516 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 int ret;
518
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300519 if (gspca_dev->usb_err < 0)
520 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 ret = usb_control_msg(dev,
522 usb_sndctrlpipe(dev, 0),
523 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300524 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300526 if (ret < 0) {
527 PDEBUG(D_ERR, "reg_w_riv err %d", ret);
528 gspca_dev->usb_err = ret;
529 return;
530 }
531 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
532 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533}
534
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535/* read 1 byte */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300536static u8 reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300537 u16 value) /* wValue */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538{
539 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300541 if (gspca_dev->usb_err < 0)
542 return 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 ret = usb_control_msg(gspca_dev->dev,
544 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300545 0x20, /* request */
546 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
547 value,
548 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300549 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550 500); /* timeout */
551 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300552 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300553 gspca_dev->usb_err = ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 return 0;
555 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300556 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557}
558
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300559/* read 1 or 2 bytes */
560static u16 reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300561 u8 req, /* bRequest */
562 u16 index, /* wIndex */
563 u16 length) /* wLength (1 or 2 only) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564{
565 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300566
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300567 if (gspca_dev->usb_err < 0)
568 return 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300569 gspca_dev->usb_buf[1] = 0;
570 ret = usb_control_msg(gspca_dev->dev,
571 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572 req,
573 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
574 0, /* value */
575 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300576 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300577 500);
578 if (ret < 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300579 PDEBUG(D_ERR, "reg_r_12 err %d", ret);
580 gspca_dev->usb_err = ret;
581 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300582 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300583 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584}
585
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300586static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300587 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300589 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300590 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300591 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593}
594
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300595static void setup_qtable(struct gspca_dev *gspca_dev,
596 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300598 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300599
600 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300601 for (i = 0; i < 64; i++)
602 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603
604 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300605 for (i = 0; i < 64; i++)
606 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300607}
608
609static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300610 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300611{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300612 u16 notdone;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300613
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300614 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300615 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300616 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300618 PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619
620 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300621 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300622 PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300623}
624
625static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300626 u8 req,
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300627 u16 idx, u16 val, u16 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300628{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300629 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300631 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300632 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300633 if (gspca_dev->usb_err < 0)
634 return;
635 PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636 if (!count)
637 return;
638 count = 200;
639 while (--count > 0) {
640 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200641 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300642/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300643 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300644 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300645 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300646 status, 200 - count);
647 break;
648 }
649 }
650}
651
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300652static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654 int count = 10;
655
656 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300657 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300658 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300659 break;
660 msleep(10);
661 }
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) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300671 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300672 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300673 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 break;
675 }
676 msleep(10);
677 }
678}
679
680static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
681{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300682 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300684 data = gspca_dev->usb_buf;
685 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300686 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300687 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300688 reg_r(gspca_dev, 0x23, 0, 64);
689 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690}
691
692static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
693{
694 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300695 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300696
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300697 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 switch (sd->bridge) {
699 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300700 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300702 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300703 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300704 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300705 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300707 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300708 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300709 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710
711 /* Init the cam width height with some values get on init ? */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300712 reg_w_riv(gspca_dev, 0x31, 0, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300714 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715 break;
716 default:
717/* case BRIDGE_SPCA504B: */
718/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300719 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300720 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300721 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300722 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300723 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724 break;
725 case BRIDGE_SPCA504:
726 Size += 3;
727 if (sd->subtype == AiptekMiniPenCam13) {
728 /* spca504a aiptek */
729 spca504A_acknowledged_command(gspca_dev,
730 0x08, Size, 0,
731 0x80 | (Size & 0x0f), 1);
732 spca504A_acknowledged_command(gspca_dev,
733 1, 3, 0, 0x9f, 0);
734 } else {
735 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
736 }
737 break;
738 case BRIDGE_SPCA504C:
739 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300740 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
741 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 break;
743 }
744}
745
746static void spca504_wait_status(struct gspca_dev *gspca_dev)
747{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300748 int cnt;
749
750 cnt = 256;
751 while (--cnt > 0) {
752 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300753 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754 return;
755 msleep(10);
756 }
757}
758
759static void spca504B_setQtable(struct gspca_dev *gspca_dev)
760{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300761 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300762 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300763 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300764}
765
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300766static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767{
768 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300769 u16 reg;
770
771 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300772 reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300773}
774
775static void setcontrast(struct gspca_dev *gspca_dev)
776{
777 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300778 u16 reg;
779
780 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300781 reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300782}
783
784static void setcolors(struct gspca_dev *gspca_dev)
785{
786 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300787 u16 reg;
788
789 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300790 reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300791}
792
793static void init_ctl_reg(struct gspca_dev *gspca_dev)
794{
795 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796 int pollreg = 1;
797
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300798 setbrightness(gspca_dev);
799 setcontrast(gspca_dev);
800 setcolors(gspca_dev);
801
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300802 switch (sd->bridge) {
803 case BRIDGE_SPCA504:
804 case BRIDGE_SPCA504C:
805 pollreg = 0;
806 /* fall thru */
807 default:
808/* case BRIDGE_SPCA533: */
809/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300810 reg_w_riv(gspca_dev, 0, 0x00, 0x21ad); /* hue */
811 reg_w_riv(gspca_dev, 0, 0x01, 0x21ac); /* sat/hue */
812 reg_w_riv(gspca_dev, 0, 0x00, 0x21a3); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813 break;
814 case BRIDGE_SPCA536:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300815 reg_w_riv(gspca_dev, 0, 0x40, 0x20f5);
816 reg_w_riv(gspca_dev, 0, 0x01, 0x20f4);
817 reg_w_riv(gspca_dev, 0, 0x00, 0x2089);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 break;
819 }
820 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300821 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822}
823
824/* this function is called at probe time */
825static int sd_config(struct gspca_dev *gspca_dev,
826 const struct usb_device_id *id)
827{
828 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300829 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830
831 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300832
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300833 sd->bridge = id->driver_info >> 8;
834 sd->subtype = id->driver_info;
835
836 if (sd->subtype == AiptekMiniPenCam13) {
837/* try to get the firmware as some cam answer 2.0.1.2.2
838 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300839 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300840 switch (gspca_dev->usb_buf[0]) {
841 case 1:
842 break; /* (right bridge/subtype) */
843 case 2:
844 sd->bridge = BRIDGE_SPCA504B;
845 sd->subtype = 0;
846 break;
847 default:
848 return -ENODEV;
849 }
850 }
851
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300852 switch (sd->bridge) {
853 default:
854/* case BRIDGE_SPCA504B: */
855/* case BRIDGE_SPCA504: */
856/* case BRIDGE_SPCA536: */
857 cam->cam_mode = vga_mode;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300858 cam->nmodes =ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300859 break;
860 case BRIDGE_SPCA533:
861 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300862 if (sd->subtype == MegaImageVI) /* 320x240 only */
863 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
864 else
865 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866 break;
867 case BRIDGE_SPCA504C:
868 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300869 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870 break;
871 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300872 sd->brightness = BRIGHTNESS_DEF;
873 sd->contrast = CONTRAST_DEF;
874 sd->colors = COLOR_DEF;
875 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300876 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300877 return 0;
878}
879
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300880/* this function is called at probe and resume time */
881static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882{
883 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300884 int i;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300885 u8 info[6];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886
887 switch (sd->bridge) {
888 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300889 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
890 reg_w_riv(gspca_dev, 0, 0x01, 0x2306);
891 reg_w_riv(gspca_dev, 0, 0x00, 0x0d04);
892 reg_w_riv(gspca_dev, 0, 0x00, 0x2000);
893 reg_w_riv(gspca_dev, 0, 0x13, 0x2301);
894 reg_w_riv(gspca_dev, 0, 0x00, 0x2306);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 /* fall thru */
896 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300897 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 spca50x_GetFirmware(gspca_dev);
899 break;
900 case BRIDGE_SPCA536:
901 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300902 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300903 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300904 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300905 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300906 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300907 spca504B_WaitCmdStatus(gspca_dev);
908 break;
909 case BRIDGE_SPCA504C: /* pccam600 */
910 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300911 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
912 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 spca504_wait_status(gspca_dev);
914 if (sd->subtype == LogitechClickSmart420)
915 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300916 spca504A_clicksmart420_open_data,
917 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300919 write_vector(gspca_dev, spca504_pccam600_open_data,
920 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300921 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 break;
923 default:
924/* case BRIDGE_SPCA504: */
925 PDEBUG(D_STREAM, "Opening SPCA504");
926 if (sd->subtype == AiptekMiniPenCam13) {
927 /*****************************/
928 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300929 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930 PDEBUG(D_STREAM,
931 "Read info: %d %d %d %d %d %d."
932 " Should be 1,0,2,2,0,0",
933 info[0], info[1], info[2],
934 info[3], info[4], info[5]);
935 /* spca504a aiptek */
936 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
937 spca504A_acknowledged_command(gspca_dev, 0x24,
938 8, 3, 0x9e, 1);
939 /* Twice sequencial need status 0xff->0x9e->0x9d */
940 spca504A_acknowledged_command(gspca_dev, 0x24,
941 8, 3, 0x9e, 0);
942
943 spca504A_acknowledged_command(gspca_dev, 0x24,
944 0, 0, 0x9d, 1);
945 /******************************/
946 /* spca504a aiptek */
947 spca504A_acknowledged_command(gspca_dev, 0x08,
948 6, 0, 0x86, 1);
949/* reg_write (dev, 0, 0x2000, 0); */
950/* reg_write (dev, 0, 0x2883, 1); */
951/* spca504A_acknowledged_command (gspca_dev, 0x08,
952 6, 0, 0x86, 1); */
953/* spca504A_acknowledged_command (gspca_dev, 0x24,
954 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300955 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
956 /* L92 sno1t.txt */
957 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300958 spca504A_acknowledged_command(gspca_dev, 0x01,
959 0x0f, 0, 0xff, 0);
960 }
961 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300962 reg_w_riv(gspca_dev, 0, 0x2000, 0);
963 reg_w_riv(gspca_dev, 0, 0x2883, 1);
964 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300965 break;
966 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300967 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968}
969
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300970static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971{
972 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300973 int enable;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300974 int i;
975 u8 info[6];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300976
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300977 /* create the JPEG header */
978 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
Julia Lawall3eb02372009-07-19 07:09:32 -0300979 if (!sd->jpeg_hdr)
980 return -ENOMEM;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300981 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
982 0x22); /* JPEG 411 */
983 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
984
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300985 if (sd->bridge == BRIDGE_SPCA504B)
986 spca504B_setQtable(gspca_dev);
987 spca504B_SetSizeType(gspca_dev);
988 switch (sd->bridge) {
989 default:
990/* case BRIDGE_SPCA504B: */
991/* case BRIDGE_SPCA533: */
992/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300993 switch (sd->subtype) {
994 case MegapixV4:
995 case LogitechClickSmart820:
996 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300997 reg_w_riv(gspca_dev, 0xf0, 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);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001001 break;
1002 default:
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001003 reg_w_riv(gspca_dev, 0x31, 0, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001004 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001005 spca504B_PollingDataReady(gspca_dev);
1006 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007 }
1008 break;
1009 case BRIDGE_SPCA504:
1010 if (sd->subtype == AiptekMiniPenCam13) {
1011 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001012 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 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 /* spca504a aiptek */
1019 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1020 spca504A_acknowledged_command(gspca_dev, 0x24,
1021 8, 3, 0x9e, 1);
1022 /* Twice sequencial need status 0xff->0x9e->0x9d */
1023 spca504A_acknowledged_command(gspca_dev, 0x24,
1024 8, 3, 0x9e, 0);
1025 spca504A_acknowledged_command(gspca_dev, 0x24,
1026 0, 0, 0x9d, 1);
1027 } else {
1028 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1029 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001030 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001031 PDEBUG(D_STREAM,
1032 "Read info: %d %d %d %d %d %d."
1033 " Should be 1,0,2,2,0,0",
1034 info[0], info[1], info[2],
1035 info[3], info[4], info[5]);
1036 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1037 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1038 }
1039 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001040 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
1041 /* L92 sno1t.txt */
1042 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001043 break;
1044 case BRIDGE_SPCA504C:
1045 if (sd->subtype == LogitechClickSmart420) {
1046 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001047 spca504A_clicksmart420_init_data,
1048 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001049 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001050 write_vector(gspca_dev, spca504_pccam600_init_data,
1051 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001053 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001054 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
1055 /* auto exposure */
1056 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
1057 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001058
1059 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001060 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1061 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001062 spca504B_SetSizeType(gspca_dev);
1063 break;
1064 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001065 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001066 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001067}
1068
1069static void sd_stopN(struct gspca_dev *gspca_dev)
1070{
1071 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001072
1073 switch (sd->bridge) {
1074 default:
1075/* case BRIDGE_SPCA533: */
1076/* case BRIDGE_SPCA536: */
1077/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001078 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001079 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001080 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081 break;
1082 case BRIDGE_SPCA504:
1083 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001084 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001085
1086 if (sd->subtype == AiptekMiniPenCam13) {
1087 /* spca504a aiptek */
1088/* spca504A_acknowledged_command(gspca_dev, 0x08,
1089 6, 0, 0x86, 1); */
1090 spca504A_acknowledged_command(gspca_dev, 0x24,
1091 0x00, 0x00, 0x9d, 1);
1092 spca504A_acknowledged_command(gspca_dev, 0x01,
1093 0x0f, 0x00, 0xff, 1);
1094 } else {
1095 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001096 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001097 }
1098 break;
1099 }
1100}
1101
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001102static void sd_stop0(struct gspca_dev *gspca_dev)
1103{
1104 struct sd *sd = (struct sd *) gspca_dev;
1105
1106 kfree(sd->jpeg_hdr);
1107}
1108
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001110 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001111 int len) /* iso packet length */
1112{
1113 struct sd *sd = (struct sd *) gspca_dev;
1114 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001115 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116
1117/* frames are jpeg 4.1.1 without 0xff escape */
1118 switch (sd->bridge) {
1119 case BRIDGE_SPCA533:
1120 if (data[0] == 0xff) {
1121 if (data[1] != 0x01) { /* drop packet */
1122/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1123 return;
1124 }
1125 sof = 1;
1126 data += SPCA533_OFFSET_DATA;
1127 len -= SPCA533_OFFSET_DATA;
1128 } else {
1129 data += 1;
1130 len -= 1;
1131 }
1132 break;
1133 case BRIDGE_SPCA536:
1134 if (data[0] == 0xff) {
1135 sof = 1;
1136 data += SPCA536_OFFSET_DATA;
1137 len -= SPCA536_OFFSET_DATA;
1138 } else {
1139 data += 2;
1140 len -= 2;
1141 }
1142 break;
1143 default:
1144/* case BRIDGE_SPCA504: */
1145/* case BRIDGE_SPCA504B: */
1146 switch (data[0]) {
1147 case 0xfe: /* start of frame */
1148 sof = 1;
1149 data += SPCA50X_OFFSET_DATA;
1150 len -= SPCA50X_OFFSET_DATA;
1151 break;
1152 case 0xff: /* drop packet */
1153/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1154 return;
1155 default:
1156 data += 1;
1157 len -= 1;
1158 break;
1159 }
1160 break;
1161 case BRIDGE_SPCA504C:
1162 switch (data[0]) {
1163 case 0xfe: /* start of frame */
1164 sof = 1;
1165 data += SPCA504_PCCAM600_OFFSET_DATA;
1166 len -= SPCA504_PCCAM600_OFFSET_DATA;
1167 break;
1168 case 0xff: /* drop packet */
1169/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1170 return;
1171 default:
1172 data += 1;
1173 len -= 1;
1174 break;
1175 }
1176 break;
1177 }
1178 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001179 gspca_frame_add(gspca_dev, LAST_PACKET,
1180 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001181
1182 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001183 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001184 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001185 }
1186
1187 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001188 i = 0;
1189 do {
1190 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001191 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001192 data, i + 1);
1193 len -= i;
1194 data += i;
1195 *data = 0x00;
1196 i = 0;
1197 }
1198 i++;
1199 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001200 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001201}
1202
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001203static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1204{
1205 struct sd *sd = (struct sd *) gspca_dev;
1206
1207 sd->brightness = val;
1208 if (gspca_dev->streaming)
1209 setbrightness(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001210 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001211}
1212
1213static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1214{
1215 struct sd *sd = (struct sd *) gspca_dev;
1216
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001217 *val = sd->brightness;
1218 return 0;
1219}
1220
1221static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1222{
1223 struct sd *sd = (struct sd *) gspca_dev;
1224
1225 sd->contrast = val;
1226 if (gspca_dev->streaming)
1227 setcontrast(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001228 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001229}
1230
1231static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1232{
1233 struct sd *sd = (struct sd *) gspca_dev;
1234
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001235 *val = sd->contrast;
1236 return 0;
1237}
1238
1239static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1240{
1241 struct sd *sd = (struct sd *) gspca_dev;
1242
1243 sd->colors = val;
1244 if (gspca_dev->streaming)
1245 setcolors(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001246 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001247}
1248
1249static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1250{
1251 struct sd *sd = (struct sd *) gspca_dev;
1252
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001253 *val = sd->colors;
1254 return 0;
1255}
1256
1257static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1258{
1259 struct sd *sd = (struct sd *) gspca_dev;
1260
1261 sd->autogain = val;
1262 return 0;
1263}
1264
1265static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1266{
1267 struct sd *sd = (struct sd *) gspca_dev;
1268
1269 *val = sd->autogain;
1270 return 0;
1271}
1272
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001273static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1274 struct v4l2_jpegcompression *jcomp)
1275{
1276 struct sd *sd = (struct sd *) gspca_dev;
1277
1278 if (jcomp->quality < QUALITY_MIN)
1279 sd->quality = QUALITY_MIN;
1280 else if (jcomp->quality > QUALITY_MAX)
1281 sd->quality = QUALITY_MAX;
1282 else
1283 sd->quality = jcomp->quality;
1284 if (gspca_dev->streaming)
1285 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001286 return gspca_dev->usb_err;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001287}
1288
1289static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1290 struct v4l2_jpegcompression *jcomp)
1291{
1292 struct sd *sd = (struct sd *) gspca_dev;
1293
1294 memset(jcomp, 0, sizeof *jcomp);
1295 jcomp->quality = sd->quality;
1296 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1297 | V4L2_JPEG_MARKER_DQT;
1298 return 0;
1299}
1300
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001301/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001302static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001303 .name = MODULE_NAME,
1304 .ctrls = sd_ctrls,
1305 .nctrls = ARRAY_SIZE(sd_ctrls),
1306 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001307 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001308 .start = sd_start,
1309 .stopN = sd_stopN,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001310 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001311 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001312 .get_jcomp = sd_get_jcomp,
1313 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001314};
1315
1316/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001317#define BS(bridge, subtype) \
1318 .driver_info = (BRIDGE_ ## bridge << 8) \
1319 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001320static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001321 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1322 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1323 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1324 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1325 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1326 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1327 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1328 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1329 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1330 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1331 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1332 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1333 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1334 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1335 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1336 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1337 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1338 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1339 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001340 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001341 {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)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001379 {}
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,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001396#ifdef CONFIG_PM
1397 .suspend = gspca_suspend,
1398 .resume = gspca_resume,
1399#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001400};
1401
1402/* -- module insert / remove -- */
1403static int __init sd_mod_init(void)
1404{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001405 int ret;
1406 ret = usb_register(&sd_driver);
1407 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001408 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001409 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001410 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);