blob: 75494016515dc888dca32e084fa39edbdc4b43b3 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * SPCA500 chip based cameras initialization data
3 *
4 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#define MODULE_NAME "spca500"
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/SPCA500 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030035 __u8 packet[ISO_MAX_SIZE + 128];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030036 /* !! no more than 128 ff in an ISO packet */
37
38 unsigned char brightness;
39 unsigned char contrast;
40 unsigned char colors;
41
42 char qindex;
43 char subtype;
44#define AgfaCl20 0
45#define AiptekPocketDV 1
46#define BenqDC1016 2
47#define CreativePCCam300 3
48#define DLinkDSC350 4
49#define Gsmartmini 5
50#define IntelPocketPCCamera 6
51#define KodakEZ200 7
52#define LogitechClickSmart310 8
53#define LogitechClickSmart510 9
54#define LogitechTraveler 10
55#define MustekGsmart300 11
56#define Optimedia 12
57#define PalmPixDC85 13
58#define ToptroIndus 14
59};
60
61/* V4L2 controls supported by the driver */
62static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
64static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
66static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
67static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
68
69static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030070 {
71 {
72 .id = V4L2_CID_BRIGHTNESS,
73 .type = V4L2_CTRL_TYPE_INTEGER,
74 .name = "Brightness",
75 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030076 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030077 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030078#define BRIGHTNESS_DEF 127
79 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080 },
81 .set = sd_setbrightness,
82 .get = sd_getbrightness,
83 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030084 {
85 {
86 .id = V4L2_CID_CONTRAST,
87 .type = V4L2_CTRL_TYPE_INTEGER,
88 .name = "Contrast",
89 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030090 .maximum = 63,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030092#define CONTRAST_DEF 31
93 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030094 },
95 .set = sd_setcontrast,
96 .get = sd_getcontrast,
97 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098 {
99 {
100 .id = V4L2_CID_SATURATION,
101 .type = V4L2_CTRL_TYPE_INTEGER,
102 .name = "Color",
103 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300104 .maximum = 63,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300105 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300106#define COLOR_DEF 31
107 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 },
109 .set = sd_setcolors,
110 .get = sd_getcolors,
111 },
112};
113
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300114static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300115 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
116 .bytesperline = 320,
117 .sizeimage = 320 * 240 * 3 / 8 + 590,
118 .colorspace = V4L2_COLORSPACE_JPEG,
119 .priv = 1},
120 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
121 .bytesperline = 640,
122 .sizeimage = 640 * 480 * 3 / 8 + 590,
123 .colorspace = V4L2_COLORSPACE_JPEG,
124 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125};
126
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300127static const struct v4l2_pix_format sif_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300128 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
129 .bytesperline = 176,
130 .sizeimage = 176 * 144 * 3 / 8 + 590,
131 .colorspace = V4L2_COLORSPACE_JPEG,
132 .priv = 1},
133 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
134 .bytesperline = 352,
135 .sizeimage = 352 * 288 * 3 / 8 + 590,
136 .colorspace = V4L2_COLORSPACE_JPEG,
137 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300138};
139
140/* Frame packet header offsets for the spca500 */
141#define SPCA500_OFFSET_PADDINGLB 2
142#define SPCA500_OFFSET_PADDINGHB 3
143#define SPCA500_OFFSET_MODE 4
144#define SPCA500_OFFSET_IMGWIDTH 5
145#define SPCA500_OFFSET_IMGHEIGHT 6
146#define SPCA500_OFFSET_IMGMODE 7
147#define SPCA500_OFFSET_QTBLINDEX 8
148#define SPCA500_OFFSET_FRAMSEQ 9
149#define SPCA500_OFFSET_CDSPINFO 10
150#define SPCA500_OFFSET_GPIO 11
151#define SPCA500_OFFSET_AUGPIO 12
152#define SPCA500_OFFSET_DATA 16
153
154
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300155static const __u16 spca500_visual_defaults[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300156 {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
157 * hue (H byte) = 0,
158 * saturation/hue enable,
159 * brightness/contrast enable.
160 */
161 {0x00, 0x0000, 0x8167}, /* brightness = 0 */
162 {0x00, 0x0020, 0x8168}, /* contrast = 0 */
163 {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
164 * hue (H byte) = 0, saturation/hue enable,
165 * brightness/contrast enable.
166 * was 0x0003, now 0x0000.
167 */
168 {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */
169 {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */
170 {0x00, 0x0050, 0x8157}, /* edge gain high threshold */
171 {0x00, 0x0030, 0x8158}, /* edge gain low threshold */
172 {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */
173 {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */
174 {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */
175 {0x0c, 0x0004, 0x0000},
176 /* set interface */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300177 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300178};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300179static const __u16 Clicksmart510_defaults[][3] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180 {0x00, 0x00, 0x8211},
181 {0x00, 0x01, 0x82c0},
182 {0x00, 0x10, 0x82cb},
183 {0x00, 0x0f, 0x800d},
184 {0x00, 0x82, 0x8225},
185 {0x00, 0x21, 0x8228},
186 {0x00, 0x00, 0x8203},
187 {0x00, 0x00, 0x8204},
188 {0x00, 0x08, 0x8205},
189 {0x00, 0xf8, 0x8206},
190 {0x00, 0x28, 0x8207},
191 {0x00, 0xa0, 0x8208},
192 {0x00, 0x08, 0x824a},
193 {0x00, 0x08, 0x8214},
194 {0x00, 0x80, 0x82c1},
195 {0x00, 0x00, 0x82c2},
196 {0x00, 0x00, 0x82ca},
197 {0x00, 0x80, 0x82c1},
198 {0x00, 0x04, 0x82c2},
199 {0x00, 0x00, 0x82ca},
200 {0x00, 0xfc, 0x8100},
201 {0x00, 0xfc, 0x8105},
202 {0x00, 0x30, 0x8101},
203 {0x00, 0x00, 0x8102},
204 {0x00, 0x00, 0x8103},
205 {0x00, 0x66, 0x8107},
206 {0x00, 0x00, 0x816b},
207 {0x00, 0x00, 0x8155},
208 {0x00, 0x01, 0x8156},
209 {0x00, 0x60, 0x8157},
210 {0x00, 0x40, 0x8158},
211 {0x00, 0x0a, 0x8159},
212 {0x00, 0x06, 0x815a},
213 {0x00, 0x00, 0x813f},
214 {0x00, 0x00, 0x8200},
215 {0x00, 0x19, 0x8201},
216 {0x00, 0x00, 0x82c1},
217 {0x00, 0xa0, 0x82c2},
218 {0x00, 0x00, 0x82ca},
219 {0x00, 0x00, 0x8117},
220 {0x00, 0x00, 0x8118},
221 {0x00, 0x65, 0x8119},
222 {0x00, 0x00, 0x811a},
223 {0x00, 0x00, 0x811b},
224 {0x00, 0x55, 0x811c},
225 {0x00, 0x65, 0x811d},
226 {0x00, 0x55, 0x811e},
227 {0x00, 0x16, 0x811f},
228 {0x00, 0x19, 0x8120},
229 {0x00, 0x80, 0x8103},
230 {0x00, 0x83, 0x816b},
231 {0x00, 0x25, 0x8168},
232 {0x00, 0x01, 0x820f},
233 {0x00, 0xff, 0x8115},
234 {0x00, 0x48, 0x8116},
235 {0x00, 0x50, 0x8151},
236 {0x00, 0x40, 0x8152},
237 {0x00, 0x78, 0x8153},
238 {0x00, 0x40, 0x8154},
239 {0x00, 0x00, 0x8167},
240 {0x00, 0x20, 0x8168},
241 {0x00, 0x00, 0x816a},
242 {0x00, 0x03, 0x816b},
243 {0x00, 0x20, 0x8169},
244 {0x00, 0x60, 0x8157},
245 {0x00, 0x00, 0x8190},
246 {0x00, 0x00, 0x81a1},
247 {0x00, 0x00, 0x81b2},
248 {0x00, 0x27, 0x8191},
249 {0x00, 0x27, 0x81a2},
250 {0x00, 0x27, 0x81b3},
251 {0x00, 0x4b, 0x8192},
252 {0x00, 0x4b, 0x81a3},
253 {0x00, 0x4b, 0x81b4},
254 {0x00, 0x66, 0x8193},
255 {0x00, 0x66, 0x81a4},
256 {0x00, 0x66, 0x81b5},
257 {0x00, 0x79, 0x8194},
258 {0x00, 0x79, 0x81a5},
259 {0x00, 0x79, 0x81b6},
260 {0x00, 0x8a, 0x8195},
261 {0x00, 0x8a, 0x81a6},
262 {0x00, 0x8a, 0x81b7},
263 {0x00, 0x9b, 0x8196},
264 {0x00, 0x9b, 0x81a7},
265 {0x00, 0x9b, 0x81b8},
266 {0x00, 0xa6, 0x8197},
267 {0x00, 0xa6, 0x81a8},
268 {0x00, 0xa6, 0x81b9},
269 {0x00, 0xb2, 0x8198},
270 {0x00, 0xb2, 0x81a9},
271 {0x00, 0xb2, 0x81ba},
272 {0x00, 0xbe, 0x8199},
273 {0x00, 0xbe, 0x81aa},
274 {0x00, 0xbe, 0x81bb},
275 {0x00, 0xc8, 0x819a},
276 {0x00, 0xc8, 0x81ab},
277 {0x00, 0xc8, 0x81bc},
278 {0x00, 0xd2, 0x819b},
279 {0x00, 0xd2, 0x81ac},
280 {0x00, 0xd2, 0x81bd},
281 {0x00, 0xdb, 0x819c},
282 {0x00, 0xdb, 0x81ad},
283 {0x00, 0xdb, 0x81be},
284 {0x00, 0xe4, 0x819d},
285 {0x00, 0xe4, 0x81ae},
286 {0x00, 0xe4, 0x81bf},
287 {0x00, 0xed, 0x819e},
288 {0x00, 0xed, 0x81af},
289 {0x00, 0xed, 0x81c0},
290 {0x00, 0xf7, 0x819f},
291 {0x00, 0xf7, 0x81b0},
292 {0x00, 0xf7, 0x81c1},
293 {0x00, 0xff, 0x81a0},
294 {0x00, 0xff, 0x81b1},
295 {0x00, 0xff, 0x81c2},
296 {0x00, 0x03, 0x8156},
297 {0x00, 0x00, 0x8211},
298 {0x00, 0x20, 0x8168},
299 {0x00, 0x01, 0x8202},
300 {0x00, 0x30, 0x8101},
301 {0x00, 0x00, 0x8111},
302 {0x00, 0x00, 0x8112},
303 {0x00, 0x00, 0x8113},
304 {0x00, 0x00, 0x8114},
305 {}
306};
307
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300308static const __u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309 { /* Q-table Y-components */
310 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
311 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
312 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
313 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
314 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
315 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
316 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
317 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
318 { /* Q-table C-components */
319 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
320 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
321 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
322 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
323 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
324 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
325 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
326 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
327};
328
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300329static const __u8 qtable_kodak_ez200[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330 { /* Q-table Y-components */
331 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
332 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
333 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
334 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
335 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
336 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
337 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
338 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
339 { /* Q-table C-components */
340 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
341 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
342 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
343 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
344 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
345 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
346 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
347 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
348};
349
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300350static const __u8 qtable_pocketdv[2][64] = {
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300351 { /* Q-table Y-components start registers 0x8800 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300352 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
353 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
354 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
355 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
356 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
357 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
358 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
359 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
360 },
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300361 { /* Q-table C-components start registers 0x8840 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300362 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
363 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
364 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
365 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
366 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
367 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
368 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
369 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
370};
371
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300372/* read 'len' bytes to gspca_dev->usb_buf */
373static void reg_r(struct gspca_dev *gspca_dev,
374 __u16 index,
375 __u16 length)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300376{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300377 usb_control_msg(gspca_dev->dev,
378 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379 0,
380 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
381 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300382 index, gspca_dev->usb_buf, length, 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300383}
384
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300385static int reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300386 __u16 req, __u16 index, __u16 value)
387{
388 int ret;
389
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300390 PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300391 ret = usb_control_msg(gspca_dev->dev,
392 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300394 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300395 value, index, NULL, 0, 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300396 if (ret < 0)
397 PDEBUG(D_ERR, "reg write: error %d", ret);
398 return ret;
399}
400
401/* returns: negative is error, pos or zero is data */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300402static int reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300403 __u16 req, /* bRequest */
404 __u16 index, /* wIndex */
405 __u16 length) /* wLength (1 or 2 only) */
406{
407 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300409 gspca_dev->usb_buf[1] = 0;
410 ret = usb_control_msg(gspca_dev->dev,
411 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412 req,
413 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
414 0, /* value */
415 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300416 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 500); /* timeout */
418 if (ret < 0) {
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300419 PDEBUG(D_ERR, "reg_r_12 err %d", ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420 return -1;
421 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300422 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423}
424
425/*
426 * Simple function to wait for a given 8-bit value to be returned from
427 * a reg_read call.
428 * Returns: negative is error or timeout, zero is success.
429 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300430static int reg_r_wait(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300431 __u16 reg, __u16 index, __u16 value)
432{
433 int ret, cnt = 20;
434
435 while (--cnt > 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300436 ret = reg_r_12(gspca_dev, reg, index, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300437 if (ret == value)
438 return 0;
439 msleep(50);
440 }
441 return -EIO;
442}
443
444static int write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300445 const __u16 data[][3])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300447 int ret, i = 0;
448
449 while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450 ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451 if (ret < 0)
452 return ret;
453 i++;
454 }
455 return 0;
456}
457
458static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
459 unsigned int request,
460 unsigned int ybase,
461 unsigned int cbase,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300462 const __u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 int i, err;
465
466 /* loop over y components */
467 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300468 err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 if (err < 0)
470 return err;
471 }
472
473 /* loop over c components */
474 for (i = 0; i < 64; i++) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300475 err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 if (err < 0)
477 return err;
478 }
479 return 0;
480}
481
482static void spca500_ping310(struct gspca_dev *gspca_dev)
483{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300484 reg_r(gspca_dev, 0x0d04, 2);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300485 PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300486 gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487}
488
489static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
490{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300491 reg_r(gspca_dev, 0x0d05, 2);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300492 PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300493 gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
494 reg_w(gspca_dev, 0x00, 0x8167, 0x5a);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 spca500_ping310(gspca_dev);
496
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300497 reg_w(gspca_dev, 0x00, 0x8168, 0x22);
498 reg_w(gspca_dev, 0x00, 0x816a, 0xc0);
499 reg_w(gspca_dev, 0x00, 0x816b, 0x0b);
500 reg_w(gspca_dev, 0x00, 0x8169, 0x25);
501 reg_w(gspca_dev, 0x00, 0x8157, 0x5b);
502 reg_w(gspca_dev, 0x00, 0x8158, 0x5b);
503 reg_w(gspca_dev, 0x00, 0x813f, 0x03);
504 reg_w(gspca_dev, 0x00, 0x8151, 0x4a);
505 reg_w(gspca_dev, 0x00, 0x8153, 0x78);
506 reg_w(gspca_dev, 0x00, 0x0d01, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 /* 00 for adjust shutter */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300508 reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
509 reg_w(gspca_dev, 0x00, 0x8169, 0x25);
510 reg_w(gspca_dev, 0x00, 0x0d01, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511}
512
513static void spca500_setmode(struct gspca_dev *gspca_dev,
514 __u8 xmult, __u8 ymult)
515{
516 int mode;
517
518 /* set x multiplier */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300519 reg_w(gspca_dev, 0, 0x8001, xmult);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300520
521 /* set y multiplier */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 reg_w(gspca_dev, 0, 0x8002, ymult);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523
524 /* use compressed mode, VGA, with mode specific subsample */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300525 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 reg_w(gspca_dev, 0, 0x8003, mode << 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527}
528
529static int spca500_full_reset(struct gspca_dev *gspca_dev)
530{
531 int err;
532
533 /* send the reset command */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 if (err < 0)
536 return err;
537
538 /* wait for the reset to complete */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300539 err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 if (err < 0)
541 return err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300542 err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543 if (err < 0)
544 return err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300545 err = reg_r_wait(gspca_dev, 0x06, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 if (err < 0) {
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300547 PDEBUG(D_ERR, "reg_r_wait() failed");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 return err;
549 }
550 /* all ok */
551 return 0;
552}
553
554/* Synchro the Bridge with sensor */
555/* Maybe that will work on all spca500 chip */
556/* because i only own a clicksmart310 try for that chip */
557/* using spca50x_set_packet_size() cause an Ooops here */
558/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
559/* up-port the same feature as in 2.4.x kernel */
560static int spca500_synch310(struct gspca_dev *gspca_dev)
561{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300562 if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
563 PDEBUG(D_ERR, "Set packet size: set interface error");
564 goto error;
565 }
566 spca500_ping310(gspca_dev);
567
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300568 reg_r(gspca_dev, 0x0d00, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569
570 /* need alt setting here */
571 PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
572
573 /* Windoze use pipe with altsetting 6 why 7 here */
574 if (usb_set_interface(gspca_dev->dev,
575 gspca_dev->iface,
576 gspca_dev->alt) < 0) {
577 PDEBUG(D_ERR, "Set packet size: set interface error");
578 goto error;
579 }
580 return 0;
581error:
582 return -EBUSY;
583}
584
585static void spca500_reinit(struct gspca_dev *gspca_dev)
586{
587 int err;
588 __u8 Data;
589
590 /* some unknow command from Aiptek pocket dv and family300 */
591
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300592 reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
593 reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
594 reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595
596 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300597 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300598
599 err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
600 qtable_pocketdv);
601 if (err < 0)
602 PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
603
604 /* set qtable index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 reg_w(gspca_dev, 0x00, 0x8880, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 /* family cam Quicksmart stuff */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300607 reg_w(gspca_dev, 0x00, 0x800a, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300608 /* Set agc transfer: synced inbetween frames */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300609 reg_w(gspca_dev, 0x00, 0x820f, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300610 /* Init SDRAM - needed for SDRAM access */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300611 reg_w(gspca_dev, 0x00, 0x870a, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 /*Start init sequence or stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300613 reg_w(gspca_dev, 0, 0x8003, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300614 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300615 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300616 msleep(2000);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300617 if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {
618 reg_r(gspca_dev, 0x816b, 1);
619 Data = gspca_dev->usb_buf[0];
620 reg_w(gspca_dev, 0x00, 0x816b, Data);
621 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300622}
623
624/* this function is called at probe time */
625static int sd_config(struct gspca_dev *gspca_dev,
626 const struct usb_device_id *id)
627{
628 struct sd *sd = (struct sd *) gspca_dev;
629 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300631 cam = &gspca_dev->cam;
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300632 sd->subtype = id->driver_info;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633 if (sd->subtype != LogitechClickSmart310) {
634 cam->cam_mode = vga_mode;
Julia Lawall80297122008-11-12 23:18:21 -0300635 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636 } else {
637 cam->cam_mode = sif_mode;
Julia Lawall80297122008-11-12 23:18:21 -0300638 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639 }
640 sd->qindex = 5;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300641 sd->brightness = BRIGHTNESS_DEF;
642 sd->contrast = CONTRAST_DEF;
643 sd->colors = COLOR_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300644 return 0;
645}
646
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300647/* this function is called at probe and resume time */
648static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300649{
650 struct sd *sd = (struct sd *) gspca_dev;
651
652 /* initialisation of spca500 based cameras is deferred */
653 PDEBUG(D_STREAM, "SPCA500 init");
654 if (sd->subtype == LogitechClickSmart310)
655 spca500_clksmart310_init(gspca_dev);
656/* else
657 spca500_initialise(gspca_dev); */
658 PDEBUG(D_STREAM, "SPCA500 init done");
659 return 0;
660}
661
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300662static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300663{
664 struct sd *sd = (struct sd *) gspca_dev;
665 int err;
666 __u8 Data;
667 __u8 xmult, ymult;
668
669 if (sd->subtype == LogitechClickSmart310) {
670 xmult = 0x16;
671 ymult = 0x12;
672 } else {
673 xmult = 0x28;
674 ymult = 0x1e;
675 }
676
677 /* is there a sensor here ? */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300678 reg_r(gspca_dev, 0x8a04, 1);
679 PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x",
680 gspca_dev->usb_buf[0]);
681 PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682 gspca_dev->curr_mode, xmult, ymult);
683
684 /* setup qtable */
685 switch (sd->subtype) {
686 case LogitechClickSmart310:
687 spca500_setmode(gspca_dev, xmult, ymult);
688
689 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300690 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
691 reg_w(gspca_dev, 0x00, 0x8880, 3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692 err = spca50x_setup_qtable(gspca_dev,
693 0x00, 0x8800, 0x8840,
694 qtable_creative_pccam);
695 if (err < 0)
696 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
697 /* Init SDRAM - needed for SDRAM access */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300698 reg_w(gspca_dev, 0x00, 0x870a, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699
700 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300701 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702 msleep(500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300704 PDEBUG(D_ERR, "reg_r_wait() failed");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300706 reg_r(gspca_dev, 0x816b, 1);
707 Data = gspca_dev->usb_buf[0];
708 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300709
710 spca500_synch310(gspca_dev);
711
712 write_vector(gspca_dev, spca500_visual_defaults);
713 spca500_setmode(gspca_dev, xmult, ymult);
714 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300715 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300716 PDEBUG(D_ERR, "failed to enable drop packet");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300717 reg_w(gspca_dev, 0x00, 0x8880, 3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718 err = spca50x_setup_qtable(gspca_dev,
719 0x00, 0x8800, 0x8840,
720 qtable_creative_pccam);
721 if (err < 0)
722 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
723
724 /* Init SDRAM - needed for SDRAM access */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300725 reg_w(gspca_dev, 0x00, 0x870a, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726
727 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300728 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300730 if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300731 PDEBUG(D_ERR, "reg_r_wait() failed");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300733 reg_r(gspca_dev, 0x816b, 1);
734 Data = gspca_dev->usb_buf[0];
735 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 break;
737 case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */
738 case IntelPocketPCCamera: /* FIXME: Temporary fix for
739 * Intel Pocket PC Camera
740 * - NWG (Sat 29th March 2003) */
741
742 /* do a full reset */
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300743 err = spca500_full_reset(gspca_dev);
744 if (err < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 PDEBUG(D_ERR, "spca500_full_reset failed");
746
747 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300748 err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749 if (err < 0)
750 PDEBUG(D_ERR, "failed to enable drop packet");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300751 reg_w(gspca_dev, 0x00, 0x8880, 3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300752 err = spca50x_setup_qtable(gspca_dev,
753 0x00, 0x8800, 0x8840,
754 qtable_creative_pccam);
755 if (err < 0)
756 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
757
758 spca500_setmode(gspca_dev, xmult, ymult);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300759 reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300760
761 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300762 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300764 if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300765 PDEBUG(D_ERR, "reg_r_wait() failed");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300766
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300767 reg_r(gspca_dev, 0x816b, 1);
768 Data = gspca_dev->usb_buf[0];
769 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300770
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300771/* write_vector(gspca_dev, spca500_visual_defaults); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772 break;
773 case KodakEZ200: /* Kodak EZ200 */
774
775 /* do a full reset */
776 err = spca500_full_reset(gspca_dev);
777 if (err < 0)
778 PDEBUG(D_ERR, "spca500_full_reset failed");
779 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300780 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
781 reg_w(gspca_dev, 0x00, 0x8880, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782 err = spca50x_setup_qtable(gspca_dev,
783 0x00, 0x8800, 0x8840,
784 qtable_kodak_ez200);
785 if (err < 0)
786 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
787 spca500_setmode(gspca_dev, xmult, ymult);
788
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300789 reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300790
791 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300792 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300793
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300794 if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300795 PDEBUG(D_ERR, "reg_r_wait() failed");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300797 reg_r(gspca_dev, 0x816b, 1);
798 Data = gspca_dev->usb_buf[0];
799 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300800
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300801/* write_vector(gspca_dev, spca500_visual_defaults); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300802 break;
803
804 case BenqDC1016:
805 case DLinkDSC350: /* FamilyCam 300 */
806 case AiptekPocketDV: /* Aiptek PocketDV */
807 case Gsmartmini: /*Mustek Gsmart Mini */
808 case MustekGsmart300: /* Mustek Gsmart 300 */
809 case PalmPixDC85:
810 case Optimedia:
811 case ToptroIndus:
812 case AgfaCl20:
813 spca500_reinit(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300814 reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300816 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817
818 err = spca50x_setup_qtable(gspca_dev,
819 0x00, 0x8800, 0x8840, qtable_pocketdv);
820 if (err < 0)
821 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300822 reg_w(gspca_dev, 0x00, 0x8880, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300823
824 /* familycam Quicksmart pocketDV stuff */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300825 reg_w(gspca_dev, 0x00, 0x800a, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300826 /* Set agc transfer: synced inbetween frames */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300827 reg_w(gspca_dev, 0x00, 0x820f, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828 /* Init SDRAM - needed for SDRAM access */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300829 reg_w(gspca_dev, 0x00, 0x870a, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300831 spca500_setmode(gspca_dev, xmult, ymult);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300832 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300833 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300834
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300835 reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300837 reg_r(gspca_dev, 0x816b, 1);
838 Data = gspca_dev->usb_buf[0];
839 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 break;
841 case LogitechTraveler:
842 case LogitechClickSmart510:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300843 reg_w(gspca_dev, 0x02, 0x00, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844 /* enable drop packet */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300845 reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846
847 err = spca50x_setup_qtable(gspca_dev,
848 0x00, 0x8800,
849 0x8840, qtable_creative_pccam);
850 if (err < 0)
851 PDEBUG(D_ERR, "spca50x_setup_qtable failed");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300852 reg_w(gspca_dev, 0x00, 0x8880, 3);
853 reg_w(gspca_dev, 0x00, 0x800a, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 /* Init SDRAM - needed for SDRAM access */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300855 reg_w(gspca_dev, 0x00, 0x870a, 0x04);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856
857 spca500_setmode(gspca_dev, xmult, ymult);
858
859 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300860 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
861 reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300863 reg_r(gspca_dev, 0x816b, 1);
864 Data = gspca_dev->usb_buf[0];
865 reg_w(gspca_dev, 0x00, 0x816b, Data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300866 write_vector(gspca_dev, Clicksmart510_defaults);
867 break;
868 }
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300869 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870}
871
872static void sd_stopN(struct gspca_dev *gspca_dev)
873{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300874 reg_w(gspca_dev, 0, 0x8003, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875
876 /* switch to video camera mode */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300877 reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
878 reg_r(gspca_dev, 0x8000, 1);
879 PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x",
880 gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881}
882
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300883static void sd_pkt_scan(struct gspca_dev *gspca_dev,
884 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300885 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 int len) /* iso packet length */
887{
888 struct sd *sd = (struct sd *) gspca_dev;
889 int i;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300890 __u8 *s, *d;
891 static __u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300892
893/* frames are jpeg 4.1.1 without 0xff escape */
894 if (data[0] == 0xff) {
895 if (data[1] != 0x01) { /* drop packet */
896/* gspca_dev->last_packet_type = DISCARD_PACKET; */
897 return;
898 }
899 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
900 ffd9, 2);
901
902 /* put the JPEG header in the new frame */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300903 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904
905 data += SPCA500_OFFSET_DATA;
906 len -= SPCA500_OFFSET_DATA;
907 } else {
908 data += 1;
909 len -= 1;
910 }
911
912 /* add 0x00 after 0xff */
913 for (i = len; --i >= 0; )
914 if (data[i] == 0xff)
915 break;
916 if (i < 0) { /* no 0xff */
917 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
918 return;
919 }
920 s = data;
921 d = sd->packet;
922 for (i = 0; i < len; i++) {
923 *d++ = *s++;
924 if (s[-1] == 0xff)
925 *d++ = 0x00;
926 }
927 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
928 sd->packet, d - sd->packet);
929}
930
931static void setbrightness(struct gspca_dev *gspca_dev)
932{
933 struct sd *sd = (struct sd *) gspca_dev;
934
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300935 reg_w(gspca_dev, 0x00, 0x8167,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936 (__u8) (sd->brightness - 128));
937}
938
939static void getbrightness(struct gspca_dev *gspca_dev)
940{
941 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300942 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300943
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300944 ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300945 if (ret >= 0)
946 sd->brightness = ret + 128;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947}
948
949static void setcontrast(struct gspca_dev *gspca_dev)
950{
951 struct sd *sd = (struct sd *) gspca_dev;
952
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300953 reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300954}
955
956static void getcontrast(struct gspca_dev *gspca_dev)
957{
958 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300959 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300960
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300961 ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300962 if (ret >= 0)
963 sd->contrast = ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300964}
965
966static void setcolors(struct gspca_dev *gspca_dev)
967{
968 struct sd *sd = (struct sd *) gspca_dev;
969
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300970 reg_w(gspca_dev, 0x00, 0x8169, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971}
972
973static void getcolors(struct gspca_dev *gspca_dev)
974{
975 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300976 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300978 ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300979 if (ret >= 0)
980 sd->colors = ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300981}
982
983static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
984{
985 struct sd *sd = (struct sd *) gspca_dev;
986
987 sd->brightness = val;
988 if (gspca_dev->streaming)
989 setbrightness(gspca_dev);
990 return 0;
991}
992
993static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
994{
995 struct sd *sd = (struct sd *) gspca_dev;
996
997 getbrightness(gspca_dev);
998 *val = sd->brightness;
999 return 0;
1000}
1001
1002static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1003{
1004 struct sd *sd = (struct sd *) gspca_dev;
1005
1006 sd->contrast = val;
1007 if (gspca_dev->streaming)
1008 setcontrast(gspca_dev);
1009 return 0;
1010}
1011
1012static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1013{
1014 struct sd *sd = (struct sd *) gspca_dev;
1015
1016 getcontrast(gspca_dev);
1017 *val = sd->contrast;
1018 return 0;
1019}
1020
1021static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1022{
1023 struct sd *sd = (struct sd *) gspca_dev;
1024
1025 sd->colors = val;
1026 if (gspca_dev->streaming)
1027 setcolors(gspca_dev);
1028 return 0;
1029}
1030
1031static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1032{
1033 struct sd *sd = (struct sd *) gspca_dev;
1034
1035 getcolors(gspca_dev);
1036 *val = sd->colors;
1037 return 0;
1038}
1039
1040/* sub-driver description */
1041static struct sd_desc sd_desc = {
1042 .name = MODULE_NAME,
1043 .ctrls = sd_ctrls,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001044 .nctrls = ARRAY_SIZE(sd_ctrls),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001045 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001046 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047 .start = sd_start,
1048 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001049 .pkt_scan = sd_pkt_scan,
1050};
1051
1052/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001053static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001054 {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
1055 {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
1056 {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
1057 {USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310},
1058 {USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510},
1059 {USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016},
1060 {USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85},
1061 {USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300},
1062 {USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini},
1063 {USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20},
1064 {USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia},
1065 {USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350},
1066 {USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV},
1067 {USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus},
1068 {USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 {}
1070};
1071MODULE_DEVICE_TABLE(usb, device_table);
1072
1073/* -- device connect -- */
1074static int sd_probe(struct usb_interface *intf,
1075 const struct usb_device_id *id)
1076{
1077 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1078 THIS_MODULE);
1079}
1080
1081static struct usb_driver sd_driver = {
1082 .name = MODULE_NAME,
1083 .id_table = device_table,
1084 .probe = sd_probe,
1085 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001086#ifdef CONFIG_PM
1087 .suspend = gspca_suspend,
1088 .resume = gspca_resume,
1089#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001090};
1091
1092/* -- module insert / remove -- */
1093static int __init sd_mod_init(void)
1094{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001095 int ret;
1096 ret = usb_register(&sd_driver);
1097 if (ret < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001098 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001099 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001100 return 0;
1101}
1102static void __exit sd_mod_exit(void)
1103{
1104 usb_deregister(&sd_driver);
1105 PDEBUG(D_PROBE, "deregistered");
1106}
1107
1108module_init(sd_mod_init);
1109module_exit(sd_mod_exit);