diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2008-04-12 08:58:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:14:28 -0400 |
commit | 63eb9546dcb5e9dc39ab88a603dede8fdd18e717 (patch) | |
tree | c61a8365a0428a58f643df35b29220f1c5e63f46 /drivers/media/video/gspca/stk014.c | |
parent | 8b53b39d6228cda41b7ddfc9d094a072afca6655 (diff) |
V4L/DVB (8152): Initial release of gspca with only one driver.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/gspca/stk014.c')
-rw-r--r-- | drivers/media/video/gspca/stk014.c | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c new file mode 100644 index 000000000000..8fd4ff01362e --- /dev/null +++ b/drivers/media/video/gspca/stk014.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * Syntek DV4000 (STK014) subdriver | ||
3 | * | ||
4 | * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define MODULE_NAME "stk014" | ||
23 | |||
24 | #include "gspca.h" | ||
25 | #include "jpeg.h" | ||
26 | |||
27 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 22) | ||
28 | static const char version[] = "0.0.22"; | ||
29 | |||
30 | MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); | ||
31 | MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | /* specific webcam descriptor */ | ||
35 | struct sd { | ||
36 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
37 | |||
38 | unsigned char brightness; | ||
39 | unsigned char contrast; | ||
40 | unsigned char colors; | ||
41 | }; | ||
42 | |||
43 | /* global parameters */ | ||
44 | static int lightfreq = 50; | ||
45 | static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */ | ||
46 | |||
47 | /* V4L2 controls supported by the driver */ | ||
48 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | ||
49 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | ||
50 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | ||
51 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | ||
52 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); | ||
53 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); | ||
54 | |||
55 | static struct ctrl sd_ctrls[] = { | ||
56 | #define SD_BRIGHTNESS 0 | ||
57 | { | ||
58 | { | ||
59 | .id = V4L2_CID_BRIGHTNESS, | ||
60 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
61 | .name = "Brightness", | ||
62 | .minimum = 0, | ||
63 | .maximum = 255, | ||
64 | .step = 1, | ||
65 | .default_value = 127, | ||
66 | }, | ||
67 | .set = sd_setbrightness, | ||
68 | .get = sd_getbrightness, | ||
69 | }, | ||
70 | #define SD_CONTRAST 1 | ||
71 | { | ||
72 | { | ||
73 | .id = V4L2_CID_CONTRAST, | ||
74 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
75 | .name = "Contrast", | ||
76 | .minimum = 0, | ||
77 | .maximum = 255, | ||
78 | .step = 1, | ||
79 | .default_value = 127, | ||
80 | }, | ||
81 | .set = sd_setcontrast, | ||
82 | .get = sd_getcontrast, | ||
83 | }, | ||
84 | #define SD_COLOR 2 | ||
85 | { | ||
86 | { | ||
87 | .id = V4L2_CID_SATURATION, | ||
88 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
89 | .name = "Saturation", | ||
90 | .minimum = 0, | ||
91 | .maximum = 255, | ||
92 | .step = 1, | ||
93 | .default_value = 127, | ||
94 | }, | ||
95 | .set = sd_setcolors, | ||
96 | .get = sd_getcolors, | ||
97 | }, | ||
98 | }; | ||
99 | |||
100 | static struct cam_mode vga_mode[] = { | ||
101 | {V4L2_PIX_FMT_JPEG, 320, 240}, | ||
102 | {V4L2_PIX_FMT_JPEG, 640, 480}, | ||
103 | }; | ||
104 | |||
105 | /* -- read a register -- */ | ||
106 | static int reg_read(struct gspca_dev *gspca_dev, | ||
107 | __u16 index, __u8 *buf) | ||
108 | { | ||
109 | int ret; | ||
110 | struct usb_device *dev = gspca_dev->dev; | ||
111 | |||
112 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
113 | 0x00, | ||
114 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
115 | 0x00, | ||
116 | index, | ||
117 | buf, 1, | ||
118 | 500); | ||
119 | if (ret < 0) | ||
120 | PDEBUG(D_ERR, "reg_read err %d", ret); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | /* -- write a register -- */ | ||
125 | static int reg_write(struct gspca_dev *gspca_dev, | ||
126 | __u16 index, __u16 value) | ||
127 | { | ||
128 | struct usb_device *dev = gspca_dev->dev; | ||
129 | int ret; | ||
130 | |||
131 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
132 | 0x01, | ||
133 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
134 | value, | ||
135 | index, | ||
136 | NULL, | ||
137 | 0, | ||
138 | 500); | ||
139 | if (ret < 0) | ||
140 | PDEBUG(D_ERR, "reg_write err %d", ret); | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /* -- get a value -- */ | ||
145 | static int rcv_val(struct gspca_dev *gspca_dev, | ||
146 | int ads, | ||
147 | int len) | ||
148 | { | ||
149 | struct usb_device *dev = gspca_dev->dev; | ||
150 | int alen, ret; | ||
151 | unsigned char bulk_buf[4]; | ||
152 | |||
153 | reg_write(gspca_dev, 0x634, (ads >> 16) & 0xff); | ||
154 | reg_write(gspca_dev, 0x635, (ads >> 8) & 0xff); | ||
155 | reg_write(gspca_dev, 0x636, ads & 0xff); | ||
156 | reg_write(gspca_dev, 0x637, 0); | ||
157 | reg_write(gspca_dev, 0x638, len & 0xff); | ||
158 | reg_write(gspca_dev, 0x639, len >> 8); | ||
159 | reg_write(gspca_dev, 0x63a, 0); | ||
160 | reg_write(gspca_dev, 0x63b, 0); | ||
161 | reg_write(gspca_dev, 0x630, 5); | ||
162 | if (len > sizeof bulk_buf) | ||
163 | return -1; | ||
164 | ret = usb_bulk_msg(dev, | ||
165 | usb_rcvbulkpipe(dev, 5), | ||
166 | bulk_buf, | ||
167 | len, | ||
168 | &alen, | ||
169 | 500); /* timeout in milliseconds */ | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | /* -- send a value -- */ | ||
174 | static int snd_val(struct gspca_dev *gspca_dev, | ||
175 | int ads, | ||
176 | unsigned int val) | ||
177 | { | ||
178 | struct usb_device *dev = gspca_dev->dev; | ||
179 | int alen, ret; | ||
180 | __u8 value, seq; | ||
181 | unsigned char bulk_buf[4]; | ||
182 | |||
183 | if (ads == 0x003f08) { | ||
184 | ret = reg_read(gspca_dev, 0x0704, &value); | ||
185 | if (ret < 0) | ||
186 | goto ko; | ||
187 | ret = reg_read(gspca_dev, 0x0705, &seq); | ||
188 | if (ret < 0) | ||
189 | goto ko; | ||
190 | ret = reg_read(gspca_dev, 0x0650, &value); | ||
191 | if (ret < 0) | ||
192 | goto ko; | ||
193 | reg_write(gspca_dev, 0x654, seq); | ||
194 | } else | ||
195 | reg_write(gspca_dev, 0x654, (ads >> 16) & 0xff); | ||
196 | reg_write(gspca_dev, 0x655, (ads >> 8) & 0xff); | ||
197 | reg_write(gspca_dev, 0x656, ads & 0xff); | ||
198 | reg_write(gspca_dev, 0x657, 0); | ||
199 | reg_write(gspca_dev, 0x658, 0x04); /* size */ | ||
200 | reg_write(gspca_dev, 0x659, 0); | ||
201 | reg_write(gspca_dev, 0x65a, 0); | ||
202 | reg_write(gspca_dev, 0x65b, 0); | ||
203 | reg_write(gspca_dev, 0x650, 5); | ||
204 | bulk_buf[0] = (val >> 24) & 0xff; | ||
205 | bulk_buf[1] = (val >> 16) & 0xff; | ||
206 | bulk_buf[2] = (val >> 8) & 0xff; | ||
207 | bulk_buf[3] = val & 0xff; | ||
208 | ret = usb_bulk_msg(dev, | ||
209 | usb_sndbulkpipe(dev, 6), | ||
210 | bulk_buf, | ||
211 | 4, | ||
212 | &alen, | ||
213 | 500); /* timeout in milliseconds */ | ||
214 | if (ret < 0) | ||
215 | goto ko; | ||
216 | if (ads == 0x003f08) { | ||
217 | seq += 4; | ||
218 | seq &= 0x3f; | ||
219 | reg_write(gspca_dev, 0x705, seq); | ||
220 | } | ||
221 | return ret; | ||
222 | ko: | ||
223 | PDEBUG(D_ERR, "snd_val err %d", ret); | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | /* set a camera parameter */ | ||
228 | static int set_par(struct gspca_dev *gspca_dev, | ||
229 | int parval) | ||
230 | { | ||
231 | return snd_val(gspca_dev, 0x003f08, parval); | ||
232 | } | ||
233 | |||
234 | static void setbrightness(struct gspca_dev *gspca_dev) | ||
235 | { | ||
236 | struct sd *sd = (struct sd *) gspca_dev; | ||
237 | int parval; | ||
238 | |||
239 | PDEBUG(D_CONF, "brightness: %d", sd->brightness); | ||
240 | parval = 0x06000000 /* whiteness */ | ||
241 | + (sd->brightness << 16); | ||
242 | set_par(gspca_dev, parval); | ||
243 | } | ||
244 | |||
245 | static void setcontrast(struct gspca_dev *gspca_dev) | ||
246 | { | ||
247 | struct sd *sd = (struct sd *) gspca_dev; | ||
248 | int parval; | ||
249 | |||
250 | PDEBUG(D_CONF, "contrast: %d", sd->contrast); | ||
251 | parval = 0x07000000 /* contrast */ | ||
252 | + (sd->contrast << 16); | ||
253 | set_par(gspca_dev, parval); | ||
254 | } | ||
255 | |||
256 | static void setcolors(struct gspca_dev *gspca_dev) | ||
257 | { | ||
258 | struct sd *sd = (struct sd *) gspca_dev; | ||
259 | int parval; | ||
260 | |||
261 | PDEBUG(D_CONF, "saturation: %d", | ||
262 | sd->colors); | ||
263 | parval = 0x08000000 /* saturation */ | ||
264 | + (sd->colors << 16); | ||
265 | set_par(gspca_dev, parval); | ||
266 | } | ||
267 | |||
268 | /* this function is called at probe time */ | ||
269 | static int sd_config(struct gspca_dev *gspca_dev, | ||
270 | const struct usb_device_id *id) | ||
271 | { | ||
272 | struct sd *sd = (struct sd *) gspca_dev; | ||
273 | struct cam *cam = &gspca_dev->cam; | ||
274 | |||
275 | cam->dev_name = (char *) id->driver_info; | ||
276 | cam->epaddr = 0x02; | ||
277 | gspca_dev->cam.cam_mode = vga_mode; | ||
278 | gspca_dev->cam.nmodes = sizeof vga_mode / sizeof vga_mode[0]; | ||
279 | sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; | ||
280 | sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; | ||
281 | sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* this function is called at open time */ | ||
286 | static int sd_open(struct gspca_dev *gspca_dev) | ||
287 | { | ||
288 | __u8 value; | ||
289 | int ret; | ||
290 | |||
291 | /* check if the device responds */ | ||
292 | usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); | ||
293 | ret = reg_read(gspca_dev, 0x0740, &value); | ||
294 | if (ret < 0) | ||
295 | return ret; | ||
296 | if (value != 0xff) { | ||
297 | PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", value); | ||
298 | return -1; | ||
299 | } | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* -- start the camera -- */ | ||
304 | static void sd_start(struct gspca_dev *gspca_dev) | ||
305 | { | ||
306 | __u8 dum; | ||
307 | int ret, value; | ||
308 | |||
309 | /* work on alternate 1 */ | ||
310 | usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); | ||
311 | |||
312 | set_par(gspca_dev, 0x10000000); | ||
313 | set_par(gspca_dev, 0x00000000); | ||
314 | set_par(gspca_dev, 0x8002e001); | ||
315 | set_par(gspca_dev, 0x14000000); | ||
316 | if (gspca_dev->width > 320) | ||
317 | value = 0x8002e001; /* 640x480 */ | ||
318 | else | ||
319 | value = 0x4001f000; /* 320x240 */ | ||
320 | set_par(gspca_dev, value); | ||
321 | ret = usb_set_interface(gspca_dev->dev, | ||
322 | gspca_dev->iface, | ||
323 | gspca_dev->alt); | ||
324 | if (ret < 0) | ||
325 | goto out; | ||
326 | ret = reg_read(gspca_dev, 0x0630, &dum); | ||
327 | if (ret < 0) | ||
328 | goto out; | ||
329 | rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */ | ||
330 | ret = reg_read(gspca_dev, 0x0650, &dum); | ||
331 | if (ret < 0) | ||
332 | goto out; | ||
333 | snd_val(gspca_dev, 0x000020, 0xffffffff); | ||
334 | reg_write(gspca_dev, 0x0620, 0); | ||
335 | reg_write(gspca_dev, 0x0630, 0); | ||
336 | reg_write(gspca_dev, 0x0640, 0); | ||
337 | reg_write(gspca_dev, 0x0650, 0); | ||
338 | reg_write(gspca_dev, 0x0660, 0); | ||
339 | setbrightness(gspca_dev); /* whiteness */ | ||
340 | setcontrast(gspca_dev); /* contrast */ | ||
341 | setcolors(gspca_dev); /* saturation */ | ||
342 | set_par(gspca_dev, 0x09800000); /* Red ? */ | ||
343 | set_par(gspca_dev, 0x0a800000); /* Green ? */ | ||
344 | set_par(gspca_dev, 0x0b800000); /* Blue ? */ | ||
345 | set_par(gspca_dev, 0x0d030000); /* Gamma ? */ | ||
346 | set_par(gspca_dev, lightfreq == 60 | ||
347 | ? 0x33780000 /* 60 Hz */ | ||
348 | : 0x33640000); /* 50 Hz */ | ||
349 | |||
350 | /* start the video flow */ | ||
351 | set_par(gspca_dev, 0x01000000); | ||
352 | set_par(gspca_dev, 0x01000000); | ||
353 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); | ||
354 | return; | ||
355 | out: | ||
356 | PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); | ||
357 | } | ||
358 | |||
359 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
360 | { | ||
361 | struct usb_device *dev = gspca_dev->dev; | ||
362 | __u8 value; | ||
363 | |||
364 | set_par(gspca_dev, 0x02000000); | ||
365 | set_par(gspca_dev, 0x02000000); | ||
366 | usb_set_interface(dev, gspca_dev->iface, 1); | ||
367 | reg_read(gspca_dev, 0x0630, &value); | ||
368 | rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */ | ||
369 | reg_read(gspca_dev, 0x0650, &value); | ||
370 | snd_val(gspca_dev, 0x000020, 0xffffffff); | ||
371 | reg_write(gspca_dev, 0x0620, 0); | ||
372 | reg_write(gspca_dev, 0x0630, 0); | ||
373 | reg_write(gspca_dev, 0x0640, 0); | ||
374 | reg_write(gspca_dev, 0x0650, 0); | ||
375 | reg_write(gspca_dev, 0x0660, 0); | ||
376 | PDEBUG(D_STREAM, "camera stopped"); | ||
377 | } | ||
378 | |||
379 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
380 | { | ||
381 | } | ||
382 | |||
383 | static void sd_close(struct gspca_dev *gspca_dev) | ||
384 | { | ||
385 | } | ||
386 | |||
387 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
388 | struct gspca_frame *frame, /* target */ | ||
389 | unsigned char *data, /* isoc packet */ | ||
390 | int len) /* iso packet length */ | ||
391 | { | ||
392 | int l; | ||
393 | |||
394 | /* a frame starts with: | ||
395 | * - 0xff 0xfe | ||
396 | * - 0x08 0x00 // length (little endian ?!) | ||
397 | * - 4 bytes = size of whole frame (big endian - including header) | ||
398 | * - 0x00 0x0c | ||
399 | * - 0xff 0xd8 | ||
400 | * - .. JPEG image with escape sequences (ff 00) | ||
401 | */ | ||
402 | if (data[0] == 0xff && data[1] == 0xfe) { | ||
403 | if (gspca_dev->last_packet_type == INTER_PACKET) { | ||
404 | PDEBUG(D_ERR|D_FRAM, "sof actual l: %d init l: %d", | ||
405 | frame->data_end - frame->data, | ||
406 | frame->v4l2_buf.bytesused); | ||
407 | } | ||
408 | |||
409 | /* put the JPEG headaer */ | ||
410 | jpeg_put_header(gspca_dev, frame, sd_quant, 0x22); | ||
411 | |||
412 | /* beginning of the frame */ | ||
413 | #define STKHDRSZ 12 | ||
414 | l = (data[4] << 24) /* frame size */ | ||
415 | + (data[5] << 16) | ||
416 | + (data[6] << 8) | ||
417 | + data[7] | ||
418 | - STKHDRSZ | ||
419 | + (frame->data_end - frame->data) | ||
420 | + 2; /* EOF (ff d9) */ | ||
421 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, | ||
422 | data + STKHDRSZ, len - STKHDRSZ); | ||
423 | #undef STKHDRSZ | ||
424 | frame->v4l2_buf.bytesused = l; | ||
425 | return; | ||
426 | } | ||
427 | if (gspca_dev->last_packet_type != INTER_PACKET) { | ||
428 | if (gspca_dev->last_packet_type == LAST_PACKET) { | ||
429 | PDEBUG(D_ERR|D_PACK, "mof actual l: %d init l: %d", | ||
430 | frame->data_end - frame->data, | ||
431 | frame->v4l2_buf.bytesused); | ||
432 | } | ||
433 | return; | ||
434 | } | ||
435 | |||
436 | /* intermediate packet */ | ||
437 | l = frame->data_end - frame->data; | ||
438 | if (len < frame->v4l2_buf.bytesused - 2 - l) { | ||
439 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, | ||
440 | data, len); | ||
441 | return; | ||
442 | } | ||
443 | |||
444 | /* last packet */ | ||
445 | if (len > frame->v4l2_buf.bytesused - 2 - l) | ||
446 | len = frame->v4l2_buf.bytesused - 2 - l; | ||
447 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); | ||
448 | gspca_frame_add(gspca_dev, LAST_PACKET, frame, "\xff\xd9", 2); | ||
449 | } | ||
450 | |||
451 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | ||
452 | { | ||
453 | struct sd *sd = (struct sd *) gspca_dev; | ||
454 | |||
455 | sd->brightness = val; | ||
456 | if (gspca_dev->streaming) | ||
457 | setbrightness(gspca_dev); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | ||
462 | { | ||
463 | struct sd *sd = (struct sd *) gspca_dev; | ||
464 | |||
465 | *val = sd->brightness; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | ||
470 | { | ||
471 | struct sd *sd = (struct sd *) gspca_dev; | ||
472 | |||
473 | sd->contrast = val; | ||
474 | if (gspca_dev->streaming) | ||
475 | setcontrast(gspca_dev); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | ||
480 | { | ||
481 | struct sd *sd = (struct sd *) gspca_dev; | ||
482 | |||
483 | *val = sd->contrast; | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) | ||
488 | { | ||
489 | struct sd *sd = (struct sd *) gspca_dev; | ||
490 | |||
491 | sd->colors = val; | ||
492 | if (gspca_dev->streaming) | ||
493 | setcolors(gspca_dev); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | ||
498 | { | ||
499 | struct sd *sd = (struct sd *) gspca_dev; | ||
500 | |||
501 | *val = sd->colors; | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /* sub-driver description */ | ||
506 | static struct sd_desc sd_desc = { | ||
507 | .name = MODULE_NAME, | ||
508 | .ctrls = sd_ctrls, | ||
509 | .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0], | ||
510 | .config = sd_config, | ||
511 | .open = sd_open, | ||
512 | .start = sd_start, | ||
513 | .stopN = sd_stopN, | ||
514 | .stop0 = sd_stop0, | ||
515 | .close = sd_close, | ||
516 | .pkt_scan = sd_pkt_scan, | ||
517 | }; | ||
518 | |||
519 | /* -- module initialisation -- */ | ||
520 | #define DVNM(name) .driver_info = (kernel_ulong_t) name | ||
521 | static __devinitdata struct usb_device_id device_table[] = { | ||
522 | {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")}, | ||
523 | {} | ||
524 | }; | ||
525 | MODULE_DEVICE_TABLE(usb, device_table); | ||
526 | |||
527 | /* -- device connect -- */ | ||
528 | static int sd_probe(struct usb_interface *intf, | ||
529 | const struct usb_device_id *id) | ||
530 | { | ||
531 | PDEBUG(D_PROBE, "camera probe"); | ||
532 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd)); | ||
533 | } | ||
534 | |||
535 | static struct usb_driver sd_driver = { | ||
536 | .name = MODULE_NAME, | ||
537 | .id_table = device_table, | ||
538 | .probe = sd_probe, | ||
539 | .disconnect = gspca_disconnect, | ||
540 | }; | ||
541 | |||
542 | /* -- module insert / remove -- */ | ||
543 | static int __init sd_mod_init(void) | ||
544 | { | ||
545 | if (usb_register(&sd_driver) < 0) | ||
546 | return -1; | ||
547 | info("v%s registered", version); | ||
548 | return 0; | ||
549 | } | ||
550 | static void __exit sd_mod_exit(void) | ||
551 | { | ||
552 | usb_deregister(&sd_driver); | ||
553 | info("deregistered"); | ||
554 | } | ||
555 | |||
556 | module_init(sd_mod_init); | ||
557 | module_exit(sd_mod_exit); | ||
558 | |||
559 | module_param(lightfreq, int, 0644); | ||
560 | MODULE_PARM_DESC(lightfreq, "Light frequency 50 or 60 Hz"); | ||
561 | module_param_named(quant, sd_quant, int, 0644); | ||
562 | MODULE_PARM_DESC(quant, "Quantization index (0..8)"); | ||