blob: 543542af272048ef0e5d6bfa07887f4eb6b44774 [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 Moine739570b2008-07-14 09:38:29 -0300399/* read 1 byte */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300400static u8 reg_r_1(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300401 u16 value) /* wValue */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300402{
403 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300405 if (gspca_dev->usb_err < 0)
406 return 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300407 ret = usb_control_msg(gspca_dev->dev,
408 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 0x20, /* request */
410 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
411 value,
412 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300413 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414 500); /* timeout */
415 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300416 err("reg_r_1 err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300417 gspca_dev->usb_err = ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418 return 0;
419 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300420 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300421}
422
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300423/* read 1 or 2 bytes */
424static u16 reg_r_12(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300425 u8 req, /* bRequest */
426 u16 index, /* wIndex */
427 u16 length) /* wLength (1 or 2 only) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428{
429 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300430
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300431 if (gspca_dev->usb_err < 0)
432 return 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300433 gspca_dev->usb_buf[1] = 0;
434 ret = usb_control_msg(gspca_dev->dev,
435 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300436 req,
437 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
438 0, /* value */
439 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300440 gspca_dev->usb_buf, length,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 500);
442 if (ret < 0) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300443 err("reg_r_12 err %d", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300444 gspca_dev->usb_err = ret;
445 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300447 return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448}
449
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300450static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300451 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300452{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300453 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300454 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300455 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457}
458
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300459static void setup_qtable(struct gspca_dev *gspca_dev,
460 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300462 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463
464 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300465 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300466 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467
468 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300469 for (i = 0; i < 64; i++)
470 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471}
472
473static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300474 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300476 u16 notdone;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300477
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300478 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300479 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300480 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300481
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300482 PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483
484 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300485 notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300486 PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487}
488
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300489static void spca504_read_info(struct gspca_dev *gspca_dev)
490{
491 int i;
492 u8 info[6];
493
494 for (i = 0; i < 6; i++)
495 info[i] = reg_r_1(gspca_dev, i);
496 PDEBUG(D_STREAM,
497 "Read info: %d %d %d %d %d %d."
498 " Should be 1,0,2,2,0,0",
499 info[0], info[1], info[2],
500 info[3], info[4], info[5]);
501}
502
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300504 u8 req,
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300505 u16 idx, u16 val, u16 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300507 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300509 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300510 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300511 if (gspca_dev->usb_err < 0)
512 return;
513 PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 if (!count)
515 return;
516 count = 200;
517 while (--count > 0) {
518 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200519 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300520/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300521 status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300523 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 status, 200 - count);
525 break;
526 }
527 }
528}
529
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300530static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 int count = 10;
533
534 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300535 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300536 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 break;
538 msleep(10);
539 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540}
541
542static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
543{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544 int count = 50;
545
546 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300547 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300548 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300549 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300550 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300551 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552 break;
553 }
554 msleep(10);
555 }
556}
557
558static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
559{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300560 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300562 data = gspca_dev->usb_buf;
563 reg_r(gspca_dev, 0x20, 0, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564 PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300565 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300566 reg_r(gspca_dev, 0x23, 0, 64);
567 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568}
569
570static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
571{
572 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300573 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300575 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576 switch (sd->bridge) {
577 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300578 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300579 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300580 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300582 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300583 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300585 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300586 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300587 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588
589 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300590 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300592 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 break;
594 default:
595/* case BRIDGE_SPCA504B: */
596/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300597 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300598 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300599 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300600 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300601 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602 break;
603 case BRIDGE_SPCA504:
604 Size += 3;
605 if (sd->subtype == AiptekMiniPenCam13) {
606 /* spca504a aiptek */
607 spca504A_acknowledged_command(gspca_dev,
608 0x08, Size, 0,
609 0x80 | (Size & 0x0f), 1);
610 spca504A_acknowledged_command(gspca_dev,
611 1, 3, 0, 0x9f, 0);
612 } else {
613 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
614 }
615 break;
616 case BRIDGE_SPCA504C:
617 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300618 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
619 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620 break;
621 }
622}
623
624static void spca504_wait_status(struct gspca_dev *gspca_dev)
625{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626 int cnt;
627
628 cnt = 256;
629 while (--cnt > 0) {
630 /* With this we get the status, when return 0 it's all ok */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300631 if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300632 return;
633 msleep(10);
634 }
635}
636
637static void spca504B_setQtable(struct gspca_dev *gspca_dev)
638{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300639 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300640 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300641 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300642}
643
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300644static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300645{
646 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300647 u16 reg;
648
649 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300650 reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300651}
652
653static void setcontrast(struct gspca_dev *gspca_dev)
654{
655 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300656 u16 reg;
657
658 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300659 reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300660}
661
662static void setcolors(struct gspca_dev *gspca_dev)
663{
664 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300665 u16 reg;
666
667 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300668 reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300669}
670
671static void init_ctl_reg(struct gspca_dev *gspca_dev)
672{
673 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 int pollreg = 1;
675
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300676 setbrightness(gspca_dev);
677 setcontrast(gspca_dev);
678 setcolors(gspca_dev);
679
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680 switch (sd->bridge) {
681 case BRIDGE_SPCA504:
682 case BRIDGE_SPCA504C:
683 pollreg = 0;
684 /* fall thru */
685 default:
686/* case BRIDGE_SPCA533: */
687/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300688 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
689 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
690 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691 break;
692 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300693 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
694 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
695 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300696 break;
697 }
698 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300699 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300700}
701
702/* this function is called at probe time */
703static int sd_config(struct gspca_dev *gspca_dev,
704 const struct usb_device_id *id)
705{
706 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300708
709 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300711 sd->bridge = id->driver_info >> 8;
712 sd->subtype = id->driver_info;
713
714 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300715
716 /* try to get the firmware as some cam answer 2.0.1.2.2
717 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300718 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300719 switch (gspca_dev->usb_buf[0]) {
720 case 1:
721 break; /* (right bridge/subtype) */
722 case 2:
723 sd->bridge = BRIDGE_SPCA504B;
724 sd->subtype = 0;
725 break;
726 default:
727 return -ENODEV;
728 }
729 }
730
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731 switch (sd->bridge) {
732 default:
733/* case BRIDGE_SPCA504B: */
734/* case BRIDGE_SPCA504: */
735/* case BRIDGE_SPCA536: */
736 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300737 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 break;
739 case BRIDGE_SPCA533:
740 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300741 if (sd->subtype == MegaImageVI) /* 320x240 only */
742 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
743 else
744 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 break;
746 case BRIDGE_SPCA504C:
747 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300748 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749 break;
750 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300751 sd->brightness = BRIGHTNESS_DEF;
752 sd->contrast = CONTRAST_DEF;
753 sd->colors = COLOR_DEF;
754 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300755 sd->quality = QUALITY_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756 return 0;
757}
758
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300759/* this function is called at probe and resume time */
760static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761{
762 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763
764 switch (sd->bridge) {
765 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300766 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300767 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
768 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
769 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
770 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
771 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772 /* fall thru */
773 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300774 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775 spca50x_GetFirmware(gspca_dev);
776 break;
777 case BRIDGE_SPCA536:
778 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300779 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300780 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300781 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300782 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300783 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300784 spca504B_WaitCmdStatus(gspca_dev);
785 break;
786 case BRIDGE_SPCA504C: /* pccam600 */
787 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300788 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
789 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300790 spca504_wait_status(gspca_dev);
791 if (sd->subtype == LogitechClickSmart420)
792 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300793 spca504A_clicksmart420_open_data,
794 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300796 write_vector(gspca_dev, spca504_pccam600_open_data,
797 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300798 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300799 break;
800 default:
801/* case BRIDGE_SPCA504: */
802 PDEBUG(D_STREAM, "Opening SPCA504");
803 if (sd->subtype == AiptekMiniPenCam13) {
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300804 spca504_read_info(gspca_dev);
805
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
807 spca504A_acknowledged_command(gspca_dev, 0x24,
808 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200809 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300810 spca504A_acknowledged_command(gspca_dev, 0x24,
811 8, 3, 0x9e, 0);
812
813 spca504A_acknowledged_command(gspca_dev, 0x24,
814 0, 0, 0x9d, 1);
815 /******************************/
816 /* spca504a aiptek */
817 spca504A_acknowledged_command(gspca_dev, 0x08,
818 6, 0, 0x86, 1);
819/* reg_write (dev, 0, 0x2000, 0); */
820/* reg_write (dev, 0, 0x2883, 1); */
821/* spca504A_acknowledged_command (gspca_dev, 0x08,
822 6, 0, 0x86, 1); */
823/* spca504A_acknowledged_command (gspca_dev, 0x24,
824 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300825 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
826 /* L92 sno1t.txt */
827 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828 spca504A_acknowledged_command(gspca_dev, 0x01,
829 0x0f, 0, 0xff, 0);
830 }
831 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300832 reg_w_riv(gspca_dev, 0, 0x2000, 0);
833 reg_w_riv(gspca_dev, 0, 0x2883, 1);
834 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300835 break;
836 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300837 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838}
839
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300840static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841{
842 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300843 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300845 /* create the JPEG header */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300846 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
847 0x22); /* JPEG 411 */
848 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
849
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300850 if (sd->bridge == BRIDGE_SPCA504B)
851 spca504B_setQtable(gspca_dev);
852 spca504B_SetSizeType(gspca_dev);
853 switch (sd->bridge) {
854 default:
855/* case BRIDGE_SPCA504B: */
856/* case BRIDGE_SPCA533: */
857/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300858 switch (sd->subtype) {
859 case MegapixV4:
860 case LogitechClickSmart820:
861 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300862 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300864 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300865 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300866 break;
867 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300868 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300870 spca504B_PollingDataReady(gspca_dev);
871 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872 }
873 break;
874 case BRIDGE_SPCA504:
875 if (sd->subtype == AiptekMiniPenCam13) {
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300876 spca504_read_info(gspca_dev);
877
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
879 spca504A_acknowledged_command(gspca_dev, 0x24,
880 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200881 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 spca504A_acknowledged_command(gspca_dev, 0x24,
883 8, 3, 0x9e, 0);
884 spca504A_acknowledged_command(gspca_dev, 0x24,
885 0, 0, 0x9d, 1);
886 } else {
887 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300888 spca504_read_info(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300889 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
890 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
891 }
892 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300893 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
894 /* L92 sno1t.txt */
895 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896 break;
897 case BRIDGE_SPCA504C:
898 if (sd->subtype == LogitechClickSmart420) {
899 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300900 spca504A_clicksmart420_init_data,
901 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300903 write_vector(gspca_dev, spca504_pccam600_init_data,
904 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300905 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300906 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300907 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
908 /* auto exposure */
909 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
910 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911
912 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300913 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
914 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300915 spca504B_SetSizeType(gspca_dev);
916 break;
917 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300918 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300919 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920}
921
922static void sd_stopN(struct gspca_dev *gspca_dev)
923{
924 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300925
926 switch (sd->bridge) {
927 default:
928/* case BRIDGE_SPCA533: */
929/* case BRIDGE_SPCA536: */
930/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300931 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300932 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300933 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300934 break;
935 case BRIDGE_SPCA504:
936 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300937 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300938
939 if (sd->subtype == AiptekMiniPenCam13) {
940 /* spca504a aiptek */
941/* spca504A_acknowledged_command(gspca_dev, 0x08,
942 6, 0, 0x86, 1); */
943 spca504A_acknowledged_command(gspca_dev, 0x24,
944 0x00, 0x00, 0x9d, 1);
945 spca504A_acknowledged_command(gspca_dev, 0x01,
946 0x0f, 0x00, 0xff, 1);
947 } else {
948 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300949 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300950 }
951 break;
952 }
953}
954
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300955static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300956 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957 int len) /* iso packet length */
958{
959 struct sd *sd = (struct sd *) gspca_dev;
960 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300961 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300962
963/* frames are jpeg 4.1.1 without 0xff escape */
964 switch (sd->bridge) {
965 case BRIDGE_SPCA533:
966 if (data[0] == 0xff) {
967 if (data[1] != 0x01) { /* drop packet */
968/* gspca_dev->last_packet_type = DISCARD_PACKET; */
969 return;
970 }
971 sof = 1;
972 data += SPCA533_OFFSET_DATA;
973 len -= SPCA533_OFFSET_DATA;
974 } else {
975 data += 1;
976 len -= 1;
977 }
978 break;
979 case BRIDGE_SPCA536:
980 if (data[0] == 0xff) {
981 sof = 1;
982 data += SPCA536_OFFSET_DATA;
983 len -= SPCA536_OFFSET_DATA;
984 } else {
985 data += 2;
986 len -= 2;
987 }
988 break;
989 default:
990/* case BRIDGE_SPCA504: */
991/* case BRIDGE_SPCA504B: */
992 switch (data[0]) {
993 case 0xfe: /* start of frame */
994 sof = 1;
995 data += SPCA50X_OFFSET_DATA;
996 len -= SPCA50X_OFFSET_DATA;
997 break;
998 case 0xff: /* drop packet */
999/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1000 return;
1001 default:
1002 data += 1;
1003 len -= 1;
1004 break;
1005 }
1006 break;
1007 case BRIDGE_SPCA504C:
1008 switch (data[0]) {
1009 case 0xfe: /* start of frame */
1010 sof = 1;
1011 data += SPCA504_PCCAM600_OFFSET_DATA;
1012 len -= SPCA504_PCCAM600_OFFSET_DATA;
1013 break;
1014 case 0xff: /* drop packet */
1015/* gspca_dev->last_packet_type = DISCARD_PACKET; */
1016 return;
1017 default:
1018 data += 1;
1019 len -= 1;
1020 break;
1021 }
1022 break;
1023 }
1024 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001025 gspca_frame_add(gspca_dev, LAST_PACKET,
1026 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001027
1028 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001029 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -03001030 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001031 }
1032
1033 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001034 i = 0;
1035 do {
1036 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001037 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -03001038 data, i + 1);
1039 len -= i;
1040 data += i;
1041 *data = 0x00;
1042 i = 0;
1043 }
1044 i++;
1045 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001046 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001047}
1048
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001049static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1050{
1051 struct sd *sd = (struct sd *) gspca_dev;
1052
1053 sd->brightness = val;
1054 if (gspca_dev->streaming)
1055 setbrightness(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001056 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001057}
1058
1059static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1060{
1061 struct sd *sd = (struct sd *) gspca_dev;
1062
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001063 *val = sd->brightness;
1064 return 0;
1065}
1066
1067static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1068{
1069 struct sd *sd = (struct sd *) gspca_dev;
1070
1071 sd->contrast = val;
1072 if (gspca_dev->streaming)
1073 setcontrast(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001074 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001075}
1076
1077static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1078{
1079 struct sd *sd = (struct sd *) gspca_dev;
1080
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081 *val = sd->contrast;
1082 return 0;
1083}
1084
1085static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1086{
1087 struct sd *sd = (struct sd *) gspca_dev;
1088
1089 sd->colors = val;
1090 if (gspca_dev->streaming)
1091 setcolors(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001092 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001093}
1094
1095static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1096{
1097 struct sd *sd = (struct sd *) gspca_dev;
1098
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001099 *val = sd->colors;
1100 return 0;
1101}
1102
1103static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1104{
1105 struct sd *sd = (struct sd *) gspca_dev;
1106
1107 sd->autogain = val;
1108 return 0;
1109}
1110
1111static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1112{
1113 struct sd *sd = (struct sd *) gspca_dev;
1114
1115 *val = sd->autogain;
1116 return 0;
1117}
1118
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001119static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1120 struct v4l2_jpegcompression *jcomp)
1121{
1122 struct sd *sd = (struct sd *) gspca_dev;
1123
1124 if (jcomp->quality < QUALITY_MIN)
1125 sd->quality = QUALITY_MIN;
1126 else if (jcomp->quality > QUALITY_MAX)
1127 sd->quality = QUALITY_MAX;
1128 else
1129 sd->quality = jcomp->quality;
1130 if (gspca_dev->streaming)
1131 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
Jean-Francois Moineecb77682009-12-02 14:39:53 -03001132 return gspca_dev->usb_err;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001133}
1134
1135static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1136 struct v4l2_jpegcompression *jcomp)
1137{
1138 struct sd *sd = (struct sd *) gspca_dev;
1139
1140 memset(jcomp, 0, sizeof *jcomp);
1141 jcomp->quality = sd->quality;
1142 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1143 | V4L2_JPEG_MARKER_DQT;
1144 return 0;
1145}
1146
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001147/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001148static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001149 .name = MODULE_NAME,
1150 .ctrls = sd_ctrls,
1151 .nctrls = ARRAY_SIZE(sd_ctrls),
1152 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001153 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001154 .start = sd_start,
1155 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001156 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001157 .get_jcomp = sd_get_jcomp,
1158 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001159};
1160
1161/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001162#define BS(bridge, subtype) \
1163 .driver_info = (BRIDGE_ ## bridge << 8) \
1164 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -03001165static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001166 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1167 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1168 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1169 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1170 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1171 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1172 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1173 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1174 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1175 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1176 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1177 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1178 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1179 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1180 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1181 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1182 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1183 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001184 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001185 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001186 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001187 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1188 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1189 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1190 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1191 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1192 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1193 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1194 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1195 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1196 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1197 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1198 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1199 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1200 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1201 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1202 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1203 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1204 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1205 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1206 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1207 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1208 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1209 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1210 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1211 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1212 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1213 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1214 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1215 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1216 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1217 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1218 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1219 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1220 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1221 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1222 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1223 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1224 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001225 {}
1226};
1227MODULE_DEVICE_TABLE(usb, device_table);
1228
1229/* -- device connect -- */
1230static int sd_probe(struct usb_interface *intf,
1231 const struct usb_device_id *id)
1232{
1233 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1234 THIS_MODULE);
1235}
1236
1237static struct usb_driver sd_driver = {
1238 .name = MODULE_NAME,
1239 .id_table = device_table,
1240 .probe = sd_probe,
1241 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001242#ifdef CONFIG_PM
1243 .suspend = gspca_suspend,
1244 .resume = gspca_resume,
1245#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001246};
1247
1248/* -- module insert / remove -- */
1249static int __init sd_mod_init(void)
1250{
Jean-François Moine54826432010-09-13 04:53:03 -03001251 return usb_register(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001252}
1253static void __exit sd_mod_exit(void)
1254{
1255 usb_deregister(&sd_driver);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001256}
1257
1258module_init(sd_mod_init);
1259module_exit(sd_mod_exit);