aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pms.c')
-rw-r--r--drivers/media/video/pms.c1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
new file mode 100644
index 00000000000..e753b5e4d2c
--- /dev/null
+++ b/drivers/media/video/pms.c
@@ -0,0 +1,1144 @@
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/ioport.h>
30#include <linux/init.h>
31#include <linux/mutex.h>
32#include <linux/uaccess.h>
33#include <asm/io.h>
34
35#include <linux/videodev2.h>
36#include <media/v4l2-common.h>
37#include <media/v4l2-ioctl.h>
38#include <media/v4l2-device.h>
39
40MODULE_LICENSE("GPL");
41MODULE_VERSION("0.0.4");
42
43#define MOTOROLA 1
44#define PHILIPS2 2 /* SAA7191 */
45#define PHILIPS1 3
46#define MVVMEMORYWIDTH 0x40 /* 512 bytes */
47
48struct i2c_info {
49 u8 slave;
50 u8 sub;
51 u8 data;
52 u8 hits;
53};
54
55struct pms {
56 struct v4l2_device v4l2_dev;
57 struct video_device vdev;
58 int height;
59 int width;
60 int depth;
61 int input;
62 s32 brightness, saturation, hue, contrast;
63 struct mutex lock;
64 int i2c_count;
65 struct i2c_info i2cinfo[64];
66
67 int decoder;
68 int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
69 v4l2_std_id std;
70 int io;
71 int data;
72 void __iomem *mem;
73};
74
75static struct pms pms_card;
76
77/*
78 * I/O ports and Shared Memory
79 */
80
81static int io_port = 0x250;
82module_param(io_port, int, 0);
83
84static int mem_base = 0xc8000;
85module_param(mem_base, int, 0);
86
87static int video_nr = -1;
88module_param(video_nr, int, 0);
89
90
91static inline void mvv_write(struct pms *dev, u8 index, u8 value)
92{
93 outw(index | (value << 8), dev->io);
94}
95
96static inline u8 mvv_read(struct pms *dev, u8 index)
97{
98 outb(index, dev->io);
99 return inb(dev->data);
100}
101
102static int pms_i2c_stat(struct pms *dev, u8 slave)
103{
104 int counter = 0;
105 int i;
106
107 outb(0x28, dev->io);
108
109 while ((inb(dev->data) & 0x01) == 0)
110 if (counter++ == 256)
111 break;
112
113 while ((inb(dev->data) & 0x01) != 0)
114 if (counter++ == 256)
115 break;
116
117 outb(slave, dev->io);
118
119 counter = 0;
120 while ((inb(dev->data) & 0x01) == 0)
121 if (counter++ == 256)
122 break;
123
124 while ((inb(dev->data) & 0x01) != 0)
125 if (counter++ == 256)
126 break;
127
128 for (i = 0; i < 12; i++) {
129 char st = inb(dev->data);
130
131 if ((st & 2) != 0)
132 return -1;
133 if ((st & 1) == 0)
134 break;
135 }
136 outb(0x29, dev->io);
137 return inb(dev->data);
138}
139
140static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data)
141{
142 int skip = 0;
143 int count;
144 int i;
145
146 for (i = 0; i < dev->i2c_count; i++) {
147 if ((dev->i2cinfo[i].slave == slave) &&
148 (dev->i2cinfo[i].sub == sub)) {
149 if (dev->i2cinfo[i].data == data)
150 skip = 1;
151 dev->i2cinfo[i].data = data;
152 i = dev->i2c_count + 1;
153 }
154 }
155
156 if (i == dev->i2c_count && dev->i2c_count < 64) {
157 dev->i2cinfo[dev->i2c_count].slave = slave;
158 dev->i2cinfo[dev->i2c_count].sub = sub;
159 dev->i2cinfo[dev->i2c_count].data = data;
160 dev->i2c_count++;
161 }
162
163 if (skip)
164 return 0;
165
166 mvv_write(dev, 0x29, sub);
167 mvv_write(dev, 0x2A, data);
168 mvv_write(dev, 0x28, slave);
169
170 outb(0x28, dev->io);
171
172 count = 0;
173 while ((inb(dev->data) & 1) == 0)
174 if (count > 255)
175 break;
176 while ((inb(dev->data) & 1) != 0)
177 if (count > 255)
178 break;
179
180 count = inb(dev->data);
181
182 if (count & 2)
183 return -1;
184 return count;
185}
186
187static int pms_i2c_read(struct pms *dev, int slave, int sub)
188{
189 int i;
190
191 for (i = 0; i < dev->i2c_count; i++) {
192 if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub)
193 return dev->i2cinfo[i].data;
194 }
195 return 0;
196}
197
198
199static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or)
200{
201 u8 tmp;
202
203 tmp = pms_i2c_read(dev, slave, sub);
204 tmp = (tmp & and) | or;
205 pms_i2c_write(dev, slave, sub, tmp);
206}
207
208/*
209 * Control functions
210 */
211
212
213static void pms_videosource(struct pms *dev, short source)
214{
215 switch (dev->decoder) {
216 case MOTOROLA:
217 break;
218 case PHILIPS2:
219 pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0);
220 break;
221 case PHILIPS1:
222 break;
223 }
224 mvv_write(dev, 0x2E, 0x31);
225 /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
226 But could not make this work correctly. Only Composite input
227 worked for me. */
228}
229
230static void pms_hue(struct pms *dev, short hue)
231{
232 switch (dev->decoder) {
233 case MOTOROLA:
234 pms_i2c_write(dev, 0x8a, 0x00, hue);
235 break;
236 case PHILIPS2:
237 pms_i2c_write(dev, 0x8a, 0x07, hue);
238 break;
239 case PHILIPS1:
240 pms_i2c_write(dev, 0x42, 0x07, hue);
241 break;
242 }
243}
244
245static void pms_saturation(struct pms *dev, short sat)
246{
247 switch (dev->decoder) {
248 case MOTOROLA:
249 pms_i2c_write(dev, 0x8a, 0x00, sat);
250 break;
251 case PHILIPS1:
252 pms_i2c_write(dev, 0x42, 0x12, sat);
253 break;
254 }
255}
256
257
258static void pms_contrast(struct pms *dev, short contrast)
259{
260 switch (dev->decoder) {
261 case MOTOROLA:
262 pms_i2c_write(dev, 0x8a, 0x00, contrast);
263 break;
264 case PHILIPS1:
265 pms_i2c_write(dev, 0x42, 0x13, contrast);
266 break;
267 }
268}
269
270static void pms_brightness(struct pms *dev, short brightness)
271{
272 switch (dev->decoder) {
273 case MOTOROLA:
274 pms_i2c_write(dev, 0x8a, 0x00, brightness);
275 pms_i2c_write(dev, 0x8a, 0x00, brightness);
276 pms_i2c_write(dev, 0x8a, 0x00, brightness);
277 break;
278 case PHILIPS1:
279 pms_i2c_write(dev, 0x42, 0x19, brightness);
280 break;
281 }
282}
283
284
285static void pms_format(struct pms *dev, short format)
286{
287 int target;
288
289 dev->standard = format;
290
291 if (dev->decoder == PHILIPS1)
292 target = 0x42;
293 else if (dev->decoder == PHILIPS2)
294 target = 0x8a;
295 else
296 return;
297
298 switch (format) {
299 case 0: /* Auto */
300 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
301 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80);
302 break;
303 case 1: /* NTSC */
304 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
305 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40);
306 break;
307 case 2: /* PAL */
308 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
309 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
310 break;
311 case 3: /* SECAM */
312 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01);
313 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
314 break;
315 }
316}
317
318#ifdef FOR_FUTURE_EXPANSION
319
320/*
321 * These features of the PMS card are not currently exposes. They
322 * could become a private v4l ioctl for PMSCONFIG or somesuch if
323 * people need it. We also don't yet use the PMS interrupt.
324 */
325
326static void pms_hstart(struct pms *dev, short start)
327{
328 switch (dev->decoder) {
329 case PHILIPS1:
330 pms_i2c_write(dev, 0x8a, 0x05, start);
331 pms_i2c_write(dev, 0x8a, 0x18, start);
332 break;
333 case PHILIPS2:
334 pms_i2c_write(dev, 0x42, 0x05, start);
335 pms_i2c_write(dev, 0x42, 0x18, start);
336 break;
337 }
338}
339
340/*
341 * Bandpass filters
342 */
343
344static void pms_bandpass(struct pms *dev, short pass)
345{
346 if (dev->decoder == PHILIPS2)
347 pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4);
348 else if (dev->decoder == PHILIPS1)
349 pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4);
350}
351
352static void pms_antisnow(struct pms *dev, short snow)
353{
354 if (dev->decoder == PHILIPS2)
355 pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2);
356 else if (dev->decoder == PHILIPS1)
357 pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2);
358}
359
360static void pms_sharpness(struct pms *dev, short sharp)
361{
362 if (dev->decoder == PHILIPS2)
363 pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03);
364 else if (dev->decoder == PHILIPS1)
365 pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03);
366}
367
368static void pms_chromaagc(struct pms *dev, short agc)
369{
370 if (dev->decoder == PHILIPS2)
371 pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5);
372 else if (dev->decoder == PHILIPS1)
373 pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5);
374}
375
376static void pms_vertnoise(struct pms *dev, short noise)
377{
378 if (dev->decoder == PHILIPS2)
379 pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3);
380 else if (dev->decoder == PHILIPS1)
381 pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3);
382}
383
384static void pms_forcecolour(struct pms *dev, short colour)
385{
386 if (dev->decoder == PHILIPS2)
387 pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7);
388 else if (dev->decoder == PHILIPS1)
389 pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7);
390}
391
392static void pms_antigamma(struct pms *dev, short gamma)
393{
394 if (dev->decoder == PHILIPS2)
395 pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7);
396 else if (dev->decoder == PHILIPS1)
397 pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7);
398}
399
400static void pms_prefilter(struct pms *dev, short filter)
401{
402 if (dev->decoder == PHILIPS2)
403 pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6);
404 else if (dev->decoder == PHILIPS1)
405 pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6);
406}
407
408static void pms_hfilter(struct pms *dev, short filter)
409{
410 if (dev->decoder == PHILIPS2)
411 pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5);
412 else if (dev->decoder == PHILIPS1)
413 pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5);
414}
415
416static void pms_vfilter(struct pms *dev, short filter)
417{
418 if (dev->decoder == PHILIPS2)
419 pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5);
420 else if (dev->decoder == PHILIPS1)
421 pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5);
422}
423
424static void pms_killcolour(struct pms *dev, short colour)
425{
426 if (dev->decoder == PHILIPS2) {
427 pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3);
428 pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3);
429 } else if (dev->decoder == PHILIPS1) {
430 pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3);
431 pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3);
432 }
433}
434
435static void pms_chromagain(struct pms *dev, short chroma)
436{
437 if (dev->decoder == PHILIPS2)
438 pms_i2c_write(dev, 0x8a, 0x11, chroma);
439 else if (dev->decoder == PHILIPS1)
440 pms_i2c_write(dev, 0x42, 0x11, chroma);
441}
442
443
444static void pms_spacialcompl(struct pms *dev, short data)
445{
446 mvv_write(dev, 0x3b, data);
447}
448
449static void pms_spacialcomph(struct pms *dev, short data)
450{
451 mvv_write(dev, 0x3a, data);
452}
453
454static void pms_vstart(struct pms *dev, short start)
455{
456 mvv_write(dev, 0x16, start);
457 mvv_write(dev, 0x17, (start >> 8) & 0x01);
458}
459
460#endif
461
462static void pms_secamcross(struct pms *dev, short cross)
463{
464 if (dev->decoder == PHILIPS2)
465 pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5);
466 else if (dev->decoder == PHILIPS1)
467 pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5);
468}
469
470
471static void pms_swsense(struct pms *dev, short sense)
472{
473 if (dev->decoder == PHILIPS2) {
474 pms_i2c_write(dev, 0x8a, 0x0a, sense);
475 pms_i2c_write(dev, 0x8a, 0x0b, sense);
476 } else if (dev->decoder == PHILIPS1) {
477 pms_i2c_write(dev, 0x42, 0x0a, sense);
478 pms_i2c_write(dev, 0x42, 0x0b, sense);
479 }
480}
481
482
483static void pms_framerate(struct pms *dev, short frr)
484{
485 int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25;
486
487 if (frr == 0)
488 return;
489 fps = fps/frr;
490 mvv_write(dev, 0x14, 0x80 | fps);
491 mvv_write(dev, 0x15, 1);
492}
493
494static void pms_vert(struct pms *dev, u8 deciden, u8 decinum)
495{
496 mvv_write(dev, 0x1c, deciden); /* Denominator */
497 mvv_write(dev, 0x1d, decinum); /* Numerator */
498}
499
500/*
501 * Turn 16bit ratios into best small ratio the chipset can grok
502 */
503
504static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden)
505{
506 /* Knock it down by / 5 once */
507 if (decinum % 5 == 0) {
508 deciden /= 5;
509 decinum /= 5;
510 }
511 /*
512 * 3's
513 */
514 while (decinum % 3 == 0 && deciden % 3 == 0) {
515 deciden /= 3;
516 decinum /= 3;
517 }
518 /*
519 * 2's
520 */
521 while (decinum % 2 == 0 && deciden % 2 == 0) {
522 decinum /= 2;
523 deciden /= 2;
524 }
525 /*
526 * Fudgyify
527 */
528 while (deciden > 32) {
529 deciden /= 2;
530 decinum = (decinum + 1) / 2;
531 }
532 if (deciden == 32)
533 deciden--;
534 pms_vert(dev, deciden, decinum);
535}
536
537static void pms_horzdeci(struct pms *dev, short decinum, short deciden)
538{
539 if (decinum <= 512) {
540 if (decinum % 5 == 0) {
541 decinum /= 5;
542 deciden /= 5;
543 }
544 } else {
545 decinum = 512;
546 deciden = 640; /* 768 would be ideal */
547 }
548
549 while (((decinum | deciden) & 1) == 0) {
550 decinum >>= 1;
551 deciden >>= 1;
552 }
553 while (deciden > 32) {
554 deciden >>= 1;
555 decinum = (decinum + 1) >> 1;
556 }
557 if (deciden == 32)
558 deciden--;
559
560 mvv_write(dev, 0x24, 0x80 | deciden);
561 mvv_write(dev, 0x25, decinum);
562}
563
564static void pms_resolution(struct pms *dev, short width, short height)
565{
566 int fg_height;
567
568 fg_height = height;
569 if (fg_height > 280)
570 fg_height = 280;
571
572 mvv_write(dev, 0x18, fg_height);
573 mvv_write(dev, 0x19, fg_height >> 8);
574
575 if (dev->std & V4L2_STD_525_60) {
576 mvv_write(dev, 0x1a, 0xfc);
577 mvv_write(dev, 0x1b, 0x00);
578 if (height > fg_height)
579 pms_vertdeci(dev, 240, 240);
580 else
581 pms_vertdeci(dev, fg_height, 240);
582 } else {
583 mvv_write(dev, 0x1a, 0x1a);
584 mvv_write(dev, 0x1b, 0x01);
585 if (fg_height > 256)
586 pms_vertdeci(dev, 270, 270);
587 else
588 pms_vertdeci(dev, fg_height, 270);
589 }
590 mvv_write(dev, 0x12, 0);
591 mvv_write(dev, 0x13, MVVMEMORYWIDTH);
592 mvv_write(dev, 0x42, 0x00);
593 mvv_write(dev, 0x43, 0x00);
594 mvv_write(dev, 0x44, MVVMEMORYWIDTH);
595
596 mvv_write(dev, 0x22, width + 8);
597 mvv_write(dev, 0x23, (width + 8) >> 8);
598
599 if (dev->std & V4L2_STD_525_60)
600 pms_horzdeci(dev, width, 640);
601 else
602 pms_horzdeci(dev, width + 8, 768);
603
604 mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe);
605 mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01);
606 mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd);
607 mvv_write(dev, 0x32, 0x00);
608 mvv_write(dev, 0x33, MVVMEMORYWIDTH);
609}
610
611
612/*
613 * Set Input
614 */
615
616static void pms_vcrinput(struct pms *dev, short input)
617{
618 if (dev->decoder == PHILIPS2)
619 pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7);
620 else if (dev->decoder == PHILIPS1)
621 pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7);
622}
623
624
625static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
626{
627 int y;
628 int dw = 2 * dev->width;
629 char tmp[dw + 32]; /* using a temp buffer is faster than direct */
630 int cnt = 0;
631 int len = 0;
632 unsigned char r8 = 0x5; /* value for reg8 */
633
634 if (rgb555)
635 r8 |= 0x20; /* else use untranslated rgb = 565 */
636 mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
637
638/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
639
640 for (y = 0; y < dev->height; y++) {
641 writeb(0, dev->mem); /* synchronisiert neue Zeile */
642
643 /*
644 * This is in truth a fifo, be very careful as if you
645 * forgot this odd things will occur 8)
646 */
647
648 memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */
649 cnt -= dev->height;
650 while (cnt <= 0) {
651 /*
652 * Don't copy too far
653 */
654 int dt = dw;
655 if (dt + len > count)
656 dt = count - len;
657 cnt += dev->height;
658 if (copy_to_user(buf, tmp + 32, dt))
659 return len ? len : -EFAULT;
660 buf += dt;
661 len += dt;
662 }
663 }
664 return len;
665}
666
667
668/*
669 * Video4linux interfacing
670 */
671
672static int pms_querycap(struct file *file, void *priv,
673 struct v4l2_capability *vcap)
674{
675 struct pms *dev = video_drvdata(file);
676
677 strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
678 strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
679 strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
680 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
681 return 0;
682}
683
684static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
685{
686 static const char *inputs[4] = {
687 "Composite",
688 "S-Video",
689 "Composite (VCR)",
690 "S-Video (VCR)"
691 };
692
693 if (vin->index > 3)
694 return -EINVAL;
695 strlcpy(vin->name, inputs[vin->index], sizeof(vin->name));
696 vin->type = V4L2_INPUT_TYPE_CAMERA;
697 vin->audioset = 0;
698 vin->tuner = 0;
699 vin->std = V4L2_STD_ALL;
700 vin->status = 0;
701 return 0;
702}
703
704static int pms_g_input(struct file *file, void *fh, unsigned int *inp)
705{
706 struct pms *dev = video_drvdata(file);
707
708 *inp = dev->input;
709 return 0;
710}
711
712static int pms_s_input(struct file *file, void *fh, unsigned int inp)
713{
714 struct pms *dev = video_drvdata(file);
715
716 if (inp > 3)
717 return -EINVAL;
718
719 mutex_lock(&dev->lock);
720 dev->input = inp;
721 pms_videosource(dev, inp & 1);
722 pms_vcrinput(dev, inp >> 1);
723 mutex_unlock(&dev->lock);
724 return 0;
725}
726
727static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
728{
729 struct pms *dev = video_drvdata(file);
730
731 *std = dev->std;
732 return 0;
733}
734
735static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
736{
737 struct pms *dev = video_drvdata(file);
738 int ret = 0;
739
740 dev->std = *std;
741 mutex_lock(&dev->lock);
742 if (dev->std & V4L2_STD_NTSC) {
743 pms_framerate(dev, 30);
744 pms_secamcross(dev, 0);
745 pms_format(dev, 1);
746 } else if (dev->std & V4L2_STD_PAL) {
747 pms_framerate(dev, 25);
748 pms_secamcross(dev, 0);
749 pms_format(dev, 2);
750 } else if (dev->std & V4L2_STD_SECAM) {
751 pms_framerate(dev, 25);
752 pms_secamcross(dev, 1);
753 pms_format(dev, 2);
754 } else {
755 ret = -EINVAL;
756 }
757 /*
758 switch (v->mode) {
759 case VIDEO_MODE_AUTO:
760 pms_framerate(dev, 25);
761 pms_secamcross(dev, 0);
762 pms_format(dev, 0);
763 break;
764 }*/
765 mutex_unlock(&dev->lock);
766 return 0;
767}
768
769static int pms_queryctrl(struct file *file, void *priv,
770 struct v4l2_queryctrl *qc)
771{
772 switch (qc->id) {
773 case V4L2_CID_BRIGHTNESS:
774 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139);
775 case V4L2_CID_CONTRAST:
776 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70);
777 case V4L2_CID_SATURATION:
778 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64);
779 case V4L2_CID_HUE:
780 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
781 }
782 return -EINVAL;
783}
784
785static int pms_g_ctrl(struct file *file, void *priv,
786 struct v4l2_control *ctrl)
787{
788 struct pms *dev = video_drvdata(file);
789 int ret = 0;
790
791 switch (ctrl->id) {
792 case V4L2_CID_BRIGHTNESS:
793 ctrl->value = dev->brightness;
794 break;
795 case V4L2_CID_CONTRAST:
796 ctrl->value = dev->contrast;
797 break;
798 case V4L2_CID_SATURATION:
799 ctrl->value = dev->saturation;
800 break;
801 case V4L2_CID_HUE:
802 ctrl->value = dev->hue;
803 break;
804 default:
805 ret = -EINVAL;
806 break;
807 }
808 return ret;
809}
810
811static int pms_s_ctrl(struct file *file, void *priv,
812 struct v4l2_control *ctrl)
813{
814 struct pms *dev = video_drvdata(file);
815 int ret = 0;
816
817 mutex_lock(&dev->lock);
818 switch (ctrl->id) {
819 case V4L2_CID_BRIGHTNESS:
820 dev->brightness = ctrl->value;
821 pms_brightness(dev, dev->brightness);
822 break;
823 case V4L2_CID_CONTRAST:
824 dev->contrast = ctrl->value;
825 pms_contrast(dev, dev->contrast);
826 break;
827 case V4L2_CID_SATURATION:
828 dev->saturation = ctrl->value;
829 pms_saturation(dev, dev->saturation);
830 break;
831 case V4L2_CID_HUE:
832 dev->hue = ctrl->value;
833 pms_hue(dev, dev->hue);
834 break;
835 default:
836 ret = -EINVAL;
837 break;
838 }
839 mutex_unlock(&dev->lock);
840 return ret;
841}
842
843static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
844{
845 struct pms *dev = video_drvdata(file);
846 struct v4l2_pix_format *pix = &fmt->fmt.pix;
847
848 pix->width = dev->width;
849 pix->height = dev->height;
850 pix->pixelformat = dev->width == 15 ?
851 V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565;
852 pix->field = V4L2_FIELD_NONE;
853 pix->bytesperline = 2 * dev->width;
854 pix->sizeimage = 2 * dev->width * dev->height;
855 /* Just a guess */
856 pix->colorspace = V4L2_COLORSPACE_SRGB;
857 return 0;
858}
859
860static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
861{
862 struct v4l2_pix_format *pix = &fmt->fmt.pix;
863
864 if (pix->height < 16 || pix->height > 480)
865 return -EINVAL;
866 if (pix->width < 16 || pix->width > 640)
867 return -EINVAL;
868 if (pix->pixelformat != V4L2_PIX_FMT_RGB555 &&
869 pix->pixelformat != V4L2_PIX_FMT_RGB565)
870 return -EINVAL;
871 pix->field = V4L2_FIELD_NONE;
872 pix->bytesperline = 2 * pix->width;
873 pix->sizeimage = 2 * pix->width * pix->height;
874 /* Just a guess */
875 pix->colorspace = V4L2_COLORSPACE_SRGB;
876 return 0;
877}
878
879static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
880{
881 struct pms *dev = video_drvdata(file);
882 struct v4l2_pix_format *pix = &fmt->fmt.pix;
883 int ret = pms_try_fmt_vid_cap(file, fh, fmt);
884
885 if (ret)
886 return ret;
887 mutex_lock(&dev->lock);
888 dev->width = pix->width;
889 dev->height = pix->height;
890 dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
891 pms_resolution(dev, dev->width, dev->height);
892 /* Ok we figured out what to use from our wide choice */
893 mutex_unlock(&dev->lock);
894 return 0;
895}
896
897static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
898{
899 static struct v4l2_fmtdesc formats[] = {
900 { 0, 0, 0,
901 "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
902 { 0, 0, 0, 0 }
903 },
904 { 0, 0, 0,
905 "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
906 { 0, 0, 0, 0 }
907 },
908 };
909 enum v4l2_buf_type type = fmt->type;
910
911 if (fmt->index > 1)
912 return -EINVAL;
913
914 *fmt = formats[fmt->index];
915 fmt->type = type;
916 return 0;
917}
918
919static ssize_t pms_read(struct file *file, char __user *buf,
920 size_t count, loff_t *ppos)
921{
922 struct pms *dev = video_drvdata(file);
923 int len;
924
925 mutex_lock(&dev->lock);
926 len = pms_capture(dev, buf, (dev->depth == 15), count);
927 mutex_unlock(&dev->lock);
928 return len;
929}
930
931static const struct v4l2_file_operations pms_fops = {
932 .owner = THIS_MODULE,
933 .unlocked_ioctl = video_ioctl2,
934 .read = pms_read,
935};
936
937static const struct v4l2_ioctl_ops pms_ioctl_ops = {
938 .vidioc_querycap = pms_querycap,
939 .vidioc_g_input = pms_g_input,
940 .vidioc_s_input = pms_s_input,
941 .vidioc_enum_input = pms_enum_input,
942 .vidioc_g_std = pms_g_std,
943 .vidioc_s_std = pms_s_std,
944 .vidioc_queryctrl = pms_queryctrl,
945 .vidioc_g_ctrl = pms_g_ctrl,
946 .vidioc_s_ctrl = pms_s_ctrl,
947 .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap,
948 .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap,
949 .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap,
950 .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap,
951};
952
953/*
954 * Probe for and initialise the Mediavision PMS
955 */
956
957static int init_mediavision(struct pms *dev)
958{
959 int id;
960 int idec, decst;
961 int i;
962 static const unsigned char i2c_defs[] = {
963 0x4c, 0x30, 0x00, 0xe8,
964 0xb6, 0xe2, 0x00, 0x00,
965 0xff, 0xff, 0x00, 0x00,
966 0x00, 0x00, 0x78, 0x98,
967 0x00, 0x00, 0x00, 0x00,
968 0x34, 0x0a, 0xf4, 0xce,
969 0xe4
970 };
971
972 dev->mem = ioremap(mem_base, 0x800);
973 if (!dev->mem)
974 return -ENOMEM;
975
976 if (!request_region(0x9a01, 1, "Mediavision PMS config")) {
977 printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n");
978 iounmap(dev->mem);
979 return -EBUSY;
980 }
981 if (!request_region(dev->io, 3, "Mediavision PMS")) {
982 printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io);
983 release_region(0x9a01, 1);
984 iounmap(dev->mem);
985 return -EBUSY;
986 }
987 outb(0xb8, 0x9a01); /* Unlock */
988 outb(dev->io >> 4, 0x9a01); /* Set IO port */
989
990
991 id = mvv_read(dev, 3);
992 decst = pms_i2c_stat(dev, 0x43);
993
994 if (decst != -1)
995 idec = 2;
996 else if (pms_i2c_stat(dev, 0xb9) != -1)
997 idec = 3;
998 else if (pms_i2c_stat(dev, 0x8b) != -1)
999 idec = 1;
1000 else
1001 idec = 0;
1002
1003 printk(KERN_INFO "PMS type is %d\n", idec);
1004 if (idec == 0) {
1005 release_region(dev->io, 3);
1006 release_region(0x9a01, 1);
1007 iounmap(dev->mem);
1008 return -ENODEV;
1009 }
1010
1011 /*
1012 * Ok we have a PMS of some sort
1013 */
1014
1015 mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */
1016
1017 /* Ok now load the defaults */
1018
1019 for (i = 0; i < 0x19; i++) {
1020 if (i2c_defs[i] == 0xff)
1021 pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00);
1022 else
1023 pms_i2c_write(dev, 0x8a, i, i2c_defs[i]);
1024 }
1025
1026 pms_i2c_write(dev, 0xb8, 0x00, 0x12);
1027 pms_i2c_write(dev, 0xb8, 0x04, 0x00);
1028 pms_i2c_write(dev, 0xb8, 0x07, 0x00);
1029 pms_i2c_write(dev, 0xb8, 0x08, 0x00);
1030 pms_i2c_write(dev, 0xb8, 0x09, 0xff);
1031 pms_i2c_write(dev, 0xb8, 0x0a, 0x00);
1032 pms_i2c_write(dev, 0xb8, 0x0b, 0x10);
1033 pms_i2c_write(dev, 0xb8, 0x10, 0x03);
1034
1035 mvv_write(dev, 0x01, 0x00);
1036 mvv_write(dev, 0x05, 0xa0);
1037 mvv_write(dev, 0x08, 0x25);
1038 mvv_write(dev, 0x09, 0x00);
1039 mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH);
1040
1041 mvv_write(dev, 0x10, 0x02);
1042 mvv_write(dev, 0x1e, 0x0c);
1043 mvv_write(dev, 0x1f, 0x03);
1044 mvv_write(dev, 0x26, 0x06);
1045
1046 mvv_write(dev, 0x2b, 0x00);
1047 mvv_write(dev, 0x2c, 0x20);
1048 mvv_write(dev, 0x2d, 0x00);
1049 mvv_write(dev, 0x2f, 0x70);
1050 mvv_write(dev, 0x32, 0x00);
1051 mvv_write(dev, 0x33, MVVMEMORYWIDTH);
1052 mvv_write(dev, 0x34, 0x00);
1053 mvv_write(dev, 0x35, 0x00);
1054 mvv_write(dev, 0x3a, 0x80);
1055 mvv_write(dev, 0x3b, 0x10);
1056 mvv_write(dev, 0x20, 0x00);
1057 mvv_write(dev, 0x21, 0x00);
1058 mvv_write(dev, 0x30, 0x22);
1059 return 0;
1060}
1061
1062/*
1063 * Initialization and module stuff
1064 */
1065
1066#ifndef MODULE
1067static int enable;
1068module_param(enable, int, 0);
1069#endif
1070
1071static int __init pms_init(void)
1072{
1073 struct pms *dev = &pms_card;
1074 struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
1075 int res;
1076
1077 strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name));
1078
1079 v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n");
1080
1081#ifndef MODULE
1082 if (!enable) {
1083 v4l2_err(v4l2_dev,
1084 "PMS: not enabled, use pms.enable=1 to probe\n");
1085 return -ENODEV;
1086 }
1087#endif
1088
1089 dev->decoder = PHILIPS2;
1090 dev->io = io_port;
1091 dev->data = io_port + 1;
1092
1093 if (init_mediavision(dev)) {
1094 v4l2_err(v4l2_dev, "Board not found.\n");
1095 return -ENODEV;
1096 }
1097
1098 res = v4l2_device_register(NULL, v4l2_dev);
1099 if (res < 0) {
1100 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
1101 return res;
1102 }
1103
1104 strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
1105 dev->vdev.v4l2_dev = v4l2_dev;
1106 dev->vdev.fops = &pms_fops;
1107 dev->vdev.ioctl_ops = &pms_ioctl_ops;
1108 dev->vdev.release = video_device_release_empty;
1109 video_set_drvdata(&dev->vdev, dev);
1110 mutex_init(&dev->lock);
1111 dev->std = V4L2_STD_NTSC_M;
1112 dev->height = 240;
1113 dev->width = 320;
1114 dev->depth = 15;
1115 dev->brightness = 139;
1116 dev->contrast = 70;
1117 dev->hue = 0;
1118 dev->saturation = 64;
1119 pms_swsense(dev, 75);
1120 pms_resolution(dev, 320, 240);
1121 pms_videosource(dev, 0);
1122 pms_vcrinput(dev, 0);
1123 if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
1124 v4l2_device_unregister(&dev->v4l2_dev);
1125 release_region(dev->io, 3);
1126 release_region(0x9a01, 1);
1127 iounmap(dev->mem);
1128 return -EINVAL;
1129 }
1130 return 0;
1131}
1132
1133static void __exit pms_exit(void)
1134{
1135 struct pms *dev = &pms_card;
1136
1137 video_unregister_device(&dev->vdev);
1138 release_region(dev->io, 3);
1139 release_region(0x9a01, 1);
1140 iounmap(dev->mem);
1141}
1142
1143module_init(pms_init);
1144module_exit(pms_exit);