Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
1da177e4 LT |
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> | |
483d67ff | 74 | #include <linux/videodev2.h> |
3593cab5 | 75 | #include <linux/mutex.h> |
1da177e4 | 76 | #include <asm/uaccess.h> |
483d67ff HV |
77 | #include <media/v4l2-common.h> |
78 | #include <media/v4l2-ioctl.h> | |
79 | #include <media/v4l2-device.h> | |
5fa1a89d HV |
80 | #include <media/v4l2-fh.h> |
81 | #include <media/v4l2-ctrls.h> | |
82 | #include <media/v4l2-event.h> | |
483d67ff HV |
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; | |
5fa1a89d | 109 | struct v4l2_ctrl_handler hdl; |
483d67ff HV |
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 | }; | |
1da177e4 | 124 | |
1d61aac0 HV |
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 */ | |
1da177e4 | 127 | static int video_nr = -1; |
d685a483 | 128 | static unsigned int force_init; /* Whether to probe aggressively */ |
1da177e4 LT |
129 | |
130 | module_param(maxpoll, int, 0); | |
131 | module_param(yieldlines, int, 0); | |
132 | module_param(video_nr, int, 0); | |
133 | ||
d685a483 BW |
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 | ||
483d67ff HV |
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) | |
1da177e4 LT |
143 | { |
144 | return parport_read_status(q->pport); | |
145 | } | |
146 | ||
483d67ff | 147 | static inline int read_lpdata(struct qcam *q) |
1da177e4 LT |
148 | { |
149 | return parport_read_data(q->pport); | |
150 | } | |
151 | ||
483d67ff | 152 | static inline void write_lpdata(struct qcam *q, int d) |
1da177e4 LT |
153 | { |
154 | parport_write_data(q->pport, d); | |
155 | } | |
156 | ||
483d67ff | 157 | static void write_lpcontrol(struct qcam *q, int d) |
1da177e4 | 158 | { |
7c596fa9 | 159 | if (d & 0x20) { |
9e19db5b BW |
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; | |
1da177e4 LT |
170 | parport_write_control(q->pport, d); |
171 | } | |
172 | ||
1da177e4 LT |
173 | |
174 | /* qc_waithand busy-waits for a handshake signal from the QuickCam. | |
175 | * Almost all communication with the camera requires handshaking. */ | |
176 | ||
483d67ff | 177 | static int qc_waithand(struct qcam *q, int val) |
1da177e4 LT |
178 | { |
179 | int status; | |
1d61aac0 | 180 | int runs = 0; |
1da177e4 | 181 | |
1d61aac0 HV |
182 | if (val) { |
183 | while (!((status = read_lpstatus(q)) & 8)) { | |
1da177e4 | 184 | /* 1000 is enough spins on the I/O for all normal |
d56410e0 | 185 | cases, at that point we start to poll slowly |
1da177e4 LT |
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. */ | |
d56410e0 | 190 | |
1d61aac0 | 191 | if (runs++ > maxpoll) |
1da177e4 | 192 | msleep_interruptible(5); |
1d61aac0 | 193 | if (runs > (maxpoll + 1000)) /* 5 seconds */ |
1da177e4 LT |
194 | return -1; |
195 | } | |
1d61aac0 HV |
196 | } else { |
197 | while (((status = read_lpstatus(q)) & 8)) { | |
1da177e4 | 198 | /* 1000 is enough spins on the I/O for all normal |
d56410e0 | 199 | cases, at that point we start to poll slowly |
1da177e4 LT |
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. */ | |
d56410e0 | 204 | |
1d61aac0 | 205 | if (runs++ > maxpoll) |
1da177e4 | 206 | msleep_interruptible(5); |
1d61aac0 | 207 | if (runs++ > (maxpoll + 1000)) /* 5 seconds */ |
1da177e4 LT |
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 | ||
483d67ff | 220 | static unsigned int qc_waithand2(struct qcam *q, int val) |
1da177e4 LT |
221 | { |
222 | unsigned int status; | |
1d61aac0 | 223 | int runs = 0; |
d56410e0 | 224 | |
1d61aac0 | 225 | do { |
1da177e4 LT |
226 | status = read_lpdata(q); |
227 | /* 1000 is enough spins on the I/O for all normal | |
d56410e0 | 228 | cases, at that point we start to poll slowly |
1da177e4 LT |
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. */ | |
d56410e0 | 233 | |
1d61aac0 | 234 | if (runs++ > maxpoll) |
1da177e4 | 235 | msleep_interruptible(5); |
1d61aac0 | 236 | if (runs++ > (maxpoll + 1000)) /* 5 seconds */ |
1da177e4 | 237 | return 0; |
1d61aac0 | 238 | } while ((status & 1) != val); |
1da177e4 LT |
239 | |
240 | return status; | |
241 | } | |
242 | ||
483d67ff HV |
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 | ||
1da177e4 LT |
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 | ||
483d67ff | 288 | static int qc_detect(struct qcam *q) |
1da177e4 LT |
289 | { |
290 | int reg, lastreg; | |
291 | int count = 0; | |
292 | int i; | |
293 | ||
d685a483 BW |
294 | if (force_init) |
295 | return 1; | |
296 | ||
1da177e4 LT |
297 | lastreg = reg = read_lpstatus(q) & 0xf0; |
298 | ||
1d61aac0 | 299 | for (i = 0; i < 500; i++) { |
1da177e4 LT |
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 */ | |
1d61aac0 | 313 | printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); |
1da177e4 LT |
314 | return 1; |
315 | #endif | |
316 | ||
317 | /* Be (even more) liberal in what you accept... */ | |
318 | ||
7c596fa9 | 319 | if (count > 20 && count < 400) { |
1da177e4 | 320 | return 1; /* found */ |
9e19db5b | 321 | } else { |
7c596fa9 | 322 | printk(KERN_ERR "No Quickcam found on port %s\n", |
1d61aac0 | 323 | q->pport->name); |
d685a483 | 324 | printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); |
1da177e4 | 325 | return 0; /* not found */ |
9e19db5b | 326 | } |
1da177e4 LT |
327 | } |
328 | ||
1da177e4 LT |
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 | ||
483d67ff | 338 | static int qc_setscanmode(struct qcam *q) |
1da177e4 LT |
339 | { |
340 | int old_mode = q->mode; | |
d56410e0 | 341 | |
1d61aac0 HV |
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; | |
1da177e4 LT |
352 | } |
353 | ||
1d61aac0 HV |
354 | switch (q->bpp) { |
355 | case 4: | |
356 | break; | |
357 | case 6: | |
358 | q->mode += 2; | |
359 | break; | |
1da177e4 LT |
360 | } |
361 | ||
1d61aac0 HV |
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; | |
1da177e4 | 369 | } |
d56410e0 | 370 | |
1da177e4 LT |
371 | if (q->mode != old_mode) |
372 | q->status |= QC_PARAM_CHANGE; | |
d56410e0 | 373 | |
1da177e4 LT |
374 | return 0; |
375 | } | |
376 | ||
377 | ||
483d67ff HV |
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 | ||
1da177e4 LT |
413 | /* Reset the QuickCam and program for brightness, contrast, |
414 | * white-balance, and resolution. */ | |
415 | ||
483d67ff | 416 | static void qc_set(struct qcam *q) |
1da177e4 LT |
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 */ | |
d56410e0 | 426 | |
1da177e4 LT |
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) * | |
1d61aac0 | 444 | q->transfer_scale; |
1da177e4 | 445 | } |
e9e24cee | 446 | val = DIV_ROUND_UP(val, val2); |
1da177e4 LT |
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 | ||
483d67ff | 470 | static inline int qc_readbytes(struct qcam *q, char buffer[]) |
1da177e4 | 471 | { |
1d61aac0 | 472 | int ret = 1; |
1da177e4 LT |
473 | unsigned int hi, lo; |
474 | unsigned int hi2, lo2; | |
ff699e6b | 475 | static int state; |
1da177e4 | 476 | |
1d61aac0 | 477 | if (buffer == NULL) { |
1da177e4 LT |
478 | state = 0; |
479 | return 0; | |
480 | } | |
d56410e0 | 481 | |
1d61aac0 HV |
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; | |
1da177e4 | 506 | break; |
1d61aac0 HV |
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; | |
1da177e4 | 515 | |
1d61aac0 HV |
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; | |
1da177e4 LT |
542 | } |
543 | break; | |
1d61aac0 HV |
544 | } |
545 | break; | |
1da177e4 LT |
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 | ||
483d67ff | 561 | static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) |
1da177e4 LT |
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; | |
1d61aac0 | 569 | int got = 0; |
1da177e4 | 570 | char buffer[6]; |
1d61aac0 | 571 | int shift = 8 - q->bpp; |
1da177e4 LT |
572 | char invert; |
573 | ||
d56410e0 | 574 | if (q->mode == -1) |
1da177e4 LT |
575 | return -ENXIO; |
576 | ||
577 | qc_command(q, 0x7); | |
578 | qc_command(q, q->mode); | |
579 | ||
1d61aac0 | 580 | if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { |
1da177e4 LT |
581 | write_lpcontrol(q, 0x2e); /* turn port around */ |
582 | write_lpcontrol(q, 0x26); | |
1d61aac0 | 583 | qc_waithand(q, 1); |
1da177e4 | 584 | write_lpcontrol(q, 0x2e); |
1d61aac0 | 585 | qc_waithand(q, 0); |
1da177e4 | 586 | } |
d56410e0 | 587 | |
1da177e4 LT |
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) * | |
1d61aac0 | 595 | q->transfer_scale; |
e9e24cee | 596 | transperline = DIV_ROUND_UP(transperline, divisor); |
1da177e4 | 597 | |
1d61aac0 HV |
598 | for (i = 0, yield = yieldlines; i < linestotrans; i++) { |
599 | for (pixels_read = j = 0; j < transperline; j++) { | |
1da177e4 | 600 | bytes = qc_readbytes(q, buffer); |
1d61aac0 | 601 | for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) { |
1da177e4 | 602 | int o; |
1d61aac0 | 603 | if (buffer[k] == 0 && invert == 16) { |
1da177e4 LT |
604 | /* 4bpp is odd (again) -- inverter is 16, not 15, but output |
605 | must be 0-15 -- bls */ | |
606 | buffer[k] = 16; | |
607 | } | |
1d61aac0 HV |
608 | o = i * pixels_per_line + pixels_read + k; |
609 | if (o < len) { | |
de87897a | 610 | u8 ch = invert - buffer[k]; |
1da177e4 | 611 | got++; |
de87897a | 612 | put_user(ch << shift, buf + o); |
1da177e4 LT |
613 | } |
614 | } | |
615 | pixels_read += bytes; | |
616 | } | |
1d61aac0 | 617 | qc_readbytes(q, NULL); /* reset state machine */ |
d56410e0 | 618 | |
1da177e4 LT |
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 | ||
1d61aac0 | 631 | if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { |
1da177e4 LT |
632 | write_lpcontrol(q, 2); |
633 | write_lpcontrol(q, 6); | |
634 | udelay(3); | |
635 | write_lpcontrol(q, 0xe); | |
636 | } | |
1d61aac0 | 637 | if (got < len) |
1da177e4 LT |
638 | return got; |
639 | return len; | |
640 | } | |
641 | ||
642 | /* | |
643 | * Video4linux interfacing | |
644 | */ | |
645 | ||
483d67ff HV |
646 | static int qcam_querycap(struct file *file, void *priv, |
647 | struct v4l2_capability *vcap) | |
1da177e4 | 648 | { |
483d67ff | 649 | struct qcam *qcam = video_drvdata(file); |
1da177e4 | 650 | |
483d67ff | 651 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); |
de87897a HV |
652 | strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card)); |
653 | strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info)); | |
5fa1a89d HV |
654 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; |
655 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | |
483d67ff HV |
656 | return 0; |
657 | } | |
d56410e0 | 658 | |
483d67ff HV |
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 | } | |
d56410e0 | 671 | |
483d67ff HV |
672 | static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) |
673 | { | |
674 | *inp = 0; | |
675 | return 0; | |
676 | } | |
1d61aac0 | 677 | |
483d67ff HV |
678 | static int qcam_s_input(struct file *file, void *fh, unsigned int inp) |
679 | { | |
680 | return (inp > 0) ? -EINVAL : 0; | |
681 | } | |
682 | ||
483d67ff HV |
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; | |
de87897a HV |
692 | pix->bytesperline = pix->width; |
693 | pix->sizeimage = pix->width * pix->height; | |
483d67ff HV |
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); | |
1da177e4 LT |
751 | return 0; |
752 | } | |
753 | ||
483d67ff | 754 | static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) |
1da177e4 | 755 | { |
483d67ff HV |
756 | static struct v4l2_fmtdesc formats[] = { |
757 | { 0, 0, 0, | |
758 | "4-Bit Monochrome", V4L2_PIX_FMT_Y4, | |
759 | { 0, 0, 0, 0 } | |
760 | }, | |
de87897a | 761 | { 1, 0, 0, |
483d67ff HV |
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; | |
1da177e4 LT |
774 | } |
775 | ||
de87897a HV |
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 | ||
1da177e4 | 795 | static ssize_t qcam_read(struct file *file, char __user *buf, |
1d61aac0 | 796 | size_t count, loff_t *ppos) |
1da177e4 | 797 | { |
483d67ff | 798 | struct qcam *qcam = video_drvdata(file); |
1da177e4 LT |
799 | int len; |
800 | parport_claim_or_block(qcam->pdev); | |
d56410e0 | 801 | |
3593cab5 | 802 | mutex_lock(&qcam->lock); |
d56410e0 | 803 | |
1da177e4 LT |
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 | ||
1d61aac0 | 810 | len = qc_capture(qcam, buf, count); |
d56410e0 | 811 | |
3593cab5 | 812 | mutex_unlock(&qcam->lock); |
d56410e0 | 813 | |
1da177e4 LT |
814 | parport_release(qcam->pdev); |
815 | return len; | |
816 | } | |
d56410e0 | 817 | |
de87897a HV |
818 | static unsigned int qcam_poll(struct file *filp, poll_table *wait) |
819 | { | |
820 | return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM; | |
821 | } | |
822 | ||
5fa1a89d HV |
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 | ||
483d67ff HV |
852 | static const struct v4l2_file_operations qcam_fops = { |
853 | .owner = THIS_MODULE, | |
5fa1a89d HV |
854 | .open = v4l2_fh_open, |
855 | .release = v4l2_fh_release, | |
de87897a | 856 | .poll = qcam_poll, |
61df3c9b | 857 | .unlocked_ioctl = video_ioctl2, |
483d67ff HV |
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, | |
483d67ff | 866 | .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, |
de87897a | 867 | .vidioc_enum_framesizes = qcam_enum_framesizes, |
483d67ff HV |
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, | |
5fa1a89d HV |
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, | |
483d67ff HV |
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) | |
7d43cd53 | 884 | { |
483d67ff HV |
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; | |
de87897a | 893 | snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams); |
7d43cd53 | 894 | |
de87897a | 895 | if (v4l2_device_register(port->dev, v4l2_dev) < 0) { |
483d67ff | 896 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); |
ee893e9a | 897 | kfree(qcam); |
483d67ff HV |
898 | return NULL; |
899 | } | |
900 | ||
5fa1a89d HV |
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 | } | |
483d67ff | 914 | qcam->pport = port; |
de87897a | 915 | qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL, |
483d67ff HV |
916 | NULL, 0, NULL); |
917 | if (qcam->pdev == NULL) { | |
918 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); | |
5fa1a89d | 919 | v4l2_ctrl_handler_free(&qcam->hdl); |
483d67ff HV |
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; | |
5fa1a89d | 926 | qcam->vdev.ctrl_handler = &qcam->hdl; |
483d67ff HV |
927 | qcam->vdev.fops = &qcam_fops; |
928 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; | |
5fa1a89d | 929 | set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags); |
483d67ff HV |
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; | |
7d43cd53 HV |
948 | } |
949 | ||
483d67ff | 950 | static int qc_calibrate(struct qcam *q) |
7d43cd53 | 951 | { |
483d67ff HV |
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 | */ | |
7d43cd53 | 957 | |
483d67ff HV |
958 | int value; |
959 | int count = 0; | |
7d43cd53 | 960 | |
483d67ff HV |
961 | qc_command(q, 27); /* AutoAdjustOffset */ |
962 | qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ | |
1da177e4 | 963 | |
483d67ff HV |
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 | } | |
1da177e4 LT |
979 | |
980 | static int init_bwqcam(struct parport *port) | |
981 | { | |
483d67ff | 982 | struct qcam *qcam; |
1da177e4 | 983 | |
1d61aac0 | 984 | if (num_cams == MAX_CAMS) { |
1da177e4 LT |
985 | printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); |
986 | return -ENOSPC; | |
987 | } | |
988 | ||
1d61aac0 HV |
989 | qcam = qcam_init(port); |
990 | if (qcam == NULL) | |
1da177e4 | 991 | return -ENODEV; |
d56410e0 | 992 | |
1da177e4 LT |
993 | parport_claim_or_block(qcam->pdev); |
994 | ||
995 | qc_reset(qcam); | |
d56410e0 | 996 | |
1d61aac0 | 997 | if (qc_detect(qcam) == 0) { |
1da177e4 LT |
998 | parport_release(qcam->pdev); |
999 | parport_unregister_device(qcam->pdev); | |
1000 | kfree(qcam); | |
1001 | return -ENODEV; | |
1002 | } | |
1003 | qc_calibrate(qcam); | |
de87897a | 1004 | v4l2_ctrl_handler_setup(&qcam->hdl); |
1da177e4 LT |
1005 | |
1006 | parport_release(qcam->pdev); | |
d56410e0 | 1007 | |
483d67ff | 1008 | v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); |
d56410e0 | 1009 | |
dc60de33 | 1010 | if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { |
1da177e4 LT |
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 | ||
483d67ff | 1021 | static void close_bwqcam(struct qcam *qcam) |
1da177e4 LT |
1022 | { |
1023 | video_unregister_device(&qcam->vdev); | |
5fa1a89d | 1024 | v4l2_ctrl_handler_free(&qcam->hdl); |
1da177e4 LT |
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 */ | |
bb2b4542 | 1044 | for (n = 0; n < MAX_CAMS && parport[n]; n++) { |
1da177e4 LT |
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++) { | |
483d67ff | 1073 | struct qcam *qcam = qcams[i]; |
1da177e4 LT |
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) { | |
1d61aac0 | 1097 | printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n"); |
1da177e4 LT |
1098 | maxpoll = 5000; |
1099 | } | |
d56410e0 | 1100 | |
1da177e4 | 1101 | if (yieldlines < 1) { |
1d61aac0 | 1102 | printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n"); |
1da177e4 LT |
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"); | |
1990d50b | 1113 | MODULE_VERSION("0.0.3"); |