📄 pms.c
字号:
/* * Media Vision Pro Movie Studio * or * "all you need is an I2C bus some RAM and a prayer" * * This draws heavily on code * * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994 * Kiefernring 15 * 14478 Potsdam, Germany * * Most of this code is directly derived from his userspace driver. * His driver works so send any reports to alan@redhat.com unless the * userspace driver also doesnt work for you... */#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/init.h>#include <asm/io.h>#include <linux/sched.h>#include <linux/videodev.h>#include <linux/version.h>#include <asm/uaccess.h>#define MOTOROLA 1#define PHILIPS2 2#define PHILIPS1 3#define MVVMEMORYWIDTH 0x40 /* 512 bytes */struct pms_device{ struct video_device v; struct video_picture picture; int height; int width; struct semaphore lock;};struct i2c_info{ u8 slave; u8 sub; u8 data; u8 hits;};static int i2c_count = 0;static struct i2c_info i2cinfo[64];static int decoder = PHILIPS2;static int standard = 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam *//* * I/O ports and Shared Memory */ static int io_port = 0x250;static int data_port = 0x251;static int mem_base = 0xC8000;static int video_nr = -1; extern __inline__ void mvv_write(u8 index, u8 value){ outw(index|(value<<8), io_port);}extern __inline__ u8 mvv_read(u8 index){ outb(index, io_port); return inb(data_port);}static int pms_i2c_stat(u8 slave){ int counter; int i; outb(0x28, io_port); counter=0; while((inb(data_port)&0x01)==0) if(counter++==256) break; while((inb(data_port)&0x01)!=0) if(counter++==256) break; outb(slave, io_port); counter=0; while((inb(data_port)&0x01)==0) if(counter++==256) break; while((inb(data_port)&0x01)!=0) if(counter++==256) break; for(i=0;i<12;i++) { char st=inb(data_port); if((st&2)!=0) return -1; if((st&1)==0) break; } outb(0x29, io_port); return inb(data_port); }static int pms_i2c_write(u16 slave, u16 sub, u16 data){ int skip=0; int count; int i; for(i=0;i<i2c_count;i++) { if((i2cinfo[i].slave==slave) && (i2cinfo[i].sub == sub)) { if(i2cinfo[i].data==data) skip=1; i2cinfo[i].data=data; i=i2c_count+1; } } if(i==i2c_count && i2c_count<64) { i2cinfo[i2c_count].slave=slave; i2cinfo[i2c_count].sub=sub; i2cinfo[i2c_count].data=data; i2c_count++; } if(skip) return 0; mvv_write(0x29, sub); mvv_write(0x2A, data); mvv_write(0x28, slave); outb(0x28, io_port); count=0; while((inb(data_port)&1)==0) if(count>255) break; while((inb(data_port)&1)!=0) if(count>255) break; count=inb(data_port); if(count&2) return -1; return count;}static int pms_i2c_read(int slave, int sub){ int i=0; for(i=0;i<i2c_count;i++) { if(i2cinfo[i].slave==slave && i2cinfo[i].sub==sub) return i2cinfo[i].data; } return 0;}static void pms_i2c_andor(int slave, int sub, int and, int or){ u8 tmp; tmp=pms_i2c_read(slave, sub); tmp = (tmp&and)|or; pms_i2c_write(slave, sub, tmp);}/* * Control functions */ static void pms_videosource(short source){ mvv_write(0x2E, source?0x31:0x30);}static void pms_hue(short hue){ switch(decoder) { case MOTOROLA: pms_i2c_write(0x8A, 0x00, hue); break; case PHILIPS2: pms_i2c_write(0x8A, 0x07, hue); break; case PHILIPS1: pms_i2c_write(0x42, 0x07, hue); break; }}static void pms_colour(short colour){ switch(decoder) { case MOTOROLA: pms_i2c_write(0x8A, 0x00, colour); break; case PHILIPS1: pms_i2c_write(0x42, 0x12, colour); break; }} static void pms_contrast(short contrast){ switch(decoder) { case MOTOROLA: pms_i2c_write(0x8A, 0x00, contrast); break; case PHILIPS1: pms_i2c_write(0x42, 0x13, contrast); break; }}static void pms_brightness(short brightness){ switch(decoder) { case MOTOROLA: pms_i2c_write(0x8A, 0x00, brightness); pms_i2c_write(0x8A, 0x00, brightness); pms_i2c_write(0x8A, 0x00, brightness); break; case PHILIPS1: pms_i2c_write(0x42, 0x19, brightness); break; }}static void pms_format(short format){ int target; standard = format; if(decoder==PHILIPS1) target=0x42; else if(decoder==PHILIPS2) target=0x8A; else return; switch(format) { case 0: /* Auto */ pms_i2c_andor(target, 0x0D, 0xFE,0x00); pms_i2c_andor(target, 0x0F, 0x3F,0x80); break; case 1: /* NTSC */ pms_i2c_andor(target, 0x0D, 0xFE, 0x00); pms_i2c_andor(target, 0x0F, 0x3F, 0x40); break; case 2: /* PAL */ pms_i2c_andor(target, 0x0D, 0xFE, 0x00); pms_i2c_andor(target, 0x0F, 0x3F, 0x00); break; case 3: /* SECAM */ pms_i2c_andor(target, 0x0D, 0xFE, 0x01); pms_i2c_andor(target, 0x0F, 0x3F, 0x00); break; }}#ifdef FOR_FUTURE_EXPANSION/* * These features of the PMS card are not currently exposes. They * could become a private v4l ioctl for PMSCONFIG or somesuch if * people need it. We also don't yet use the PMS interrupt. */static void pms_hstart(short start){ switch(decoder) { case PHILIPS1: pms_i2c_write(0x8A, 0x05, start); pms_i2c_write(0x8A, 0x18, start); break; case PHILIPS2: pms_i2c_write(0x42, 0x05, start); pms_i2c_write(0x42, 0x18, start); break; }}/* * Bandpass filters */ static void pms_bandpass(short pass){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x06, 0xCF, (pass&0x03)<<4); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x06, 0xCF, (pass&0x03)<<4);}static void pms_antisnow(short snow){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x06, 0xF3, (snow&0x03)<<2); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x06, 0xF3, (snow&0x03)<<2);}static void pms_sharpness(short sharp){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x06, 0xFC, sharp&0x03); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x06, 0xFC, sharp&0x03);}static void pms_chromaagc(short agc){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc&0x03)<<5); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x0C, 0x9F, (agc&0x03)<<5);}static void pms_vertnoise(short noise){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x10, 0xFC, noise&3); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x10, 0xFC, noise&3);}static void pms_forcecolour(short colour){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour&1)<<7); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x0C, 0x7, (colour&1)<<7);}static void pms_antigamma(short gamma){ if(decoder==PHILIPS2) pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma&1)<<7); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x20, 0x7, (gamma&1)<<7);}static void pms_prefilter(short filter){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x06, 0xBF, (filter&1)<<6); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x06, 0xBF, (filter&1)<<6);}static void pms_hfilter(short filter){ if(decoder==PHILIPS2) pms_i2c_andor(0xB8, 0x04, 0x1F, (filter&7)<<5); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x24, 0x1F, (filter&7)<<5);}static void pms_vfilter(short filter){ if(decoder==PHILIPS2) pms_i2c_andor(0xB8, 0x08, 0x9F, (filter&3)<<5); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x28, 0x9F, (filter&3)<<5);}static void pms_killcolour(short colour){ if(decoder==PHILIPS2) { pms_i2c_andor(0x8A, 0x08, 0x07, (colour&0x1F)<<3); pms_i2c_andor(0x8A, 0x09, 0x07, (colour&0x1F)<<3); } else if(decoder==PHILIPS1) { pms_i2c_andor(0x42, 0x08, 0x07, (colour&0x1F)<<3); pms_i2c_andor(0x42, 0x09, 0x07, (colour&0x1F)<<3); }}static void pms_chromagain(short chroma){ if(decoder==PHILIPS2) { pms_i2c_write(0x8A, 0x11, chroma); } else if(decoder==PHILIPS1) { pms_i2c_write(0x42, 0x11, chroma); }}static void pms_spacialcompl(short data){ mvv_write(0x3B, data);}static void pms_spacialcomph(short data){ mvv_write(0x3A, data);}static void pms_vstart(short start){ mvv_write(0x16, start); mvv_write(0x17, (start>>8)&0x01);}#endifstatic void pms_secamcross(short cross){ if(decoder==PHILIPS2) pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5); else if(decoder==PHILIPS1) pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);}static void pms_swsense(short sense){ if(decoder==PHILIPS2) { pms_i2c_write(0x8A, 0x0A, sense); pms_i2c_write(0x8A, 0x0B, sense); } else if(decoder==PHILIPS1) { pms_i2c_write(0x42, 0x0A, sense); pms_i2c_write(0x42, 0x0B, sense); }}static void pms_framerate(short frr){ int fps=(standard==1)?30:25; if(frr==0) return; fps=fps/frr; mvv_write(0x14,0x80|fps); mvv_write(0x15,1);}static void pms_vert(u8 deciden, u8 decinum){ mvv_write(0x1C, deciden); /* Denominator */ mvv_write(0x1D, decinum); /* Numerator */}/* * Turn 16bit ratios into best small ratio the chipset can grok */ static void pms_vertdeci(unsigned short decinum, unsigned short deciden){ /* Knock it down by /5 once */ if(decinum%5==0) { deciden/=5; decinum/=5; } /* * 3's */ while(decinum%3==0 && deciden%3==0) { deciden/=3; decinum/=3; } /* * 2's */ while(decinum%2==0 && deciden%2==0) { decinum/=2; deciden/=2; } /* * Fudgyify */ while(deciden>32) { deciden/=2; decinum=(decinum+1)/2; } if(deciden==32) deciden--; pms_vert(deciden,decinum);}static void pms_horzdeci(short decinum, short deciden){ if(decinum<=512) { if(decinum%5==0) { decinum/=5; deciden/=5; } } else { decinum=512;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -