blob: c8909772435ac8252bd5e6633c888259c53133b7 [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
Joe Perches133a9fe2011-08-21 19:56:57 -030022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030024#define MODULE_NAME "sunplus"
25
26#include "gspca.h"
27#include "jpeg.h"
28
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
30MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
31MODULE_LICENSE("GPL");
32
33/* specific webcam descriptor */
34struct sd {
35 struct gspca_dev gspca_dev; /* !! must be the first item */
36
Jean-Francois Moine760f2712009-09-02 06:04:14 -030037 s8 brightness;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030038 u8 contrast;
39 u8 colors;
40 u8 autogain;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030041 u8 quality;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -030042#define QUALITY_MIN 70
43#define QUALITY_MAX 95
44#define QUALITY_DEF 85
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030046 u8 bridge;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047#define BRIDGE_SPCA504 0
48#define BRIDGE_SPCA504B 1
49#define BRIDGE_SPCA504C 2
50#define BRIDGE_SPCA533 3
51#define BRIDGE_SPCA536 4
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030052 u8 subtype;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053#define AiptekMiniPenCam13 1
54#define LogitechClickSmart420 2
55#define LogitechClickSmart820 3
56#define MegapixV4 4
Johannes Goerneraf5f88c2009-07-09 03:28:46 -030057#define MegaImageVI 5
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030058
Jean-François Moine9a731a32010-06-04 05:26:42 -030059 u8 jpeg_hdr[JPEG_HDR_SZ];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060};
61
62/* V4L2 controls supported by the driver */
63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
71
Marton Nemeth7e64dc42009-12-30 09:12:41 -030072static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030073 {
74 {
75 .id = V4L2_CID_BRIGHTNESS,
76 .type = V4L2_CTRL_TYPE_INTEGER,
77 .name = "Brightness",
Jean-Francois Moine760f2712009-09-02 06:04:14 -030078 .minimum = -128,
79 .maximum = 127,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030081#define BRIGHTNESS_DEF 0
82 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030083 },
84 .set = sd_setbrightness,
85 .get = sd_getbrightness,
86 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087 {
88 {
89 .id = V4L2_CID_CONTRAST,
90 .type = V4L2_CTRL_TYPE_INTEGER,
91 .name = "Contrast",
92 .minimum = 0,
93 .maximum = 0xff,
94 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030095#define CONTRAST_DEF 0x20
96 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 },
98 .set = sd_setcontrast,
99 .get = sd_getcontrast,
100 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 {
102 {
103 .id = V4L2_CID_SATURATION,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "Color",
106 .minimum = 0,
107 .maximum = 0xff,
108 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300109#define COLOR_DEF 0x1a
110 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 },
112 .set = sd_setcolors,
113 .get = sd_getcolors,
114 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 {
116 {
117 .id = V4L2_CID_AUTOGAIN,
118 .type = V4L2_CTRL_TYPE_BOOLEAN,
119 .name = "Auto Gain",
120 .minimum = 0,
121 .maximum = 1,
122 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300123#define AUTOGAIN_DEF 1
124 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125 },
126 .set = sd_setautogain,
127 .get = sd_getautogain,
128 },
129};
130
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300131static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300132 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133 .bytesperline = 320,
134 .sizeimage = 320 * 240 * 3 / 8 + 590,
135 .colorspace = V4L2_COLORSPACE_JPEG,
136 .priv = 2},
137 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
138 .bytesperline = 640,
139 .sizeimage = 640 * 480 * 3 / 8 + 590,
140 .colorspace = V4L2_COLORSPACE_JPEG,
141 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142};
143
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300144static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300145 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
146 .bytesperline = 320,
147 .sizeimage = 320 * 240 * 3 / 8 + 590,
148 .colorspace = V4L2_COLORSPACE_JPEG,
149 .priv = 2},
150 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
151 .bytesperline = 464,
152 .sizeimage = 464 * 480 * 3 / 8 + 590,
153 .colorspace = V4L2_COLORSPACE_JPEG,
154 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155};
156
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300157static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300158 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
159 .bytesperline = 176,
160 .sizeimage = 176 * 144 * 3 / 8 + 590,
161 .colorspace = V4L2_COLORSPACE_JPEG,
162 .priv = 4},
163 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
164 .bytesperline = 320,
165 .sizeimage = 320 * 240 * 3 / 8 + 590,
166 .colorspace = V4L2_COLORSPACE_JPEG,
167 .priv = 3},
168 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
169 .bytesperline = 352,
170 .sizeimage = 352 * 288 * 3 / 8 + 590,
171 .colorspace = V4L2_COLORSPACE_JPEG,
172 .priv = 2},
173 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
174 .bytesperline = 640,
175 .sizeimage = 640 * 480 * 3 / 8 + 590,
176 .colorspace = V4L2_COLORSPACE_JPEG,
177 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300178};
179
180#define SPCA50X_OFFSET_DATA 10
181#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
182#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
183#define SPCA504_PCCAM600_OFFSET_MODE 5
184#define SPCA504_PCCAM600_OFFSET_DATA 14
185 /* Frame packet header offsets for the spca533 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300186#define SPCA533_OFFSET_DATA 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300187#define SPCA533_OFFSET_FRAMSEQ 15
188/* Frame packet header offsets for the spca536 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300189#define SPCA536_OFFSET_DATA 4
190#define SPCA536_OFFSET_FRAMSEQ 1
191
192struct cmd {
193 u8 req;
194 u16 val;
195 u16 idx;
196};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197
198/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300199static const struct cmd spca504_pccam600_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200/* {0xa0, 0x0000, 0x0503}, * capture mode */
201 {0x00, 0x0000, 0x2000},
202 {0x00, 0x0013, 0x2301},
203 {0x00, 0x0003, 0x2000},
204 {0x00, 0x0001, 0x21ac},
205 {0x00, 0x0001, 0x21a6},
206 {0x00, 0x0000, 0x21a7}, /* brightness */
207 {0x00, 0x0020, 0x21a8}, /* contrast */
208 {0x00, 0x0001, 0x21ac}, /* sat/hue */
209 {0x00, 0x0000, 0x21ad}, /* hue */
210 {0x00, 0x001a, 0x21ae}, /* saturation */
211 {0x00, 0x0002, 0x21a3}, /* gamma */
212 {0x30, 0x0154, 0x0008},
213 {0x30, 0x0004, 0x0006},
214 {0x30, 0x0258, 0x0009},
215 {0x30, 0x0004, 0x0000},
216 {0x30, 0x0093, 0x0004},
217 {0x30, 0x0066, 0x0005},
218 {0x00, 0x0000, 0x2000},
219 {0x00, 0x0013, 0x2301},
220 {0x00, 0x0003, 0x2000},
221 {0x00, 0x0013, 0x2301},
222 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300223};
224
225/* Creative PC-CAM 600 specific open data, sent before using the
226 * generic initialisation data from spca504_open_data.
227 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300228static const struct cmd spca504_pccam600_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229 {0x00, 0x0001, 0x2501},
230 {0x20, 0x0500, 0x0001}, /* snapshot mode */
231 {0x00, 0x0003, 0x2880},
232 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233};
234
235/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300236static const struct cmd spca504A_clicksmart420_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237/* {0xa0, 0x0000, 0x0503}, * capture mode */
238 {0x00, 0x0000, 0x2000},
239 {0x00, 0x0013, 0x2301},
240 {0x00, 0x0003, 0x2000},
241 {0x00, 0x0001, 0x21ac},
242 {0x00, 0x0001, 0x21a6},
243 {0x00, 0x0000, 0x21a7}, /* brightness */
244 {0x00, 0x0020, 0x21a8}, /* contrast */
245 {0x00, 0x0001, 0x21ac}, /* sat/hue */
246 {0x00, 0x0000, 0x21ad}, /* hue */
247 {0x00, 0x001a, 0x21ae}, /* saturation */
248 {0x00, 0x0002, 0x21a3}, /* gamma */
249 {0x30, 0x0004, 0x000a},
250 {0xb0, 0x0001, 0x0000},
251
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300252 {0xa1, 0x0080, 0x0001},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300253 {0x30, 0x0049, 0x0000},
254 {0x30, 0x0060, 0x0005},
255 {0x0c, 0x0004, 0x0000},
256 {0x00, 0x0000, 0x0000},
257 {0x00, 0x0000, 0x2000},
258 {0x00, 0x0013, 0x2301},
259 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300260};
261
262/* clicksmart 420 open data ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300263static const struct cmd spca504A_clicksmart420_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264 {0x00, 0x0001, 0x2501},
265 {0x20, 0x0502, 0x0000},
266 {0x06, 0x0000, 0x0000},
267 {0x00, 0x0004, 0x2880},
268 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269
270 {0xa0, 0x0000, 0x0503},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300271};
272
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300273static const u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274 { /* Q-table Y-components */
275 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
276 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
277 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
278 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
279 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
280 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
281 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
282 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
283 { /* Q-table C-components */
284 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
285 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
286 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
287 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
288 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
289 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
290 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
291 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
292};
293
294/* FIXME: This Q-table is identical to the Creative PC-CAM one,
295 * except for one byte. Possibly a typo?
296 * NWG: 18/05/2003.
297 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300298static const u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300299 { /* Q-table Y-components */
300 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
301 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
302 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
303 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
304 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
305 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
306 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
307 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
308 },
309 { /* Q-table C-components */
310 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
311 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
312 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
313 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
314 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
315 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
316 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
317 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
318};
319
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300320/* read <len> bytes to gspca_dev->usb_buf */
321static void reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300322 u8 req,
323 u16 index,
324 u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300325{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300326 int ret;
327
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300328#ifdef GSPCA_DEBUG
329 if (len > USB_BUF_SZ) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300330 pr_err("reg_r: buffer overflow\n");
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300331 return;
332 }
333#endif
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300334 if (gspca_dev->usb_err < 0)
335 return;
336 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300337 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300338 req,
339 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
340 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300341 index,
342 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300343 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300344 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300345 pr_err("reg_r err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300346 gspca_dev->usb_err = ret;
347 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300348}
349
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300350/* write one byte */
351static void reg_w_1(struct gspca_dev *gspca_dev,
352 u8 req,
353 u16 value,
354 u16 index,
355 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300356{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300357 int ret;
358
359 if (gspca_dev->usb_err < 0)
360 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300361 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300362 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300363 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300364 req,
365 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300366 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300367 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300368 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300369 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300370 pr_err("reg_w_1 err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300371 gspca_dev->usb_err = ret;
372 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300373}
374
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300375/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300376static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300377 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300378{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300379 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300380 int ret;
381
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300382 if (gspca_dev->usb_err < 0)
383 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300384 ret = usb_control_msg(dev,
385 usb_sndctrlpipe(dev, 0),
386 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300387 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300388 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300389 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300390 pr_err("reg_w_riv err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300391 gspca_dev->usb_err = ret;
392 return;
393 }
394 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
395 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300396}
397
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300398static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300399 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300401 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300402 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300403 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405}
406
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300407static void setup_qtable(struct gspca_dev *gspca_dev,
408 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300410 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411
412 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300413 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300414 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415
416 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300417 for (i = 0; i < 64; i++)
418 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419}
420
421static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300422 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300424 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300425 reg_r(gspca_dev, 0x01, 0x0001, 1);
426 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300427 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300429 msleep(200);
Jean-François Moinecf252202011-05-17 05:32:39 -0300430 reg_r(gspca_dev, 0x01, 0x0001, 1);
431 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300432}
433
Jean-François Moinecf252202011-05-17 05:32:39 -0300434#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300435static void spca504_read_info(struct gspca_dev *gspca_dev)
436{
437 int i;
438 u8 info[6];
439
Jean-François Moinecf252202011-05-17 05:32:39 -0300440 for (i = 0; i < 6; i++) {
441 reg_r(gspca_dev, 0, i, 1);
442 info[i] = gspca_dev->usb_buf[0];
443 }
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300444 PDEBUG(D_STREAM,
445 "Read info: %d %d %d %d %d %d."
446 " Should be 1,0,2,2,0,0",
447 info[0], info[1], info[2],
448 info[3], info[4], info[5]);
449}
Jean-François Moinecf252202011-05-17 05:32:39 -0300450#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300451
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300452static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300453 u8 req,
Jean-François Moinecf252202011-05-17 05:32:39 -0300454 u16 idx, u16 val, u8 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300456 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300458 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300459 reg_r(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300460 if (gspca_dev->usb_err < 0)
461 return;
Jean-François Moinecf252202011-05-17 05:32:39 -0300462 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
463 gspca_dev->usb_buf[0], endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 if (!count)
465 return;
466 count = 200;
467 while (--count > 0) {
468 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200469 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300470/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-François Moinecf252202011-05-17 05:32:39 -0300471 reg_r(gspca_dev, 0x01, 0x0001, 1);
472 status = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300474 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 status, 200 - count);
476 break;
477 }
478 }
479}
480
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300481static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483 int count = 10;
484
485 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300486 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300487 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488 break;
489 msleep(10);
490 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491}
492
493static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
494{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 int count = 50;
496
497 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300498 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300499 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300500 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300501 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 break;
504 }
505 msleep(10);
506 }
507}
508
Jean-François Moinecf252202011-05-17 05:32:39 -0300509#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
511{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300512 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300514 data = gspca_dev->usb_buf;
515 reg_r(gspca_dev, 0x20, 0, 5);
Jean-François Moinecf252202011-05-17 05:32:39 -0300516 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300517 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300518 reg_r(gspca_dev, 0x23, 0, 64);
519 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300520}
Jean-François Moinecf252202011-05-17 05:32:39 -0300521#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522
523static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
524{
525 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300526 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300528 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 switch (sd->bridge) {
530 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300531 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300533 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300534#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300536#endif
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300537 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300538 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300540 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300541 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300542 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543
544 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300545 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300547 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300548 break;
549 default:
550/* case BRIDGE_SPCA504B: */
551/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300552 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300553 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300554 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300555 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300556 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557 break;
558 case BRIDGE_SPCA504:
559 Size += 3;
560 if (sd->subtype == AiptekMiniPenCam13) {
561 /* spca504a aiptek */
562 spca504A_acknowledged_command(gspca_dev,
563 0x08, Size, 0,
564 0x80 | (Size & 0x0f), 1);
565 spca504A_acknowledged_command(gspca_dev,
566 1, 3, 0, 0x9f, 0);
567 } else {
568 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
569 }
570 break;
571 case BRIDGE_SPCA504C:
572 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300573 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
574 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300575 break;
576 }
577}
578
579static void spca504_wait_status(struct gspca_dev *gspca_dev)
580{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 int cnt;
582
583 cnt = 256;
584 while (--cnt > 0) {
585 /* With this we get the status, when return 0 it's all ok */
Jean-François Moinecf252202011-05-17 05:32:39 -0300586 reg_r(gspca_dev, 0x06, 0x00, 1);
587 if (gspca_dev->usb_buf[0] == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588 return;
589 msleep(10);
590 }
591}
592
593static void spca504B_setQtable(struct gspca_dev *gspca_dev)
594{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300595 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300596 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300597 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300598}
599
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300600static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300601{
602 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300603 u16 reg;
604
605 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300606 reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300607}
608
609static void setcontrast(struct gspca_dev *gspca_dev)
610{
611 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300612 u16 reg;
613
614 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300615 reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300616}
617
618static void setcolors(struct gspca_dev *gspca_dev)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300621 u16 reg;
622
623 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300624 reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300625}
626
627static void init_ctl_reg(struct gspca_dev *gspca_dev)
628{
629 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630 int pollreg = 1;
631
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300632 setbrightness(gspca_dev);
633 setcontrast(gspca_dev);
634 setcolors(gspca_dev);
635
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636 switch (sd->bridge) {
637 case BRIDGE_SPCA504:
638 case BRIDGE_SPCA504C:
639 pollreg = 0;
640 /* fall thru */
641 default:
642/* case BRIDGE_SPCA533: */
643/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300644 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
645 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
646 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647 break;
648 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300649 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
650 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
651 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652 break;
653 }
654 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300655 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656}
657
658/* this function is called at probe time */
659static int sd_config(struct gspca_dev *gspca_dev,
660 const struct usb_device_id *id)
661{
662 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300663 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664
665 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300667 sd->bridge = id->driver_info >> 8;
668 sd->subtype = id->driver_info;
669
670 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300671
672 /* try to get the firmware as some cam answer 2.0.1.2.2
673 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300674 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300675 switch (gspca_dev->usb_buf[0]) {
676 case 1:
677 break; /* (right bridge/subtype) */
678 case 2:
679 sd->bridge = BRIDGE_SPCA504B;
680 sd->subtype = 0;
681 break;
682 default:
683 return -ENODEV;
684 }
685 }
686
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687 switch (sd->bridge) {
688 default:
689/* case BRIDGE_SPCA504B: */
690/* case BRIDGE_SPCA504: */
691/* case BRIDGE_SPCA536: */
692 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300693 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300694 break;
695 case BRIDGE_SPCA533:
696 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300697 if (sd->subtype == MegaImageVI) /* 320x240 only */
698 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
699 else
700 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701 break;
702 case BRIDGE_SPCA504C:
703 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300704 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705 break;
706 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300707 sd->brightness = BRIGHTNESS_DEF;
708 sd->contrast = CONTRAST_DEF;
709 sd->colors = COLOR_DEF;
710 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300711 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712 return 0;
713}
714
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300715/* this function is called at probe and resume time */
716static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717{
718 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719
720 switch (sd->bridge) {
721 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300722 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300723 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
724 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
725 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
726 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
727 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728 /* fall thru */
729 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300730 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300731#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300733#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300734 break;
735 case BRIDGE_SPCA536:
Jean-François Moinecf252202011-05-17 05:32:39 -0300736#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300737 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300738#endif
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300739 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300740 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300741 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300742 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300743 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300744 spca504B_WaitCmdStatus(gspca_dev);
745 break;
746 case BRIDGE_SPCA504C: /* pccam600 */
747 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300748 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
749 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300750 spca504_wait_status(gspca_dev);
751 if (sd->subtype == LogitechClickSmart420)
752 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300753 spca504A_clicksmart420_open_data,
754 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300755 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300756 write_vector(gspca_dev, spca504_pccam600_open_data,
757 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300758 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300759 break;
760 default:
761/* case BRIDGE_SPCA504: */
762 PDEBUG(D_STREAM, "Opening SPCA504");
763 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300764#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300765 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300766#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300767
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300768 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
769 spca504A_acknowledged_command(gspca_dev, 0x24,
770 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200771 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772 spca504A_acknowledged_command(gspca_dev, 0x24,
773 8, 3, 0x9e, 0);
774
775 spca504A_acknowledged_command(gspca_dev, 0x24,
776 0, 0, 0x9d, 1);
777 /******************************/
778 /* spca504a aiptek */
779 spca504A_acknowledged_command(gspca_dev, 0x08,
780 6, 0, 0x86, 1);
781/* reg_write (dev, 0, 0x2000, 0); */
782/* reg_write (dev, 0, 0x2883, 1); */
783/* spca504A_acknowledged_command (gspca_dev, 0x08,
784 6, 0, 0x86, 1); */
785/* spca504A_acknowledged_command (gspca_dev, 0x24,
786 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300787 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
788 /* L92 sno1t.txt */
789 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300790 spca504A_acknowledged_command(gspca_dev, 0x01,
791 0x0f, 0, 0xff, 0);
792 }
793 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300794 reg_w_riv(gspca_dev, 0, 0x2000, 0);
795 reg_w_riv(gspca_dev, 0, 0x2883, 1);
796 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797 break;
798 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300799 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300800}
801
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300802static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803{
804 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300805 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300807 /* create the JPEG header */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300808 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
809 0x22); /* JPEG 411 */
810 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
811
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300812 if (sd->bridge == BRIDGE_SPCA504B)
813 spca504B_setQtable(gspca_dev);
814 spca504B_SetSizeType(gspca_dev);
815 switch (sd->bridge) {
816 default:
817/* case BRIDGE_SPCA504B: */
818/* case BRIDGE_SPCA533: */
819/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300820 switch (sd->subtype) {
821 case MegapixV4:
822 case LogitechClickSmart820:
823 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300824 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300825 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300826 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300828 break;
829 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300830 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300832 spca504B_PollingDataReady(gspca_dev);
833 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300834 }
835 break;
836 case BRIDGE_SPCA504:
837 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300838#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300839 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300840#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300841
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300842 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
843 spca504A_acknowledged_command(gspca_dev, 0x24,
844 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200845 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846 spca504A_acknowledged_command(gspca_dev, 0x24,
847 8, 3, 0x9e, 0);
848 spca504A_acknowledged_command(gspca_dev, 0x24,
849 0, 0, 0x9d, 1);
850 } else {
851 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-François Moinecf252202011-05-17 05:32:39 -0300852#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300853 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300854#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
856 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
857 }
858 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300859 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
860 /* L92 sno1t.txt */
861 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862 break;
863 case BRIDGE_SPCA504C:
864 if (sd->subtype == LogitechClickSmart420) {
865 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300866 spca504A_clicksmart420_init_data,
867 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300868 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300869 write_vector(gspca_dev, spca504_pccam600_init_data,
870 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300872 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300873 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
874 /* auto exposure */
875 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
876 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300877
878 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300879 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
880 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881 spca504B_SetSizeType(gspca_dev);
882 break;
883 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300884 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300885 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886}
887
888static void sd_stopN(struct gspca_dev *gspca_dev)
889{
890 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300891
892 switch (sd->bridge) {
893 default:
894/* case BRIDGE_SPCA533: */
895/* case BRIDGE_SPCA536: */
896/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300897 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300899 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300900 break;
901 case BRIDGE_SPCA504:
902 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300903 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904
905 if (sd->subtype == AiptekMiniPenCam13) {
906 /* spca504a aiptek */
907/* spca504A_acknowledged_command(gspca_dev, 0x08,
908 6, 0, 0x86, 1); */
909 spca504A_acknowledged_command(gspca_dev, 0x24,
910 0x00, 0x00, 0x9d, 1);
911 spca504A_acknowledged_command(gspca_dev, 0x01,
912 0x0f, 0x00, 0xff, 1);
913 } else {
914 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300915 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300916 }
917 break;
918 }
919}
920
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300921static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300922 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300923 int len) /* iso packet length */
924{
925 struct sd *sd = (struct sd *) gspca_dev;
926 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300927 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300928
929/* frames are jpeg 4.1.1 without 0xff escape */
930 switch (sd->bridge) {
931 case BRIDGE_SPCA533:
932 if (data[0] == 0xff) {
933 if (data[1] != 0x01) { /* drop packet */
934/* gspca_dev->last_packet_type = DISCARD_PACKET; */
935 return;
936 }
937 sof = 1;
938 data += SPCA533_OFFSET_DATA;
939 len -= SPCA533_OFFSET_DATA;
940 } else {
941 data += 1;
942 len -= 1;
943 }
944 break;
945 case BRIDGE_SPCA536:
946 if (data[0] == 0xff) {
947 sof = 1;
948 data += SPCA536_OFFSET_DATA;
949 len -= SPCA536_OFFSET_DATA;
950 } else {
951 data += 2;
952 len -= 2;
953 }
954 break;
955 default:
956/* case BRIDGE_SPCA504: */
957/* case BRIDGE_SPCA504B: */
958 switch (data[0]) {
959 case 0xfe: /* start of frame */
960 sof = 1;
961 data += SPCA50X_OFFSET_DATA;
962 len -= SPCA50X_OFFSET_DATA;
963 break;
964 case 0xff: /* drop packet */
965/* gspca_dev->last_packet_type = DISCARD_PACKET; */
966 return;
967 default:
968 data += 1;
969 len -= 1;
970 break;
971 }
972 break;
973 case BRIDGE_SPCA504C:
974 switch (data[0]) {
975 case 0xfe: /* start of frame */
976 sof = 1;
977 data += SPCA504_PCCAM600_OFFSET_DATA;
978 len -= SPCA504_PCCAM600_OFFSET_DATA;
979 break;
980 case 0xff: /* drop packet */
981/* gspca_dev->last_packet_type = DISCARD_PACKET; */
982 return;
983 default:
984 data += 1;
985 len -= 1;
986 break;
987 }
988 break;
989 }
990 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300991 gspca_frame_add(gspca_dev, LAST_PACKET,
992 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993
994 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300995 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300996 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300997 }
998
999 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001000 i = 0;
1001 do {
1002 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001003 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001004 data, i + 1);
1005 len -= i;
1006 data += i;
1007 *data = 0x00;
1008 i = 0;
1009 }
1010 i++;
1011 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001012 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013}
1014
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1016{
1017 struct sd *sd = (struct sd *) gspca_dev;
1018
1019 sd->brightness = val;
1020 if (gspca_dev->streaming)
1021 setbrightness(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001022 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001023}
1024
1025static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1026{
1027 struct sd *sd = (struct sd *) gspca_dev;
1028
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001029 *val = sd->brightness;
1030 return 0;
1031}
1032
1033static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1034{
1035 struct sd *sd = (struct sd *) gspca_dev;
1036
1037 sd->contrast = val;
1038 if (gspca_dev->streaming)
1039 setcontrast(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001040 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041}
1042
1043static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1044{
1045 struct sd *sd = (struct sd *) gspca_dev;
1046
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047 *val = sd->contrast;
1048 return 0;
1049}
1050
1051static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1052{
1053 struct sd *sd = (struct sd *) gspca_dev;
1054
1055 sd->colors = val;
1056 if (gspca_dev->streaming)
1057 setcolors(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001058 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001059}
1060
1061static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1062{
1063 struct sd *sd = (struct sd *) gspca_dev;
1064
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001065 *val = sd->colors;
1066 return 0;
1067}
1068
1069static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1070{
1071 struct sd *sd = (struct sd *) gspca_dev;
1072
1073 sd->autogain = val;
1074 return 0;
1075}
1076
1077static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1078{
1079 struct sd *sd = (struct sd *) gspca_dev;
1080
1081 *val = sd->autogain;
1082 return 0;
1083}
1084
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001085static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1086 struct v4l2_jpegcompression *jcomp)
1087{
1088 struct sd *sd = (struct sd *) gspca_dev;
1089
1090 if (jcomp->quality < QUALITY_MIN)
1091 sd->quality = QUALITY_MIN;
1092 else if (jcomp->quality > QUALITY_MAX)
1093 sd->quality = QUALITY_MAX;
1094 else
1095 sd->quality = jcomp->quality;
1096 if (gspca_dev->streaming)
1097 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001098 return gspca_dev->usb_err;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001099}
1100
1101static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1102 struct v4l2_jpegcompression *jcomp)
1103{
1104 struct sd *sd = (struct sd *) gspca_dev;
1105
1106 memset(jcomp, 0, sizeof *jcomp);
1107 jcomp->quality = sd->quality;
1108 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1109 | V4L2_JPEG_MARKER_DQT;
1110 return 0;
1111}
1112
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001113/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001114static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001115 .name = MODULE_NAME,
1116 .ctrls = sd_ctrls,
1117 .nctrls = ARRAY_SIZE(sd_ctrls),
1118 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001119 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001120 .start = sd_start,
1121 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001122 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001123 .get_jcomp = sd_get_jcomp,
1124 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001125};
1126
1127/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001128#define BS(bridge, subtype) \
1129 .driver_info = (BRIDGE_ ## bridge << 8) \
1130 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -03001131static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001132 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1133 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1134 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1135 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1136 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1137 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1138 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1139 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1140 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1141 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1142 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1143 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1144 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1145 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1146 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1147 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1148 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1149 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001150 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001151 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001152 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001153 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1154 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1155 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1156 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1157 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1158 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1159 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1160 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1161 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1162 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1163 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1164 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1165 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1166 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1167 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1168 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1169 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1170 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1171 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1172 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1173 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1174 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1175 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1176 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1177 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1178 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1179 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1180 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1181 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1182 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1183 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1184 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1185 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1186 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1187 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1188 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1189 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1190 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001191 {}
1192};
1193MODULE_DEVICE_TABLE(usb, device_table);
1194
1195/* -- device connect -- */
1196static int sd_probe(struct usb_interface *intf,
1197 const struct usb_device_id *id)
1198{
1199 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1200 THIS_MODULE);
1201}
1202
1203static struct usb_driver sd_driver = {
1204 .name = MODULE_NAME,
1205 .id_table = device_table,
1206 .probe = sd_probe,
1207 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001208#ifdef CONFIG_PM
1209 .suspend = gspca_suspend,
1210 .resume = gspca_resume,
1211#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001212};
1213
1214/* -- module insert / remove -- */
1215static int __init sd_mod_init(void)
1216{
Jean-François Moine54826432010-09-13 04:53:03 -03001217 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001218}
1219static void __exit sd_mod_exit(void)
1220{
1221 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001222}
1223
1224module_init(sd_mod_init);
1225module_exit(sd_mod_exit);