blob: 682652cb7fe19e613af1a059802fafd44df99f25 [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 Moine8295d992008-09-03 17:12:19 -0300463#ifdef GSPCA_DEBUG
464 if (len > USB_BUF_SZ) {
465 err("reg_r: buffer overflow");
466 return;
467 }
468#endif
469 usb_control_msg(gspca_dev->dev,
470 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 req,
472 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
473 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300474 index,
475 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 500);
477}
478
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300479/* write one byte */
480static void reg_w_1(struct gspca_dev *gspca_dev,
481 u8 req,
482 u16 value,
483 u16 index,
484 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300485{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300486 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300487 usb_control_msg(gspca_dev->dev,
488 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 req,
490 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300491 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300492 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 500);
494}
495
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300496/* write req / index / value */
497static int reg_w_riv(struct usb_device *dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300498 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499{
500 int ret;
501
502 ret = usb_control_msg(dev,
503 usb_sndctrlpipe(dev, 0),
504 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300505 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 value, index, NULL, 0, 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300507 PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300508 req, index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 if (ret < 0)
510 PDEBUG(D_ERR, "reg write: error %d", ret);
511 return ret;
512}
513
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300514/* read 1 byte */
515static int reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300516 u16 value) /* wValue */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517{
518 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300520 ret = usb_control_msg(gspca_dev->dev,
521 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522 0x20, /* request */
523 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
524 value,
525 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 500); /* timeout */
528 if (ret < 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 PDEBUG(D_ERR, "reg_r_1 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 return 0;
531 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533}
534
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300535/* read 1 or 2 bytes - returns < 0 if error */
536static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300537 u8 req, /* bRequest */
538 u16 index, /* wIndex */
539 u16 length) /* wLength (1 or 2 only) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540{
541 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 gspca_dev->usb_buf[1] = 0;
544 ret = usb_control_msg(gspca_dev->dev,
545 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 req,
547 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
548 0, /* value */
549 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 500);
552 if (ret < 0) {
553 PDEBUG(D_ERR, "reg_read err %d", ret);
554 return -1;
555 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300556 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557}
558
559static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300560 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561{
562 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300563 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300565 while (--ncmds >= 0) {
566 ret = reg_w_riv(dev, data->req, data->idx, data->val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567 if (ret < 0) {
568 PDEBUG(D_ERR,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300569 "Register write failed for 0x%02x, 0x%04x, 0x%04x",
570 data->req, data->val, data->idx);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571 return ret;
572 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300573 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574 }
575 return 0;
576}
577
578static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300579 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300580{
581 struct usb_device *dev = gspca_dev->dev;
582 int i, err;
583
584 /* loop over y components */
585 for (i = 0; i < 64; i++) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300586 err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587 if (err < 0)
588 return err;
589 }
590
591 /* loop over c components */
592 for (i = 0; i < 64; i++) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300593 err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300594 if (err < 0)
595 return err;
596 }
597 return 0;
598}
599
600static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300601 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602{
603 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300604 int notdone;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300605
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300606 reg_w_riv(dev, req, idx, val);
607 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
608 reg_w_riv(dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300609
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300610 PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300611
612 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300613 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300614 PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615}
616
617static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300618 u8 req,
619 u16 idx, u16 val, u8 stat, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620{
621 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300622 int status;
623 u8 endcode;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300625 reg_w_riv(dev, req, idx, val);
626 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300627 endcode = stat;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300628 PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300629 if (!count)
630 return;
631 count = 200;
632 while (--count > 0) {
633 msleep(10);
634 /* gsmart mini2 write a each wait setting 1 ms is enought */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300635/* reg_w_riv(dev, req, idx, val); */
636 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300638 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639 status, 200 - count);
640 break;
641 }
642 }
643}
644
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300645static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300646{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647 int count = 10;
648
649 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300650 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300651 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652 break;
653 msleep(10);
654 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300655 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656}
657
658static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
659{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300660 int count = 50;
661
662 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300663 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300664 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300665 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300666 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300667 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300668 break;
669 }
670 msleep(10);
671 }
672}
673
674static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
675{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300676 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300677
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300678 data = gspca_dev->usb_buf;
679 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300681 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300682 reg_r(gspca_dev, 0x23, 0, 64);
683 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300684}
685
686static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
687{
688 struct sd *sd = (struct sd *) gspca_dev;
689 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300690 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691 int rc;
692
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300693 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300694 switch (sd->bridge) {
695 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300696 reg_w_riv(dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300697 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300698 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300700 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300701 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300703 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300704 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300705 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706
707 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300708 reg_w_riv(dev, 0x31, 0, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300709 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300710 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711 break;
712 default:
713/* case BRIDGE_SPCA504B: */
714/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300715 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300716 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300717 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300718 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300719 rc = spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720 break;
721 case BRIDGE_SPCA504:
722 Size += 3;
723 if (sd->subtype == AiptekMiniPenCam13) {
724 /* spca504a aiptek */
725 spca504A_acknowledged_command(gspca_dev,
726 0x08, Size, 0,
727 0x80 | (Size & 0x0f), 1);
728 spca504A_acknowledged_command(gspca_dev,
729 1, 3, 0, 0x9f, 0);
730 } else {
731 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
732 }
733 break;
734 case BRIDGE_SPCA504C:
735 /* capture mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300736 reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
737 reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 break;
739 }
740}
741
742static void spca504_wait_status(struct gspca_dev *gspca_dev)
743{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300744 int cnt;
745
746 cnt = 256;
747 while (--cnt > 0) {
748 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300749 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300750 return;
751 msleep(10);
752 }
753}
754
755static void spca504B_setQtable(struct gspca_dev *gspca_dev)
756{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300757 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300758 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300759 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300760}
761
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300762static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763{
764 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300765 struct usb_device *dev = gspca_dev->dev;
766 u16 reg;
767
768 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
769 reg_w_riv(dev, 0x00, reg, sd->brightness);
770}
771
772static void setcontrast(struct gspca_dev *gspca_dev)
773{
774 struct sd *sd = (struct sd *) gspca_dev;
775 struct usb_device *dev = gspca_dev->dev;
776 u16 reg;
777
778 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
779 reg_w_riv(dev, 0x00, reg, sd->contrast);
780}
781
782static void setcolors(struct gspca_dev *gspca_dev)
783{
784 struct sd *sd = (struct sd *) gspca_dev;
785 struct usb_device *dev = gspca_dev->dev;
786 u16 reg;
787
788 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
789 reg_w_riv(dev, 0x00, reg, sd->colors);
790}
791
792static void init_ctl_reg(struct gspca_dev *gspca_dev)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795 struct usb_device *dev = gspca_dev->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 Moine2e1794b2009-08-31 06:15:22 -0300810 reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */
811 reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */
812 reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813 break;
814 case BRIDGE_SPCA536:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300815 reg_w_riv(dev, 0, 0x40, 0x20f5);
816 reg_w_riv(dev, 0, 0x01, 0x20f4);
817 reg_w_riv(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;
884 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300885 int i, err_code;
886 u8 info[6];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887
888 switch (sd->bridge) {
889 case BRIDGE_SPCA504B:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300890 reg_w_riv(dev, 0x1d, 0x00, 0);
891 reg_w_riv(dev, 0, 0x01, 0x2306);
892 reg_w_riv(dev, 0, 0x00, 0x0d04);
893 reg_w_riv(dev, 0, 0x00, 0x2000);
894 reg_w_riv(dev, 0, 0x13, 0x2301);
895 reg_w_riv(dev, 0, 0x00, 0x2306);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896 /* fall thru */
897 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300898 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899 spca50x_GetFirmware(gspca_dev);
900 break;
901 case BRIDGE_SPCA536:
902 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300903 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300904 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300905 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300906 spca504B_PollingDataReady(gspca_dev);
907 reg_w_riv(dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300908 spca504B_WaitCmdStatus(gspca_dev);
909 break;
910 case BRIDGE_SPCA504C: /* pccam600 */
911 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300912 reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
913 reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300914 spca504_wait_status(gspca_dev);
915 if (sd->subtype == LogitechClickSmart420)
916 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300917 spca504A_clicksmart420_open_data,
918 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300919 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300920 write_vector(gspca_dev, spca504_pccam600_open_data,
921 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 err_code = spca50x_setup_qtable(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300923 qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 if (err_code < 0) {
925 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
926 return err_code;
927 }
928 break;
929 default:
930/* case BRIDGE_SPCA504: */
931 PDEBUG(D_STREAM, "Opening SPCA504");
932 if (sd->subtype == AiptekMiniPenCam13) {
933 /*****************************/
934 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300935 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936 PDEBUG(D_STREAM,
937 "Read info: %d %d %d %d %d %d."
938 " Should be 1,0,2,2,0,0",
939 info[0], info[1], info[2],
940 info[3], info[4], info[5]);
941 /* spca504a aiptek */
942 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
943 spca504A_acknowledged_command(gspca_dev, 0x24,
944 8, 3, 0x9e, 1);
945 /* Twice sequencial need status 0xff->0x9e->0x9d */
946 spca504A_acknowledged_command(gspca_dev, 0x24,
947 8, 3, 0x9e, 0);
948
949 spca504A_acknowledged_command(gspca_dev, 0x24,
950 0, 0, 0x9d, 1);
951 /******************************/
952 /* spca504a aiptek */
953 spca504A_acknowledged_command(gspca_dev, 0x08,
954 6, 0, 0x86, 1);
955/* reg_write (dev, 0, 0x2000, 0); */
956/* reg_write (dev, 0, 0x2883, 1); */
957/* spca504A_acknowledged_command (gspca_dev, 0x08,
958 6, 0, 0x86, 1); */
959/* spca504A_acknowledged_command (gspca_dev, 0x24,
960 0, 0, 0x9D, 1); */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300961 reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */
962 reg_w_riv(dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300963 spca504A_acknowledged_command(gspca_dev, 0x01,
964 0x0f, 0, 0xff, 0);
965 }
966 /* setup qtable */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300967 reg_w_riv(dev, 0, 0x2000, 0);
968 reg_w_riv(dev, 0, 0x2883, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300969 err_code = spca50x_setup_qtable(gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300970 qtable_spca504_default);
971 if (err_code < 0) {
972 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
973 return err_code;
974 }
975 break;
976 }
977 return 0;
978}
979
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300980static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300981{
982 struct sd *sd = (struct sd *) gspca_dev;
983 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 int enable;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300985 int i;
986 u8 info[6];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300987
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300988 /* create the JPEG header */
989 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
Julia Lawall3eb02372009-07-19 07:09:32 -0300990 if (!sd->jpeg_hdr)
991 return -ENOMEM;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300992 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
993 0x22); /* JPEG 411 */
994 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
995
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300996 if (sd->bridge == BRIDGE_SPCA504B)
997 spca504B_setQtable(gspca_dev);
998 spca504B_SetSizeType(gspca_dev);
999 switch (sd->bridge) {
1000 default:
1001/* case BRIDGE_SPCA504B: */
1002/* case BRIDGE_SPCA533: */
1003/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001004 switch (sd->subtype) {
1005 case MegapixV4:
1006 case LogitechClickSmart820:
1007 case MegaImageVI:
1008 reg_w_riv(dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001009 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -03001010 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001012 break;
1013 default:
1014 reg_w_riv(dev, 0x31, 0, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001016 spca504B_PollingDataReady(gspca_dev);
1017 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001018 }
1019 break;
1020 case BRIDGE_SPCA504:
1021 if (sd->subtype == AiptekMiniPenCam13) {
1022 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001023 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024 PDEBUG(D_STREAM,
1025 "Read info: %d %d %d %d %d %d."
1026 " Should be 1,0,2,2,0,0",
1027 info[0], info[1], info[2],
1028 info[3], info[4], info[5]);
1029 /* spca504a aiptek */
1030 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
1031 spca504A_acknowledged_command(gspca_dev, 0x24,
1032 8, 3, 0x9e, 1);
1033 /* Twice sequencial need status 0xff->0x9e->0x9d */
1034 spca504A_acknowledged_command(gspca_dev, 0x24,
1035 8, 3, 0x9e, 0);
1036 spca504A_acknowledged_command(gspca_dev, 0x24,
1037 0, 0, 0x9d, 1);
1038 } else {
1039 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1040 for (i = 0; i < 6; i++)
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001041 info[i] = reg_r_1(gspca_dev, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001042 PDEBUG(D_STREAM,
1043 "Read info: %d %d %d %d %d %d."
1044 " Should be 1,0,2,2,0,0",
1045 info[0], info[1], info[2],
1046 info[3], info[4], info[5]);
1047 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
1048 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
1049 }
1050 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001051 reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */
1052 reg_w_riv(dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001053 break;
1054 case BRIDGE_SPCA504C:
1055 if (sd->subtype == LogitechClickSmart420) {
1056 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001057 spca504A_clicksmart420_init_data,
1058 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001060 write_vector(gspca_dev, spca504_pccam600_init_data,
1061 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001062 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001063 enable = (sd->autogain ? 0x04 : 0x01);
1064 reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
1065 reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001066
1067 /* set default exposure compensation and whiteness balance */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001068 reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
1069 reg_w_riv(dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001070 spca504B_SetSizeType(gspca_dev);
1071 break;
1072 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001073 init_ctl_reg(gspca_dev);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -03001074 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075}
1076
1077static void sd_stopN(struct gspca_dev *gspca_dev)
1078{
1079 struct sd *sd = (struct sd *) gspca_dev;
1080 struct usb_device *dev = gspca_dev->dev;
1081
1082 switch (sd->bridge) {
1083 default:
1084/* case BRIDGE_SPCA533: */
1085/* case BRIDGE_SPCA536: */
1086/* case BRIDGE_SPCA504B: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001087 reg_w_riv(dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001088 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001089 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001090 break;
1091 case BRIDGE_SPCA504:
1092 case BRIDGE_SPCA504C:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001093 reg_w_riv(dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001094
1095 if (sd->subtype == AiptekMiniPenCam13) {
1096 /* spca504a aiptek */
1097/* spca504A_acknowledged_command(gspca_dev, 0x08,
1098 6, 0, 0x86, 1); */
1099 spca504A_acknowledged_command(gspca_dev, 0x24,
1100 0x00, 0x00, 0x9d, 1);
1101 spca504A_acknowledged_command(gspca_dev, 0x01,
1102 0x0f, 0x00, 0xff, 1);
1103 } else {
1104 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001105 reg_w_riv(dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001106 }
1107 break;
1108 }
1109}
1110
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001111static void sd_stop0(struct gspca_dev *gspca_dev)
1112{
1113 struct sd *sd = (struct sd *) gspca_dev;
1114
1115 kfree(sd->jpeg_hdr);
1116}
1117
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001118static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001119 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001120 int len) /* iso packet length */
1121{
1122 struct sd *sd = (struct sd *) gspca_dev;
1123 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -03001124 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001125
1126/* frames are jpeg 4.1.1 without 0xff escape */
1127 switch (sd->bridge) {
1128 case BRIDGE_SPCA533:
1129 if (data[0] == 0xff) {
1130 if (data[1] != 0x01) { /* drop packet */
1131/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1132 return;
1133 }
1134 sof = 1;
1135 data += SPCA533_OFFSET_DATA;
1136 len -= SPCA533_OFFSET_DATA;
1137 } else {
1138 data += 1;
1139 len -= 1;
1140 }
1141 break;
1142 case BRIDGE_SPCA536:
1143 if (data[0] == 0xff) {
1144 sof = 1;
1145 data += SPCA536_OFFSET_DATA;
1146 len -= SPCA536_OFFSET_DATA;
1147 } else {
1148 data += 2;
1149 len -= 2;
1150 }
1151 break;
1152 default:
1153/* case BRIDGE_SPCA504: */
1154/* case BRIDGE_SPCA504B: */
1155 switch (data[0]) {
1156 case 0xfe: /* start of frame */
1157 sof = 1;
1158 data += SPCA50X_OFFSET_DATA;
1159 len -= SPCA50X_OFFSET_DATA;
1160 break;
1161 case 0xff: /* drop packet */
1162/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1163 return;
1164 default:
1165 data += 1;
1166 len -= 1;
1167 break;
1168 }
1169 break;
1170 case BRIDGE_SPCA504C:
1171 switch (data[0]) {
1172 case 0xfe: /* start of frame */
1173 sof = 1;
1174 data += SPCA504_PCCAM600_OFFSET_DATA;
1175 len -= SPCA504_PCCAM600_OFFSET_DATA;
1176 break;
1177 case 0xff: /* drop packet */
1178/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1179 return;
1180 default:
1181 data += 1;
1182 len -= 1;
1183 break;
1184 }
1185 break;
1186 }
1187 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001188 gspca_frame_add(gspca_dev, LAST_PACKET,
1189 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001190
1191 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001192 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001193 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001194 }
1195
1196 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001197 i = 0;
1198 do {
1199 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001200 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001201 data, i + 1);
1202 len -= i;
1203 data += i;
1204 *data = 0x00;
1205 i = 0;
1206 }
1207 i++;
1208 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001209 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001210}
1211
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001212static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1213{
1214 struct sd *sd = (struct sd *) gspca_dev;
1215
1216 sd->brightness = val;
1217 if (gspca_dev->streaming)
1218 setbrightness(gspca_dev);
1219 return 0;
1220}
1221
1222static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1223{
1224 struct sd *sd = (struct sd *) gspca_dev;
1225
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001226 *val = sd->brightness;
1227 return 0;
1228}
1229
1230static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1231{
1232 struct sd *sd = (struct sd *) gspca_dev;
1233
1234 sd->contrast = val;
1235 if (gspca_dev->streaming)
1236 setcontrast(gspca_dev);
1237 return 0;
1238}
1239
1240static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1241{
1242 struct sd *sd = (struct sd *) gspca_dev;
1243
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244 *val = sd->contrast;
1245 return 0;
1246}
1247
1248static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1249{
1250 struct sd *sd = (struct sd *) gspca_dev;
1251
1252 sd->colors = val;
1253 if (gspca_dev->streaming)
1254 setcolors(gspca_dev);
1255 return 0;
1256}
1257
1258static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1259{
1260 struct sd *sd = (struct sd *) gspca_dev;
1261
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001262 *val = sd->colors;
1263 return 0;
1264}
1265
1266static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1267{
1268 struct sd *sd = (struct sd *) gspca_dev;
1269
1270 sd->autogain = val;
1271 return 0;
1272}
1273
1274static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1275{
1276 struct sd *sd = (struct sd *) gspca_dev;
1277
1278 *val = sd->autogain;
1279 return 0;
1280}
1281
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001282static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1283 struct v4l2_jpegcompression *jcomp)
1284{
1285 struct sd *sd = (struct sd *) gspca_dev;
1286
1287 if (jcomp->quality < QUALITY_MIN)
1288 sd->quality = QUALITY_MIN;
1289 else if (jcomp->quality > QUALITY_MAX)
1290 sd->quality = QUALITY_MAX;
1291 else
1292 sd->quality = jcomp->quality;
1293 if (gspca_dev->streaming)
1294 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1295 return 0;
1296}
1297
1298static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1299 struct v4l2_jpegcompression *jcomp)
1300{
1301 struct sd *sd = (struct sd *) gspca_dev;
1302
1303 memset(jcomp, 0, sizeof *jcomp);
1304 jcomp->quality = sd->quality;
1305 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1306 | V4L2_JPEG_MARKER_DQT;
1307 return 0;
1308}
1309
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001310/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001311static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001312 .name = MODULE_NAME,
1313 .ctrls = sd_ctrls,
1314 .nctrls = ARRAY_SIZE(sd_ctrls),
1315 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001316 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001317 .start = sd_start,
1318 .stopN = sd_stopN,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001319 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001320 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001321 .get_jcomp = sd_get_jcomp,
1322 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001323};
1324
1325/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001326#define BS(bridge, subtype) \
1327 .driver_info = (BRIDGE_ ## bridge << 8) \
1328 | (subtype)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001329static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001330 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1331 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1332 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1333 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1334 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1335 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1336 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1337 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1338 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1339 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1340 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1341 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1342 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1343 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1344 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1345 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1346 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1347 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1348 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001349 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001350 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1351 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1352 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1353 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1354 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1355 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1356 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1357 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1358 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1359 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1360 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1361 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1362 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1363 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1364 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1365 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1366 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1367 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1368 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1369 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1370 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1371 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1372 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1373 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1374 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1375 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1376 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1377 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1378 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1379 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1380 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1381 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1382 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1383 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1384 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1385 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1386 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1387 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001388 {}
1389};
1390MODULE_DEVICE_TABLE(usb, device_table);
1391
1392/* -- device connect -- */
1393static int sd_probe(struct usb_interface *intf,
1394 const struct usb_device_id *id)
1395{
1396 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1397 THIS_MODULE);
1398}
1399
1400static struct usb_driver sd_driver = {
1401 .name = MODULE_NAME,
1402 .id_table = device_table,
1403 .probe = sd_probe,
1404 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001405#ifdef CONFIG_PM
1406 .suspend = gspca_suspend,
1407 .resume = gspca_resume,
1408#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001409};
1410
1411/* -- module insert / remove -- */
1412static int __init sd_mod_init(void)
1413{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001414 int ret;
1415 ret = usb_register(&sd_driver);
1416 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001417 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001418 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001419 return 0;
1420}
1421static void __exit sd_mod_exit(void)
1422{
1423 usb_deregister(&sd_driver);
1424 PDEBUG(D_PROBE, "deregistered");
1425}
1426
1427module_init(sd_mod_init);
1428module_exit(sd_mod_exit);