blob: 82cdd43aada9e138e026fd19f68f15f6da40dcf5 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
Hans de Goede327c4ab2008-09-03 17:12:14 -030022/* Some documentation about various registers as determined by trial and error.
23 When the register addresses differ between the 7202 and the 7311 the 2
24 different addresses are written as 7302addr/7311addr, when one of the 2
25 addresses is a - sign that register description is not valid for the
26 matching IC.
27
28 Register page 1:
29
30 Address Description
31 -/0x08 Unknown compressor related, must always be 8 except when not
32 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
33 -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
34 bits 345 seem to toggle per color gains on/off (inverted)
35 0x78 Global control, bit 6 controls the LED (inverted)
36 -/0x80 JPEG compression ratio ? Best not touched
37
38 Register page 3/4:
39
40 Address Description
41 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
Hans de Goede038ec7c2008-09-03 17:12:18 -030042 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
Hans de Goede327c4ab2008-09-03 17:12:14 -030043 -/0x0f Master gain 1-245, low value = high gain
44 0x10/- Master gain 0-31
45 -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goede8a5b2e92008-09-03 17:12:17 -030047 -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
48 completely disable the analog amplification block. Set to 0x68
49 for max gain, 0x14 for minimal gain.
Hans de Goede327c4ab2008-09-03 17:12:14 -030050*/
51
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052#define MODULE_NAME "pac7311"
53
54#include "gspca.h"
55
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030056MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
57MODULE_DESCRIPTION("Pixart PAC7311");
58MODULE_LICENSE("GPL");
59
Marton Nemeth1408b842009-11-02 08:13:21 -030060/* specific webcam descriptor for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061struct sd {
62 struct gspca_dev gspca_dev; /* !! must be the first item */
63
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064 unsigned char contrast;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030065 unsigned char gain;
66 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030068 __u8 hflip;
69 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030070
Hans de Goede327c4ab2008-09-03 17:12:14 -030071 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030072 u8 autogain_ignore_frames;
73
74 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075};
76
77/* V4L2 controls supported by the driver */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
79static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030080static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030082static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030086static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
88static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
89static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090
91static struct ctrl sd_ctrls[] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -030092/* This control is for both the 7302 and the 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 {
94 {
95 .id = V4L2_CID_CONTRAST,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Contrast",
98 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030099#define CONTRAST_MAX 255
100 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300102#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300103 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 },
105 .set = sd_setcontrast,
106 .get = sd_getcontrast,
107 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300108/* All controls below are for both the 7302 and the 7311 */
109 {
110 {
111 .id = V4L2_CID_GAIN,
112 .type = V4L2_CTRL_TYPE_INTEGER,
113 .name = "Gain",
114 .minimum = 0,
115#define GAIN_MAX 255
116 .maximum = GAIN_MAX,
117 .step = 1,
118#define GAIN_DEF 127
119#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
120 .default_value = GAIN_DEF,
121 },
122 .set = sd_setgain,
123 .get = sd_getgain,
124 },
125 {
126 {
127 .id = V4L2_CID_EXPOSURE,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "Exposure",
130 .minimum = 0,
131#define EXPOSURE_MAX 255
132 .maximum = EXPOSURE_MAX,
133 .step = 1,
134#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
135#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
136 .default_value = EXPOSURE_DEF,
137 },
138 .set = sd_setexposure,
139 .get = sd_getexposure,
140 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300141 {
142 {
143 .id = V4L2_CID_AUTOGAIN,
144 .type = V4L2_CTRL_TYPE_BOOLEAN,
145 .name = "Auto Gain",
146 .minimum = 0,
147 .maximum = 1,
148 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300149#define AUTOGAIN_DEF 1
150 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 },
152 .set = sd_setautogain,
153 .get = sd_getautogain,
154 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300155 {
156 {
157 .id = V4L2_CID_HFLIP,
158 .type = V4L2_CTRL_TYPE_BOOLEAN,
159 .name = "Mirror",
160 .minimum = 0,
161 .maximum = 1,
162 .step = 1,
163#define HFLIP_DEF 0
164 .default_value = HFLIP_DEF,
165 },
166 .set = sd_sethflip,
167 .get = sd_gethflip,
168 },
169 {
170 {
171 .id = V4L2_CID_VFLIP,
172 .type = V4L2_CTRL_TYPE_BOOLEAN,
173 .name = "Vflip",
174 .minimum = 0,
175 .maximum = 1,
176 .step = 1,
177#define VFLIP_DEF 0
178 .default_value = VFLIP_DEF,
179 },
180 .set = sd_setvflip,
181 .get = sd_getvflip,
182 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183};
184
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300185static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300186 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300187 .bytesperline = 160,
188 .sizeimage = 160 * 120 * 3 / 8 + 590,
189 .colorspace = V4L2_COLORSPACE_JPEG,
190 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300191 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300192 .bytesperline = 320,
193 .sizeimage = 320 * 240 * 3 / 8 + 590,
194 .colorspace = V4L2_COLORSPACE_JPEG,
195 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300196 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300197 .bytesperline = 640,
198 .sizeimage = 640 * 480 * 3 / 8 + 590,
199 .colorspace = V4L2_COLORSPACE_JPEG,
200 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300201};
202
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300203#define LOAD_PAGE3 255
204#define LOAD_PAGE4 254
205#define END_OF_SEQUENCE 0
206
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300207/* pac 7311 */
Hans de Goede271315a2008-09-03 17:12:19 -0300208static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300209 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
210 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
211 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300212 0xff, 0x04,
213 0x27, 0x80,
214 0x28, 0xca,
215 0x29, 0x53,
216 0x2a, 0x0e,
217 0xff, 0x01,
218 0x3e, 0x20,
219};
220
221static const __u8 start_7311[] = {
222/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300223 0xff, 1, 0x01, /* page 1 */
224 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300225 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
226 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
227 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300230 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300231 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
232 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
233 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
234 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
235 0xd0, 0xff,
236 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
237 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
238 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
239 0x18, 0x20,
240 0x96, 3, 0x01, 0x08, 0x04,
241 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
242 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
243 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300244 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300245 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300246 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300247 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300248};
249
Marton Nemeth1408b842009-11-02 08:13:21 -0300250#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300251/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300252static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300253 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
254 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
255 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
257 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300258 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
259 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
260};
261
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300262static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300263 __u8 index,
264 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300266 int ret;
267
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300268 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300269 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300270 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300271 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300272 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300273 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300274 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300275 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300276 if (ret < 0)
277 PDEBUG(D_ERR, "reg_w_buf(): "
278 "Failed to write registers to index 0x%x, error %i",
279 index, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280}
281
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300283static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300284 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300285 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300286{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300287 int ret;
288
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300289 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300290 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300291 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300292 0, /* request */
293 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300294 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300295 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300296 if (ret < 0)
297 PDEBUG(D_ERR, "reg_w(): "
298 "Failed to write register to index 0x%x, value 0x%x, error %i",
299 index, value, ret);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300}
301
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300302static void reg_w_seq(struct gspca_dev *gspca_dev,
303 const __u8 *seq, int len)
304{
305 while (--len >= 0) {
306 reg_w(gspca_dev, seq[0], seq[1]);
307 seq += 2;
308 }
309}
310
311/* load the beginning of a page */
312static void reg_w_page(struct gspca_dev *gspca_dev,
313 const __u8 *page, int len)
314{
315 int index;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300316 int ret;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300317
318 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300319 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300320 continue;
321 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300322 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300323 usb_sndctrlpipe(gspca_dev->dev, 0),
324 0, /* request */
325 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
326 0, index, gspca_dev->usb_buf, 1,
327 500);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300328 if (ret < 0)
329 PDEBUG(D_ERR, "reg_w_page(): "
330 "Failed to write register to index 0x%x, "
331 "value 0x%x, error %i",
332 index, page[index], ret);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300333 }
334}
335
336/* output a variable sequence */
337static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300338 const __u8 *seq,
339 const __u8 *page3, unsigned int page3_len,
340 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300341{
342 int index, len;
343
344 for (;;) {
345 index = *seq++;
346 len = *seq++;
347 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300348 case END_OF_SEQUENCE:
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300349 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300350 case LOAD_PAGE4:
Marton Nemeth1408b842009-11-02 08:13:21 -0300351 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300352 break;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300353 case LOAD_PAGE3:
Marton Nemeth1408b842009-11-02 08:13:21 -0300354 reg_w_page(gspca_dev, page3, page3_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300355 break;
356 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300357 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300358 PDEBUG(D_ERR|D_STREAM,
359 "Incorrect variable sequence");
360 return;
361 }
362 while (len > 0) {
363 if (len < 8) {
364 reg_w_buf(gspca_dev, index, seq, len);
365 seq += len;
366 break;
367 }
368 reg_w_buf(gspca_dev, index, seq, 8);
369 seq += 8;
370 index += 8;
371 len -= 8;
372 }
373 }
374 }
375 /* not reached */
376}
377
Marton Nemeth1408b842009-11-02 08:13:21 -0300378/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379static int sd_config(struct gspca_dev *gspca_dev,
380 const struct usb_device_id *id)
381{
382 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300383 struct cam *cam;
384
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300385 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300386
Marton Nemeth1408b842009-11-02 08:13:21 -0300387 PDEBUG(D_CONF, "Find Sensor PAC7311");
388 cam->cam_mode = vga_mode;
389 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300390
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300391 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300392 sd->gain = GAIN_DEF;
393 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300394 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300395 sd->hflip = HFLIP_DEF;
396 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397 return 0;
398}
399
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300400/* This function is used by pac7311 only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300401static void setcontrast(struct gspca_dev *gspca_dev)
402{
403 struct sd *sd = (struct sd *) gspca_dev;
404
Hans de Goede327c4ab2008-09-03 17:12:14 -0300405 reg_w(gspca_dev, 0xff, 0x04);
406 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409}
410
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300411static void setgain(struct gspca_dev *gspca_dev)
412{
413 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300414 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415
Marton Nemeth1408b842009-11-02 08:13:21 -0300416 if (gain < 1)
417 gain = 1;
418 else if (gain > 245)
419 gain = 245;
420 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
421 reg_w(gspca_dev, 0x0e, 0x00);
422 reg_w(gspca_dev, 0x0f, gain);
423
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300424 /* load registers to sensor (Bit 0, auto clear) */
425 reg_w(gspca_dev, 0x11, 0x01);
426}
427
428static void setexposure(struct gspca_dev *gspca_dev)
429{
430 struct sd *sd = (struct sd *) gspca_dev;
431 __u8 reg;
432
433 /* register 2 of frame 3/4 contains the clock divider configuring the
434 no fps according to the formula: 60 / reg. sd->exposure is the
435 desired exposure time in ms. */
436 reg = 120 * sd->exposure / 1000;
437 if (reg < 2)
438 reg = 2;
439 else if (reg > 63)
440 reg = 63;
441
Marton Nemeth1408b842009-11-02 08:13:21 -0300442 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
443 reg_w(gspca_dev, 0x02, reg);
444 /* Page 1 register 8 must always be 0x08 except when not in
445 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
446 reg_w(gspca_dev, 0xff, 0x01);
447 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
448 reg <= 3)
449 reg_w(gspca_dev, 0x08, 0x09);
450 else
451 reg_w(gspca_dev, 0x08, 0x08);
452
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300453 /* load registers to sensor (Bit 0, auto clear) */
454 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300455}
456
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300457static void sethvflip(struct gspca_dev *gspca_dev)
458{
459 struct sd *sd = (struct sd *) gspca_dev;
460 __u8 data;
461
Marton Nemeth1408b842009-11-02 08:13:21 -0300462 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
463 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300464 reg_w(gspca_dev, 0x21, data);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300465 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300466 reg_w(gspca_dev, 0x11, 0x01);
467}
468
Marton Nemeth1408b842009-11-02 08:13:21 -0300469/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300470static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471{
Marton Nemeth1408b842009-11-02 08:13:21 -0300472 reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
Hans de Goede271315a2008-09-03 17:12:19 -0300473
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 return 0;
475}
476
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300477static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300478{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300479 struct sd *sd = (struct sd *) gspca_dev;
480
Hans de Goede327c4ab2008-09-03 17:12:14 -0300481 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482
Marton Nemeth1408b842009-11-02 08:13:21 -0300483 reg_w_var(gspca_dev, start_7311,
484 NULL, 0,
485 page4_7311, sizeof(page4_7311));
486 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300487 setgain(gspca_dev);
488 setexposure(gspca_dev);
489 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300490
491 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300492 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300493 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300494 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300495 reg_w(gspca_dev, 0x17, 0x20);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300496 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300497 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300498 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300499 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300500 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300501 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300502 break;
503 case 0: /* 640x480 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300504 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300505 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300506 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300507 break;
508 }
509
Hans de Goede327c4ab2008-09-03 17:12:14 -0300510 sd->sof_read = 0;
511 sd->autogain_ignore_frames = 0;
512 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300513
514 /* start stream */
515 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300516 reg_w(gspca_dev, 0x78, 0x05);
517
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300518 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519}
520
521static void sd_stopN(struct gspca_dev *gspca_dev)
522{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300523 reg_w(gspca_dev, 0xff, 0x04);
524 reg_w(gspca_dev, 0x27, 0x80);
525 reg_w(gspca_dev, 0x28, 0xca);
526 reg_w(gspca_dev, 0x29, 0x53);
527 reg_w(gspca_dev, 0x2a, 0x0e);
528 reg_w(gspca_dev, 0xff, 0x01);
529 reg_w(gspca_dev, 0x3e, 0x20);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300530 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
531 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
532 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533}
534
Marton Nemeth1408b842009-11-02 08:13:21 -0300535/* called on streamoff with alt 0 and on disconnect for 7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300536static void sd_stop0(struct gspca_dev *gspca_dev)
537{
538}
539
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300540/* Include pac common sof detection functions */
541#include "pac_common.h"
542
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300543static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300545 struct sd *sd = (struct sd *) gspca_dev;
546 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300547 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300548
549 if (avg_lum == -1)
550 return;
551
Marton Nemeth1408b842009-11-02 08:13:21 -0300552 desired_lum = 200;
553 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300554
555 if (sd->autogain_ignore_frames > 0)
556 sd->autogain_ignore_frames--;
557 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300558 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300559 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300560}
561
Marton Nemeth56f6f552009-10-04 13:58:19 -0300562/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300563static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300564 0xff, 0xd8, /* SOI: Start of Image */
565
566 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
567 0x00, 0x11, /* length = 17 bytes (including this length field) */
568 0x08 /* Precision: 8 */
569 /* 2 bytes is placed here: number of image lines */
570 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300571};
572
Marton Nemeth56f6f552009-10-04 13:58:19 -0300573/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300574static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300575 0x03, /* Number of image components: 3 */
576 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
577 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
578 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
579
580 0xff, 0xda, /* SOS: Start Of Scan */
581 0x00, 0x0c, /* length = 12 bytes (including this length field) */
582 0x03, /* number of components: 3 */
583 0x01, 0x00, /* selector 1, table 0x00 */
584 0x02, 0x11, /* selector 2, table 0x11 */
585 0x03, 0x11, /* selector 3, table 0x11 */
586 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
587 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300588};
589
Marton Nemethcc409c02009-11-02 08:09:34 -0300590static void pac_start_frame(struct gspca_dev *gspca_dev,
591 struct gspca_frame *frame,
592 __u16 lines, __u16 samples_per_line)
593{
594 unsigned char tmpbuf[4];
595
596 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
597 pac_jpeg_header1, sizeof(pac_jpeg_header1));
598
599 tmpbuf[0] = lines >> 8;
600 tmpbuf[1] = lines & 0xff;
601 tmpbuf[2] = samples_per_line >> 8;
602 tmpbuf[3] = samples_per_line & 0xff;
603
604 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
605 tmpbuf, sizeof(tmpbuf));
606 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
607 pac_jpeg_header2, sizeof(pac_jpeg_header2));
608}
609
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300610/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300611static void sd_pkt_scan(struct gspca_dev *gspca_dev,
612 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300613 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300614 int len) /* iso packet length */
615{
616 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300617 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300618
Marton Nemetha6b69e42009-11-02 08:05:51 -0300619 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300620 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300621 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300622
Marton Nemeth1408b842009-11-02 08:13:21 -0300623 /* 6 bytes after the FF D9 EOF marker a number of lumination
624 bytes are send corresponding to different parts of the
625 image, the 14th and 15th byte after the EOF seem to
626 correspond to the center of the image */
627 lum_offset = 24 + sizeof pac_sof_marker;
628 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300629
630 /* Finish decoding current frame */
631 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
632 if (n < 0) {
633 frame->data_end += n;
634 n = 0;
635 }
636 frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
637 data, n);
638 if (gspca_dev->last_packet_type != DISCARD_PACKET &&
639 frame->data_end[-2] == 0xff &&
640 frame->data_end[-1] == 0xd9)
641 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
642 NULL, 0);
643
644 n = sof - data;
645 len -= n;
646 data = sof;
647
648 /* Get average lumination */
649 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300650 n >= lum_offset)
651 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300652 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300653 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300654 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300655
656 /* Start the new frame with the jpeg header */
Marton Nemeth1408b842009-11-02 08:13:21 -0300657 pac_start_frame(gspca_dev, frame,
658 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300659 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300660 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661}
662
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300663static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
664{
665 struct sd *sd = (struct sd *) gspca_dev;
666
667 sd->contrast = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300668 if (gspca_dev->streaming) {
Marton Nemeth1408b842009-11-02 08:13:21 -0300669 setcontrast(gspca_dev);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300670 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671 return 0;
672}
673
674static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
675{
676 struct sd *sd = (struct sd *) gspca_dev;
677
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678 *val = sd->contrast;
679 return 0;
680}
681
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300682static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
683{
684 struct sd *sd = (struct sd *) gspca_dev;
685
686 sd->gain = val;
687 if (gspca_dev->streaming)
688 setgain(gspca_dev);
689 return 0;
690}
691
692static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
693{
694 struct sd *sd = (struct sd *) gspca_dev;
695
696 *val = sd->gain;
697 return 0;
698}
699
700static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
701{
702 struct sd *sd = (struct sd *) gspca_dev;
703
704 sd->exposure = val;
705 if (gspca_dev->streaming)
706 setexposure(gspca_dev);
707 return 0;
708}
709
710static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
711{
712 struct sd *sd = (struct sd *) gspca_dev;
713
714 *val = sd->exposure;
715 return 0;
716}
717
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
719{
720 struct sd *sd = (struct sd *) gspca_dev;
721
722 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300723 /* when switching to autogain set defaults to make sure
724 we are on a valid point of the autogain gain /
725 exposure knee graph, and give this change time to
726 take effect before doing autogain. */
727 if (sd->autogain) {
728 sd->exposure = EXPOSURE_DEF;
729 sd->gain = GAIN_DEF;
730 if (gspca_dev->streaming) {
731 sd->autogain_ignore_frames =
732 PAC_AUTOGAIN_IGNORE_FRAMES;
733 setexposure(gspca_dev);
734 setgain(gspca_dev);
735 }
736 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300737
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 return 0;
739}
740
741static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
742{
743 struct sd *sd = (struct sd *) gspca_dev;
744
745 *val = sd->autogain;
746 return 0;
747}
748
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300749static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
750{
751 struct sd *sd = (struct sd *) gspca_dev;
752
753 sd->hflip = val;
754 if (gspca_dev->streaming)
755 sethvflip(gspca_dev);
756 return 0;
757}
758
759static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
760{
761 struct sd *sd = (struct sd *) gspca_dev;
762
763 *val = sd->hflip;
764 return 0;
765}
766
767static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
768{
769 struct sd *sd = (struct sd *) gspca_dev;
770
771 sd->vflip = val;
772 if (gspca_dev->streaming)
773 sethvflip(gspca_dev);
774 return 0;
775}
776
777static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
778{
779 struct sd *sd = (struct sd *) gspca_dev;
780
781 *val = sd->vflip;
782 return 0;
783}
784
Marton Nemeth1408b842009-11-02 08:13:21 -0300785/* sub-driver description for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300786static struct sd_desc sd_desc = {
787 .name = MODULE_NAME,
788 .ctrls = sd_ctrls,
789 .nctrls = ARRAY_SIZE(sd_ctrls),
790 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300791 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792 .start = sd_start,
793 .stopN = sd_stopN,
794 .stop0 = sd_stop0,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300796 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797};
798
799/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300800static __devinitdata struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300801 {USB_DEVICE(0x093a, 0x2600)},
802 {USB_DEVICE(0x093a, 0x2601)},
803 {USB_DEVICE(0x093a, 0x2603)},
804 {USB_DEVICE(0x093a, 0x2608)},
805 {USB_DEVICE(0x093a, 0x260e)},
806 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 {}
808};
809MODULE_DEVICE_TABLE(usb, device_table);
810
811/* -- device connect -- */
812static int sd_probe(struct usb_interface *intf,
813 const struct usb_device_id *id)
814{
815 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
816 THIS_MODULE);
817}
818
819static struct usb_driver sd_driver = {
820 .name = MODULE_NAME,
821 .id_table = device_table,
822 .probe = sd_probe,
823 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300824#ifdef CONFIG_PM
825 .suspend = gspca_suspend,
826 .resume = gspca_resume,
827#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300828};
829
830/* -- module insert / remove -- */
831static int __init sd_mod_init(void)
832{
Alexey Klimovf69e9522009-01-01 13:02:07 -0300833 int ret;
834 ret = usb_register(&sd_driver);
835 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -0300836 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300837 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 return 0;
839}
840static void __exit sd_mod_exit(void)
841{
842 usb_deregister(&sd_driver);
843 PDEBUG(D_PROBE, "deregistered");
844}
845
846module_init(sd_mod_init);
847module_exit(sd_mod_exit);