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 #include <linux/module.h>
18 #include <linux/delay.h>
19 #include <linux/errno.h>
21 #include <linux/kernel.h>
22 #include <linux/slab.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;
44 struct semaphore lock;
55 static int i2c_count = 0;
56 static struct i2c_info i2cinfo[64];
58 static int decoder = PHILIPS2;
59 static int standard = 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
62 * I/O ports and Shared Memory
65 static int io_port = 0x250;
66 static int data_port = 0x251;
67 static int mem_base = 0xC8000;
68 static int video_nr = -1;
72 static inline void mvv_write(u8 index, u8 value)
74 outw(index|(value<<8), io_port);
77 static inline u8 mvv_read(u8 index)
80 return inb(data_port);
83 static int pms_i2c_stat(u8 slave)
91 while((inb(data_port)&0x01)==0)
95 while((inb(data_port)&0x01)!=0)
102 while((inb(data_port)&0x01)==0)
106 while((inb(data_port)&0x01)!=0)
112 char st=inb(data_port);
119 return inb(data_port);
122 static int pms_i2c_write(u16 slave, u16 sub, u16 data)
128 for(i=0;i<i2c_count;i++)
130 if((i2cinfo[i].slave==slave) &&
131 (i2cinfo[i].sub == sub))
133 if(i2cinfo[i].data==data)
135 i2cinfo[i].data=data;
140 if(i==i2c_count && i2c_count<64)
142 i2cinfo[i2c_count].slave=slave;
143 i2cinfo[i2c_count].sub=sub;
144 i2cinfo[i2c_count].data=data;
151 mvv_write(0x29, sub);
152 mvv_write(0x2A, data);
153 mvv_write(0x28, slave);
158 while((inb(data_port)&1)==0)
161 while((inb(data_port)&1)!=0)
165 count=inb(data_port);
172 static int pms_i2c_read(int slave, int sub)
175 for(i=0;i<i2c_count;i++)
177 if(i2cinfo[i].slave==slave && i2cinfo[i].sub==sub)
178 return i2cinfo[i].data;
184 static void pms_i2c_andor(int slave, int sub, int and, int or)
188 tmp=pms_i2c_read(slave, sub);
190 pms_i2c_write(slave, sub, tmp);
198 static void pms_videosource(short source)
200 mvv_write(0x2E, source?0x31:0x30);
203 static void pms_hue(short hue)
208 pms_i2c_write(0x8A, 0x00, hue);
211 pms_i2c_write(0x8A, 0x07, hue);
214 pms_i2c_write(0x42, 0x07, hue);
219 static void pms_colour(short colour)
224 pms_i2c_write(0x8A, 0x00, colour);
227 pms_i2c_write(0x42, 0x12, colour);
233 static void pms_contrast(short contrast)
238 pms_i2c_write(0x8A, 0x00, contrast);
241 pms_i2c_write(0x42, 0x13, contrast);
246 static void pms_brightness(short brightness)
251 pms_i2c_write(0x8A, 0x00, brightness);
252 pms_i2c_write(0x8A, 0x00, brightness);
253 pms_i2c_write(0x8A, 0x00, brightness);
256 pms_i2c_write(0x42, 0x19, brightness);
262 static void pms_format(short format)
267 if(decoder==PHILIPS1)
269 else if(decoder==PHILIPS2)
277 pms_i2c_andor(target, 0x0D, 0xFE,0x00);
278 pms_i2c_andor(target, 0x0F, 0x3F,0x80);
281 pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
282 pms_i2c_andor(target, 0x0F, 0x3F, 0x40);
285 pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
286 pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
289 pms_i2c_andor(target, 0x0D, 0xFE, 0x01);
290 pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
295 #ifdef FOR_FUTURE_EXPANSION
298 * These features of the PMS card are not currently exposes. They
299 * could become a private v4l ioctl for PMSCONFIG or somesuch if
300 * people need it. We also don't yet use the PMS interrupt.
303 static void pms_hstart(short start)
308 pms_i2c_write(0x8A, 0x05, start);
309 pms_i2c_write(0x8A, 0x18, start);
312 pms_i2c_write(0x42, 0x05, start);
313 pms_i2c_write(0x42, 0x18, start);
322 static void pms_bandpass(short pass)
324 if(decoder==PHILIPS2)
325 pms_i2c_andor(0x8A, 0x06, 0xCF, (pass&0x03)<<4);
326 else if(decoder==PHILIPS1)
327 pms_i2c_andor(0x42, 0x06, 0xCF, (pass&0x03)<<4);
330 static void pms_antisnow(short snow)
332 if(decoder==PHILIPS2)
333 pms_i2c_andor(0x8A, 0x06, 0xF3, (snow&0x03)<<2);
334 else if(decoder==PHILIPS1)
335 pms_i2c_andor(0x42, 0x06, 0xF3, (snow&0x03)<<2);
338 static void pms_sharpness(short sharp)
340 if(decoder==PHILIPS2)
341 pms_i2c_andor(0x8A, 0x06, 0xFC, sharp&0x03);
342 else if(decoder==PHILIPS1)
343 pms_i2c_andor(0x42, 0x06, 0xFC, sharp&0x03);
346 static void pms_chromaagc(short agc)
348 if(decoder==PHILIPS2)
349 pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc&0x03)<<5);
350 else if(decoder==PHILIPS1)
351 pms_i2c_andor(0x42, 0x0C, 0x9F, (agc&0x03)<<5);
354 static void pms_vertnoise(short noise)
356 if(decoder==PHILIPS2)
357 pms_i2c_andor(0x8A, 0x10, 0xFC, noise&3);
358 else if(decoder==PHILIPS1)
359 pms_i2c_andor(0x42, 0x10, 0xFC, noise&3);
362 static void pms_forcecolour(short colour)
364 if(decoder==PHILIPS2)
365 pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour&1)<<7);
366 else if(decoder==PHILIPS1)
367 pms_i2c_andor(0x42, 0x0C, 0x7, (colour&1)<<7);
370 static void pms_antigamma(short gamma)
372 if(decoder==PHILIPS2)
373 pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma&1)<<7);
374 else if(decoder==PHILIPS1)
375 pms_i2c_andor(0x42, 0x20, 0x7, (gamma&1)<<7);
378 static void pms_prefilter(short filter)
380 if(decoder==PHILIPS2)
381 pms_i2c_andor(0x8A, 0x06, 0xBF, (filter&1)<<6);
382 else if(decoder==PHILIPS1)
383 pms_i2c_andor(0x42, 0x06, 0xBF, (filter&1)<<6);
386 static void pms_hfilter(short filter)
388 if(decoder==PHILIPS2)
389 pms_i2c_andor(0xB8, 0x04, 0x1F, (filter&7)<<5);
390 else if(decoder==PHILIPS1)
391 pms_i2c_andor(0x42, 0x24, 0x1F, (filter&7)<<5);
394 static void pms_vfilter(short filter)
396 if(decoder==PHILIPS2)
397 pms_i2c_andor(0xB8, 0x08, 0x9F, (filter&3)<<5);
398 else if(decoder==PHILIPS1)
399 pms_i2c_andor(0x42, 0x28, 0x9F, (filter&3)<<5);
402 static void pms_killcolour(short colour)
404 if(decoder==PHILIPS2)
406 pms_i2c_andor(0x8A, 0x08, 0x07, (colour&0x1F)<<3);
407 pms_i2c_andor(0x8A, 0x09, 0x07, (colour&0x1F)<<3);
409 else if(decoder==PHILIPS1)
411 pms_i2c_andor(0x42, 0x08, 0x07, (colour&0x1F)<<3);
412 pms_i2c_andor(0x42, 0x09, 0x07, (colour&0x1F)<<3);
416 static void pms_chromagain(short chroma)
418 if(decoder==PHILIPS2)
420 pms_i2c_write(0x8A, 0x11, chroma);
422 else if(decoder==PHILIPS1)
424 pms_i2c_write(0x42, 0x11, chroma);
429 static void pms_spacialcompl(short data)
431 mvv_write(0x3B, data);
434 static void pms_spacialcomph(short data)
436 mvv_write(0x3A, data);
439 static void pms_vstart(short start)
441 mvv_write(0x16, start);
442 mvv_write(0x17, (start>>8)&0x01);
447 static void pms_secamcross(short cross)
449 if(decoder==PHILIPS2)
450 pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5);
451 else if(decoder==PHILIPS1)
452 pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);
456 static void pms_swsense(short sense)
458 if(decoder==PHILIPS2)
460 pms_i2c_write(0x8A, 0x0A, sense);
461 pms_i2c_write(0x8A, 0x0B, sense);
463 else if(decoder==PHILIPS1)
465 pms_i2c_write(0x42, 0x0A, sense);
466 pms_i2c_write(0x42, 0x0B, sense);
471 static void pms_framerate(short frr)
473 int fps=(standard==1)?30:25;
477 mvv_write(0x14,0x80|fps);
481 static void pms_vert(u8 deciden, u8 decinum)
483 mvv_write(0x1C, deciden); /* Denominator */
484 mvv_write(0x1D, decinum); /* Numerator */
488 * Turn 16bit ratios into best small ratio the chipset can grok
491 static void pms_vertdeci(unsigned short decinum, unsigned short deciden)
493 /* Knock it down by /5 once */
502 while(decinum%3==0 && deciden%3==0)
510 while(decinum%2==0 && deciden%2==0)
521 decinum=(decinum+1)/2;
525 pms_vert(deciden,decinum);
528 static void pms_horzdeci(short decinum, short deciden)
541 deciden=640; /* 768 would be ideal */
544 while(((decinum|deciden)&1)==0)
552 decinum=(decinum+1)>>1;
557 mvv_write(0x24, 0x80|deciden);
558 mvv_write(0x25, decinum);
561 static void pms_resolution(short width, short height)
569 mvv_write(0x18, fg_height);
570 mvv_write(0x19, fg_height>>8);
574 mvv_write(0x1A, 0xFC);
575 mvv_write(0x1B, 0x00);
577 pms_vertdeci(240,240);
579 pms_vertdeci(fg_height,240);
583 mvv_write(0x1A, 0x1A);
584 mvv_write(0x1B, 0x01);
586 pms_vertdeci(270,270);
588 pms_vertdeci(fg_height, 270);
591 mvv_write(0x13, MVVMEMORYWIDTH);
592 mvv_write(0x42, 0x00);
593 mvv_write(0x43, 0x00);
594 mvv_write(0x44, MVVMEMORYWIDTH);
596 mvv_write(0x22, width+8);
597 mvv_write(0x23, (width+8)>> 8);
600 pms_horzdeci(width,640);
602 pms_horzdeci(width+8, 768);
604 mvv_write(0x30, mvv_read(0x30)&0xFE);
605 mvv_write(0x08, mvv_read(0x08)|0x01);
606 mvv_write(0x01, mvv_read(0x01)&0xFD);
607 mvv_write(0x32, 0x00);
608 mvv_write(0x33, MVVMEMORYWIDTH);
616 static void pms_vcrinput(short input)
618 if(decoder==PHILIPS2)
619 pms_i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7);
620 else if(decoder==PHILIPS1)
621 pms_i2c_andor(0x42,0x0D,0x7F,(input&1)<<7);
625 static int pms_capture(struct pms_device *dev, char *buf, int rgb555, unsigned long count)
628 int dw = 2*dev->width;
631 char tmp[dw+32]; /* using a temp buffer is faster than direct */
634 unsigned char r8 = 0x5; /* value for reg8 */
637 r8 |= 0x20; /* else use untranslated rgb = 565 */
638 mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */
640 /* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
642 for (y = 0; y < dev->height; y++ )
644 isa_writeb(0, src); /* synchronisiert neue Zeile */
647 * This is in truth a fifo, be very careful as if you
648 * forgot this odd things will occur 8)
651 isa_memcpy_fromio(tmp, src, dw+32); /* discard 16 word */
662 copy_to_user(buf, tmp+32, dt);
672 * Video4linux interfacing
675 static int pms_open(struct video_device *dev, int flags)
680 static void pms_close(struct video_device *dev)
684 static long pms_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
689 static int pms_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
691 struct pms_device *pd=(struct pms_device *)dev;
697 struct video_capability b;
698 strcpy(b.name, "Mediavision PMS");
699 b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
706 if(copy_to_user(arg, &b,sizeof(b)))
712 struct video_channel v;
713 if(copy_from_user(&v, arg, sizeof(v)))
715 if(v.channel<0 || v.channel>3)
719 /* Good question.. its composite or SVHS so.. */
720 v.type = VIDEO_TYPE_CAMERA;
724 strcpy(v.name, "Composite");break;
726 strcpy(v.name, "SVideo");break;
728 strcpy(v.name, "Composite(VCR)");break;
730 strcpy(v.name, "SVideo(VCR)");break;
732 if(copy_to_user(arg, &v, sizeof(v)))
739 if(copy_from_user(&v, arg,sizeof(v)))
744 pms_videosource(v&1);
751 struct video_tuner v;
752 if(copy_from_user(&v, arg, sizeof(v))!=0)
756 strcpy(v.name, "Format");
759 v.flags= VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
763 v.mode = VIDEO_MODE_AUTO;
766 v.mode = VIDEO_MODE_NTSC;
769 v.mode = VIDEO_MODE_PAL;
772 v.mode = VIDEO_MODE_SECAM;
775 if(copy_to_user(arg,&v,sizeof(v))!=0)
781 struct video_tuner v;
782 if(copy_from_user(&v, arg, sizeof(v))!=0)
789 case VIDEO_MODE_AUTO:
794 case VIDEO_MODE_NTSC:
804 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)))
838 pms_brightness(p.brightness>>8);
840 pms_colour(p.colour>>8);
841 pms_contrast(p.contrast>>8);
847 struct video_window vw;
848 if(copy_from_user(&vw, arg,sizeof(vw)))
854 if(vw.height<16||vw.height>480)
856 if(vw.width<16||vw.width>640)
859 pd->height=vw.height;
861 pms_resolution(pd->width, pd->height);
862 up(&pd->lock); /* Ok we figured out what to use from our wide choice */
867 struct video_window vw;
871 vw.height=pd->height;
874 if(copy_to_user(arg, &vw, sizeof(vw)))
900 static long pms_read(struct video_device *v, char *buf, unsigned long count, int noblock)
902 struct pms_device *pd=(struct pms_device *)v;
906 len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
912 struct video_device pms_template=
915 name: "Mediavision PMS",
916 type: VID_TYPE_CAPTURE,
917 hardware: VID_HARDWARE_PMS,
925 struct pms_device pms_device;
929 * Probe for and initialise the Mediavision PMS
932 static int init_mediavision(void)
938 unsigned char i2c_defs[]={
948 if (!request_region(0x9A01, 1, "Mediavision PMS config"))
950 printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
953 if (!request_region(io_port, 3, "Mediavision PMS"))
955 printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port);
956 release_region(0x9A01, 1);
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);
977 release_region(io_port, 3);
978 release_region(0x9A01, 1);
983 * Ok we have a PMS of some sort
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 init_MUTEX(&pms_device.lock);
1051 pms_device.height=240;
1052 pms_device.width=320;
1054 pms_resolution(320,240);
1055 return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr);
1058 MODULE_PARM(io_port,"i");
1059 MODULE_PARM(mem_base,"i");
1060 MODULE_PARM(video_nr,"i");
1061 MODULE_LICENSE("GPL");
1064 static void __exit shutdown_mediavision(void)
1066 release_region(io_port,3);
1067 release_region(0x9A01, 1);
1070 static void __exit cleanup_pms_module(void)
1072 shutdown_mediavision();
1073 video_unregister_device((struct video_device *)&pms_device);
1076 module_init(init_pms_cards);
1077 module_exit(cleanup_pms_module);