diff options
Diffstat (limited to 'drivers/media/video/gspca/ov534.c')
-rw-r--r-- | drivers/media/video/gspca/ov534.c | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c new file mode 100644 index 000000000000..a574be09bd41 --- /dev/null +++ b/drivers/media/video/gspca/ov534.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* | ||
2 | * ov534/ov772x gspca driver | ||
3 | * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> | ||
4 | * | ||
5 | * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> | ||
6 | * USB protocol reverse engineered by Jim Paris <jim@jtan.com> | ||
7 | * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #define MODULE_NAME "ov534" | ||
25 | |||
26 | #include "gspca.h" | ||
27 | |||
28 | #define OV534_REG_ADDRESS 0xf1 /* ? */ | ||
29 | #define OV534_REG_SUBADDR 0xf2 | ||
30 | #define OV534_REG_WRITE 0xf3 | ||
31 | #define OV534_REG_READ 0xf4 | ||
32 | #define OV534_REG_OPERATION 0xf5 | ||
33 | #define OV534_REG_STATUS 0xf6 | ||
34 | |||
35 | #define OV534_OP_WRITE_3 0x37 | ||
36 | #define OV534_OP_WRITE_2 0x33 | ||
37 | #define OV534_OP_READ_2 0xf9 | ||
38 | |||
39 | #define CTRL_TIMEOUT 500 | ||
40 | |||
41 | MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | ||
42 | MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | /* global parameters */ | ||
46 | static int frame_rate; | ||
47 | |||
48 | /* specific webcam descriptor */ | ||
49 | struct sd { | ||
50 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
51 | __u8 frame_rate; | ||
52 | }; | ||
53 | |||
54 | /* V4L2 controls supported by the driver */ | ||
55 | static struct ctrl sd_ctrls[] = { | ||
56 | }; | ||
57 | |||
58 | static struct v4l2_pix_format vga_mode[] = { | ||
59 | {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | ||
60 | .bytesperline = 640 * 2, | ||
61 | .sizeimage = 640 * 480 * 2, | ||
62 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
63 | .priv = 0}, | ||
64 | }; | ||
65 | |||
66 | static void ov534_reg_write(struct usb_device *udev, u16 reg, u16 val) | ||
67 | { | ||
68 | u16 data = val; | ||
69 | int ret; | ||
70 | |||
71 | PDEBUG(D_USBO, "reg=0x%04x, val=0%04x", reg, val); | ||
72 | ret = usb_control_msg(udev, | ||
73 | usb_sndctrlpipe(udev, 0), | ||
74 | 0x1, | ||
75 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
76 | 0x0, reg, &data, 1, CTRL_TIMEOUT); | ||
77 | if (ret < 0) | ||
78 | PDEBUG(D_ERR, "write failed"); | ||
79 | } | ||
80 | |||
81 | static u16 ov534_reg_read(struct usb_device *udev, u16 reg) | ||
82 | { | ||
83 | u16 data; | ||
84 | int ret; | ||
85 | |||
86 | ret = usb_control_msg(udev, | ||
87 | usb_rcvctrlpipe(udev, 0), | ||
88 | 0x1, | ||
89 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
90 | 0x0, reg, &data, 1, CTRL_TIMEOUT); | ||
91 | PDEBUG(D_USBI, "reg=0x%04x, data=0x%04x", reg, data); | ||
92 | if (ret < 0) | ||
93 | PDEBUG(D_ERR, "read failed"); | ||
94 | return data; | ||
95 | } | ||
96 | |||
97 | static void ov534_reg_verify_write(struct usb_device *udev, u16 reg, u16 val) | ||
98 | { | ||
99 | u16 data; | ||
100 | |||
101 | ov534_reg_write(udev, reg, val); | ||
102 | data = ov534_reg_read(udev, reg); | ||
103 | if (data != val) { | ||
104 | PDEBUG(D_ERR | D_USBO, | ||
105 | "unexpected result from read: 0x%04x != 0x%04x", val, | ||
106 | data); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. | ||
111 | * (direction and output)? */ | ||
112 | static void ov534_set_led(struct usb_device *udev, int status) | ||
113 | { | ||
114 | u16 data; | ||
115 | |||
116 | PDEBUG(D_CONF, "led status: %d", status); | ||
117 | |||
118 | data = ov534_reg_read(udev, 0x21); | ||
119 | data |= 0x80; | ||
120 | ov534_reg_write(udev, 0x21, data); | ||
121 | |||
122 | data = ov534_reg_read(udev, 0x23); | ||
123 | if (status) | ||
124 | data |= 0x80; | ||
125 | else | ||
126 | data &= ~(0x80); | ||
127 | |||
128 | ov534_reg_write(udev, 0x23, data); | ||
129 | } | ||
130 | |||
131 | static int sccb_check_status(struct usb_device *udev) | ||
132 | { | ||
133 | u16 data; | ||
134 | int i; | ||
135 | |||
136 | for (i = 0; i < 5; i++) { | ||
137 | data = ov534_reg_read(udev, OV534_REG_STATUS); | ||
138 | |||
139 | switch (data & 0xFF) { | ||
140 | case 0x00: | ||
141 | return 1; | ||
142 | case 0x04: | ||
143 | return 0; | ||
144 | case 0x03: | ||
145 | break; | ||
146 | default: | ||
147 | PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5\n", | ||
148 | data, i + 1); | ||
149 | } | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static void sccb_reg_write(struct usb_device *udev, u16 reg, u16 val) | ||
155 | { | ||
156 | PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%04x", reg, val); | ||
157 | ov534_reg_write(udev, OV534_REG_SUBADDR, reg); | ||
158 | ov534_reg_write(udev, OV534_REG_WRITE, val); | ||
159 | ov534_reg_write(udev, OV534_REG_OPERATION, OV534_OP_WRITE_3); | ||
160 | |||
161 | if (!sccb_check_status(udev)) | ||
162 | PDEBUG(D_ERR, "sccb_reg_write failed"); | ||
163 | } | ||
164 | |||
165 | /* setup method */ | ||
166 | static void ov534_setup(struct usb_device *udev) | ||
167 | { | ||
168 | ov534_reg_verify_write(udev, 0xe7, 0x3a); | ||
169 | |||
170 | ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); | ||
171 | ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); | ||
172 | ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); | ||
173 | ov534_reg_write(udev, OV534_REG_ADDRESS, 0x42); | ||
174 | |||
175 | ov534_reg_verify_write(udev, 0xc2, 0x0c); | ||
176 | ov534_reg_verify_write(udev, 0x88, 0xf8); | ||
177 | ov534_reg_verify_write(udev, 0xc3, 0x69); | ||
178 | ov534_reg_verify_write(udev, 0x89, 0xff); | ||
179 | ov534_reg_verify_write(udev, 0x76, 0x03); | ||
180 | ov534_reg_verify_write(udev, 0x92, 0x01); | ||
181 | ov534_reg_verify_write(udev, 0x93, 0x18); | ||
182 | ov534_reg_verify_write(udev, 0x94, 0x10); | ||
183 | ov534_reg_verify_write(udev, 0x95, 0x10); | ||
184 | ov534_reg_verify_write(udev, 0xe2, 0x00); | ||
185 | ov534_reg_verify_write(udev, 0xe7, 0x3e); | ||
186 | |||
187 | ov534_reg_write(udev, 0x1c, 0x0a); | ||
188 | ov534_reg_write(udev, 0x1d, 0x22); | ||
189 | ov534_reg_write(udev, 0x1d, 0x06); | ||
190 | |||
191 | ov534_reg_verify_write(udev, 0x96, 0x00); | ||
192 | |||
193 | ov534_reg_write(udev, 0x97, 0x20); | ||
194 | ov534_reg_write(udev, 0x97, 0x20); | ||
195 | ov534_reg_write(udev, 0x97, 0x20); | ||
196 | ov534_reg_write(udev, 0x97, 0x0a); | ||
197 | ov534_reg_write(udev, 0x97, 0x3f); | ||
198 | ov534_reg_write(udev, 0x97, 0x4a); | ||
199 | ov534_reg_write(udev, 0x97, 0x20); | ||
200 | ov534_reg_write(udev, 0x97, 0x15); | ||
201 | ov534_reg_write(udev, 0x97, 0x0b); | ||
202 | |||
203 | ov534_reg_verify_write(udev, 0x8e, 0x40); | ||
204 | ov534_reg_verify_write(udev, 0x1f, 0x81); | ||
205 | ov534_reg_verify_write(udev, 0x34, 0x05); | ||
206 | ov534_reg_verify_write(udev, 0xe3, 0x04); | ||
207 | ov534_reg_verify_write(udev, 0x88, 0x00); | ||
208 | ov534_reg_verify_write(udev, 0x89, 0x00); | ||
209 | ov534_reg_verify_write(udev, 0x76, 0x00); | ||
210 | ov534_reg_verify_write(udev, 0xe7, 0x2e); | ||
211 | ov534_reg_verify_write(udev, 0x31, 0xf9); | ||
212 | ov534_reg_verify_write(udev, 0x25, 0x42); | ||
213 | ov534_reg_verify_write(udev, 0x21, 0xf0); | ||
214 | |||
215 | ov534_reg_write(udev, 0x1c, 0x00); | ||
216 | ov534_reg_write(udev, 0x1d, 0x40); | ||
217 | ov534_reg_write(udev, 0x1d, 0x02); | ||
218 | ov534_reg_write(udev, 0x1d, 0x00); | ||
219 | ov534_reg_write(udev, 0x1d, 0x02); | ||
220 | ov534_reg_write(udev, 0x1d, 0x57); | ||
221 | ov534_reg_write(udev, 0x1d, 0xff); | ||
222 | |||
223 | ov534_reg_verify_write(udev, 0x8d, 0x1c); | ||
224 | ov534_reg_verify_write(udev, 0x8e, 0x80); | ||
225 | ov534_reg_verify_write(udev, 0xe5, 0x04); | ||
226 | |||
227 | ov534_set_led(udev, 1); | ||
228 | |||
229 | sccb_reg_write(udev, 0x12, 0x80); | ||
230 | sccb_reg_write(udev, 0x11, 0x01); | ||
231 | sccb_reg_write(udev, 0x11, 0x01); | ||
232 | sccb_reg_write(udev, 0x11, 0x01); | ||
233 | sccb_reg_write(udev, 0x11, 0x01); | ||
234 | sccb_reg_write(udev, 0x11, 0x01); | ||
235 | sccb_reg_write(udev, 0x11, 0x01); | ||
236 | sccb_reg_write(udev, 0x11, 0x01); | ||
237 | sccb_reg_write(udev, 0x11, 0x01); | ||
238 | sccb_reg_write(udev, 0x11, 0x01); | ||
239 | sccb_reg_write(udev, 0x11, 0x01); | ||
240 | sccb_reg_write(udev, 0x11, 0x01); | ||
241 | |||
242 | ov534_set_led(udev, 0); | ||
243 | |||
244 | sccb_reg_write(udev, 0x3d, 0x03); | ||
245 | sccb_reg_write(udev, 0x17, 0x26); | ||
246 | sccb_reg_write(udev, 0x18, 0xa0); | ||
247 | sccb_reg_write(udev, 0x19, 0x07); | ||
248 | sccb_reg_write(udev, 0x1a, 0xf0); | ||
249 | sccb_reg_write(udev, 0x32, 0x00); | ||
250 | sccb_reg_write(udev, 0x29, 0xa0); | ||
251 | sccb_reg_write(udev, 0x2c, 0xf0); | ||
252 | sccb_reg_write(udev, 0x65, 0x20); | ||
253 | sccb_reg_write(udev, 0x11, 0x01); | ||
254 | sccb_reg_write(udev, 0x42, 0x7f); | ||
255 | sccb_reg_write(udev, 0x63, 0xe0); | ||
256 | sccb_reg_write(udev, 0x64, 0xff); | ||
257 | sccb_reg_write(udev, 0x66, 0x00); | ||
258 | sccb_reg_write(udev, 0x13, 0xf0); | ||
259 | sccb_reg_write(udev, 0x0d, 0x41); | ||
260 | sccb_reg_write(udev, 0x0f, 0xc5); | ||
261 | sccb_reg_write(udev, 0x14, 0x11); | ||
262 | |||
263 | ov534_set_led(udev, 1); | ||
264 | |||
265 | sccb_reg_write(udev, 0x22, 0x7f); | ||
266 | sccb_reg_write(udev, 0x23, 0x03); | ||
267 | sccb_reg_write(udev, 0x24, 0x40); | ||
268 | sccb_reg_write(udev, 0x25, 0x30); | ||
269 | sccb_reg_write(udev, 0x26, 0xa1); | ||
270 | sccb_reg_write(udev, 0x2a, 0x00); | ||
271 | sccb_reg_write(udev, 0x2b, 0x00); | ||
272 | sccb_reg_write(udev, 0x6b, 0xaa); | ||
273 | sccb_reg_write(udev, 0x13, 0xff); | ||
274 | |||
275 | ov534_set_led(udev, 0); | ||
276 | |||
277 | sccb_reg_write(udev, 0x90, 0x05); | ||
278 | sccb_reg_write(udev, 0x91, 0x01); | ||
279 | sccb_reg_write(udev, 0x92, 0x03); | ||
280 | sccb_reg_write(udev, 0x93, 0x00); | ||
281 | sccb_reg_write(udev, 0x94, 0x60); | ||
282 | sccb_reg_write(udev, 0x95, 0x3c); | ||
283 | sccb_reg_write(udev, 0x96, 0x24); | ||
284 | sccb_reg_write(udev, 0x97, 0x1e); | ||
285 | sccb_reg_write(udev, 0x98, 0x62); | ||
286 | sccb_reg_write(udev, 0x99, 0x80); | ||
287 | sccb_reg_write(udev, 0x9a, 0x1e); | ||
288 | sccb_reg_write(udev, 0x9b, 0x08); | ||
289 | sccb_reg_write(udev, 0x9c, 0x20); | ||
290 | sccb_reg_write(udev, 0x9e, 0x81); | ||
291 | |||
292 | ov534_set_led(udev, 1); | ||
293 | |||
294 | sccb_reg_write(udev, 0xa6, 0x04); | ||
295 | sccb_reg_write(udev, 0x7e, 0x0c); | ||
296 | sccb_reg_write(udev, 0x7f, 0x16); | ||
297 | sccb_reg_write(udev, 0x80, 0x2a); | ||
298 | sccb_reg_write(udev, 0x81, 0x4e); | ||
299 | sccb_reg_write(udev, 0x82, 0x61); | ||
300 | sccb_reg_write(udev, 0x83, 0x6f); | ||
301 | sccb_reg_write(udev, 0x84, 0x7b); | ||
302 | sccb_reg_write(udev, 0x85, 0x86); | ||
303 | sccb_reg_write(udev, 0x86, 0x8e); | ||
304 | sccb_reg_write(udev, 0x87, 0x97); | ||
305 | sccb_reg_write(udev, 0x88, 0xa4); | ||
306 | sccb_reg_write(udev, 0x89, 0xaf); | ||
307 | sccb_reg_write(udev, 0x8a, 0xc5); | ||
308 | sccb_reg_write(udev, 0x8b, 0xd7); | ||
309 | sccb_reg_write(udev, 0x8c, 0xe8); | ||
310 | sccb_reg_write(udev, 0x8d, 0x20); | ||
311 | |||
312 | sccb_reg_write(udev, 0x0c, 0x90); | ||
313 | |||
314 | ov534_reg_verify_write(udev, 0xc0, 0x50); | ||
315 | ov534_reg_verify_write(udev, 0xc1, 0x3c); | ||
316 | ov534_reg_verify_write(udev, 0xc2, 0x0c); | ||
317 | |||
318 | ov534_set_led(udev, 1); | ||
319 | |||
320 | sccb_reg_write(udev, 0x2b, 0x00); | ||
321 | sccb_reg_write(udev, 0x22, 0x7f); | ||
322 | sccb_reg_write(udev, 0x23, 0x03); | ||
323 | sccb_reg_write(udev, 0x11, 0x01); | ||
324 | sccb_reg_write(udev, 0x0c, 0xd0); | ||
325 | sccb_reg_write(udev, 0x64, 0xff); | ||
326 | sccb_reg_write(udev, 0x0d, 0x41); | ||
327 | |||
328 | sccb_reg_write(udev, 0x14, 0x41); | ||
329 | sccb_reg_write(udev, 0x0e, 0xcd); | ||
330 | sccb_reg_write(udev, 0xac, 0xbf); | ||
331 | sccb_reg_write(udev, 0x8e, 0x00); | ||
332 | sccb_reg_write(udev, 0x0c, 0xd0); | ||
333 | |||
334 | ov534_reg_write(udev, 0xe0, 0x09); | ||
335 | ov534_set_led(udev, 0); | ||
336 | } | ||
337 | |||
338 | /* this function is called at probe time */ | ||
339 | static int sd_config(struct gspca_dev *gspca_dev, | ||
340 | const struct usb_device_id *id) | ||
341 | { | ||
342 | struct cam *cam; | ||
343 | |||
344 | cam = &gspca_dev->cam; | ||
345 | |||
346 | cam->epaddr = 0x01; | ||
347 | cam->cam_mode = vga_mode; | ||
348 | cam->nmodes = ARRAY_SIZE(vga_mode); | ||
349 | |||
350 | cam->bulk_size = vga_mode[0].sizeimage; | ||
351 | cam->bulk_nurbs = 2; | ||
352 | |||
353 | PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | /* this function is called at probe and resume time */ | ||
359 | static int sd_init(struct gspca_dev *gspca_dev) | ||
360 | { | ||
361 | struct sd *sd = (struct sd *)gspca_dev; | ||
362 | ov534_setup(gspca_dev->dev); | ||
363 | |||
364 | if (frame_rate > 0) | ||
365 | sd->frame_rate = frame_rate; | ||
366 | |||
367 | PDEBUG(D_PROBE, "frame_rate = %d", sd->frame_rate); | ||
368 | |||
369 | switch (sd->frame_rate) { | ||
370 | case 50: | ||
371 | sccb_reg_write(gspca_dev->dev, 0x11, 0x01); | ||
372 | sccb_check_status(gspca_dev->dev); | ||
373 | sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); | ||
374 | sccb_check_status(gspca_dev->dev); | ||
375 | ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); | ||
376 | break; | ||
377 | case 40: | ||
378 | sccb_reg_write(gspca_dev->dev, 0x11, 0x02); | ||
379 | sccb_check_status(gspca_dev->dev); | ||
380 | sccb_reg_write(gspca_dev->dev, 0x0d, 0xc1); | ||
381 | sccb_check_status(gspca_dev->dev); | ||
382 | ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); | ||
383 | break; | ||
384 | case 30: | ||
385 | default: | ||
386 | sccb_reg_write(gspca_dev->dev, 0x11, 0x04); | ||
387 | sccb_check_status(gspca_dev->dev); | ||
388 | sccb_reg_write(gspca_dev->dev, 0x0d, 0x81); | ||
389 | sccb_check_status(gspca_dev->dev); | ||
390 | ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); | ||
391 | break; | ||
392 | case 15: | ||
393 | sccb_reg_write(gspca_dev->dev, 0x11, 0x03); | ||
394 | sccb_check_status(gspca_dev->dev); | ||
395 | sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); | ||
396 | sccb_check_status(gspca_dev->dev); | ||
397 | ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); | ||
398 | break; | ||
399 | }; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int sd_start(struct gspca_dev *gspca_dev) | ||
405 | { | ||
406 | PDEBUG(D_PROBE, "width = %d, height = %d", | ||
407 | gspca_dev->width, gspca_dev->height); | ||
408 | |||
409 | gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height * 2; | ||
410 | |||
411 | /* start streaming data */ | ||
412 | ov534_set_led(gspca_dev->dev, 1); | ||
413 | ov534_reg_write(gspca_dev->dev, 0xe0, 0x00); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
419 | { | ||
420 | /* stop streaming data */ | ||
421 | ov534_reg_write(gspca_dev->dev, 0xe0, 0x09); | ||
422 | ov534_set_led(gspca_dev->dev, 0); | ||
423 | } | ||
424 | |||
425 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, | ||
426 | __u8 *data, int len) | ||
427 | { | ||
428 | /* | ||
429 | * The current camera setup doesn't stream the last pixel, so we set it | ||
430 | * to a dummy value | ||
431 | */ | ||
432 | __u8 last_pixel[4] = { 0, 0, 0, 0 }; | ||
433 | int framesize = gspca_dev->cam.bulk_size; | ||
434 | |||
435 | if (len == framesize - 4) { | ||
436 | frame = | ||
437 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); | ||
438 | frame = | ||
439 | gspca_frame_add(gspca_dev, LAST_PACKET, frame, last_pixel, | ||
440 | 4); | ||
441 | } else | ||
442 | PDEBUG(D_PACK, "packet len = %d, framesize = %d", len, | ||
443 | framesize); | ||
444 | } | ||
445 | |||
446 | /* sub-driver description */ | ||
447 | static const struct sd_desc sd_desc = { | ||
448 | .name = MODULE_NAME, | ||
449 | .ctrls = sd_ctrls, | ||
450 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
451 | .config = sd_config, | ||
452 | .init = sd_init, | ||
453 | .start = sd_start, | ||
454 | .stopN = sd_stopN, | ||
455 | .pkt_scan = sd_pkt_scan, | ||
456 | }; | ||
457 | |||
458 | /* -- module initialisation -- */ | ||
459 | static const __devinitdata struct usb_device_id device_table[] = { | ||
460 | {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */ | ||
461 | {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */ | ||
462 | {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */ | ||
463 | {} | ||
464 | }; | ||
465 | |||
466 | MODULE_DEVICE_TABLE(usb, device_table); | ||
467 | |||
468 | /* -- device connect -- */ | ||
469 | static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
470 | { | ||
471 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
472 | THIS_MODULE); | ||
473 | } | ||
474 | |||
475 | static struct usb_driver sd_driver = { | ||
476 | .name = MODULE_NAME, | ||
477 | .id_table = device_table, | ||
478 | .probe = sd_probe, | ||
479 | .disconnect = gspca_disconnect, | ||
480 | #ifdef CONFIG_PM | ||
481 | .suspend = gspca_suspend, | ||
482 | .resume = gspca_resume, | ||
483 | #endif | ||
484 | }; | ||
485 | |||
486 | /* -- module insert / remove -- */ | ||
487 | static int __init sd_mod_init(void) | ||
488 | { | ||
489 | if (usb_register(&sd_driver) < 0) | ||
490 | return -1; | ||
491 | PDEBUG(D_PROBE, "registered"); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static void __exit sd_mod_exit(void) | ||
496 | { | ||
497 | usb_deregister(&sd_driver); | ||
498 | PDEBUG(D_PROBE, "deregistered"); | ||
499 | } | ||
500 | |||
501 | module_init(sd_mod_init); | ||
502 | module_exit(sd_mod_exit); | ||
503 | |||
504 | module_param(frame_rate, int, 0644); | ||
505 | MODULE_PARM_DESC(frame_rate, "Frame rate (15, 30, 40, 50)"); | ||