blob: b089c0d3ee9f96dc7b2de6f770105efe35db1503 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Sunplus spca504(abc) spca533 spca536 library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#define MODULE_NAME "sunplus"
23
24#include "gspca.h"
25#include "jpeg.h"
26
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Jean-Francois Moine760f2712009-09-02 06:04:14 -030035 s8 brightness;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030036 u8 contrast;
37 u8 colors;
38 u8 autogain;
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030039 u8 quality;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -030040#define QUALITY_MIN 70
41#define QUALITY_MAX 95
42#define QUALITY_DEF 85
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030043
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030044 u8 bridge;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045#define BRIDGE_SPCA504 0
46#define BRIDGE_SPCA504B 1
47#define BRIDGE_SPCA504C 2
48#define BRIDGE_SPCA533 3
49#define BRIDGE_SPCA536 4
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030050 u8 subtype;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#define AiptekMiniPenCam13 1
52#define LogitechClickSmart420 2
53#define LogitechClickSmart820 3
54#define MegapixV4 4
Johannes Goerneraf5f88c2009-07-09 03:28:46 -030055#define MegaImageVI 5
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030056
Jean-François Moine9a731a32010-06-04 05:26:42 -030057 u8 jpeg_hdr[JPEG_HDR_SZ];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030058};
59
60/* V4L2 controls supported by the driver */
61static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
63static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
69
Marton Nemeth7e64dc42009-12-30 09:12:41 -030070static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 {
72 {
73 .id = V4L2_CID_BRIGHTNESS,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Brightness",
Jean-Francois Moine760f2712009-09-02 06:04:14 -030076 .minimum = -128,
77 .maximum = 127,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030079#define BRIGHTNESS_DEF 0
80 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081 },
82 .set = sd_setbrightness,
83 .get = sd_getbrightness,
84 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085 {
86 {
87 .id = V4L2_CID_CONTRAST,
88 .type = V4L2_CTRL_TYPE_INTEGER,
89 .name = "Contrast",
90 .minimum = 0,
91 .maximum = 0xff,
92 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030093#define CONTRAST_DEF 0x20
94 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030095 },
96 .set = sd_setcontrast,
97 .get = sd_getcontrast,
98 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 {
100 {
101 .id = V4L2_CID_SATURATION,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Color",
104 .minimum = 0,
105 .maximum = 0xff,
106 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300107#define COLOR_DEF 0x1a
108 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 },
110 .set = sd_setcolors,
111 .get = sd_getcolors,
112 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 {
114 {
115 .id = V4L2_CID_AUTOGAIN,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Auto Gain",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300121#define AUTOGAIN_DEF 1
122 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123 },
124 .set = sd_setautogain,
125 .get = sd_getautogain,
126 },
127};
128
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300129static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300130 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .bytesperline = 320,
132 .sizeimage = 320 * 240 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
134 .priv = 2},
135 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
136 .bytesperline = 640,
137 .sizeimage = 640 * 480 * 3 / 8 + 590,
138 .colorspace = V4L2_COLORSPACE_JPEG,
139 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300140};
141
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300142static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300143 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
144 .bytesperline = 320,
145 .sizeimage = 320 * 240 * 3 / 8 + 590,
146 .colorspace = V4L2_COLORSPACE_JPEG,
147 .priv = 2},
148 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
149 .bytesperline = 464,
150 .sizeimage = 464 * 480 * 3 / 8 + 590,
151 .colorspace = V4L2_COLORSPACE_JPEG,
152 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300153};
154
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300155static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300156 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
157 .bytesperline = 176,
158 .sizeimage = 176 * 144 * 3 / 8 + 590,
159 .colorspace = V4L2_COLORSPACE_JPEG,
160 .priv = 4},
161 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
162 .bytesperline = 320,
163 .sizeimage = 320 * 240 * 3 / 8 + 590,
164 .colorspace = V4L2_COLORSPACE_JPEG,
165 .priv = 3},
166 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
167 .bytesperline = 352,
168 .sizeimage = 352 * 288 * 3 / 8 + 590,
169 .colorspace = V4L2_COLORSPACE_JPEG,
170 .priv = 2},
171 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
172 .bytesperline = 640,
173 .sizeimage = 640 * 480 * 3 / 8 + 590,
174 .colorspace = V4L2_COLORSPACE_JPEG,
175 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300176};
177
178#define SPCA50X_OFFSET_DATA 10
179#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
180#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
181#define SPCA504_PCCAM600_OFFSET_MODE 5
182#define SPCA504_PCCAM600_OFFSET_DATA 14
183 /* Frame packet header offsets for the spca533 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300184#define SPCA533_OFFSET_DATA 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185#define SPCA533_OFFSET_FRAMSEQ 15
186/* Frame packet header offsets for the spca536 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300187#define SPCA536_OFFSET_DATA 4
188#define SPCA536_OFFSET_FRAMSEQ 1
189
190struct cmd {
191 u8 req;
192 u16 val;
193 u16 idx;
194};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300195
196/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300197static const struct cmd spca504_pccam600_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198/* {0xa0, 0x0000, 0x0503}, * capture mode */
199 {0x00, 0x0000, 0x2000},
200 {0x00, 0x0013, 0x2301},
201 {0x00, 0x0003, 0x2000},
202 {0x00, 0x0001, 0x21ac},
203 {0x00, 0x0001, 0x21a6},
204 {0x00, 0x0000, 0x21a7}, /* brightness */
205 {0x00, 0x0020, 0x21a8}, /* contrast */
206 {0x00, 0x0001, 0x21ac}, /* sat/hue */
207 {0x00, 0x0000, 0x21ad}, /* hue */
208 {0x00, 0x001a, 0x21ae}, /* saturation */
209 {0x00, 0x0002, 0x21a3}, /* gamma */
210 {0x30, 0x0154, 0x0008},
211 {0x30, 0x0004, 0x0006},
212 {0x30, 0x0258, 0x0009},
213 {0x30, 0x0004, 0x0000},
214 {0x30, 0x0093, 0x0004},
215 {0x30, 0x0066, 0x0005},
216 {0x00, 0x0000, 0x2000},
217 {0x00, 0x0013, 0x2301},
218 {0x00, 0x0003, 0x2000},
219 {0x00, 0x0013, 0x2301},
220 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300221};
222
223/* Creative PC-CAM 600 specific open data, sent before using the
224 * generic initialisation data from spca504_open_data.
225 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300226static const struct cmd spca504_pccam600_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 {0x00, 0x0001, 0x2501},
228 {0x20, 0x0500, 0x0001}, /* snapshot mode */
229 {0x00, 0x0003, 0x2880},
230 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231};
232
233/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300234static const struct cmd spca504A_clicksmart420_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235/* {0xa0, 0x0000, 0x0503}, * capture mode */
236 {0x00, 0x0000, 0x2000},
237 {0x00, 0x0013, 0x2301},
238 {0x00, 0x0003, 0x2000},
239 {0x00, 0x0001, 0x21ac},
240 {0x00, 0x0001, 0x21a6},
241 {0x00, 0x0000, 0x21a7}, /* brightness */
242 {0x00, 0x0020, 0x21a8}, /* contrast */
243 {0x00, 0x0001, 0x21ac}, /* sat/hue */
244 {0x00, 0x0000, 0x21ad}, /* hue */
245 {0x00, 0x001a, 0x21ae}, /* saturation */
246 {0x00, 0x0002, 0x21a3}, /* gamma */
247 {0x30, 0x0004, 0x000a},
248 {0xb0, 0x0001, 0x0000},
249
250
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300251 {0xa1, 0x0080, 0x0001},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252 {0x30, 0x0049, 0x0000},
253 {0x30, 0x0060, 0x0005},
254 {0x0c, 0x0004, 0x0000},
255 {0x00, 0x0000, 0x0000},
256 {0x00, 0x0000, 0x2000},
257 {0x00, 0x0013, 0x2301},
258 {0x00, 0x0003, 0x2000},
259 {0x00, 0x0000, 0x2000},
260
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300261};
262
263/* clicksmart 420 open data ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300264static const struct cmd spca504A_clicksmart420_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265 {0x00, 0x0001, 0x2501},
266 {0x20, 0x0502, 0x0000},
267 {0x06, 0x0000, 0x0000},
268 {0x00, 0x0004, 0x2880},
269 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300270
271 {0xa0, 0x0000, 0x0503},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272};
273
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300274static const u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300275 { /* Q-table Y-components */
276 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
277 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
278 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
279 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
280 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
281 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
282 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
283 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
284 { /* Q-table C-components */
285 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
286 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
287 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
288 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
293};
294
295/* FIXME: This Q-table is identical to the Creative PC-CAM one,
296 * except for one byte. Possibly a typo?
297 * NWG: 18/05/2003.
298 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300299static const u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300 { /* Q-table Y-components */
301 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
302 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
303 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
304 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
305 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
306 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
307 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
308 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
309 },
310 { /* Q-table C-components */
311 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
312 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
313 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
314 0x0e, 0x14, 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 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
319};
320
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300321/* read <len> bytes to gspca_dev->usb_buf */
322static void reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300323 u8 req,
324 u16 index,
325 u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300326{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300327 int ret;
328
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300329#ifdef GSPCA_DEBUG
330 if (len > USB_BUF_SZ) {
331 err("reg_r: buffer overflow");
332 return;
333 }
334#endif
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300335 if (gspca_dev->usb_err < 0)
336 return;
337 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300338 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300339 req,
340 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
341 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300342 index,
343 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300344 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300345 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300346 err("reg_r err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300347 gspca_dev->usb_err = ret;
348 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300349}
350
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300351/* write one byte */
352static void reg_w_1(struct gspca_dev *gspca_dev,
353 u8 req,
354 u16 value,
355 u16 index,
356 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300357{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300358 int ret;
359
360 if (gspca_dev->usb_err < 0)
361 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300362 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300363 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300364 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300365 req,
366 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300367 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300368 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300369 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300370 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300371 err("reg_w_1 err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300372 gspca_dev->usb_err = ret;
373 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300374}
375
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300376/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300377static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300378 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300380 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300381 int ret;
382
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300383 if (gspca_dev->usb_err < 0)
384 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300385 ret = usb_control_msg(dev,
386 usb_sndctrlpipe(dev, 0),
387 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300388 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300389 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300390 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300391 err("reg_w_riv err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300392 gspca_dev->usb_err = ret;
393 return;
394 }
395 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
396 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397}
398
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300399static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300400 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300401{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300402 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300403 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300404 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406}
407
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300408static void setup_qtable(struct gspca_dev *gspca_dev,
409 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300410{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300411 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412
413 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300414 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300415 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416
417 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300418 for (i = 0; i < 64; i++)
419 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420}
421
422static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300423 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300425 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300426 reg_r(gspca_dev, 0x01, 0x0001, 1);
427 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300428 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300429
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300430 msleep(200);
Jean-François Moinecf252202011-05-17 05:32:39 -0300431 reg_r(gspca_dev, 0x01, 0x0001, 1);
432 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300433}
434
Jean-François Moinecf252202011-05-17 05:32:39 -0300435#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300436static void spca504_read_info(struct gspca_dev *gspca_dev)
437{
438 int i;
439 u8 info[6];
440
Jean-François Moinecf252202011-05-17 05:32:39 -0300441 for (i = 0; i < 6; i++) {
442 reg_r(gspca_dev, 0, i, 1);
443 info[i] = gspca_dev->usb_buf[0];
444 }
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300445 PDEBUG(D_STREAM,
446 "Read info: %d %d %d %d %d %d."
447 " Should be 1,0,2,2,0,0",
448 info[0], info[1], info[2],
449 info[3], info[4], info[5]);
450}
Jean-François Moinecf252202011-05-17 05:32:39 -0300451#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300452
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300454 u8 req,
Jean-François Moinecf252202011-05-17 05:32:39 -0300455 u16 idx, u16 val, u8 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300457 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300459 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300460 reg_r(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300461 if (gspca_dev->usb_err < 0)
462 return;
Jean-François Moinecf252202011-05-17 05:32:39 -0300463 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
464 gspca_dev->usb_buf[0], endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465 if (!count)
466 return;
467 count = 200;
468 while (--count > 0) {
469 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200470 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300471/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-François Moinecf252202011-05-17 05:32:39 -0300472 reg_r(gspca_dev, 0x01, 0x0001, 1);
473 status = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300475 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 status, 200 - count);
477 break;
478 }
479 }
480}
481
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300482static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484 int count = 10;
485
486 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300487 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300488 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 break;
490 msleep(10);
491 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492}
493
494static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
495{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496 int count = 50;
497
498 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300499 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300500 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300501 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300502 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300503 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504 break;
505 }
506 msleep(10);
507 }
508}
509
Jean-François Moinecf252202011-05-17 05:32:39 -0300510#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
512{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300513 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300515 data = gspca_dev->usb_buf;
516 reg_r(gspca_dev, 0x20, 0, 5);
Jean-François Moinecf252202011-05-17 05:32:39 -0300517 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300518 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300519 reg_r(gspca_dev, 0x23, 0, 64);
520 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521}
Jean-François Moinecf252202011-05-17 05:32:39 -0300522#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523
524static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
525{
526 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300527 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300529 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 switch (sd->bridge) {
531 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300532 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300534 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300535#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300536 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300537#endif
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300538 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300539 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300541 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300542 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300543 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544
545 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300546 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300548 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549 break;
550 default:
551/* case BRIDGE_SPCA504B: */
552/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300553 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300554 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300555 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300556 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300557 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300558 break;
559 case BRIDGE_SPCA504:
560 Size += 3;
561 if (sd->subtype == AiptekMiniPenCam13) {
562 /* spca504a aiptek */
563 spca504A_acknowledged_command(gspca_dev,
564 0x08, Size, 0,
565 0x80 | (Size & 0x0f), 1);
566 spca504A_acknowledged_command(gspca_dev,
567 1, 3, 0, 0x9f, 0);
568 } else {
569 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
570 }
571 break;
572 case BRIDGE_SPCA504C:
573 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300574 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
575 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576 break;
577 }
578}
579
580static void spca504_wait_status(struct gspca_dev *gspca_dev)
581{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300582 int cnt;
583
584 cnt = 256;
585 while (--cnt > 0) {
586 /* With this we get the status, when return 0 it's all ok */
Jean-François Moinecf252202011-05-17 05:32:39 -0300587 reg_r(gspca_dev, 0x06, 0x00, 1);
588 if (gspca_dev->usb_buf[0] == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300589 return;
590 msleep(10);
591 }
592}
593
594static void spca504B_setQtable(struct gspca_dev *gspca_dev)
595{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300596 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300597 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300598 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300599}
600
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300601static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602{
603 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300604 u16 reg;
605
606 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300607 reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300608}
609
610static void setcontrast(struct gspca_dev *gspca_dev)
611{
612 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300613 u16 reg;
614
615 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300616 reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300617}
618
619static void setcolors(struct gspca_dev *gspca_dev)
620{
621 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300622 u16 reg;
623
624 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300625 reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300626}
627
628static void init_ctl_reg(struct gspca_dev *gspca_dev)
629{
630 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300631 int pollreg = 1;
632
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300633 setbrightness(gspca_dev);
634 setcontrast(gspca_dev);
635 setcolors(gspca_dev);
636
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637 switch (sd->bridge) {
638 case BRIDGE_SPCA504:
639 case BRIDGE_SPCA504C:
640 pollreg = 0;
641 /* fall thru */
642 default:
643/* case BRIDGE_SPCA533: */
644/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300645 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
646 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
647 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300648 break;
649 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300650 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
651 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
652 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653 break;
654 }
655 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300656 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657}
658
659/* this function is called at probe time */
660static int sd_config(struct gspca_dev *gspca_dev,
661 const struct usb_device_id *id)
662{
663 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300665
666 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300668 sd->bridge = id->driver_info >> 8;
669 sd->subtype = id->driver_info;
670
671 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300672
673 /* try to get the firmware as some cam answer 2.0.1.2.2
674 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300675 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300676 switch (gspca_dev->usb_buf[0]) {
677 case 1:
678 break; /* (right bridge/subtype) */
679 case 2:
680 sd->bridge = BRIDGE_SPCA504B;
681 sd->subtype = 0;
682 break;
683 default:
684 return -ENODEV;
685 }
686 }
687
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688 switch (sd->bridge) {
689 default:
690/* case BRIDGE_SPCA504B: */
691/* case BRIDGE_SPCA504: */
692/* case BRIDGE_SPCA536: */
693 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300694 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300695 break;
696 case BRIDGE_SPCA533:
697 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300698 if (sd->subtype == MegaImageVI) /* 320x240 only */
699 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
700 else
701 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702 break;
703 case BRIDGE_SPCA504C:
704 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300705 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 break;
707 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300708 sd->brightness = BRIGHTNESS_DEF;
709 sd->contrast = CONTRAST_DEF;
710 sd->colors = COLOR_DEF;
711 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300712 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713 return 0;
714}
715
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300716/* this function is called at probe and resume time */
717static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718{
719 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720
721 switch (sd->bridge) {
722 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300723 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300724 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
725 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
726 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
727 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
728 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729 /* fall thru */
730 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300731 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300732#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300734#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735 break;
736 case BRIDGE_SPCA536:
Jean-François Moinecf252202011-05-17 05:32:39 -0300737#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300739#endif
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300740 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300741 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300742 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300743 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300744 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 spca504B_WaitCmdStatus(gspca_dev);
746 break;
747 case BRIDGE_SPCA504C: /* pccam600 */
748 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300749 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
750 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 spca504_wait_status(gspca_dev);
752 if (sd->subtype == LogitechClickSmart420)
753 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300754 spca504A_clicksmart420_open_data,
755 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300757 write_vector(gspca_dev, spca504_pccam600_open_data,
758 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300759 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300760 break;
761 default:
762/* case BRIDGE_SPCA504: */
763 PDEBUG(D_STREAM, "Opening SPCA504");
764 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300765#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300766 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300767#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300768
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
770 spca504A_acknowledged_command(gspca_dev, 0x24,
771 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200772 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300773 spca504A_acknowledged_command(gspca_dev, 0x24,
774 8, 3, 0x9e, 0);
775
776 spca504A_acknowledged_command(gspca_dev, 0x24,
777 0, 0, 0x9d, 1);
778 /******************************/
779 /* spca504a aiptek */
780 spca504A_acknowledged_command(gspca_dev, 0x08,
781 6, 0, 0x86, 1);
782/* reg_write (dev, 0, 0x2000, 0); */
783/* reg_write (dev, 0, 0x2883, 1); */
784/* spca504A_acknowledged_command (gspca_dev, 0x08,
785 6, 0, 0x86, 1); */
786/* spca504A_acknowledged_command (gspca_dev, 0x24,
787 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300788 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
789 /* L92 sno1t.txt */
790 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791 spca504A_acknowledged_command(gspca_dev, 0x01,
792 0x0f, 0, 0xff, 0);
793 }
794 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300795 reg_w_riv(gspca_dev, 0, 0x2000, 0);
796 reg_w_riv(gspca_dev, 0, 0x2883, 1);
797 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300798 break;
799 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300800 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801}
802
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300803static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804{
805 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300808 /* create the JPEG header */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300809 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
810 0x22); /* JPEG 411 */
811 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
812
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300813 if (sd->bridge == BRIDGE_SPCA504B)
814 spca504B_setQtable(gspca_dev);
815 spca504B_SetSizeType(gspca_dev);
816 switch (sd->bridge) {
817 default:
818/* case BRIDGE_SPCA504B: */
819/* case BRIDGE_SPCA533: */
820/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300821 switch (sd->subtype) {
822 case MegapixV4:
823 case LogitechClickSmart820:
824 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300825 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300826 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300827 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300829 break;
830 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300831 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300832 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300833 spca504B_PollingDataReady(gspca_dev);
834 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300835 }
836 break;
837 case BRIDGE_SPCA504:
838 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300839#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300840 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300841#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300842
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300843 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
844 spca504A_acknowledged_command(gspca_dev, 0x24,
845 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200846 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 spca504A_acknowledged_command(gspca_dev, 0x24,
848 8, 3, 0x9e, 0);
849 spca504A_acknowledged_command(gspca_dev, 0x24,
850 0, 0, 0x9d, 1);
851 } else {
852 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-François Moinecf252202011-05-17 05:32:39 -0300853#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300854 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300855#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
857 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
858 }
859 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300860 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
861 /* L92 sno1t.txt */
862 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 break;
864 case BRIDGE_SPCA504C:
865 if (sd->subtype == LogitechClickSmart420) {
866 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300867 spca504A_clicksmart420_init_data,
868 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300870 write_vector(gspca_dev, spca504_pccam600_init_data,
871 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300873 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300874 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
875 /* auto exposure */
876 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
877 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878
879 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300880 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
881 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 spca504B_SetSizeType(gspca_dev);
883 break;
884 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300885 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300886 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300887}
888
889static void sd_stopN(struct gspca_dev *gspca_dev)
890{
891 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300892
893 switch (sd->bridge) {
894 default:
895/* case BRIDGE_SPCA533: */
896/* case BRIDGE_SPCA536: */
897/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300898 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300900 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300901 break;
902 case BRIDGE_SPCA504:
903 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300904 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300905
906 if (sd->subtype == AiptekMiniPenCam13) {
907 /* spca504a aiptek */
908/* spca504A_acknowledged_command(gspca_dev, 0x08,
909 6, 0, 0x86, 1); */
910 spca504A_acknowledged_command(gspca_dev, 0x24,
911 0x00, 0x00, 0x9d, 1);
912 spca504A_acknowledged_command(gspca_dev, 0x01,
913 0x0f, 0x00, 0xff, 1);
914 } else {
915 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300916 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 }
918 break;
919 }
920}
921
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300923 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 int len) /* iso packet length */
925{
926 struct sd *sd = (struct sd *) gspca_dev;
927 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300928 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300929
930/* frames are jpeg 4.1.1 without 0xff escape */
931 switch (sd->bridge) {
932 case BRIDGE_SPCA533:
933 if (data[0] == 0xff) {
934 if (data[1] != 0x01) { /* drop packet */
935/* gspca_dev->last_packet_type = DISCARD_PACKET; */
936 return;
937 }
938 sof = 1;
939 data += SPCA533_OFFSET_DATA;
940 len -= SPCA533_OFFSET_DATA;
941 } else {
942 data += 1;
943 len -= 1;
944 }
945 break;
946 case BRIDGE_SPCA536:
947 if (data[0] == 0xff) {
948 sof = 1;
949 data += SPCA536_OFFSET_DATA;
950 len -= SPCA536_OFFSET_DATA;
951 } else {
952 data += 2;
953 len -= 2;
954 }
955 break;
956 default:
957/* case BRIDGE_SPCA504: */
958/* case BRIDGE_SPCA504B: */
959 switch (data[0]) {
960 case 0xfe: /* start of frame */
961 sof = 1;
962 data += SPCA50X_OFFSET_DATA;
963 len -= SPCA50X_OFFSET_DATA;
964 break;
965 case 0xff: /* drop packet */
966/* gspca_dev->last_packet_type = DISCARD_PACKET; */
967 return;
968 default:
969 data += 1;
970 len -= 1;
971 break;
972 }
973 break;
974 case BRIDGE_SPCA504C:
975 switch (data[0]) {
976 case 0xfe: /* start of frame */
977 sof = 1;
978 data += SPCA504_PCCAM600_OFFSET_DATA;
979 len -= SPCA504_PCCAM600_OFFSET_DATA;
980 break;
981 case 0xff: /* drop packet */
982/* gspca_dev->last_packet_type = DISCARD_PACKET; */
983 return;
984 default:
985 data += 1;
986 len -= 1;
987 break;
988 }
989 break;
990 }
991 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300992 gspca_frame_add(gspca_dev, LAST_PACKET,
993 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994
995 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300996 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300997 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300998 }
999
1000 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001001 i = 0;
1002 do {
1003 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001004 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001005 data, i + 1);
1006 len -= i;
1007 data += i;
1008 *data = 0x00;
1009 i = 0;
1010 }
1011 i++;
1012 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001013 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001014}
1015
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001016static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1017{
1018 struct sd *sd = (struct sd *) gspca_dev;
1019
1020 sd->brightness = val;
1021 if (gspca_dev->streaming)
1022 setbrightness(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001023 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001024}
1025
1026static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1027{
1028 struct sd *sd = (struct sd *) gspca_dev;
1029
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030 *val = sd->brightness;
1031 return 0;
1032}
1033
1034static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1035{
1036 struct sd *sd = (struct sd *) gspca_dev;
1037
1038 sd->contrast = val;
1039 if (gspca_dev->streaming)
1040 setcontrast(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001041 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001042}
1043
1044static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1045{
1046 struct sd *sd = (struct sd *) gspca_dev;
1047
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001048 *val = sd->contrast;
1049 return 0;
1050}
1051
1052static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1053{
1054 struct sd *sd = (struct sd *) gspca_dev;
1055
1056 sd->colors = val;
1057 if (gspca_dev->streaming)
1058 setcolors(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001059 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001060}
1061
1062static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1063{
1064 struct sd *sd = (struct sd *) gspca_dev;
1065
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001066 *val = sd->colors;
1067 return 0;
1068}
1069
1070static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1071{
1072 struct sd *sd = (struct sd *) gspca_dev;
1073
1074 sd->autogain = val;
1075 return 0;
1076}
1077
1078static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1079{
1080 struct sd *sd = (struct sd *) gspca_dev;
1081
1082 *val = sd->autogain;
1083 return 0;
1084}
1085
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001086static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1087 struct v4l2_jpegcompression *jcomp)
1088{
1089 struct sd *sd = (struct sd *) gspca_dev;
1090
1091 if (jcomp->quality < QUALITY_MIN)
1092 sd->quality = QUALITY_MIN;
1093 else if (jcomp->quality > QUALITY_MAX)
1094 sd->quality = QUALITY_MAX;
1095 else
1096 sd->quality = jcomp->quality;
1097 if (gspca_dev->streaming)
1098 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001099 return gspca_dev->usb_err;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001100}
1101
1102static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1103 struct v4l2_jpegcompression *jcomp)
1104{
1105 struct sd *sd = (struct sd *) gspca_dev;
1106
1107 memset(jcomp, 0, sizeof *jcomp);
1108 jcomp->quality = sd->quality;
1109 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1110 | V4L2_JPEG_MARKER_DQT;
1111 return 0;
1112}
1113
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001114/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001115static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116 .name = MODULE_NAME,
1117 .ctrls = sd_ctrls,
1118 .nctrls = ARRAY_SIZE(sd_ctrls),
1119 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001120 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001121 .start = sd_start,
1122 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001123 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001124 .get_jcomp = sd_get_jcomp,
1125 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001126};
1127
1128/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001129#define BS(bridge, subtype) \
1130 .driver_info = (BRIDGE_ ## bridge << 8) \
1131 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -03001132static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001133 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1134 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1135 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1136 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1137 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1138 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1139 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1140 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1141 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1142 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1143 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1144 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1145 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1146 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1147 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1148 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1149 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1150 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001151 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001152 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001153 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001154 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1155 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1156 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1157 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1158 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1159 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1160 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1161 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1162 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1163 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1164 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1165 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1166 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1167 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1168 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1169 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1170 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1171 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1172 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1173 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1174 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1175 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1176 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1177 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1178 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1179 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1180 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1181 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1182 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1183 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1184 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1185 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1186 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1187 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1188 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1189 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1190 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1191 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001192 {}
1193};
1194MODULE_DEVICE_TABLE(usb, device_table);
1195
1196/* -- device connect -- */
1197static int sd_probe(struct usb_interface *intf,
1198 const struct usb_device_id *id)
1199{
1200 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1201 THIS_MODULE);
1202}
1203
1204static struct usb_driver sd_driver = {
1205 .name = MODULE_NAME,
1206 .id_table = device_table,
1207 .probe = sd_probe,
1208 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001209#ifdef CONFIG_PM
1210 .suspend = gspca_suspend,
1211 .resume = gspca_resume,
1212#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001213};
1214
1215/* -- module insert / remove -- */
1216static int __init sd_mod_init(void)
1217{
Jean-François Moine54826432010-09-13 04:53:03 -03001218 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001219}
1220static void __exit sd_mod_exit(void)
1221{
1222 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001223}
1224
1225module_init(sd_mod_init);
1226module_exit(sd_mod_exit);