2 * Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
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
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.
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
22 #define MODULE_NAME "sonixj"
27 #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
28 static const char version
[] = "2.1.7";
30 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
32 MODULE_LICENSE("GPL");
34 /* specific webcam descriptor */
36 struct gspca_dev gspca_dev
; /* !! must be the first item */
39 unsigned int exposure
;
41 unsigned short brightness
;
42 unsigned char contrast
;
44 unsigned char autogain
;
47 #define AG_CNT_START 13
51 #define BRIDGE_SN9C102P 0
52 #define BRIDGE_SN9C105 1
53 #define BRIDGE_SN9C110 2
54 #define BRIDGE_SN9C120 3
55 #define BRIDGE_SN9C325 4
56 char sensor
; /* Type of image sensor chip */
57 #define SENSOR_HV7131R 0
58 #define SENSOR_MI0360 1
59 #define SENSOR_MO4000 2
60 #define SENSOR_OV7648 3
61 #define SENSOR_OV7660 4
62 unsigned char i2c_base
;
65 /* V4L2 controls supported by the driver */
66 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
);
67 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
);
68 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
);
69 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
);
70 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
);
71 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
);
72 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
);
73 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
);
75 static struct ctrl sd_ctrls
[] = {
78 .id
= V4L2_CID_BRIGHTNESS
,
79 .type
= V4L2_CTRL_TYPE_INTEGER
,
84 #define BRIGHTNESS_DEF 0x7fff
85 .default_value
= BRIGHTNESS_DEF
,
87 .set
= sd_setbrightness
,
88 .get
= sd_getbrightness
,
92 .id
= V4L2_CID_CONTRAST
,
93 .type
= V4L2_CTRL_TYPE_INTEGER
,
98 #define CONTRAST_DEF 63
99 .default_value
= CONTRAST_DEF
,
101 .set
= sd_setcontrast
,
102 .get
= sd_getcontrast
,
106 .id
= V4L2_CID_SATURATION
,
107 .type
= V4L2_CTRL_TYPE_INTEGER
,
112 #define COLOR_DEF 127
113 .default_value
= COLOR_DEF
,
120 .id
= V4L2_CID_AUTOGAIN
,
121 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
126 #define AUTOGAIN_DEF 1
127 .default_value
= AUTOGAIN_DEF
,
129 .set
= sd_setautogain
,
130 .get
= sd_getautogain
,
134 static struct v4l2_pix_format vga_mode
[] = {
135 {160, 120, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
137 .sizeimage
= 160 * 120 * 3 / 8 + 590,
138 .colorspace
= V4L2_COLORSPACE_JPEG
,
140 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
142 .sizeimage
= 320 * 240 * 3 / 8 + 590,
143 .colorspace
= V4L2_COLORSPACE_JPEG
,
145 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
147 .sizeimage
= 640 * 480 * 3 / 8 + 590,
148 .colorspace
= V4L2_COLORSPACE_JPEG
,
152 /*Data from sn9c102p+hv71331r */
153 static const __u8 sn_hv7131
[] = {
154 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
155 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
156 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */
157 /* rega regb regc regd rege regf reg10 reg11 */
158 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
159 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
161 /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
164 static const __u8 sn_mi0360
[] = {
165 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
166 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
167 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
168 /* rega regb regc regd rege regf reg10 reg11 */
169 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
170 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
172 /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
175 static const __u8 sn_mo4000
[] = {
176 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81,
177 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
178 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
179 /* reg9 rega regb regc regd rege regf reg10 reg11*/
180 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00,
181 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b,
183 /* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
184 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7,
185 0xd3, 0xdf, 0xea, 0xf5
188 static const __u8 sn_ov7648
[] = {
189 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
190 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
191 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
194 static const __u8 sn_ov7660
[] = {
195 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
196 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81,
197 /* reg9 rega regb regc regd rege regf reg10 reg11*/
198 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
199 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
200 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, 0x07, 0x00, 0x00,
201 /* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
205 /* sequence specific to the sensors - !! index = SENSOR_xxx */
206 static const __u8
*sn_tb
[] = {
214 static const __u8 regsn20
[] = {
215 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
216 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
218 static const __u8 regsn20_sn9c325
[] = {
219 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
220 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
223 static const __u8 reg84
[] = {
224 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
225 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
226 /* 0x00, 0x00, 0x00, 0x00, 0x00 */
227 0xf7, 0x0f, 0x0a, 0x00, 0x00
229 static const __u8 reg84_sn9c325
[] = {
230 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
231 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
232 0xf8, 0x0f, 0x00, 0x00, 0x00
235 static const __u8 hv7131r_sensor_init
[][8] = {
236 {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
237 {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
238 {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
239 {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
240 {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
241 {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
242 {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
244 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
245 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
246 {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
247 {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
248 {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
249 {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
250 {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
251 {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
253 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
254 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
255 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
256 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
257 {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
259 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
260 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
261 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
262 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
263 {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
266 static const __u8 mi0360_sensor_init
[][8] = {
267 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
268 {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
269 {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
270 {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
271 {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
272 {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
273 {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
274 {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
275 {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
276 {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
277 {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
278 {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
279 {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
280 {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
281 {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
282 {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
283 {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
284 {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
285 {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
286 {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
287 {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
288 {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
289 {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
290 {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
291 {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
292 {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
293 {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
294 {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
295 {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
296 {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
297 {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
298 {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
299 {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
301 {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
302 {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
303 {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
304 {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
305 {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
307 {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
308 {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
309 {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
310 {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
312 {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
313 {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
314 /* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
315 /* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
316 {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
317 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
320 static const __u8 mo4000_sensor_init
[][8] = {
321 {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
322 {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
323 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
324 {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
325 {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
326 {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
327 {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
328 {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
329 {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
330 {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
331 {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
332 {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
333 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
334 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
335 {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
336 {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
337 {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
338 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
339 {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
340 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
343 static const __u8 ov7660_sensor_init
[][8] = {
344 {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
345 {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
346 /* Outformat ?? rawRGB */
347 {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
348 /* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
349 * GAIN BLUE RED VREF */
350 {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
351 /* GAIN BLUE RED VREF */
352 {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
353 /* COM 1 BAVE GEAVE AECHH */
354 {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
355 {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
356 /* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
357 * AECH CLKRC COM7 COM8 */
358 {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
359 /* AECH CLKRC COM7 COM8 */
360 {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
361 {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
362 /* HSTART HSTOP VSTRT VSTOP */
363 {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
364 {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
365 {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
366 /* BOS GBOS GROS ROS (BGGR offset) */
367 /* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
368 * AEW AEB VPT BBIAS */
369 {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
370 /* AEW AEB VPT BBIAS */
371 {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
372 /* GbBIAS RSVD EXHCH EXHCL */
373 {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
374 /* RBIAS ADVFL ASDVFH YAVE */
375 {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
376 /* HSYST HSYEN HREF */
377 {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
378 {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
379 /* ADC ACOM OFON TSLB */
380 {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
381 /* COM11 COM12 COM13 COM14 */
382 {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
383 /* EDGE COM15 COM16 COM17 */
384 {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
385 {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
386 {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
387 {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
388 {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
389 {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
390 {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
391 {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
392 {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
393 {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
394 /* LCC1 LCC2 LCC3 LCC4 */
395 {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
396 {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
397 {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
398 /* band gap reference [0..3] DBLV */
399 {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
400 {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
401 {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
402 {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
403 {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
404 {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
405 {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
406 {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
407 {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
408 {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
409 /****** (some exchanges in the win trace) ******/
410 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
411 /* bits[3..0]reserved */
412 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
413 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
414 /* VREF vertical frame ctrl */
415 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
416 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
417 {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
418 {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
419 {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10},
420 /* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, */
421 /****** (some exchanges in the win trace) ******/
422 {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
423 {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
424 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
425 {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
426 /* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, */
427 /****** (some exchanges in the win trace) ******/
428 /**********startsensor KO if changed !!****/
429 {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
430 {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
431 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
432 {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
433 /* here may start the isoc exchanges */
436 /* reg0x04 reg0x07 reg 0x10 */
437 /* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
439 static const __u8 ov7648_sensor_init
[][8] = {
440 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
441 {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
442 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
443 {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
444 {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
445 {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
446 {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
447 {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
448 {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
449 {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
450 {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
451 {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
452 {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
453 {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
454 {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
455 {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
456 {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
457 {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
458 {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
459 {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
460 {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
461 {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
462 {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
463 {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
464 {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
465 {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
466 {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
467 {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
468 {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
469 /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
470 {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
471 * This is currently setting a
472 * blue tint, and some things more , i leave it here for future test if
473 * somene is having problems with color on this sensor
474 {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
475 {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
476 {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
477 {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
478 {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
479 {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
480 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
481 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
482 {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
483 {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
484 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
485 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
486 {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */
487 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
488 {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
489 {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
490 {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
491 /* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */
495 static const __u8 qtable4
[] = {
496 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
497 0x06, 0x08, 0x0A, 0x11,
498 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
499 0x19, 0x19, 0x17, 0x15,
500 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
501 0x21, 0x2E, 0x21, 0x23,
502 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
503 0x25, 0x29, 0x2C, 0x29,
504 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
505 0x17, 0x1B, 0x29, 0x29,
506 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
507 0x29, 0x29, 0x29, 0x29,
508 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
509 0x29, 0x29, 0x29, 0x29,
510 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
511 0x29, 0x29, 0x29, 0x29
514 /* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
515 static void reg_r(struct gspca_dev
*gspca_dev
,
516 __u16 value
, int len
)
518 usb_control_msg(gspca_dev
->dev
,
519 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
521 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
523 gspca_dev
->usb_buf
, len
,
527 static void reg_w(struct gspca_dev
*gspca_dev
,
532 if (len
<= sizeof gspca_dev
->usb_buf
) {
533 memcpy(gspca_dev
->usb_buf
, buffer
, len
);
534 usb_control_msg(gspca_dev
->dev
,
535 usb_sndctrlpipe(gspca_dev
->dev
, 0),
537 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
539 gspca_dev
->usb_buf
, len
,
544 tmpbuf
= kmalloc(len
, GFP_KERNEL
);
545 memcpy(tmpbuf
, buffer
, len
);
546 usb_control_msg(gspca_dev
->dev
,
547 usb_sndctrlpipe(gspca_dev
->dev
, 0),
549 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_INTERFACE
,
557 /* I2C write 2 bytes */
558 static void i2c_w2(struct gspca_dev
*gspca_dev
,
561 struct sd
*sd
= (struct sd
*) gspca_dev
;
565 mode
[0] = 0x81 | (2 << 4);
566 mode
[1] = sd
->i2c_base
;
573 reg_w(gspca_dev
, 0x08, mode
, 8);
576 /* I2C write 8 bytes */
577 static void i2c_w8(struct gspca_dev
*gspca_dev
,
580 reg_w(gspca_dev
, 0x08, buffer
, 8);
584 /* read 5 bytes in gspca_dev->usb_buf */
585 static void i2c_r5(struct gspca_dev
*gspca_dev
, __u8 reg
)
587 struct sd
*sd
= (struct sd
*) gspca_dev
;
590 mode
[0] = 0x81 | 0x10;
591 mode
[1] = sd
->i2c_base
;
598 i2c_w8(gspca_dev
, mode
);
599 mode
[0] = 0x81 | (5 << 4) | 0x02;
601 i2c_w8(gspca_dev
, mode
);
602 reg_r(gspca_dev
, 0x0a, 5);
605 static int probesensor(struct gspca_dev
*gspca_dev
)
607 struct sd
*sd
= (struct sd
*) gspca_dev
;
609 static const __u8 datasend
[] = { 2, 0 };
610 /* reg val1 val2 val3 val4 */
612 i2c_w2(gspca_dev
, datasend
);
613 /* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
616 reg_w(gspca_dev
, 0x02, ®02
, 1); /* Gpio on */
618 i2c_r5(gspca_dev
, 0); /* read sensor id */
619 if (gspca_dev
->usb_buf
[0] == 0x02
620 && gspca_dev
->usb_buf
[1] == 0x09
621 && gspca_dev
->usb_buf
[2] == 0x01
622 && gspca_dev
->usb_buf
[3] == 0x00
623 && gspca_dev
->usb_buf
[4] == 0x00) {
624 PDEBUG(D_PROBE
, "Find Sensor sn9c102P HV7131R");
625 sd
->sensor
= SENSOR_HV7131R
;
626 return SENSOR_HV7131R
;
628 PDEBUG(D_PROBE
, "Find Sensor %d %d %d",
629 gspca_dev
->usb_buf
[0], gspca_dev
->usb_buf
[1],
630 gspca_dev
->usb_buf
[2]);
631 PDEBUG(D_PROBE
, "Sensor sn9c102P Not found");
635 static int configure_gpio(struct gspca_dev
*gspca_dev
,
638 struct sd
*sd
= (struct sd
*) gspca_dev
;
642 static const __u8 reg9a_def
[] =
643 {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
644 static const __u8 reg9a_sn9c120
[] = /* from win trace */
645 {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
646 static const __u8 reg9a_sn9c325
[] =
647 {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
651 reg_w(gspca_dev
, 0xf1, ®F1
, 1);
653 reg_w(gspca_dev
, 0x01, &sn9c1xx
[0], 1);
654 /*fixme:jfm was [1] en v1*/
657 reg_w(gspca_dev
, 0x01, &sn9c1xx
[1], 2);
658 reg_w(gspca_dev
, 0x08, &sn9c1xx
[8], 2);
659 reg_w(gspca_dev
, 0x17, &sn9c1xx
[0x17], 3);
660 switch (sd
->bridge
) {
662 reg9a
= reg9a_sn9c325
;
665 reg9a
= reg9a_sn9c120
;
671 reg_w(gspca_dev
, 0x9a, reg9a
, 6);
673 data
= 0x60; /*fixme:jfm 60 00 00 (3) */
674 reg_w(gspca_dev
, 0xd4, &data
, 1);
676 reg_w(gspca_dev
, 0x03, &sn9c1xx
[3], 0x0f);
678 switch (sd
->bridge
) {
679 case BRIDGE_SN9C120
: /* from win trace */
681 reg_w(gspca_dev
, 0x01, &data
, 1);
683 reg_w(gspca_dev
, 0x17, &data
, 1);
685 reg_w(gspca_dev
, 0x01, &data
, 1);
689 reg_w(gspca_dev
, 0x01, &data
, 1);
691 reg_w(gspca_dev
, 0x17, &data
, 1);
693 reg_w(gspca_dev
, 0x01, &data
, 1);
697 reg_w(gspca_dev
, 0x01, &data
, 1);
699 reg_w(gspca_dev
, 0x17, &data
, 1);
701 reg_w(gspca_dev
, 0x01, &data
, 1);
704 if (sd
->sensor
== SENSOR_HV7131R
) {
705 if (probesensor(gspca_dev
) < 0)
711 static void hv7131R_InitSensor(struct gspca_dev
*gspca_dev
)
714 static const __u8 SetSensorClk
[] = /* 0x08 Mclk */
715 { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
717 while (hv7131r_sensor_init
[i
][0]) {
718 i2c_w8(gspca_dev
, hv7131r_sensor_init
[i
]);
721 i2c_w8(gspca_dev
, SetSensorClk
);
724 static void mi0360_InitSensor(struct gspca_dev
*gspca_dev
)
728 while (mi0360_sensor_init
[i
][0]) {
729 i2c_w8(gspca_dev
, mi0360_sensor_init
[i
]);
734 static void mo4000_InitSensor(struct gspca_dev
*gspca_dev
)
738 while (mo4000_sensor_init
[i
][0]) {
739 i2c_w8(gspca_dev
, mo4000_sensor_init
[i
]);
744 static void ov7648_InitSensor(struct gspca_dev
*gspca_dev
)
748 while (ov7648_sensor_init
[i
][0]) {
749 i2c_w8(gspca_dev
, ov7648_sensor_init
[i
]);
754 static void ov7660_InitSensor(struct gspca_dev
*gspca_dev
)
758 while (ov7660_sensor_init
[i
][0]) {
759 i2c_w8(gspca_dev
, ov7660_sensor_init
[i
]);
764 /* this function is called at probe time */
765 static int sd_config(struct gspca_dev
*gspca_dev
,
766 const struct usb_device_id
*id
)
768 struct sd
*sd
= (struct sd
*) gspca_dev
;
773 vendor
= id
->idVendor
;
774 product
= id
->idProduct
;
777 case 0x0458: /* Genius */
778 /* switch (product) {
780 sd
->bridge
= BRIDGE_SN9C120
;
781 sd
->sensor
= SENSOR_MI0360
;
787 /* switch (product) {
790 sd
->bridge
= BRIDGE_SN9C105
;
791 sd
->sensor
= SENSOR_OV7660
;
796 case 0x0471: /* Philips */
797 /* switch (product) {
801 sd
->bridge
= BRIDGE_SN9C105
;
802 sd
->sensor
= SENSOR_MI0360
;
807 case 0x0c45: /* Sonix */
810 sd
->bridge
= BRIDGE_SN9C102P
;
811 sd
->sensor
= SENSOR_MI0360
; /* from BW600.inf */
812 /* sd->sensor = SENSOR_HV7131R; * gspcav1 value */
815 /* case 0x607a: * from BW600.inf
816 sd->bridge = BRIDGE_SN9C102P;
817 sd->sensor = SENSOR_OV7648;
821 sd
->bridge
= BRIDGE_SN9C102P
;
822 sd
->sensor
= SENSOR_HV7131R
;
825 /* case 0x607e: * from BW600.inf
826 sd->bridge = BRIDGE_SN9C102P;
827 sd->sensor = SENSOR_OV7630;
831 sd
->bridge
= BRIDGE_SN9C105
;
832 sd
->sensor
= SENSOR_MI0360
;
835 /* case 0x60c8: * from BW600.inf
836 sd->bridge = BRIDGE_SN9C105;
837 sd->sensor = SENSOR_OM6801;
840 /* case 0x60cc: * from BW600.inf
841 sd->bridge = BRIDGE_SN9C105;
842 sd->sensor = SENSOR_HV7131GP;
846 sd
->bridge
= BRIDGE_SN9C105
;
847 sd
->sensor
= SENSOR_MO4000
;
850 /* case 0x60ef: * from BW600.inf
851 sd->bridge = BRIDGE_SN9C105;
852 sd->sensor = SENSOR_ICM105C;
855 /* case 0x60fa: * from BW600.inf
856 sd->bridge = BRIDGE_SN9C105;
857 sd->sensor = SENSOR_OV7648;
861 sd
->bridge
= BRIDGE_SN9C105
;
862 sd
->sensor
= SENSOR_OV7660
;
866 sd
->bridge
= BRIDGE_SN9C105
;
867 sd
->sensor
= SENSOR_HV7131R
;
870 /* case 0x60fe: * from BW600.inf
871 sd->bridge = BRIDGE_SN9C105;
872 sd->sensor = SENSOR_OV7630;
875 /* case 0x6108: * from BW600.inf
876 sd->bridge = BRIDGE_SN9C120;
877 sd->sensor = SENSOR_OM6801;
880 /* case 0x6122: * from BW600.inf
881 sd->bridge = BRIDGE_SN9C110;
882 sd->sensor = SENSOR_ICM105C;
886 /* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */
887 sd
->bridge
= BRIDGE_SN9C325
;
888 sd
->sensor
= SENSOR_OV7648
;
891 /* case 0x6123: * from BW600.inf
892 sd->bridge = BRIDGE_SN9C110;
893 sd->sensor = SENSOR_SanyoCCD;
897 sd
->bridge
= BRIDGE_SN9C110
;
898 sd
->sensor
= SENSOR_MO4000
;
901 /* case 0x612e: * from BW600.inf
902 sd->bridge = BRIDGE_SN9C110;
903 sd->sensor = SENSOR_OV7630;
906 /* case 0x612f: * from BW600.inf
907 sd->bridge = BRIDGE_SN9C110;
908 sd->sensor = SENSOR_ICM105C;
912 sd
->bridge
= BRIDGE_SN9C120
;
913 sd
->sensor
= SENSOR_MI0360
;
917 sd
->bridge
= BRIDGE_SN9C120
;
918 sd
->sensor
= SENSOR_MO4000
;
921 /* case 0x613a: * from BW600.inf
922 sd->bridge = BRIDGE_SN9C120;
923 sd->sensor = SENSOR_OV7648;
927 sd
->bridge
= BRIDGE_SN9C120
;
928 sd
->sensor
= SENSOR_OV7660
;
932 sd
->bridge
= BRIDGE_SN9C120
;
933 sd
->sensor
= SENSOR_HV7131R
;
936 /* case 0x613e: * from BW600.inf
937 sd->bridge = BRIDGE_SN9C120;
938 sd->sensor = SENSOR_OV7630;
944 if (sd
->sensor
< 0) {
945 PDEBUG(D_ERR
, "Invalid vendor/product %04x:%04x",
950 cam
= &gspca_dev
->cam
;
951 cam
->dev_name
= (char *) id
->driver_info
;
953 cam
->cam_mode
= vga_mode
;
954 cam
->nmodes
= ARRAY_SIZE(vga_mode
);
956 sd
->qindex
= 4; /* set the quantization table */
957 sd
->brightness
= BRIGHTNESS_DEF
;
958 sd
->contrast
= CONTRAST_DEF
;
959 sd
->colors
= COLOR_DEF
;
960 sd
->autogain
= AUTOGAIN_DEF
;
964 /* this function is called at open time */
965 static int sd_open(struct gspca_dev
*gspca_dev
)
967 struct sd
*sd
= (struct sd
*) gspca_dev
;
968 /* const __u8 *sn9c1xx; */
970 __u8 regGpio
[] = { 0x29, 0x74 };
972 /* setup a selector by bridge */
974 reg_w(gspca_dev
, 0xf1, ®F1
, 1);
975 reg_r(gspca_dev
, 0x00, 1); /* -> regF1 = 0x00 */
976 regF1
= gspca_dev
->usb_buf
[0];
977 reg_w(gspca_dev
, 0xf1, ®F1
, 1);
978 reg_r(gspca_dev
, 0x00, 1);
979 regF1
= gspca_dev
->usb_buf
[0];
980 switch (sd
->bridge
) {
981 case BRIDGE_SN9C102P
:
984 reg_w(gspca_dev
, 0x02, ®Gpio
[1], 1);
989 reg_w(gspca_dev
, 0x02, regGpio
, 2);
995 reg_w(gspca_dev
, 0x02, ®Gpio
[1], 1);
1001 reg_w(gspca_dev
, 0x02, regGpio
, 2);
1004 /* case BRIDGE_SN9C325: */
1008 reg_w(gspca_dev
, 0x02, ®Gpio
[1], 1);
1013 reg_w(gspca_dev
, 0xf1, ®F1
, 1);
1018 static unsigned int setexposure(struct gspca_dev
*gspca_dev
,
1021 struct sd
*sd
= (struct sd
*) gspca_dev
;
1022 static const __u8 doit
[] = /* update sensor */
1023 { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
1024 static const __u8 sensorgo
[] = /* sensor on */
1025 { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
1026 static const __u8 gainMo
[] =
1027 { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
1029 switch (sd
->sensor
) {
1030 case SENSOR_HV7131R
: {
1032 { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
1034 Expodoit
[3] = expo
>> 16;
1035 Expodoit
[4] = expo
>> 8;
1037 i2c_w8(gspca_dev
, Expodoit
);
1040 case SENSOR_MI0360
: {
1041 __u8 expoMi
[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
1042 { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
1046 else if (expo
< 0x0001)
1048 expoMi
[3] = expo
>> 8;
1050 i2c_w8(gspca_dev
, expoMi
);
1051 i2c_w8(gspca_dev
, doit
);
1052 i2c_w8(gspca_dev
, sensorgo
);
1055 case SENSOR_MO4000
: {
1057 { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
1059 { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
1063 else if (expo
< 0x0001)
1065 expoMof
[3] = (expo
& 0x03fc) >> 2;
1066 i2c_w8(gspca_dev
, expoMof
);
1067 expoMo10
[3] = ((expo
& 0x1c00) >> 10)
1068 | ((expo
& 0x0003) << 4);
1069 i2c_w8(gspca_dev
, expoMo10
);
1070 i2c_w8(gspca_dev
, gainMo
);
1071 PDEBUG(D_CONF
, "set exposure %d",
1072 ((expoMo10
[3] & 0x07) << 10)
1074 | ((expoMo10
[3] & 0x30) >> 4));
1081 static void setbrightness(struct gspca_dev
*gspca_dev
)
1083 struct sd
*sd
= (struct sd
*) gspca_dev
;
1087 switch (sd
->sensor
) {
1088 case SENSOR_HV7131R
:
1089 expo
= sd
->brightness
<< 4;
1090 if (expo
> 0x002dc6c0)
1092 else if (expo
< 0x02a0)
1094 sd
->exposure
= setexposure(gspca_dev
, expo
);
1097 expo
= sd
->brightness
>> 4;
1098 sd
->exposure
= setexposure(gspca_dev
, expo
);
1101 expo
= sd
->brightness
>> 4;
1102 sd
->exposure
= setexposure(gspca_dev
, expo
);
1108 k2
= sd
->brightness
>> 10;
1109 reg_w(gspca_dev
, 0x96, &k2
, 1);
1112 static void setcontrast(struct gspca_dev
*gspca_dev
)
1114 struct sd
*sd
= (struct sd
*) gspca_dev
;
1116 __u8 contrast
[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
1118 if (sd
->sensor
== SENSOR_OV7660
)
1122 contrast
[0] = (k2
+ 1) >> 1;
1123 contrast
[4] = (k2
+ 1) / 5;
1124 reg_w(gspca_dev
, 0x84, contrast
, 6);
1127 static void setcolors(struct gspca_dev
*gspca_dev
)
1129 struct sd
*sd
= (struct sd
*) gspca_dev
;
1133 colour
= sd
->colors
- 128;
1135 data
= (colour
+ 32) & 0x7f; /* blue */
1137 data
= (-colour
+ 32) & 0x7f; /* red */
1138 reg_w(gspca_dev
, 0x05, &data
, 1);
1141 /* -- start the camera -- */
1142 static void sd_start(struct gspca_dev
*gspca_dev
)
1144 struct sd
*sd
= (struct sd
*) gspca_dev
;
1149 const __u8
*sn9c1xx
;
1151 static const __u8 DC29
[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
1152 static const __u8 C0
[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
1153 static const __u8 CA
[] = { 0x28, 0xd8, 0x14, 0xec };
1154 static const __u8 CA_sn9c120
[] =
1155 { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
1156 static const __u8 CE
[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
1157 static const __u8 CE_sn9c325
[] =
1158 { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
1160 sn9c1xx
= sn_tb
[(int) sd
->sensor
];
1161 configure_gpio(gspca_dev
, sn9c1xx
);
1163 /*fixme:jfm this sequence should appear at end of sd_start */
1166 reg_w(gspca_dev, 0x01, &data, 1); */
1167 reg_w(gspca_dev
, 0x15, &sn9c1xx
[0x15], 1);
1168 reg_w(gspca_dev
, 0x16, &sn9c1xx
[0x16], 1);
1169 reg_w(gspca_dev
, 0x12, &sn9c1xx
[0x12], 1);
1170 reg_w(gspca_dev
, 0x13, &sn9c1xx
[0x13], 1);
1171 reg_w(gspca_dev
, 0x18, &sn9c1xx
[0x18], 1);
1172 reg_w(gspca_dev
, 0xd2, &DC29
[0], 1);
1173 reg_w(gspca_dev
, 0xd3, &DC29
[1], 1);
1174 reg_w(gspca_dev
, 0xc6, &DC29
[2], 1);
1175 reg_w(gspca_dev
, 0xc7, &DC29
[3], 1);
1176 reg_w(gspca_dev
, 0xc8, &DC29
[4], 1);
1177 reg_w(gspca_dev
, 0xc9, &DC29
[5], 1);
1178 /*fixme:jfm end of ending sequence */
1179 reg_w(gspca_dev
, 0x18, &sn9c1xx
[0x18], 1);
1180 if (sd
->bridge
== BRIDGE_SN9C325
)
1184 reg_w(gspca_dev
, 0x17, &data
, 1);
1185 reg_w(gspca_dev
, 0x05, &sn9c1xx
[5], 1);
1186 reg_w(gspca_dev
, 0x07, &sn9c1xx
[7], 1);
1187 reg_w(gspca_dev
, 0x06, &sn9c1xx
[6], 1);
1188 reg_w(gspca_dev
, 0x14, &sn9c1xx
[0x14], 1);
1189 if (sd
->bridge
== BRIDGE_SN9C325
) {
1190 reg_w(gspca_dev
, 0x20, regsn20_sn9c325
, 0x11);
1191 for (i
= 0; i
< 8; i
++)
1192 reg_w(gspca_dev
, 0x84, reg84_sn9c325
, 0x15);
1194 reg_w(gspca_dev
, 0x9a, &data
, 1);
1196 reg_w(gspca_dev
, 0x99, &data
, 1);
1198 reg_w(gspca_dev
, 0x20, regsn20
, 0x11);
1199 for (i
= 0; i
< 8; i
++)
1200 reg_w(gspca_dev
, 0x84, reg84
, 0x15);
1202 reg_w(gspca_dev
, 0x9a, &data
, 1);
1204 reg_w(gspca_dev
, 0x99, &data
, 1);
1207 mode
= gspca_dev
->cam
.cam_mode
[(int) gspca_dev
->curr_mode
].priv
;
1210 switch (sd
->sensor
) {
1211 case SENSOR_HV7131R
:
1212 hv7131R_InitSensor(gspca_dev
);
1214 reg1
= 0x46; /* 320 clk 48Mhz */
1216 reg1
= 0x06; /* 640 clk 24Mz */
1219 mi0360_InitSensor(gspca_dev
);
1221 reg1
= 0x46; /* 320 clk 48Mhz */
1223 reg1
= 0x06; /* 640 clk 24Mz */
1226 mo4000_InitSensor(gspca_dev
);
1228 /* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
1229 reg1
= 0x06; /* clk 24Mz */
1231 reg17
= 0x22; /* 640 MCKSIZE */
1232 reg1
= 0x06; /* 640 clk 24Mz */
1238 ov7648_InitSensor(gspca_dev
);
1245 /* case SENSOR_OV7660: */
1246 ov7660_InitSensor(gspca_dev
);
1248 /* reg17 = 0x21; * 320 */
1252 reg17
= 0xa2; /* 640 */
1257 reg_w(gspca_dev
, 0xc0, C0
, 6);
1258 switch (sd
->bridge
) {
1259 case BRIDGE_SN9C120
: /*jfm ?? */
1260 reg_w(gspca_dev
, 0xca, CA_sn9c120
, 4);
1263 reg_w(gspca_dev
, 0xca, CA
, 4);
1266 switch (sd
->bridge
) {
1267 case BRIDGE_SN9C120
: /*jfm ?? */
1268 case BRIDGE_SN9C325
:
1269 reg_w(gspca_dev
, 0xce, CE_sn9c325
, 4);
1272 reg_w(gspca_dev
, 0xce, CE
, 4);
1273 /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
1277 /* here change size mode 0 -> VGA; 1 -> CIF */
1278 data
= 0x40 | sn9c1xx
[0x18] | (mode
<< 4);
1279 reg_w(gspca_dev
, 0x18, &data
, 1);
1281 reg_w(gspca_dev
, 0x100, qtable4
, 0x40);
1282 reg_w(gspca_dev
, 0x140, qtable4
+ 0x40, 0x40);
1284 data
= sn9c1xx
[0x18] | (mode
<< 4);
1285 reg_w(gspca_dev
, 0x18, &data
, 1);
1287 reg_w(gspca_dev
, 0x17, ®17
, 1);
1288 reg_w(gspca_dev
, 0x01, ®1
, 1);
1289 setbrightness(gspca_dev
);
1290 setcontrast(gspca_dev
);
1293 static void sd_stopN(struct gspca_dev
*gspca_dev
)
1295 struct sd
*sd
= (struct sd
*) gspca_dev
;
1296 static const __u8 stophv7131
[] =
1297 { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
1298 static const __u8 stopmi0360
[] =
1299 { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
1302 const __u8
*sn9c1xx
;
1305 switch (sd
->sensor
) {
1306 case SENSOR_HV7131R
:
1307 i2c_w8(gspca_dev
, stophv7131
);
1311 i2c_w8(gspca_dev
, stopmi0360
);
1320 /* case SENSOR_OV7660: */
1323 sn9c1xx
= sn_tb
[(int) sd
->sensor
];
1324 reg_w(gspca_dev
, 0x01, &sn9c1xx
[1], 1);
1325 reg_w(gspca_dev
, 0x17, &sn9c1xx
[0x17], 1);
1326 reg_w(gspca_dev
, 0x01, &sn9c1xx
[1], 1);
1327 reg_w(gspca_dev
, 0x01, &data
, 1);
1329 reg_w(gspca_dev
, 0xf1, ®F1
, 1);
1332 static void sd_stop0(struct gspca_dev
*gspca_dev
)
1336 static void sd_close(struct gspca_dev
*gspca_dev
)
1340 static void setautogain(struct gspca_dev
*gspca_dev
)
1342 struct sd
*sd
= (struct sd
*) gspca_dev
;
1343 /* Thanks S., without your advice, autobright should not work :) */
1346 __u8 luma_mean
= 130;
1347 __u8 luma_delta
= 20;
1349 delta
= sd
->avg_lum
;
1350 if (delta
< luma_mean
- luma_delta
||
1351 delta
> luma_mean
+ luma_delta
) {
1352 switch (sd
->sensor
) {
1353 case SENSOR_HV7131R
:
1354 expotimes
= sd
->exposure
>> 8;
1355 expotimes
+= (luma_mean
- delta
) >> 4;
1358 sd
->exposure
= setexposure(gspca_dev
,
1359 (unsigned int) (expotimes
<< 8));
1363 expotimes
= sd
->exposure
;
1364 expotimes
+= (luma_mean
- delta
) >> 6;
1367 sd
->exposure
= setexposure(gspca_dev
,
1368 (unsigned int) expotimes
);
1369 setcolors(gspca_dev
);
1375 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
1376 struct gspca_frame
*frame
, /* target */
1377 __u8
*data
, /* isoc packet */
1378 int len
) /* iso packet length */
1380 struct sd
*sd
= (struct sd
*) gspca_dev
;
1384 if (sof
>= 0 && data
[sof
] == 0xff && data
[sof
+ 1] == 0xd9) {
1387 gspca_frame_add(gspca_dev
, LAST_PACKET
,
1388 frame
, data
, sof
+ 2);
1391 if (--sd
->ag_cnt
>= 0)
1393 sd
->ag_cnt
= AG_CNT_START
;
1398 avg_lum
= ((data
[sof
+ 29] << 8) | data
[sof
+ 30]) >> 6;
1400 avg_lum
+= ((data
[sof
+ 33] << 8) | data
[sof
+ 34]) >> 6;
1402 avg_lum
+= ((data
[sof
+ 25] << 8) | data
[sof
+ 26]) >> 6;
1404 avg_lum
+= ((data
[sof
+ 37] << 8) | data
[sof
+ 38]) >> 6;
1406 avg_lum
+= ((data
[sof
+ 31] << 8) | data
[sof
+ 32]) >> 4;
1408 sd
->avg_lum
= avg_lum
;
1409 PDEBUG(D_PACK
, "mean lum %d", avg_lum
);
1410 setautogain(gspca_dev
);
1413 if (gspca_dev
->last_packet_type
== LAST_PACKET
) {
1415 /* put the JPEG 422 header */
1416 jpeg_put_header(gspca_dev
, frame
, sd
->qindex
, 0x21);
1418 gspca_frame_add(gspca_dev
, INTER_PACKET
, frame
, data
, len
);
1421 static unsigned int getexposure(struct gspca_dev
*gspca_dev
)
1423 struct sd
*sd
= (struct sd
*) gspca_dev
;
1424 __u8 hexpo
, mexpo
, lexpo
;
1426 switch (sd
->sensor
) {
1427 case SENSOR_HV7131R
:
1428 /* read sensor exposure */
1429 i2c_r5(gspca_dev
, 0x25);
1430 return (gspca_dev
->usb_buf
[0] << 16)
1431 | (gspca_dev
->usb_buf
[1] << 8)
1432 | gspca_dev
->usb_buf
[2];
1434 /* read sensor exposure */
1435 i2c_r5(gspca_dev
, 0x09);
1436 return (gspca_dev
->usb_buf
[0] << 8)
1437 | gspca_dev
->usb_buf
[1];
1439 i2c_r5(gspca_dev
, 0x0e);
1440 hexpo
= 0; /* gspca_dev->usb_buf[1] & 0x07; */
1441 mexpo
= 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
1442 lexpo
= (gspca_dev
->usb_buf
[1] & 0x30) >> 4;
1443 PDEBUG(D_CONF
, "exposure %d",
1444 (hexpo
<< 10) | (mexpo
<< 2) | lexpo
);
1445 return (hexpo
<< 10) | (mexpo
<< 2) | lexpo
;
1447 /* case SENSOR_OV7660: */
1448 /* read sensor exposure */
1449 i2c_r5(gspca_dev
, 0x04);
1450 hexpo
= gspca_dev
->usb_buf
[3] & 0x2f;
1451 lexpo
= gspca_dev
->usb_buf
[0] & 0x02;
1452 i2c_r5(gspca_dev
, 0x08);
1453 mexpo
= gspca_dev
->usb_buf
[2];
1454 return (hexpo
<< 10) | (mexpo
<< 2) | lexpo
;
1458 static void getbrightness(struct gspca_dev
*gspca_dev
)
1460 struct sd
*sd
= (struct sd
*) gspca_dev
;
1462 /* hardcoded registers seem not readable */
1463 switch (sd
->sensor
) {
1464 case SENSOR_HV7131R
:
1465 /* sd->brightness = 0x7fff; */
1466 sd
->brightness
= getexposure(gspca_dev
) >> 4;
1469 sd
->brightness
= getexposure(gspca_dev
) << 4;
1472 /* sd->brightness = 0x1fff; */
1473 sd
->brightness
= getexposure(gspca_dev
) << 4;
1478 static int sd_setbrightness(struct gspca_dev
*gspca_dev
, __s32 val
)
1480 struct sd
*sd
= (struct sd
*) gspca_dev
;
1482 sd
->brightness
= val
;
1483 if (gspca_dev
->streaming
)
1484 setbrightness(gspca_dev
);
1488 static int sd_getbrightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
1490 struct sd
*sd
= (struct sd
*) gspca_dev
;
1492 getbrightness(gspca_dev
);
1493 *val
= sd
->brightness
;
1497 static int sd_setcontrast(struct gspca_dev
*gspca_dev
, __s32 val
)
1499 struct sd
*sd
= (struct sd
*) gspca_dev
;
1502 if (gspca_dev
->streaming
)
1503 setcontrast(gspca_dev
);
1507 static int sd_getcontrast(struct gspca_dev
*gspca_dev
, __s32
*val
)
1509 struct sd
*sd
= (struct sd
*) gspca_dev
;
1511 *val
= sd
->contrast
;
1515 static int sd_setcolors(struct gspca_dev
*gspca_dev
, __s32 val
)
1517 struct sd
*sd
= (struct sd
*) gspca_dev
;
1520 if (gspca_dev
->streaming
)
1521 setcolors(gspca_dev
);
1525 static int sd_getcolors(struct gspca_dev
*gspca_dev
, __s32
*val
)
1527 struct sd
*sd
= (struct sd
*) gspca_dev
;
1533 static int sd_setautogain(struct gspca_dev
*gspca_dev
, __s32 val
)
1535 struct sd
*sd
= (struct sd
*) gspca_dev
;
1539 sd
->ag_cnt
= AG_CNT_START
;
1545 static int sd_getautogain(struct gspca_dev
*gspca_dev
, __s32
*val
)
1547 struct sd
*sd
= (struct sd
*) gspca_dev
;
1549 *val
= sd
->autogain
;
1553 /* sub-driver description */
1554 static const struct sd_desc sd_desc
= {
1555 .name
= MODULE_NAME
,
1557 .nctrls
= ARRAY_SIZE(sd_ctrls
),
1558 .config
= sd_config
,
1564 .pkt_scan
= sd_pkt_scan
,
1567 /* -- module initialisation -- */
1568 #define DVNM(name) .driver_info = (kernel_ulong_t) name
1569 static const __devinitdata
struct usb_device_id device_table
[] = {
1570 #ifndef CONFIG_USB_SN9C102
1571 {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
1572 {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
1573 {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
1574 {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
1575 {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
1577 {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
1578 {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
1579 {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
1580 {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
1581 {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
1582 {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
1583 {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
1584 {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
1585 {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
1586 #ifndef CONFIG_USB_SN9C102
1587 {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
1588 {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
1589 {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
1590 {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
1594 MODULE_DEVICE_TABLE(usb
, device_table
);
1596 /* -- device connect -- */
1597 static int sd_probe(struct usb_interface
*intf
,
1598 const struct usb_device_id
*id
)
1600 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1604 static struct usb_driver sd_driver
= {
1605 .name
= MODULE_NAME
,
1606 .id_table
= device_table
,
1608 .disconnect
= gspca_disconnect
,
1611 /* -- module insert / remove -- */
1612 static int __init
sd_mod_init(void)
1614 if (usb_register(&sd_driver
) < 0)
1616 info("v%s registered", version
);
1619 static void __exit
sd_mod_exit(void)
1621 usb_deregister(&sd_driver
);
1622 info("deregistered");
1625 module_init(sd_mod_init
);
1626 module_exit(sd_mod_exit
);