blob: bd3d5a615384832790349fefe9fdd57c6438aa4a [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Sunplus spca504(abc) spca533 spca536 library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
Joe Perches133a9fe2011-08-21 19:56:57 -030022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030024#define MODULE_NAME "sunplus"
25
26#include "gspca.h"
27#include "jpeg.h"
28
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
30MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
31MODULE_LICENSE("GPL");
32
33/* specific webcam descriptor */
34struct sd {
35 struct gspca_dev gspca_dev; /* !! must be the first item */
36
Hans Verkuiled5cd6b2012-05-16 08:49:10 -030037 struct v4l2_ctrl *jpegqual;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -030038#define QUALITY_MIN 70
39#define QUALITY_MAX 95
40#define QUALITY_DEF 85
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030041
Hans Verkuiled5cd6b2012-05-16 08:49:10 -030042 bool autogain;
43
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
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030060static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030061 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
62 .bytesperline = 320,
63 .sizeimage = 320 * 240 * 3 / 8 + 590,
64 .colorspace = V4L2_COLORSPACE_JPEG,
65 .priv = 2},
66 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
67 .bytesperline = 640,
68 .sizeimage = 640 * 480 * 3 / 8 + 590,
69 .colorspace = V4L2_COLORSPACE_JPEG,
70 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071};
72
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030073static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030074 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
75 .bytesperline = 320,
76 .sizeimage = 320 * 240 * 3 / 8 + 590,
77 .colorspace = V4L2_COLORSPACE_JPEG,
78 .priv = 2},
79 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
80 .bytesperline = 464,
81 .sizeimage = 464 * 480 * 3 / 8 + 590,
82 .colorspace = V4L2_COLORSPACE_JPEG,
83 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030084};
85
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030086static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030087 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
88 .bytesperline = 176,
89 .sizeimage = 176 * 144 * 3 / 8 + 590,
90 .colorspace = V4L2_COLORSPACE_JPEG,
91 .priv = 4},
92 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
93 .bytesperline = 320,
94 .sizeimage = 320 * 240 * 3 / 8 + 590,
95 .colorspace = V4L2_COLORSPACE_JPEG,
96 .priv = 3},
97 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
98 .bytesperline = 352,
99 .sizeimage = 352 * 288 * 3 / 8 + 590,
100 .colorspace = V4L2_COLORSPACE_JPEG,
101 .priv = 2},
102 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
103 .bytesperline = 640,
104 .sizeimage = 640 * 480 * 3 / 8 + 590,
105 .colorspace = V4L2_COLORSPACE_JPEG,
106 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107};
108
109#define SPCA50X_OFFSET_DATA 10
110#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
111#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
112#define SPCA504_PCCAM600_OFFSET_MODE 5
113#define SPCA504_PCCAM600_OFFSET_DATA 14
114 /* Frame packet header offsets for the spca533 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300115#define SPCA533_OFFSET_DATA 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300116#define SPCA533_OFFSET_FRAMSEQ 15
117/* Frame packet header offsets for the spca536 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300118#define SPCA536_OFFSET_DATA 4
119#define SPCA536_OFFSET_FRAMSEQ 1
120
121struct cmd {
122 u8 req;
123 u16 val;
124 u16 idx;
125};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126
127/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300128static const struct cmd spca504_pccam600_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300129/* {0xa0, 0x0000, 0x0503}, * capture mode */
130 {0x00, 0x0000, 0x2000},
131 {0x00, 0x0013, 0x2301},
132 {0x00, 0x0003, 0x2000},
133 {0x00, 0x0001, 0x21ac},
134 {0x00, 0x0001, 0x21a6},
135 {0x00, 0x0000, 0x21a7}, /* brightness */
136 {0x00, 0x0020, 0x21a8}, /* contrast */
137 {0x00, 0x0001, 0x21ac}, /* sat/hue */
138 {0x00, 0x0000, 0x21ad}, /* hue */
139 {0x00, 0x001a, 0x21ae}, /* saturation */
140 {0x00, 0x0002, 0x21a3}, /* gamma */
141 {0x30, 0x0154, 0x0008},
142 {0x30, 0x0004, 0x0006},
143 {0x30, 0x0258, 0x0009},
144 {0x30, 0x0004, 0x0000},
145 {0x30, 0x0093, 0x0004},
146 {0x30, 0x0066, 0x0005},
147 {0x00, 0x0000, 0x2000},
148 {0x00, 0x0013, 0x2301},
149 {0x00, 0x0003, 0x2000},
150 {0x00, 0x0013, 0x2301},
151 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300152};
153
154/* Creative PC-CAM 600 specific open data, sent before using the
155 * generic initialisation data from spca504_open_data.
156 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300157static const struct cmd spca504_pccam600_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300158 {0x00, 0x0001, 0x2501},
159 {0x20, 0x0500, 0x0001}, /* snapshot mode */
160 {0x00, 0x0003, 0x2880},
161 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300162};
163
164/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300165static const struct cmd spca504A_clicksmart420_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300166/* {0xa0, 0x0000, 0x0503}, * capture mode */
167 {0x00, 0x0000, 0x2000},
168 {0x00, 0x0013, 0x2301},
169 {0x00, 0x0003, 0x2000},
170 {0x00, 0x0001, 0x21ac},
171 {0x00, 0x0001, 0x21a6},
172 {0x00, 0x0000, 0x21a7}, /* brightness */
173 {0x00, 0x0020, 0x21a8}, /* contrast */
174 {0x00, 0x0001, 0x21ac}, /* sat/hue */
175 {0x00, 0x0000, 0x21ad}, /* hue */
176 {0x00, 0x001a, 0x21ae}, /* saturation */
177 {0x00, 0x0002, 0x21a3}, /* gamma */
178 {0x30, 0x0004, 0x000a},
179 {0xb0, 0x0001, 0x0000},
180
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300181 {0xa1, 0x0080, 0x0001},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300182 {0x30, 0x0049, 0x0000},
183 {0x30, 0x0060, 0x0005},
184 {0x0c, 0x0004, 0x0000},
185 {0x00, 0x0000, 0x0000},
186 {0x00, 0x0000, 0x2000},
187 {0x00, 0x0013, 0x2301},
188 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300189};
190
191/* clicksmart 420 open data ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300192static const struct cmd spca504A_clicksmart420_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300193 {0x00, 0x0001, 0x2501},
194 {0x20, 0x0502, 0x0000},
195 {0x06, 0x0000, 0x0000},
196 {0x00, 0x0004, 0x2880},
197 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198
199 {0xa0, 0x0000, 0x0503},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200};
201
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300202static const u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203 { /* Q-table Y-components */
204 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
205 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
206 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
207 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
208 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
209 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
210 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
211 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
212 { /* Q-table C-components */
213 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
214 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
215 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
216 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
217 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
218 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
219 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
220 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
221};
222
223/* FIXME: This Q-table is identical to the Creative PC-CAM one,
224 * except for one byte. Possibly a typo?
225 * NWG: 18/05/2003.
226 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300227static const u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 { /* Q-table Y-components */
229 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
230 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
231 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
232 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
233 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
234 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
235 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
236 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
237 },
238 { /* Q-table C-components */
239 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
240 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
241 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
242 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
243 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
244 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
245 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
246 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
247};
248
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300249/* read <len> bytes to gspca_dev->usb_buf */
250static void reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300251 u8 req,
252 u16 index,
253 u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300254{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300255 int ret;
256
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300257#ifdef GSPCA_DEBUG
258 if (len > USB_BUF_SZ) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300259 pr_err("reg_r: buffer overflow\n");
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300260 return;
261 }
262#endif
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300263 if (gspca_dev->usb_err < 0)
264 return;
265 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300266 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267 req,
268 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
269 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300270 index,
271 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300273 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300274 pr_err("reg_r err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300275 gspca_dev->usb_err = ret;
276 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300277}
278
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300279/* write one byte */
280static void reg_w_1(struct gspca_dev *gspca_dev,
281 u8 req,
282 u16 value,
283 u16 index,
284 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300286 int ret;
287
288 if (gspca_dev->usb_err < 0)
289 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300290 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300291 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300292 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300293 req,
294 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300295 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300296 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300298 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300299 pr_err("reg_w_1 err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300300 gspca_dev->usb_err = ret;
301 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302}
303
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300304/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300305static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300306 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300308 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309 int ret;
310
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300311 if (gspca_dev->usb_err < 0)
312 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300313 ret = usb_control_msg(dev,
314 usb_sndctrlpipe(dev, 0),
315 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300316 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300317 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300318 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300319 pr_err("reg_w_riv err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300320 gspca_dev->usb_err = ret;
321 return;
322 }
323 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
324 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300325}
326
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300327static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300328 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300330 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300331 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300332 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300333 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300334}
335
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300336static void setup_qtable(struct gspca_dev *gspca_dev,
337 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300338{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300339 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300340
341 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300342 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300343 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300344
345 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300346 for (i = 0; i < 64; i++)
347 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300348}
349
350static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300351 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300352{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300353 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300354 reg_r(gspca_dev, 0x01, 0x0001, 1);
355 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300356 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300357
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300358 msleep(200);
Jean-François Moinecf252202011-05-17 05:32:39 -0300359 reg_r(gspca_dev, 0x01, 0x0001, 1);
360 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300361}
362
Jean-François Moinecf252202011-05-17 05:32:39 -0300363#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300364static void spca504_read_info(struct gspca_dev *gspca_dev)
365{
366 int i;
367 u8 info[6];
368
Jean-François Moinecf252202011-05-17 05:32:39 -0300369 for (i = 0; i < 6; i++) {
370 reg_r(gspca_dev, 0, i, 1);
371 info[i] = gspca_dev->usb_buf[0];
372 }
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300373 PDEBUG(D_STREAM,
374 "Read info: %d %d %d %d %d %d."
375 " Should be 1,0,2,2,0,0",
376 info[0], info[1], info[2],
377 info[3], info[4], info[5]);
378}
Jean-François Moinecf252202011-05-17 05:32:39 -0300379#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300380
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300381static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300382 u8 req,
Jean-François Moinecf252202011-05-17 05:32:39 -0300383 u16 idx, u16 val, u8 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300384{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300385 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300386
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300387 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300388 reg_r(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300389 if (gspca_dev->usb_err < 0)
390 return;
Jean-François Moinecf252202011-05-17 05:32:39 -0300391 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
392 gspca_dev->usb_buf[0], endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 if (!count)
394 return;
395 count = 200;
396 while (--count > 0) {
397 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200398 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300399/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-François Moinecf252202011-05-17 05:32:39 -0300400 reg_r(gspca_dev, 0x01, 0x0001, 1);
401 status = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300402 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300403 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404 status, 200 - count);
405 break;
406 }
407 }
408}
409
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300410static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412 int count = 10;
413
414 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300415 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300416 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 break;
418 msleep(10);
419 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420}
421
422static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
423{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424 int count = 50;
425
426 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300427 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300428 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300429 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300430 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300431 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300432 break;
433 }
434 msleep(10);
435 }
436}
437
Jean-François Moinecf252202011-05-17 05:32:39 -0300438#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300439static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
440{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300441 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300442
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300443 data = gspca_dev->usb_buf;
444 reg_r(gspca_dev, 0x20, 0, 5);
Jean-François Moinecf252202011-05-17 05:32:39 -0300445 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300446 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300447 reg_r(gspca_dev, 0x23, 0, 64);
448 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300449}
Jean-François Moinecf252202011-05-17 05:32:39 -0300450#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451
452static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
453{
454 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300455 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300457 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458 switch (sd->bridge) {
459 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300460 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300462 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300463#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300465#endif
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300466 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300467 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300469 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300470 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300471 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300472
473 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300474 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300476 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300477 break;
478 default:
479/* case BRIDGE_SPCA504B: */
480/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300481 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300482 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300483 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300484 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300485 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486 break;
487 case BRIDGE_SPCA504:
488 Size += 3;
489 if (sd->subtype == AiptekMiniPenCam13) {
490 /* spca504a aiptek */
491 spca504A_acknowledged_command(gspca_dev,
492 0x08, Size, 0,
493 0x80 | (Size & 0x0f), 1);
494 spca504A_acknowledged_command(gspca_dev,
495 1, 3, 0, 0x9f, 0);
496 } else {
497 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
498 }
499 break;
500 case BRIDGE_SPCA504C:
501 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300502 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
503 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504 break;
505 }
506}
507
508static void spca504_wait_status(struct gspca_dev *gspca_dev)
509{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510 int cnt;
511
512 cnt = 256;
513 while (--cnt > 0) {
514 /* With this we get the status, when return 0 it's all ok */
Jean-François Moinecf252202011-05-17 05:32:39 -0300515 reg_r(gspca_dev, 0x06, 0x00, 1);
516 if (gspca_dev->usb_buf[0] == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 return;
518 msleep(10);
519 }
520}
521
522static void spca504B_setQtable(struct gspca_dev *gspca_dev)
523{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300524 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300525 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527}
528
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300529static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530{
531 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300532 u16 reg;
533
534 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300535 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300536}
537
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300538static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300539{
540 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300541 u16 reg;
542
543 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300544 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300545}
546
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300547static void setcolors(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300548{
549 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300550 u16 reg;
551
552 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300553 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300554}
555
556static void init_ctl_reg(struct gspca_dev *gspca_dev)
557{
558 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300559 int pollreg = 1;
560
561 switch (sd->bridge) {
562 case BRIDGE_SPCA504:
563 case BRIDGE_SPCA504C:
564 pollreg = 0;
565 /* fall thru */
566 default:
567/* case BRIDGE_SPCA533: */
568/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300569 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
570 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
571 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572 break;
573 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300574 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
575 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
576 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300577 break;
578 }
579 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300580 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581}
582
583/* this function is called at probe time */
584static int sd_config(struct gspca_dev *gspca_dev,
585 const struct usb_device_id *id)
586{
587 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300589
590 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300592 sd->bridge = id->driver_info >> 8;
593 sd->subtype = id->driver_info;
594
595 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300596
597 /* try to get the firmware as some cam answer 2.0.1.2.2
598 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300599 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300600 switch (gspca_dev->usb_buf[0]) {
601 case 1:
602 break; /* (right bridge/subtype) */
603 case 2:
604 sd->bridge = BRIDGE_SPCA504B;
605 sd->subtype = 0;
606 break;
607 default:
608 return -ENODEV;
609 }
610 }
611
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 switch (sd->bridge) {
613 default:
614/* case BRIDGE_SPCA504B: */
615/* case BRIDGE_SPCA504: */
616/* case BRIDGE_SPCA536: */
617 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300618 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619 break;
620 case BRIDGE_SPCA533:
621 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300622 if (sd->subtype == MegaImageVI) /* 320x240 only */
623 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
624 else
625 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626 break;
627 case BRIDGE_SPCA504C:
628 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300629 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300630 break;
631 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300632 return 0;
633}
634
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300635/* this function is called at probe and resume time */
636static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637{
638 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639
640 switch (sd->bridge) {
641 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300642 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300643 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
644 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
645 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
646 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
647 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300648 /* fall thru */
649 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300650 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300651#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300653#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654 break;
655 case BRIDGE_SPCA536:
Jean-François Moinecf252202011-05-17 05:32:39 -0300656#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300658#endif
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300659 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300660 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300661 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300662 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300663 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 spca504B_WaitCmdStatus(gspca_dev);
665 break;
666 case BRIDGE_SPCA504C: /* pccam600 */
667 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300668 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
669 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670 spca504_wait_status(gspca_dev);
671 if (sd->subtype == LogitechClickSmart420)
672 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300673 spca504A_clicksmart420_open_data,
674 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300675 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300676 write_vector(gspca_dev, spca504_pccam600_open_data,
677 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300678 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679 break;
680 default:
681/* case BRIDGE_SPCA504: */
682 PDEBUG(D_STREAM, "Opening SPCA504");
683 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300684#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300685 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300686#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300687
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
689 spca504A_acknowledged_command(gspca_dev, 0x24,
690 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200691 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692 spca504A_acknowledged_command(gspca_dev, 0x24,
693 8, 3, 0x9e, 0);
694
695 spca504A_acknowledged_command(gspca_dev, 0x24,
696 0, 0, 0x9d, 1);
697 /******************************/
698 /* spca504a aiptek */
699 spca504A_acknowledged_command(gspca_dev, 0x08,
700 6, 0, 0x86, 1);
701/* reg_write (dev, 0, 0x2000, 0); */
702/* reg_write (dev, 0, 0x2883, 1); */
703/* spca504A_acknowledged_command (gspca_dev, 0x08,
704 6, 0, 0x86, 1); */
705/* spca504A_acknowledged_command (gspca_dev, 0x24,
706 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300707 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
708 /* L92 sno1t.txt */
709 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710 spca504A_acknowledged_command(gspca_dev, 0x01,
711 0x0f, 0, 0xff, 0);
712 }
713 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300714 reg_w_riv(gspca_dev, 0, 0x2000, 0);
715 reg_w_riv(gspca_dev, 0, 0x2883, 1);
716 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717 break;
718 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300719 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720}
721
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300722static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723{
724 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300727 /* create the JPEG header */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300728 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
729 0x22); /* JPEG 411 */
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300730 jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300731
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732 if (sd->bridge == BRIDGE_SPCA504B)
733 spca504B_setQtable(gspca_dev);
734 spca504B_SetSizeType(gspca_dev);
735 switch (sd->bridge) {
736 default:
737/* case BRIDGE_SPCA504B: */
738/* case BRIDGE_SPCA533: */
739/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300740 switch (sd->subtype) {
741 case MegapixV4:
742 case LogitechClickSmart820:
743 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300744 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300746 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300747 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300748 break;
749 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300750 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300752 spca504B_PollingDataReady(gspca_dev);
753 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300754 }
755 break;
756 case BRIDGE_SPCA504:
757 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300758#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300759 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300760#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300761
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
763 spca504A_acknowledged_command(gspca_dev, 0x24,
764 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200765 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300766 spca504A_acknowledged_command(gspca_dev, 0x24,
767 8, 3, 0x9e, 0);
768 spca504A_acknowledged_command(gspca_dev, 0x24,
769 0, 0, 0x9d, 1);
770 } else {
771 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-François Moinecf252202011-05-17 05:32:39 -0300772#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300773 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300774#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
776 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
777 }
778 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300779 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
780 /* L92 sno1t.txt */
781 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782 break;
783 case BRIDGE_SPCA504C:
784 if (sd->subtype == LogitechClickSmart420) {
785 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300786 spca504A_clicksmart420_init_data,
787 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300789 write_vector(gspca_dev, spca504_pccam600_init_data,
790 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300792 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300793 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
794 /* auto exposure */
795 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
796 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797
798 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300799 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
800 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 spca504B_SetSizeType(gspca_dev);
802 break;
803 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300804 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300805 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806}
807
808static void sd_stopN(struct gspca_dev *gspca_dev)
809{
810 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811
812 switch (sd->bridge) {
813 default:
814/* case BRIDGE_SPCA533: */
815/* case BRIDGE_SPCA536: */
816/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300817 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300819 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820 break;
821 case BRIDGE_SPCA504:
822 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300823 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824
825 if (sd->subtype == AiptekMiniPenCam13) {
826 /* spca504a aiptek */
827/* spca504A_acknowledged_command(gspca_dev, 0x08,
828 6, 0, 0x86, 1); */
829 spca504A_acknowledged_command(gspca_dev, 0x24,
830 0x00, 0x00, 0x9d, 1);
831 spca504A_acknowledged_command(gspca_dev, 0x01,
832 0x0f, 0x00, 0xff, 1);
833 } else {
834 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300835 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 }
837 break;
838 }
839}
840
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300842 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300843 int len) /* iso packet length */
844{
845 struct sd *sd = (struct sd *) gspca_dev;
846 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300847 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300848
849/* frames are jpeg 4.1.1 without 0xff escape */
850 switch (sd->bridge) {
851 case BRIDGE_SPCA533:
852 if (data[0] == 0xff) {
853 if (data[1] != 0x01) { /* drop packet */
854/* gspca_dev->last_packet_type = DISCARD_PACKET; */
855 return;
856 }
857 sof = 1;
858 data += SPCA533_OFFSET_DATA;
859 len -= SPCA533_OFFSET_DATA;
860 } else {
861 data += 1;
862 len -= 1;
863 }
864 break;
865 case BRIDGE_SPCA536:
866 if (data[0] == 0xff) {
867 sof = 1;
868 data += SPCA536_OFFSET_DATA;
869 len -= SPCA536_OFFSET_DATA;
870 } else {
871 data += 2;
872 len -= 2;
873 }
874 break;
875 default:
876/* case BRIDGE_SPCA504: */
877/* case BRIDGE_SPCA504B: */
878 switch (data[0]) {
879 case 0xfe: /* start of frame */
880 sof = 1;
881 data += SPCA50X_OFFSET_DATA;
882 len -= SPCA50X_OFFSET_DATA;
883 break;
884 case 0xff: /* drop packet */
885/* gspca_dev->last_packet_type = DISCARD_PACKET; */
886 return;
887 default:
888 data += 1;
889 len -= 1;
890 break;
891 }
892 break;
893 case BRIDGE_SPCA504C:
894 switch (data[0]) {
895 case 0xfe: /* start of frame */
896 sof = 1;
897 data += SPCA504_PCCAM600_OFFSET_DATA;
898 len -= SPCA504_PCCAM600_OFFSET_DATA;
899 break;
900 case 0xff: /* drop packet */
901/* gspca_dev->last_packet_type = DISCARD_PACKET; */
902 return;
903 default:
904 data += 1;
905 len -= 1;
906 break;
907 }
908 break;
909 }
910 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300911 gspca_frame_add(gspca_dev, LAST_PACKET,
912 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913
914 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300915 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300916 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 }
918
919 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300920 i = 0;
921 do {
922 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300923 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300924 data, i + 1);
925 len -= i;
926 data += i;
927 *data = 0x00;
928 i = 0;
929 }
930 i++;
931 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300932 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300933}
934
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300935static int sd_set_jcomp(struct gspca_dev *gspca_dev,
936 struct v4l2_jpegcompression *jcomp)
937{
938 struct sd *sd = (struct sd *) gspca_dev;
939
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300940 v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
941 return 0;
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300942}
943
944static int sd_get_jcomp(struct gspca_dev *gspca_dev,
945 struct v4l2_jpegcompression *jcomp)
946{
947 struct sd *sd = (struct sd *) gspca_dev;
948
949 memset(jcomp, 0, sizeof *jcomp);
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300950 jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -0300951 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
952 | V4L2_JPEG_MARKER_DQT;
953 return 0;
954}
955
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300956static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
957{
958 struct gspca_dev *gspca_dev =
959 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
960 struct sd *sd = (struct sd *)gspca_dev;
961
962 gspca_dev->usb_err = 0;
963
964 if (!gspca_dev->streaming)
965 return 0;
966
967 switch (ctrl->id) {
968 case V4L2_CID_BRIGHTNESS:
969 setbrightness(gspca_dev, ctrl->val);
970 break;
971 case V4L2_CID_CONTRAST:
972 setcontrast(gspca_dev, ctrl->val);
973 break;
974 case V4L2_CID_SATURATION:
975 setcolors(gspca_dev, ctrl->val);
976 break;
977 case V4L2_CID_AUTOGAIN:
978 sd->autogain = ctrl->val;
979 break;
980 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
981 jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
982 break;
983 }
984 return gspca_dev->usb_err;
985}
986
987static const struct v4l2_ctrl_ops sd_ctrl_ops = {
988 .s_ctrl = sd_s_ctrl,
989};
990
991static int sd_init_controls(struct gspca_dev *gspca_dev)
992{
993 struct sd *sd = (struct sd *)gspca_dev;
994 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
995
996 gspca_dev->vdev.ctrl_handler = hdl;
997 v4l2_ctrl_handler_init(hdl, 5);
998 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
999 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
1000 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1001 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
1002 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1003 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
1004 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1005 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
1006 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1007 V4L2_CID_JPEG_COMPRESSION_QUALITY,
1008 QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
1009
1010 if (hdl->error) {
1011 pr_err("Could not initialize controls\n");
1012 return hdl->error;
1013 }
1014 return 0;
1015}
1016
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001018static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001019 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001020 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001021 .init = sd_init,
Hans Verkuiled5cd6b2012-05-16 08:49:10 -03001022 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001023 .start = sd_start,
1024 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001025 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine77ac0ba2009-03-02 06:40:52 -03001026 .get_jcomp = sd_get_jcomp,
1027 .set_jcomp = sd_set_jcomp,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001028};
1029
1030/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001031#define BS(bridge, subtype) \
1032 .driver_info = (BRIDGE_ ## bridge << 8) \
1033 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -03001034static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001035 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1036 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1037 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1038 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1039 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1040 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1041 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1042 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1043 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1044 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1045 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1046 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1047 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1048 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1049 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1050 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1051 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1052 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001053 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001054 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001055 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001056 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1057 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1058 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1059 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1060 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1061 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1062 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1063 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1064 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1065 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1066 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1067 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1068 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1069 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1070 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1071 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1072 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1073 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1074 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1075 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1076 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1077 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1078 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1079 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1080 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1081 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1082 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1083 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1084 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1085 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1086 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1087 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1088 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1089 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1090 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1091 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1092 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1093 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001094 {}
1095};
1096MODULE_DEVICE_TABLE(usb, device_table);
1097
1098/* -- device connect -- */
1099static int sd_probe(struct usb_interface *intf,
1100 const struct usb_device_id *id)
1101{
1102 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1103 THIS_MODULE);
1104}
1105
1106static struct usb_driver sd_driver = {
1107 .name = MODULE_NAME,
1108 .id_table = device_table,
1109 .probe = sd_probe,
1110 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001111#ifdef CONFIG_PM
1112 .suspend = gspca_suspend,
1113 .resume = gspca_resume,
1114#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001115};
1116
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08001117module_usb_driver(sd_driver);