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