blob: 46c9f2229a18675c6a1ca39528dab2196937c0c5 [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 if (len > USB_BUF_SZ) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300255 PERR("reg_r: buffer overflow\n");
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300256 return;
257 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300258 if (gspca_dev->usb_err < 0)
259 return;
260 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300261 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300262 req,
263 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
264 0, /* value */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300265 index,
266 len ? gspca_dev->usb_buf : NULL, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300268 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300269 pr_err("reg_r err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300270 gspca_dev->usb_err = ret;
271 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272}
273
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300274/* write one byte */
275static void reg_w_1(struct gspca_dev *gspca_dev,
276 u8 req,
277 u16 value,
278 u16 index,
279 u16 byte)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300281 int ret;
282
283 if (gspca_dev->usb_err < 0)
284 return;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300285 gspca_dev->usb_buf[0] = byte;
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300286 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300287 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300288 req,
289 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300290 value, index,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300291 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300292 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300293 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300294 pr_err("reg_w_1 err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300295 gspca_dev->usb_err = ret;
296 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297}
298
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300299/* write req / index / value */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300300static void reg_w_riv(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300301 u8 req, u16 index, u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300303 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304 int ret;
305
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300306 if (gspca_dev->usb_err < 0)
307 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308 ret = usb_control_msg(dev,
309 usb_sndctrlpipe(dev, 0),
310 req,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300311 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300312 value, index, NULL, 0, 500);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300313 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300314 pr_err("reg_w_riv err %d\n", ret);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300315 gspca_dev->usb_err = ret;
316 return;
317 }
318 PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
319 req, index, value);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300320}
321
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300322static void write_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300323 const struct cmd *data, int ncmds)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300324{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300325 while (--ncmds >= 0) {
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300326 reg_w_riv(gspca_dev, data->req, data->idx, data->val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300327 data++;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300328 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329}
330
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300331static void setup_qtable(struct gspca_dev *gspca_dev,
332 const u8 qtable[2][64])
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300333{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300334 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300335
336 /* loop over y components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300337 for (i = 0; i < 64; i++)
Jean-François Moine780e3122010-10-19 04:29:10 -0300338 reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300339
340 /* loop over c components */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300341 for (i = 0; i < 64; i++)
342 reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300343}
344
345static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300346 u8 req, u16 idx, u16 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300347{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300348 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300349 reg_r(gspca_dev, 0x01, 0x0001, 1);
350 PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300351 reg_w_riv(gspca_dev, req, idx, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300352
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300353 msleep(200);
Jean-François Moinecf252202011-05-17 05:32:39 -0300354 reg_r(gspca_dev, 0x01, 0x0001, 1);
355 PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300356}
357
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300358static void spca504_read_info(struct gspca_dev *gspca_dev)
359{
360 int i;
361 u8 info[6];
362
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300363 if (gspca_debug < D_STREAM)
364 return;
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}
376
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300377static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300378 u8 req,
Jean-François Moinecf252202011-05-17 05:32:39 -0300379 u16 idx, u16 val, u8 endcode, u8 count)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300380{
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300381 u16 status;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300383 reg_w_riv(gspca_dev, req, idx, val);
Jean-François Moinecf252202011-05-17 05:32:39 -0300384 reg_r(gspca_dev, 0x01, 0x0001, 1);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300385 if (gspca_dev->usb_err < 0)
386 return;
Jean-François Moinecf252202011-05-17 05:32:39 -0300387 PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
388 gspca_dev->usb_buf[0], endcode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300389 if (!count)
390 return;
391 count = 200;
392 while (--count > 0) {
393 msleep(10);
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200394 /* gsmart mini2 write a each wait setting 1 ms is enough */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300395/* reg_w_riv(gspca_dev, req, idx, val); */
Jean-François Moinecf252202011-05-17 05:32:39 -0300396 reg_r(gspca_dev, 0x01, 0x0001, 1);
397 status = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398 if (status == endcode) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300399 PDEBUG(D_FRAM, "status 0x%04x after wait %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 status, 200 - count);
401 break;
402 }
403 }
404}
405
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300406static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408 int count = 10;
409
410 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300411 reg_r(gspca_dev, 0x21, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300412 if ((gspca_dev->usb_buf[0] & 0x01) == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300413 break;
414 msleep(10);
415 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416}
417
418static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
419{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420 int count = 50;
421
422 while (--count > 0) {
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300423 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300424 if (gspca_dev->usb_buf[0] != 0) {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300425 reg_w_1(gspca_dev, 0x21, 0, 1, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300426 reg_r(gspca_dev, 0x21, 1, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300427 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428 break;
429 }
430 msleep(10);
431 }
432}
433
434static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
435{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300436 u8 *data;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300437
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300438 if (gspca_debug < D_STREAM)
439 return;
440
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300441 data = gspca_dev->usb_buf;
442 reg_r(gspca_dev, 0x20, 0, 5);
Jean-François Moinecf252202011-05-17 05:32:39 -0300443 PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300444 data[0], data[1], data[2], data[3], data[4]);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300445 reg_r(gspca_dev, 0x23, 0, 64);
446 reg_r(gspca_dev, 0x23, 1, 64);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300447}
448
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-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 spca50x_GetFirmware(gspca_dev);
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300461
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300462 reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300463 reg_r(gspca_dev, 0x24, 8, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300465 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300466 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300467 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468
469 /* Init the cam width height with some values get on init ? */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300470 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300472 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 break;
474 default:
475/* case BRIDGE_SPCA504B: */
476/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300477 reg_w_1(gspca_dev, 0x25, 0, 4, Size);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300478 reg_r(gspca_dev, 0x25, 4, 1); /* size */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300479 reg_w_1(gspca_dev, 0x27, 0, 0, 6);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300480 reg_r(gspca_dev, 0x27, 0, 1); /* type */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300481 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 break;
483 case BRIDGE_SPCA504:
484 Size += 3;
485 if (sd->subtype == AiptekMiniPenCam13) {
486 /* spca504a aiptek */
487 spca504A_acknowledged_command(gspca_dev,
488 0x08, Size, 0,
489 0x80 | (Size & 0x0f), 1);
490 spca504A_acknowledged_command(gspca_dev,
491 1, 3, 0, 0x9f, 0);
492 } else {
493 spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
494 }
495 break;
496 case BRIDGE_SPCA504C:
497 /* capture mode */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300498 reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
499 reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 break;
501 }
502}
503
504static void spca504_wait_status(struct gspca_dev *gspca_dev)
505{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 int cnt;
507
508 cnt = 256;
509 while (--cnt > 0) {
510 /* With this we get the status, when return 0 it's all ok */
Jean-François Moinecf252202011-05-17 05:32:39 -0300511 reg_r(gspca_dev, 0x06, 0x00, 1);
512 if (gspca_dev->usb_buf[0] == 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 return;
514 msleep(10);
515 }
516}
517
518static void spca504B_setQtable(struct gspca_dev *gspca_dev)
519{
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300520 reg_w_1(gspca_dev, 0x26, 0, 0, 3);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300521 reg_r(gspca_dev, 0x26, 0, 1);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523}
524
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300525static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526{
527 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300528 u16 reg;
529
530 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300531 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300532}
533
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300534static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300535{
536 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300537 u16 reg;
538
539 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300540 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300541}
542
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300543static void setcolors(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300544{
545 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300546 u16 reg;
547
548 reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300549 reg_w_riv(gspca_dev, 0x00, reg, val);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300550}
551
552static void init_ctl_reg(struct gspca_dev *gspca_dev)
553{
554 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555 int pollreg = 1;
556
557 switch (sd->bridge) {
558 case BRIDGE_SPCA504:
559 case BRIDGE_SPCA504C:
560 pollreg = 0;
561 /* fall thru */
562 default:
563/* case BRIDGE_SPCA533: */
564/* case BRIDGE_SPCA504B: */
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300565 reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
566 reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
567 reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568 break;
569 case BRIDGE_SPCA536:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300570 reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
571 reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
572 reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300573 break;
574 }
575 if (pollreg)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300576 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300577}
578
579/* this function is called at probe time */
580static int sd_config(struct gspca_dev *gspca_dev,
581 const struct usb_device_id *id)
582{
583 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300585
586 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300588 sd->bridge = id->driver_info >> 8;
589 sd->subtype = id->driver_info;
590
591 if (sd->subtype == AiptekMiniPenCam13) {
Jean-François Moine780e3122010-10-19 04:29:10 -0300592
593 /* try to get the firmware as some cam answer 2.0.1.2.2
594 * and should be a spca504b then overwrite that setting */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300595 reg_r(gspca_dev, 0x20, 0, 1);
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300596 switch (gspca_dev->usb_buf[0]) {
597 case 1:
598 break; /* (right bridge/subtype) */
599 case 2:
600 sd->bridge = BRIDGE_SPCA504B;
601 sd->subtype = 0;
602 break;
603 default:
604 return -ENODEV;
605 }
606 }
607
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300608 switch (sd->bridge) {
609 default:
610/* case BRIDGE_SPCA504B: */
611/* case BRIDGE_SPCA504: */
612/* case BRIDGE_SPCA536: */
613 cam->cam_mode = vga_mode;
Jean-François Moine780e3122010-10-19 04:29:10 -0300614 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615 break;
616 case BRIDGE_SPCA533:
617 cam->cam_mode = custom_mode;
Johannes Goerneraf5f88c2009-07-09 03:28:46 -0300618 if (sd->subtype == MegaImageVI) /* 320x240 only */
619 cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
620 else
621 cam->nmodes = ARRAY_SIZE(custom_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300622 break;
623 case BRIDGE_SPCA504C:
624 cam->cam_mode = vga_mode2;
Mauro Carvalho Chehabd6f76b92009-07-22 00:02:29 -0300625 cam->nmodes = ARRAY_SIZE(vga_mode2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626 break;
627 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300628 return 0;
629}
630
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300631/* this function is called at probe and resume time */
632static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633{
634 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300635
636 switch (sd->bridge) {
637 case BRIDGE_SPCA504B:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300638 reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300639 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
640 reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
641 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
642 reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
643 reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300644 /* fall thru */
645 case BRIDGE_SPCA533:
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300646 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647 spca50x_GetFirmware(gspca_dev);
648 break;
649 case BRIDGE_SPCA536:
650 spca50x_GetFirmware(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300651 reg_r(gspca_dev, 0x00, 0x5002, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300652 reg_w_1(gspca_dev, 0x24, 0, 0, 0);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300653 reg_r(gspca_dev, 0x24, 0, 1);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300654 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300655 reg_w_riv(gspca_dev, 0x34, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656 spca504B_WaitCmdStatus(gspca_dev);
657 break;
658 case BRIDGE_SPCA504C: /* pccam600 */
659 PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300660 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
661 reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300662 spca504_wait_status(gspca_dev);
663 if (sd->subtype == LogitechClickSmart420)
664 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300665 spca504A_clicksmart420_open_data,
666 ARRAY_SIZE(spca504A_clicksmart420_open_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 else
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300668 write_vector(gspca_dev, spca504_pccam600_open_data,
669 ARRAY_SIZE(spca504_pccam600_open_data));
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300670 setup_qtable(gspca_dev, qtable_creative_pccam);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671 break;
672 default:
673/* case BRIDGE_SPCA504: */
674 PDEBUG(D_STREAM, "Opening SPCA504");
675 if (sd->subtype == AiptekMiniPenCam13) {
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300676 spca504_read_info(gspca_dev);
677
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
679 spca504A_acknowledged_command(gspca_dev, 0x24,
680 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200681 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682 spca504A_acknowledged_command(gspca_dev, 0x24,
683 8, 3, 0x9e, 0);
684
685 spca504A_acknowledged_command(gspca_dev, 0x24,
686 0, 0, 0x9d, 1);
687 /******************************/
688 /* spca504a aiptek */
689 spca504A_acknowledged_command(gspca_dev, 0x08,
690 6, 0, 0x86, 1);
691/* reg_write (dev, 0, 0x2000, 0); */
692/* reg_write (dev, 0, 0x2883, 1); */
693/* spca504A_acknowledged_command (gspca_dev, 0x08,
694 6, 0, 0x86, 1); */
695/* spca504A_acknowledged_command (gspca_dev, 0x24,
696 0, 0, 0x9D, 1); */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300697 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
698 /* L92 sno1t.txt */
699 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300700 spca504A_acknowledged_command(gspca_dev, 0x01,
701 0x0f, 0, 0xff, 0);
702 }
703 /* setup qtable */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300704 reg_w_riv(gspca_dev, 0, 0x2000, 0);
705 reg_w_riv(gspca_dev, 0, 0x2883, 1);
706 setup_qtable(gspca_dev, qtable_spca504_default);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 break;
708 }
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300709 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710}
711
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300712static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713{
714 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715 int enable;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300716
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300717 /* create the JPEG header */
Ondrej Zary1966bc22013-08-30 17:54:23 -0300718 jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
719 gspca_dev->pixfmt.width,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300720 0x22); /* JPEG 411 */
Hans de Goedeb56ab4c2012-06-27 16:48:33 -0300721 jpeg_set_qual(sd->jpeg_hdr, QUALITY);
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300722
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723 if (sd->bridge == BRIDGE_SPCA504B)
724 spca504B_setQtable(gspca_dev);
725 spca504B_SetSizeType(gspca_dev);
726 switch (sd->bridge) {
727 default:
728/* case BRIDGE_SPCA504B: */
729/* case BRIDGE_SPCA533: */
730/* case BRIDGE_SPCA536: */
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300731 switch (sd->subtype) {
732 case MegapixV4:
733 case LogitechClickSmart820:
734 case MegaImageVI:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300735 reg_w_riv(gspca_dev, 0xf0, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300737 reg_r(gspca_dev, 0xf0, 4, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300739 break;
740 default:
Jean-Francois Moine07d1c692010-01-10 04:32:11 -0300741 reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300743 spca504B_PollingDataReady(gspca_dev);
744 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 }
746 break;
747 case BRIDGE_SPCA504:
748 if (sd->subtype == AiptekMiniPenCam13) {
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300749 spca504_read_info(gspca_dev);
750
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
752 spca504A_acknowledged_command(gspca_dev, 0x24,
753 8, 3, 0x9e, 1);
Uwe Kleine-Königb27d63d2010-07-01 20:48:44 +0200754 /* Twice sequential need status 0xff->0x9e->0x9d */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300755 spca504A_acknowledged_command(gspca_dev, 0x24,
756 8, 3, 0x9e, 0);
757 spca504A_acknowledged_command(gspca_dev, 0x24,
758 0, 0, 0x9d, 1);
759 } else {
760 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
Jean-Francois Moine6f081262010-01-10 14:39:24 -0300761 spca504_read_info(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762 spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
763 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
764 }
765 spca504B_SetSizeType(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300766 reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
767 /* L92 sno1t.txt */
768 reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769 break;
770 case BRIDGE_SPCA504C:
771 if (sd->subtype == LogitechClickSmart420) {
772 write_vector(gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300773 spca504A_clicksmart420_init_data,
774 ARRAY_SIZE(spca504A_clicksmart420_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775 } else {
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300776 write_vector(gspca_dev, spca504_pccam600_init_data,
777 ARRAY_SIZE(spca504_pccam600_init_data));
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300778 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300779 enable = (sd->autogain ? 0x04 : 0x01);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300780 reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
781 /* auto exposure */
782 reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
783 /* auto whiteness */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300784
785 /* set default exposure compensation and whiteness balance */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300786 reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
787 reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 spca504B_SetSizeType(gspca_dev);
789 break;
790 }
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300791 init_ctl_reg(gspca_dev);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300792 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300793}
794
795static void sd_stopN(struct gspca_dev *gspca_dev)
796{
797 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300798
799 switch (sd->bridge) {
800 default:
801/* case BRIDGE_SPCA533: */
802/* case BRIDGE_SPCA536: */
803/* case BRIDGE_SPCA504B: */
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300804 reg_w_riv(gspca_dev, 0x31, 0, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300805 spca504B_WaitCmdStatus(gspca_dev);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300806 spca504B_PollingDataReady(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 break;
808 case BRIDGE_SPCA504:
809 case BRIDGE_SPCA504C:
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300810 reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811
812 if (sd->subtype == AiptekMiniPenCam13) {
813 /* spca504a aiptek */
814/* spca504A_acknowledged_command(gspca_dev, 0x08,
815 6, 0, 0x86, 1); */
816 spca504A_acknowledged_command(gspca_dev, 0x24,
817 0x00, 0x00, 0x9d, 1);
818 spca504A_acknowledged_command(gspca_dev, 0x01,
819 0x0f, 0x00, 0xff, 1);
820 } else {
821 spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
Jean-Francois Moineecb77682009-12-02 14:39:53 -0300822 reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300823 }
824 break;
825 }
826}
827
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300829 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300830 int len) /* iso packet length */
831{
832 struct sd *sd = (struct sd *) gspca_dev;
833 int i, sof = 0;
Jean-Francois Moine2e1794b2009-08-31 06:15:22 -0300834 static u8 ffd9[] = {0xff, 0xd9};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300835
836/* frames are jpeg 4.1.1 without 0xff escape */
837 switch (sd->bridge) {
838 case BRIDGE_SPCA533:
839 if (data[0] == 0xff) {
840 if (data[1] != 0x01) { /* drop packet */
841/* gspca_dev->last_packet_type = DISCARD_PACKET; */
842 return;
843 }
844 sof = 1;
845 data += SPCA533_OFFSET_DATA;
846 len -= SPCA533_OFFSET_DATA;
847 } else {
848 data += 1;
849 len -= 1;
850 }
851 break;
852 case BRIDGE_SPCA536:
853 if (data[0] == 0xff) {
854 sof = 1;
855 data += SPCA536_OFFSET_DATA;
856 len -= SPCA536_OFFSET_DATA;
857 } else {
858 data += 2;
859 len -= 2;
860 }
861 break;
862 default:
863/* case BRIDGE_SPCA504: */
864/* case BRIDGE_SPCA504B: */
865 switch (data[0]) {
866 case 0xfe: /* start of frame */
867 sof = 1;
868 data += SPCA50X_OFFSET_DATA;
869 len -= SPCA50X_OFFSET_DATA;
870 break;
871 case 0xff: /* drop packet */
872/* gspca_dev->last_packet_type = DISCARD_PACKET; */
873 return;
874 default:
875 data += 1;
876 len -= 1;
877 break;
878 }
879 break;
880 case BRIDGE_SPCA504C:
881 switch (data[0]) {
882 case 0xfe: /* start of frame */
883 sof = 1;
884 data += SPCA504_PCCAM600_OFFSET_DATA;
885 len -= SPCA504_PCCAM600_OFFSET_DATA;
886 break;
887 case 0xff: /* drop packet */
888/* gspca_dev->last_packet_type = DISCARD_PACKET; */
889 return;
890 default:
891 data += 1;
892 len -= 1;
893 break;
894 }
895 break;
896 }
897 if (sof) { /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300898 gspca_frame_add(gspca_dev, LAST_PACKET,
899 ffd9, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300900
901 /* put the JPEG header in the new frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300902 gspca_frame_add(gspca_dev, FIRST_PACKET,
Jean-Francois Moine71cb2762009-03-03 05:33:41 -0300903 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904 }
905
906 /* add 0x00 after 0xff */
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300907 i = 0;
908 do {
909 if (data[i] == 0xff) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300910 gspca_frame_add(gspca_dev, INTER_PACKET,
Jean-Francois Moine59746e12009-04-23 14:33:00 -0300911 data, i + 1);
912 len -= i;
913 data += i;
914 *data = 0x00;
915 i = 0;
916 }
917 i++;
918 } while (i < len);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300919 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920}
921
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300922static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
923{
924 struct gspca_dev *gspca_dev =
925 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
926 struct sd *sd = (struct sd *)gspca_dev;
927
928 gspca_dev->usb_err = 0;
929
930 if (!gspca_dev->streaming)
931 return 0;
932
933 switch (ctrl->id) {
934 case V4L2_CID_BRIGHTNESS:
935 setbrightness(gspca_dev, ctrl->val);
936 break;
937 case V4L2_CID_CONTRAST:
938 setcontrast(gspca_dev, ctrl->val);
939 break;
940 case V4L2_CID_SATURATION:
941 setcolors(gspca_dev, ctrl->val);
942 break;
943 case V4L2_CID_AUTOGAIN:
944 sd->autogain = ctrl->val;
945 break;
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300946 }
947 return gspca_dev->usb_err;
948}
949
950static const struct v4l2_ctrl_ops sd_ctrl_ops = {
951 .s_ctrl = sd_s_ctrl,
952};
953
954static int sd_init_controls(struct gspca_dev *gspca_dev)
955{
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300956 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
957
958 gspca_dev->vdev.ctrl_handler = hdl;
Hans de Goedeb56ab4c2012-06-27 16:48:33 -0300959 v4l2_ctrl_handler_init(hdl, 4);
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300960 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
961 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
962 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
963 V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
964 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
965 V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
966 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
967 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300968
969 if (hdl->error) {
970 pr_err("Could not initialize controls\n");
971 return hdl->error;
972 }
973 return 0;
974}
975
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300976/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300977static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300978 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300979 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300980 .init = sd_init,
Hans Verkuiled5cd6b2012-05-16 08:49:10 -0300981 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300982 .start = sd_start,
983 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300984 .pkt_scan = sd_pkt_scan,
985};
986
987/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300988#define BS(bridge, subtype) \
989 .driver_info = (BRIDGE_ ## bridge << 8) \
990 | (subtype)
Jean-François Moine95c967c2011-01-13 05:20:29 -0300991static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300992 {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
993 {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
994 {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
995 {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
996 {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
997 {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
998 {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
999 {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1000 {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1001 {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1002 {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1003 {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1004 {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1005 {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1006 {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1007 {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1008 {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1009 {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
Jean-Francois Moined41592a2009-12-13 14:11:07 -03001010 {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001011 {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
Johannes Goerneraf5f88c2009-07-09 03:28:46 -03001012 {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001013 {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1014 {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1015 {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1016 {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1017 {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1018 {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1019 {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1020 {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1021 {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1022 {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1023 {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1024 {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1025 {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1026 {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1027 {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1028 {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1029 {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
Hans de Goede858559a22013-11-24 10:03:57 -03001030 {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001031 {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1032 {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1033 {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1034 {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1035 {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1036 {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1037 {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1038 {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1039 {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1040 {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1041 {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1042 {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1043 {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1044 {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1045 {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1046 {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1047 {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1048 {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1049 {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1050 {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1051 {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052 {}
1053};
1054MODULE_DEVICE_TABLE(usb, device_table);
1055
1056/* -- device connect -- */
1057static int sd_probe(struct usb_interface *intf,
1058 const struct usb_device_id *id)
1059{
1060 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1061 THIS_MODULE);
1062}
1063
1064static struct usb_driver sd_driver = {
1065 .name = MODULE_NAME,
1066 .id_table = device_table,
1067 .probe = sd_probe,
1068 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001069#ifdef CONFIG_PM
1070 .suspend = gspca_suspend,
1071 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -03001072 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001073#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001074};
1075
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08001076module_usb_driver(sd_driver);