blob: c73748b2d21f13486dc0938ae117983f45400d66 [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
Hans de Goedeb56ab4c2012-06-27 16:48:33 -030033#define QUALITY 85
34
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030035/* specific webcam descriptor */
36struct sd {
37 struct gspca_dev gspca_dev; /* !! must be the first item */
38
Hans Verkuiled5cd6b2012-05-16 08:49:10 -030039 bool autogain;
40
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030041 u8 bridge;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030042#define BRIDGE_SPCA504 0
43#define BRIDGE_SPCA504B 1
44#define BRIDGE_SPCA504C 2
45#define BRIDGE_SPCA533 3
46#define BRIDGE_SPCA536 4
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -030047 u8 subtype;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048#define AiptekMiniPenCam13 1
49#define LogitechClickSmart420 2
50#define LogitechClickSmart820 3
51#define MegapixV4 4
Johannes Goerneraf5f88c2009-07-09 03:28:46 -030052#define MegaImageVI 5
Jean-Francois Moine71cb2762009-03-03 05:33:41 -030053
Jean-François Moine9a731a32010-06-04 05:26:42 -030054 u8 jpeg_hdr[JPEG_HDR_SZ];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055};
56
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030057static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030058 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
59 .bytesperline = 320,
60 .sizeimage = 320 * 240 * 3 / 8 + 590,
61 .colorspace = V4L2_COLORSPACE_JPEG,
62 .priv = 2},
63 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
64 .bytesperline = 640,
65 .sizeimage = 640 * 480 * 3 / 8 + 590,
66 .colorspace = V4L2_COLORSPACE_JPEG,
67 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068};
69
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030070static const struct v4l2_pix_format custom_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030071 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
72 .bytesperline = 320,
73 .sizeimage = 320 * 240 * 3 / 8 + 590,
74 .colorspace = V4L2_COLORSPACE_JPEG,
75 .priv = 2},
76 {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
77 .bytesperline = 464,
78 .sizeimage = 464 * 480 * 3 / 8 + 590,
79 .colorspace = V4L2_COLORSPACE_JPEG,
80 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081};
82
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030083static const struct v4l2_pix_format vga_mode2[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030084 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
85 .bytesperline = 176,
86 .sizeimage = 176 * 144 * 3 / 8 + 590,
87 .colorspace = V4L2_COLORSPACE_JPEG,
88 .priv = 4},
89 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
90 .bytesperline = 320,
91 .sizeimage = 320 * 240 * 3 / 8 + 590,
92 .colorspace = V4L2_COLORSPACE_JPEG,
93 .priv = 3},
94 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
95 .bytesperline = 352,
96 .sizeimage = 352 * 288 * 3 / 8 + 590,
97 .colorspace = V4L2_COLORSPACE_JPEG,
98 .priv = 2},
99 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
100 .bytesperline = 640,
101 .sizeimage = 640 * 480 * 3 / 8 + 590,
102 .colorspace = V4L2_COLORSPACE_JPEG,
103 .priv = 1},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104};
105
106#define SPCA50X_OFFSET_DATA 10
107#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
108#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
109#define SPCA504_PCCAM600_OFFSET_MODE 5
110#define SPCA504_PCCAM600_OFFSET_DATA 14
111 /* Frame packet header offsets for the spca533 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300112#define SPCA533_OFFSET_DATA 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113#define SPCA533_OFFSET_FRAMSEQ 15
114/* Frame packet header offsets for the spca536 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300115#define SPCA536_OFFSET_DATA 4
116#define SPCA536_OFFSET_FRAMSEQ 1
117
118struct cmd {
119 u8 req;
120 u16 val;
121 u16 idx;
122};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300123
124/* Initialisation data for the Creative PC-CAM 600 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300125static const struct cmd spca504_pccam600_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126/* {0xa0, 0x0000, 0x0503}, * capture mode */
127 {0x00, 0x0000, 0x2000},
128 {0x00, 0x0013, 0x2301},
129 {0x00, 0x0003, 0x2000},
130 {0x00, 0x0001, 0x21ac},
131 {0x00, 0x0001, 0x21a6},
132 {0x00, 0x0000, 0x21a7}, /* brightness */
133 {0x00, 0x0020, 0x21a8}, /* contrast */
134 {0x00, 0x0001, 0x21ac}, /* sat/hue */
135 {0x00, 0x0000, 0x21ad}, /* hue */
136 {0x00, 0x001a, 0x21ae}, /* saturation */
137 {0x00, 0x0002, 0x21a3}, /* gamma */
138 {0x30, 0x0154, 0x0008},
139 {0x30, 0x0004, 0x0006},
140 {0x30, 0x0258, 0x0009},
141 {0x30, 0x0004, 0x0000},
142 {0x30, 0x0093, 0x0004},
143 {0x30, 0x0066, 0x0005},
144 {0x00, 0x0000, 0x2000},
145 {0x00, 0x0013, 0x2301},
146 {0x00, 0x0003, 0x2000},
147 {0x00, 0x0013, 0x2301},
148 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149};
150
151/* Creative PC-CAM 600 specific open data, sent before using the
152 * generic initialisation data from spca504_open_data.
153 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300154static const struct cmd spca504_pccam600_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155 {0x00, 0x0001, 0x2501},
156 {0x20, 0x0500, 0x0001}, /* snapshot mode */
157 {0x00, 0x0003, 0x2880},
158 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300159};
160
161/* Initialisation data for the logitech clicksmart 420 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300162static const struct cmd spca504A_clicksmart420_init_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300163/* {0xa0, 0x0000, 0x0503}, * capture mode */
164 {0x00, 0x0000, 0x2000},
165 {0x00, 0x0013, 0x2301},
166 {0x00, 0x0003, 0x2000},
167 {0x00, 0x0001, 0x21ac},
168 {0x00, 0x0001, 0x21a6},
169 {0x00, 0x0000, 0x21a7}, /* brightness */
170 {0x00, 0x0020, 0x21a8}, /* contrast */
171 {0x00, 0x0001, 0x21ac}, /* sat/hue */
172 {0x00, 0x0000, 0x21ad}, /* hue */
173 {0x00, 0x001a, 0x21ae}, /* saturation */
174 {0x00, 0x0002, 0x21a3}, /* gamma */
175 {0x30, 0x0004, 0x000a},
176 {0xb0, 0x0001, 0x0000},
177
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300178 {0xa1, 0x0080, 0x0001},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300179 {0x30, 0x0049, 0x0000},
180 {0x30, 0x0060, 0x0005},
181 {0x0c, 0x0004, 0x0000},
182 {0x00, 0x0000, 0x0000},
183 {0x00, 0x0000, 0x2000},
184 {0x00, 0x0013, 0x2301},
185 {0x00, 0x0003, 0x2000},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300186};
187
188/* clicksmart 420 open data ? */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300189static const struct cmd spca504A_clicksmart420_open_data[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300190 {0x00, 0x0001, 0x2501},
191 {0x20, 0x0502, 0x0000},
192 {0x06, 0x0000, 0x0000},
193 {0x00, 0x0004, 0x2880},
194 {0x00, 0x0001, 0x2881},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300195
196 {0xa0, 0x0000, 0x0503},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197};
198
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300199static const u8 qtable_creative_pccam[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200 { /* Q-table Y-components */
201 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
202 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
203 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
204 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
205 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
206 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
207 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
208 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
209 { /* Q-table C-components */
210 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
211 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
212 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
213 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
214 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
215 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
216 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
217 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
218};
219
220/* FIXME: This Q-table is identical to the Creative PC-CAM one,
221 * except for one byte. Possibly a typo?
222 * NWG: 18/05/2003.
223 */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300224static const u8 qtable_spca504_default[2][64] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300225 { /* Q-table Y-components */
226 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
227 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
228 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
229 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
230 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
231 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
232 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
233 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
234 },
235 { /* Q-table C-components */
236 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
237 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
238 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
239 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
240 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
241 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
242 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
243 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
244};
245
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300246/* read <len> bytes to gspca_dev->usb_buf */
247static void reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300248 u8 req,
249 u16 index,
250 u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300251{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300252 int ret;
253
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300254#ifdef GSPCA_DEBUG
255 if (len > USB_BUF_SZ) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300256 pr_err("reg_r: buffer overflow\n");
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300257 return;
258 }
259#endif
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300260 if (gspca_dev->usb_err < 0)
261 return;
262 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300263 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264 req,
265 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
266 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300267 index,
268 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300270 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300271 pr_err("reg_r err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300272 gspca_dev->usb_err = ret;
273 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274}
275
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300276/* write one byte */
277static void reg_w_1(struct gspca_dev *gspca_dev,
278 u8 req,
279 u16 value,
280 u16 index,
281 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300283 int ret;
284
285 if (gspca_dev->usb_err < 0)
286 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300287 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300288 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300289 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290 req,
291 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300292 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300293 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300294 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300295 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300296 pr_err("reg_w_1 err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300297 gspca_dev->usb_err = ret;
298 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300299}
300
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300301/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300302static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300303 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300305 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300306 int ret;
307
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300308 if (gspca_dev->usb_err < 0)
309 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310 ret = usb_control_msg(dev,
311 usb_sndctrlpipe(dev, 0),
312 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300313 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300314 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300315 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300316 pr_err("reg_w_riv err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300317 gspca_dev->usb_err = ret;
318 return;
319 }
320 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
321 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300322}
323
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300324static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300325 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300326{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300327 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300328 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300329 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300331}
332
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300333static void setup_qtable(struct gspca_dev *gspca_dev,
334 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300335{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300336 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300337
338 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300339 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300340 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300341
342 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300343 for (i = 0; i < 64; i++)
344 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300345}
346
347static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300348 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300349{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300350 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300351 reg_r(gspca_dev, 0x01, 0x0001, 1);
352 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300353 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300354
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300355 msleep(200);
Jean-François Moinecf252202011-05-17 05:32:39 -0300356 reg_r(gspca_dev, 0x01, 0x0001, 1);
357 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300358}
359
Jean-François Moinecf252202011-05-17 05:32:39 -0300360#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300361static void spca504_read_info(struct gspca_dev *gspca_dev)
362{
363 int i;
364 u8 info[6];
365
Jean-François Moinecf252202011-05-17 05:32:39 -0300366 for (i = 0; i < 6; i++) {
367 reg_r(gspca_dev, 0, i, 1);
368 info[i] = gspca_dev->usb_buf[0];
369 }
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300370 PDEBUG(D_STREAM,
371 "Read info: %d %d %d %d %d %d."
372 " Should be 1,0,2,2,0,0",
373 info[0], info[1], info[2],
374 info[3], info[4], info[5]);
375}
Jean-François Moinecf252202011-05-17 05:32:39 -0300376#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300377
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300378static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300379 u8 req,
Jean-François Moinecf252202011-05-17 05:32:39 -0300380 u16 idx, u16 val, u8 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300381{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300382 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300383
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300384 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300385 reg_r(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300386 if (gspca_dev->usb_err < 0)
387 return;
Jean-François Moinecf252202011-05-17 05:32:39 -0300388 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
389 gspca_dev->usb_buf[0], endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300390 if (!count)
391 return;
392 count = 200;
393 while (--count > 0) {
394 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200395 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300396/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-François Moinecf252202011-05-17 05:32:39 -0300397 reg_r(gspca_dev, 0x01, 0x0001, 1);
398 status = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300399 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300400 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300401 status, 200 - count);
402 break;
403 }
404 }
405}
406
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300407static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 int count = 10;
410
411 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300412 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300413 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414 break;
415 msleep(10);
416 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417}
418
419static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
420{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300421 int count = 50;
422
423 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300424 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300425 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300426 reg_w_1(gspca_dev, 0x21, 0, 1, 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 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300429 break;
430 }
431 msleep(10);
432 }
433}
434
Jean-François Moinecf252202011-05-17 05:32:39 -0300435#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300436static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
437{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300438 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300439
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300440 data = gspca_dev->usb_buf;
441 reg_r(gspca_dev, 0x20, 0, 5);
Jean-François Moinecf252202011-05-17 05:32:39 -0300442 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300443 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300444 reg_r(gspca_dev, 0x23, 0, 64);
445 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446}
Jean-François Moinecf252202011-05-17 05:32:39 -0300447#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448
449static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
450{
451 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300452 u8 Size;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300454 Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455 switch (sd->bridge) {
456 case BRIDGE_SPCA533:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300457 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300459 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300460#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300462#endif
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300463 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300464 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300466 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300467 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300468 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469
470 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300471 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300472 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300473 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 break;
475 default:
476/* case BRIDGE_SPCA504B: */
477/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300478 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300479 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300480 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300481 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300482 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483 break;
484 case BRIDGE_SPCA504:
485 Size += 3;
486 if (sd->subtype == AiptekMiniPenCam13) {
487 /* spca504a aiptek */
488 spca504A_acknowledged_command(gspca_dev,
489 0x08, Size, 0,
490 0x80 | (Size & 0x0f), 1);
491 spca504A_acknowledged_command(gspca_dev,
492 1, 3, 0, 0x9f, 0);
493 } else {
494 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
495 }
496 break;
497 case BRIDGE_SPCA504C:
498 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300499 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
500 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 break;
502 }
503}
504
505static void spca504_wait_status(struct gspca_dev *gspca_dev)
506{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 int cnt;
508
509 cnt = 256;
510 while (--cnt > 0) {
511 /* With this we get the status, when return 0 it's all ok */
Jean-François Moinecf252202011-05-17 05:32:39 -0300512 reg_r(gspca_dev, 0x06, 0x00, 1);
513 if (gspca_dev->usb_buf[0] == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 return;
515 msleep(10);
516 }
517}
518
519static void spca504B_setQtable(struct gspca_dev *gspca_dev)
520{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300521 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300522 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300523 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524}
525
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300526static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527{
528 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300529 u16 reg;
530
531 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300532 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300533}
534
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300535static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300536{
537 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300538 u16 reg;
539
540 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300541 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300542}
543
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300544static void setcolors(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300545{
546 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300547 u16 reg;
548
549 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300550 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300551}
552
553static void init_ctl_reg(struct gspca_dev *gspca_dev)
554{
555 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300556 int pollreg = 1;
557
558 switch (sd->bridge) {
559 case BRIDGE_SPCA504:
560 case BRIDGE_SPCA504C:
561 pollreg = 0;
562 /* fall thru */
563 default:
564/* case BRIDGE_SPCA533: */
565/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300566 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
567 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
568 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569 break;
570 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300571 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
572 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
573 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574 break;
575 }
576 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300577 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300578}
579
580/* this function is called at probe time */
581static int sd_config(struct gspca_dev *gspca_dev,
582 const struct usb_device_id *id)
583{
584 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300585 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586
587 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300589 sd->bridge = id->driver_info >> 8;
590 sd->subtype = id->driver_info;
591
592 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300593
594 /* try to get the firmware as some cam answer 2.0.1.2.2
595 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300596 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300597 switch (gspca_dev->usb_buf[0]) {
598 case 1:
599 break; /* (right bridge/subtype) */
600 case 2:
601 sd->bridge = BRIDGE_SPCA504B;
602 sd->subtype = 0;
603 break;
604 default:
605 return -ENODEV;
606 }
607 }
608
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300609 switch (sd->bridge) {
610 default:
611/* case BRIDGE_SPCA504B: */
612/* case BRIDGE_SPCA504: */
613/* case BRIDGE_SPCA536: */
614 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300615 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300616 break;
617 case BRIDGE_SPCA533:
618 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300619 if (sd->subtype == MegaImageVI) /* 320x240 only */
620 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
621 else
622 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300623 break;
624 case BRIDGE_SPCA504C:
625 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300626 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300627 break;
628 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300629 return 0;
630}
631
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300632/* this function is called at probe and resume time */
633static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300634{
635 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636
637 switch (sd->bridge) {
638 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300639 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300640 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
641 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
642 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
643 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
644 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300645 /* fall thru */
646 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300647 spca504B_PollingDataReady(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300648#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300649 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300650#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651 break;
652 case BRIDGE_SPCA536:
Jean-François Moinecf252202011-05-17 05:32:39 -0300653#ifdef GSPCA_DEBUG
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654 spca50x_GetFirmware(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300655#endif
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300656 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300657 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300658 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300659 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300660 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 spca504B_WaitCmdStatus(gspca_dev);
662 break;
663 case BRIDGE_SPCA504C: /* pccam600 */
664 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300665 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
666 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 spca504_wait_status(gspca_dev);
668 if (sd->subtype == LogitechClickSmart420)
669 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300670 spca504A_clicksmart420_open_data,
671 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300673 write_vector(gspca_dev, spca504_pccam600_open_data,
674 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300675 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676 break;
677 default:
678/* case BRIDGE_SPCA504: */
679 PDEBUG(D_STREAM, "Opening SPCA504");
680 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300681#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300682 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300683#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300684
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300685 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
686 spca504A_acknowledged_command(gspca_dev, 0x24,
687 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200688 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689 spca504A_acknowledged_command(gspca_dev, 0x24,
690 8, 3, 0x9e, 0);
691
692 spca504A_acknowledged_command(gspca_dev, 0x24,
693 0, 0, 0x9d, 1);
694 /******************************/
695 /* spca504a aiptek */
696 spca504A_acknowledged_command(gspca_dev, 0x08,
697 6, 0, 0x86, 1);
698/* reg_write (dev, 0, 0x2000, 0); */
699/* reg_write (dev, 0, 0x2883, 1); */
700/* spca504A_acknowledged_command (gspca_dev, 0x08,
701 6, 0, 0x86, 1); */
702/* spca504A_acknowledged_command (gspca_dev, 0x24,
703 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300704 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
705 /* L92 sno1t.txt */
706 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 spca504A_acknowledged_command(gspca_dev, 0x01,
708 0x0f, 0, 0xff, 0);
709 }
710 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300711 reg_w_riv(gspca_dev, 0, 0x2000, 0);
712 reg_w_riv(gspca_dev, 0, 0x2883, 1);
713 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300714 break;
715 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300716 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300717}
718
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300719static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720{
721 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300724 /* create the JPEG header */
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300725 jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
726 0x22); /* JPEG 411 */
Hans de Goedeb56ab4c2012-06-27 16:48:33 -0300727 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300728
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729 if (sd->bridge == BRIDGE_SPCA504B)
730 spca504B_setQtable(gspca_dev);
731 spca504B_SetSizeType(gspca_dev);
732 switch (sd->bridge) {
733 default:
734/* case BRIDGE_SPCA504B: */
735/* case BRIDGE_SPCA533: */
736/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300737 switch (sd->subtype) {
738 case MegapixV4:
739 case LogitechClickSmart820:
740 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300741 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300743 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300744 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300745 break;
746 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300747 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300748 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300749 spca504B_PollingDataReady(gspca_dev);
750 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 }
752 break;
753 case BRIDGE_SPCA504:
754 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moinecf252202011-05-17 05:32:39 -0300755#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300756 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300757#endif
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300758
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300759 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
760 spca504A_acknowledged_command(gspca_dev, 0x24,
761 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200762 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763 spca504A_acknowledged_command(gspca_dev, 0x24,
764 8, 3, 0x9e, 0);
765 spca504A_acknowledged_command(gspca_dev, 0x24,
766 0, 0, 0x9d, 1);
767 } else {
768 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-François Moinecf252202011-05-17 05:32:39 -0300769#ifdef GSPCA_DEBUG
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300770 spca504_read_info(gspca_dev);
Jean-François Moinecf252202011-05-17 05:32:39 -0300771#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300772 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
773 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
774 }
775 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300776 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
777 /* L92 sno1t.txt */
778 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300779 break;
780 case BRIDGE_SPCA504C:
781 if (sd->subtype == LogitechClickSmart420) {
782 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300783 spca504A_clicksmart420_init_data,
784 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300785 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300786 write_vector(gspca_dev, spca504_pccam600_init_data,
787 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300789 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300790 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
791 /* auto exposure */
792 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
793 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794
795 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300796 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
797 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300798 spca504B_SetSizeType(gspca_dev);
799 break;
800 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300801 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300802 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803}
804
805static void sd_stopN(struct gspca_dev *gspca_dev)
806{
807 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808
809 switch (sd->bridge) {
810 default:
811/* case BRIDGE_SPCA533: */
812/* case BRIDGE_SPCA536: */
813/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300814 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300815 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300816 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 break;
818 case BRIDGE_SPCA504:
819 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300820 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300821
822 if (sd->subtype == AiptekMiniPenCam13) {
823 /* spca504a aiptek */
824/* spca504A_acknowledged_command(gspca_dev, 0x08,
825 6, 0, 0x86, 1); */
826 spca504A_acknowledged_command(gspca_dev, 0x24,
827 0x00, 0x00, 0x9d, 1);
828 spca504A_acknowledged_command(gspca_dev, 0x01,
829 0x0f, 0x00, 0xff, 1);
830 } else {
831 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300832 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 }
834 break;
835 }
836}
837
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300839 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 int len) /* iso packet length */
841{
842 struct sd *sd = (struct sd *) gspca_dev;
843 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300844 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300845
846/* frames are jpeg 4.1.1 without 0xff escape */
847 switch (sd->bridge) {
848 case BRIDGE_SPCA533:
849 if (data[0] == 0xff) {
850 if (data[1] != 0x01) { /* drop packet */
851/* gspca_dev->last_packet_type = DISCARD_PACKET; */
852 return;
853 }
854 sof = 1;
855 data += SPCA533_OFFSET_DATA;
856 len -= SPCA533_OFFSET_DATA;
857 } else {
858 data += 1;
859 len -= 1;
860 }
861 break;
862 case BRIDGE_SPCA536:
863 if (data[0] == 0xff) {
864 sof = 1;
865 data += SPCA536_OFFSET_DATA;
866 len -= SPCA536_OFFSET_DATA;
867 } else {
868 data += 2;
869 len -= 2;
870 }
871 break;
872 default:
873/* case BRIDGE_SPCA504: */
874/* case BRIDGE_SPCA504B: */
875 switch (data[0]) {
876 case 0xfe: /* start of frame */
877 sof = 1;
878 data += SPCA50X_OFFSET_DATA;
879 len -= SPCA50X_OFFSET_DATA;
880 break;
881 case 0xff: /* drop packet */
882/* gspca_dev->last_packet_type = DISCARD_PACKET; */
883 return;
884 default:
885 data += 1;
886 len -= 1;
887 break;
888 }
889 break;
890 case BRIDGE_SPCA504C:
891 switch (data[0]) {
892 case 0xfe: /* start of frame */
893 sof = 1;
894 data += SPCA504_PCCAM600_OFFSET_DATA;
895 len -= SPCA504_PCCAM600_OFFSET_DATA;
896 break;
897 case 0xff: /* drop packet */
898/* gspca_dev->last_packet_type = DISCARD_PACKET; */
899 return;
900 default:
901 data += 1;
902 len -= 1;
903 break;
904 }
905 break;
906 }
907 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300908 gspca_frame_add(gspca_dev, LAST_PACKET,
909 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910
911 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300912 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300913 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300914 }
915
916 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300917 i = 0;
918 do {
919 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300920 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300921 data, i + 1);
922 len -= i;
923 data += i;
924 *data = 0x00;
925 i = 0;
926 }
927 i++;
928 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300929 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930}
931
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300932static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
933{
934 struct gspca_dev *gspca_dev =
935 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
936 struct sd *sd = (struct sd *)gspca_dev;
937
938 gspca_dev->usb_err = 0;
939
940 if (!gspca_dev->streaming)
941 return 0;
942
943 switch (ctrl->id) {
944 case V4L2_CID_BRIGHTNESS:
945 setbrightness(gspca_dev, ctrl->val);
946 break;
947 case V4L2_CID_CONTRAST:
948 setcontrast(gspca_dev, ctrl->val);
949 break;
950 case V4L2_CID_SATURATION:
951 setcolors(gspca_dev, ctrl->val);
952 break;
953 case V4L2_CID_AUTOGAIN:
954 sd->autogain = ctrl->val;
955 break;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300956 }
957 return gspca_dev->usb_err;
958}
959
960static const struct v4l2_ctrl_ops sd_ctrl_ops = {
961 .s_ctrl = sd_s_ctrl,
962};
963
964static int sd_init_controls(struct gspca_dev *gspca_dev)
965{
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300966 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
967
968 gspca_dev->vdev.ctrl_handler = hdl;
Hans de Goedeb56ab4c2012-06-27 16:48:33 -0300969 v4l2_ctrl_handler_init(hdl, 4);
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300970 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
971 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
972 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
973 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
974 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
975 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
976 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
977 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300978
979 if (hdl->error) {
980 pr_err("Could not initialize controls\n");
981 return hdl->error;
982 }
983 return 0;
984}
985
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300986/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300987static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300988 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300989 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300990 .init = sd_init,
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300991 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300992 .start = sd_start,
993 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994 .pkt_scan = sd_pkt_scan,
995};
996
997/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300998#define BS(bridge, subtype) \
999 .driver_info = (BRIDGE_ ## bridge << 8) \
1000 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -03001001static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001002 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1003 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1004 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1005 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1006 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1007 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1008 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1009 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1010 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1011 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1012 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1013 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1014 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1015 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1016 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1017 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1018 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1019 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001020 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001021 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001022 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001023 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1024 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1025 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1026 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1027 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1028 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1029 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1030 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1031 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1032 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1033 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1034 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1035 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1036 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1037 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1038 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1039 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1040 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1041 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1042 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1043 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1044 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1045 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1047 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1048 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1049 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1050 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1051 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1052 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1053 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1054 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1055 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1056 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1057 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1058 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1059 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1060 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001061 {}
1062};
1063MODULE_DEVICE_TABLE(usb, device_table);
1064
1065/* -- device connect -- */
1066static int sd_probe(struct usb_interface *intf,
1067 const struct usb_device_id *id)
1068{
1069 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1070 THIS_MODULE);
1071}
1072
1073static struct usb_driver sd_driver = {
1074 .name = MODULE_NAME,
1075 .id_table = device_table,
1076 .probe = sd_probe,
1077 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001078#ifdef CONFIG_PM
1079 .suspend = gspca_suspend,
1080 .resume = gspca_resume,
1081#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001082};
1083
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08001084module_usb_driver(sd_driver);