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