diff options
Diffstat (limited to 'drivers/media/parport/bw-qcam.c')
-rw-r--r-- | drivers/media/parport/bw-qcam.c | 1113 |
1 files changed, 1113 insertions, 0 deletions
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c new file mode 100644 index 00000000000..5b75a64b199 --- /dev/null +++ b/drivers/media/parport/bw-qcam.c | |||
@@ -0,0 +1,1113 @@ | |||
1 | /* | ||
2 | * QuickCam Driver For Video4Linux. | ||
3 | * | ||
4 | * Video4Linux conversion work by Alan Cox. | ||
5 | * Parport compatibility by Phil Blundell. | ||
6 | * Busy loop avoidance by Mark Cooke. | ||
7 | * | ||
8 | * Module parameters: | ||
9 | * | ||
10 | * maxpoll=<1 - 5000> | ||
11 | * | ||
12 | * When polling the QuickCam for a response, busy-wait for a | ||
13 | * maximum of this many loops. The default of 250 gives little | ||
14 | * impact on interactive response. | ||
15 | * | ||
16 | * NOTE: If this parameter is set too high, the processor | ||
17 | * will busy wait until this loop times out, and then | ||
18 | * slowly poll for a further 5 seconds before failing | ||
19 | * the transaction. You have been warned. | ||
20 | * | ||
21 | * yieldlines=<1 - 250> | ||
22 | * | ||
23 | * When acquiring a frame from the camera, the data gathering | ||
24 | * loop will yield back to the scheduler after completing | ||
25 | * this many lines. The default of 4 provides a trade-off | ||
26 | * between increased frame acquisition time and impact on | ||
27 | * interactive response. | ||
28 | */ | ||
29 | |||
30 | /* qcam-lib.c -- Library for programming with the Connectix QuickCam. | ||
31 | * See the included documentation for usage instructions and details | ||
32 | * of the protocol involved. */ | ||
33 | |||
34 | |||
35 | /* Version 0.5, August 4, 1996 */ | ||
36 | /* Version 0.7, August 27, 1996 */ | ||
37 | /* Version 0.9, November 17, 1996 */ | ||
38 | |||
39 | |||
40 | /****************************************************************** | ||
41 | |||
42 | Copyright (C) 1996 by Scott Laird | ||
43 | |||
44 | Permission is hereby granted, free of charge, to any person obtaining | ||
45 | a copy of this software and associated documentation files (the | ||
46 | "Software"), to deal in the Software without restriction, including | ||
47 | without limitation the rights to use, copy, modify, merge, publish, | ||
48 | distribute, sublicense, and/or sell copies of the Software, and to | ||
49 | permit persons to whom the Software is furnished to do so, subject to | ||
50 | the following conditions: | ||
51 | |||
52 | The above copyright notice and this permission notice shall be | ||
53 | included in all copies or substantial portions of the Software. | ||
54 | |||
55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
56 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
57 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
58 | IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
59 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
60 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
61 | OTHER DEALINGS IN THE SOFTWARE. | ||
62 | |||
63 | ******************************************************************/ | ||
64 | |||
65 | #include <linux/module.h> | ||
66 | #include <linux/delay.h> | ||
67 | #include <linux/errno.h> | ||
68 | #include <linux/fs.h> | ||
69 | #include <linux/kernel.h> | ||
70 | #include <linux/slab.h> | ||
71 | #include <linux/mm.h> | ||
72 | #include <linux/parport.h> | ||
73 | #include <linux/sched.h> | ||
74 | #include <linux/videodev2.h> | ||
75 | #include <linux/mutex.h> | ||
76 | #include <asm/uaccess.h> | ||
77 | #include <media/v4l2-common.h> | ||
78 | #include <media/v4l2-ioctl.h> | ||
79 | #include <media/v4l2-device.h> | ||
80 | #include <media/v4l2-fh.h> | ||
81 | #include <media/v4l2-ctrls.h> | ||
82 | #include <media/v4l2-event.h> | ||
83 | |||
84 | /* One from column A... */ | ||
85 | #define QC_NOTSET 0 | ||
86 | #define QC_UNIDIR 1 | ||
87 | #define QC_BIDIR 2 | ||
88 | #define QC_SERIAL 3 | ||
89 | |||
90 | /* ... and one from column B */ | ||
91 | #define QC_ANY 0x00 | ||
92 | #define QC_FORCE_UNIDIR 0x10 | ||
93 | #define QC_FORCE_BIDIR 0x20 | ||
94 | #define QC_FORCE_SERIAL 0x30 | ||
95 | /* in the port_mode member */ | ||
96 | |||
97 | #define QC_MODE_MASK 0x07 | ||
98 | #define QC_FORCE_MASK 0x70 | ||
99 | |||
100 | #define MAX_HEIGHT 243 | ||
101 | #define MAX_WIDTH 336 | ||
102 | |||
103 | /* Bit fields for status flags */ | ||
104 | #define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ | ||
105 | |||
106 | struct qcam { | ||
107 | struct v4l2_device v4l2_dev; | ||
108 | struct video_device vdev; | ||
109 | struct v4l2_ctrl_handler hdl; | ||
110 | struct pardevice *pdev; | ||
111 | struct parport *pport; | ||
112 | struct mutex lock; | ||
113 | int width, height; | ||
114 | int bpp; | ||
115 | int mode; | ||
116 | int contrast, brightness, whitebal; | ||
117 | int port_mode; | ||
118 | int transfer_scale; | ||
119 | int top, left; | ||
120 | int status; | ||
121 | unsigned int saved_bits; | ||
122 | unsigned long in_use; | ||
123 | }; | ||
124 | |||
125 | static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ | ||
126 | static unsigned int yieldlines = 4; /* Yield after this many during capture */ | ||
127 | static int video_nr = -1; | ||
128 | static unsigned int force_init; /* Whether to probe aggressively */ | ||
129 | |||
130 | module_param(maxpoll, int, 0); | ||
131 | module_param(yieldlines, int, 0); | ||
132 | module_param(video_nr, int, 0); | ||
133 | |||
134 | /* Set force_init=1 to avoid detection by polling status register and | ||
135 | * immediately attempt to initialize qcam */ | ||
136 | module_param(force_init, int, 0); | ||
137 | |||
138 | #define MAX_CAMS 4 | ||
139 | static struct qcam *qcams[MAX_CAMS]; | ||
140 | static unsigned int num_cams; | ||
141 | |||
142 | static inline int read_lpstatus(struct qcam *q) | ||
143 | { | ||
144 | return parport_read_status(q->pport); | ||
145 | } | ||
146 | |||
147 | static inline int read_lpdata(struct qcam *q) | ||
148 | { | ||
149 | return parport_read_data(q->pport); | ||
150 | } | ||
151 | |||
152 | static inline void write_lpdata(struct qcam *q, int d) | ||
153 | { | ||
154 | parport_write_data(q->pport, d); | ||
155 | } | ||
156 | |||
157 | static void write_lpcontrol(struct qcam *q, int d) | ||
158 | { | ||
159 | if (d & 0x20) { | ||
160 | /* Set bidirectional mode to reverse (data in) */ | ||
161 | parport_data_reverse(q->pport); | ||
162 | } else { | ||
163 | /* Set bidirectional mode to forward (data out) */ | ||
164 | parport_data_forward(q->pport); | ||
165 | } | ||
166 | |||
167 | /* Now issue the regular port command, but strip out the | ||
168 | * direction flag */ | ||
169 | d &= ~0x20; | ||
170 | parport_write_control(q->pport, d); | ||
171 | } | ||
172 | |||
173 | |||
174 | /* qc_waithand busy-waits for a handshake signal from the QuickCam. | ||
175 | * Almost all communication with the camera requires handshaking. */ | ||
176 | |||
177 | static int qc_waithand(struct qcam *q, int val) | ||
178 | { | ||
179 | int status; | ||
180 | int runs = 0; | ||
181 | |||
182 | if (val) { | ||
183 | while (!((status = read_lpstatus(q)) & 8)) { | ||
184 | /* 1000 is enough spins on the I/O for all normal | ||
185 | cases, at that point we start to poll slowly | ||
186 | until the camera wakes up. However, we are | ||
187 | busy blocked until the camera responds, so | ||
188 | setting it lower is much better for interactive | ||
189 | response. */ | ||
190 | |||
191 | if (runs++ > maxpoll) | ||
192 | msleep_interruptible(5); | ||
193 | if (runs > (maxpoll + 1000)) /* 5 seconds */ | ||
194 | return -1; | ||
195 | } | ||
196 | } else { | ||
197 | while (((status = read_lpstatus(q)) & 8)) { | ||
198 | /* 1000 is enough spins on the I/O for all normal | ||
199 | cases, at that point we start to poll slowly | ||
200 | until the camera wakes up. However, we are | ||
201 | busy blocked until the camera responds, so | ||
202 | setting it lower is much better for interactive | ||
203 | response. */ | ||
204 | |||
205 | if (runs++ > maxpoll) | ||
206 | msleep_interruptible(5); | ||
207 | if (runs++ > (maxpoll + 1000)) /* 5 seconds */ | ||
208 | return -1; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | return status; | ||
213 | } | ||
214 | |||
215 | /* Waithand2 is used when the qcam is in bidirectional mode, and the | ||
216 | * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 | ||
217 | * (bit 3 of status register). It also returns the last value read, | ||
218 | * since this data is useful. */ | ||
219 | |||
220 | static unsigned int qc_waithand2(struct qcam *q, int val) | ||
221 | { | ||
222 | unsigned int status; | ||
223 | int runs = 0; | ||
224 | |||
225 | do { | ||
226 | status = read_lpdata(q); | ||
227 | /* 1000 is enough spins on the I/O for all normal | ||
228 | cases, at that point we start to poll slowly | ||
229 | until the camera wakes up. However, we are | ||
230 | busy blocked until the camera responds, so | ||
231 | setting it lower is much better for interactive | ||
232 | response. */ | ||
233 | |||
234 | if (runs++ > maxpoll) | ||
235 | msleep_interruptible(5); | ||
236 | if (runs++ > (maxpoll + 1000)) /* 5 seconds */ | ||
237 | return 0; | ||
238 | } while ((status & 1) != val); | ||
239 | |||
240 | return status; | ||
241 | } | ||
242 | |||
243 | /* qc_command is probably a bit of a misnomer -- it's used to send | ||
244 | * bytes *to* the camera. Generally, these bytes are either commands | ||
245 | * or arguments to commands, so the name fits, but it still bugs me a | ||
246 | * bit. See the documentation for a list of commands. */ | ||
247 | |||
248 | static int qc_command(struct qcam *q, int command) | ||
249 | { | ||
250 | int n1, n2; | ||
251 | int cmd; | ||
252 | |||
253 | write_lpdata(q, command); | ||
254 | write_lpcontrol(q, 6); | ||
255 | |||
256 | n1 = qc_waithand(q, 1); | ||
257 | |||
258 | write_lpcontrol(q, 0xe); | ||
259 | n2 = qc_waithand(q, 0); | ||
260 | |||
261 | cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); | ||
262 | return cmd; | ||
263 | } | ||
264 | |||
265 | static int qc_readparam(struct qcam *q) | ||
266 | { | ||
267 | int n1, n2; | ||
268 | int cmd; | ||
269 | |||
270 | write_lpcontrol(q, 6); | ||
271 | n1 = qc_waithand(q, 1); | ||
272 | |||
273 | write_lpcontrol(q, 0xe); | ||
274 | n2 = qc_waithand(q, 0); | ||
275 | |||
276 | cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); | ||
277 | return cmd; | ||
278 | } | ||
279 | |||
280 | |||
281 | /* Try to detect a QuickCam. It appears to flash the upper 4 bits of | ||
282 | the status register at 5-10 Hz. This is only used in the autoprobe | ||
283 | code. Be aware that this isn't the way Connectix detects the | ||
284 | camera (they send a reset and try to handshake), but this should be | ||
285 | almost completely safe, while their method screws up my printer if | ||
286 | I plug it in before the camera. */ | ||
287 | |||
288 | static int qc_detect(struct qcam *q) | ||
289 | { | ||
290 | int reg, lastreg; | ||
291 | int count = 0; | ||
292 | int i; | ||
293 | |||
294 | if (force_init) | ||
295 | return 1; | ||
296 | |||
297 | lastreg = reg = read_lpstatus(q) & 0xf0; | ||
298 | |||
299 | for (i = 0; i < 500; i++) { | ||
300 | reg = read_lpstatus(q) & 0xf0; | ||
301 | if (reg != lastreg) | ||
302 | count++; | ||
303 | lastreg = reg; | ||
304 | mdelay(2); | ||
305 | } | ||
306 | |||
307 | |||
308 | #if 0 | ||
309 | /* Force camera detection during testing. Sometimes the camera | ||
310 | won't be flashing these bits. Possibly unloading the module | ||
311 | in the middle of a grab? Or some timeout condition? | ||
312 | I've seen this parameter as low as 19 on my 450Mhz box - mpc */ | ||
313 | printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); | ||
314 | return 1; | ||
315 | #endif | ||
316 | |||
317 | /* Be (even more) liberal in what you accept... */ | ||
318 | |||
319 | if (count > 20 && count < 400) { | ||
320 | return 1; /* found */ | ||
321 | } else { | ||
322 | printk(KERN_ERR "No Quickcam found on port %s\n", | ||
323 | q->pport->name); | ||
324 | printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); | ||
325 | return 0; /* not found */ | ||
326 | } | ||
327 | } | ||
328 | |||
329 | /* Decide which scan mode to use. There's no real requirement that | ||
330 | * the scanmode match the resolution in q->height and q-> width -- the | ||
331 | * camera takes the picture at the resolution specified in the | ||
332 | * "scanmode" and then returns the image at the resolution specified | ||
333 | * with the resolution commands. If the scan is bigger than the | ||
334 | * requested resolution, the upper-left hand corner of the scan is | ||
335 | * returned. If the scan is smaller, then the rest of the image | ||
336 | * returned contains garbage. */ | ||
337 | |||
338 | static int qc_setscanmode(struct qcam *q) | ||
339 | { | ||
340 | int old_mode = q->mode; | ||
341 | |||
342 | switch (q->transfer_scale) { | ||
343 | case 1: | ||
344 | q->mode = 0; | ||
345 | break; | ||
346 | case 2: | ||
347 | q->mode = 4; | ||
348 | break; | ||
349 | case 4: | ||
350 | q->mode = 8; | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | switch (q->bpp) { | ||
355 | case 4: | ||
356 | break; | ||
357 | case 6: | ||
358 | q->mode += 2; | ||
359 | break; | ||
360 | } | ||
361 | |||
362 | switch (q->port_mode & QC_MODE_MASK) { | ||
363 | case QC_BIDIR: | ||
364 | q->mode += 1; | ||
365 | break; | ||
366 | case QC_NOTSET: | ||
367 | case QC_UNIDIR: | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | if (q->mode != old_mode) | ||
372 | q->status |= QC_PARAM_CHANGE; | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | |||
378 | /* Reset the QuickCam. This uses the same sequence the Windows | ||
379 | * QuickPic program uses. Someone with a bi-directional port should | ||
380 | * check that bi-directional mode is detected right, and then | ||
381 | * implement bi-directional mode in qc_readbyte(). */ | ||
382 | |||
383 | static void qc_reset(struct qcam *q) | ||
384 | { | ||
385 | switch (q->port_mode & QC_FORCE_MASK) { | ||
386 | case QC_FORCE_UNIDIR: | ||
387 | q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; | ||
388 | break; | ||
389 | |||
390 | case QC_FORCE_BIDIR: | ||
391 | q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; | ||
392 | break; | ||
393 | |||
394 | case QC_ANY: | ||
395 | write_lpcontrol(q, 0x20); | ||
396 | write_lpdata(q, 0x75); | ||
397 | |||
398 | if (read_lpdata(q) != 0x75) | ||
399 | q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; | ||
400 | else | ||
401 | q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | write_lpcontrol(q, 0xb); | ||
406 | udelay(250); | ||
407 | write_lpcontrol(q, 0xe); | ||
408 | qc_setscanmode(q); /* in case port_mode changed */ | ||
409 | } | ||
410 | |||
411 | |||
412 | |||
413 | /* Reset the QuickCam and program for brightness, contrast, | ||
414 | * white-balance, and resolution. */ | ||
415 | |||
416 | static void qc_set(struct qcam *q) | ||
417 | { | ||
418 | int val; | ||
419 | int val2; | ||
420 | |||
421 | qc_reset(q); | ||
422 | |||
423 | /* Set the brightness. Yes, this is repetitive, but it works. | ||
424 | * Shorter versions seem to fail subtly. Feel free to try :-). */ | ||
425 | /* I think the problem was in qc_command, not here -- bls */ | ||
426 | |||
427 | qc_command(q, 0xb); | ||
428 | qc_command(q, q->brightness); | ||
429 | |||
430 | val = q->height / q->transfer_scale; | ||
431 | qc_command(q, 0x11); | ||
432 | qc_command(q, val); | ||
433 | if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { | ||
434 | /* The normal "transfers per line" calculation doesn't seem to work | ||
435 | as expected here (and yet it works fine in qc_scan). No idea | ||
436 | why this case is the odd man out. Fortunately, Laird's original | ||
437 | working version gives me a good way to guess at working values. | ||
438 | -- bls */ | ||
439 | val = q->width; | ||
440 | val2 = q->transfer_scale * 4; | ||
441 | } else { | ||
442 | val = q->width * q->bpp; | ||
443 | val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * | ||
444 | q->transfer_scale; | ||
445 | } | ||
446 | val = DIV_ROUND_UP(val, val2); | ||
447 | qc_command(q, 0x13); | ||
448 | qc_command(q, val); | ||
449 | |||
450 | /* Setting top and left -- bls */ | ||
451 | qc_command(q, 0xd); | ||
452 | qc_command(q, q->top); | ||
453 | qc_command(q, 0xf); | ||
454 | qc_command(q, q->left / 2); | ||
455 | |||
456 | qc_command(q, 0x19); | ||
457 | qc_command(q, q->contrast); | ||
458 | qc_command(q, 0x1f); | ||
459 | qc_command(q, q->whitebal); | ||
460 | |||
461 | /* Clear flag that we must update the grabbing parameters on the camera | ||
462 | before we grab the next frame */ | ||
463 | q->status &= (~QC_PARAM_CHANGE); | ||
464 | } | ||
465 | |||
466 | /* Qc_readbytes reads some bytes from the QC and puts them in | ||
467 | the supplied buffer. It returns the number of bytes read, | ||
468 | or -1 on error. */ | ||
469 | |||
470 | static inline int qc_readbytes(struct qcam *q, char buffer[]) | ||
471 | { | ||
472 | int ret = 1; | ||
473 | unsigned int hi, lo; | ||
474 | unsigned int hi2, lo2; | ||
475 | static int state; | ||
476 | |||
477 | if (buffer == NULL) { | ||
478 | state = 0; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | switch (q->port_mode & QC_MODE_MASK) { | ||
483 | case QC_BIDIR: /* Bi-directional Port */ | ||
484 | write_lpcontrol(q, 0x26); | ||
485 | lo = (qc_waithand2(q, 1) >> 1); | ||
486 | hi = (read_lpstatus(q) >> 3) & 0x1f; | ||
487 | write_lpcontrol(q, 0x2e); | ||
488 | lo2 = (qc_waithand2(q, 0) >> 1); | ||
489 | hi2 = (read_lpstatus(q) >> 3) & 0x1f; | ||
490 | switch (q->bpp) { | ||
491 | case 4: | ||
492 | buffer[0] = lo & 0xf; | ||
493 | buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); | ||
494 | buffer[2] = (hi & 0x1e) >> 1; | ||
495 | buffer[3] = lo2 & 0xf; | ||
496 | buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); | ||
497 | buffer[5] = (hi2 & 0x1e) >> 1; | ||
498 | ret = 6; | ||
499 | break; | ||
500 | case 6: | ||
501 | buffer[0] = lo & 0x3f; | ||
502 | buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); | ||
503 | buffer[2] = lo2 & 0x3f; | ||
504 | buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); | ||
505 | ret = 4; | ||
506 | break; | ||
507 | } | ||
508 | break; | ||
509 | |||
510 | case QC_UNIDIR: /* Unidirectional Port */ | ||
511 | write_lpcontrol(q, 6); | ||
512 | lo = (qc_waithand(q, 1) & 0xf0) >> 4; | ||
513 | write_lpcontrol(q, 0xe); | ||
514 | hi = (qc_waithand(q, 0) & 0xf0) >> 4; | ||
515 | |||
516 | switch (q->bpp) { | ||
517 | case 4: | ||
518 | buffer[0] = lo; | ||
519 | buffer[1] = hi; | ||
520 | ret = 2; | ||
521 | break; | ||
522 | case 6: | ||
523 | switch (state) { | ||
524 | case 0: | ||
525 | buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); | ||
526 | q->saved_bits = (hi & 3) << 4; | ||
527 | state = 1; | ||
528 | ret = 1; | ||
529 | break; | ||
530 | case 1: | ||
531 | buffer[0] = lo | q->saved_bits; | ||
532 | q->saved_bits = hi << 2; | ||
533 | state = 2; | ||
534 | ret = 1; | ||
535 | break; | ||
536 | case 2: | ||
537 | buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; | ||
538 | buffer[1] = ((lo & 3) << 4) | hi; | ||
539 | state = 0; | ||
540 | ret = 2; | ||
541 | break; | ||
542 | } | ||
543 | break; | ||
544 | } | ||
545 | break; | ||
546 | } | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | /* requests a scan from the camera. It sends the correct instructions | ||
551 | * to the camera and then reads back the correct number of bytes. In | ||
552 | * previous versions of this routine the return structure contained | ||
553 | * the raw output from the camera, and there was a 'qc_convertscan' | ||
554 | * function that converted that to a useful format. In version 0.3 I | ||
555 | * rolled qc_convertscan into qc_scan and now I only return the | ||
556 | * converted scan. The format is just an one-dimensional array of | ||
557 | * characters, one for each pixel, with 0=black up to n=white, where | ||
558 | * n=2^(bit depth)-1. Ask me for more details if you don't understand | ||
559 | * this. */ | ||
560 | |||
561 | static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) | ||
562 | { | ||
563 | int i, j, k, yield; | ||
564 | int bytes; | ||
565 | int linestotrans, transperline; | ||
566 | int divisor; | ||
567 | int pixels_per_line; | ||
568 | int pixels_read = 0; | ||
569 | int got = 0; | ||
570 | char buffer[6]; | ||
571 | int shift = 8 - q->bpp; | ||
572 | char invert; | ||
573 | |||
574 | if (q->mode == -1) | ||
575 | return -ENXIO; | ||
576 | |||
577 | qc_command(q, 0x7); | ||
578 | qc_command(q, q->mode); | ||
579 | |||
580 | if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { | ||
581 | write_lpcontrol(q, 0x2e); /* turn port around */ | ||
582 | write_lpcontrol(q, 0x26); | ||
583 | qc_waithand(q, 1); | ||
584 | write_lpcontrol(q, 0x2e); | ||
585 | qc_waithand(q, 0); | ||
586 | } | ||
587 | |||
588 | /* strange -- should be 15:63 below, but 4bpp is odd */ | ||
589 | invert = (q->bpp == 4) ? 16 : 63; | ||
590 | |||
591 | linestotrans = q->height / q->transfer_scale; | ||
592 | pixels_per_line = q->width / q->transfer_scale; | ||
593 | transperline = q->width * q->bpp; | ||
594 | divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * | ||
595 | q->transfer_scale; | ||
596 | transperline = DIV_ROUND_UP(transperline, divisor); | ||
597 | |||
598 | for (i = 0, yield = yieldlines; i < linestotrans; i++) { | ||
599 | for (pixels_read = j = 0; j < transperline; j++) { | ||
600 | bytes = qc_readbytes(q, buffer); | ||
601 | for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) { | ||
602 | int o; | ||
603 | if (buffer[k] == 0 && invert == 16) { | ||
604 | /* 4bpp is odd (again) -- inverter is 16, not 15, but output | ||
605 | must be 0-15 -- bls */ | ||
606 | buffer[k] = 16; | ||
607 | } | ||
608 | o = i * pixels_per_line + pixels_read + k; | ||
609 | if (o < len) { | ||
610 | u8 ch = invert - buffer[k]; | ||
611 | got++; | ||
612 | put_user(ch << shift, buf + o); | ||
613 | } | ||
614 | } | ||
615 | pixels_read += bytes; | ||
616 | } | ||
617 | qc_readbytes(q, NULL); /* reset state machine */ | ||
618 | |||
619 | /* Grabbing an entire frame from the quickcam is a lengthy | ||
620 | process. We don't (usually) want to busy-block the | ||
621 | processor for the entire frame. yieldlines is a module | ||
622 | parameter. If we yield every line, the minimum frame | ||
623 | time will be 240 / 200 = 1.2 seconds. The compile-time | ||
624 | default is to yield every 4 lines. */ | ||
625 | if (i >= yield) { | ||
626 | msleep_interruptible(5); | ||
627 | yield = i + yieldlines; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { | ||
632 | write_lpcontrol(q, 2); | ||
633 | write_lpcontrol(q, 6); | ||
634 | udelay(3); | ||
635 | write_lpcontrol(q, 0xe); | ||
636 | } | ||
637 | if (got < len) | ||
638 | return got; | ||
639 | return len; | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * Video4linux interfacing | ||
644 | */ | ||
645 | |||
646 | static int qcam_querycap(struct file *file, void *priv, | ||
647 | struct v4l2_capability *vcap) | ||
648 | { | ||
649 | struct qcam *qcam = video_drvdata(file); | ||
650 | |||
651 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); | ||
652 | strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card)); | ||
653 | strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info)); | ||
654 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
655 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) | ||
660 | { | ||
661 | if (vin->index > 0) | ||
662 | return -EINVAL; | ||
663 | strlcpy(vin->name, "Camera", sizeof(vin->name)); | ||
664 | vin->type = V4L2_INPUT_TYPE_CAMERA; | ||
665 | vin->audioset = 0; | ||
666 | vin->tuner = 0; | ||
667 | vin->std = 0; | ||
668 | vin->status = 0; | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) | ||
673 | { | ||
674 | *inp = 0; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int qcam_s_input(struct file *file, void *fh, unsigned int inp) | ||
679 | { | ||
680 | return (inp > 0) ? -EINVAL : 0; | ||
681 | } | ||
682 | |||
683 | static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
684 | { | ||
685 | struct qcam *qcam = video_drvdata(file); | ||
686 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
687 | |||
688 | pix->width = qcam->width / qcam->transfer_scale; | ||
689 | pix->height = qcam->height / qcam->transfer_scale; | ||
690 | pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; | ||
691 | pix->field = V4L2_FIELD_NONE; | ||
692 | pix->bytesperline = pix->width; | ||
693 | pix->sizeimage = pix->width * pix->height; | ||
694 | /* Just a guess */ | ||
695 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
700 | { | ||
701 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
702 | |||
703 | if (pix->height <= 60 || pix->width <= 80) { | ||
704 | pix->height = 60; | ||
705 | pix->width = 80; | ||
706 | } else if (pix->height <= 120 || pix->width <= 160) { | ||
707 | pix->height = 120; | ||
708 | pix->width = 160; | ||
709 | } else { | ||
710 | pix->height = 240; | ||
711 | pix->width = 320; | ||
712 | } | ||
713 | if (pix->pixelformat != V4L2_PIX_FMT_Y4 && | ||
714 | pix->pixelformat != V4L2_PIX_FMT_Y6) | ||
715 | pix->pixelformat = V4L2_PIX_FMT_Y4; | ||
716 | pix->field = V4L2_FIELD_NONE; | ||
717 | pix->bytesperline = pix->width; | ||
718 | pix->sizeimage = pix->width * pix->height; | ||
719 | /* Just a guess */ | ||
720 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
725 | { | ||
726 | struct qcam *qcam = video_drvdata(file); | ||
727 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
728 | int ret = qcam_try_fmt_vid_cap(file, fh, fmt); | ||
729 | |||
730 | if (ret) | ||
731 | return ret; | ||
732 | qcam->width = 320; | ||
733 | qcam->height = 240; | ||
734 | if (pix->height == 60) | ||
735 | qcam->transfer_scale = 4; | ||
736 | else if (pix->height == 120) | ||
737 | qcam->transfer_scale = 2; | ||
738 | else | ||
739 | qcam->transfer_scale = 1; | ||
740 | if (pix->pixelformat == V4L2_PIX_FMT_Y6) | ||
741 | qcam->bpp = 6; | ||
742 | else | ||
743 | qcam->bpp = 4; | ||
744 | |||
745 | mutex_lock(&qcam->lock); | ||
746 | qc_setscanmode(qcam); | ||
747 | /* We must update the camera before we grab. We could | ||
748 | just have changed the grab size */ | ||
749 | qcam->status |= QC_PARAM_CHANGE; | ||
750 | mutex_unlock(&qcam->lock); | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) | ||
755 | { | ||
756 | static struct v4l2_fmtdesc formats[] = { | ||
757 | { 0, 0, 0, | ||
758 | "4-Bit Monochrome", V4L2_PIX_FMT_Y4, | ||
759 | { 0, 0, 0, 0 } | ||
760 | }, | ||
761 | { 1, 0, 0, | ||
762 | "6-Bit Monochrome", V4L2_PIX_FMT_Y6, | ||
763 | { 0, 0, 0, 0 } | ||
764 | }, | ||
765 | }; | ||
766 | enum v4l2_buf_type type = fmt->type; | ||
767 | |||
768 | if (fmt->index > 1) | ||
769 | return -EINVAL; | ||
770 | |||
771 | *fmt = formats[fmt->index]; | ||
772 | fmt->type = type; | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int qcam_enum_framesizes(struct file *file, void *fh, | ||
777 | struct v4l2_frmsizeenum *fsize) | ||
778 | { | ||
779 | static const struct v4l2_frmsize_discrete sizes[] = { | ||
780 | { 80, 60 }, | ||
781 | { 160, 120 }, | ||
782 | { 320, 240 }, | ||
783 | }; | ||
784 | |||
785 | if (fsize->index > 2) | ||
786 | return -EINVAL; | ||
787 | if (fsize->pixel_format != V4L2_PIX_FMT_Y4 && | ||
788 | fsize->pixel_format != V4L2_PIX_FMT_Y6) | ||
789 | return -EINVAL; | ||
790 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
791 | fsize->discrete = sizes[fsize->index]; | ||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static ssize_t qcam_read(struct file *file, char __user *buf, | ||
796 | size_t count, loff_t *ppos) | ||
797 | { | ||
798 | struct qcam *qcam = video_drvdata(file); | ||
799 | int len; | ||
800 | parport_claim_or_block(qcam->pdev); | ||
801 | |||
802 | mutex_lock(&qcam->lock); | ||
803 | |||
804 | qc_reset(qcam); | ||
805 | |||
806 | /* Update the camera parameters if we need to */ | ||
807 | if (qcam->status & QC_PARAM_CHANGE) | ||
808 | qc_set(qcam); | ||
809 | |||
810 | len = qc_capture(qcam, buf, count); | ||
811 | |||
812 | mutex_unlock(&qcam->lock); | ||
813 | |||
814 | parport_release(qcam->pdev); | ||
815 | return len; | ||
816 | } | ||
817 | |||
818 | static unsigned int qcam_poll(struct file *filp, poll_table *wait) | ||
819 | { | ||
820 | return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM; | ||
821 | } | ||
822 | |||
823 | static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) | ||
824 | { | ||
825 | struct qcam *qcam = | ||
826 | container_of(ctrl->handler, struct qcam, hdl); | ||
827 | int ret = 0; | ||
828 | |||
829 | mutex_lock(&qcam->lock); | ||
830 | switch (ctrl->id) { | ||
831 | case V4L2_CID_BRIGHTNESS: | ||
832 | qcam->brightness = ctrl->val; | ||
833 | break; | ||
834 | case V4L2_CID_CONTRAST: | ||
835 | qcam->contrast = ctrl->val; | ||
836 | break; | ||
837 | case V4L2_CID_GAMMA: | ||
838 | qcam->whitebal = ctrl->val; | ||
839 | break; | ||
840 | default: | ||
841 | ret = -EINVAL; | ||
842 | break; | ||
843 | } | ||
844 | if (ret == 0) { | ||
845 | qc_setscanmode(qcam); | ||
846 | qcam->status |= QC_PARAM_CHANGE; | ||
847 | } | ||
848 | mutex_unlock(&qcam->lock); | ||
849 | return ret; | ||
850 | } | ||
851 | |||
852 | static const struct v4l2_file_operations qcam_fops = { | ||
853 | .owner = THIS_MODULE, | ||
854 | .open = v4l2_fh_open, | ||
855 | .release = v4l2_fh_release, | ||
856 | .poll = qcam_poll, | ||
857 | .unlocked_ioctl = video_ioctl2, | ||
858 | .read = qcam_read, | ||
859 | }; | ||
860 | |||
861 | static const struct v4l2_ioctl_ops qcam_ioctl_ops = { | ||
862 | .vidioc_querycap = qcam_querycap, | ||
863 | .vidioc_g_input = qcam_g_input, | ||
864 | .vidioc_s_input = qcam_s_input, | ||
865 | .vidioc_enum_input = qcam_enum_input, | ||
866 | .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, | ||
867 | .vidioc_enum_framesizes = qcam_enum_framesizes, | ||
868 | .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, | ||
869 | .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, | ||
870 | .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, | ||
871 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
872 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
873 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
874 | }; | ||
875 | |||
876 | static const struct v4l2_ctrl_ops qcam_ctrl_ops = { | ||
877 | .s_ctrl = qcam_s_ctrl, | ||
878 | }; | ||
879 | |||
880 | /* Initialize the QuickCam driver control structure. This is where | ||
881 | * defaults are set for people who don't have a config file.*/ | ||
882 | |||
883 | static struct qcam *qcam_init(struct parport *port) | ||
884 | { | ||
885 | struct qcam *qcam; | ||
886 | struct v4l2_device *v4l2_dev; | ||
887 | |||
888 | qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); | ||
889 | if (qcam == NULL) | ||
890 | return NULL; | ||
891 | |||
892 | v4l2_dev = &qcam->v4l2_dev; | ||
893 | snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams); | ||
894 | |||
895 | if (v4l2_device_register(port->dev, v4l2_dev) < 0) { | ||
896 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
897 | kfree(qcam); | ||
898 | return NULL; | ||
899 | } | ||
900 | |||
901 | v4l2_ctrl_handler_init(&qcam->hdl, 3); | ||
902 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
903 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 180); | ||
904 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
905 | V4L2_CID_CONTRAST, 0, 255, 1, 192); | ||
906 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
907 | V4L2_CID_GAMMA, 0, 255, 1, 105); | ||
908 | if (qcam->hdl.error) { | ||
909 | v4l2_err(v4l2_dev, "couldn't register controls\n"); | ||
910 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
911 | kfree(qcam); | ||
912 | return NULL; | ||
913 | } | ||
914 | qcam->pport = port; | ||
915 | qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL, | ||
916 | NULL, 0, NULL); | ||
917 | if (qcam->pdev == NULL) { | ||
918 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); | ||
919 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
920 | kfree(qcam); | ||
921 | return NULL; | ||
922 | } | ||
923 | |||
924 | strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); | ||
925 | qcam->vdev.v4l2_dev = v4l2_dev; | ||
926 | qcam->vdev.ctrl_handler = &qcam->hdl; | ||
927 | qcam->vdev.fops = &qcam_fops; | ||
928 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; | ||
929 | set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags); | ||
930 | qcam->vdev.release = video_device_release_empty; | ||
931 | video_set_drvdata(&qcam->vdev, qcam); | ||
932 | |||
933 | mutex_init(&qcam->lock); | ||
934 | |||
935 | qcam->port_mode = (QC_ANY | QC_NOTSET); | ||
936 | qcam->width = 320; | ||
937 | qcam->height = 240; | ||
938 | qcam->bpp = 4; | ||
939 | qcam->transfer_scale = 2; | ||
940 | qcam->contrast = 192; | ||
941 | qcam->brightness = 180; | ||
942 | qcam->whitebal = 105; | ||
943 | qcam->top = 1; | ||
944 | qcam->left = 14; | ||
945 | qcam->mode = -1; | ||
946 | qcam->status = QC_PARAM_CHANGE; | ||
947 | return qcam; | ||
948 | } | ||
949 | |||
950 | static int qc_calibrate(struct qcam *q) | ||
951 | { | ||
952 | /* | ||
953 | * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 | ||
954 | * The white balance is an individual value for each | ||
955 | * quickcam. | ||
956 | */ | ||
957 | |||
958 | int value; | ||
959 | int count = 0; | ||
960 | |||
961 | qc_command(q, 27); /* AutoAdjustOffset */ | ||
962 | qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ | ||
963 | |||
964 | /* GetOffset (33) will read 255 until autocalibration */ | ||
965 | /* is finished. After that, a value of 1-254 will be */ | ||
966 | /* returned. */ | ||
967 | |||
968 | do { | ||
969 | qc_command(q, 33); | ||
970 | value = qc_readparam(q); | ||
971 | mdelay(1); | ||
972 | schedule(); | ||
973 | count++; | ||
974 | } while (value == 0xff && count < 2048); | ||
975 | |||
976 | q->whitebal = value; | ||
977 | return value; | ||
978 | } | ||
979 | |||
980 | static int init_bwqcam(struct parport *port) | ||
981 | { | ||
982 | struct qcam *qcam; | ||
983 | |||
984 | if (num_cams == MAX_CAMS) { | ||
985 | printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); | ||
986 | return -ENOSPC; | ||
987 | } | ||
988 | |||
989 | qcam = qcam_init(port); | ||
990 | if (qcam == NULL) | ||
991 | return -ENODEV; | ||
992 | |||
993 | parport_claim_or_block(qcam->pdev); | ||
994 | |||
995 | qc_reset(qcam); | ||
996 | |||
997 | if (qc_detect(qcam) == 0) { | ||
998 | parport_release(qcam->pdev); | ||
999 | parport_unregister_device(qcam->pdev); | ||
1000 | kfree(qcam); | ||
1001 | return -ENODEV; | ||
1002 | } | ||
1003 | qc_calibrate(qcam); | ||
1004 | v4l2_ctrl_handler_setup(&qcam->hdl); | ||
1005 | |||
1006 | parport_release(qcam->pdev); | ||
1007 | |||
1008 | v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); | ||
1009 | |||
1010 | if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { | ||
1011 | parport_unregister_device(qcam->pdev); | ||
1012 | kfree(qcam); | ||
1013 | return -ENODEV; | ||
1014 | } | ||
1015 | |||
1016 | qcams[num_cams++] = qcam; | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static void close_bwqcam(struct qcam *qcam) | ||
1022 | { | ||
1023 | video_unregister_device(&qcam->vdev); | ||
1024 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
1025 | parport_unregister_device(qcam->pdev); | ||
1026 | kfree(qcam); | ||
1027 | } | ||
1028 | |||
1029 | /* The parport parameter controls which parports will be scanned. | ||
1030 | * Scanning all parports causes some printers to print a garbage page. | ||
1031 | * -- March 14, 1999 Billy Donahue <billy@escape.com> */ | ||
1032 | #ifdef MODULE | ||
1033 | static char *parport[MAX_CAMS] = { NULL, }; | ||
1034 | module_param_array(parport, charp, NULL, 0); | ||
1035 | #endif | ||
1036 | |||
1037 | static int accept_bwqcam(struct parport *port) | ||
1038 | { | ||
1039 | #ifdef MODULE | ||
1040 | int n; | ||
1041 | |||
1042 | if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { | ||
1043 | /* user gave parport parameters */ | ||
1044 | for (n = 0; n < MAX_CAMS && parport[n]; n++) { | ||
1045 | char *ep; | ||
1046 | unsigned long r; | ||
1047 | r = simple_strtoul(parport[n], &ep, 0); | ||
1048 | if (ep == parport[n]) { | ||
1049 | printk(KERN_ERR | ||
1050 | "bw-qcam: bad port specifier \"%s\"\n", | ||
1051 | parport[n]); | ||
1052 | continue; | ||
1053 | } | ||
1054 | if (r == port->number) | ||
1055 | return 1; | ||
1056 | } | ||
1057 | return 0; | ||
1058 | } | ||
1059 | #endif | ||
1060 | return 1; | ||
1061 | } | ||
1062 | |||
1063 | static void bwqcam_attach(struct parport *port) | ||
1064 | { | ||
1065 | if (accept_bwqcam(port)) | ||
1066 | init_bwqcam(port); | ||
1067 | } | ||
1068 | |||
1069 | static void bwqcam_detach(struct parport *port) | ||
1070 | { | ||
1071 | int i; | ||
1072 | for (i = 0; i < num_cams; i++) { | ||
1073 | struct qcam *qcam = qcams[i]; | ||
1074 | if (qcam && qcam->pdev->port == port) { | ||
1075 | qcams[i] = NULL; | ||
1076 | close_bwqcam(qcam); | ||
1077 | } | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | static struct parport_driver bwqcam_driver = { | ||
1082 | .name = "bw-qcam", | ||
1083 | .attach = bwqcam_attach, | ||
1084 | .detach = bwqcam_detach, | ||
1085 | }; | ||
1086 | |||
1087 | static void __exit exit_bw_qcams(void) | ||
1088 | { | ||
1089 | parport_unregister_driver(&bwqcam_driver); | ||
1090 | } | ||
1091 | |||
1092 | static int __init init_bw_qcams(void) | ||
1093 | { | ||
1094 | #ifdef MODULE | ||
1095 | /* Do some sanity checks on the module parameters. */ | ||
1096 | if (maxpoll > 5000) { | ||
1097 | printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n"); | ||
1098 | maxpoll = 5000; | ||
1099 | } | ||
1100 | |||
1101 | if (yieldlines < 1) { | ||
1102 | printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n"); | ||
1103 | yieldlines = 1; | ||
1104 | } | ||
1105 | #endif | ||
1106 | return parport_register_driver(&bwqcam_driver); | ||
1107 | } | ||
1108 | |||
1109 | module_init(init_bw_qcams); | ||
1110 | module_exit(exit_bw_qcams); | ||
1111 | |||
1112 | MODULE_LICENSE("GPL"); | ||
1113 | MODULE_VERSION("0.0.3"); | ||