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 doesn't work for you...
17 * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
18 * - pms_capture: report back -EFAULT
21 #include <linux/module.h>
22 #include <linux/delay.h>
23 #include <linux/errno.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
28 #include <linux/ioport.h>
29 #include <linux/init.h>
31 #include <linux/sched.h>
32 #include <linux/videodev.h>
33 #include <asm/uaccess.h>
39 #define MVVMEMORYWIDTH 0x40 /* 512 bytes */
43 struct video_device v
;
44 struct video_picture picture
;
47 struct semaphore lock
;
58 static int i2c_count
= 0;
59 static struct i2c_info i2cinfo
[64];
61 static int decoder
= PHILIPS2
;
62 static int standard
= 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
65 * I/O ports and Shared Memory
68 static int io_port
= 0x250;
69 static int data_port
= 0x251;
70 static int mem_base
= 0xC8000;
71 static void __iomem
*mem
;
72 static int video_nr
= -1;
76 static inline void mvv_write(u8 index
, u8 value
)
78 outw(index
|(value
<<8), io_port
);
81 static inline u8
mvv_read(u8 index
)
84 return inb(data_port
);
87 static int pms_i2c_stat(u8 slave
)
95 while((inb(data_port
)&0x01)==0)
99 while((inb(data_port
)&0x01)!=0)
103 outb(slave
, io_port
);
106 while((inb(data_port
)&0x01)==0)
110 while((inb(data_port
)&0x01)!=0)
116 char st
=inb(data_port
);
123 return inb(data_port
);
126 static int pms_i2c_write(u16 slave
, u16 sub
, u16 data
)
132 for(i
=0;i
<i2c_count
;i
++)
134 if((i2cinfo
[i
].slave
==slave
) &&
135 (i2cinfo
[i
].sub
== sub
))
137 if(i2cinfo
[i
].data
==data
)
139 i2cinfo
[i
].data
=data
;
144 if(i
==i2c_count
&& i2c_count
<64)
146 i2cinfo
[i2c_count
].slave
=slave
;
147 i2cinfo
[i2c_count
].sub
=sub
;
148 i2cinfo
[i2c_count
].data
=data
;
155 mvv_write(0x29, sub
);
156 mvv_write(0x2A, data
);
157 mvv_write(0x28, slave
);
162 while((inb(data_port
)&1)==0)
165 while((inb(data_port
)&1)!=0)
169 count
=inb(data_port
);
176 static int pms_i2c_read(int slave
, int sub
)
179 for(i
=0;i
<i2c_count
;i
++)
181 if(i2cinfo
[i
].slave
==slave
&& i2cinfo
[i
].sub
==sub
)
182 return i2cinfo
[i
].data
;
188 static void pms_i2c_andor(int slave
, int sub
, int and, int or)
192 tmp
=pms_i2c_read(slave
, sub
);
194 pms_i2c_write(slave
, sub
, tmp
);
202 static void pms_videosource(short source
)
204 mvv_write(0x2E, source
?0x31:0x30);
207 static void pms_hue(short hue
)
212 pms_i2c_write(0x8A, 0x00, hue
);
215 pms_i2c_write(0x8A, 0x07, hue
);
218 pms_i2c_write(0x42, 0x07, hue
);
223 static void pms_colour(short colour
)
228 pms_i2c_write(0x8A, 0x00, colour
);
231 pms_i2c_write(0x42, 0x12, colour
);
237 static void pms_contrast(short contrast
)
242 pms_i2c_write(0x8A, 0x00, contrast
);
245 pms_i2c_write(0x42, 0x13, contrast
);
250 static void pms_brightness(short brightness
)
255 pms_i2c_write(0x8A, 0x00, brightness
);
256 pms_i2c_write(0x8A, 0x00, brightness
);
257 pms_i2c_write(0x8A, 0x00, brightness
);
260 pms_i2c_write(0x42, 0x19, brightness
);
266 static void pms_format(short format
)
271 if(decoder
==PHILIPS1
)
273 else if(decoder
==PHILIPS2
)
281 pms_i2c_andor(target
, 0x0D, 0xFE,0x00);
282 pms_i2c_andor(target
, 0x0F, 0x3F,0x80);
285 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
286 pms_i2c_andor(target
, 0x0F, 0x3F, 0x40);
289 pms_i2c_andor(target
, 0x0D, 0xFE, 0x00);
290 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
293 pms_i2c_andor(target
, 0x0D, 0xFE, 0x01);
294 pms_i2c_andor(target
, 0x0F, 0x3F, 0x00);
299 #ifdef FOR_FUTURE_EXPANSION
302 * These features of the PMS card are not currently exposes. They
303 * could become a private v4l ioctl for PMSCONFIG or somesuch if
304 * people need it. We also don't yet use the PMS interrupt.
307 static void pms_hstart(short start
)
312 pms_i2c_write(0x8A, 0x05, start
);
313 pms_i2c_write(0x8A, 0x18, start
);
316 pms_i2c_write(0x42, 0x05, start
);
317 pms_i2c_write(0x42, 0x18, start
);
326 static void pms_bandpass(short pass
)
328 if(decoder
==PHILIPS2
)
329 pms_i2c_andor(0x8A, 0x06, 0xCF, (pass
&0x03)<<4);
330 else if(decoder
==PHILIPS1
)
331 pms_i2c_andor(0x42, 0x06, 0xCF, (pass
&0x03)<<4);
334 static void pms_antisnow(short snow
)
336 if(decoder
==PHILIPS2
)
337 pms_i2c_andor(0x8A, 0x06, 0xF3, (snow
&0x03)<<2);
338 else if(decoder
==PHILIPS1
)
339 pms_i2c_andor(0x42, 0x06, 0xF3, (snow
&0x03)<<2);
342 static void pms_sharpness(short sharp
)
344 if(decoder
==PHILIPS2
)
345 pms_i2c_andor(0x8A, 0x06, 0xFC, sharp
&0x03);
346 else if(decoder
==PHILIPS1
)
347 pms_i2c_andor(0x42, 0x06, 0xFC, sharp
&0x03);
350 static void pms_chromaagc(short agc
)
352 if(decoder
==PHILIPS2
)
353 pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc
&0x03)<<5);
354 else if(decoder
==PHILIPS1
)
355 pms_i2c_andor(0x42, 0x0C, 0x9F, (agc
&0x03)<<5);
358 static void pms_vertnoise(short noise
)
360 if(decoder
==PHILIPS2
)
361 pms_i2c_andor(0x8A, 0x10, 0xFC, noise
&3);
362 else if(decoder
==PHILIPS1
)
363 pms_i2c_andor(0x42, 0x10, 0xFC, noise
&3);
366 static void pms_forcecolour(short colour
)
368 if(decoder
==PHILIPS2
)
369 pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour
&1)<<7);
370 else if(decoder
==PHILIPS1
)
371 pms_i2c_andor(0x42, 0x0C, 0x7, (colour
&1)<<7);
374 static void pms_antigamma(short gamma
)
376 if(decoder
==PHILIPS2
)
377 pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma
&1)<<7);
378 else if(decoder
==PHILIPS1
)
379 pms_i2c_andor(0x42, 0x20, 0x7, (gamma
&1)<<7);
382 static void pms_prefilter(short filter
)
384 if(decoder
==PHILIPS2
)
385 pms_i2c_andor(0x8A, 0x06, 0xBF, (filter
&1)<<6);
386 else if(decoder
==PHILIPS1
)
387 pms_i2c_andor(0x42, 0x06, 0xBF, (filter
&1)<<6);
390 static void pms_hfilter(short filter
)
392 if(decoder
==PHILIPS2
)
393 pms_i2c_andor(0xB8, 0x04, 0x1F, (filter
&7)<<5);
394 else if(decoder
==PHILIPS1
)
395 pms_i2c_andor(0x42, 0x24, 0x1F, (filter
&7)<<5);
398 static void pms_vfilter(short filter
)
400 if(decoder
==PHILIPS2
)
401 pms_i2c_andor(0xB8, 0x08, 0x9F, (filter
&3)<<5);
402 else if(decoder
==PHILIPS1
)
403 pms_i2c_andor(0x42, 0x28, 0x9F, (filter
&3)<<5);
406 static void pms_killcolour(short colour
)
408 if(decoder
==PHILIPS2
)
410 pms_i2c_andor(0x8A, 0x08, 0x07, (colour
&0x1F)<<3);
411 pms_i2c_andor(0x8A, 0x09, 0x07, (colour
&0x1F)<<3);
413 else if(decoder
==PHILIPS1
)
415 pms_i2c_andor(0x42, 0x08, 0x07, (colour
&0x1F)<<3);
416 pms_i2c_andor(0x42, 0x09, 0x07, (colour
&0x1F)<<3);
420 static void pms_chromagain(short chroma
)
422 if(decoder
==PHILIPS2
)
424 pms_i2c_write(0x8A, 0x11, chroma
);
426 else if(decoder
==PHILIPS1
)
428 pms_i2c_write(0x42, 0x11, chroma
);
433 static void pms_spacialcompl(short data
)
435 mvv_write(0x3B, data
);
438 static void pms_spacialcomph(short data
)
440 mvv_write(0x3A, data
);
443 static void pms_vstart(short start
)
445 mvv_write(0x16, start
);
446 mvv_write(0x17, (start
>>8)&0x01);
451 static void pms_secamcross(short cross
)
453 if(decoder
==PHILIPS2
)
454 pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross
&1)<<5);
455 else if(decoder
==PHILIPS1
)
456 pms_i2c_andor(0x42, 0x0F, 0xDF, (cross
&1)<<5);
460 static void pms_swsense(short sense
)
462 if(decoder
==PHILIPS2
)
464 pms_i2c_write(0x8A, 0x0A, sense
);
465 pms_i2c_write(0x8A, 0x0B, sense
);
467 else if(decoder
==PHILIPS1
)
469 pms_i2c_write(0x42, 0x0A, sense
);
470 pms_i2c_write(0x42, 0x0B, sense
);
475 static void pms_framerate(short frr
)
477 int fps
=(standard
==1)?30:25;
481 mvv_write(0x14,0x80|fps
);
485 static void pms_vert(u8 deciden
, u8 decinum
)
487 mvv_write(0x1C, deciden
); /* Denominator */
488 mvv_write(0x1D, decinum
); /* Numerator */
492 * Turn 16bit ratios into best small ratio the chipset can grok
495 static void pms_vertdeci(unsigned short decinum
, unsigned short deciden
)
497 /* Knock it down by /5 once */
506 while(decinum
%3==0 && deciden
%3==0)
514 while(decinum
%2==0 && deciden
%2==0)
525 decinum
=(decinum
+1)/2;
529 pms_vert(deciden
,decinum
);
532 static void pms_horzdeci(short decinum
, short deciden
)
545 deciden
=640; /* 768 would be ideal */
548 while(((decinum
|deciden
)&1)==0)
556 decinum
=(decinum
+1)>>1;
561 mvv_write(0x24, 0x80|deciden
);
562 mvv_write(0x25, decinum
);
565 static void pms_resolution(short width
, short height
)
573 mvv_write(0x18, fg_height
);
574 mvv_write(0x19, fg_height
>>8);
578 mvv_write(0x1A, 0xFC);
579 mvv_write(0x1B, 0x00);
581 pms_vertdeci(240,240);
583 pms_vertdeci(fg_height
,240);
587 mvv_write(0x1A, 0x1A);
588 mvv_write(0x1B, 0x01);
590 pms_vertdeci(270,270);
592 pms_vertdeci(fg_height
, 270);
595 mvv_write(0x13, MVVMEMORYWIDTH
);
596 mvv_write(0x42, 0x00);
597 mvv_write(0x43, 0x00);
598 mvv_write(0x44, MVVMEMORYWIDTH
);
600 mvv_write(0x22, width
+8);
601 mvv_write(0x23, (width
+8)>> 8);
604 pms_horzdeci(width
,640);
606 pms_horzdeci(width
+8, 768);
608 mvv_write(0x30, mvv_read(0x30)&0xFE);
609 mvv_write(0x08, mvv_read(0x08)|0x01);
610 mvv_write(0x01, mvv_read(0x01)&0xFD);
611 mvv_write(0x32, 0x00);
612 mvv_write(0x33, MVVMEMORYWIDTH
);
620 static void pms_vcrinput(short input
)
622 if(decoder
==PHILIPS2
)
623 pms_i2c_andor(0x8A,0x0D,0x7F,(input
&1)<<7);
624 else if(decoder
==PHILIPS1
)
625 pms_i2c_andor(0x42,0x0D,0x7F,(input
&1)<<7);
629 static int pms_capture(struct pms_device
*dev
, char __user
*buf
, int rgb555
, int count
)
632 int dw
= 2*dev
->width
;
634 char tmp
[dw
+32]; /* using a temp buffer is faster than direct */
637 unsigned char r8
= 0x5; /* value for reg8 */
640 r8
|= 0x20; /* else use untranslated rgb = 565 */
641 mvv_write(0x08,r8
); /* capture rgb555/565, init DRAM, PC enable */
643 /* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
645 for (y
= 0; y
< dev
->height
; y
++ )
647 writeb(0, mem
); /* synchronisiert neue Zeile */
650 * This is in truth a fifo, be very careful as if you
651 * forgot this odd things will occur 8)
654 memcpy_fromio(tmp
, mem
, dw
+32); /* discard 16 word */
665 if (copy_to_user(buf
, tmp
+32, dt
))
666 return len
? len
: -EFAULT
;
676 * Video4linux interfacing
679 static int pms_do_ioctl(struct inode
*inode
, struct file
*file
,
680 unsigned int cmd
, void *arg
)
682 struct video_device
*dev
= video_devdata(file
);
683 struct pms_device
*pd
=(struct pms_device
*)dev
;
689 struct video_capability
*b
= arg
;
690 strcpy(b
->name
, "Mediavision PMS");
691 b
->type
= VID_TYPE_CAPTURE
|VID_TYPE_SCALES
;
702 struct video_channel
*v
= arg
;
703 if(v
->channel
<0 || v
->channel
>3)
707 /* Good question.. its composite or SVHS so.. */
708 v
->type
= VIDEO_TYPE_CAMERA
;
712 strcpy(v
->name
, "Composite");break;
714 strcpy(v
->name
, "SVideo");break;
716 strcpy(v
->name
, "Composite(VCR)");break;
718 strcpy(v
->name
, "SVideo(VCR)");break;
724 struct video_channel
*v
= arg
;
725 if(v
->channel
<0 || v
->channel
>3)
728 pms_videosource(v
->channel
&1);
729 pms_vcrinput(v
->channel
>>1);
735 struct video_tuner
*v
= arg
;
738 strcpy(v
->name
, "Format");
741 v
->flags
= VIDEO_TUNER_PAL
|VIDEO_TUNER_NTSC
|VIDEO_TUNER_SECAM
;
745 v
->mode
= VIDEO_MODE_AUTO
;
748 v
->mode
= VIDEO_MODE_NTSC
;
751 v
->mode
= VIDEO_MODE_PAL
;
754 v
->mode
= VIDEO_MODE_SECAM
;
761 struct video_tuner
*v
= arg
;
767 case VIDEO_MODE_AUTO
:
772 case VIDEO_MODE_NTSC
:
782 case VIDEO_MODE_SECAM
:
796 struct video_picture
*p
= arg
;
802 struct video_picture
*p
= arg
;
803 if(!((p
->palette
==VIDEO_PALETTE_RGB565
&& p
->depth
==16)
804 ||(p
->palette
==VIDEO_PALETTE_RGB555
&& p
->depth
==15)))
813 pms_brightness(p
->brightness
>>8);
815 pms_colour(p
->colour
>>8);
816 pms_contrast(p
->contrast
>>8);
822 struct video_window
*vw
= arg
;
827 if(vw
->height
<16||vw
->height
>480)
829 if(vw
->width
<16||vw
->width
>640)
832 pd
->height
=vw
->height
;
834 pms_resolution(pd
->width
, pd
->height
);
835 up(&pd
->lock
); /* Ok we figured out what to use from our wide choice */
840 struct video_window
*vw
= arg
;
841 memset(vw
,0,sizeof(*vw
));
843 vw
->height
=pd
->height
;
862 static int pms_ioctl(struct inode
*inode
, struct file
*file
,
863 unsigned int cmd
, unsigned long arg
)
865 return video_usercopy(inode
, file
, cmd
, arg
, pms_do_ioctl
);
868 static ssize_t
pms_read(struct file
*file
, char __user
*buf
,
869 size_t count
, loff_t
*ppos
)
871 struct video_device
*v
= video_devdata(file
);
872 struct pms_device
*pd
=(struct pms_device
*)v
;
876 len
=pms_capture(pd
, buf
, (pd
->picture
.depth
==16)?0:1,count
);
881 static struct file_operations pms_fops
= {
882 .owner
= THIS_MODULE
,
883 .open
= video_exclusive_open
,
884 .release
= video_exclusive_release
,
886 .compat_ioctl
= v4l_compat_ioctl32
,
891 static struct video_device pms_template
=
893 .owner
= THIS_MODULE
,
894 .name
= "Mediavision PMS",
895 .type
= VID_TYPE_CAPTURE
,
896 .hardware
= VID_HARDWARE_PMS
,
900 static struct pms_device pms_device
;
904 * Probe for and initialise the Mediavision PMS
907 static int init_mediavision(void)
913 unsigned char i2c_defs
[]={
923 mem
= ioremap(mem_base
, 0x800);
927 if (!request_region(0x9A01, 1, "Mediavision PMS config"))
929 printk(KERN_WARNING
"mediavision: unable to detect: 0x9A01 in use.\n");
933 if (!request_region(io_port
, 3, "Mediavision PMS"))
935 printk(KERN_WARNING
"mediavision: I/O port %d in use.\n", io_port
);
936 release_region(0x9A01, 1);
940 outb(0xB8, 0x9A01); /* Unlock */
941 outb(io_port
>>4, 0x9A01); /* Set IO port */
945 decst
=pms_i2c_stat(0x43);
949 else if(pms_i2c_stat(0xb9)!=-1)
951 else if(pms_i2c_stat(0x8b)!=-1)
956 printk(KERN_INFO
"PMS type is %d\n", idec
);
958 release_region(io_port
, 3);
959 release_region(0x9A01, 1);
965 * Ok we have a PMS of some sort
968 mvv_write(0x04, mem_base
>>12); /* Set the memory area */
970 /* Ok now load the defaults */
974 if(i2c_defs
[i
]==0xFF)
975 pms_i2c_andor(0x8A, i
, 0x07,0x00);
977 pms_i2c_write(0x8A, i
, i2c_defs
[i
]);
980 pms_i2c_write(0xB8,0x00,0x12);
981 pms_i2c_write(0xB8,0x04,0x00);
982 pms_i2c_write(0xB8,0x07,0x00);
983 pms_i2c_write(0xB8,0x08,0x00);
984 pms_i2c_write(0xB8,0x09,0xFF);
985 pms_i2c_write(0xB8,0x0A,0x00);
986 pms_i2c_write(0xB8,0x0B,0x10);
987 pms_i2c_write(0xB8,0x10,0x03);
989 mvv_write(0x01, 0x00);
990 mvv_write(0x05, 0xA0);
991 mvv_write(0x08, 0x25);
992 mvv_write(0x09, 0x00);
993 mvv_write(0x0A, 0x20|MVVMEMORYWIDTH
);
995 mvv_write(0x10, 0x02);
996 mvv_write(0x1E, 0x0C);
997 mvv_write(0x1F, 0x03);
998 mvv_write(0x26, 0x06);
1000 mvv_write(0x2B, 0x00);
1001 mvv_write(0x2C, 0x20);
1002 mvv_write(0x2D, 0x00);
1003 mvv_write(0x2F, 0x70);
1004 mvv_write(0x32, 0x00);
1005 mvv_write(0x33, MVVMEMORYWIDTH
);
1006 mvv_write(0x34, 0x00);
1007 mvv_write(0x35, 0x00);
1008 mvv_write(0x3A, 0x80);
1009 mvv_write(0x3B, 0x10);
1010 mvv_write(0x20, 0x00);
1011 mvv_write(0x21, 0x00);
1012 mvv_write(0x30, 0x22);
1017 * Initialization and module stuff
1020 static int __init
init_pms_cards(void)
1022 printk(KERN_INFO
"Mediavision Pro Movie Studio driver 0.02\n");
1024 data_port
= io_port
+1;
1026 if(init_mediavision())
1028 printk(KERN_INFO
"Board not found.\n");
1031 memcpy(&pms_device
, &pms_template
, sizeof(pms_template
));
1032 init_MUTEX(&pms_device
.lock
);
1033 pms_device
.height
=240;
1034 pms_device
.width
=320;
1036 pms_resolution(320,240);
1037 return video_register_device((struct video_device
*)&pms_device
, VFL_TYPE_GRABBER
, video_nr
);
1040 module_param(io_port
, int, 0);
1041 module_param(mem_base
, int, 0);
1042 module_param(video_nr
, int, 0);
1043 MODULE_LICENSE("GPL");
1046 static void __exit
shutdown_mediavision(void)
1048 release_region(io_port
,3);
1049 release_region(0x9A01, 1);
1052 static void __exit
cleanup_pms_module(void)
1054 shutdown_mediavision();
1055 video_unregister_device((struct video_device
*)&pms_device
);
1059 module_init(init_pms_cards
);
1060 module_exit(cleanup_pms_module
);