diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 14:12:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:41:37 -0400 |
commit | d1677dc31ac1918f6a91e77ab74d456df01f2bb2 (patch) | |
tree | 643800823d727f3c958ac3ab2f52024752cfd585 /drivers/media/video | |
parent | e5cdf69d36f667d9840ce050abbe4a95c2a6b536 (diff) |
[media] move parallel port/isa video drivers to drivers/media/parport/
We should keep just the I2C drivers under drivers/media/video, and
then rename it to drivers/media/i2c.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/Kconfig | 61 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 4 | ||||
-rw-r--r-- | drivers/media/video/bw-qcam.c | 1113 | ||||
-rw-r--r-- | drivers/media/video/c-qcam.c | 883 | ||||
-rw-r--r-- | drivers/media/video/pms.c | 1152 | ||||
-rw-r--r-- | drivers/media/video/w9966.c | 981 |
6 files changed, 0 insertions, 4194 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d545d939c7d5..f9703a0a7d65 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -606,67 +606,6 @@ config VIDEO_VIVI | |||
606 | In doubt, say N. | 606 | In doubt, say N. |
607 | 607 | ||
608 | # | 608 | # |
609 | # ISA & parallel port drivers configuration | ||
610 | # All devices here are webcam or grabber devices | ||
611 | # | ||
612 | |||
613 | menuconfig V4L_ISA_PARPORT_DRIVERS | ||
614 | bool "V4L ISA and parallel port devices" | ||
615 | depends on ISA || PARPORT | ||
616 | depends on MEDIA_CAMERA_SUPPORT | ||
617 | default n | ||
618 | ---help--- | ||
619 | Say Y here to enable support for these ISA and parallel port drivers. | ||
620 | |||
621 | if V4L_ISA_PARPORT_DRIVERS | ||
622 | |||
623 | config VIDEO_BWQCAM | ||
624 | tristate "Quickcam BW Video For Linux" | ||
625 | depends on PARPORT && VIDEO_V4L2 | ||
626 | help | ||
627 | Say Y have if you the black and white version of the QuickCam | ||
628 | camera. See the next option for the color version. | ||
629 | |||
630 | To compile this driver as a module, choose M here: the | ||
631 | module will be called bw-qcam. | ||
632 | |||
633 | config VIDEO_CQCAM | ||
634 | tristate "QuickCam Colour Video For Linux" | ||
635 | depends on PARPORT && VIDEO_V4L2 | ||
636 | help | ||
637 | This is the video4linux driver for the colour version of the | ||
638 | Connectix QuickCam. If you have one of these cameras, say Y here, | ||
639 | otherwise say N. This driver does not work with the original | ||
640 | monochrome QuickCam, QuickCam VC or QuickClip. It is also available | ||
641 | as a module (c-qcam). | ||
642 | Read <file:Documentation/video4linux/CQcam.txt> for more information. | ||
643 | |||
644 | config VIDEO_PMS | ||
645 | tristate "Mediavision Pro Movie Studio Video For Linux" | ||
646 | depends on ISA && VIDEO_V4L2 | ||
647 | help | ||
648 | Say Y if you have the ISA Mediavision Pro Movie Studio | ||
649 | capture card. | ||
650 | |||
651 | To compile this driver as a module, choose M here: the | ||
652 | module will be called pms. | ||
653 | |||
654 | config VIDEO_W9966 | ||
655 | tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" | ||
656 | depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 | ||
657 | help | ||
658 | Video4linux driver for Winbond's w9966 based Webcams. | ||
659 | Currently tested with the LifeView FlyCam Supra. | ||
660 | If you have one of these cameras, say Y here | ||
661 | otherwise say N. | ||
662 | This driver is also available as a module (w9966). | ||
663 | |||
664 | Check out <file:Documentation/video4linux/w9966.txt> for more | ||
665 | information. | ||
666 | |||
667 | endif # V4L_ISA_PARPORT_DRIVERS | ||
668 | |||
669 | # | ||
670 | # Platform drivers | 609 | # Platform drivers |
671 | # All drivers here are currently for webcam support | 610 | # All drivers here are currently for webcam support |
672 | 611 | ||
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index f212af3ec740..a0c66923fcde 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -87,10 +87,6 @@ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o | |||
87 | 87 | ||
88 | # And now the v4l2 drivers: | 88 | # And now the v4l2 drivers: |
89 | 89 | ||
90 | obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o | ||
91 | obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o | ||
92 | obj-$(CONFIG_VIDEO_W9966) += w9966.o | ||
93 | obj-$(CONFIG_VIDEO_PMS) += pms.o | ||
94 | obj-$(CONFIG_VIDEO_VINO) += vino.o | 90 | obj-$(CONFIG_VIDEO_VINO) += vino.o |
95 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o | 91 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o |
96 | 92 | ||
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c deleted file mode 100644 index 5b75a64b199b..000000000000 --- a/drivers/media/video/bw-qcam.c +++ /dev/null | |||
@@ -1,1113 +0,0 @@ | |||
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"); | ||
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c deleted file mode 100644 index ec51e1f12e82..000000000000 --- a/drivers/media/video/c-qcam.c +++ /dev/null | |||
@@ -1,883 +0,0 @@ | |||
1 | /* | ||
2 | * Video4Linux Colour QuickCam driver | ||
3 | * Copyright 1997-2000 Philip Blundell <philb@gnu.org> | ||
4 | * | ||
5 | * Module parameters: | ||
6 | * | ||
7 | * parport=auto -- probe all parports (default) | ||
8 | * parport=0 -- parport0 becomes qcam1 | ||
9 | * parport=2,0,1 -- parports 2,0,1 are tried in that order | ||
10 | * | ||
11 | * probe=0 -- do no probing, assume camera is present | ||
12 | * probe=1 -- use IEEE-1284 autoprobe data only (default) | ||
13 | * probe=2 -- probe aggressively for cameras | ||
14 | * | ||
15 | * force_rgb=1 -- force data format to RGB (default is BGR) | ||
16 | * | ||
17 | * The parport parameter controls which parports will be scanned. | ||
18 | * Scanning all parports causes some printers to print a garbage page. | ||
19 | * -- March 14, 1999 Billy Donahue <billy@escape.com> | ||
20 | * | ||
21 | * Fixed data format to BGR, added force_rgb parameter. Added missing | ||
22 | * parport_unregister_driver() on module removal. | ||
23 | * -- May 28, 2000 Claudio Matsuoka <claudio@conectiva.com> | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/parport.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/jiffies.h> | ||
38 | #include <linux/videodev2.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | #include <media/v4l2-device.h> | ||
41 | #include <media/v4l2-common.h> | ||
42 | #include <media/v4l2-ioctl.h> | ||
43 | #include <media/v4l2-fh.h> | ||
44 | #include <media/v4l2-ctrls.h> | ||
45 | #include <media/v4l2-event.h> | ||
46 | |||
47 | struct qcam { | ||
48 | struct v4l2_device v4l2_dev; | ||
49 | struct video_device vdev; | ||
50 | struct v4l2_ctrl_handler hdl; | ||
51 | struct pardevice *pdev; | ||
52 | struct parport *pport; | ||
53 | int width, height; | ||
54 | int ccd_width, ccd_height; | ||
55 | int mode; | ||
56 | int contrast, brightness, whitebal; | ||
57 | int top, left; | ||
58 | unsigned int bidirectional; | ||
59 | struct mutex lock; | ||
60 | }; | ||
61 | |||
62 | /* cameras maximum */ | ||
63 | #define MAX_CAMS 4 | ||
64 | |||
65 | /* The three possible QuickCam modes */ | ||
66 | #define QC_MILLIONS 0x18 | ||
67 | #define QC_BILLIONS 0x10 | ||
68 | #define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ | ||
69 | |||
70 | /* The three possible decimations */ | ||
71 | #define QC_DECIMATION_1 0 | ||
72 | #define QC_DECIMATION_2 2 | ||
73 | #define QC_DECIMATION_4 4 | ||
74 | |||
75 | #define BANNER "Colour QuickCam for Video4Linux v0.06" | ||
76 | |||
77 | static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; | ||
78 | static int probe = 2; | ||
79 | static bool force_rgb; | ||
80 | static int video_nr = -1; | ||
81 | |||
82 | /* FIXME: parport=auto would never have worked, surely? --RR */ | ||
83 | MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n" | ||
84 | "probe=<0|1|2> for camera detection method\n" | ||
85 | "force_rgb=<0|1> for RGB data format (default BGR)"); | ||
86 | module_param_array(parport, int, NULL, 0); | ||
87 | module_param(probe, int, 0); | ||
88 | module_param(force_rgb, bool, 0); | ||
89 | module_param(video_nr, int, 0); | ||
90 | |||
91 | static struct qcam *qcams[MAX_CAMS]; | ||
92 | static unsigned int num_cams; | ||
93 | |||
94 | static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) | ||
95 | { | ||
96 | /* note: the QC specs refer to the PCAck pin by voltage, not | ||
97 | software level. PC ports have builtin inverters. */ | ||
98 | parport_frob_control(qcam->pport, 8, i ? 8 : 0); | ||
99 | } | ||
100 | |||
101 | static inline unsigned int qcam_ready1(struct qcam *qcam) | ||
102 | { | ||
103 | return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; | ||
104 | } | ||
105 | |||
106 | static inline unsigned int qcam_ready2(struct qcam *qcam) | ||
107 | { | ||
108 | return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; | ||
109 | } | ||
110 | |||
111 | static unsigned int qcam_await_ready1(struct qcam *qcam, int value) | ||
112 | { | ||
113 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
114 | unsigned long oldjiffies = jiffies; | ||
115 | unsigned int i; | ||
116 | |||
117 | for (oldjiffies = jiffies; | ||
118 | time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) | ||
119 | if (qcam_ready1(qcam) == value) | ||
120 | return 0; | ||
121 | |||
122 | /* If the camera didn't respond within 1/25 second, poll slowly | ||
123 | for a while. */ | ||
124 | for (i = 0; i < 50; i++) { | ||
125 | if (qcam_ready1(qcam) == value) | ||
126 | return 0; | ||
127 | msleep_interruptible(100); | ||
128 | } | ||
129 | |||
130 | /* Probably somebody pulled the plug out. Not much we can do. */ | ||
131 | v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, | ||
132 | parport_read_status(qcam->pport), | ||
133 | parport_read_control(qcam->pport)); | ||
134 | return 1; | ||
135 | } | ||
136 | |||
137 | static unsigned int qcam_await_ready2(struct qcam *qcam, int value) | ||
138 | { | ||
139 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
140 | unsigned long oldjiffies = jiffies; | ||
141 | unsigned int i; | ||
142 | |||
143 | for (oldjiffies = jiffies; | ||
144 | time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) | ||
145 | if (qcam_ready2(qcam) == value) | ||
146 | return 0; | ||
147 | |||
148 | /* If the camera didn't respond within 1/25 second, poll slowly | ||
149 | for a while. */ | ||
150 | for (i = 0; i < 50; i++) { | ||
151 | if (qcam_ready2(qcam) == value) | ||
152 | return 0; | ||
153 | msleep_interruptible(100); | ||
154 | } | ||
155 | |||
156 | /* Probably somebody pulled the plug out. Not much we can do. */ | ||
157 | v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, | ||
158 | parport_read_status(qcam->pport), | ||
159 | parport_read_control(qcam->pport), | ||
160 | parport_read_data(qcam->pport)); | ||
161 | return 1; | ||
162 | } | ||
163 | |||
164 | static int qcam_read_data(struct qcam *qcam) | ||
165 | { | ||
166 | unsigned int idata; | ||
167 | |||
168 | qcam_set_ack(qcam, 0); | ||
169 | if (qcam_await_ready1(qcam, 1)) | ||
170 | return -1; | ||
171 | idata = parport_read_status(qcam->pport) & 0xf0; | ||
172 | qcam_set_ack(qcam, 1); | ||
173 | if (qcam_await_ready1(qcam, 0)) | ||
174 | return -1; | ||
175 | idata |= parport_read_status(qcam->pport) >> 4; | ||
176 | return idata; | ||
177 | } | ||
178 | |||
179 | static int qcam_write_data(struct qcam *qcam, unsigned int data) | ||
180 | { | ||
181 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
182 | unsigned int idata; | ||
183 | |||
184 | parport_write_data(qcam->pport, data); | ||
185 | idata = qcam_read_data(qcam); | ||
186 | if (data != idata) { | ||
187 | v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, | ||
188 | idata); | ||
189 | return 1; | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) | ||
195 | { | ||
196 | if (qcam_write_data(qcam, cmd)) | ||
197 | return -1; | ||
198 | if (qcam_write_data(qcam, data)) | ||
199 | return -1; | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static inline int qcam_get(struct qcam *qcam, unsigned int cmd) | ||
204 | { | ||
205 | if (qcam_write_data(qcam, cmd)) | ||
206 | return -1; | ||
207 | return qcam_read_data(qcam); | ||
208 | } | ||
209 | |||
210 | static int qc_detect(struct qcam *qcam) | ||
211 | { | ||
212 | unsigned int stat, ostat, i, count = 0; | ||
213 | |||
214 | /* The probe routine below is not very reliable. The IEEE-1284 | ||
215 | probe takes precedence. */ | ||
216 | /* XXX Currently parport provides no way to distinguish between | ||
217 | "the IEEE probe was not done" and "the probe was done, but | ||
218 | no device was found". Fix this one day. */ | ||
219 | if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA | ||
220 | && qcam->pport->probe_info[0].model | ||
221 | && !strcmp(qcam->pdev->port->probe_info[0].model, | ||
222 | "Color QuickCam 2.0")) { | ||
223 | printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); | ||
224 | return 1; | ||
225 | } | ||
226 | |||
227 | if (probe < 2) | ||
228 | return 0; | ||
229 | |||
230 | parport_write_control(qcam->pport, 0xc); | ||
231 | |||
232 | /* look for a heartbeat */ | ||
233 | ostat = stat = parport_read_status(qcam->pport); | ||
234 | for (i = 0; i < 250; i++) { | ||
235 | mdelay(1); | ||
236 | stat = parport_read_status(qcam->pport); | ||
237 | if (ostat != stat) { | ||
238 | if (++count >= 3) | ||
239 | return 1; | ||
240 | ostat = stat; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* Reset the camera and try again */ | ||
245 | parport_write_control(qcam->pport, 0xc); | ||
246 | parport_write_control(qcam->pport, 0x8); | ||
247 | mdelay(1); | ||
248 | parport_write_control(qcam->pport, 0xc); | ||
249 | mdelay(1); | ||
250 | count = 0; | ||
251 | |||
252 | ostat = stat = parport_read_status(qcam->pport); | ||
253 | for (i = 0; i < 250; i++) { | ||
254 | mdelay(1); | ||
255 | stat = parport_read_status(qcam->pport); | ||
256 | if (ostat != stat) { | ||
257 | if (++count >= 3) | ||
258 | return 1; | ||
259 | ostat = stat; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /* no (or flatline) camera, give up */ | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static void qc_reset(struct qcam *qcam) | ||
268 | { | ||
269 | parport_write_control(qcam->pport, 0xc); | ||
270 | parport_write_control(qcam->pport, 0x8); | ||
271 | mdelay(1); | ||
272 | parport_write_control(qcam->pport, 0xc); | ||
273 | mdelay(1); | ||
274 | } | ||
275 | |||
276 | /* Reset the QuickCam and program for brightness, contrast, | ||
277 | * white-balance, and resolution. */ | ||
278 | |||
279 | static void qc_setup(struct qcam *qcam) | ||
280 | { | ||
281 | qc_reset(qcam); | ||
282 | |||
283 | /* Set the brightness. */ | ||
284 | qcam_set(qcam, 11, qcam->brightness); | ||
285 | |||
286 | /* Set the height and width. These refer to the actual | ||
287 | CCD area *before* applying the selected decimation. */ | ||
288 | qcam_set(qcam, 17, qcam->ccd_height); | ||
289 | qcam_set(qcam, 19, qcam->ccd_width / 2); | ||
290 | |||
291 | /* Set top and left. */ | ||
292 | qcam_set(qcam, 0xd, qcam->top); | ||
293 | qcam_set(qcam, 0xf, qcam->left); | ||
294 | |||
295 | /* Set contrast and white balance. */ | ||
296 | qcam_set(qcam, 0x19, qcam->contrast); | ||
297 | qcam_set(qcam, 0x1f, qcam->whitebal); | ||
298 | |||
299 | /* Set the speed. */ | ||
300 | qcam_set(qcam, 45, 2); | ||
301 | } | ||
302 | |||
303 | /* Read some bytes from the camera and put them in the buffer. | ||
304 | nbytes should be a multiple of 3, because bidirectional mode gives | ||
305 | us three bytes at a time. */ | ||
306 | |||
307 | static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) | ||
308 | { | ||
309 | unsigned int bytes = 0; | ||
310 | |||
311 | qcam_set_ack(qcam, 0); | ||
312 | if (qcam->bidirectional) { | ||
313 | /* It's a bidirectional port */ | ||
314 | while (bytes < nbytes) { | ||
315 | unsigned int lo1, hi1, lo2, hi2; | ||
316 | unsigned char r, g, b; | ||
317 | |||
318 | if (qcam_await_ready2(qcam, 1)) | ||
319 | return bytes; | ||
320 | lo1 = parport_read_data(qcam->pport) >> 1; | ||
321 | hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; | ||
322 | qcam_set_ack(qcam, 1); | ||
323 | if (qcam_await_ready2(qcam, 0)) | ||
324 | return bytes; | ||
325 | lo2 = parport_read_data(qcam->pport) >> 1; | ||
326 | hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; | ||
327 | qcam_set_ack(qcam, 0); | ||
328 | r = lo1 | ((hi1 & 1) << 7); | ||
329 | g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); | ||
330 | b = lo2 | ((hi2 & 1) << 7); | ||
331 | if (force_rgb) { | ||
332 | buf[bytes++] = r; | ||
333 | buf[bytes++] = g; | ||
334 | buf[bytes++] = b; | ||
335 | } else { | ||
336 | buf[bytes++] = b; | ||
337 | buf[bytes++] = g; | ||
338 | buf[bytes++] = r; | ||
339 | } | ||
340 | } | ||
341 | } else { | ||
342 | /* It's a unidirectional port */ | ||
343 | int i = 0, n = bytes; | ||
344 | unsigned char rgb[3]; | ||
345 | |||
346 | while (bytes < nbytes) { | ||
347 | unsigned int hi, lo; | ||
348 | |||
349 | if (qcam_await_ready1(qcam, 1)) | ||
350 | return bytes; | ||
351 | hi = (parport_read_status(qcam->pport) & 0xf0); | ||
352 | qcam_set_ack(qcam, 1); | ||
353 | if (qcam_await_ready1(qcam, 0)) | ||
354 | return bytes; | ||
355 | lo = (parport_read_status(qcam->pport) & 0xf0); | ||
356 | qcam_set_ack(qcam, 0); | ||
357 | /* flip some bits */ | ||
358 | rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; | ||
359 | if (i >= 2) { | ||
360 | get_fragment: | ||
361 | if (force_rgb) { | ||
362 | buf[n++] = rgb[0]; | ||
363 | buf[n++] = rgb[1]; | ||
364 | buf[n++] = rgb[2]; | ||
365 | } else { | ||
366 | buf[n++] = rgb[2]; | ||
367 | buf[n++] = rgb[1]; | ||
368 | buf[n++] = rgb[0]; | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | if (i) { | ||
373 | i = 0; | ||
374 | goto get_fragment; | ||
375 | } | ||
376 | } | ||
377 | return bytes; | ||
378 | } | ||
379 | |||
380 | #define BUFSZ 150 | ||
381 | |||
382 | static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) | ||
383 | { | ||
384 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
385 | unsigned lines, pixelsperline; | ||
386 | unsigned int is_bi_dir = qcam->bidirectional; | ||
387 | size_t wantlen, outptr = 0; | ||
388 | char tmpbuf[BUFSZ]; | ||
389 | |||
390 | if (!access_ok(VERIFY_WRITE, buf, len)) | ||
391 | return -EFAULT; | ||
392 | |||
393 | /* Wait for camera to become ready */ | ||
394 | for (;;) { | ||
395 | int i = qcam_get(qcam, 41); | ||
396 | |||
397 | if (i == -1) { | ||
398 | qc_setup(qcam); | ||
399 | return -EIO; | ||
400 | } | ||
401 | if ((i & 0x80) == 0) | ||
402 | break; | ||
403 | schedule(); | ||
404 | } | ||
405 | |||
406 | if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) | ||
407 | return -EIO; | ||
408 | |||
409 | lines = qcam->height; | ||
410 | pixelsperline = qcam->width; | ||
411 | |||
412 | if (is_bi_dir) { | ||
413 | /* Turn the port around */ | ||
414 | parport_data_reverse(qcam->pport); | ||
415 | mdelay(3); | ||
416 | qcam_set_ack(qcam, 0); | ||
417 | if (qcam_await_ready1(qcam, 1)) { | ||
418 | qc_setup(qcam); | ||
419 | return -EIO; | ||
420 | } | ||
421 | qcam_set_ack(qcam, 1); | ||
422 | if (qcam_await_ready1(qcam, 0)) { | ||
423 | qc_setup(qcam); | ||
424 | return -EIO; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | wantlen = lines * pixelsperline * 24 / 8; | ||
429 | |||
430 | while (wantlen) { | ||
431 | size_t t, s; | ||
432 | |||
433 | s = (wantlen > BUFSZ) ? BUFSZ : wantlen; | ||
434 | t = qcam_read_bytes(qcam, tmpbuf, s); | ||
435 | if (outptr < len) { | ||
436 | size_t sz = len - outptr; | ||
437 | |||
438 | if (sz > t) | ||
439 | sz = t; | ||
440 | if (__copy_to_user(buf + outptr, tmpbuf, sz)) | ||
441 | break; | ||
442 | outptr += sz; | ||
443 | } | ||
444 | wantlen -= t; | ||
445 | if (t < s) | ||
446 | break; | ||
447 | cond_resched(); | ||
448 | } | ||
449 | |||
450 | len = outptr; | ||
451 | |||
452 | if (wantlen) { | ||
453 | v4l2_err(v4l2_dev, "short read.\n"); | ||
454 | if (is_bi_dir) | ||
455 | parport_data_forward(qcam->pport); | ||
456 | qc_setup(qcam); | ||
457 | return len; | ||
458 | } | ||
459 | |||
460 | if (is_bi_dir) { | ||
461 | int l; | ||
462 | |||
463 | do { | ||
464 | l = qcam_read_bytes(qcam, tmpbuf, 3); | ||
465 | cond_resched(); | ||
466 | } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); | ||
467 | if (force_rgb) { | ||
468 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) | ||
469 | v4l2_err(v4l2_dev, "bad EOF\n"); | ||
470 | } else { | ||
471 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) | ||
472 | v4l2_err(v4l2_dev, "bad EOF\n"); | ||
473 | } | ||
474 | qcam_set_ack(qcam, 0); | ||
475 | if (qcam_await_ready1(qcam, 1)) { | ||
476 | v4l2_err(v4l2_dev, "no ack after EOF\n"); | ||
477 | parport_data_forward(qcam->pport); | ||
478 | qc_setup(qcam); | ||
479 | return len; | ||
480 | } | ||
481 | parport_data_forward(qcam->pport); | ||
482 | mdelay(3); | ||
483 | qcam_set_ack(qcam, 1); | ||
484 | if (qcam_await_ready1(qcam, 0)) { | ||
485 | v4l2_err(v4l2_dev, "no ack to port turnaround\n"); | ||
486 | qc_setup(qcam); | ||
487 | return len; | ||
488 | } | ||
489 | } else { | ||
490 | int l; | ||
491 | |||
492 | do { | ||
493 | l = qcam_read_bytes(qcam, tmpbuf, 1); | ||
494 | cond_resched(); | ||
495 | } while (l && tmpbuf[0] == 0x7e); | ||
496 | l = qcam_read_bytes(qcam, tmpbuf + 1, 2); | ||
497 | if (force_rgb) { | ||
498 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) | ||
499 | v4l2_err(v4l2_dev, "bad EOF\n"); | ||
500 | } else { | ||
501 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) | ||
502 | v4l2_err(v4l2_dev, "bad EOF\n"); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | qcam_write_data(qcam, 0); | ||
507 | return len; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * Video4linux interfacing | ||
512 | */ | ||
513 | |||
514 | static int qcam_querycap(struct file *file, void *priv, | ||
515 | struct v4l2_capability *vcap) | ||
516 | { | ||
517 | struct qcam *qcam = video_drvdata(file); | ||
518 | |||
519 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); | ||
520 | strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); | ||
521 | strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); | ||
522 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
523 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) | ||
528 | { | ||
529 | if (vin->index > 0) | ||
530 | return -EINVAL; | ||
531 | strlcpy(vin->name, "Camera", sizeof(vin->name)); | ||
532 | vin->type = V4L2_INPUT_TYPE_CAMERA; | ||
533 | vin->audioset = 0; | ||
534 | vin->tuner = 0; | ||
535 | vin->std = 0; | ||
536 | vin->status = 0; | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) | ||
541 | { | ||
542 | *inp = 0; | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static int qcam_s_input(struct file *file, void *fh, unsigned int inp) | ||
547 | { | ||
548 | return (inp > 0) ? -EINVAL : 0; | ||
549 | } | ||
550 | |||
551 | static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
552 | { | ||
553 | struct qcam *qcam = video_drvdata(file); | ||
554 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
555 | |||
556 | pix->width = qcam->width; | ||
557 | pix->height = qcam->height; | ||
558 | pix->pixelformat = V4L2_PIX_FMT_RGB24; | ||
559 | pix->field = V4L2_FIELD_NONE; | ||
560 | pix->bytesperline = 3 * qcam->width; | ||
561 | pix->sizeimage = 3 * qcam->width * qcam->height; | ||
562 | /* Just a guess */ | ||
563 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
568 | { | ||
569 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
570 | |||
571 | if (pix->height < 60 || pix->width < 80) { | ||
572 | pix->height = 60; | ||
573 | pix->width = 80; | ||
574 | } else if (pix->height < 120 || pix->width < 160) { | ||
575 | pix->height = 120; | ||
576 | pix->width = 160; | ||
577 | } else { | ||
578 | pix->height = 240; | ||
579 | pix->width = 320; | ||
580 | } | ||
581 | pix->pixelformat = V4L2_PIX_FMT_RGB24; | ||
582 | pix->field = V4L2_FIELD_NONE; | ||
583 | pix->bytesperline = 3 * pix->width; | ||
584 | pix->sizeimage = 3 * pix->width * pix->height; | ||
585 | /* Just a guess */ | ||
586 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
591 | { | ||
592 | struct qcam *qcam = video_drvdata(file); | ||
593 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
594 | int ret = qcam_try_fmt_vid_cap(file, fh, fmt); | ||
595 | |||
596 | if (ret) | ||
597 | return ret; | ||
598 | switch (pix->height) { | ||
599 | case 60: | ||
600 | qcam->mode = QC_DECIMATION_4; | ||
601 | break; | ||
602 | case 120: | ||
603 | qcam->mode = QC_DECIMATION_2; | ||
604 | break; | ||
605 | default: | ||
606 | qcam->mode = QC_DECIMATION_1; | ||
607 | break; | ||
608 | } | ||
609 | |||
610 | mutex_lock(&qcam->lock); | ||
611 | qcam->mode |= QC_MILLIONS; | ||
612 | qcam->height = pix->height; | ||
613 | qcam->width = pix->width; | ||
614 | parport_claim_or_block(qcam->pdev); | ||
615 | qc_setup(qcam); | ||
616 | parport_release(qcam->pdev); | ||
617 | mutex_unlock(&qcam->lock); | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) | ||
622 | { | ||
623 | static struct v4l2_fmtdesc formats[] = { | ||
624 | { 0, 0, 0, | ||
625 | "RGB 8:8:8", V4L2_PIX_FMT_RGB24, | ||
626 | { 0, 0, 0, 0 } | ||
627 | }, | ||
628 | }; | ||
629 | enum v4l2_buf_type type = fmt->type; | ||
630 | |||
631 | if (fmt->index > 0) | ||
632 | return -EINVAL; | ||
633 | |||
634 | *fmt = formats[fmt->index]; | ||
635 | fmt->type = type; | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static ssize_t qcam_read(struct file *file, char __user *buf, | ||
640 | size_t count, loff_t *ppos) | ||
641 | { | ||
642 | struct qcam *qcam = video_drvdata(file); | ||
643 | int len; | ||
644 | |||
645 | mutex_lock(&qcam->lock); | ||
646 | parport_claim_or_block(qcam->pdev); | ||
647 | /* Probably should have a semaphore against multiple users */ | ||
648 | len = qc_capture(qcam, buf, count); | ||
649 | parport_release(qcam->pdev); | ||
650 | mutex_unlock(&qcam->lock); | ||
651 | return len; | ||
652 | } | ||
653 | |||
654 | static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) | ||
655 | { | ||
656 | struct qcam *qcam = | ||
657 | container_of(ctrl->handler, struct qcam, hdl); | ||
658 | int ret = 0; | ||
659 | |||
660 | mutex_lock(&qcam->lock); | ||
661 | switch (ctrl->id) { | ||
662 | case V4L2_CID_BRIGHTNESS: | ||
663 | qcam->brightness = ctrl->val; | ||
664 | break; | ||
665 | case V4L2_CID_CONTRAST: | ||
666 | qcam->contrast = ctrl->val; | ||
667 | break; | ||
668 | case V4L2_CID_GAMMA: | ||
669 | qcam->whitebal = ctrl->val; | ||
670 | break; | ||
671 | default: | ||
672 | ret = -EINVAL; | ||
673 | break; | ||
674 | } | ||
675 | if (ret == 0) { | ||
676 | parport_claim_or_block(qcam->pdev); | ||
677 | qc_setup(qcam); | ||
678 | parport_release(qcam->pdev); | ||
679 | } | ||
680 | mutex_unlock(&qcam->lock); | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static const struct v4l2_file_operations qcam_fops = { | ||
685 | .owner = THIS_MODULE, | ||
686 | .open = v4l2_fh_open, | ||
687 | .release = v4l2_fh_release, | ||
688 | .poll = v4l2_ctrl_poll, | ||
689 | .unlocked_ioctl = video_ioctl2, | ||
690 | .read = qcam_read, | ||
691 | }; | ||
692 | |||
693 | static const struct v4l2_ioctl_ops qcam_ioctl_ops = { | ||
694 | .vidioc_querycap = qcam_querycap, | ||
695 | .vidioc_g_input = qcam_g_input, | ||
696 | .vidioc_s_input = qcam_s_input, | ||
697 | .vidioc_enum_input = qcam_enum_input, | ||
698 | .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, | ||
699 | .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, | ||
700 | .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, | ||
701 | .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, | ||
702 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
703 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
704 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
705 | }; | ||
706 | |||
707 | static const struct v4l2_ctrl_ops qcam_ctrl_ops = { | ||
708 | .s_ctrl = qcam_s_ctrl, | ||
709 | }; | ||
710 | |||
711 | /* Initialize the QuickCam driver control structure. */ | ||
712 | |||
713 | static struct qcam *qcam_init(struct parport *port) | ||
714 | { | ||
715 | struct qcam *qcam; | ||
716 | struct v4l2_device *v4l2_dev; | ||
717 | |||
718 | qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); | ||
719 | if (qcam == NULL) | ||
720 | return NULL; | ||
721 | |||
722 | v4l2_dev = &qcam->v4l2_dev; | ||
723 | strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); | ||
724 | |||
725 | if (v4l2_device_register(NULL, v4l2_dev) < 0) { | ||
726 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
727 | kfree(qcam); | ||
728 | return NULL; | ||
729 | } | ||
730 | |||
731 | v4l2_ctrl_handler_init(&qcam->hdl, 3); | ||
732 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
733 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 240); | ||
734 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
735 | V4L2_CID_CONTRAST, 0, 255, 1, 192); | ||
736 | v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, | ||
737 | V4L2_CID_GAMMA, 0, 255, 1, 128); | ||
738 | if (qcam->hdl.error) { | ||
739 | v4l2_err(v4l2_dev, "couldn't register controls\n"); | ||
740 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
741 | kfree(qcam); | ||
742 | return NULL; | ||
743 | } | ||
744 | |||
745 | qcam->pport = port; | ||
746 | qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, | ||
747 | NULL, 0, NULL); | ||
748 | |||
749 | qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; | ||
750 | |||
751 | if (qcam->pdev == NULL) { | ||
752 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); | ||
753 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
754 | kfree(qcam); | ||
755 | return NULL; | ||
756 | } | ||
757 | |||
758 | strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); | ||
759 | qcam->vdev.v4l2_dev = v4l2_dev; | ||
760 | qcam->vdev.fops = &qcam_fops; | ||
761 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; | ||
762 | qcam->vdev.release = video_device_release_empty; | ||
763 | qcam->vdev.ctrl_handler = &qcam->hdl; | ||
764 | set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags); | ||
765 | video_set_drvdata(&qcam->vdev, qcam); | ||
766 | |||
767 | mutex_init(&qcam->lock); | ||
768 | qcam->width = qcam->ccd_width = 320; | ||
769 | qcam->height = qcam->ccd_height = 240; | ||
770 | qcam->mode = QC_MILLIONS | QC_DECIMATION_1; | ||
771 | qcam->contrast = 192; | ||
772 | qcam->brightness = 240; | ||
773 | qcam->whitebal = 128; | ||
774 | qcam->top = 1; | ||
775 | qcam->left = 14; | ||
776 | return qcam; | ||
777 | } | ||
778 | |||
779 | static int init_cqcam(struct parport *port) | ||
780 | { | ||
781 | struct qcam *qcam; | ||
782 | struct v4l2_device *v4l2_dev; | ||
783 | |||
784 | if (parport[0] != -1) { | ||
785 | /* The user gave specific instructions */ | ||
786 | int i, found = 0; | ||
787 | |||
788 | for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) { | ||
789 | if (parport[0] == port->number) | ||
790 | found = 1; | ||
791 | } | ||
792 | if (!found) | ||
793 | return -ENODEV; | ||
794 | } | ||
795 | |||
796 | if (num_cams == MAX_CAMS) | ||
797 | return -ENOSPC; | ||
798 | |||
799 | qcam = qcam_init(port); | ||
800 | if (qcam == NULL) | ||
801 | return -ENODEV; | ||
802 | |||
803 | v4l2_dev = &qcam->v4l2_dev; | ||
804 | |||
805 | parport_claim_or_block(qcam->pdev); | ||
806 | |||
807 | qc_reset(qcam); | ||
808 | |||
809 | if (probe && qc_detect(qcam) == 0) { | ||
810 | parport_release(qcam->pdev); | ||
811 | parport_unregister_device(qcam->pdev); | ||
812 | kfree(qcam); | ||
813 | return -ENODEV; | ||
814 | } | ||
815 | |||
816 | qc_setup(qcam); | ||
817 | |||
818 | parport_release(qcam->pdev); | ||
819 | |||
820 | if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { | ||
821 | v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", | ||
822 | qcam->pport->name); | ||
823 | parport_unregister_device(qcam->pdev); | ||
824 | kfree(qcam); | ||
825 | return -ENODEV; | ||
826 | } | ||
827 | |||
828 | v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", | ||
829 | video_device_node_name(&qcam->vdev), qcam->pport->name); | ||
830 | |||
831 | qcams[num_cams++] = qcam; | ||
832 | |||
833 | return 0; | ||
834 | } | ||
835 | |||
836 | static void close_cqcam(struct qcam *qcam) | ||
837 | { | ||
838 | video_unregister_device(&qcam->vdev); | ||
839 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
840 | parport_unregister_device(qcam->pdev); | ||
841 | kfree(qcam); | ||
842 | } | ||
843 | |||
844 | static void cq_attach(struct parport *port) | ||
845 | { | ||
846 | init_cqcam(port); | ||
847 | } | ||
848 | |||
849 | static void cq_detach(struct parport *port) | ||
850 | { | ||
851 | /* Write this some day. */ | ||
852 | } | ||
853 | |||
854 | static struct parport_driver cqcam_driver = { | ||
855 | .name = "cqcam", | ||
856 | .attach = cq_attach, | ||
857 | .detach = cq_detach, | ||
858 | }; | ||
859 | |||
860 | static int __init cqcam_init(void) | ||
861 | { | ||
862 | printk(KERN_INFO BANNER "\n"); | ||
863 | |||
864 | return parport_register_driver(&cqcam_driver); | ||
865 | } | ||
866 | |||
867 | static void __exit cqcam_cleanup(void) | ||
868 | { | ||
869 | unsigned int i; | ||
870 | |||
871 | for (i = 0; i < num_cams; i++) | ||
872 | close_cqcam(qcams[i]); | ||
873 | |||
874 | parport_unregister_driver(&cqcam_driver); | ||
875 | } | ||
876 | |||
877 | MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); | ||
878 | MODULE_DESCRIPTION(BANNER); | ||
879 | MODULE_LICENSE("GPL"); | ||
880 | MODULE_VERSION("0.0.4"); | ||
881 | |||
882 | module_init(cqcam_init); | ||
883 | module_exit(cqcam_cleanup); | ||
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c deleted file mode 100644 index 77f9c92186f4..000000000000 --- a/drivers/media/video/pms.c +++ /dev/null | |||
@@ -1,1152 +0,0 @@ | |||
1 | /* | ||
2 | * Media Vision Pro Movie Studio | ||
3 | * or | ||
4 | * "all you need is an I2C bus some RAM and a prayer" | ||
5 | * | ||
6 | * This draws heavily on code | ||
7 | * | ||
8 | * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994 | ||
9 | * Kiefernring 15 | ||
10 | * 14478 Potsdam, Germany | ||
11 | * | ||
12 | * Most of this code is directly derived from his userspace driver. | ||
13 | * His driver works so send any reports to alan@lxorguk.ukuu.org.uk | ||
14 | * unless the userspace driver also doesn't work for you... | ||
15 | * | ||
16 | * Changes: | ||
17 | * 25-11-2009 Hans Verkuil <hverkuil@xs4all.nl> | ||
18 | * - converted to version 2 of the V4L API. | ||
19 | * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> | ||
20 | * - pms_capture: report back -EFAULT | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/uaccess.h> | ||
34 | #include <linux/isa.h> | ||
35 | #include <asm/io.h> | ||
36 | |||
37 | #include <linux/videodev2.h> | ||
38 | #include <media/v4l2-common.h> | ||
39 | #include <media/v4l2-ioctl.h> | ||
40 | #include <media/v4l2-ctrls.h> | ||
41 | #include <media/v4l2-fh.h> | ||
42 | #include <media/v4l2-event.h> | ||
43 | #include <media/v4l2-device.h> | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_VERSION("0.0.5"); | ||
47 | |||
48 | #define MOTOROLA 1 | ||
49 | #define PHILIPS2 2 /* SAA7191 */ | ||
50 | #define PHILIPS1 3 | ||
51 | #define MVVMEMORYWIDTH 0x40 /* 512 bytes */ | ||
52 | |||
53 | struct i2c_info { | ||
54 | u8 slave; | ||
55 | u8 sub; | ||
56 | u8 data; | ||
57 | u8 hits; | ||
58 | }; | ||
59 | |||
60 | struct pms { | ||
61 | struct v4l2_device v4l2_dev; | ||
62 | struct video_device vdev; | ||
63 | struct v4l2_ctrl_handler hdl; | ||
64 | int height; | ||
65 | int width; | ||
66 | int depth; | ||
67 | int input; | ||
68 | struct mutex lock; | ||
69 | int i2c_count; | ||
70 | struct i2c_info i2cinfo[64]; | ||
71 | |||
72 | int decoder; | ||
73 | int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */ | ||
74 | v4l2_std_id std; | ||
75 | int io; | ||
76 | int data; | ||
77 | void __iomem *mem; | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * I/O ports and Shared Memory | ||
82 | */ | ||
83 | |||
84 | static int io_port = 0x250; | ||
85 | module_param(io_port, int, 0); | ||
86 | |||
87 | static int mem_base = 0xc8000; | ||
88 | module_param(mem_base, int, 0); | ||
89 | |||
90 | static int video_nr = -1; | ||
91 | module_param(video_nr, int, 0); | ||
92 | |||
93 | |||
94 | static inline void mvv_write(struct pms *dev, u8 index, u8 value) | ||
95 | { | ||
96 | outw(index | (value << 8), dev->io); | ||
97 | } | ||
98 | |||
99 | static inline u8 mvv_read(struct pms *dev, u8 index) | ||
100 | { | ||
101 | outb(index, dev->io); | ||
102 | return inb(dev->data); | ||
103 | } | ||
104 | |||
105 | static int pms_i2c_stat(struct pms *dev, u8 slave) | ||
106 | { | ||
107 | int counter = 0; | ||
108 | int i; | ||
109 | |||
110 | outb(0x28, dev->io); | ||
111 | |||
112 | while ((inb(dev->data) & 0x01) == 0) | ||
113 | if (counter++ == 256) | ||
114 | break; | ||
115 | |||
116 | while ((inb(dev->data) & 0x01) != 0) | ||
117 | if (counter++ == 256) | ||
118 | break; | ||
119 | |||
120 | outb(slave, dev->io); | ||
121 | |||
122 | counter = 0; | ||
123 | while ((inb(dev->data) & 0x01) == 0) | ||
124 | if (counter++ == 256) | ||
125 | break; | ||
126 | |||
127 | while ((inb(dev->data) & 0x01) != 0) | ||
128 | if (counter++ == 256) | ||
129 | break; | ||
130 | |||
131 | for (i = 0; i < 12; i++) { | ||
132 | char st = inb(dev->data); | ||
133 | |||
134 | if ((st & 2) != 0) | ||
135 | return -1; | ||
136 | if ((st & 1) == 0) | ||
137 | break; | ||
138 | } | ||
139 | outb(0x29, dev->io); | ||
140 | return inb(dev->data); | ||
141 | } | ||
142 | |||
143 | static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data) | ||
144 | { | ||
145 | int skip = 0; | ||
146 | int count; | ||
147 | int i; | ||
148 | |||
149 | for (i = 0; i < dev->i2c_count; i++) { | ||
150 | if ((dev->i2cinfo[i].slave == slave) && | ||
151 | (dev->i2cinfo[i].sub == sub)) { | ||
152 | if (dev->i2cinfo[i].data == data) | ||
153 | skip = 1; | ||
154 | dev->i2cinfo[i].data = data; | ||
155 | i = dev->i2c_count + 1; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | if (i == dev->i2c_count && dev->i2c_count < 64) { | ||
160 | dev->i2cinfo[dev->i2c_count].slave = slave; | ||
161 | dev->i2cinfo[dev->i2c_count].sub = sub; | ||
162 | dev->i2cinfo[dev->i2c_count].data = data; | ||
163 | dev->i2c_count++; | ||
164 | } | ||
165 | |||
166 | if (skip) | ||
167 | return 0; | ||
168 | |||
169 | mvv_write(dev, 0x29, sub); | ||
170 | mvv_write(dev, 0x2A, data); | ||
171 | mvv_write(dev, 0x28, slave); | ||
172 | |||
173 | outb(0x28, dev->io); | ||
174 | |||
175 | count = 0; | ||
176 | while ((inb(dev->data) & 1) == 0) | ||
177 | if (count > 255) | ||
178 | break; | ||
179 | while ((inb(dev->data) & 1) != 0) | ||
180 | if (count > 255) | ||
181 | break; | ||
182 | |||
183 | count = inb(dev->data); | ||
184 | |||
185 | if (count & 2) | ||
186 | return -1; | ||
187 | return count; | ||
188 | } | ||
189 | |||
190 | static int pms_i2c_read(struct pms *dev, int slave, int sub) | ||
191 | { | ||
192 | int i; | ||
193 | |||
194 | for (i = 0; i < dev->i2c_count; i++) { | ||
195 | if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub) | ||
196 | return dev->i2cinfo[i].data; | ||
197 | } | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | |||
202 | static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or) | ||
203 | { | ||
204 | u8 tmp; | ||
205 | |||
206 | tmp = pms_i2c_read(dev, slave, sub); | ||
207 | tmp = (tmp & and) | or; | ||
208 | pms_i2c_write(dev, slave, sub, tmp); | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Control functions | ||
213 | */ | ||
214 | |||
215 | |||
216 | static void pms_videosource(struct pms *dev, short source) | ||
217 | { | ||
218 | switch (dev->decoder) { | ||
219 | case MOTOROLA: | ||
220 | break; | ||
221 | case PHILIPS2: | ||
222 | pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0); | ||
223 | break; | ||
224 | case PHILIPS1: | ||
225 | break; | ||
226 | } | ||
227 | mvv_write(dev, 0x2E, 0x31); | ||
228 | /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30); | ||
229 | But could not make this work correctly. Only Composite input | ||
230 | worked for me. */ | ||
231 | } | ||
232 | |||
233 | static void pms_hue(struct pms *dev, short hue) | ||
234 | { | ||
235 | switch (dev->decoder) { | ||
236 | case MOTOROLA: | ||
237 | pms_i2c_write(dev, 0x8a, 0x00, hue); | ||
238 | break; | ||
239 | case PHILIPS2: | ||
240 | pms_i2c_write(dev, 0x8a, 0x07, hue); | ||
241 | break; | ||
242 | case PHILIPS1: | ||
243 | pms_i2c_write(dev, 0x42, 0x07, hue); | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static void pms_saturation(struct pms *dev, short sat) | ||
249 | { | ||
250 | switch (dev->decoder) { | ||
251 | case MOTOROLA: | ||
252 | pms_i2c_write(dev, 0x8a, 0x00, sat); | ||
253 | break; | ||
254 | case PHILIPS1: | ||
255 | pms_i2c_write(dev, 0x42, 0x12, sat); | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | |||
261 | static void pms_contrast(struct pms *dev, short contrast) | ||
262 | { | ||
263 | switch (dev->decoder) { | ||
264 | case MOTOROLA: | ||
265 | pms_i2c_write(dev, 0x8a, 0x00, contrast); | ||
266 | break; | ||
267 | case PHILIPS1: | ||
268 | pms_i2c_write(dev, 0x42, 0x13, contrast); | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | static void pms_brightness(struct pms *dev, short brightness) | ||
274 | { | ||
275 | switch (dev->decoder) { | ||
276 | case MOTOROLA: | ||
277 | pms_i2c_write(dev, 0x8a, 0x00, brightness); | ||
278 | pms_i2c_write(dev, 0x8a, 0x00, brightness); | ||
279 | pms_i2c_write(dev, 0x8a, 0x00, brightness); | ||
280 | break; | ||
281 | case PHILIPS1: | ||
282 | pms_i2c_write(dev, 0x42, 0x19, brightness); | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | |||
288 | static void pms_format(struct pms *dev, short format) | ||
289 | { | ||
290 | int target; | ||
291 | |||
292 | dev->standard = format; | ||
293 | |||
294 | if (dev->decoder == PHILIPS1) | ||
295 | target = 0x42; | ||
296 | else if (dev->decoder == PHILIPS2) | ||
297 | target = 0x8a; | ||
298 | else | ||
299 | return; | ||
300 | |||
301 | switch (format) { | ||
302 | case 0: /* Auto */ | ||
303 | pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); | ||
304 | pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80); | ||
305 | break; | ||
306 | case 1: /* NTSC */ | ||
307 | pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); | ||
308 | pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40); | ||
309 | break; | ||
310 | case 2: /* PAL */ | ||
311 | pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); | ||
312 | pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); | ||
313 | break; | ||
314 | case 3: /* SECAM */ | ||
315 | pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01); | ||
316 | pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | #ifdef FOR_FUTURE_EXPANSION | ||
322 | |||
323 | /* | ||
324 | * These features of the PMS card are not currently exposes. They | ||
325 | * could become a private v4l ioctl for PMSCONFIG or somesuch if | ||
326 | * people need it. We also don't yet use the PMS interrupt. | ||
327 | */ | ||
328 | |||
329 | static void pms_hstart(struct pms *dev, short start) | ||
330 | { | ||
331 | switch (dev->decoder) { | ||
332 | case PHILIPS1: | ||
333 | pms_i2c_write(dev, 0x8a, 0x05, start); | ||
334 | pms_i2c_write(dev, 0x8a, 0x18, start); | ||
335 | break; | ||
336 | case PHILIPS2: | ||
337 | pms_i2c_write(dev, 0x42, 0x05, start); | ||
338 | pms_i2c_write(dev, 0x42, 0x18, start); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Bandpass filters | ||
345 | */ | ||
346 | |||
347 | static void pms_bandpass(struct pms *dev, short pass) | ||
348 | { | ||
349 | if (dev->decoder == PHILIPS2) | ||
350 | pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4); | ||
351 | else if (dev->decoder == PHILIPS1) | ||
352 | pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4); | ||
353 | } | ||
354 | |||
355 | static void pms_antisnow(struct pms *dev, short snow) | ||
356 | { | ||
357 | if (dev->decoder == PHILIPS2) | ||
358 | pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2); | ||
359 | else if (dev->decoder == PHILIPS1) | ||
360 | pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2); | ||
361 | } | ||
362 | |||
363 | static void pms_sharpness(struct pms *dev, short sharp) | ||
364 | { | ||
365 | if (dev->decoder == PHILIPS2) | ||
366 | pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03); | ||
367 | else if (dev->decoder == PHILIPS1) | ||
368 | pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03); | ||
369 | } | ||
370 | |||
371 | static void pms_chromaagc(struct pms *dev, short agc) | ||
372 | { | ||
373 | if (dev->decoder == PHILIPS2) | ||
374 | pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5); | ||
375 | else if (dev->decoder == PHILIPS1) | ||
376 | pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5); | ||
377 | } | ||
378 | |||
379 | static void pms_vertnoise(struct pms *dev, short noise) | ||
380 | { | ||
381 | if (dev->decoder == PHILIPS2) | ||
382 | pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3); | ||
383 | else if (dev->decoder == PHILIPS1) | ||
384 | pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3); | ||
385 | } | ||
386 | |||
387 | static void pms_forcecolour(struct pms *dev, short colour) | ||
388 | { | ||
389 | if (dev->decoder == PHILIPS2) | ||
390 | pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7); | ||
391 | else if (dev->decoder == PHILIPS1) | ||
392 | pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7); | ||
393 | } | ||
394 | |||
395 | static void pms_antigamma(struct pms *dev, short gamma) | ||
396 | { | ||
397 | if (dev->decoder == PHILIPS2) | ||
398 | pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7); | ||
399 | else if (dev->decoder == PHILIPS1) | ||
400 | pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7); | ||
401 | } | ||
402 | |||
403 | static void pms_prefilter(struct pms *dev, short filter) | ||
404 | { | ||
405 | if (dev->decoder == PHILIPS2) | ||
406 | pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6); | ||
407 | else if (dev->decoder == PHILIPS1) | ||
408 | pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6); | ||
409 | } | ||
410 | |||
411 | static void pms_hfilter(struct pms *dev, short filter) | ||
412 | { | ||
413 | if (dev->decoder == PHILIPS2) | ||
414 | pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5); | ||
415 | else if (dev->decoder == PHILIPS1) | ||
416 | pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5); | ||
417 | } | ||
418 | |||
419 | static void pms_vfilter(struct pms *dev, short filter) | ||
420 | { | ||
421 | if (dev->decoder == PHILIPS2) | ||
422 | pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5); | ||
423 | else if (dev->decoder == PHILIPS1) | ||
424 | pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5); | ||
425 | } | ||
426 | |||
427 | static void pms_killcolour(struct pms *dev, short colour) | ||
428 | { | ||
429 | if (dev->decoder == PHILIPS2) { | ||
430 | pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3); | ||
431 | pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3); | ||
432 | } else if (dev->decoder == PHILIPS1) { | ||
433 | pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3); | ||
434 | pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | static void pms_chromagain(struct pms *dev, short chroma) | ||
439 | { | ||
440 | if (dev->decoder == PHILIPS2) | ||
441 | pms_i2c_write(dev, 0x8a, 0x11, chroma); | ||
442 | else if (dev->decoder == PHILIPS1) | ||
443 | pms_i2c_write(dev, 0x42, 0x11, chroma); | ||
444 | } | ||
445 | |||
446 | |||
447 | static void pms_spacialcompl(struct pms *dev, short data) | ||
448 | { | ||
449 | mvv_write(dev, 0x3b, data); | ||
450 | } | ||
451 | |||
452 | static void pms_spacialcomph(struct pms *dev, short data) | ||
453 | { | ||
454 | mvv_write(dev, 0x3a, data); | ||
455 | } | ||
456 | |||
457 | static void pms_vstart(struct pms *dev, short start) | ||
458 | { | ||
459 | mvv_write(dev, 0x16, start); | ||
460 | mvv_write(dev, 0x17, (start >> 8) & 0x01); | ||
461 | } | ||
462 | |||
463 | #endif | ||
464 | |||
465 | static void pms_secamcross(struct pms *dev, short cross) | ||
466 | { | ||
467 | if (dev->decoder == PHILIPS2) | ||
468 | pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5); | ||
469 | else if (dev->decoder == PHILIPS1) | ||
470 | pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5); | ||
471 | } | ||
472 | |||
473 | |||
474 | static void pms_swsense(struct pms *dev, short sense) | ||
475 | { | ||
476 | if (dev->decoder == PHILIPS2) { | ||
477 | pms_i2c_write(dev, 0x8a, 0x0a, sense); | ||
478 | pms_i2c_write(dev, 0x8a, 0x0b, sense); | ||
479 | } else if (dev->decoder == PHILIPS1) { | ||
480 | pms_i2c_write(dev, 0x42, 0x0a, sense); | ||
481 | pms_i2c_write(dev, 0x42, 0x0b, sense); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | |||
486 | static void pms_framerate(struct pms *dev, short frr) | ||
487 | { | ||
488 | int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25; | ||
489 | |||
490 | if (frr == 0) | ||
491 | return; | ||
492 | fps = fps/frr; | ||
493 | mvv_write(dev, 0x14, 0x80 | fps); | ||
494 | mvv_write(dev, 0x15, 1); | ||
495 | } | ||
496 | |||
497 | static void pms_vert(struct pms *dev, u8 deciden, u8 decinum) | ||
498 | { | ||
499 | mvv_write(dev, 0x1c, deciden); /* Denominator */ | ||
500 | mvv_write(dev, 0x1d, decinum); /* Numerator */ | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Turn 16bit ratios into best small ratio the chipset can grok | ||
505 | */ | ||
506 | |||
507 | static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden) | ||
508 | { | ||
509 | /* Knock it down by / 5 once */ | ||
510 | if (decinum % 5 == 0) { | ||
511 | deciden /= 5; | ||
512 | decinum /= 5; | ||
513 | } | ||
514 | /* | ||
515 | * 3's | ||
516 | */ | ||
517 | while (decinum % 3 == 0 && deciden % 3 == 0) { | ||
518 | deciden /= 3; | ||
519 | decinum /= 3; | ||
520 | } | ||
521 | /* | ||
522 | * 2's | ||
523 | */ | ||
524 | while (decinum % 2 == 0 && deciden % 2 == 0) { | ||
525 | decinum /= 2; | ||
526 | deciden /= 2; | ||
527 | } | ||
528 | /* | ||
529 | * Fudgyify | ||
530 | */ | ||
531 | while (deciden > 32) { | ||
532 | deciden /= 2; | ||
533 | decinum = (decinum + 1) / 2; | ||
534 | } | ||
535 | if (deciden == 32) | ||
536 | deciden--; | ||
537 | pms_vert(dev, deciden, decinum); | ||
538 | } | ||
539 | |||
540 | static void pms_horzdeci(struct pms *dev, short decinum, short deciden) | ||
541 | { | ||
542 | if (decinum <= 512) { | ||
543 | if (decinum % 5 == 0) { | ||
544 | decinum /= 5; | ||
545 | deciden /= 5; | ||
546 | } | ||
547 | } else { | ||
548 | decinum = 512; | ||
549 | deciden = 640; /* 768 would be ideal */ | ||
550 | } | ||
551 | |||
552 | while (((decinum | deciden) & 1) == 0) { | ||
553 | decinum >>= 1; | ||
554 | deciden >>= 1; | ||
555 | } | ||
556 | while (deciden > 32) { | ||
557 | deciden >>= 1; | ||
558 | decinum = (decinum + 1) >> 1; | ||
559 | } | ||
560 | if (deciden == 32) | ||
561 | deciden--; | ||
562 | |||
563 | mvv_write(dev, 0x24, 0x80 | deciden); | ||
564 | mvv_write(dev, 0x25, decinum); | ||
565 | } | ||
566 | |||
567 | static void pms_resolution(struct pms *dev, short width, short height) | ||
568 | { | ||
569 | int fg_height; | ||
570 | |||
571 | fg_height = height; | ||
572 | if (fg_height > 280) | ||
573 | fg_height = 280; | ||
574 | |||
575 | mvv_write(dev, 0x18, fg_height); | ||
576 | mvv_write(dev, 0x19, fg_height >> 8); | ||
577 | |||
578 | if (dev->std & V4L2_STD_525_60) { | ||
579 | mvv_write(dev, 0x1a, 0xfc); | ||
580 | mvv_write(dev, 0x1b, 0x00); | ||
581 | if (height > fg_height) | ||
582 | pms_vertdeci(dev, 240, 240); | ||
583 | else | ||
584 | pms_vertdeci(dev, fg_height, 240); | ||
585 | } else { | ||
586 | mvv_write(dev, 0x1a, 0x1a); | ||
587 | mvv_write(dev, 0x1b, 0x01); | ||
588 | if (fg_height > 256) | ||
589 | pms_vertdeci(dev, 270, 270); | ||
590 | else | ||
591 | pms_vertdeci(dev, fg_height, 270); | ||
592 | } | ||
593 | mvv_write(dev, 0x12, 0); | ||
594 | mvv_write(dev, 0x13, MVVMEMORYWIDTH); | ||
595 | mvv_write(dev, 0x42, 0x00); | ||
596 | mvv_write(dev, 0x43, 0x00); | ||
597 | mvv_write(dev, 0x44, MVVMEMORYWIDTH); | ||
598 | |||
599 | mvv_write(dev, 0x22, width + 8); | ||
600 | mvv_write(dev, 0x23, (width + 8) >> 8); | ||
601 | |||
602 | if (dev->std & V4L2_STD_525_60) | ||
603 | pms_horzdeci(dev, width, 640); | ||
604 | else | ||
605 | pms_horzdeci(dev, width + 8, 768); | ||
606 | |||
607 | mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe); | ||
608 | mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01); | ||
609 | mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd); | ||
610 | mvv_write(dev, 0x32, 0x00); | ||
611 | mvv_write(dev, 0x33, MVVMEMORYWIDTH); | ||
612 | } | ||
613 | |||
614 | |||
615 | /* | ||
616 | * Set Input | ||
617 | */ | ||
618 | |||
619 | static void pms_vcrinput(struct pms *dev, short input) | ||
620 | { | ||
621 | if (dev->decoder == PHILIPS2) | ||
622 | pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7); | ||
623 | else if (dev->decoder == PHILIPS1) | ||
624 | pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7); | ||
625 | } | ||
626 | |||
627 | |||
628 | static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) | ||
629 | { | ||
630 | int y; | ||
631 | int dw = 2 * dev->width; | ||
632 | char tmp[dw + 32]; /* using a temp buffer is faster than direct */ | ||
633 | int cnt = 0; | ||
634 | int len = 0; | ||
635 | unsigned char r8 = 0x5; /* value for reg8 */ | ||
636 | |||
637 | if (rgb555) | ||
638 | r8 |= 0x20; /* else use untranslated rgb = 565 */ | ||
639 | mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */ | ||
640 | |||
641 | /* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */ | ||
642 | |||
643 | for (y = 0; y < dev->height; y++) { | ||
644 | writeb(0, dev->mem); /* synchronisiert neue Zeile */ | ||
645 | |||
646 | /* | ||
647 | * This is in truth a fifo, be very careful as if you | ||
648 | * forgot this odd things will occur 8) | ||
649 | */ | ||
650 | |||
651 | memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */ | ||
652 | cnt -= dev->height; | ||
653 | while (cnt <= 0) { | ||
654 | /* | ||
655 | * Don't copy too far | ||
656 | */ | ||
657 | int dt = dw; | ||
658 | if (dt + len > count) | ||
659 | dt = count - len; | ||
660 | cnt += dev->height; | ||
661 | if (copy_to_user(buf, tmp + 32, dt)) | ||
662 | return len ? len : -EFAULT; | ||
663 | buf += dt; | ||
664 | len += dt; | ||
665 | } | ||
666 | } | ||
667 | return len; | ||
668 | } | ||
669 | |||
670 | |||
671 | /* | ||
672 | * Video4linux interfacing | ||
673 | */ | ||
674 | |||
675 | static int pms_querycap(struct file *file, void *priv, | ||
676 | struct v4l2_capability *vcap) | ||
677 | { | ||
678 | struct pms *dev = video_drvdata(file); | ||
679 | |||
680 | strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver)); | ||
681 | strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card)); | ||
682 | snprintf(vcap->bus_info, sizeof(vcap->bus_info), | ||
683 | "ISA:%s", dev->v4l2_dev.name); | ||
684 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
685 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin) | ||
690 | { | ||
691 | static const char *inputs[4] = { | ||
692 | "Composite", | ||
693 | "S-Video", | ||
694 | "Composite (VCR)", | ||
695 | "S-Video (VCR)" | ||
696 | }; | ||
697 | |||
698 | if (vin->index > 3) | ||
699 | return -EINVAL; | ||
700 | strlcpy(vin->name, inputs[vin->index], sizeof(vin->name)); | ||
701 | vin->type = V4L2_INPUT_TYPE_CAMERA; | ||
702 | vin->audioset = 0; | ||
703 | vin->tuner = 0; | ||
704 | vin->std = V4L2_STD_ALL; | ||
705 | vin->status = 0; | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int pms_g_input(struct file *file, void *fh, unsigned int *inp) | ||
710 | { | ||
711 | struct pms *dev = video_drvdata(file); | ||
712 | |||
713 | *inp = dev->input; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int pms_s_input(struct file *file, void *fh, unsigned int inp) | ||
718 | { | ||
719 | struct pms *dev = video_drvdata(file); | ||
720 | |||
721 | if (inp > 3) | ||
722 | return -EINVAL; | ||
723 | |||
724 | dev->input = inp; | ||
725 | pms_videosource(dev, inp & 1); | ||
726 | pms_vcrinput(dev, inp >> 1); | ||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std) | ||
731 | { | ||
732 | struct pms *dev = video_drvdata(file); | ||
733 | |||
734 | *std = dev->std; | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std) | ||
739 | { | ||
740 | struct pms *dev = video_drvdata(file); | ||
741 | int ret = 0; | ||
742 | |||
743 | dev->std = *std; | ||
744 | if (dev->std & V4L2_STD_NTSC) { | ||
745 | pms_framerate(dev, 30); | ||
746 | pms_secamcross(dev, 0); | ||
747 | pms_format(dev, 1); | ||
748 | } else if (dev->std & V4L2_STD_PAL) { | ||
749 | pms_framerate(dev, 25); | ||
750 | pms_secamcross(dev, 0); | ||
751 | pms_format(dev, 2); | ||
752 | } else if (dev->std & V4L2_STD_SECAM) { | ||
753 | pms_framerate(dev, 25); | ||
754 | pms_secamcross(dev, 1); | ||
755 | pms_format(dev, 2); | ||
756 | } else { | ||
757 | ret = -EINVAL; | ||
758 | } | ||
759 | /* | ||
760 | switch (v->mode) { | ||
761 | case VIDEO_MODE_AUTO: | ||
762 | pms_framerate(dev, 25); | ||
763 | pms_secamcross(dev, 0); | ||
764 | pms_format(dev, 0); | ||
765 | break; | ||
766 | }*/ | ||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | static int pms_s_ctrl(struct v4l2_ctrl *ctrl) | ||
771 | { | ||
772 | struct pms *dev = container_of(ctrl->handler, struct pms, hdl); | ||
773 | int ret = 0; | ||
774 | |||
775 | switch (ctrl->id) { | ||
776 | case V4L2_CID_BRIGHTNESS: | ||
777 | pms_brightness(dev, ctrl->val); | ||
778 | break; | ||
779 | case V4L2_CID_CONTRAST: | ||
780 | pms_contrast(dev, ctrl->val); | ||
781 | break; | ||
782 | case V4L2_CID_SATURATION: | ||
783 | pms_saturation(dev, ctrl->val); | ||
784 | break; | ||
785 | case V4L2_CID_HUE: | ||
786 | pms_hue(dev, ctrl->val); | ||
787 | break; | ||
788 | default: | ||
789 | ret = -EINVAL; | ||
790 | break; | ||
791 | } | ||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
796 | { | ||
797 | struct pms *dev = video_drvdata(file); | ||
798 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
799 | |||
800 | pix->width = dev->width; | ||
801 | pix->height = dev->height; | ||
802 | pix->pixelformat = dev->width == 15 ? | ||
803 | V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565; | ||
804 | pix->field = V4L2_FIELD_NONE; | ||
805 | pix->bytesperline = 2 * dev->width; | ||
806 | pix->sizeimage = 2 * dev->width * dev->height; | ||
807 | /* Just a guess */ | ||
808 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
813 | { | ||
814 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
815 | |||
816 | if (pix->height < 16 || pix->height > 480) | ||
817 | return -EINVAL; | ||
818 | if (pix->width < 16 || pix->width > 640) | ||
819 | return -EINVAL; | ||
820 | if (pix->pixelformat != V4L2_PIX_FMT_RGB555 && | ||
821 | pix->pixelformat != V4L2_PIX_FMT_RGB565) | ||
822 | return -EINVAL; | ||
823 | pix->field = V4L2_FIELD_NONE; | ||
824 | pix->bytesperline = 2 * pix->width; | ||
825 | pix->sizeimage = 2 * pix->width * pix->height; | ||
826 | /* Just a guess */ | ||
827 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
832 | { | ||
833 | struct pms *dev = video_drvdata(file); | ||
834 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
835 | int ret = pms_try_fmt_vid_cap(file, fh, fmt); | ||
836 | |||
837 | if (ret) | ||
838 | return ret; | ||
839 | dev->width = pix->width; | ||
840 | dev->height = pix->height; | ||
841 | dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16; | ||
842 | pms_resolution(dev, dev->width, dev->height); | ||
843 | /* Ok we figured out what to use from our wide choice */ | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) | ||
848 | { | ||
849 | static struct v4l2_fmtdesc formats[] = { | ||
850 | { 0, 0, 0, | ||
851 | "RGB 5:5:5", V4L2_PIX_FMT_RGB555, | ||
852 | { 0, 0, 0, 0 } | ||
853 | }, | ||
854 | { 1, 0, 0, | ||
855 | "RGB 5:6:5", V4L2_PIX_FMT_RGB565, | ||
856 | { 0, 0, 0, 0 } | ||
857 | }, | ||
858 | }; | ||
859 | enum v4l2_buf_type type = fmt->type; | ||
860 | |||
861 | if (fmt->index > 1) | ||
862 | return -EINVAL; | ||
863 | |||
864 | *fmt = formats[fmt->index]; | ||
865 | fmt->type = type; | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static ssize_t pms_read(struct file *file, char __user *buf, | ||
870 | size_t count, loff_t *ppos) | ||
871 | { | ||
872 | struct pms *dev = video_drvdata(file); | ||
873 | int len; | ||
874 | |||
875 | len = pms_capture(dev, buf, (dev->depth == 15), count); | ||
876 | return len; | ||
877 | } | ||
878 | |||
879 | static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait) | ||
880 | { | ||
881 | struct v4l2_fh *fh = file->private_data; | ||
882 | unsigned int res = POLLIN | POLLRDNORM; | ||
883 | |||
884 | if (v4l2_event_pending(fh)) | ||
885 | res |= POLLPRI; | ||
886 | poll_wait(file, &fh->wait, wait); | ||
887 | return res; | ||
888 | } | ||
889 | |||
890 | static const struct v4l2_file_operations pms_fops = { | ||
891 | .owner = THIS_MODULE, | ||
892 | .open = v4l2_fh_open, | ||
893 | .release = v4l2_fh_release, | ||
894 | .poll = pms_poll, | ||
895 | .unlocked_ioctl = video_ioctl2, | ||
896 | .read = pms_read, | ||
897 | }; | ||
898 | |||
899 | static const struct v4l2_ioctl_ops pms_ioctl_ops = { | ||
900 | .vidioc_querycap = pms_querycap, | ||
901 | .vidioc_g_input = pms_g_input, | ||
902 | .vidioc_s_input = pms_s_input, | ||
903 | .vidioc_enum_input = pms_enum_input, | ||
904 | .vidioc_g_std = pms_g_std, | ||
905 | .vidioc_s_std = pms_s_std, | ||
906 | .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap, | ||
907 | .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap, | ||
908 | .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap, | ||
909 | .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap, | ||
910 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
911 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
912 | }; | ||
913 | |||
914 | /* | ||
915 | * Probe for and initialise the Mediavision PMS | ||
916 | */ | ||
917 | |||
918 | static int init_mediavision(struct pms *dev) | ||
919 | { | ||
920 | int idec, decst; | ||
921 | int i; | ||
922 | static const unsigned char i2c_defs[] = { | ||
923 | 0x4c, 0x30, 0x00, 0xe8, | ||
924 | 0xb6, 0xe2, 0x00, 0x00, | ||
925 | 0xff, 0xff, 0x00, 0x00, | ||
926 | 0x00, 0x00, 0x78, 0x98, | ||
927 | 0x00, 0x00, 0x00, 0x00, | ||
928 | 0x34, 0x0a, 0xf4, 0xce, | ||
929 | 0xe4 | ||
930 | }; | ||
931 | |||
932 | dev->mem = ioremap(mem_base, 0x800); | ||
933 | if (!dev->mem) | ||
934 | return -ENOMEM; | ||
935 | |||
936 | if (!request_region(0x9a01, 1, "Mediavision PMS config")) { | ||
937 | printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n"); | ||
938 | iounmap(dev->mem); | ||
939 | return -EBUSY; | ||
940 | } | ||
941 | if (!request_region(dev->io, 3, "Mediavision PMS")) { | ||
942 | printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io); | ||
943 | release_region(0x9a01, 1); | ||
944 | iounmap(dev->mem); | ||
945 | return -EBUSY; | ||
946 | } | ||
947 | outb(0xb8, 0x9a01); /* Unlock */ | ||
948 | outb(dev->io >> 4, 0x9a01); /* Set IO port */ | ||
949 | |||
950 | |||
951 | decst = pms_i2c_stat(dev, 0x43); | ||
952 | |||
953 | if (decst != -1) | ||
954 | idec = 2; | ||
955 | else if (pms_i2c_stat(dev, 0xb9) != -1) | ||
956 | idec = 3; | ||
957 | else if (pms_i2c_stat(dev, 0x8b) != -1) | ||
958 | idec = 1; | ||
959 | else | ||
960 | idec = 0; | ||
961 | |||
962 | printk(KERN_INFO "PMS type is %d\n", idec); | ||
963 | if (idec == 0) { | ||
964 | release_region(dev->io, 3); | ||
965 | release_region(0x9a01, 1); | ||
966 | iounmap(dev->mem); | ||
967 | return -ENODEV; | ||
968 | } | ||
969 | |||
970 | /* | ||
971 | * Ok we have a PMS of some sort | ||
972 | */ | ||
973 | |||
974 | mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */ | ||
975 | |||
976 | /* Ok now load the defaults */ | ||
977 | |||
978 | for (i = 0; i < 0x19; i++) { | ||
979 | if (i2c_defs[i] == 0xff) | ||
980 | pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00); | ||
981 | else | ||
982 | pms_i2c_write(dev, 0x8a, i, i2c_defs[i]); | ||
983 | } | ||
984 | |||
985 | pms_i2c_write(dev, 0xb8, 0x00, 0x12); | ||
986 | pms_i2c_write(dev, 0xb8, 0x04, 0x00); | ||
987 | pms_i2c_write(dev, 0xb8, 0x07, 0x00); | ||
988 | pms_i2c_write(dev, 0xb8, 0x08, 0x00); | ||
989 | pms_i2c_write(dev, 0xb8, 0x09, 0xff); | ||
990 | pms_i2c_write(dev, 0xb8, 0x0a, 0x00); | ||
991 | pms_i2c_write(dev, 0xb8, 0x0b, 0x10); | ||
992 | pms_i2c_write(dev, 0xb8, 0x10, 0x03); | ||
993 | |||
994 | mvv_write(dev, 0x01, 0x00); | ||
995 | mvv_write(dev, 0x05, 0xa0); | ||
996 | mvv_write(dev, 0x08, 0x25); | ||
997 | mvv_write(dev, 0x09, 0x00); | ||
998 | mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH); | ||
999 | |||
1000 | mvv_write(dev, 0x10, 0x02); | ||
1001 | mvv_write(dev, 0x1e, 0x0c); | ||
1002 | mvv_write(dev, 0x1f, 0x03); | ||
1003 | mvv_write(dev, 0x26, 0x06); | ||
1004 | |||
1005 | mvv_write(dev, 0x2b, 0x00); | ||
1006 | mvv_write(dev, 0x2c, 0x20); | ||
1007 | mvv_write(dev, 0x2d, 0x00); | ||
1008 | mvv_write(dev, 0x2f, 0x70); | ||
1009 | mvv_write(dev, 0x32, 0x00); | ||
1010 | mvv_write(dev, 0x33, MVVMEMORYWIDTH); | ||
1011 | mvv_write(dev, 0x34, 0x00); | ||
1012 | mvv_write(dev, 0x35, 0x00); | ||
1013 | mvv_write(dev, 0x3a, 0x80); | ||
1014 | mvv_write(dev, 0x3b, 0x10); | ||
1015 | mvv_write(dev, 0x20, 0x00); | ||
1016 | mvv_write(dev, 0x21, 0x00); | ||
1017 | mvv_write(dev, 0x30, 0x22); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | /* | ||
1022 | * Initialization and module stuff | ||
1023 | */ | ||
1024 | |||
1025 | #ifndef MODULE | ||
1026 | static int enable; | ||
1027 | module_param(enable, int, 0); | ||
1028 | #endif | ||
1029 | |||
1030 | static const struct v4l2_ctrl_ops pms_ctrl_ops = { | ||
1031 | .s_ctrl = pms_s_ctrl, | ||
1032 | }; | ||
1033 | |||
1034 | static int pms_probe(struct device *pdev, unsigned int card) | ||
1035 | { | ||
1036 | struct pms *dev; | ||
1037 | struct v4l2_device *v4l2_dev; | ||
1038 | struct v4l2_ctrl_handler *hdl; | ||
1039 | int res; | ||
1040 | |||
1041 | #ifndef MODULE | ||
1042 | if (!enable) { | ||
1043 | pr_err("PMS: not enabled, use pms.enable=1 to probe\n"); | ||
1044 | return -ENODEV; | ||
1045 | } | ||
1046 | #endif | ||
1047 | |||
1048 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
1049 | if (dev == NULL) | ||
1050 | return -ENOMEM; | ||
1051 | |||
1052 | dev->decoder = PHILIPS2; | ||
1053 | dev->io = io_port; | ||
1054 | dev->data = io_port + 1; | ||
1055 | v4l2_dev = &dev->v4l2_dev; | ||
1056 | hdl = &dev->hdl; | ||
1057 | |||
1058 | res = v4l2_device_register(pdev, v4l2_dev); | ||
1059 | if (res < 0) { | ||
1060 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
1061 | goto free_dev; | ||
1062 | } | ||
1063 | v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n"); | ||
1064 | |||
1065 | res = init_mediavision(dev); | ||
1066 | if (res) { | ||
1067 | v4l2_err(v4l2_dev, "Board not found.\n"); | ||
1068 | goto free_io; | ||
1069 | } | ||
1070 | |||
1071 | v4l2_ctrl_handler_init(hdl, 4); | ||
1072 | v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, | ||
1073 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 139); | ||
1074 | v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, | ||
1075 | V4L2_CID_CONTRAST, 0, 255, 1, 70); | ||
1076 | v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, | ||
1077 | V4L2_CID_SATURATION, 0, 255, 1, 64); | ||
1078 | v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, | ||
1079 | V4L2_CID_HUE, 0, 255, 1, 0); | ||
1080 | if (hdl->error) { | ||
1081 | res = hdl->error; | ||
1082 | goto free_hdl; | ||
1083 | } | ||
1084 | |||
1085 | mutex_init(&dev->lock); | ||
1086 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); | ||
1087 | dev->vdev.v4l2_dev = v4l2_dev; | ||
1088 | dev->vdev.ctrl_handler = hdl; | ||
1089 | dev->vdev.fops = &pms_fops; | ||
1090 | dev->vdev.ioctl_ops = &pms_ioctl_ops; | ||
1091 | dev->vdev.release = video_device_release_empty; | ||
1092 | dev->vdev.lock = &dev->lock; | ||
1093 | dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; | ||
1094 | set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); | ||
1095 | video_set_drvdata(&dev->vdev, dev); | ||
1096 | dev->std = V4L2_STD_NTSC_M; | ||
1097 | dev->height = 240; | ||
1098 | dev->width = 320; | ||
1099 | dev->depth = 16; | ||
1100 | pms_swsense(dev, 75); | ||
1101 | pms_resolution(dev, 320, 240); | ||
1102 | pms_videosource(dev, 0); | ||
1103 | pms_vcrinput(dev, 0); | ||
1104 | v4l2_ctrl_handler_setup(hdl); | ||
1105 | res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); | ||
1106 | if (res >= 0) | ||
1107 | return 0; | ||
1108 | |||
1109 | free_hdl: | ||
1110 | v4l2_ctrl_handler_free(hdl); | ||
1111 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1112 | free_io: | ||
1113 | release_region(dev->io, 3); | ||
1114 | release_region(0x9a01, 1); | ||
1115 | iounmap(dev->mem); | ||
1116 | free_dev: | ||
1117 | kfree(dev); | ||
1118 | return res; | ||
1119 | } | ||
1120 | |||
1121 | static int pms_remove(struct device *pdev, unsigned int card) | ||
1122 | { | ||
1123 | struct pms *dev = dev_get_drvdata(pdev); | ||
1124 | |||
1125 | video_unregister_device(&dev->vdev); | ||
1126 | v4l2_ctrl_handler_free(&dev->hdl); | ||
1127 | release_region(dev->io, 3); | ||
1128 | release_region(0x9a01, 1); | ||
1129 | iounmap(dev->mem); | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | static struct isa_driver pms_driver = { | ||
1134 | .probe = pms_probe, | ||
1135 | .remove = pms_remove, | ||
1136 | .driver = { | ||
1137 | .name = "pms", | ||
1138 | }, | ||
1139 | }; | ||
1140 | |||
1141 | static int __init pms_init(void) | ||
1142 | { | ||
1143 | return isa_register_driver(&pms_driver, 1); | ||
1144 | } | ||
1145 | |||
1146 | static void __exit pms_exit(void) | ||
1147 | { | ||
1148 | isa_unregister_driver(&pms_driver); | ||
1149 | } | ||
1150 | |||
1151 | module_init(pms_init); | ||
1152 | module_exit(pms_exit); | ||
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c deleted file mode 100644 index db2a6003a1c3..000000000000 --- a/drivers/media/video/w9966.c +++ /dev/null | |||
@@ -1,981 +0,0 @@ | |||
1 | /* | ||
2 | Winbond w9966cf Webcam parport driver. | ||
3 | |||
4 | Version 0.33 | ||
5 | |||
6 | Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | /* | ||
23 | Supported devices: | ||
24 | *Lifeview FlyCam Supra (using the Philips saa7111a chip) | ||
25 | |||
26 | Does any other model using the w9966 interface chip exist ? | ||
27 | |||
28 | Todo: | ||
29 | |||
30 | *Add a working EPP mode, since DMA ECP read isn't implemented | ||
31 | in the parport drivers. (That's why it's so sloow) | ||
32 | |||
33 | *Add support for other ccd-control chips than the saa7111 | ||
34 | please send me feedback on what kind of chips you have. | ||
35 | |||
36 | *Add proper probing. I don't know what's wrong with the IEEE1284 | ||
37 | parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) | ||
38 | and nibble read seems to be broken for some peripherals. | ||
39 | |||
40 | *Add probing for onboard SRAM, port directions etc. (if possible) | ||
41 | |||
42 | *Add support for the hardware compressed modes (maybe using v4l2) | ||
43 | |||
44 | *Fix better support for the capture window (no skewed images, v4l | ||
45 | interface to capt. window) | ||
46 | |||
47 | *Probably some bugs that I don't know of | ||
48 | |||
49 | Please support me by sending feedback! | ||
50 | |||
51 | Changes: | ||
52 | |||
53 | Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE | ||
54 | and owner support for newer module locks | ||
55 | */ | ||
56 | |||
57 | #include <linux/module.h> | ||
58 | #include <linux/init.h> | ||
59 | #include <linux/delay.h> | ||
60 | #include <linux/videodev2.h> | ||
61 | #include <linux/slab.h> | ||
62 | #include <media/v4l2-common.h> | ||
63 | #include <media/v4l2-ioctl.h> | ||
64 | #include <media/v4l2-device.h> | ||
65 | #include <media/v4l2-fh.h> | ||
66 | #include <media/v4l2-ctrls.h> | ||
67 | #include <media/v4l2-event.h> | ||
68 | #include <linux/parport.h> | ||
69 | |||
70 | /*#define DEBUG*/ /* Undef me for production */ | ||
71 | |||
72 | #ifdef DEBUG | ||
73 | #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) | ||
74 | #else | ||
75 | #define DPRINTF(x...) | ||
76 | #endif | ||
77 | |||
78 | /* | ||
79 | * Defines, simple typedefs etc. | ||
80 | */ | ||
81 | |||
82 | #define W9966_DRIVERNAME "W9966CF Webcam" | ||
83 | #define W9966_MAXCAMS 4 /* Maximum number of cameras */ | ||
84 | #define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */ | ||
85 | #define W9966_SRAMSIZE 131072 /* 128kb */ | ||
86 | #define W9966_SRAMID 0x02 /* check w9966cf.pdf */ | ||
87 | |||
88 | /* Empirically determined window limits */ | ||
89 | #define W9966_WND_MIN_X 16 | ||
90 | #define W9966_WND_MIN_Y 14 | ||
91 | #define W9966_WND_MAX_X 705 | ||
92 | #define W9966_WND_MAX_Y 253 | ||
93 | #define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) | ||
94 | #define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) | ||
95 | |||
96 | /* Keep track of our current state */ | ||
97 | #define W9966_STATE_PDEV 0x01 | ||
98 | #define W9966_STATE_CLAIMED 0x02 | ||
99 | #define W9966_STATE_VDEV 0x04 | ||
100 | |||
101 | #define W9966_I2C_W_ID 0x48 | ||
102 | #define W9966_I2C_R_ID 0x49 | ||
103 | #define W9966_I2C_R_DATA 0x08 | ||
104 | #define W9966_I2C_R_CLOCK 0x04 | ||
105 | #define W9966_I2C_W_DATA 0x02 | ||
106 | #define W9966_I2C_W_CLOCK 0x01 | ||
107 | |||
108 | struct w9966 { | ||
109 | struct v4l2_device v4l2_dev; | ||
110 | struct v4l2_ctrl_handler hdl; | ||
111 | unsigned char dev_state; | ||
112 | unsigned char i2c_state; | ||
113 | unsigned short ppmode; | ||
114 | struct parport *pport; | ||
115 | struct pardevice *pdev; | ||
116 | struct video_device vdev; | ||
117 | unsigned short width; | ||
118 | unsigned short height; | ||
119 | unsigned char brightness; | ||
120 | signed char contrast; | ||
121 | signed char color; | ||
122 | signed char hue; | ||
123 | struct mutex lock; | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * Module specific properties | ||
128 | */ | ||
129 | |||
130 | MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); | ||
131 | MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); | ||
132 | MODULE_LICENSE("GPL"); | ||
133 | MODULE_VERSION("0.33.1"); | ||
134 | |||
135 | #ifdef MODULE | ||
136 | static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; | ||
137 | #else | ||
138 | static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; | ||
139 | #endif | ||
140 | module_param_array(pardev, charp, NULL, 0); | ||
141 | MODULE_PARM_DESC(pardev, "pardev: where to search for\n" | ||
142 | "\teach camera. 'aggressive' means brute-force search.\n" | ||
143 | "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n" | ||
144 | "\tcam 1 to parport3 and search every parport for cam 2 etc..."); | ||
145 | |||
146 | static int parmode; | ||
147 | module_param(parmode, int, 0); | ||
148 | MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); | ||
149 | |||
150 | static int video_nr = -1; | ||
151 | module_param(video_nr, int, 0); | ||
152 | |||
153 | static struct w9966 w9966_cams[W9966_MAXCAMS]; | ||
154 | |||
155 | /* | ||
156 | * Private function defines | ||
157 | */ | ||
158 | |||
159 | |||
160 | /* Set camera phase flags, so we know what to uninit when terminating */ | ||
161 | static inline void w9966_set_state(struct w9966 *cam, int mask, int val) | ||
162 | { | ||
163 | cam->dev_state = (cam->dev_state & ~mask) ^ val; | ||
164 | } | ||
165 | |||
166 | /* Get camera phase flags */ | ||
167 | static inline int w9966_get_state(struct w9966 *cam, int mask, int val) | ||
168 | { | ||
169 | return ((cam->dev_state & mask) == val); | ||
170 | } | ||
171 | |||
172 | /* Claim parport for ourself */ | ||
173 | static void w9966_pdev_claim(struct w9966 *cam) | ||
174 | { | ||
175 | if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) | ||
176 | return; | ||
177 | parport_claim_or_block(cam->pdev); | ||
178 | w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); | ||
179 | } | ||
180 | |||
181 | /* Release parport for others to use */ | ||
182 | static void w9966_pdev_release(struct w9966 *cam) | ||
183 | { | ||
184 | if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0)) | ||
185 | return; | ||
186 | parport_release(cam->pdev); | ||
187 | w9966_set_state(cam, W9966_STATE_CLAIMED, 0); | ||
188 | } | ||
189 | |||
190 | /* Read register from W9966 interface-chip | ||
191 | Expects a claimed pdev | ||
192 | -1 on error, else register data (byte) */ | ||
193 | static int w9966_read_reg(struct w9966 *cam, int reg) | ||
194 | { | ||
195 | /* ECP, read, regtransfer, REG, REG, REG, REG, REG */ | ||
196 | const unsigned char addr = 0x80 | (reg & 0x1f); | ||
197 | unsigned char val; | ||
198 | |||
199 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) | ||
200 | return -1; | ||
201 | if (parport_write(cam->pport, &addr, 1) != 1) | ||
202 | return -1; | ||
203 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) | ||
204 | return -1; | ||
205 | if (parport_read(cam->pport, &val, 1) != 1) | ||
206 | return -1; | ||
207 | |||
208 | return val; | ||
209 | } | ||
210 | |||
211 | /* Write register to W9966 interface-chip | ||
212 | Expects a claimed pdev | ||
213 | -1 on error */ | ||
214 | static int w9966_write_reg(struct w9966 *cam, int reg, int data) | ||
215 | { | ||
216 | /* ECP, write, regtransfer, REG, REG, REG, REG, REG */ | ||
217 | const unsigned char addr = 0xc0 | (reg & 0x1f); | ||
218 | const unsigned char val = data; | ||
219 | |||
220 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) | ||
221 | return -1; | ||
222 | if (parport_write(cam->pport, &addr, 1) != 1) | ||
223 | return -1; | ||
224 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) | ||
225 | return -1; | ||
226 | if (parport_write(cam->pport, &val, 1) != 1) | ||
227 | return -1; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Ugly and primitive i2c protocol functions | ||
234 | */ | ||
235 | |||
236 | /* Sets the data line on the i2c bus. | ||
237 | Expects a claimed pdev. */ | ||
238 | static void w9966_i2c_setsda(struct w9966 *cam, int state) | ||
239 | { | ||
240 | if (state) | ||
241 | cam->i2c_state |= W9966_I2C_W_DATA; | ||
242 | else | ||
243 | cam->i2c_state &= ~W9966_I2C_W_DATA; | ||
244 | |||
245 | w9966_write_reg(cam, 0x18, cam->i2c_state); | ||
246 | udelay(5); | ||
247 | } | ||
248 | |||
249 | /* Get peripheral clock line | ||
250 | Expects a claimed pdev. */ | ||
251 | static int w9966_i2c_getscl(struct w9966 *cam) | ||
252 | { | ||
253 | const unsigned char state = w9966_read_reg(cam, 0x18); | ||
254 | return ((state & W9966_I2C_R_CLOCK) > 0); | ||
255 | } | ||
256 | |||
257 | /* Sets the clock line on the i2c bus. | ||
258 | Expects a claimed pdev. -1 on error */ | ||
259 | static int w9966_i2c_setscl(struct w9966 *cam, int state) | ||
260 | { | ||
261 | unsigned long timeout; | ||
262 | |||
263 | if (state) | ||
264 | cam->i2c_state |= W9966_I2C_W_CLOCK; | ||
265 | else | ||
266 | cam->i2c_state &= ~W9966_I2C_W_CLOCK; | ||
267 | |||
268 | w9966_write_reg(cam, 0x18, cam->i2c_state); | ||
269 | udelay(5); | ||
270 | |||
271 | /* we go to high, we also expect the peripheral to ack. */ | ||
272 | if (state) { | ||
273 | timeout = jiffies + 100; | ||
274 | while (!w9966_i2c_getscl(cam)) { | ||
275 | if (time_after(jiffies, timeout)) | ||
276 | return -1; | ||
277 | } | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | #if 0 | ||
283 | /* Get peripheral data line | ||
284 | Expects a claimed pdev. */ | ||
285 | static int w9966_i2c_getsda(struct w9966 *cam) | ||
286 | { | ||
287 | const unsigned char state = w9966_read_reg(cam, 0x18); | ||
288 | return ((state & W9966_I2C_R_DATA) > 0); | ||
289 | } | ||
290 | #endif | ||
291 | |||
292 | /* Write a byte with ack to the i2c bus. | ||
293 | Expects a claimed pdev. -1 on error */ | ||
294 | static int w9966_i2c_wbyte(struct w9966 *cam, int data) | ||
295 | { | ||
296 | int i; | ||
297 | |||
298 | for (i = 7; i >= 0; i--) { | ||
299 | w9966_i2c_setsda(cam, (data >> i) & 0x01); | ||
300 | |||
301 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
302 | return -1; | ||
303 | w9966_i2c_setscl(cam, 0); | ||
304 | } | ||
305 | |||
306 | w9966_i2c_setsda(cam, 1); | ||
307 | |||
308 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
309 | return -1; | ||
310 | w9966_i2c_setscl(cam, 0); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* Read a data byte with ack from the i2c-bus | ||
316 | Expects a claimed pdev. -1 on error */ | ||
317 | #if 0 | ||
318 | static int w9966_i2c_rbyte(struct w9966 *cam) | ||
319 | { | ||
320 | unsigned char data = 0x00; | ||
321 | int i; | ||
322 | |||
323 | w9966_i2c_setsda(cam, 1); | ||
324 | |||
325 | for (i = 0; i < 8; i++) { | ||
326 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
327 | return -1; | ||
328 | data = data << 1; | ||
329 | if (w9966_i2c_getsda(cam)) | ||
330 | data |= 0x01; | ||
331 | |||
332 | w9966_i2c_setscl(cam, 0); | ||
333 | } | ||
334 | return data; | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | /* Read a register from the i2c device. | ||
339 | Expects claimed pdev. -1 on error */ | ||
340 | #if 0 | ||
341 | static int w9966_read_reg_i2c(struct w9966 *cam, int reg) | ||
342 | { | ||
343 | int data; | ||
344 | |||
345 | w9966_i2c_setsda(cam, 0); | ||
346 | w9966_i2c_setscl(cam, 0); | ||
347 | |||
348 | if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || | ||
349 | w9966_i2c_wbyte(cam, reg) == -1) | ||
350 | return -1; | ||
351 | |||
352 | w9966_i2c_setsda(cam, 1); | ||
353 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
354 | return -1; | ||
355 | w9966_i2c_setsda(cam, 0); | ||
356 | w9966_i2c_setscl(cam, 0); | ||
357 | |||
358 | if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1) | ||
359 | return -1; | ||
360 | data = w9966_i2c_rbyte(cam); | ||
361 | if (data == -1) | ||
362 | return -1; | ||
363 | |||
364 | w9966_i2c_setsda(cam, 0); | ||
365 | |||
366 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
367 | return -1; | ||
368 | w9966_i2c_setsda(cam, 1); | ||
369 | |||
370 | return data; | ||
371 | } | ||
372 | #endif | ||
373 | |||
374 | /* Write a register to the i2c device. | ||
375 | Expects claimed pdev. -1 on error */ | ||
376 | static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data) | ||
377 | { | ||
378 | w9966_i2c_setsda(cam, 0); | ||
379 | w9966_i2c_setscl(cam, 0); | ||
380 | |||
381 | if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || | ||
382 | w9966_i2c_wbyte(cam, reg) == -1 || | ||
383 | w9966_i2c_wbyte(cam, data) == -1) | ||
384 | return -1; | ||
385 | |||
386 | w9966_i2c_setsda(cam, 0); | ||
387 | if (w9966_i2c_setscl(cam, 1) == -1) | ||
388 | return -1; | ||
389 | |||
390 | w9966_i2c_setsda(cam, 1); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | /* Find a good length for capture window (used both for W and H) | ||
396 | A bit ugly but pretty functional. The capture length | ||
397 | have to match the downscale */ | ||
398 | static int w9966_findlen(int near, int size, int maxlen) | ||
399 | { | ||
400 | int bestlen = size; | ||
401 | int besterr = abs(near - bestlen); | ||
402 | int len; | ||
403 | |||
404 | for (len = size + 1; len < maxlen; len++) { | ||
405 | int err; | ||
406 | if (((64 * size) % len) != 0) | ||
407 | continue; | ||
408 | |||
409 | err = abs(near - len); | ||
410 | |||
411 | /* Only continue as long as we keep getting better values */ | ||
412 | if (err > besterr) | ||
413 | break; | ||
414 | |||
415 | besterr = err; | ||
416 | bestlen = len; | ||
417 | } | ||
418 | |||
419 | return bestlen; | ||
420 | } | ||
421 | |||
422 | /* Modify capture window (if necessary) | ||
423 | and calculate downscaling | ||
424 | Return -1 on error */ | ||
425 | static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor) | ||
426 | { | ||
427 | int maxlen = max - min; | ||
428 | int len = *end - *beg + 1; | ||
429 | int newlen = w9966_findlen(len, size, maxlen); | ||
430 | int err = newlen - len; | ||
431 | |||
432 | /* Check for bad format */ | ||
433 | if (newlen > maxlen || newlen < size) | ||
434 | return -1; | ||
435 | |||
436 | /* Set factor (6 bit fixed) */ | ||
437 | *factor = (64 * size) / newlen; | ||
438 | if (*factor == 64) | ||
439 | *factor = 0x00; /* downscale is disabled */ | ||
440 | else | ||
441 | *factor |= 0x80; /* set downscale-enable bit */ | ||
442 | |||
443 | /* Modify old beginning and end */ | ||
444 | *beg -= err / 2; | ||
445 | *end += err - (err / 2); | ||
446 | |||
447 | /* Move window if outside borders */ | ||
448 | if (*beg < min) { | ||
449 | *end += min - *beg; | ||
450 | *beg += min - *beg; | ||
451 | } | ||
452 | if (*end > max) { | ||
453 | *beg -= *end - max; | ||
454 | *end -= *end - max; | ||
455 | } | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /* Setup the cameras capture window etc. | ||
461 | Expects a claimed pdev | ||
462 | return -1 on error */ | ||
463 | static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h) | ||
464 | { | ||
465 | unsigned int i; | ||
466 | unsigned int enh_s, enh_e; | ||
467 | unsigned char scale_x, scale_y; | ||
468 | unsigned char regs[0x1c]; | ||
469 | unsigned char saa7111_regs[] = { | ||
470 | 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, | ||
471 | 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, | ||
472 | 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
473 | 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 | ||
474 | }; | ||
475 | |||
476 | |||
477 | if (w * h * 2 > W9966_SRAMSIZE) { | ||
478 | DPRINTF("capture window exceeds SRAM size!.\n"); | ||
479 | w = 200; h = 160; /* Pick default values */ | ||
480 | } | ||
481 | |||
482 | w &= ~0x1; | ||
483 | if (w < 2) | ||
484 | w = 2; | ||
485 | if (h < 1) | ||
486 | h = 1; | ||
487 | if (w > W9966_WND_MAX_W) | ||
488 | w = W9966_WND_MAX_W; | ||
489 | if (h > W9966_WND_MAX_H) | ||
490 | h = W9966_WND_MAX_H; | ||
491 | |||
492 | cam->width = w; | ||
493 | cam->height = h; | ||
494 | |||
495 | enh_s = 0; | ||
496 | enh_e = w * h * 2; | ||
497 | |||
498 | /* Modify capture window if necessary and calculate downscaling */ | ||
499 | if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || | ||
500 | w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0) | ||
501 | return -1; | ||
502 | |||
503 | DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", | ||
504 | w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80); | ||
505 | |||
506 | /* Setup registers */ | ||
507 | regs[0x00] = 0x00; /* Set normal operation */ | ||
508 | regs[0x01] = 0x18; /* Capture mode */ | ||
509 | regs[0x02] = scale_y; /* V-scaling */ | ||
510 | regs[0x03] = scale_x; /* H-scaling */ | ||
511 | |||
512 | /* Capture window */ | ||
513 | regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */ | ||
514 | regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */ | ||
515 | regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */ | ||
516 | regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */ | ||
517 | regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */ | ||
518 | regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */ | ||
519 | regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */ | ||
520 | |||
521 | regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */ | ||
522 | |||
523 | /* Enhancement layer */ | ||
524 | regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */ | ||
525 | regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */ | ||
526 | regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */ | ||
527 | regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */ | ||
528 | regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */ | ||
529 | regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */ | ||
530 | |||
531 | /* Misc */ | ||
532 | regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */ | ||
533 | regs[0x17] = 0x00; /* ??? */ | ||
534 | regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */ | ||
535 | regs[0x19] = 0xff; /* I/O port direction control */ | ||
536 | regs[0x1a] = 0xff; /* I/O port data register */ | ||
537 | regs[0x1b] = 0x10; /* ??? */ | ||
538 | |||
539 | /* SAA7111 chip settings */ | ||
540 | saa7111_regs[0x0a] = cam->brightness; | ||
541 | saa7111_regs[0x0b] = cam->contrast; | ||
542 | saa7111_regs[0x0c] = cam->color; | ||
543 | saa7111_regs[0x0d] = cam->hue; | ||
544 | |||
545 | /* Reset (ECP-fifo & serial-bus) */ | ||
546 | if (w9966_write_reg(cam, 0x00, 0x03) == -1) | ||
547 | return -1; | ||
548 | |||
549 | /* Write regs to w9966cf chip */ | ||
550 | for (i = 0; i < 0x1c; i++) | ||
551 | if (w9966_write_reg(cam, i, regs[i]) == -1) | ||
552 | return -1; | ||
553 | |||
554 | /* Write regs to saa7111 chip */ | ||
555 | for (i = 0; i < 0x20; i++) | ||
556 | if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1) | ||
557 | return -1; | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | /* | ||
563 | * Video4linux interfacing | ||
564 | */ | ||
565 | |||
566 | static int cam_querycap(struct file *file, void *priv, | ||
567 | struct v4l2_capability *vcap) | ||
568 | { | ||
569 | struct w9966 *cam = video_drvdata(file); | ||
570 | |||
571 | strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver)); | ||
572 | strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card)); | ||
573 | strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); | ||
574 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
575 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) | ||
580 | { | ||
581 | if (vin->index > 0) | ||
582 | return -EINVAL; | ||
583 | strlcpy(vin->name, "Camera", sizeof(vin->name)); | ||
584 | vin->type = V4L2_INPUT_TYPE_CAMERA; | ||
585 | vin->audioset = 0; | ||
586 | vin->tuner = 0; | ||
587 | vin->std = 0; | ||
588 | vin->status = 0; | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int cam_g_input(struct file *file, void *fh, unsigned int *inp) | ||
593 | { | ||
594 | *inp = 0; | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int cam_s_input(struct file *file, void *fh, unsigned int inp) | ||
599 | { | ||
600 | return (inp > 0) ? -EINVAL : 0; | ||
601 | } | ||
602 | |||
603 | static int cam_s_ctrl(struct v4l2_ctrl *ctrl) | ||
604 | { | ||
605 | struct w9966 *cam = | ||
606 | container_of(ctrl->handler, struct w9966, hdl); | ||
607 | int ret = 0; | ||
608 | |||
609 | mutex_lock(&cam->lock); | ||
610 | switch (ctrl->id) { | ||
611 | case V4L2_CID_BRIGHTNESS: | ||
612 | cam->brightness = ctrl->val; | ||
613 | break; | ||
614 | case V4L2_CID_CONTRAST: | ||
615 | cam->contrast = ctrl->val; | ||
616 | break; | ||
617 | case V4L2_CID_SATURATION: | ||
618 | cam->color = ctrl->val; | ||
619 | break; | ||
620 | case V4L2_CID_HUE: | ||
621 | cam->hue = ctrl->val; | ||
622 | break; | ||
623 | default: | ||
624 | ret = -EINVAL; | ||
625 | break; | ||
626 | } | ||
627 | |||
628 | if (ret == 0) { | ||
629 | w9966_pdev_claim(cam); | ||
630 | |||
631 | if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 || | ||
632 | w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 || | ||
633 | w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 || | ||
634 | w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) { | ||
635 | ret = -EIO; | ||
636 | } | ||
637 | |||
638 | w9966_pdev_release(cam); | ||
639 | } | ||
640 | mutex_unlock(&cam->lock); | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
645 | { | ||
646 | struct w9966 *cam = video_drvdata(file); | ||
647 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
648 | |||
649 | pix->width = cam->width; | ||
650 | pix->height = cam->height; | ||
651 | pix->pixelformat = V4L2_PIX_FMT_YUYV; | ||
652 | pix->field = V4L2_FIELD_NONE; | ||
653 | pix->bytesperline = 2 * cam->width; | ||
654 | pix->sizeimage = 2 * cam->width * cam->height; | ||
655 | /* Just a guess */ | ||
656 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
661 | { | ||
662 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
663 | |||
664 | if (pix->width < 2) | ||
665 | pix->width = 2; | ||
666 | if (pix->height < 1) | ||
667 | pix->height = 1; | ||
668 | if (pix->width > W9966_WND_MAX_W) | ||
669 | pix->width = W9966_WND_MAX_W; | ||
670 | if (pix->height > W9966_WND_MAX_H) | ||
671 | pix->height = W9966_WND_MAX_H; | ||
672 | pix->pixelformat = V4L2_PIX_FMT_YUYV; | ||
673 | pix->field = V4L2_FIELD_NONE; | ||
674 | pix->bytesperline = 2 * pix->width; | ||
675 | pix->sizeimage = 2 * pix->width * pix->height; | ||
676 | /* Just a guess */ | ||
677 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) | ||
682 | { | ||
683 | struct w9966 *cam = video_drvdata(file); | ||
684 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
685 | int ret = cam_try_fmt_vid_cap(file, fh, fmt); | ||
686 | |||
687 | if (ret) | ||
688 | return ret; | ||
689 | |||
690 | mutex_lock(&cam->lock); | ||
691 | /* Update camera regs */ | ||
692 | w9966_pdev_claim(cam); | ||
693 | ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height); | ||
694 | w9966_pdev_release(cam); | ||
695 | mutex_unlock(&cam->lock); | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) | ||
700 | { | ||
701 | static struct v4l2_fmtdesc formats[] = { | ||
702 | { 0, 0, 0, | ||
703 | "YUV 4:2:2", V4L2_PIX_FMT_YUYV, | ||
704 | { 0, 0, 0, 0 } | ||
705 | }, | ||
706 | }; | ||
707 | enum v4l2_buf_type type = fmt->type; | ||
708 | |||
709 | if (fmt->index > 0) | ||
710 | return -EINVAL; | ||
711 | |||
712 | *fmt = formats[fmt->index]; | ||
713 | fmt->type = type; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /* Capture data */ | ||
718 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, | ||
719 | size_t count, loff_t *ppos) | ||
720 | { | ||
721 | struct w9966 *cam = video_drvdata(file); | ||
722 | unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */ | ||
723 | unsigned char __user *dest = (unsigned char __user *)buf; | ||
724 | unsigned long dleft = count; | ||
725 | unsigned char *tbuf; | ||
726 | |||
727 | /* Why would anyone want more than this?? */ | ||
728 | if (count > cam->width * cam->height * 2) | ||
729 | return -EINVAL; | ||
730 | |||
731 | mutex_lock(&cam->lock); | ||
732 | w9966_pdev_claim(cam); | ||
733 | w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */ | ||
734 | w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */ | ||
735 | w9966_write_reg(cam, 0x01, 0x98); /* Enable capture */ | ||
736 | |||
737 | /* write special capture-addr and negotiate into data transfer */ | ||
738 | if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) || | ||
739 | (parport_write(cam->pport, &addr, 1) != 1) || | ||
740 | (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) { | ||
741 | w9966_pdev_release(cam); | ||
742 | mutex_unlock(&cam->lock); | ||
743 | return -EFAULT; | ||
744 | } | ||
745 | |||
746 | tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); | ||
747 | if (tbuf == NULL) { | ||
748 | count = -ENOMEM; | ||
749 | goto out; | ||
750 | } | ||
751 | |||
752 | while (dleft > 0) { | ||
753 | unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; | ||
754 | |||
755 | if (parport_read(cam->pport, tbuf, tsize) < tsize) { | ||
756 | count = -EFAULT; | ||
757 | goto out; | ||
758 | } | ||
759 | if (copy_to_user(dest, tbuf, tsize) != 0) { | ||
760 | count = -EFAULT; | ||
761 | goto out; | ||
762 | } | ||
763 | dest += tsize; | ||
764 | dleft -= tsize; | ||
765 | } | ||
766 | |||
767 | w9966_write_reg(cam, 0x01, 0x18); /* Disable capture */ | ||
768 | |||
769 | out: | ||
770 | kfree(tbuf); | ||
771 | w9966_pdev_release(cam); | ||
772 | mutex_unlock(&cam->lock); | ||
773 | |||
774 | return count; | ||
775 | } | ||
776 | |||
777 | static const struct v4l2_file_operations w9966_fops = { | ||
778 | .owner = THIS_MODULE, | ||
779 | .open = v4l2_fh_open, | ||
780 | .release = v4l2_fh_release, | ||
781 | .poll = v4l2_ctrl_poll, | ||
782 | .unlocked_ioctl = video_ioctl2, | ||
783 | .read = w9966_v4l_read, | ||
784 | }; | ||
785 | |||
786 | static const struct v4l2_ioctl_ops w9966_ioctl_ops = { | ||
787 | .vidioc_querycap = cam_querycap, | ||
788 | .vidioc_g_input = cam_g_input, | ||
789 | .vidioc_s_input = cam_s_input, | ||
790 | .vidioc_enum_input = cam_enum_input, | ||
791 | .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap, | ||
792 | .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap, | ||
793 | .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap, | ||
794 | .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap, | ||
795 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
796 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
797 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
798 | }; | ||
799 | |||
800 | static const struct v4l2_ctrl_ops cam_ctrl_ops = { | ||
801 | .s_ctrl = cam_s_ctrl, | ||
802 | }; | ||
803 | |||
804 | |||
805 | /* Initialize camera device. Setup all internal flags, set a | ||
806 | default video mode, setup ccd-chip, register v4l device etc.. | ||
807 | Also used for 'probing' of hardware. | ||
808 | -1 on error */ | ||
809 | static int w9966_init(struct w9966 *cam, struct parport *port) | ||
810 | { | ||
811 | struct v4l2_device *v4l2_dev = &cam->v4l2_dev; | ||
812 | |||
813 | if (cam->dev_state != 0) | ||
814 | return -1; | ||
815 | |||
816 | strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name)); | ||
817 | |||
818 | if (v4l2_device_register(NULL, v4l2_dev) < 0) { | ||
819 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
820 | return -1; | ||
821 | } | ||
822 | |||
823 | v4l2_ctrl_handler_init(&cam->hdl, 4); | ||
824 | v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, | ||
825 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
826 | v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, | ||
827 | V4L2_CID_CONTRAST, -64, 64, 1, 64); | ||
828 | v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, | ||
829 | V4L2_CID_SATURATION, -64, 64, 1, 64); | ||
830 | v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, | ||
831 | V4L2_CID_HUE, -128, 127, 1, 0); | ||
832 | if (cam->hdl.error) { | ||
833 | v4l2_err(v4l2_dev, "couldn't register controls\n"); | ||
834 | return -1; | ||
835 | } | ||
836 | cam->pport = port; | ||
837 | cam->brightness = 128; | ||
838 | cam->contrast = 64; | ||
839 | cam->color = 64; | ||
840 | cam->hue = 0; | ||
841 | |||
842 | /* Select requested transfer mode */ | ||
843 | switch (parmode) { | ||
844 | default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */ | ||
845 | case 0: | ||
846 | if (port->modes & PARPORT_MODE_ECP) | ||
847 | cam->ppmode = IEEE1284_MODE_ECP; | ||
848 | else if (port->modes & PARPORT_MODE_EPP) | ||
849 | cam->ppmode = IEEE1284_MODE_EPP; | ||
850 | else | ||
851 | cam->ppmode = IEEE1284_MODE_ECP; | ||
852 | break; | ||
853 | case 1: /* hw- or sw-ecp */ | ||
854 | cam->ppmode = IEEE1284_MODE_ECP; | ||
855 | break; | ||
856 | case 2: /* hw- or sw-epp */ | ||
857 | cam->ppmode = IEEE1284_MODE_EPP; | ||
858 | break; | ||
859 | } | ||
860 | |||
861 | /* Tell the parport driver that we exists */ | ||
862 | cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); | ||
863 | if (cam->pdev == NULL) { | ||
864 | DPRINTF("parport_register_device() failed\n"); | ||
865 | return -1; | ||
866 | } | ||
867 | w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); | ||
868 | |||
869 | w9966_pdev_claim(cam); | ||
870 | |||
871 | /* Setup a default capture mode */ | ||
872 | if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { | ||
873 | DPRINTF("w9966_setup() failed.\n"); | ||
874 | return -1; | ||
875 | } | ||
876 | |||
877 | w9966_pdev_release(cam); | ||
878 | |||
879 | /* Fill in the video_device struct and register us to v4l */ | ||
880 | strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name)); | ||
881 | cam->vdev.v4l2_dev = v4l2_dev; | ||
882 | cam->vdev.fops = &w9966_fops; | ||
883 | cam->vdev.ioctl_ops = &w9966_ioctl_ops; | ||
884 | cam->vdev.release = video_device_release_empty; | ||
885 | cam->vdev.ctrl_handler = &cam->hdl; | ||
886 | set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags); | ||
887 | video_set_drvdata(&cam->vdev, cam); | ||
888 | |||
889 | mutex_init(&cam->lock); | ||
890 | |||
891 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) | ||
892 | return -1; | ||
893 | |||
894 | w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); | ||
895 | |||
896 | /* All ok */ | ||
897 | v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n", | ||
898 | cam->pport->name); | ||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | |||
903 | /* Terminate everything gracefully */ | ||
904 | static void w9966_term(struct w9966 *cam) | ||
905 | { | ||
906 | /* Unregister from v4l */ | ||
907 | if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { | ||
908 | video_unregister_device(&cam->vdev); | ||
909 | w9966_set_state(cam, W9966_STATE_VDEV, 0); | ||
910 | } | ||
911 | |||
912 | v4l2_ctrl_handler_free(&cam->hdl); | ||
913 | |||
914 | /* Terminate from IEEE1284 mode and release pdev block */ | ||
915 | if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { | ||
916 | w9966_pdev_claim(cam); | ||
917 | parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); | ||
918 | w9966_pdev_release(cam); | ||
919 | } | ||
920 | |||
921 | /* Unregister from parport */ | ||
922 | if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { | ||
923 | parport_unregister_device(cam->pdev); | ||
924 | w9966_set_state(cam, W9966_STATE_PDEV, 0); | ||
925 | } | ||
926 | memset(cam, 0, sizeof(*cam)); | ||
927 | } | ||
928 | |||
929 | |||
930 | /* Called once for every parport on init */ | ||
931 | static void w9966_attach(struct parport *port) | ||
932 | { | ||
933 | int i; | ||
934 | |||
935 | for (i = 0; i < W9966_MAXCAMS; i++) { | ||
936 | if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */ | ||
937 | continue; | ||
938 | if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) { | ||
939 | if (w9966_init(&w9966_cams[i], port) != 0) | ||
940 | w9966_term(&w9966_cams[i]); | ||
941 | break; /* return */ | ||
942 | } | ||
943 | } | ||
944 | } | ||
945 | |||
946 | /* Called once for every parport on termination */ | ||
947 | static void w9966_detach(struct parport *port) | ||
948 | { | ||
949 | int i; | ||
950 | |||
951 | for (i = 0; i < W9966_MAXCAMS; i++) | ||
952 | if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) | ||
953 | w9966_term(&w9966_cams[i]); | ||
954 | } | ||
955 | |||
956 | |||
957 | static struct parport_driver w9966_ppd = { | ||
958 | .name = W9966_DRIVERNAME, | ||
959 | .attach = w9966_attach, | ||
960 | .detach = w9966_detach, | ||
961 | }; | ||
962 | |||
963 | /* Module entry point */ | ||
964 | static int __init w9966_mod_init(void) | ||
965 | { | ||
966 | int i; | ||
967 | |||
968 | for (i = 0; i < W9966_MAXCAMS; i++) | ||
969 | w9966_cams[i].dev_state = 0; | ||
970 | |||
971 | return parport_register_driver(&w9966_ppd); | ||
972 | } | ||
973 | |||
974 | /* Module cleanup */ | ||
975 | static void __exit w9966_mod_term(void) | ||
976 | { | ||
977 | parport_unregister_driver(&w9966_ppd); | ||
978 | } | ||
979 | |||
980 | module_init(w9966_mod_init); | ||
981 | module_exit(w9966_mod_term); | ||