]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/gspca/pac207.c
V4L/DVB (8820): gspca: Change initialization and gamma of zc3xx - pas106.
[mirror_ubuntu-artful-kernel.git] / drivers / media / video / gspca / pac207.c
CommitLineData
e2997a72
HG
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
e2997a72
HG
30MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
31MODULE_DESCRIPTION("Pixart PAC207");
32MODULE_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
46ccdafa
HG
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
e2997a72 49#define PAC207_EXPOSURE_MAX 26
46ccdafa 50#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
e2997a72
HG
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
e2997a72
HG
66/* specific webcam descriptor */
67struct sd {
68 struct gspca_dev gspca_dev; /* !! must be the first item */
69
e2997a72
HG
70 u8 mode;
71
72 u8 brightness;
73 u8 exposure;
74 u8 autogain;
75 u8 gain;
76
77 u8 sof_read;
ab8f12cf 78 u8 header_read;
e2997a72
HG
79 u8 autogain_ignore_frames;
80
81 atomic_t avg_lum;
82};
83
84/* V4L2 controls supported by the driver */
85static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
91static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
93
94static 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,
66e4124f
JFM
134#define AUTOGAIN_DEF 1
135 .default_value = AUTOGAIN_DEF,
e2997a72
HG
136 .flags = 0,
137 },
138 .set = sd_setautogain,
139 .get = sd_getautogain,
140 },
141#define SD_GAIN 3
142 {
143 {
144 .id = V4L2_CID_GAIN,
145 .type = V4L2_CTRL_TYPE_INTEGER,
146 .name = "gain",
147 .minimum = PAC207_GAIN_MIN,
148 .maximum = PAC207_GAIN_MAX,
149 .step = 1,
150 .default_value = PAC207_GAIN_DEFAULT,
151 .flags = 0,
152 },
153 .set = sd_setgain,
154 .get = sd_getgain,
155 },
156};
157
c2446b3e
JFM
158static struct v4l2_pix_format sif_mode[] = {
159 {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
160 .bytesperline = 176,
161 .sizeimage = (176 + 2) * 144,
162 /* uncompressed, add 2 bytes / line for line header */
163 .colorspace = V4L2_COLORSPACE_SRGB,
164 .priv = 1},
165 {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
166 .bytesperline = 352,
80544d3c
HG
167 /* compressed, but only when needed (not compressed
168 when the framerate is low) */
169 .sizeimage = (352 + 2) * 288,
c2446b3e
JFM
170 .colorspace = V4L2_COLORSPACE_SRGB,
171 .priv = 0},
e2997a72
HG
172};
173
174static const __u8 pac207_sensor_init[][8] = {
175 {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
176 {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
177 {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
178 {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
179 {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
180};
181
182 /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
183static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
184
739570bb 185static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
e2997a72
HG
186 const u8 *buffer, u16 length)
187{
188 struct usb_device *udev = gspca_dev->dev;
189 int err;
e2997a72 190
739570bb 191 memcpy(gspca_dev->usb_buf, buffer, length);
e2997a72
HG
192
193 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
194 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
739570bb
JFM
195 0x00, index,
196 gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
e2997a72
HG
197 if (err < 0)
198 PDEBUG(D_ERR,
199 "Failed to write registers to index 0x%04X, error %d)",
200 index, err);
201
202 return err;
203}
204
205
903e10aa 206static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
e2997a72
HG
207{
208 struct usb_device *udev = gspca_dev->dev;
209 int err;
210
211 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
212 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
213 value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
214 if (err)
215 PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
216 " value 0x%02X, error %d)", index, value, err);
217
218 return err;
219}
220
903e10aa 221static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
e2997a72
HG
222{
223 struct usb_device *udev = gspca_dev->dev;
e2997a72
HG
224 int res;
225
226 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
227 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
739570bb
JFM
228 0x00, index,
229 gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
e2997a72
HG
230 if (res < 0) {
231 PDEBUG(D_ERR,
232 "Failed to read a register (index 0x%04X, error %d)",
233 index, res);
234 return res;
235 }
236
739570bb 237 return gspca_dev->usb_buf[0];
e2997a72
HG
238}
239
e2997a72
HG
240/* this function is called at probe time */
241static int sd_config(struct gspca_dev *gspca_dev,
242 const struct usb_device_id *id)
243{
4aa0d037 244 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
245 struct cam *cam;
246 u8 idreg[2];
247
248 idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
249 idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
250 idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
251 idreg[1] = idreg[1] & 0x0f;
252 PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
253 idreg[0], idreg[1]);
254
255 if (idreg[0] != 0x27) {
256 PDEBUG(D_PROBE, "Error invalid sensor ID!");
257 return -ENODEV;
258 }
259
e2997a72
HG
260 PDEBUG(D_PROBE,
261 "Pixart PAC207BCA Image Processor and Control Chip detected"
262 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
263
264 cam = &gspca_dev->cam;
e2997a72
HG
265 cam->epaddr = 0x05;
266 cam->cam_mode = sif_mode;
267 cam->nmodes = ARRAY_SIZE(sif_mode);
4aa0d037
JFM
268 sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
269 sd->exposure = PAC207_EXPOSURE_DEFAULT;
270 sd->gain = PAC207_GAIN_DEFAULT;
66e4124f 271 sd->autogain = AUTOGAIN_DEF;
e2997a72
HG
272
273 return 0;
274}
275
276/* this function is called at open time */
277static int sd_open(struct gspca_dev *gspca_dev)
278{
66e4124f
JFM
279 pac207_write_reg(gspca_dev, 0x41, 0x00);
280 /* Bit_0=Image Format,
281 * Bit_1=LED,
282 * Bit_2=Compression test mode enable */
283 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
284 pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
e2997a72 285
e2997a72
HG
286 return 0;
287}
288
289/* -- start the camera -- */
290static void sd_start(struct gspca_dev *gspca_dev)
291{
292 struct sd *sd = (struct sd *) gspca_dev;
293 __u8 mode;
294
295 pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
296 pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
297 pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
298 pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
299 pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
300 pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
301 pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
302
303 /* Compression Balance */
304 if (gspca_dev->width == 176)
305 pac207_write_reg(gspca_dev, 0x4a, 0xff);
306 else
307 pac207_write_reg(gspca_dev, 0x4a, 0x88);
308 pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
309 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
310
311 /* PGA global gain (Bit 4-0) */
312 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
313 pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
314
315 mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
d43fa32f 316 if (gspca_dev->width == 176) { /* 176x144 */
e2997a72
HG
317 mode |= 0x01;
318 PDEBUG(D_STREAM, "pac207_start mode 176x144");
d43fa32f 319 } else { /* 352x288 */
e2997a72 320 PDEBUG(D_STREAM, "pac207_start mode 352x288");
d43fa32f 321 }
e2997a72
HG
322 pac207_write_reg(gspca_dev, 0x41, mode);
323
324 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
325 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
6a7eba24 326 msleep(10);
e2997a72
HG
327 pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
328
329 sd->sof_read = 0;
330 sd->autogain_ignore_frames = 0;
331 atomic_set(&sd->avg_lum, -1);
332}
333
334static void sd_stopN(struct gspca_dev *gspca_dev)
335{
336 pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
337 pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
338 pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
339}
340
341static void sd_stop0(struct gspca_dev *gspca_dev)
342{
343}
344
345/* this function is called at close time */
346static void sd_close(struct gspca_dev *gspca_dev)
347{
348}
349
e2997a72
HG
350static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
351{
352 struct sd *sd = (struct sd *) gspca_dev;
e2997a72
HG
353 int avg_lum = atomic_read(&sd->avg_lum);
354
dcef3237 355 if (avg_lum == -1)
e2997a72
HG
356 return;
357
dcef3237 358 if (sd->autogain_ignore_frames > 0)
e2997a72 359 sd->autogain_ignore_frames--;
dcef3237
HG
360 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
361 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
362 PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
e2997a72 363 sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
e2997a72
HG
364}
365
327c4abf
HG
366/* Include pac common sof detection functions */
367#include "pac_common.h"
e2997a72 368
e2997a72
HG
369static void sd_pkt_scan(struct gspca_dev *gspca_dev,
370 struct gspca_frame *frame,
a5ae2062 371 __u8 *data,
e2997a72
HG
372 int len)
373{
ab8f12cf 374 struct sd *sd = (struct sd *) gspca_dev;
e2997a72 375 unsigned char *sof;
e2997a72 376
327c4abf 377 sof = pac_find_sof(gspca_dev, data, len);
e2997a72 378 if (sof) {
ab8f12cf
HG
379 int n;
380
e2997a72 381 /* finish decoding current frame */
ab8f12cf 382 n = sof - data;
327c4abf
HG
383 if (n > sizeof pac_sof_marker)
384 n -= sizeof pac_sof_marker;
ab8f12cf
HG
385 else
386 n = 0;
387 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
388 data, n);
389 sd->header_read = 0;
6a7eba24 390 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
e2997a72
HG
391 len -= sof - data;
392 data = sof;
393 }
ab8f12cf
HG
394 if (sd->header_read < 11) {
395 int needed;
e2997a72 396
ab8f12cf
HG
397 /* get average lumination from frame header (byte 5) */
398 if (sd->header_read < 5) {
399 needed = 5 - sd->header_read;
400 if (len >= needed)
401 atomic_set(&sd->avg_lum, data[needed - 1]);
402 }
403 /* skip the rest of the header */
404 needed = 11 - sd->header_read;
405 if (len <= needed) {
406 sd->header_read += len;
407 return;
408 }
409 data += needed;
410 len -= needed;
411 sd->header_read = 11;
412 }
e2997a72 413
ab8f12cf 414 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
e2997a72
HG
415}
416
417static void setbrightness(struct gspca_dev *gspca_dev)
418{
419 struct sd *sd = (struct sd *) gspca_dev;
420
421 pac207_write_reg(gspca_dev, 0x08, sd->brightness);
422 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
423 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
424}
425
426static void setexposure(struct gspca_dev *gspca_dev)
427{
428 struct sd *sd = (struct sd *) gspca_dev;
429
430 pac207_write_reg(gspca_dev, 0x02, sd->exposure);
431 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
432 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
433}
434
435static void setgain(struct gspca_dev *gspca_dev)
436{
437 struct sd *sd = (struct sd *) gspca_dev;
438
439 pac207_write_reg(gspca_dev, 0x0e, sd->gain);
440 pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
441 pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
442}
443
444static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
445{
446 struct sd *sd = (struct sd *) gspca_dev;
447
448 sd->brightness = val;
449 if (gspca_dev->streaming)
450 setbrightness(gspca_dev);
451 return 0;
452}
453
454static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
455{
456 struct sd *sd = (struct sd *) gspca_dev;
457
458 *val = sd->brightness;
459 return 0;
460}
461
462static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
463{
464 struct sd *sd = (struct sd *) gspca_dev;
465
e2997a72
HG
466 sd->exposure = val;
467 if (gspca_dev->streaming)
468 setexposure(gspca_dev);
469 return 0;
470}
471
472static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
473{
474 struct sd *sd = (struct sd *) gspca_dev;
475
476 *val = sd->exposure;
477 return 0;
478}
479
480static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
481{
482 struct sd *sd = (struct sd *) gspca_dev;
483
e2997a72
HG
484 sd->gain = val;
485 if (gspca_dev->streaming)
486 setgain(gspca_dev);
487 return 0;
488}
489
490static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
491{
492 struct sd *sd = (struct sd *) gspca_dev;
493
494 *val = sd->gain;
495 return 0;
496}
497
498static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
499{
500 struct sd *sd = (struct sd *) gspca_dev;
501
502 sd->autogain = val;
503 /* when switching to autogain set defaults to make sure
504 we are on a valid point of the autogain gain /
505 exposure knee graph, and give this change time to
506 take effect before doing autogain. */
507 if (sd->autogain) {
508 sd->exposure = PAC207_EXPOSURE_DEFAULT;
509 sd->gain = PAC207_GAIN_DEFAULT;
510 if (gspca_dev->streaming) {
511 sd->autogain_ignore_frames =
512 PAC207_AUTOGAIN_IGNORE_FRAMES;
513 setexposure(gspca_dev);
514 setgain(gspca_dev);
515 }
516 }
517
518 return 0;
519}
520
521static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
522{
523 struct sd *sd = (struct sd *) gspca_dev;
524
525 *val = sd->autogain;
526 return 0;
527}
528
529/* sub-driver description */
a5ae2062 530static const struct sd_desc sd_desc = {
e2997a72
HG
531 .name = MODULE_NAME,
532 .ctrls = sd_ctrls,
533 .nctrls = ARRAY_SIZE(sd_ctrls),
534 .config = sd_config,
535 .open = sd_open,
536 .start = sd_start,
537 .stopN = sd_stopN,
538 .stop0 = sd_stop0,
539 .close = sd_close,
540 .dq_callback = pac207_do_auto_gain,
541 .pkt_scan = sd_pkt_scan,
542};
543
544/* -- module initialisation -- */
a5ae2062 545static const __devinitdata struct usb_device_id device_table[] = {
9d64fdb1
JFM
546 {USB_DEVICE(0x041e, 0x4028)},
547 {USB_DEVICE(0x093a, 0x2460)},
548 {USB_DEVICE(0x093a, 0x2463)},
549 {USB_DEVICE(0x093a, 0x2464)},
550 {USB_DEVICE(0x093a, 0x2468)},
551 {USB_DEVICE(0x093a, 0x2470)},
552 {USB_DEVICE(0x093a, 0x2471)},
553 {USB_DEVICE(0x093a, 0x2472)},
554 {USB_DEVICE(0x2001, 0xf115)},
e2997a72
HG
555 {}
556};
557MODULE_DEVICE_TABLE(usb, device_table);
558
559/* -- device connect -- */
560static int sd_probe(struct usb_interface *intf,
561 const struct usb_device_id *id)
562{
d43fa32f
JFM
563 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
564 THIS_MODULE);
e2997a72
HG
565}
566
567static struct usb_driver sd_driver = {
568 .name = MODULE_NAME,
569 .id_table = device_table,
570 .probe = sd_probe,
571 .disconnect = gspca_disconnect,
6a709749
JFM
572#ifdef CONFIG_PM
573 .suspend = gspca_suspend,
574 .resume = gspca_resume,
575#endif
e2997a72
HG
576};
577
578/* -- module insert / remove -- */
579static int __init sd_mod_init(void)
580{
e2997a72
HG
581 if (usb_register(&sd_driver) < 0)
582 return -1;
903e10aa 583 PDEBUG(D_PROBE, "registered");
e2997a72
HG
584 return 0;
585}
586static void __exit sd_mod_exit(void)
587{
588 usb_deregister(&sd_driver);
589 PDEBUG(D_PROBE, "deregistered");
590}
591
592module_init(sd_mod_init);
593module_exit(sd_mod_exit);