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>
26 #include <linux/sched.h>
27 #include <linux/videodev.h>
28 #include <linux/version.h>
29 #include <asm/uaccess.h>
35 #define MVVMEMORYWIDTH 0x40 /* 512 bytes */
39 struct video_device v
;
40 struct video_picture picture
;
53 static int i2c_count
= 0;
54 static struct i2c_info i2cinfo
[64];
56 static int decoder
= PHILIPS2
;
57 static int standard
= 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
60 * I/O ports and Shared Memory
63 static int io_port
= 0x250;
64 static int data_port
= 0x251;
65 static int mem_base
= 0xC8000;
69 extern __inline__
void mvv_write(u8 index
, u8 value
)
71 outw(index
|(value
<<8), io_port
);
74 extern __inline__ u8
mvv_read(u8 index
)
77 return inb(data_port
);
80 static int pms_i2c_stat(u8 slave
)
88 while((inb(data_port
)&0x01)==0)
92 while((inb(data_port
)&0x01)!=0)
99 while((inb(data_port
)&0x01)==0)
103 while((inb(data_port
)&0x01)!=0)
109 char st
=inb(data_port
);
116 return inb(data_port
);
119 static int pms_i2c_write(u16 slave
, u16 sub
, u16 data
)
125 for(i
=0;i
<i2c_count
;i
++)
127 if((i2cinfo
[i
].slave
==slave
) &&
128 (i2cinfo
[i
].sub
== sub
))
130 if(i2cinfo
[i
].data
==data
)
132 i2cinfo
[i
].data
=data
;
137 if(i
==i2c_count
&& i2c_count
<64)
139 i2cinfo
[i2c_count
].slave
=slave
;
140 i2cinfo
[i2c_count
].sub
=sub
;
141 i2cinfo
[i2c_count
].data
=data
;
148 mvv_write(0x29, sub
);
149 mvv_write(0x2A, data
);
150 mvv_write(0x28, slave
);
155 while((inb(data_port
)&1)==0)
158 while((inb(data_port
)&1)!=0)
162 count
=inb(data_port
);
169 static int pms_i2c_read(int slave
, int sub
)
172 for(i
=0;i
<i2c_count
;i
++)
174 if(i2cinfo
[i
].slave
==slave
&& i2cinfo
[i
].sub
==sub
)
175 return i2cinfo
[i
].data
;
181 static void pms_i2c_andor(int slave
, int sub
, int and, int or)
185 tmp
=pms_i2c_read(slave
, sub
);
187 pms_i2c_write(slave
, sub
, tmp
);
195 static void pms_videosource(short source
)
197 mvv_write(0x2E, source
?0x31:0x30);
200 static void pms_hue(short hue
)
205 pms_i2c_write(0x8A, 0x00, hue
);
208 pms_i2c_write(0x8A, 0x07, hue
);
211 pms_i2c_write(0x42, 0x07, hue
);
216 static void pms_colour(short colour
)
221 pms_i2c_write(0x8A, 0x00, colour
);
224 pms_i2c_write(0x42, 0x12, colour
);
230 static void pms_contrast(short contrast
)
235 pms_i2c_write(0x8A, 0x00, contrast
);
238 pms_i2c_write(0x42, 0x13, contrast
);
243 static void pms_brightness(short brightness
)
248 pms_i2c_write(0x8A, 0x00, brightness
);
249 pms_i2c_write(0x8A, 0x00, brightness
);
250 pms_i2c_write(0x8A, 0x00, brightness
);
253 pms_i2c_write(0x42, 0x19, brightness
);
259 static void pms_format(short format
)
264 if(decoder
==PHILIPS1
)
266 else if(decoder
==PHILIPS2
)
274 pms_i2c_andor(target
, 0x0D, 0xFE,0x00);
275 pms_i2c_andor(target
, 0x0F, 0x3F,0x80);
278 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
279 pms_i2c_andor(target
, 0x0F, 0x3F, 0x40);
282 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
283 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
286 pms_i2c_andor(target
, 0x0D, 0xFE, 0x01);
287 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
292 #ifdef FOR_FUTURE_EXPANSION
295 * These features of the PMS card are not currently exposes. They
296 * could become a private v4l ioctl for PMSCONFIG or somesuch if
297 * people need it. We also don't yet use the PMS interrupt.
300 static void pms_hstart(short start
)
305 pms_i2c_write(0x8A, 0x05, start
);
306 pms_i2c_write(0x8A, 0x18, start
);
309 pms_i2c_write(0x42, 0x05, start
);
310 pms_i2c_write(0x42, 0x18, start
);
319 static void pms_bandpass(short pass
)
321 if(decoder
==PHILIPS2
)
322 pms_i2c_andor(0x8A, 0x06, 0xCF, (pass
&0x03)<<4);
323 else if(decoder
==PHILIPS1
)
324 pms_i2c_andor(0x42, 0x06, 0xCF, (pass
&0x03)<<4);
327 static void pms_antisnow(short snow
)
329 if(decoder
==PHILIPS2
)
330 pms_i2c_andor(0x8A, 0x06, 0xF3, (snow
&0x03)<<2);
331 else if(decoder
==PHILIPS1
)
332 pms_i2c_andor(0x42, 0x06, 0xF3, (snow
&0x03)<<2);
335 static void pms_sharpness(short sharp
)
337 if(decoder
==PHILIPS2
)
338 pms_i2c_andor(0x8A, 0x06, 0xFC, sharp
&0x03);
339 else if(decoder
==PHILIPS1
)
340 pms_i2c_andor(0x42, 0x06, 0xFC, sharp
&0x03);
343 static void pms_chromaagc(short agc
)
345 if(decoder
==PHILIPS2
)
346 pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc
&0x03)<<5);
347 else if(decoder
==PHILIPS1
)
348 pms_i2c_andor(0x42, 0x0C, 0x9F, (agc
&0x03)<<5);
351 static void pms_vertnoise(short noise
)
353 if(decoder
==PHILIPS2
)
354 pms_i2c_andor(0x8A, 0x10, 0xFC, noise
&3);
355 else if(decoder
==PHILIPS1
)
356 pms_i2c_andor(0x42, 0x10, 0xFC, noise
&3);
359 static void pms_forcecolour(short colour
)
361 if(decoder
==PHILIPS2
)
362 pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour
&1)<<7);
363 else if(decoder
==PHILIPS1
)
364 pms_i2c_andor(0x42, 0x0C, 0x7, (colour
&1)<<7);
367 static void pms_antigamma(short gamma
)
369 if(decoder
==PHILIPS2
)
370 pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma
&1)<<7);
371 else if(decoder
==PHILIPS1
)
372 pms_i2c_andor(0x42, 0x20, 0x7, (gamma
&1)<<7);
375 static void pms_prefilter(short filter
)
377 if(decoder
==PHILIPS2
)
378 pms_i2c_andor(0x8A, 0x06, 0xBF, (filter
&1)<<6);
379 else if(decoder
==PHILIPS1
)
380 pms_i2c_andor(0x42, 0x06, 0xBF, (filter
&1)<<6);
383 static void pms_hfilter(short filter
)
385 if(decoder
==PHILIPS2
)
386 pms_i2c_andor(0xB8, 0x04, 0x1F, (filter
&7)<<5);
387 else if(decoder
==PHILIPS1
)
388 pms_i2c_andor(0x42, 0x24, 0x1F, (filter
&7)<<5);
391 static void pms_vfilter(short filter
)
393 if(decoder
==PHILIPS2
)
394 pms_i2c_andor(0xB8, 0x08, 0x9F, (filter
&3)<<5);
395 else if(decoder
==PHILIPS1
)
396 pms_i2c_andor(0x42, 0x28, 0x9F, (filter
&3)<<5);
399 static void pms_killcolour(short colour
)
401 if(decoder
==PHILIPS2
)
403 pms_i2c_andor(0x8A, 0x08, 0x07, (colour
&0x1F)<<3);
404 pms_i2c_andor(0x8A, 0x09, 0x07, (colour
&0x1F)<<3);
406 else if(decoder
==PHILIPS1
)
408 pms_i2c_andor(0x42, 0x08, 0x07, (colour
&0x1F)<<3);
409 pms_i2c_andor(0x42, 0x09, 0x07, (colour
&0x1F)<<3);
413 static void pms_chromagain(short chroma
)
415 if(decoder
==PHILIPS2
)
417 pms_i2c_write(0x8A, 0x11, chroma
);
419 else if(decoder
==PHILIPS1
)
421 pms_i2c_write(0x42, 0x11, chroma
);
426 static void pms_spacialcompl(short data
)
428 mvv_write(0x3B, data
);
431 static void pms_spacialcomph(short data
)
433 mvv_write(0x3A, data
);
436 static void pms_vstart(short start
)
438 mvv_write(0x16, start
);
439 mvv_write(0x17, (start
>>8)&0x01);
444 static void pms_secamcross(short cross
)
446 if(decoder
==PHILIPS2
)
447 pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross
&1)<<5);
448 else if(decoder
==PHILIPS1
)
449 pms_i2c_andor(0x42, 0x0F, 0xDF, (cross
&1)<<5);
453 static void pms_swsense(short sense
)
455 if(decoder
==PHILIPS2
)
457 pms_i2c_write(0x8A, 0x0A, sense
);
458 pms_i2c_write(0x8A, 0x0B, sense
);
460 else if(decoder
==PHILIPS1
)
462 pms_i2c_write(0x42, 0x0A, sense
);
463 pms_i2c_write(0x42, 0x0B, sense
);
468 static void pms_framerate(short frr
)
470 int fps
=(standard
==1)?30:25;
474 mvv_write(0x14,0x80|fps
);
478 static void pms_vert(u8 deciden
, u8 decinum
)
480 mvv_write(0x1C, deciden
); /* Denominator */
481 mvv_write(0x1D, decinum
); /* Numerator */
485 * Turn 16bit ratios into best small ratio the chipset can grok
488 static void pms_vertdeci(unsigned short decinum
, unsigned short deciden
)
490 /* Knock it down by /5 once */
499 while(decinum
%3==0 && deciden
%3==0)
507 while(decinum
%2==0 && deciden
%2==0)
518 decinum
=(decinum
+1)/2;
522 pms_vert(deciden
,decinum
);
525 static void pms_horzdeci(short decinum
, short deciden
)
538 deciden
=640; /* 768 would be ideal */
541 while(((decinum
|deciden
)&1)==0)
549 decinum
=(decinum
+1)>>1;
554 mvv_write(0x24, 0x80|deciden
);
555 mvv_write(0x25, decinum
);
558 static void pms_resolution(short width
, short height
)
566 mvv_write(0x18, fg_height
);
567 mvv_write(0x19, fg_height
>>8);
571 mvv_write(0x1A, 0xFC);
572 mvv_write(0x1B, 0x00);
574 pms_vertdeci(240,240);
576 pms_vertdeci(fg_height
,240);
580 mvv_write(0x1A, 0x1A);
581 mvv_write(0x1B, 0x01);
583 pms_vertdeci(270,270);
585 pms_vertdeci(fg_height
, 270);
588 mvv_write(0x13, MVVMEMORYWIDTH
);
589 mvv_write(0x42, 0x00);
590 mvv_write(0x43, 0x00);
591 mvv_write(0x44, MVVMEMORYWIDTH
);
593 mvv_write(0x22, width
+8);
594 mvv_write(0x23, (width
+8)>> 8);
597 pms_horzdeci(width
,640);
599 pms_horzdeci(width
+8, 768);
601 mvv_write(0x30, mvv_read(0x30)&0xFE);
602 mvv_write(0x08, mvv_read(0x08)|0x01);
603 mvv_write(0x01, mvv_read(0x01)&0xFD);
604 mvv_write(0x32, 0x00);
605 mvv_write(0x33, MVVMEMORYWIDTH
);
613 static void pms_vcrinput(short input
)
615 if(decoder
==PHILIPS2
)
616 pms_i2c_andor(0x8A,0x0D,0x7F,(input
&1)<<7);
617 else if(decoder
==PHILIPS1
)
618 pms_i2c_andor(0x42,0x0D,0x7F,(input
&1)<<7);
622 static int pms_capture(struct pms_device
*dev
, char *buf
, int rgb555
, int count
)
625 int dw
= 2*dev
->width
;
626 char *src
= (char *)bus_to_virt(mem_base
);
628 char tmp
[dw
+32]; /* using a temp buffer is faster than direct */
631 unsigned char r8
= 0x5; /* value for reg8 */
634 r8
|= 0x20; /* else use untranslated rgb = 565 */
635 mvv_write(0x08,r8
); /* capture rgb555/565, init DRAM, PC enable */
637 /* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
639 for (y
= 0; y
< dev
->height
; y
++ )
641 *src
= 0; /* synchronisiert neue Zeile */
642 memcpy(tmp
, src
, dw
+32); /* discard 16 word */
653 copy_to_user(buf
, tmp
+32, dt
);
663 * Video4linux interfacing
666 static int pms_open(struct video_device
*dev
, int flags
)
672 static void pms_close(struct video_device
*dev
)
677 static int pms_init_done(struct video_device
*dev
)
682 static long pms_write(struct video_device
*v
, const char *buf
, unsigned long count
, int noblock
)
687 static int pms_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
689 struct pms_device
*pd
=(struct pms_device
*)dev
;
695 struct video_capability b
;
696 strcpy(b
.name
, "Mediavision PMS");
697 b
.type
= VID_TYPE_CAPTURE
|VID_TYPE_SCALES
;
704 if(copy_to_user(arg
, &b
,sizeof(b
)))
710 struct video_channel v
;
711 if(copy_from_user(&v
, arg
, sizeof(v
)))
713 if(v
.channel
<0 || v
.channel
>3)
717 /* Good question.. its composite or SVHS so.. */
718 v
.type
= VIDEO_TYPE_CAMERA
;
722 strcpy(v
.name
, "Composite");break;
724 strcpy(v
.name
, "SVideo");break;
726 strcpy(v
.name
, "Composite(VCR)");break;
728 strcpy(v
.name
, "SVideo(VCR)");break;
730 if(copy_to_user(arg
, &v
, sizeof(v
)))
737 if(copy_from_user(&v
, arg
,sizeof(v
)))
741 pms_videosource(v
&1);
747 struct video_tuner v
;
748 if(copy_from_user(&v
, arg
, sizeof(v
))!=0)
752 strcpy(v
.name
, "Format");
755 v
.flags
= VIDEO_TUNER_PAL
|VIDEO_TUNER_NTSC
|VIDEO_TUNER_SECAM
;
759 v
.mode
= VIDEO_MODE_AUTO
;
762 v
.mode
= VIDEO_MODE_NTSC
;
765 v
.mode
= VIDEO_MODE_PAL
;
768 v
.mode
= VIDEO_MODE_SECAM
;
771 if(copy_to_user(arg
,&v
,sizeof(v
))!=0)
777 struct video_tuner v
;
778 if(copy_from_user(&v
, arg
, sizeof(v
))!=0)
784 case VIDEO_MODE_AUTO
:
789 case VIDEO_MODE_NTSC
:
799 case VIDEO_MODE_SECAM
:
811 struct video_picture p
=pd
->picture
;
812 if(copy_to_user(arg
, &p
, sizeof(p
)))
818 struct video_picture p
;
819 if(copy_from_user(&p
, arg
, sizeof(p
)))
821 if(!((p
.palette
==VIDEO_PALETTE_RGB565
&& p
.depth
==16)
822 ||(p
.palette
==VIDEO_PALETTE_RGB555
&& p
.depth
==15)))
830 pms_brightness(p
.brightness
>>8);
832 pms_colour(p
.colour
>>8);
833 pms_contrast(p
.contrast
>>8);
838 struct video_window vw
;
839 if(copy_from_user(&vw
, arg
,sizeof(vw
)))
845 if(vw
.height
<16||vw
.height
>480)
847 if(vw
.width
<16||vw
.width
>640)
850 pd
->height
=vw
.height
;
851 pms_resolution(pd
->width
, pd
->height
);
852 /* Ok we figured out what to use from our wide choice */
857 struct video_window vw
;
861 vw
.height
=pd
->height
;
864 if(copy_to_user(arg
, &vw
, sizeof(vw
)))
890 static long pms_read(struct video_device
*v
, char *buf
, unsigned long count
, int noblock
)
892 struct pms_device
*pd
=(struct pms_device
*)v
;
895 /* FIXME: semaphore this */
896 len
=pms_capture(pd
, buf
, (pd
->picture
.depth
==16)?0:1,count
);
901 struct video_device pms_template
=
910 NULL
, /* FIXME - we can use POLL on this board with the irq */
919 struct pms_device pms_device
;
923 * Probe for and initialise the Mediavision PMS
926 static int init_mediavision(void)
932 unsigned char i2c_defs
[]={
942 if(check_region(0x9A01,1))
944 printk(KERN_WARNING
"mediavision: unable to detect: 0x9A01 in use.\n");
947 if(check_region(io_port
,3))
949 printk(KERN_WARNING
"mediavision: I/O port %d in use.\n", io_port
);
952 outb(0xB8, 0x9A01); /* Unlock */
953 outb(io_port
>>4, 0x9A01); /* Set IO port */
957 decst
=pms_i2c_stat(0x43);
961 else if(pms_i2c_stat(0xb9)!=-1)
963 else if(pms_i2c_stat(0x8b)!=-1)
968 printk(KERN_INFO
"PMS type is %d\n", idec
);
973 * Ok we have a PMS of some sort
976 request_region(io_port
,3, "Mediavision PMS");
977 request_region(0x9A01, 1, "Mediavision PMS config");
979 mvv_write(0x04, mem_base
>>12); /* Set the memory area */
981 /* Ok now load the defaults */
985 if(i2c_defs
[i
]==0xFF)
986 pms_i2c_andor(0x8A, i
, 0x07,0x00);
988 pms_i2c_write(0x8A, i
, i2c_defs
[i
]);
991 pms_i2c_write(0xB8,0x00,0x12);
992 pms_i2c_write(0xB8,0x04,0x00);
993 pms_i2c_write(0xB8,0x07,0x00);
994 pms_i2c_write(0xB8,0x08,0x00);
995 pms_i2c_write(0xB8,0x09,0xFF);
996 pms_i2c_write(0xB8,0x0A,0x00);
997 pms_i2c_write(0xB8,0x0B,0x10);
998 pms_i2c_write(0xB8,0x10,0x03);
1000 mvv_write(0x01, 0x00);
1001 mvv_write(0x05, 0xA0);
1002 mvv_write(0x08, 0x25);
1003 mvv_write(0x09, 0x00);
1004 mvv_write(0x0A, 0x20|MVVMEMORYWIDTH
);
1006 mvv_write(0x10, 0x02);
1007 mvv_write(0x1E, 0x0C);
1008 mvv_write(0x1F, 0x03);
1009 mvv_write(0x26, 0x06);
1011 mvv_write(0x2B, 0x00);
1012 mvv_write(0x2C, 0x20);
1013 mvv_write(0x2D, 0x00);
1014 mvv_write(0x2F, 0x70);
1015 mvv_write(0x32, 0x00);
1016 mvv_write(0x33, MVVMEMORYWIDTH
);
1017 mvv_write(0x34, 0x00);
1018 mvv_write(0x35, 0x00);
1019 mvv_write(0x3A, 0x80);
1020 mvv_write(0x3B, 0x10);
1021 mvv_write(0x20, 0x00);
1022 mvv_write(0x21, 0x00);
1023 mvv_write(0x30, 0x22);
1027 static void shutdown_mediavision(void)
1029 release_region(io_port
,3);
1030 release_region(0x9A01, 1);
1038 int init_module(void)
1040 int init_pms_cards(struct video_init
*v
)
1043 printk(KERN_INFO
"Mediavision Pro Movie Studio driver 0.02\n");
1045 data_port
= io_port
+1;
1047 if(init_mediavision())
1049 printk(KERN_INFO
"Board not found.\n");
1052 memcpy(&pms_device
, &pms_template
, sizeof(pms_template
));
1053 pms_device
.height
=240;
1054 pms_device
.width
=320;
1056 pms_resolution(320,240);
1057 return video_register_device((struct video_device
*)&pms_device
, VFL_TYPE_GRABBER
);
1062 MODULE_PARM(io_port
,"i");
1063 MODULE_PARM(mem_base
,"i");
1065 void cleanup_module(void)
1067 shutdown_mediavision();
1068 video_unregister_device((struct video_device
*)&pms_device
);