]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/gspca/t613.c
V4L/DVB (8512): gspca: Do not use the driver_info field of usb_device_id.
[mirror_ubuntu-artful-kernel.git] / drivers / media / video / gspca / t613.c
CommitLineData
6a7eba24 1/*
6a7eba24
JFM
2 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
10b0e96e
JFM
17 *
18 *Notes: * t613 + tas5130A
19 * * Focus to light do not balance well as in win.
20 * Quality in win is not good, but its kinda better.
21 * * Fix some "extraneous bytes", most of apps will show the image anyway
22 * * Gamma table, is there, but its really doing something?
23 * * 7~8 Fps, its ok, max on win its 10.
24 * Costantino Leandro
6a7eba24
JFM
25 */
26
27#define MODULE_NAME "t613"
10b0e96e 28
6a7eba24 29#include "gspca.h"
6a7eba24
JFM
30
31#define MAX_GAMMA 0x10 /* 0 to 15 */
32
6a7eba24
JFM
33#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
34
35MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
36MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
37MODULE_LICENSE("GPL");
38
39struct sd {
40 struct gspca_dev gspca_dev; /* !! must be the first item */
41
42 unsigned char brightness;
43 unsigned char contrast;
44 unsigned char colors;
45 unsigned char autogain;
46 unsigned char gamma;
47 unsigned char sharpness;
48 unsigned char freq;
49 unsigned char whitebalance;
50 unsigned char mirror;
51 unsigned char effect;
52};
53
54/* V4L2 controls supported by the driver */
55static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
56static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
57static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
58static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
59static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
60static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
61static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
63static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
71static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
72static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
73static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
74static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
75static int sd_querymenu(struct gspca_dev *gspca_dev,
76 struct v4l2_querymenu *menu);
77
78static struct ctrl sd_ctrls[] = {
79#define SD_BRIGHTNESS 0
80 {
81 {
82 .id = V4L2_CID_BRIGHTNESS,
83 .type = V4L2_CTRL_TYPE_INTEGER,
84 .name = "Brightness",
85 .minimum = 0,
86 .maximum = 0x0f,
87 .step = 1,
88 .default_value = 0x09,
89 },
90 .set = sd_setbrightness,
91 .get = sd_getbrightness,
92 },
93#define SD_CONTRAST 1
94 {
95 {
96 .id = V4L2_CID_CONTRAST,
97 .type = V4L2_CTRL_TYPE_INTEGER,
98 .name = "Contrast",
99 .minimum = 0,
100 .maximum = 0x0d,
101 .step = 1,
102 .default_value = 0x07,
103 },
104 .set = sd_setcontrast,
105 .get = sd_getcontrast,
106 },
107#define SD_COLOR 2
108 {
109 {
110 .id = V4L2_CID_SATURATION,
111 .type = V4L2_CTRL_TYPE_INTEGER,
112 .name = "Color",
113 .minimum = 0,
114 .maximum = 0x0f,
115 .step = 1,
116 .default_value = 0x05,
117 },
118 .set = sd_setcolors,
119 .get = sd_getcolors,
120 },
121#define SD_GAMMA 3
122 {
123 {
124 .id = V4L2_CID_GAMMA, /* (gamma on win) */
125 .type = V4L2_CTRL_TYPE_INTEGER,
126 .name = "Gamma (Untested)",
127 .minimum = 0,
128 .maximum = MAX_GAMMA,
129 .step = 1,
130 .default_value = 0x09,
131 },
132 .set = sd_setgamma,
133 .get = sd_getgamma,
134 },
135#define SD_AUTOGAIN 4
136 {
137 {
138 .id = V4L2_CID_GAIN, /* here, i activate only the lowlight,
139 * some apps dont bring up the
140 * backligth_compensation control) */
141 .type = V4L2_CTRL_TYPE_INTEGER,
142 .name = "Low Light",
143 .minimum = 0,
144 .maximum = 1,
145 .step = 1,
146 .default_value = 0x01,
147 },
148 .set = sd_setlowlight,
149 .get = sd_getlowlight,
150 },
151#define SD_MIRROR 5
152 {
153 {
154 .id = V4L2_CID_HFLIP,
155 .type = V4L2_CTRL_TYPE_BOOLEAN,
156 .name = "Mirror Image",
157 .minimum = 0,
158 .maximum = 1,
159 .step = 1,
160 .default_value = 0,
161 },
162 .set = sd_setflip,
163 .get = sd_getflip
164 },
165#define SD_LIGHTFREQ 6
166 {
167 {
168 .id = V4L2_CID_POWER_LINE_FREQUENCY,
169 .type = V4L2_CTRL_TYPE_MENU,
170 .name = "Light Frequency Filter",
171 .minimum = 1, /* 1 -> 0x50, 2->0x60 */
172 .maximum = 2,
173 .step = 1,
174 .default_value = 1,
175 },
176 .set = sd_setfreq,
177 .get = sd_getfreq},
178
179#define SD_WHITE_BALANCE 7
180 {
181 {
182 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
183 .type = V4L2_CTRL_TYPE_INTEGER,
184 .name = "White Balance",
185 .minimum = 0,
186 .maximum = 1,
187 .step = 1,
188 .default_value = 1,
189 },
190 .set = sd_setwhitebalance,
191 .get = sd_getwhitebalance
192 },
193#define SD_SHARPNESS 8 /* (aka definition on win) */
194 {
195 {
196 .id = V4L2_CID_SHARPNESS,
197 .type = V4L2_CTRL_TYPE_INTEGER,
198 .name = "Sharpness",
199 .minimum = 0,
200 .maximum = MAX_GAMMA, /* 0 to 16 */
201 .step = 1,
202 .default_value = 0x06,
203 },
204 .set = sd_setsharpness,
205 .get = sd_getsharpness,
206 },
207#define SD_EFFECTS 9
208 {
209 {
210 .id = V4L2_CID_EFFECTS,
211 .type = V4L2_CTRL_TYPE_MENU,
212 .name = "Webcam Effects",
213 .minimum = 0,
214 .maximum = 4,
215 .step = 1,
216 .default_value = 0,
217 },
218 .set = sd_seteffect,
219 .get = sd_geteffect
220 },
221};
222
a5ae2062
JFM
223static char *effects_control[] = {
224 "Normal",
225 "Emboss", /* disabled */
226 "Monochrome",
227 "Sepia",
228 "Sketch",
229 "Sun Effect", /* disabled */
230 "Negative",
6a7eba24
JFM
231};
232
c2446b3e
JFM
233static struct v4l2_pix_format vga_mode_t16[] = {
234 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
235 .bytesperline = 160,
236 .sizeimage = 160 * 120 * 3 / 8 + 590,
237 .colorspace = V4L2_COLORSPACE_JPEG,
238 .priv = 4},
239 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
240 .bytesperline = 176,
241 .sizeimage = 176 * 144 * 3 / 8 + 590,
242 .colorspace = V4L2_COLORSPACE_JPEG,
243 .priv = 3},
244 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
245 .bytesperline = 320,
246 .sizeimage = 320 * 240 * 3 / 8 + 590,
247 .colorspace = V4L2_COLORSPACE_JPEG,
248 .priv = 2},
249 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
250 .bytesperline = 352,
251 .sizeimage = 352 * 288 * 3 / 8 + 590,
252 .colorspace = V4L2_COLORSPACE_JPEG,
253 .priv = 1},
254 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
255 .bytesperline = 640,
256 .sizeimage = 640 * 480 * 3 / 8 + 590,
257 .colorspace = V4L2_COLORSPACE_JPEG,
258 .priv = 0},
6a7eba24
JFM
259};
260
261#define T16_OFFSET_DATA 631
262#define MAX_EFFECTS 7
263/* easily done by soft, this table could be removed,
264 * i keep it here just in case */
a5ae2062 265static const __u8 effects_table[MAX_EFFECTS][6] = {
6a7eba24
JFM
266 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
267 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
268 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
269 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
270 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
271 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
272 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
273};
274
a5ae2062 275static const __u8 gamma_table[MAX_GAMMA][34] = {
6a7eba24
JFM
276 {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
277 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
278 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
279 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
280 0xa0, 0xff},
281 {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
282 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
283 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
284 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
285 0xa0, 0xff},
286 {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
287 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
288 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
289 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
290 0xa0, 0xff},
291 {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
292 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
293 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
294 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
295 0xa0, 0xff},
296 {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
297 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
298 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
299 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
300 0xa0, 0xff},
301 {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
302 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
303 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
304 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
305 0xa0, 0xff},
306 {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
307 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
308 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
309 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
310 0xa0, 0xff},
311 {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
312 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
313 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
314 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
315 0xa0, 0xff},
316 {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
317 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
318 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
319 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
320 0xa0, 0xff},
321 {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
322 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
323 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
324 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
325 0xa0, 0xff},
326 {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
327 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
328 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
329 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
330 0xa0, 0xff},
331 {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
332 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
333 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
334 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
335 0xa0, 0xff},
336 {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
337 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
338 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
339 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
340 0xA0, 0xFF},
341 {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
342 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
343 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
344 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
345 0xa0, 0xff},
346 {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
347 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
348 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
349 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
350 0xa0, 0xff},
351 {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
352 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
353 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
354 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
355 0xA0, 0xFF}
356};
357
a5ae2062 358static const __u8 tas5130a_sensor_init[][8] = {
6a7eba24
JFM
359 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
360 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
361 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
362 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
363 {},
364};
365
739570bb
JFM
366/* read 1 byte */
367static int reg_r_1(struct gspca_dev *gspca_dev,
368 __u16 index)
6a7eba24 369{
739570bb
JFM
370 usb_control_msg(gspca_dev->dev,
371 usb_rcvctrlpipe(gspca_dev->dev, 0),
6a7eba24
JFM
372 0, /* request */
373 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
374 0, /* value */
739570bb
JFM
375 index,
376 gspca_dev->usb_buf, 1, 500);
377 return gspca_dev->usb_buf[0];
6a7eba24
JFM
378}
379
739570bb 380static void reg_w(struct gspca_dev *gspca_dev,
6a7eba24 381 __u16 value,
a5ae2062
JFM
382 __u16 index,
383 const __u8 *buffer, __u16 len)
6a7eba24 384{
a5ae2062 385 if (buffer == NULL) {
739570bb
JFM
386 usb_control_msg(gspca_dev->dev,
387 usb_sndctrlpipe(gspca_dev->dev, 0),
a5ae2062
JFM
388 0,
389 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
390 value, index,
391 NULL, 0, 500);
bf7f0b98
JFM
392 return;
393 }
739570bb
JFM
394 if (len <= sizeof gspca_dev->usb_buf) {
395 memcpy(gspca_dev->usb_buf, buffer, len);
396 usb_control_msg(gspca_dev->dev,
397 usb_sndctrlpipe(gspca_dev->dev, 0),
a5ae2062
JFM
398 0,
399 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
400 value, index,
739570bb 401 gspca_dev->usb_buf, len, 500);
a5ae2062
JFM
402 } else {
403 __u8 *tmpbuf;
404
405 tmpbuf = kmalloc(len, GFP_KERNEL);
406 memcpy(tmpbuf, buffer, len);
739570bb
JFM
407 usb_control_msg(gspca_dev->dev,
408 usb_sndctrlpipe(gspca_dev->dev, 0),
a5ae2062
JFM
409 0,
410 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
411 value, index,
412 tmpbuf, len, 500);
413 kfree(tmpbuf);
414 }
6a7eba24
JFM
415}
416
417/* this function is called at probe time */
418static int sd_config(struct gspca_dev *gspca_dev,
419 const struct usb_device_id *id)
420{
421 struct sd *sd = (struct sd *) gspca_dev;
422 struct cam *cam;
423
424 cam = &gspca_dev->cam;
6a7eba24
JFM
425 cam->epaddr = 0x01;
426
427 cam->cam_mode = vga_mode_t16;
428 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
429
430 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
431 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
432 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
433 sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
434 sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
435 sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
436 sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
437 sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
438 sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
439 return 0;
440}
441
442static int init_default_parameters(struct gspca_dev *gspca_dev)
443{
6a7eba24
JFM
444 /* some of this registers are not really neded, because
445 * they are overriden by setbrigthness, setcontrast, etc,
446 * but wont hurt anyway, and can help someone with similar webcam
447 * to see the initial parameters.*/
448 int i = 0;
449 __u8 test_byte;
450
a5ae2062 451 static const __u8 read_indexs[] =
6a7eba24
JFM
452 { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
453 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
a5ae2062 454 static const __u8 n1[6] =
6a7eba24 455 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
a5ae2062 456 static const __u8 n2[2] =
6a7eba24 457 {0x08, 0x00};
a5ae2062 458 static const __u8 nset[6] =
6a7eba24 459 { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
a5ae2062 460 static const __u8 n3[6] =
6a7eba24 461 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
a5ae2062 462 static const __u8 n4[0x46] =
6a7eba24
JFM
463 {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
464 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
465 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
466 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
467 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
468 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
469 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
470 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
471 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
a5ae2062 472 static const __u8 nset4[18] = {
6a7eba24
JFM
473 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
474 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
475 0xe8, 0xe0
476 };
477 /* ojo puede ser 0xe6 en vez de 0xe9 */
a5ae2062 478 static const __u8 nset2[20] = {
6a7eba24
JFM
479 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
480 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
481 0xd8, 0xc8, 0xd9, 0xfc
482 };
a5ae2062 483 static const __u8 missing[8] =
6a7eba24 484 { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
a5ae2062 485 static const __u8 nset3[18] = {
6a7eba24
JFM
486 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
487 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
488 0xcf, 0xe0
489 };
a5ae2062 490 static const __u8 nset5[4] =
6a7eba24 491 { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */
a5ae2062 492 static const __u8 nset6[34] = {
6a7eba24
JFM
493 0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
494 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
495 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
496 0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
497 0xa0, 0xff
498 }; /* Gamma */
a5ae2062 499 static const __u8 nset7[4] =
6a7eba24 500 { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */
a5ae2062 501 static const __u8 nset9[4] =
6a7eba24 502 { 0x0b, 0x04, 0x0a, 0x78 };
a5ae2062 503 static const __u8 nset8[6] =
6a7eba24 504 { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
a5ae2062 505 static const __u8 nset10[6] =
6a7eba24
JFM
506 { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
507
739570bb
JFM
508 reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
509 reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
510 reg_r_1(gspca_dev, 0x0063);
511 reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
6a7eba24
JFM
512
513 while (read_indexs[i] != 0x00) {
739570bb
JFM
514 test_byte = reg_r_1(gspca_dev, read_indexs[i]);
515 PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
6a7eba24
JFM
516 test_byte);
517 i++;
518 }
519
739570bb
JFM
520 reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
521 reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
522 reg_r_1(gspca_dev, 0x0080);
523 reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
524 reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
525 reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
526 reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
527 reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
528 reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
529 reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
530 reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
531 reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
532 reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
533 reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
534 reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
535
536 reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
537
538 reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
539 reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
540 reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
541
542 reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
543 reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
544 reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
545 reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
546
547 reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
548 reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
549 reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
550 reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
6a7eba24
JFM
551
552 return 0;
553}
554
555static void setbrightness(struct gspca_dev *gspca_dev)
556{
557 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24 558 unsigned int brightness;
a5ae2062 559 __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
6a7eba24
JFM
560 brightness = sd->brightness;
561
562 if (brightness < 7) {
563 set6[3] = 0x70 - (brightness * 0xa);
564 } else {
565 set6[1] = 0x24;
566 set6[3] = 0x00 + ((brightness - 7) * 0xa);
567 }
568
739570bb 569 reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
6a7eba24
JFM
570}
571
572static void setflip(struct gspca_dev *gspca_dev)
573{
574 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24 575
a5ae2062 576 __u8 flipcmd[8] =
6a7eba24
JFM
577 { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
578
579 if (sd->mirror == 1)
580 flipcmd[3] = 0x01;
581
739570bb 582 reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
6a7eba24
JFM
583}
584
585static void seteffect(struct gspca_dev *gspca_dev)
586{
587 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24 588
739570bb 589 reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
6a7eba24
JFM
590 if (sd->effect == 1 || sd->effect == 5) {
591 PDEBUG(D_CONF,
592 "This effect have been disabled for webcam \"safety\"");
593 return;
594 }
595
596 if (sd->effect == 1 || sd->effect == 4)
739570bb 597 reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
6a7eba24 598 else
739570bb 599 reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
6a7eba24
JFM
600}
601
602static void setwhitebalance(struct gspca_dev *gspca_dev)
603{
604 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24 605
a5ae2062 606 __u8 white_balance[8] =
6a7eba24
JFM
607 { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
608
609 if (sd->whitebalance == 1)
610 white_balance[7] = 0x3c;
611
739570bb 612 reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
6a7eba24
JFM
613}
614
615static void setlightfreq(struct gspca_dev *gspca_dev)
616{
617 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24
JFM
618 __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
619
620 if (sd->freq == 2) /* 60hz */
621 freq[1] = 0x00;
622
739570bb 623 reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
6a7eba24
JFM
624}
625
626static void setcontrast(struct gspca_dev *gspca_dev)
627{
628 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24
JFM
629 unsigned int contrast = sd->contrast;
630 __u16 reg_to_write = 0x00;
631
632 if (contrast < 7)
633 reg_to_write = 0x8ea9 - (0x200 * contrast);
634 else
635 reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
636
739570bb 637 reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
6a7eba24
JFM
638}
639
640static void setcolors(struct gspca_dev *gspca_dev)
641{
642 struct sd *sd = (struct sd *) gspca_dev;
a5ae2062 643 __u16 reg_to_write;
6a7eba24
JFM
644
645 reg_to_write = 0xc0bb + sd->colors * 0x100;
739570bb 646 reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
6a7eba24
JFM
647}
648
649static void setgamma(struct gspca_dev *gspca_dev)
650{
651}
652
653static void setsharpness(struct gspca_dev *gspca_dev)
654{
655 struct sd *sd = (struct sd *) gspca_dev;
a5ae2062 656 __u16 reg_to_write;
6a7eba24
JFM
657
658 reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
659
739570bb 660 reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
6a7eba24
JFM
661}
662
663static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
664{
665 struct sd *sd = (struct sd *) gspca_dev;
666
667 sd->brightness = val;
668 if (gspca_dev->streaming)
669 setbrightness(gspca_dev);
670 return 0;
671}
672
673static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
674{
675 struct sd *sd = (struct sd *) gspca_dev;
a5ae2062 676
6a7eba24
JFM
677 *val = sd->brightness;
678 return *val;
679}
680
681static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
682{
683 struct sd *sd = (struct sd *) gspca_dev;
684
685 sd->whitebalance = val;
686 if (gspca_dev->streaming)
687 setwhitebalance(gspca_dev);
688 return 0;
689}
690
691static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
692{
693 struct sd *sd = (struct sd *) gspca_dev;
694
695 *val = sd->whitebalance;
696 return *val;
697}
698
6a7eba24
JFM
699static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
700{
701 struct sd *sd = (struct sd *) gspca_dev;
702
703 sd->mirror = val;
704 if (gspca_dev->streaming)
705 setflip(gspca_dev);
706 return 0;
707}
708
709static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
710{
711 struct sd *sd = (struct sd *) gspca_dev;
712
713 *val = sd->mirror;
714 return *val;
715}
716
717static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
718{
719 struct sd *sd = (struct sd *) gspca_dev;
720
721 sd->effect = val;
722 if (gspca_dev->streaming)
723 seteffect(gspca_dev);
724 return 0;
725}
726
727static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
728{
729 struct sd *sd = (struct sd *) gspca_dev;
730
731 *val = sd->effect;
732 return *val;
733}
734
735static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
736{
737 struct sd *sd = (struct sd *) gspca_dev;
738
739 sd->contrast = val;
740 if (gspca_dev->streaming)
741 setcontrast(gspca_dev);
742 return 0;
743}
744
745static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
746{
747 struct sd *sd = (struct sd *) gspca_dev;
748
749 *val = sd->contrast;
750 return *val;
751}
752
753static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
754{
755 struct sd *sd = (struct sd *) gspca_dev;
756
757 sd->colors = val;
758 if (gspca_dev->streaming)
759 setcolors(gspca_dev);
760 return 0;
761}
762
763static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
764{
765 struct sd *sd = (struct sd *) gspca_dev;
766
767 *val = sd->colors;
768 return 0;
769}
770
771static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
772{
773 struct sd *sd = (struct sd *) gspca_dev;
774
775 sd->gamma = val;
776 if (gspca_dev->streaming)
777 setgamma(gspca_dev);
778 return 0;
779}
780
781static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
782{
783 struct sd *sd = (struct sd *) gspca_dev;
784 *val = sd->gamma;
785 return 0;
786}
787
788static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
789{
790 struct sd *sd = (struct sd *) gspca_dev;
791
792 sd->freq = val;
793 if (gspca_dev->streaming)
794 setlightfreq(gspca_dev);
795 return 0;
796}
797
798static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
799{
800 struct sd *sd = (struct sd *) gspca_dev;
801
802 *val = sd->freq;
803 return 0;
804}
805
806static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
807{
808 struct sd *sd = (struct sd *) gspca_dev;
809
810 sd->sharpness = val;
811 if (gspca_dev->streaming)
812 setsharpness(gspca_dev);
813 return 0;
814}
815
816static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
817{
818 struct sd *sd = (struct sd *) gspca_dev;
819
820 *val = sd->sharpness;
821 return 0;
822}
823
824/* Low Light set here......*/
825static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
826{
827 struct sd *sd = (struct sd *) gspca_dev;
6a7eba24
JFM
828
829 sd->autogain = val;
830 if (val != 0)
739570bb 831 reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
6a7eba24 832 else
739570bb 833 reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
6a7eba24
JFM
834 return 0;
835}
836
837static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
838{
839 struct sd *sd = (struct sd *) gspca_dev;
840
841 *val = sd->autogain;
842 return 0;
843}
844
845static void sd_start(struct gspca_dev *gspca_dev)
846{
6a7eba24 847 int mode;
6a7eba24 848
a5ae2062 849 static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
6a7eba24 850 __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
a5ae2062 851 static const __u8 t3[] =
6a7eba24
JFM
852 { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
853 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
a5ae2062 854 static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
6a7eba24 855
c2446b3e 856 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
6a7eba24
JFM
857 switch (mode) {
858 case 1: /* 352x288 */
859 t2[1] = 0x40;
860 break;
861 case 2: /* 320x240 */
862 t2[1] = 0x10;
863 break;
864 case 3: /* 176x144 */
865 t2[1] = 0x50;
866 break;
867 case 4: /* 160x120 */
868 t2[1] = 0x20;
869 break;
870 default: /* 640x480 (0x00) */
871 break;
872 }
873
739570bb
JFM
874 reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
875 reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
876 reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
877 reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
878 reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
6a7eba24 879 /* just in case and to keep sync with logs (for mine) */
739570bb
JFM
880 reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
881 reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
6a7eba24 882 /* just in case and to keep sync with logs (for mine) */
739570bb
JFM
883 reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
884 reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
885 reg_r_1(gspca_dev, 0x0012);
886 reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
887 reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
888 reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
6a7eba24
JFM
889 /* restart on each start, just in case, sometimes regs goes wrong
890 * when using controls from app */
891 setbrightness(gspca_dev);
892 setcontrast(gspca_dev);
893 setcolors(gspca_dev);
894}
895
896static void sd_stopN(struct gspca_dev *gspca_dev)
897{
898}
899
900static void sd_stop0(struct gspca_dev *gspca_dev)
901{
902}
903
904static void sd_close(struct gspca_dev *gspca_dev)
905{
906}
907
908static void sd_pkt_scan(struct gspca_dev *gspca_dev,
909 struct gspca_frame *frame, /* target */
a5ae2062 910 __u8 *data, /* isoc packet */
6a7eba24
JFM
911 int len) /* iso packet length */
912{
913 int sof = 0;
a5ae2062 914 static __u8 ffd9[] = { 0xff, 0xd9 };
6a7eba24
JFM
915
916 if (data[0] == 0x5a) {
917 /* Control Packet, after this came the header again,
918 * but extra bytes came in the packet before this,
919 * sometimes an EOF arrives, sometimes not... */
920 return;
921 }
922
923 if (data[len - 1] == 0xff && data[len] == 0xd9) {
924 /* Just in case, i have seen packets with the marker,
925 * other's do not include it... */
926 data += 2;
927 len -= 4;
928 } else if (data[2] == 0xff && data[3] == 0xd8) {
929 sof = 1;
930 data += 2;
931 len -= 2;
932 } else {
933 data += 2;
934 len -= 2;
935 }
936
937 if (sof) {
938 /* extra bytes....., could be processed too but would be
939 * a waste of time, right now leave the application and
940 * libjpeg do it for ourserlves.. */
941 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
942 ffd9, 2);
943 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
944 return;
945 }
946
947 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
948}
949
950static int sd_querymenu(struct gspca_dev *gspca_dev,
951 struct v4l2_querymenu *menu)
952{
6a7eba24
JFM
953 switch (menu->id) {
954 case V4L2_CID_POWER_LINE_FREQUENCY:
955 switch (menu->index) {
956 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
a5ae2062 957 strcpy((char *) menu->name, "50 Hz");
6a7eba24
JFM
958 return 0;
959 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
a5ae2062 960 strcpy((char *) menu->name, "60 Hz");
6a7eba24
JFM
961 return 0;
962 }
963 break;
964 case V4L2_CID_EFFECTS:
a5ae2062
JFM
965 if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
966 strncpy((char *) menu->name,
967 effects_control[menu->index], 32);
968 return 0;
969 }
6a7eba24
JFM
970 break;
971 }
a5ae2062 972 return -EINVAL;
6a7eba24
JFM
973}
974
975/* this function is called at open time */
976static int sd_open(struct gspca_dev *gspca_dev)
977{
978 init_default_parameters(gspca_dev);
979 return 0;
980}
981
982/* sub-driver description */
a5ae2062 983static const struct sd_desc sd_desc = {
6a7eba24
JFM
984 .name = MODULE_NAME,
985 .ctrls = sd_ctrls,
986 .nctrls = ARRAY_SIZE(sd_ctrls),
987 .config = sd_config,
988 .open = sd_open,
989 .start = sd_start,
990 .stopN = sd_stopN,
991 .stop0 = sd_stop0,
992 .close = sd_close,
993 .pkt_scan = sd_pkt_scan,
994 .querymenu = sd_querymenu,
995};
996
997/* -- module initialisation -- */
998#define DVNM(name) .driver_info = (kernel_ulong_t) name
a5ae2062 999static const __devinitdata struct usb_device_id device_table[] = {
6a7eba24
JFM
1000 {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
1001 {}
1002};
6a7eba24
JFM
1003MODULE_DEVICE_TABLE(usb, device_table);
1004
1005/* -- device connect -- */
1006static int sd_probe(struct usb_interface *intf,
1007 const struct usb_device_id *id)
1008{
1009 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1010 THIS_MODULE);
1011}
1012
1013static struct usb_driver sd_driver = {
1014 .name = MODULE_NAME,
1015 .id_table = device_table,
1016 .probe = sd_probe,
1017 .disconnect = gspca_disconnect,
1018};
1019
1020/* -- module insert / remove -- */
1021static int __init sd_mod_init(void)
1022{
1023 if (usb_register(&sd_driver) < 0)
1024 return -1;
10b0e96e 1025 PDEBUG(D_PROBE, "registered");
6a7eba24
JFM
1026 return 0;
1027}
1028static void __exit sd_mod_exit(void)
1029{
1030 usb_deregister(&sd_driver);
1031 PDEBUG(D_PROBE, "deregistered");
1032}
1033
1034module_init(sd_mod_init);
1035module_exit(sd_mod_exit);