V4L/DVB (8718): gspca: suspend/resume added.
[linux-2.6.git] / drivers / media / video / gspca / pac207.c
1 /*
2  * Pixart PAC207BCA library
3  *
4  * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
5  * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
6  * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
7  *
8  * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #define MODULE_NAME "pac207"
27
28 #include "gspca.h"
29
30 MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
31 MODULE_DESCRIPTION("Pixart PAC207");
32 MODULE_LICENSE("GPL");
33
34 #define PAC207_CTRL_TIMEOUT             100  /* ms */
35
36 #define PAC207_BRIGHTNESS_MIN           0
37 #define PAC207_BRIGHTNESS_MAX           255
38 #define PAC207_BRIGHTNESS_DEFAULT       4 /* power on default: 4 */
39
40 /* An exposure value of 4 also works (3 does not) but then we need to lower
41    the compression balance setting when in 352x288 mode, otherwise the usb
42    bandwidth is not enough and packets get dropped resulting in corrupt
43    frames. The problem with this is that when the compression balance gets
44    lowered below 0x80, the pac207 starts using a different compression
45    algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
46    and currently we do not know how to decompress these lines, so for now
47    we use a minimum exposure value of 5 */
48 #define PAC207_EXPOSURE_MIN             5
49 #define PAC207_EXPOSURE_MAX             26
50 #define PAC207_EXPOSURE_DEFAULT         5 /* power on default: 3 ?? */
51 #define PAC207_EXPOSURE_KNEE            11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
52
53 #define PAC207_GAIN_MIN                 0
54 #define PAC207_GAIN_MAX                 31
55 #define PAC207_GAIN_DEFAULT             9 /* power on default: 9 */
56 #define PAC207_GAIN_KNEE                20
57
58 #define PAC207_AUTOGAIN_DEADZONE        30
59 /* We calculating the autogain at the end of the transfer of a frame, at this
60    moment a frame with the old settings is being transmitted, and a frame is
61    being captured with the old settings. So if we adjust the autogain we must
62    ignore atleast the 2 next frames for the new settings to come into effect
63    before doing any other adjustments */
64 #define PAC207_AUTOGAIN_IGNORE_FRAMES   3
65
66 /* specific webcam descriptor */
67 struct sd {
68         struct gspca_dev gspca_dev;             /* !! must be the first item */
69
70         u8 mode;
71
72         u8 brightness;
73         u8 exposure;
74         u8 autogain;
75         u8 gain;
76
77         u8 sof_read;
78         u8 header_read;
79         u8 autogain_ignore_frames;
80
81         atomic_t avg_lum;
82 };
83
84 /* V4L2 controls supported by the driver */
85 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
86 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
87 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
88 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
89 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
90 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
91 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
92 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
93
94 static struct ctrl sd_ctrls[] = {
95 #define SD_BRIGHTNESS 0
96         {
97             {
98                 .id      = V4L2_CID_BRIGHTNESS,
99                 .type    = V4L2_CTRL_TYPE_INTEGER,
100                 .name    = "Brightness",
101                 .minimum = PAC207_BRIGHTNESS_MIN,
102                 .maximum = PAC207_BRIGHTNESS_MAX,
103                 .step = 1,
104                 .default_value = PAC207_BRIGHTNESS_DEFAULT,
105                 .flags = 0,
106             },
107             .set = sd_setbrightness,
108             .get = sd_getbrightness,
109         },
110 #define SD_EXPOSURE 1
111         {
112             {
113                 .id = V4L2_CID_EXPOSURE,
114                 .type = V4L2_CTRL_TYPE_INTEGER,
115                 .name = "exposure",
116                 .minimum = PAC207_EXPOSURE_MIN,
117                 .maximum = PAC207_EXPOSURE_MAX,
118                 .step = 1,
119                 .default_value = PAC207_EXPOSURE_DEFAULT,
120                 .flags = 0,
121             },
122             .set = sd_setexposure,
123             .get = sd_getexposure,
124         },
125 #define SD_AUTOGAIN 2
126         {
127             {
128                 .id       = V4L2_CID_AUTOGAIN,
129                 .type   = V4L2_CTRL_TYPE_BOOLEAN,
130                 .name   = "Auto Gain",
131                 .minimum = 0,
132                 .maximum = 1,
133                 .step   = 1,
134                 .default_value = 1,
135                 .flags = 0,
136             },
137             .set = sd_setautogain,
138             .get = sd_getautogain,
139         },
140 #define SD_GAIN 3
141         {
142             {
143                 .id = V4L2_CID_GAIN,
144                 .type = V4L2_CTRL_TYPE_INTEGER,
145                 .name = "gain",
146                 .minimum = PAC207_GAIN_MIN,
147                 .maximum = PAC207_GAIN_MAX,
148                 .step = 1,
149                 .default_value = PAC207_GAIN_DEFAULT,
150                 .flags = 0,
151             },
152             .set = sd_setgain,
153             .get = sd_getgain,
154         },
155 };
156
157 static struct v4l2_pix_format sif_mode[] = {
158         {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
159                 .bytesperline = 176,
160                 .sizeimage = (176 + 2) * 144,
161                         /* uncompressed, add 2 bytes / line for line header */
162                 .colorspace = V4L2_COLORSPACE_SRGB,
163                 .priv = 1},
164         {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
165                 .bytesperline = 352,
166                         /* compressed, but only when needed (not compressed
167                            when the framerate is low) */
168                 .sizeimage = (352 + 2) * 288,
169                 .colorspace = V4L2_COLORSPACE_SRGB,
170                 .priv = 0},
171 };
172
173 static const __u8 pac207_sensor_init[][8] = {
174         {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
175         {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
176         {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
177         {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
178         {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
179 };
180
181                         /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
182 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
183
184 static const unsigned char pac207_sof_marker[5] =
185                 { 0xff, 0xff, 0x00, 0xff, 0x96 };
186
187 static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
188         const u8 *buffer, u16 length)
189 {
190         struct usb_device *udev = gspca_dev->dev;
191         int err;
192
193         memcpy(gspca_dev->usb_buf, buffer, length);
194
195         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
196                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
197                         0x00, index,
198                         gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
199         if (err < 0)
200                 PDEBUG(D_ERR,
201                         "Failed to write registers to index 0x%04X, error %d)",
202                         index, err);
203
204         return err;
205 }
206
207
208 static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
209 {
210         struct usb_device *udev = gspca_dev->dev;
211         int err;
212
213         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
214                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
215                         value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
216         if (err)
217                 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
218                         " value 0x%02X, error %d)", index, value, err);
219
220         return err;
221 }
222
223 static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
224 {
225         struct usb_device *udev = gspca_dev->dev;
226         int res;
227
228         res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
229                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
230                         0x00, index,
231                         gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
232         if (res < 0) {
233                 PDEBUG(D_ERR,
234                         "Failed to read a register (index 0x%04X, error %d)",
235                         index, res);
236                 return res;
237         }
238
239         return gspca_dev->usb_buf[0];
240 }
241
242 /* this function is called at probe time */
243 static int sd_config(struct gspca_dev *gspca_dev,
244                         const struct usb_device_id *id)
245 {
246         struct sd *sd = (struct sd *) gspca_dev;
247         struct cam *cam;
248         u8 idreg[2];
249
250         idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
251         idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
252         idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
253         idreg[1] = idreg[1] & 0x0f;
254         PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
255                 idreg[0], idreg[1]);
256
257         if (idreg[0] != 0x27) {
258                 PDEBUG(D_PROBE, "Error invalid sensor ID!");
259                 return -ENODEV;
260         }
261
262         pac207_write_reg(gspca_dev, 0x41, 0x00);
263                                 /* Bit_0=Image Format,
264                                  * Bit_1=LED,
265                                  * Bit_2=Compression test mode enable */
266         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
267         pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
268
269         PDEBUG(D_PROBE,
270                 "Pixart PAC207BCA Image Processor and Control Chip detected"
271                 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
272
273         cam = &gspca_dev->cam;
274         cam->epaddr = 0x05;
275         cam->cam_mode = sif_mode;
276         cam->nmodes = ARRAY_SIZE(sif_mode);
277         sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
278         sd->exposure = PAC207_EXPOSURE_DEFAULT;
279         sd->gain = PAC207_GAIN_DEFAULT;
280
281         return 0;
282 }
283
284 /* this function is called at open time */
285 static int sd_open(struct gspca_dev *gspca_dev)
286 {
287         struct sd *sd = (struct sd *) gspca_dev;
288
289         sd->autogain = 1;
290         return 0;
291 }
292
293 /* -- start the camera -- */
294 static void sd_start(struct gspca_dev *gspca_dev)
295 {
296         struct sd *sd = (struct sd *) gspca_dev;
297         __u8 mode;
298
299         pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
300         pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
301         pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
302         pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
303         pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
304         pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
305         pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
306
307         /* Compression Balance */
308         if (gspca_dev->width == 176)
309                 pac207_write_reg(gspca_dev, 0x4a, 0xff);
310         else
311                 pac207_write_reg(gspca_dev, 0x4a, 0x88);
312         pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
313         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
314
315         /* PGA global gain (Bit 4-0) */
316         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
317         pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
318
319         mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
320         if (gspca_dev->width == 176) {  /* 176x144 */
321                 mode |= 0x01;
322                 PDEBUG(D_STREAM, "pac207_start mode 176x144");
323         } else {                                /* 352x288 */
324                 PDEBUG(D_STREAM, "pac207_start mode 352x288");
325         }
326         pac207_write_reg(gspca_dev, 0x41, mode);
327
328         pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
329         pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
330         msleep(10);
331         pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
332
333         sd->sof_read = 0;
334         sd->autogain_ignore_frames = 0;
335         atomic_set(&sd->avg_lum, -1);
336 }
337
338 static void sd_stopN(struct gspca_dev *gspca_dev)
339 {
340         pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
341         pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
342         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
343 }
344
345 static void sd_stop0(struct gspca_dev *gspca_dev)
346 {
347 }
348
349 /* this function is called at close time */
350 static void sd_close(struct gspca_dev *gspca_dev)
351 {
352 }
353
354 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
355 {
356         struct sd *sd = (struct sd *) gspca_dev;
357         int avg_lum = atomic_read(&sd->avg_lum);
358
359         if (avg_lum == -1)
360                 return;
361
362         if (sd->autogain_ignore_frames > 0)
363                 sd->autogain_ignore_frames--;
364         else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
365                         100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
366                         PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
367                 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
368 }
369
370 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
371                                         unsigned char *m, int len)
372 {
373         struct sd *sd = (struct sd *) gspca_dev;
374         int i;
375
376         /* Search for the SOF marker (fixed part) in the header */
377         for (i = 0; i < len; i++) {
378                 if (m[i] == pac207_sof_marker[sd->sof_read]) {
379                         sd->sof_read++;
380                         if (sd->sof_read == sizeof(pac207_sof_marker)) {
381                                 PDEBUG(D_STREAM,
382                                         "SOF found, bytes to analyze: %u."
383                                         " Frame starts at byte #%u",
384                                         len, i + 1);
385                                 sd->sof_read = 0;
386                                 return m + i + 1;
387                         }
388                 } else {
389                         sd->sof_read = 0;
390                 }
391         }
392
393         return NULL;
394 }
395
396 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
397                         struct gspca_frame *frame,
398                         __u8 *data,
399                         int len)
400 {
401         struct sd *sd = (struct sd *) gspca_dev;
402         unsigned char *sof;
403
404         sof = pac207_find_sof(gspca_dev, data, len);
405         if (sof) {
406                 int n;
407
408                 /* finish decoding current frame */
409                 n = sof - data;
410                 if (n > sizeof pac207_sof_marker)
411                         n -= sizeof pac207_sof_marker;
412                 else
413                         n = 0;
414                 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
415                                         data, n);
416                 sd->header_read = 0;
417                 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
418                 len -= sof - data;
419                 data = sof;
420         }
421         if (sd->header_read < 11) {
422                 int needed;
423
424                 /* get average lumination from frame header (byte 5) */
425                 if (sd->header_read < 5) {
426                         needed = 5 - sd->header_read;
427                         if (len >= needed)
428                                 atomic_set(&sd->avg_lum, data[needed - 1]);
429                 }
430                 /* skip the rest of the header */
431                 needed = 11 - sd->header_read;
432                 if (len <= needed) {
433                         sd->header_read += len;
434                         return;
435                 }
436                 data += needed;
437                 len -= needed;
438                 sd->header_read = 11;
439         }
440
441         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
442 }
443
444 static void setbrightness(struct gspca_dev *gspca_dev)
445 {
446         struct sd *sd = (struct sd *) gspca_dev;
447
448         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
449         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
450         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
451 }
452
453 static void setexposure(struct gspca_dev *gspca_dev)
454 {
455         struct sd *sd = (struct sd *) gspca_dev;
456
457         pac207_write_reg(gspca_dev, 0x02, sd->exposure);
458         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
459         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
460 }
461
462 static void setgain(struct gspca_dev *gspca_dev)
463 {
464         struct sd *sd = (struct sd *) gspca_dev;
465
466         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
467         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
468         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
469 }
470
471 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
472 {
473         struct sd *sd = (struct sd *) gspca_dev;
474
475         sd->brightness = val;
476         if (gspca_dev->streaming)
477                 setbrightness(gspca_dev);
478         return 0;
479 }
480
481 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
482 {
483         struct sd *sd = (struct sd *) gspca_dev;
484
485         *val = sd->brightness;
486         return 0;
487 }
488
489 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
490 {
491         struct sd *sd = (struct sd *) gspca_dev;
492
493         sd->exposure = val;
494         if (gspca_dev->streaming)
495                 setexposure(gspca_dev);
496         return 0;
497 }
498
499 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
500 {
501         struct sd *sd = (struct sd *) gspca_dev;
502
503         *val = sd->exposure;
504         return 0;
505 }
506
507 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
508 {
509         struct sd *sd = (struct sd *) gspca_dev;
510
511         sd->gain = val;
512         if (gspca_dev->streaming)
513                 setgain(gspca_dev);
514         return 0;
515 }
516
517 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
518 {
519         struct sd *sd = (struct sd *) gspca_dev;
520
521         *val = sd->gain;
522         return 0;
523 }
524
525 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
526 {
527         struct sd *sd = (struct sd *) gspca_dev;
528
529         sd->autogain = val;
530         /* when switching to autogain set defaults to make sure
531            we are on a valid point of the autogain gain /
532            exposure knee graph, and give this change time to
533            take effect before doing autogain. */
534         if (sd->autogain) {
535                 sd->exposure = PAC207_EXPOSURE_DEFAULT;
536                 sd->gain = PAC207_GAIN_DEFAULT;
537                 if (gspca_dev->streaming) {
538                         sd->autogain_ignore_frames =
539                                 PAC207_AUTOGAIN_IGNORE_FRAMES;
540                         setexposure(gspca_dev);
541                         setgain(gspca_dev);
542                 }
543         }
544
545         return 0;
546 }
547
548 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
549 {
550         struct sd *sd = (struct sd *) gspca_dev;
551
552         *val = sd->autogain;
553         return 0;
554 }
555
556 /* sub-driver description */
557 static const struct sd_desc sd_desc = {
558         .name = MODULE_NAME,
559         .ctrls = sd_ctrls,
560         .nctrls = ARRAY_SIZE(sd_ctrls),
561         .config = sd_config,
562         .open = sd_open,
563         .start = sd_start,
564         .stopN = sd_stopN,
565         .stop0 = sd_stop0,
566         .close = sd_close,
567         .dq_callback = pac207_do_auto_gain,
568         .pkt_scan = sd_pkt_scan,
569 };
570
571 /* -- module initialisation -- */
572 static const __devinitdata struct usb_device_id device_table[] = {
573         {USB_DEVICE(0x041e, 0x4028)},
574         {USB_DEVICE(0x093a, 0x2460)},
575         {USB_DEVICE(0x093a, 0x2463)},
576         {USB_DEVICE(0x093a, 0x2464)},
577         {USB_DEVICE(0x093a, 0x2468)},
578         {USB_DEVICE(0x093a, 0x2470)},
579         {USB_DEVICE(0x093a, 0x2471)},
580         {USB_DEVICE(0x093a, 0x2472)},
581         {USB_DEVICE(0x2001, 0xf115)},
582         {}
583 };
584 MODULE_DEVICE_TABLE(usb, device_table);
585
586 /* -- device connect -- */
587 static int sd_probe(struct usb_interface *intf,
588                         const struct usb_device_id *id)
589 {
590         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
591                                 THIS_MODULE);
592 }
593
594 static struct usb_driver sd_driver = {
595         .name = MODULE_NAME,
596         .id_table = device_table,
597         .probe = sd_probe,
598         .disconnect = gspca_disconnect,
599 #ifdef CONFIG_PM
600         .suspend = gspca_suspend,
601         .resume = gspca_resume,
602 #endif
603 };
604
605 /* -- module insert / remove -- */
606 static int __init sd_mod_init(void)
607 {
608         if (usb_register(&sd_driver) < 0)
609                 return -1;
610         PDEBUG(D_PROBE, "registered");
611         return 0;
612 }
613 static void __exit sd_mod_exit(void)
614 {
615         usb_deregister(&sd_driver);
616         PDEBUG(D_PROBE, "deregistered");
617 }
618
619 module_init(sd_mod_init);
620 module_exit(sd_mod_exit);