2 * Media Vision Pro Movie Studio
4 * "all you need is an I2C bus some RAM and a prayer"
6 * This draws heavily on code
8 * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994
10 * 14478 Potsdam, Germany
12 * Most of this code is directly derived from his userspace driver.
13 * His driver works so send any reports to alan@redhat.com unless the
14 * userspace driver also doesnt work for you...
17 #include <linux/module.h>
18 #include <linux/delay.h>
19 #include <linux/errno.h>
21 #include <linux/kernel.h>
22 #include <linux/malloc.h>
24 #include <linux/ioport.h>
25 #include <linux/init.h>
27 #include <linux/sched.h>
28 #include <linux/videodev.h>
29 #include <linux/version.h>
30 #include <asm/uaccess.h>
36 #define MVVMEMORYWIDTH 0x40 /* 512 bytes */
40 struct video_device v
;
41 struct video_picture picture
;
54 static int i2c_count
= 0;
55 static struct i2c_info i2cinfo
[64];
57 static int decoder
= PHILIPS2
;
58 static int standard
= 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
61 * I/O ports and Shared Memory
64 static int io_port
= 0x250;
65 static int data_port
= 0x251;
66 static int mem_base
= 0xC8000;
70 extern __inline__
void mvv_write(u8 index
, u8 value
)
72 outw(index
|(value
<<8), io_port
);
75 extern __inline__ u8
mvv_read(u8 index
)
78 return inb(data_port
);
81 static int pms_i2c_stat(u8 slave
)
89 while((inb(data_port
)&0x01)==0)
93 while((inb(data_port
)&0x01)!=0)
100 while((inb(data_port
)&0x01)==0)
104 while((inb(data_port
)&0x01)!=0)
110 char st
=inb(data_port
);
117 return inb(data_port
);
120 static int pms_i2c_write(u16 slave
, u16 sub
, u16 data
)
126 for(i
=0;i
<i2c_count
;i
++)
128 if((i2cinfo
[i
].slave
==slave
) &&
129 (i2cinfo
[i
].sub
== sub
))
131 if(i2cinfo
[i
].data
==data
)
133 i2cinfo
[i
].data
=data
;
138 if(i
==i2c_count
&& i2c_count
<64)
140 i2cinfo
[i2c_count
].slave
=slave
;
141 i2cinfo
[i2c_count
].sub
=sub
;
142 i2cinfo
[i2c_count
].data
=data
;
149 mvv_write(0x29, sub
);
150 mvv_write(0x2A, data
);
151 mvv_write(0x28, slave
);
156 while((inb(data_port
)&1)==0)
159 while((inb(data_port
)&1)!=0)
163 count
=inb(data_port
);
170 static int pms_i2c_read(int slave
, int sub
)
173 for(i
=0;i
<i2c_count
;i
++)
175 if(i2cinfo
[i
].slave
==slave
&& i2cinfo
[i
].sub
==sub
)
176 return i2cinfo
[i
].data
;
182 static void pms_i2c_andor(int slave
, int sub
, int and, int or)
186 tmp
=pms_i2c_read(slave
, sub
);
188 pms_i2c_write(slave
, sub
, tmp
);
196 static void pms_videosource(short source
)
198 mvv_write(0x2E, source
?0x31:0x30);
201 static void pms_hue(short hue
)
206 pms_i2c_write(0x8A, 0x00, hue
);
209 pms_i2c_write(0x8A, 0x07, hue
);
212 pms_i2c_write(0x42, 0x07, hue
);
217 static void pms_colour(short colour
)
222 pms_i2c_write(0x8A, 0x00, colour
);
225 pms_i2c_write(0x42, 0x12, colour
);
231 static void pms_contrast(short contrast
)
236 pms_i2c_write(0x8A, 0x00, contrast
);
239 pms_i2c_write(0x42, 0x13, contrast
);
244 static void pms_brightness(short brightness
)
249 pms_i2c_write(0x8A, 0x00, brightness
);
250 pms_i2c_write(0x8A, 0x00, brightness
);
251 pms_i2c_write(0x8A, 0x00, brightness
);
254 pms_i2c_write(0x42, 0x19, brightness
);
260 static void pms_format(short format
)
265 if(decoder
==PHILIPS1
)
267 else if(decoder
==PHILIPS2
)
275 pms_i2c_andor(target
, 0x0D, 0xFE,0x00);
276 pms_i2c_andor(target
, 0x0F, 0x3F,0x80);
279 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
280 pms_i2c_andor(target
, 0x0F, 0x3F, 0x40);
283 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
284 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
287 pms_i2c_andor(target
, 0x0D, 0xFE, 0x01);
288 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
293 #ifdef FOR_FUTURE_EXPANSION
296 * These features of the PMS card are not currently exposes. They
297 * could become a private v4l ioctl for PMSCONFIG or somesuch if
298 * people need it. We also don't yet use the PMS interrupt.
301 static void pms_hstart(short start
)
306 pms_i2c_write(0x8A, 0x05, start
);
307 pms_i2c_write(0x8A, 0x18, start
);
310 pms_i2c_write(0x42, 0x05, start
);
311 pms_i2c_write(0x42, 0x18, start
);
320 static void pms_bandpass(short pass
)
322 if(decoder
==PHILIPS2
)
323 pms_i2c_andor(0x8A, 0x06, 0xCF, (pass
&0x03)<<4);
324 else if(decoder
==PHILIPS1
)
325 pms_i2c_andor(0x42, 0x06, 0xCF, (pass
&0x03)<<4);
328 static void pms_antisnow(short snow
)
330 if(decoder
==PHILIPS2
)
331 pms_i2c_andor(0x8A, 0x06, 0xF3, (snow
&0x03)<<2);
332 else if(decoder
==PHILIPS1
)
333 pms_i2c_andor(0x42, 0x06, 0xF3, (snow
&0x03)<<2);
336 static void pms_sharpness(short sharp
)
338 if(decoder
==PHILIPS2
)
339 pms_i2c_andor(0x8A, 0x06, 0xFC, sharp
&0x03);
340 else if(decoder
==PHILIPS1
)
341 pms_i2c_andor(0x42, 0x06, 0xFC, sharp
&0x03);
344 static void pms_chromaagc(short agc
)
346 if(decoder
==PHILIPS2
)
347 pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc
&0x03)<<5);
348 else if(decoder
==PHILIPS1
)
349 pms_i2c_andor(0x42, 0x0C, 0x9F, (agc
&0x03)<<5);
352 static void pms_vertnoise(short noise
)
354 if(decoder
==PHILIPS2
)
355 pms_i2c_andor(0x8A, 0x10, 0xFC, noise
&3);
356 else if(decoder
==PHILIPS1
)
357 pms_i2c_andor(0x42, 0x10, 0xFC, noise
&3);
360 static void pms_forcecolour(short colour
)
362 if(decoder
==PHILIPS2
)
363 pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour
&1)<<7);
364 else if(decoder
==PHILIPS1
)
365 pms_i2c_andor(0x42, 0x0C, 0x7, (colour
&1)<<7);
368 static void pms_antigamma(short gamma
)
370 if(decoder
==PHILIPS2
)
371 pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma
&1)<<7);
372 else if(decoder
==PHILIPS1
)
373 pms_i2c_andor(0x42, 0x20, 0x7, (gamma
&1)<<7);
376 static void pms_prefilter(short filter
)
378 if(decoder
==PHILIPS2
)
379 pms_i2c_andor(0x8A, 0x06, 0xBF, (filter
&1)<<6);
380 else if(decoder
==PHILIPS1
)
381 pms_i2c_andor(0x42, 0x06, 0xBF, (filter
&1)<<6);
384 static void pms_hfilter(short filter
)
386 if(decoder
==PHILIPS2
)
387 pms_i2c_andor(0xB8, 0x04, 0x1F, (filter
&7)<<5);
388 else if(decoder
==PHILIPS1
)
389 pms_i2c_andor(0x42, 0x24, 0x1F, (filter
&7)<<5);
392 static void pms_vfilter(short filter
)
394 if(decoder
==PHILIPS2
)
395 pms_i2c_andor(0xB8, 0x08, 0x9F, (filter
&3)<<5);
396 else if(decoder
==PHILIPS1
)
397 pms_i2c_andor(0x42, 0x28, 0x9F, (filter
&3)<<5);
400 static void pms_killcolour(short colour
)
402 if(decoder
==PHILIPS2
)
404 pms_i2c_andor(0x8A, 0x08, 0x07, (colour
&0x1F)<<3);
405 pms_i2c_andor(0x8A, 0x09, 0x07, (colour
&0x1F)<<3);
407 else if(decoder
==PHILIPS1
)
409 pms_i2c_andor(0x42, 0x08, 0x07, (colour
&0x1F)<<3);
410 pms_i2c_andor(0x42, 0x09, 0x07, (colour
&0x1F)<<3);
414 static void pms_chromagain(short chroma
)
416 if(decoder
==PHILIPS2
)
418 pms_i2c_write(0x8A, 0x11, chroma
);
420 else if(decoder
==PHILIPS1
)
422 pms_i2c_write(0x42, 0x11, chroma
);
427 static void pms_spacialcompl(short data
)
429 mvv_write(0x3B, data
);
432 static void pms_spacialcomph(short data
)
434 mvv_write(0x3A, data
);
437 static void pms_vstart(short start
)
439 mvv_write(0x16, start
);
440 mvv_write(0x17, (start
>>8)&0x01);
445 static void pms_secamcross(short cross
)
447 if(decoder
==PHILIPS2
)
448 pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross
&1)<<5);
449 else if(decoder
==PHILIPS1
)
450 pms_i2c_andor(0x42, 0x0F, 0xDF, (cross
&1)<<5);
454 static void pms_swsense(short sense
)
456 if(decoder
==PHILIPS2
)
458 pms_i2c_write(0x8A, 0x0A, sense
);
459 pms_i2c_write(0x8A, 0x0B, sense
);
461 else if(decoder
==PHILIPS1
)
463 pms_i2c_write(0x42, 0x0A, sense
);
464 pms_i2c_write(0x42, 0x0B, sense
);
469 static void pms_framerate(short frr
)
471 int fps
=(standard
==1)?30:25;
475 mvv_write(0x14,0x80|fps
);
479 static void pms_vert(u8 deciden
, u8 decinum
)
481 mvv_write(0x1C, deciden
); /* Denominator */
482 mvv_write(0x1D, decinum
); /* Numerator */
486 * Turn 16bit ratios into best small ratio the chipset can grok
489 static void pms_vertdeci(unsigned short decinum
, unsigned short deciden
)
491 /* Knock it down by /5 once */
500 while(decinum
%3==0 && deciden
%3==0)
508 while(decinum
%2==0 && deciden
%2==0)
519 decinum
=(decinum
+1)/2;
523 pms_vert(deciden
,decinum
);
526 static void pms_horzdeci(short decinum
, short deciden
)
539 deciden
=640; /* 768 would be ideal */
542 while(((decinum
|deciden
)&1)==0)
550 decinum
=(decinum
+1)>>1;
555 mvv_write(0x24, 0x80|deciden
);
556 mvv_write(0x25, decinum
);
559 static void pms_resolution(short width
, short height
)
567 mvv_write(0x18, fg_height
);
568 mvv_write(0x19, fg_height
>>8);
572 mvv_write(0x1A, 0xFC);
573 mvv_write(0x1B, 0x00);
575 pms_vertdeci(240,240);
577 pms_vertdeci(fg_height
,240);
581 mvv_write(0x1A, 0x1A);
582 mvv_write(0x1B, 0x01);
584 pms_vertdeci(270,270);
586 pms_vertdeci(fg_height
, 270);
589 mvv_write(0x13, MVVMEMORYWIDTH
);
590 mvv_write(0x42, 0x00);
591 mvv_write(0x43, 0x00);
592 mvv_write(0x44, MVVMEMORYWIDTH
);
594 mvv_write(0x22, width
+8);
595 mvv_write(0x23, (width
+8)>> 8);
598 pms_horzdeci(width
,640);
600 pms_horzdeci(width
+8, 768);
602 mvv_write(0x30, mvv_read(0x30)&0xFE);
603 mvv_write(0x08, mvv_read(0x08)|0x01);
604 mvv_write(0x01, mvv_read(0x01)&0xFD);
605 mvv_write(0x32, 0x00);
606 mvv_write(0x33, MVVMEMORYWIDTH
);
614 static void pms_vcrinput(short input
)
616 if(decoder
==PHILIPS2
)
617 pms_i2c_andor(0x8A,0x0D,0x7F,(input
&1)<<7);
618 else if(decoder
==PHILIPS1
)
619 pms_i2c_andor(0x42,0x0D,0x7F,(input
&1)<<7);
623 static int pms_capture(struct pms_device
*dev
, char *buf
, int rgb555
, int count
)
626 int dw
= 2*dev
->width
;
629 char tmp
[dw
+32]; /* using a temp buffer is faster than direct */
632 unsigned char r8
= 0x5; /* value for reg8 */
635 r8
|= 0x20; /* else use untranslated rgb = 565 */
636 mvv_write(0x08,r8
); /* capture rgb555/565, init DRAM, PC enable */
638 /* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
640 for (y
= 0; y
< dev
->height
; y
++ )
642 isa_writeb(0, src
); /* synchronisiert neue Zeile */
645 * This is in truth a fifo, be very careful as if you
646 * forgot this odd things will occur 8)
649 isa_memcpy_fromio(tmp
, src
, dw
+32); /* discard 16 word */
660 copy_to_user(buf
, tmp
+32, dt
);
670 * Video4linux interfacing
673 static int pms_open(struct video_device
*dev
, int flags
)
679 static void pms_close(struct video_device
*dev
)
684 static int pms_init_done(struct video_device
*dev
)
689 static long pms_write(struct video_device
*v
, const char *buf
, unsigned long count
, int noblock
)
694 static int pms_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
696 struct pms_device
*pd
=(struct pms_device
*)dev
;
702 struct video_capability b
;
703 strcpy(b
.name
, "Mediavision PMS");
704 b
.type
= VID_TYPE_CAPTURE
|VID_TYPE_SCALES
;
711 if(copy_to_user(arg
, &b
,sizeof(b
)))
717 struct video_channel v
;
718 if(copy_from_user(&v
, arg
, sizeof(v
)))
720 if(v
.channel
<0 || v
.channel
>3)
724 /* Good question.. its composite or SVHS so.. */
725 v
.type
= VIDEO_TYPE_CAMERA
;
729 strcpy(v
.name
, "Composite");break;
731 strcpy(v
.name
, "SVideo");break;
733 strcpy(v
.name
, "Composite(VCR)");break;
735 strcpy(v
.name
, "SVideo(VCR)");break;
737 if(copy_to_user(arg
, &v
, sizeof(v
)))
744 if(copy_from_user(&v
, arg
,sizeof(v
)))
748 pms_videosource(v
&1);
754 struct video_tuner v
;
755 if(copy_from_user(&v
, arg
, sizeof(v
))!=0)
759 strcpy(v
.name
, "Format");
762 v
.flags
= VIDEO_TUNER_PAL
|VIDEO_TUNER_NTSC
|VIDEO_TUNER_SECAM
;
766 v
.mode
= VIDEO_MODE_AUTO
;
769 v
.mode
= VIDEO_MODE_NTSC
;
772 v
.mode
= VIDEO_MODE_PAL
;
775 v
.mode
= VIDEO_MODE_SECAM
;
778 if(copy_to_user(arg
,&v
,sizeof(v
))!=0)
784 struct video_tuner v
;
785 if(copy_from_user(&v
, arg
, sizeof(v
))!=0)
791 case VIDEO_MODE_AUTO
:
796 case VIDEO_MODE_NTSC
:
806 case VIDEO_MODE_SECAM
:
818 struct video_picture p
=pd
->picture
;
819 if(copy_to_user(arg
, &p
, sizeof(p
)))
825 struct video_picture p
;
826 if(copy_from_user(&p
, arg
, sizeof(p
)))
828 if(!((p
.palette
==VIDEO_PALETTE_RGB565
&& p
.depth
==16)
829 ||(p
.palette
==VIDEO_PALETTE_RGB555
&& p
.depth
==15)))
837 pms_brightness(p
.brightness
>>8);
839 pms_colour(p
.colour
>>8);
840 pms_contrast(p
.contrast
>>8);
845 struct video_window vw
;
846 if(copy_from_user(&vw
, arg
,sizeof(vw
)))
852 if(vw
.height
<16||vw
.height
>480)
854 if(vw
.width
<16||vw
.width
>640)
857 pd
->height
=vw
.height
;
858 pms_resolution(pd
->width
, pd
->height
);
859 /* Ok we figured out what to use from our wide choice */
864 struct video_window vw
;
868 vw
.height
=pd
->height
;
871 if(copy_to_user(arg
, &vw
, sizeof(vw
)))
897 static long pms_read(struct video_device
*v
, char *buf
, unsigned long count
, int noblock
)
899 struct pms_device
*pd
=(struct pms_device
*)v
;
902 /* FIXME: semaphore this */
903 len
=pms_capture(pd
, buf
, (pd
->picture
.depth
==16)?0:1,count
);
908 struct video_device pms_template
=
917 NULL
, /* FIXME - we can use POLL on this board with the irq */
926 struct pms_device pms_device
;
930 * Probe for and initialise the Mediavision PMS
933 static int init_mediavision(void)
939 unsigned char i2c_defs
[]={
949 if(check_region(0x9A01,1))
951 printk(KERN_WARNING
"mediavision: unable to detect: 0x9A01 in use.\n");
954 if(check_region(io_port
,3))
956 printk(KERN_WARNING
"mediavision: I/O port %d in use.\n", io_port
);
959 outb(0xB8, 0x9A01); /* Unlock */
960 outb(io_port
>>4, 0x9A01); /* Set IO port */
964 decst
=pms_i2c_stat(0x43);
968 else if(pms_i2c_stat(0xb9)!=-1)
970 else if(pms_i2c_stat(0x8b)!=-1)
975 printk(KERN_INFO
"PMS type is %d\n", idec
);
980 * Ok we have a PMS of some sort
983 request_region(io_port
,3, "Mediavision PMS");
984 request_region(0x9A01, 1, "Mediavision PMS config");
986 mvv_write(0x04, mem_base
>>12); /* Set the memory area */
988 /* Ok now load the defaults */
992 if(i2c_defs
[i
]==0xFF)
993 pms_i2c_andor(0x8A, i
, 0x07,0x00);
995 pms_i2c_write(0x8A, i
, i2c_defs
[i
]);
998 pms_i2c_write(0xB8,0x00,0x12);
999 pms_i2c_write(0xB8,0x04,0x00);
1000 pms_i2c_write(0xB8,0x07,0x00);
1001 pms_i2c_write(0xB8,0x08,0x00);
1002 pms_i2c_write(0xB8,0x09,0xFF);
1003 pms_i2c_write(0xB8,0x0A,0x00);
1004 pms_i2c_write(0xB8,0x0B,0x10);
1005 pms_i2c_write(0xB8,0x10,0x03);
1007 mvv_write(0x01, 0x00);
1008 mvv_write(0x05, 0xA0);
1009 mvv_write(0x08, 0x25);
1010 mvv_write(0x09, 0x00);
1011 mvv_write(0x0A, 0x20|MVVMEMORYWIDTH
);
1013 mvv_write(0x10, 0x02);
1014 mvv_write(0x1E, 0x0C);
1015 mvv_write(0x1F, 0x03);
1016 mvv_write(0x26, 0x06);
1018 mvv_write(0x2B, 0x00);
1019 mvv_write(0x2C, 0x20);
1020 mvv_write(0x2D, 0x00);
1021 mvv_write(0x2F, 0x70);
1022 mvv_write(0x32, 0x00);
1023 mvv_write(0x33, MVVMEMORYWIDTH
);
1024 mvv_write(0x34, 0x00);
1025 mvv_write(0x35, 0x00);
1026 mvv_write(0x3A, 0x80);
1027 mvv_write(0x3B, 0x10);
1028 mvv_write(0x20, 0x00);
1029 mvv_write(0x21, 0x00);
1030 mvv_write(0x30, 0x22);
1035 * Initialization and module stuff
1038 static int __init
init_pms_cards(void)
1040 printk(KERN_INFO
"Mediavision Pro Movie Studio driver 0.02\n");
1042 data_port
= io_port
+1;
1044 if(init_mediavision())
1046 printk(KERN_INFO
"Board not found.\n");
1049 memcpy(&pms_device
, &pms_template
, sizeof(pms_template
));
1050 pms_device
.height
=240;
1051 pms_device
.width
=320;
1053 pms_resolution(320,240);
1054 return video_register_device((struct video_device
*)&pms_device
, VFL_TYPE_GRABBER
);
1057 MODULE_PARM(io_port
,"i");
1058 MODULE_PARM(mem_base
,"i");
1060 static void __exit
shutdown_mediavision(void)
1062 release_region(io_port
,3);
1063 release_region(0x9A01, 1);
1066 static void __exit
cleanup_pms_module(void)
1068 shutdown_mediavision();
1069 video_unregister_device((struct video_device
*)&pms_device
);
1072 module_init(init_pms_cards
);
1073 module_exit(cleanup_pms_module
);