x86, tracehook: clean up implementation of syscall_get_error()
[pandora-kernel.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->dev_name = (char *) id->driver_info;
275         cam->epaddr = 0x05;
276         cam->cam_mode = sif_mode;
277         cam->nmodes = ARRAY_SIZE(sif_mode);
278         sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
279         sd->exposure = PAC207_EXPOSURE_DEFAULT;
280         sd->gain = PAC207_GAIN_DEFAULT;
281
282         return 0;
283 }
284
285 /* this function is called at open time */
286 static int sd_open(struct gspca_dev *gspca_dev)
287 {
288         struct sd *sd = (struct sd *) gspca_dev;
289
290         sd->autogain = 1;
291         return 0;
292 }
293
294 /* -- start the camera -- */
295 static void sd_start(struct gspca_dev *gspca_dev)
296 {
297         struct sd *sd = (struct sd *) gspca_dev;
298         __u8 mode;
299
300         pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
301         pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
302         pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
303         pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
304         pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
305         pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
306         pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
307
308         /* Compression Balance */
309         if (gspca_dev->width == 176)
310                 pac207_write_reg(gspca_dev, 0x4a, 0xff);
311         else
312                 pac207_write_reg(gspca_dev, 0x4a, 0x88);
313         pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
314         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
315
316         /* PGA global gain (Bit 4-0) */
317         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
318         pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
319
320         mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
321         if (gspca_dev->width == 176) {  /* 176x144 */
322                 mode |= 0x01;
323                 PDEBUG(D_STREAM, "pac207_start mode 176x144");
324         } else {                                /* 352x288 */
325                 PDEBUG(D_STREAM, "pac207_start mode 352x288");
326         }
327         pac207_write_reg(gspca_dev, 0x41, mode);
328
329         pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
330         pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
331         msleep(10);
332         pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
333
334         sd->sof_read = 0;
335         sd->autogain_ignore_frames = 0;
336         atomic_set(&sd->avg_lum, -1);
337 }
338
339 static void sd_stopN(struct gspca_dev *gspca_dev)
340 {
341         pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
342         pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
343         pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
344 }
345
346 static void sd_stop0(struct gspca_dev *gspca_dev)
347 {
348 }
349
350 /* this function is called at close time */
351 static void sd_close(struct gspca_dev *gspca_dev)
352 {
353 }
354
355 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
356 {
357         struct sd *sd = (struct sd *) gspca_dev;
358         int avg_lum = atomic_read(&sd->avg_lum);
359
360         if (avg_lum == -1)
361                 return;
362
363         if (sd->autogain_ignore_frames > 0)
364                 sd->autogain_ignore_frames--;
365         else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
366                         100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
367                         PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
368                 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
369 }
370
371 static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
372                                         unsigned char *m, int len)
373 {
374         struct sd *sd = (struct sd *) gspca_dev;
375         int i;
376
377         /* Search for the SOF marker (fixed part) in the header */
378         for (i = 0; i < len; i++) {
379                 if (m[i] == pac207_sof_marker[sd->sof_read]) {
380                         sd->sof_read++;
381                         if (sd->sof_read == sizeof(pac207_sof_marker)) {
382                                 PDEBUG(D_STREAM,
383                                         "SOF found, bytes to analyze: %u."
384                                         " Frame starts at byte #%u",
385                                         len, i + 1);
386                                 sd->sof_read = 0;
387                                 return m + i + 1;
388                         }
389                 } else {
390                         sd->sof_read = 0;
391                 }
392         }
393
394         return NULL;
395 }
396
397 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
398                         struct gspca_frame *frame,
399                         __u8 *data,
400                         int len)
401 {
402         struct sd *sd = (struct sd *) gspca_dev;
403         unsigned char *sof;
404
405         sof = pac207_find_sof(gspca_dev, data, len);
406         if (sof) {
407                 int n;
408
409                 /* finish decoding current frame */
410                 n = sof - data;
411                 if (n > sizeof pac207_sof_marker)
412                         n -= sizeof pac207_sof_marker;
413                 else
414                         n = 0;
415                 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
416                                         data, n);
417                 sd->header_read = 0;
418                 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
419                 len -= sof - data;
420                 data = sof;
421         }
422         if (sd->header_read < 11) {
423                 int needed;
424
425                 /* get average lumination from frame header (byte 5) */
426                 if (sd->header_read < 5) {
427                         needed = 5 - sd->header_read;
428                         if (len >= needed)
429                                 atomic_set(&sd->avg_lum, data[needed - 1]);
430                 }
431                 /* skip the rest of the header */
432                 needed = 11 - sd->header_read;
433                 if (len <= needed) {
434                         sd->header_read += len;
435                         return;
436                 }
437                 data += needed;
438                 len -= needed;
439                 sd->header_read = 11;
440         }
441
442         gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
443 }
444
445 static void setbrightness(struct gspca_dev *gspca_dev)
446 {
447         struct sd *sd = (struct sd *) gspca_dev;
448
449         pac207_write_reg(gspca_dev, 0x08, sd->brightness);
450         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
451         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
452 }
453
454 static void setexposure(struct gspca_dev *gspca_dev)
455 {
456         struct sd *sd = (struct sd *) gspca_dev;
457
458         pac207_write_reg(gspca_dev, 0x02, sd->exposure);
459         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
460         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
461 }
462
463 static void setgain(struct gspca_dev *gspca_dev)
464 {
465         struct sd *sd = (struct sd *) gspca_dev;
466
467         pac207_write_reg(gspca_dev, 0x0e, sd->gain);
468         pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
469         pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
470 }
471
472 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
473 {
474         struct sd *sd = (struct sd *) gspca_dev;
475
476         sd->brightness = val;
477         if (gspca_dev->streaming)
478                 setbrightness(gspca_dev);
479         return 0;
480 }
481
482 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
483 {
484         struct sd *sd = (struct sd *) gspca_dev;
485
486         *val = sd->brightness;
487         return 0;
488 }
489
490 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
491 {
492         struct sd *sd = (struct sd *) gspca_dev;
493
494         sd->exposure = val;
495         if (gspca_dev->streaming)
496                 setexposure(gspca_dev);
497         return 0;
498 }
499
500 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
501 {
502         struct sd *sd = (struct sd *) gspca_dev;
503
504         *val = sd->exposure;
505         return 0;
506 }
507
508 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
509 {
510         struct sd *sd = (struct sd *) gspca_dev;
511
512         sd->gain = val;
513         if (gspca_dev->streaming)
514                 setgain(gspca_dev);
515         return 0;
516 }
517
518 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
519 {
520         struct sd *sd = (struct sd *) gspca_dev;
521
522         *val = sd->gain;
523         return 0;
524 }
525
526 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
527 {
528         struct sd *sd = (struct sd *) gspca_dev;
529
530         sd->autogain = val;
531         /* when switching to autogain set defaults to make sure
532            we are on a valid point of the autogain gain /
533            exposure knee graph, and give this change time to
534            take effect before doing autogain. */
535         if (sd->autogain) {
536                 sd->exposure = PAC207_EXPOSURE_DEFAULT;
537                 sd->gain = PAC207_GAIN_DEFAULT;
538                 if (gspca_dev->streaming) {
539                         sd->autogain_ignore_frames =
540                                 PAC207_AUTOGAIN_IGNORE_FRAMES;
541                         setexposure(gspca_dev);
542                         setgain(gspca_dev);
543                 }
544         }
545
546         return 0;
547 }
548
549 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
550 {
551         struct sd *sd = (struct sd *) gspca_dev;
552
553         *val = sd->autogain;
554         return 0;
555 }
556
557 /* sub-driver description */
558 static const struct sd_desc sd_desc = {
559         .name = MODULE_NAME,
560         .ctrls = sd_ctrls,
561         .nctrls = ARRAY_SIZE(sd_ctrls),
562         .config = sd_config,
563         .open = sd_open,
564         .start = sd_start,
565         .stopN = sd_stopN,
566         .stop0 = sd_stop0,
567         .close = sd_close,
568         .dq_callback = pac207_do_auto_gain,
569         .pkt_scan = sd_pkt_scan,
570 };
571
572 /* -- module initialisation -- */
573 static const __devinitdata struct usb_device_id device_table[] = {
574         {USB_DEVICE(0x041e, 0x4028)},
575         {USB_DEVICE(0x093a, 0x2460)},
576         {USB_DEVICE(0x093a, 0x2463)},
577         {USB_DEVICE(0x093a, 0x2464)},
578         {USB_DEVICE(0x093a, 0x2468)},
579         {USB_DEVICE(0x093a, 0x2470)},
580         {USB_DEVICE(0x093a, 0x2471)},
581         {USB_DEVICE(0x093a, 0x2472)},
582         {USB_DEVICE(0x2001, 0xf115)},
583         {}
584 };
585 MODULE_DEVICE_TABLE(usb, device_table);
586
587 /* -- device connect -- */
588 static int sd_probe(struct usb_interface *intf,
589                         const struct usb_device_id *id)
590 {
591         return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
592                                 THIS_MODULE);
593 }
594
595 static struct usb_driver sd_driver = {
596         .name = MODULE_NAME,
597         .id_table = device_table,
598         .probe = sd_probe,
599         .disconnect = gspca_disconnect,
600 };
601
602 /* -- module insert / remove -- */
603 static int __init sd_mod_init(void)
604 {
605         if (usb_register(&sd_driver) < 0)
606                 return -1;
607         PDEBUG(D_PROBE, "registered");
608         return 0;
609 }
610 static void __exit sd_mod_exit(void)
611 {
612         usb_deregister(&sd_driver);
613         PDEBUG(D_PROBE, "deregistered");
614 }
615
616 module_init(sd_mod_init);
617 module_exit(sd_mod_exit);