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 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
155 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
156 /* rega regb regc regd rege regf reg10 reg11 */
157 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */
158 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
159 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
160 /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
164 static const __u8 sn_mi0360[] = {
165 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
166 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
167 /* rega regb regc regd rege regf reg10 reg11 */
168 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
169 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
170 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
171 /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
175 static const __u8 sn_mo4000[] = {
176 /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
177 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81,
178 /* reg9 rega regb regc regd rege regf reg10 reg11*/
179 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
180 /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
181 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00,
182 /* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b,
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, 0x14, 0x28, 0x1e, 0x00, 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_sn9c120[] = {
219 0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90,
220 0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff
222 static const __u8 regsn20_sn9c325[] = {
223 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
224 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
227 static const __u8 reg84[] = {
228 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
229 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
230 /* 0x00, 0x00, 0x00, 0x00, 0x00 */
231 0xf7, 0x0f, 0x0a, 0x00, 0x00
233 static const __u8 reg84_sn9c120_1[] = {
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x0c, 0x00, 0x00
238 static const __u8 reg84_sn9c120_2[] = {
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x0c, 0x02, 0x3b
243 static const __u8 reg84_sn9c120_3[] = {
244 0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f,
245 0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f,
246 0xf5, 0x0f, 0x0c, 0x02, 0x3b
248 static const __u8 reg84_sn9c325[] = {
249 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
250 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
251 0xf8, 0x0f, 0x00, 0x00, 0x00
254 static const __u8 hv7131r_sensor_init[][8] = {
255 {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
256 {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
257 {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
258 {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
259 {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
260 {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
261 {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
263 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
264 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
265 {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
266 {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
267 {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
268 {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
269 {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
270 {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
272 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
273 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
274 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
275 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
276 {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
278 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
279 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
280 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
281 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
282 {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
285 static const __u8 mi0360_sensor_init[][8] = {
286 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
287 {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
288 {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
289 {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
290 {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
291 {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
292 {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
293 {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
294 {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
295 {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
296 {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
297 {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
298 {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
299 {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
300 {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
301 {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
302 {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
303 {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
304 {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
305 {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
306 {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
307 {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
308 {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
309 {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
310 {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
311 {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
312 {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
313 {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
314 {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
315 {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
316 {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
317 {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
318 {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
320 {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
321 {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
322 {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
323 {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
324 {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
326 {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
327 {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
328 {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
329 {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
331 {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
332 {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
333 /* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
334 /* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
335 {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
336 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
339 static const __u8 mo4000_sensor_init[][8] = {
340 {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
341 {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
342 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
343 {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
344 {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
345 {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
346 {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
347 {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
348 {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
349 {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
350 {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
351 {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
352 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
353 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
354 {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
355 {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
356 {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
357 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
358 {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
359 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
362 static const __u8 ov7660_sensor_init[][8] = {
363 {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
364 {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
365 /* Outformat ?? rawRGB */
366 {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
367 {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
368 /* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */
369 /* GAIN BLUE RED VREF */
370 {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
371 /* COM 1 BAVE GEAVE AECHH */
372 {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
373 {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
374 {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
375 /* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */
376 /* AECH CLKRC COM7 COM8 */
377 {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
378 {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
379 /* HSTART HSTOP VSTRT VSTOP */
380 {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
381 {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
382 {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
383 /* BOS GBOS GROS ROS (BGGR offset) */
384 {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
385 /* {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */
386 /* AEW AEB VPT BBIAS */
387 {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
388 /* GbBIAS RSVD EXHCH EXHCL */
389 {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
390 /* RBIAS ADVFL ASDVFH YAVE */
391 {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
392 /* HSYST HSYEN HREF */
393 {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
394 {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
395 /* ADC ACOM OFON TSLB */
396 {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
397 /* COM11 COM12 COM13 COM14 */
398 {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
399 /* EDGE COM15 COM16 COM17 */
400 {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
401 {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
402 {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
403 {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
404 {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
405 {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
406 {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
407 {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
408 {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
409 {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
410 /* LCC1 LCC2 LCC3 LCC4 */
411 {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
412 {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
413 {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
414 /* band gap reference [0..3] DBLV */
415 {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
416 {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
417 {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
418 {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
419 {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
420 {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
421 {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
422 {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
423 {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
424 {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
425 /****** (some exchanges in the win trace) ******/
426 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
427 /* bits[3..0]reserved */
428 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
429 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
430 /* VREF vertical frame ctrl */
431 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
432 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
433 {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
434 {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
435 /* {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */
436 {0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10},
437 {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10},
438 /****** (some exchanges in the win trace) ******/
439 {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
440 {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
441 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
442 {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
443 {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},
444 /****** (some exchanges in the win trace) ******/
445 /**********startsensor KO if changed !!****/
446 {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
447 {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
448 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
449 {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
450 /* here may start the isoc exchanges */
453 /* reg0x04 reg0x07 reg 0x10 */
454 /* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
456 static const __u8 ov7648_sensor_init[][8] = {
457 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
458 {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
459 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
460 {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
461 {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
462 {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
463 {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
464 {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
465 {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
466 {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
467 {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
468 {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
469 {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
470 {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
471 {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
472 {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
473 {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
474 {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
475 {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
476 {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
477 {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
478 {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
479 {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
480 {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
481 {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
482 {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
483 {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
484 {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
485 {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
486 /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
487 {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
488 * This is currently setting a
489 * blue tint, and some things more , i leave it here for future test if
490 * somene is having problems with color on this sensor
491 {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
492 {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
493 {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
494 {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
495 {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
496 {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
497 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
498 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
499 {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
500 {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
501 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
502 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
503 {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */
504 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
505 {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
506 {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
507 {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
508 /* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */
512 static const __u8 qtable4[] = {
513 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
514 0x06, 0x08, 0x0A, 0x11,
515 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
516 0x19, 0x19, 0x17, 0x15,
517 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
518 0x21, 0x2E, 0x21, 0x23,
519 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
520 0x25, 0x29, 0x2C, 0x29,
521 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
522 0x17, 0x1B, 0x29, 0x29,
523 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
524 0x29, 0x29, 0x29, 0x29,
525 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
526 0x29, 0x29, 0x29, 0x29,
527 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
528 0x29, 0x29, 0x29, 0x29
531 /* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
532 static void reg_r(struct gspca_dev *gspca_dev,
533 __u16 value, int len)
535 usb_control_msg(gspca_dev->dev,
536 usb_rcvctrlpipe(gspca_dev->dev, 0),
538 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
540 gspca_dev->usb_buf, len,
544 static void reg_w(struct gspca_dev *gspca_dev,
549 if (len <= sizeof gspca_dev->usb_buf) {
550 memcpy(gspca_dev->usb_buf, buffer, len);
551 usb_control_msg(gspca_dev->dev,
552 usb_sndctrlpipe(gspca_dev->dev, 0),
554 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
556 gspca_dev->usb_buf, len,
561 tmpbuf = kmalloc(len, GFP_KERNEL);
562 memcpy(tmpbuf, buffer, len);
563 usb_control_msg(gspca_dev->dev,
564 usb_sndctrlpipe(gspca_dev->dev, 0),
566 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
574 /* I2C write 2 bytes */
575 static void i2c_w2(struct gspca_dev *gspca_dev,
578 struct sd *sd = (struct sd *) gspca_dev;
582 mode[0] = 0x81 | (2 << 4);
583 mode[1] = sd->i2c_base;
590 reg_w(gspca_dev, 0x08, mode, 8);
593 /* I2C write 8 bytes */
594 static void i2c_w8(struct gspca_dev *gspca_dev,
597 reg_w(gspca_dev, 0x08, buffer, 8);
601 /* read 5 bytes in gspca_dev->usb_buf */
602 static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
604 struct sd *sd = (struct sd *) gspca_dev;
607 mode[0] = 0x81 | 0x10;
608 mode[1] = sd->i2c_base;
615 i2c_w8(gspca_dev, mode);
616 mode[0] = 0x81 | (5 << 4) | 0x02;
618 i2c_w8(gspca_dev, mode);
619 reg_r(gspca_dev, 0x0a, 5);
622 static int probesensor(struct gspca_dev *gspca_dev)
624 struct sd *sd = (struct sd *) gspca_dev;
626 static const __u8 datasend[] = { 2, 0 };
627 /* reg val1 val2 val3 val4 */
629 i2c_w2(gspca_dev, datasend);
630 /* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
633 reg_w(gspca_dev, 0x02, ®02, 1); /* Gpio on */
635 i2c_r5(gspca_dev, 0); /* read sensor id */
636 if (gspca_dev->usb_buf[0] == 0x02
637 && gspca_dev->usb_buf[1] == 0x09
638 && gspca_dev->usb_buf[2] == 0x01
639 && gspca_dev->usb_buf[3] == 0x00
640 && gspca_dev->usb_buf[4] == 0x00) {
641 PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
642 sd->sensor = SENSOR_HV7131R;
643 return SENSOR_HV7131R;
645 PDEBUG(D_PROBE, "Find Sensor %d %d %d",
646 gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
647 gspca_dev->usb_buf[2]);
648 PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
652 static int configure_gpio(struct gspca_dev *gspca_dev,
655 struct sd *sd = (struct sd *) gspca_dev;
659 static const __u8 reg9a_def[] =
660 {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
661 static const __u8 reg9a_sn9c120[] = /* from win trace */
662 {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
663 static const __u8 reg9a_sn9c325[] =
664 {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
668 reg_w(gspca_dev, 0xf1, ®F1, 1);
669 reg_w(gspca_dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/
672 reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
673 reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
674 reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm was 3 */
675 switch (sd->bridge) {
677 reg9a = reg9a_sn9c325;
680 reg9a = reg9a_sn9c120;
686 reg_w(gspca_dev, 0x9a, reg9a, 6);
688 data = 0x60; /*fixme:jfm 60 00 00 (3) */
689 reg_w(gspca_dev, 0xd4, &data, 1);
691 reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
693 switch (sd->bridge) {
694 case BRIDGE_SN9C120: /* from win trace */
696 reg_w(gspca_dev, 0x01, &data, 1);
698 reg_w(gspca_dev, 0x17, &data, 1);
700 reg_w(gspca_dev, 0x01, &data, 1);
704 reg_w(gspca_dev, 0x01, &data, 1);
706 reg_w(gspca_dev, 0x17, &data, 1);
708 reg_w(gspca_dev, 0x01, &data, 1);
712 reg_w(gspca_dev, 0x01, &data, 1);
714 reg_w(gspca_dev, 0x17, &data, 1);
716 reg_w(gspca_dev, 0x01, &data, 1);
719 if (sd->sensor == SENSOR_HV7131R) {
720 if (probesensor(gspca_dev) < 0)
726 static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
729 static const __u8 SetSensorClk[] = /* 0x08 Mclk */
730 { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
732 while (hv7131r_sensor_init[i][0]) {
733 i2c_w8(gspca_dev, hv7131r_sensor_init[i]);
736 i2c_w8(gspca_dev, SetSensorClk);
739 static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
743 while (mi0360_sensor_init[i][0]) {
744 i2c_w8(gspca_dev, mi0360_sensor_init[i]);
749 static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
753 while (mo4000_sensor_init[i][0]) {
754 i2c_w8(gspca_dev, mo4000_sensor_init[i]);
759 static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
763 while (ov7648_sensor_init[i][0]) {
764 i2c_w8(gspca_dev, ov7648_sensor_init[i]);
769 static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
773 while (ov7660_sensor_init[i][0]) {
774 i2c_w8(gspca_dev, ov7660_sensor_init[i]);
779 /* this function is called at probe time */
780 static int sd_config(struct gspca_dev *gspca_dev,
781 const struct usb_device_id *id)
783 struct sd *sd = (struct sd *) gspca_dev;
788 vendor = id->idVendor;
789 product = id->idProduct;
792 case 0x0458: /* Genius */
793 /* switch (product) {
795 sd->bridge = BRIDGE_SN9C120;
796 sd->sensor = SENSOR_MI0360;
802 /* switch (product) {
805 sd->bridge = BRIDGE_SN9C105;
806 sd->sensor = SENSOR_OV7660;
811 case 0x0471: /* Philips */
812 /* switch (product) {
816 sd->bridge = BRIDGE_SN9C105;
817 sd->sensor = SENSOR_MI0360;
822 case 0x0c45: /* Sonix */
825 sd->bridge = BRIDGE_SN9C102P;
826 /* sd->sensor = SENSOR_MI0360; * from BW600.inf */
827 /*fixme: MI0360 base=5d ? */
828 sd->sensor = SENSOR_HV7131R; /* gspcav1 value */
831 /* case 0x607a: * from BW600.inf
832 sd->bridge = BRIDGE_SN9C102P;
833 sd->sensor = SENSOR_OV7648;
837 sd->bridge = BRIDGE_SN9C102P;
838 sd->sensor = SENSOR_HV7131R;
841 /* case 0x607e: * from BW600.inf
842 sd->bridge = BRIDGE_SN9C102P;
843 sd->sensor = SENSOR_OV7630;
847 sd->bridge = BRIDGE_SN9C105;
848 sd->sensor = SENSOR_MI0360;
851 /* case 0x60c8: * from BW600.inf
852 sd->bridge = BRIDGE_SN9C105;
853 sd->sensor = SENSOR_OM6801;
856 /* case 0x60cc: * from BW600.inf
857 sd->bridge = BRIDGE_SN9C105;
858 sd->sensor = SENSOR_HV7131GP;
862 sd->bridge = BRIDGE_SN9C105;
863 sd->sensor = SENSOR_MO4000;
866 /* case 0x60ef: * from BW600.inf
867 sd->bridge = BRIDGE_SN9C105;
868 sd->sensor = SENSOR_ICM105C;
871 /* case 0x60fa: * from BW600.inf
872 sd->bridge = BRIDGE_SN9C105;
873 sd->sensor = SENSOR_OV7648;
877 sd->bridge = BRIDGE_SN9C105;
878 sd->sensor = SENSOR_OV7660;
882 sd->bridge = BRIDGE_SN9C105;
883 sd->sensor = SENSOR_HV7131R;
886 /* case 0x60fe: * from BW600.inf
887 sd->bridge = BRIDGE_SN9C105;
888 sd->sensor = SENSOR_OV7630;
891 /* case 0x6108: * from BW600.inf
892 sd->bridge = BRIDGE_SN9C120;
893 sd->sensor = SENSOR_OM6801;
896 /* case 0x6122: * from BW600.inf
897 sd->bridge = BRIDGE_SN9C110;
898 sd->sensor = SENSOR_ICM105C;
902 /* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */
903 sd->bridge = BRIDGE_SN9C325;
904 sd->sensor = SENSOR_OV7648;
906 /*fixme: sensor_init has base = 00 et 6e!*/
908 /* case 0x6123: * from BW600.inf
909 sd->bridge = BRIDGE_SN9C110;
910 sd->sensor = SENSOR_SanyoCCD;
914 sd->bridge = BRIDGE_SN9C110;
915 sd->sensor = SENSOR_MO4000;
918 /* case 0x612e: * from BW600.inf
919 sd->bridge = BRIDGE_SN9C110;
920 sd->sensor = SENSOR_OV7630;
923 /* case 0x612f: * from BW600.inf
924 sd->bridge = BRIDGE_SN9C110;
925 sd->sensor = SENSOR_ICM105C;
929 sd->bridge = BRIDGE_SN9C120;
930 sd->sensor = SENSOR_MI0360;
934 sd->bridge = BRIDGE_SN9C120;
935 sd->sensor = SENSOR_MO4000;
938 /* case 0x613a: * from BW600.inf
939 sd->bridge = BRIDGE_SN9C120;
940 sd->sensor = SENSOR_OV7648;
944 sd->bridge = BRIDGE_SN9C120;
945 sd->sensor = SENSOR_OV7660;
949 sd->bridge = BRIDGE_SN9C120;
950 sd->sensor = SENSOR_HV7131R;
953 /* case 0x613e: * from BW600.inf
954 sd->bridge = BRIDGE_SN9C120;
955 sd->sensor = SENSOR_OV7630;
961 if (sd->sensor < 0) {
962 PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
967 cam = &gspca_dev->cam;
968 cam->dev_name = (char *) id->driver_info;
970 cam->cam_mode = vga_mode;
971 cam->nmodes = ARRAY_SIZE(vga_mode);
973 sd->qindex = 4; /* set the quantization table */
974 sd->brightness = BRIGHTNESS_DEF;
975 sd->contrast = CONTRAST_DEF;
976 sd->colors = COLOR_DEF;
977 sd->autogain = AUTOGAIN_DEF;
981 /* this function is called at open time */
982 static int sd_open(struct gspca_dev *gspca_dev)
984 struct sd *sd = (struct sd *) gspca_dev;
985 /* const __u8 *sn9c1xx; */
987 __u8 regGpio[] = { 0x29, 0x74 };
989 /* setup a selector by bridge */
991 reg_w(gspca_dev, 0xf1, ®F1, 1);
992 reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */
993 regF1 = gspca_dev->usb_buf[0];
994 reg_w(gspca_dev, 0xf1, ®F1, 1);
995 reg_r(gspca_dev, 0x00, 1);
996 regF1 = gspca_dev->usb_buf[0];
997 switch (sd->bridge) {
998 case BRIDGE_SN9C102P:
1001 reg_w(gspca_dev, 0x02, ®Gpio[1], 1);
1003 case BRIDGE_SN9C105:
1006 reg_w(gspca_dev, 0x02, regGpio, 2);
1008 case BRIDGE_SN9C110:
1012 reg_w(gspca_dev, 0x02, ®Gpio[1], 1);
1014 case BRIDGE_SN9C120:
1018 reg_w(gspca_dev, 0x02, regGpio, 2);
1021 /* case BRIDGE_SN9C325: */
1025 reg_w(gspca_dev, 0x02, ®Gpio[1], 1);
1030 reg_w(gspca_dev, 0xf1, ®F1, 1);
1035 static unsigned int setexposure(struct gspca_dev *gspca_dev,
1038 struct sd *sd = (struct sd *) gspca_dev;
1039 static const __u8 doit[] = /* update sensor */
1040 { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
1041 static const __u8 sensorgo[] = /* sensor on */
1042 { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
1043 static const __u8 gainMo[] =
1044 { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
1046 switch (sd->sensor) {
1047 case SENSOR_HV7131R: {
1049 { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
1051 Expodoit[3] = expo >> 16;
1052 Expodoit[4] = expo >> 8;
1054 i2c_w8(gspca_dev, Expodoit);
1057 case SENSOR_MI0360: {
1058 __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
1059 { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
1063 else if (expo < 0x0001)
1065 expoMi[3] = expo >> 8;
1067 i2c_w8(gspca_dev, expoMi);
1068 i2c_w8(gspca_dev, doit);
1069 i2c_w8(gspca_dev, sensorgo);
1072 case SENSOR_MO4000: {
1074 { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
1076 { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
1080 else if (expo < 0x0001)
1082 expoMof[3] = (expo & 0x03fc) >> 2;
1083 i2c_w8(gspca_dev, expoMof);
1084 expoMo10[3] = ((expo & 0x1c00) >> 10)
1085 | ((expo & 0x0003) << 4);
1086 i2c_w8(gspca_dev, expoMo10);
1087 i2c_w8(gspca_dev, gainMo);
1088 PDEBUG(D_CONF, "set exposure %d",
1089 ((expoMo10[3] & 0x07) << 10)
1091 | ((expoMo10[3] & 0x30) >> 4));
1098 static void setbrightness(struct gspca_dev *gspca_dev)
1100 struct sd *sd = (struct sd *) gspca_dev;
1104 switch (sd->sensor) {
1105 case SENSOR_HV7131R:
1106 expo = sd->brightness << 4;
1107 if (expo > 0x002dc6c0)
1109 else if (expo < 0x02a0)
1111 sd->exposure = setexposure(gspca_dev, expo);
1114 expo = sd->brightness >> 4;
1115 sd->exposure = setexposure(gspca_dev, expo);
1118 expo = sd->brightness >> 4;
1119 sd->exposure = setexposure(gspca_dev, expo);
1125 k2 = sd->brightness >> 10;
1126 reg_w(gspca_dev, 0x96, &k2, 1);
1129 static void setcontrast(struct gspca_dev *gspca_dev)
1131 struct sd *sd = (struct sd *) gspca_dev;
1133 __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
1135 if (sd->sensor == SENSOR_OV7660)
1139 contrast[0] = (k2 + 1) >> 1;
1140 contrast[4] = (k2 + 1) / 5;
1141 reg_w(gspca_dev, 0x84, contrast, 6);
1144 static void setcolors(struct gspca_dev *gspca_dev)
1146 struct sd *sd = (struct sd *) gspca_dev;
1150 colour = sd->colors - 128;
1152 data = (colour + 32) & 0x7f; /* blue */
1154 data = (-colour + 32) & 0x7f; /* red */
1155 reg_w(gspca_dev, 0x05, &data, 1);
1158 /* -- start the camera -- */
1159 static void sd_start(struct gspca_dev *gspca_dev)
1161 struct sd *sd = (struct sd *) gspca_dev;
1166 const __u8 *sn9c1xx;
1168 static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
1169 static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
1170 static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
1171 static const __u8 CA_sn9c120[] =
1172 { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
1173 static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
1174 static const __u8 CE_sn9c325[] =
1175 { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
1177 sn9c1xx = sn_tb[(int) sd->sensor];
1178 configure_gpio(gspca_dev, sn9c1xx);
1180 /*fixme:jfm this sequence should appear at end of sd_start */
1183 reg_w(gspca_dev, 0x01, &data, 1); */
1184 reg_w(gspca_dev, 0x15, &sn9c1xx[0x15], 1);
1185 reg_w(gspca_dev, 0x16, &sn9c1xx[0x16], 1);
1186 reg_w(gspca_dev, 0x12, &sn9c1xx[0x12], 1);
1187 reg_w(gspca_dev, 0x13, &sn9c1xx[0x13], 1);
1188 reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
1189 reg_w(gspca_dev, 0xd2, &DC29[0], 1);
1190 reg_w(gspca_dev, 0xd3, &DC29[1], 1);
1191 reg_w(gspca_dev, 0xc6, &DC29[2], 1);
1192 reg_w(gspca_dev, 0xc7, &DC29[3], 1);
1193 reg_w(gspca_dev, 0xc8, &DC29[4], 1);
1194 reg_w(gspca_dev, 0xc9, &DC29[5], 1);
1195 /*fixme:jfm end of ending sequence */
1196 reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
1197 switch (sd->bridge) {
1198 case BRIDGE_SN9C325:
1201 case BRIDGE_SN9C120:
1208 reg_w(gspca_dev, 0x17, &data, 1);
1209 reg_w(gspca_dev, 0x05, &sn9c1xx[5], 1);
1210 reg_w(gspca_dev, 0x07, &sn9c1xx[7], 1);
1211 reg_w(gspca_dev, 0x06, &sn9c1xx[6], 1);
1212 reg_w(gspca_dev, 0x14, &sn9c1xx[0x14], 1);
1213 switch (sd->bridge) {
1214 case BRIDGE_SN9C325:
1215 reg_w(gspca_dev, 0x20, regsn20_sn9c325,
1216 sizeof regsn20_sn9c325);
1217 for (i = 0; i < 8; i++)
1218 reg_w(gspca_dev, 0x84, reg84_sn9c325,
1219 sizeof reg84_sn9c325);
1221 reg_w(gspca_dev, 0x9a, &data, 1);
1223 reg_w(gspca_dev, 0x99, &data, 1);
1225 case BRIDGE_SN9C120:
1226 reg_w(gspca_dev, 0x20, regsn20_sn9c120,
1227 sizeof regsn20_sn9c120);
1228 for (i = 0; i < 2; i++)
1229 reg_w(gspca_dev, 0x84, reg84_sn9c120_1,
1230 sizeof reg84_sn9c120_1);
1231 for (i = 0; i < 6; i++)
1232 reg_w(gspca_dev, 0x84, reg84_sn9c120_2,
1233 sizeof reg84_sn9c120_2);
1234 reg_w(gspca_dev, 0x84, reg84_sn9c120_3,
1235 sizeof reg84_sn9c120_3);
1237 reg_w(gspca_dev, 0x9a, &data, 1);
1239 reg_w(gspca_dev, 0x99, &data, 1);
1242 reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
1243 for (i = 0; i < 8; i++)
1244 reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
1246 reg_w(gspca_dev, 0x9a, &data, 1);
1248 reg_w(gspca_dev, 0x99, &data, 1);
1252 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
1255 switch (sd->sensor) {
1256 case SENSOR_HV7131R:
1257 hv7131R_InitSensor(gspca_dev);
1259 reg1 = 0x46; /* 320 clk 48Mhz */
1261 reg1 = 0x06; /* 640 clk 24Mz */
1264 mi0360_InitSensor(gspca_dev);
1266 reg1 = 0x46; /* 320 clk 48Mhz */
1268 reg1 = 0x06; /* 640 clk 24Mz */
1271 mo4000_InitSensor(gspca_dev);
1273 /* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
1274 reg1 = 0x06; /* clk 24Mz */
1276 reg17 = 0x22; /* 640 MCKSIZE */
1277 reg1 = 0x06; /* 640 clk 24Mz */
1283 ov7648_InitSensor(gspca_dev);
1290 /* case SENSOR_OV7660: */
1291 ov7660_InitSensor(gspca_dev);
1293 /* reg17 = 0x21; * 320 */
1297 reg17 = 0xa2; /* 640 */
1302 reg_w(gspca_dev, 0xc0, C0, 6);
1303 switch (sd->bridge) {
1304 case BRIDGE_SN9C120: /*jfm ?? */
1305 reg_w(gspca_dev, 0xca, CA_sn9c120, 4);
1308 reg_w(gspca_dev, 0xca, CA, 4);
1311 switch (sd->bridge) {
1312 case BRIDGE_SN9C120: /*jfm ?? */
1313 case BRIDGE_SN9C325:
1314 reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
1317 reg_w(gspca_dev, 0xce, CE, 4);
1318 /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
1322 /* here change size mode 0 -> VGA; 1 -> CIF */
1323 data = 0x40 | sn9c1xx[0x18] | (mode << 4);
1324 reg_w(gspca_dev, 0x18, &data, 1);
1326 reg_w(gspca_dev, 0x100, qtable4, 0x40);
1327 reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
1329 data = sn9c1xx[0x18] | (mode << 4);
1330 reg_w(gspca_dev, 0x18, &data, 1);
1332 reg_w(gspca_dev, 0x17, ®17, 1);
1333 reg_w(gspca_dev, 0x01, ®1, 1);
1334 setbrightness(gspca_dev);
1335 setcontrast(gspca_dev);
1338 static void sd_stopN(struct gspca_dev *gspca_dev)
1340 struct sd *sd = (struct sd *) gspca_dev;
1341 static const __u8 stophv7131[] =
1342 { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
1343 static const __u8 stopmi0360[] =
1344 { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
1347 const __u8 *sn9c1xx;
1350 switch (sd->sensor) {
1351 case SENSOR_HV7131R:
1352 i2c_w8(gspca_dev, stophv7131);
1356 i2c_w8(gspca_dev, stopmi0360);
1365 /* case SENSOR_OV7660: */
1368 sn9c1xx = sn_tb[(int) sd->sensor];
1369 reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
1370 reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 1);
1371 reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
1372 reg_w(gspca_dev, 0x01, &data, 1);
1374 reg_w(gspca_dev, 0xf1, ®F1, 1);
1377 static void sd_stop0(struct gspca_dev *gspca_dev)
1381 static void sd_close(struct gspca_dev *gspca_dev)
1385 static void setautogain(struct gspca_dev *gspca_dev)
1387 struct sd *sd = (struct sd *) gspca_dev;
1388 /* Thanks S., without your advice, autobright should not work :) */
1391 __u8 luma_mean = 130;
1392 __u8 luma_delta = 20;
1394 delta = sd->avg_lum;
1395 if (delta < luma_mean - luma_delta ||
1396 delta > luma_mean + luma_delta) {
1397 switch (sd->sensor) {
1398 case SENSOR_HV7131R:
1399 expotimes = sd->exposure >> 8;
1400 expotimes += (luma_mean - delta) >> 4;
1403 sd->exposure = setexposure(gspca_dev,
1404 (unsigned int) (expotimes << 8));
1408 expotimes = sd->exposure;
1409 expotimes += (luma_mean - delta) >> 6;
1412 sd->exposure = setexposure(gspca_dev,
1413 (unsigned int) expotimes);
1414 setcolors(gspca_dev);
1420 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1421 struct gspca_frame *frame, /* target */
1422 __u8 *data, /* isoc packet */
1423 int len) /* iso packet length */
1425 struct sd *sd = (struct sd *) gspca_dev;
1429 if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
1432 gspca_frame_add(gspca_dev, LAST_PACKET,
1433 frame, data, sof + 2);
1436 if (--sd->ag_cnt >= 0)
1438 sd->ag_cnt = AG_CNT_START;
1443 avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
1445 avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
1447 avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
1449 avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
1451 avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
1453 sd->avg_lum = avg_lum;
1454 PDEBUG(D_PACK, "mean lum %d", avg_lum);
1455 setautogain(gspca_dev);
1458 if (gspca_dev->last_packet_type == LAST_PACKET) {
1460 /* put the JPEG 422 header */
1461 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
1463 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1466 static unsigned int getexposure(struct gspca_dev *gspca_dev)
1468 struct sd *sd = (struct sd *) gspca_dev;
1469 __u8 hexpo, mexpo, lexpo;
1471 switch (sd->sensor) {
1472 case SENSOR_HV7131R:
1473 /* read sensor exposure */
1474 i2c_r5(gspca_dev, 0x25);
1475 return (gspca_dev->usb_buf[0] << 16)
1476 | (gspca_dev->usb_buf[1] << 8)
1477 | gspca_dev->usb_buf[2];
1479 /* read sensor exposure */
1480 i2c_r5(gspca_dev, 0x09);
1481 return (gspca_dev->usb_buf[0] << 8)
1482 | gspca_dev->usb_buf[1];
1484 i2c_r5(gspca_dev, 0x0e);
1485 hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */
1486 mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
1487 lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
1488 PDEBUG(D_CONF, "exposure %d",
1489 (hexpo << 10) | (mexpo << 2) | lexpo);
1490 return (hexpo << 10) | (mexpo << 2) | lexpo;
1492 /* case SENSOR_OV7660: */
1493 /* read sensor exposure */
1494 i2c_r5(gspca_dev, 0x04);
1495 hexpo = gspca_dev->usb_buf[3] & 0x2f;
1496 lexpo = gspca_dev->usb_buf[0] & 0x02;
1497 i2c_r5(gspca_dev, 0x08);
1498 mexpo = gspca_dev->usb_buf[2];
1499 return (hexpo << 10) | (mexpo << 2) | lexpo;
1503 static void getbrightness(struct gspca_dev *gspca_dev)
1505 struct sd *sd = (struct sd *) gspca_dev;
1507 /* hardcoded registers seem not readable */
1508 switch (sd->sensor) {
1509 case SENSOR_HV7131R:
1510 /* sd->brightness = 0x7fff; */
1511 sd->brightness = getexposure(gspca_dev) >> 4;
1514 sd->brightness = getexposure(gspca_dev) << 4;
1517 /* sd->brightness = 0x1fff; */
1518 sd->brightness = getexposure(gspca_dev) << 4;
1523 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1525 struct sd *sd = (struct sd *) gspca_dev;
1527 sd->brightness = val;
1528 if (gspca_dev->streaming)
1529 setbrightness(gspca_dev);
1533 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1535 struct sd *sd = (struct sd *) gspca_dev;
1537 getbrightness(gspca_dev);
1538 *val = sd->brightness;
1542 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1544 struct sd *sd = (struct sd *) gspca_dev;
1547 if (gspca_dev->streaming)
1548 setcontrast(gspca_dev);
1552 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1554 struct sd *sd = (struct sd *) gspca_dev;
1556 *val = sd->contrast;
1560 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1562 struct sd *sd = (struct sd *) gspca_dev;
1565 if (gspca_dev->streaming)
1566 setcolors(gspca_dev);
1570 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1572 struct sd *sd = (struct sd *) gspca_dev;
1578 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1580 struct sd *sd = (struct sd *) gspca_dev;
1584 sd->ag_cnt = AG_CNT_START;
1590 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1592 struct sd *sd = (struct sd *) gspca_dev;
1594 *val = sd->autogain;
1598 /* sub-driver description */
1599 static const struct sd_desc sd_desc = {
1600 .name = MODULE_NAME,
1602 .nctrls = ARRAY_SIZE(sd_ctrls),
1603 .config = sd_config,
1609 .pkt_scan = sd_pkt_scan,
1612 /* -- module initialisation -- */
1613 #define DVNM(name) .driver_info = (kernel_ulong_t) name
1614 static const __devinitdata struct usb_device_id device_table[] = {
1615 #ifndef CONFIG_USB_SN9C102
1616 {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
1617 {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
1618 {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
1619 {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
1620 {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
1622 {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
1623 {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
1624 {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
1625 {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
1626 {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
1627 {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
1628 {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
1629 {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
1630 {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
1631 #ifndef CONFIG_USB_SN9C102
1632 {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
1633 {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
1634 {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
1635 {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
1639 MODULE_DEVICE_TABLE(usb, device_table);
1641 /* -- device connect -- */
1642 static int sd_probe(struct usb_interface *intf,
1643 const struct usb_device_id *id)
1645 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1649 static struct usb_driver sd_driver = {
1650 .name = MODULE_NAME,
1651 .id_table = device_table,
1653 .disconnect = gspca_disconnect,
1656 /* -- module insert / remove -- */
1657 static int __init sd_mod_init(void)
1659 if (usb_register(&sd_driver) < 0)
1661 info("v%s registered", version);
1664 static void __exit sd_mod_exit(void)
1666 usb_deregister(&sd_driver);
1667 info("deregistered");
1670 module_init(sd_mod_init);
1671 module_exit(sd_mod_exit);