linux/drivers/media/video/pms.c
<<
>>
Prefs
   1/*
   2 *      Media Vision Pro Movie Studio
   3 *                      or
   4 *      "all you need is an I2C bus some RAM and a prayer"
   5 *
   6 *      This draws heavily on code
   7 *
   8 *      (c) Wolfgang Koehler,  wolf@first.gmd.de, Dec. 1994
   9 *      Kiefernring 15
  10 *      14478 Potsdam, Germany
  11 *
  12 *      Most of this code is directly derived from his userspace driver.
  13 *      His driver works so send any reports to alan@lxorguk.ukuu.org.uk
  14 *      unless the userspace driver also doesn't work for you...
  15 *
  16 *      Changes:
  17 *      08/07/2003        Daniele Bellucci <bellucda@tiscali.it>
  18 *                        - pms_capture: report back -EFAULT
  19 */
  20
  21#include <linux/module.h>
  22#include <linux/delay.h>
  23#include <linux/errno.h>
  24#include <linux/fs.h>
  25#include <linux/kernel.h>
  26#include <linux/slab.h>
  27#include <linux/mm.h>
  28#include <linux/ioport.h>
  29#include <linux/init.h>
  30#include <asm/io.h>
  31#include <linux/videodev.h>
  32#include <media/v4l2-common.h>
  33#include <media/v4l2-ioctl.h>
  34#include <linux/mutex.h>
  35
  36#include <asm/uaccess.h>
  37
  38
  39#define MOTOROLA        1
  40#define PHILIPS2        2
  41#define PHILIPS1        3
  42#define MVVMEMORYWIDTH  0x40            /* 512 bytes */
  43
  44struct pms_device
  45{
  46        struct video_device v;
  47        struct video_picture picture;
  48        int height;
  49        int width;
  50        unsigned long in_use;
  51        struct mutex lock;
  52};
  53
  54struct i2c_info
  55{
  56        u8 slave;
  57        u8 sub;
  58        u8 data;
  59        u8 hits;
  60};
  61
  62static int i2c_count;
  63static struct i2c_info i2cinfo[64];
  64
  65static int decoder              = PHILIPS2;
  66static int standard;    /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
  67
  68/*
  69 *      I/O ports and Shared Memory
  70 */
  71
  72static int io_port              =       0x250;
  73static int data_port            =       0x251;
  74static int mem_base             =       0xC8000;
  75static void __iomem *mem;
  76static int video_nr             =       -1;
  77
  78
  79
  80static inline void mvv_write(u8 index, u8 value)
  81{
  82        outw(index|(value<<8), io_port);
  83}
  84
  85static inline u8 mvv_read(u8 index)
  86{
  87        outb(index, io_port);
  88        return inb(data_port);
  89}
  90
  91static int pms_i2c_stat(u8 slave)
  92{
  93        int counter;
  94        int i;
  95
  96        outb(0x28, io_port);
  97
  98        counter=0;
  99        while((inb(data_port)&0x01)==0)
 100                if(counter++==256)
 101                        break;
 102
 103        while((inb(data_port)&0x01)!=0)
 104                if(counter++==256)
 105                        break;
 106
 107        outb(slave, io_port);
 108
 109        counter=0;
 110        while((inb(data_port)&0x01)==0)
 111                if(counter++==256)
 112                        break;
 113
 114        while((inb(data_port)&0x01)!=0)
 115                if(counter++==256)
 116                        break;
 117
 118        for(i=0;i<12;i++)
 119        {
 120                char st=inb(data_port);
 121                if((st&2)!=0)
 122                        return -1;
 123                if((st&1)==0)
 124                        break;
 125        }
 126        outb(0x29, io_port);
 127        return inb(data_port);
 128}
 129
 130static int pms_i2c_write(u16 slave, u16 sub, u16 data)
 131{
 132        int skip=0;
 133        int count;
 134        int i;
 135
 136        for(i=0;i<i2c_count;i++)
 137        {
 138                if((i2cinfo[i].slave==slave) &&
 139                   (i2cinfo[i].sub == sub))
 140                {
 141                        if(i2cinfo[i].data==data)
 142                                skip=1;
 143                        i2cinfo[i].data=data;
 144                        i=i2c_count+1;
 145                }
 146        }
 147
 148        if(i==i2c_count && i2c_count<64)
 149        {
 150                i2cinfo[i2c_count].slave=slave;
 151                i2cinfo[i2c_count].sub=sub;
 152                i2cinfo[i2c_count].data=data;
 153                i2c_count++;
 154        }
 155
 156        if(skip)
 157                return 0;
 158
 159        mvv_write(0x29, sub);
 160        mvv_write(0x2A, data);
 161        mvv_write(0x28, slave);
 162
 163        outb(0x28, io_port);
 164
 165        count=0;
 166        while((inb(data_port)&1)==0)
 167                if(count>255)
 168                        break;
 169        while((inb(data_port)&1)!=0)
 170                if(count>255)
 171                        break;
 172
 173        count=inb(data_port);
 174
 175        if(count&2)
 176                return -1;
 177        return count;
 178}
 179
 180static int pms_i2c_read(int slave, int sub)
 181{
 182        int i=0;
 183        for(i=0;i<i2c_count;i++)
 184        {
 185                if(i2cinfo[i].slave==slave && i2cinfo[i].sub==sub)
 186                        return i2cinfo[i].data;
 187        }
 188        return 0;
 189}
 190
 191
 192static void pms_i2c_andor(int slave, int sub, int and, int or)
 193{
 194        u8 tmp;
 195
 196        tmp=pms_i2c_read(slave, sub);
 197        tmp = (tmp&and)|or;
 198        pms_i2c_write(slave, sub, tmp);
 199}
 200
 201/*
 202 *      Control functions
 203 */
 204
 205
 206static void pms_videosource(short source)
 207{
 208        mvv_write(0x2E, source?0x31:0x30);
 209}
 210
 211static void pms_hue(short hue)
 212{
 213        switch(decoder)
 214        {
 215                case MOTOROLA:
 216                        pms_i2c_write(0x8A, 0x00, hue);
 217                        break;
 218                case PHILIPS2:
 219                        pms_i2c_write(0x8A, 0x07, hue);
 220                        break;
 221                case PHILIPS1:
 222                        pms_i2c_write(0x42, 0x07, hue);
 223                        break;
 224        }
 225}
 226
 227static void pms_colour(short colour)
 228{
 229        switch(decoder)
 230        {
 231                case MOTOROLA:
 232                        pms_i2c_write(0x8A, 0x00, colour);
 233                        break;
 234                case PHILIPS1:
 235                        pms_i2c_write(0x42, 0x12, colour);
 236                        break;
 237        }
 238}
 239
 240
 241static void pms_contrast(short contrast)
 242{
 243        switch(decoder)
 244        {
 245                case MOTOROLA:
 246                        pms_i2c_write(0x8A, 0x00, contrast);
 247                        break;
 248                case PHILIPS1:
 249                        pms_i2c_write(0x42, 0x13, contrast);
 250                        break;
 251        }
 252}
 253
 254static void pms_brightness(short brightness)
 255{
 256        switch(decoder)
 257        {
 258                case MOTOROLA:
 259                        pms_i2c_write(0x8A, 0x00, brightness);
 260                        pms_i2c_write(0x8A, 0x00, brightness);
 261                        pms_i2c_write(0x8A, 0x00, brightness);
 262                        break;
 263                case PHILIPS1:
 264                        pms_i2c_write(0x42, 0x19, brightness);
 265                        break;
 266        }
 267}
 268
 269
 270static void pms_format(short format)
 271{
 272        int target;
 273        standard = format;
 274
 275        if(decoder==PHILIPS1)
 276                target=0x42;
 277        else if(decoder==PHILIPS2)
 278                target=0x8A;
 279        else
 280                return;
 281
 282        switch(format)
 283        {
 284                case 0: /* Auto */
 285                        pms_i2c_andor(target, 0x0D, 0xFE,0x00);
 286                        pms_i2c_andor(target, 0x0F, 0x3F,0x80);
 287                        break;
 288                case 1: /* NTSC */
 289                        pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
 290                        pms_i2c_andor(target, 0x0F, 0x3F, 0x40);
 291                        break;
 292                case 2: /* PAL */
 293                        pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
 294                        pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
 295                        break;
 296                case 3: /* SECAM */
 297                        pms_i2c_andor(target, 0x0D, 0xFE, 0x01);
 298                        pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
 299                        break;
 300        }
 301}
 302
 303#ifdef FOR_FUTURE_EXPANSION
 304
 305/*
 306 *      These features of the PMS card are not currently exposes. They
 307 *      could become a private v4l ioctl for PMSCONFIG or somesuch if
 308 *      people need it. We also don't yet use the PMS interrupt.
 309 */
 310
 311static void pms_hstart(short start)
 312{
 313        switch(decoder)
 314        {
 315                case PHILIPS1:
 316                        pms_i2c_write(0x8A, 0x05, start);
 317                        pms_i2c_write(0x8A, 0x18, start);
 318                        break;
 319                case PHILIPS2:
 320                        pms_i2c_write(0x42, 0x05, start);
 321                        pms_i2c_write(0x42, 0x18, start);
 322                        break;
 323        }
 324}
 325
 326/*
 327 *      Bandpass filters
 328 */
 329
 330static void pms_bandpass(short pass)
 331{
 332        if(decoder==PHILIPS2)
 333                pms_i2c_andor(0x8A, 0x06, 0xCF, (pass&0x03)<<4);
 334        else if(decoder==PHILIPS1)
 335                pms_i2c_andor(0x42, 0x06, 0xCF, (pass&0x03)<<4);
 336}
 337
 338static void pms_antisnow(short snow)
 339{
 340        if(decoder==PHILIPS2)
 341                pms_i2c_andor(0x8A, 0x06, 0xF3, (snow&0x03)<<2);
 342        else if(decoder==PHILIPS1)
 343                pms_i2c_andor(0x42, 0x06, 0xF3, (snow&0x03)<<2);
 344}
 345
 346static void pms_sharpness(short sharp)
 347{
 348        if(decoder==PHILIPS2)
 349                pms_i2c_andor(0x8A, 0x06, 0xFC, sharp&0x03);
 350        else if(decoder==PHILIPS1)
 351                pms_i2c_andor(0x42, 0x06, 0xFC, sharp&0x03);
 352}
 353
 354static void pms_chromaagc(short agc)
 355{
 356        if(decoder==PHILIPS2)
 357                pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc&0x03)<<5);
 358        else if(decoder==PHILIPS1)
 359                pms_i2c_andor(0x42, 0x0C, 0x9F, (agc&0x03)<<5);
 360}
 361
 362static void pms_vertnoise(short noise)
 363{
 364        if(decoder==PHILIPS2)
 365                pms_i2c_andor(0x8A, 0x10, 0xFC, noise&3);
 366        else if(decoder==PHILIPS1)
 367                pms_i2c_andor(0x42, 0x10, 0xFC, noise&3);
 368}
 369
 370static void pms_forcecolour(short colour)
 371{
 372        if(decoder==PHILIPS2)
 373                pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour&1)<<7);
 374        else if(decoder==PHILIPS1)
 375                pms_i2c_andor(0x42, 0x0C, 0x7, (colour&1)<<7);
 376}
 377
 378static void pms_antigamma(short gamma)
 379{
 380        if(decoder==PHILIPS2)
 381                pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma&1)<<7);
 382        else if(decoder==PHILIPS1)
 383                pms_i2c_andor(0x42, 0x20, 0x7, (gamma&1)<<7);
 384}
 385
 386static void pms_prefilter(short filter)
 387{
 388        if(decoder==PHILIPS2)
 389                pms_i2c_andor(0x8A, 0x06, 0xBF, (filter&1)<<6);
 390        else if(decoder==PHILIPS1)
 391                pms_i2c_andor(0x42, 0x06, 0xBF, (filter&1)<<6);
 392}
 393
 394static void pms_hfilter(short filter)
 395{
 396        if(decoder==PHILIPS2)
 397                pms_i2c_andor(0xB8, 0x04, 0x1F, (filter&7)<<5);
 398        else if(decoder==PHILIPS1)
 399                pms_i2c_andor(0x42, 0x24, 0x1F, (filter&7)<<5);
 400}
 401
 402static void pms_vfilter(short filter)
 403{
 404        if(decoder==PHILIPS2)
 405                pms_i2c_andor(0xB8, 0x08, 0x9F, (filter&3)<<5);
 406        else if(decoder==PHILIPS1)
 407                pms_i2c_andor(0x42, 0x28, 0x9F, (filter&3)<<5);
 408}
 409
 410static void pms_killcolour(short colour)
 411{
 412        if(decoder==PHILIPS2)
 413        {
 414                pms_i2c_andor(0x8A, 0x08, 0x07, (colour&0x1F)<<3);
 415                pms_i2c_andor(0x8A, 0x09, 0x07, (colour&0x1F)<<3);
 416        }
 417        else if(decoder==PHILIPS1)
 418        {
 419                pms_i2c_andor(0x42, 0x08, 0x07, (colour&0x1F)<<3);
 420                pms_i2c_andor(0x42, 0x09, 0x07, (colour&0x1F)<<3);
 421        }
 422}
 423
 424static void pms_chromagain(short chroma)
 425{
 426        if(decoder==PHILIPS2)
 427        {
 428                pms_i2c_write(0x8A, 0x11, chroma);
 429        }
 430        else if(decoder==PHILIPS1)
 431        {
 432                pms_i2c_write(0x42, 0x11, chroma);
 433        }
 434}
 435
 436
 437static void pms_spacialcompl(short data)
 438{
 439        mvv_write(0x3B, data);
 440}
 441
 442static void pms_spacialcomph(short data)
 443{
 444        mvv_write(0x3A, data);
 445}
 446
 447static void pms_vstart(short start)
 448{
 449        mvv_write(0x16, start);
 450        mvv_write(0x17, (start>>8)&0x01);
 451}
 452
 453#endif
 454
 455static void pms_secamcross(short cross)
 456{
 457        if(decoder==PHILIPS2)
 458                pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5);
 459        else if(decoder==PHILIPS1)
 460                pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);
 461}
 462
 463
 464static void pms_swsense(short sense)
 465{
 466        if(decoder==PHILIPS2)
 467        {
 468                pms_i2c_write(0x8A, 0x0A, sense);
 469                pms_i2c_write(0x8A, 0x0B, sense);
 470        }
 471        else if(decoder==PHILIPS1)
 472        {
 473                pms_i2c_write(0x42, 0x0A, sense);
 474                pms_i2c_write(0x42, 0x0B, sense);
 475        }
 476}
 477
 478
 479static void pms_framerate(short frr)
 480{
 481        int fps=(standard==1)?30:25;
 482        if(frr==0)
 483                return;
 484        fps=fps/frr;
 485        mvv_write(0x14,0x80|fps);
 486        mvv_write(0x15,1);
 487}
 488
 489static void pms_vert(u8 deciden, u8 decinum)
 490{
 491        mvv_write(0x1C, deciden);       /* Denominator */
 492        mvv_write(0x1D, decinum);       /* Numerator */
 493}
 494
 495/*
 496 *      Turn 16bit ratios into best small ratio the chipset can grok
 497 */
 498
 499static void pms_vertdeci(unsigned short decinum, unsigned short deciden)
 500{
 501        /* Knock it down by /5 once */
 502        if(decinum%5==0)
 503        {
 504                deciden/=5;
 505                decinum/=5;
 506        }
 507        /*
 508         *      3's
 509         */
 510        while(decinum%3==0 && deciden%3==0)
 511        {
 512                deciden/=3;
 513                decinum/=3;
 514        }
 515        /*
 516         *      2's
 517         */
 518        while(decinum%2==0 && deciden%2==0)
 519        {
 520                decinum/=2;
 521                deciden/=2;
 522        }
 523        /*
 524         *      Fudgyify
 525         */
 526        while(deciden>32)
 527        {
 528                deciden/=2;
 529                decinum=(decinum+1)/2;
 530        }
 531        if(deciden==32)
 532                deciden--;
 533        pms_vert(deciden,decinum);
 534}
 535
 536static void pms_horzdeci(short decinum, short deciden)
 537{
 538        if(decinum<=512)
 539        {
 540                if(decinum%5==0)
 541                {
 542                        decinum/=5;
 543                        deciden/=5;
 544                }
 545        }
 546        else
 547        {
 548                decinum=512;
 549                deciden=640;    /* 768 would be ideal */
 550        }
 551
 552        while(((decinum|deciden)&1)==0)
 553        {
 554                decinum>>=1;
 555                deciden>>=1;
 556        }
 557        while(deciden>32)
 558        {
 559                deciden>>=1;
 560                decinum=(decinum+1)>>1;
 561        }
 562        if(deciden==32)
 563                deciden--;
 564
 565        mvv_write(0x24, 0x80|deciden);
 566        mvv_write(0x25, decinum);
 567}
 568
 569static void pms_resolution(short width, short height)
 570{
 571        int fg_height;
 572
 573        fg_height=height;
 574        if(fg_height>280)
 575                fg_height=280;
 576
 577        mvv_write(0x18, fg_height);
 578        mvv_write(0x19, fg_height>>8);
 579
 580        if(standard==1)
 581        {
 582                mvv_write(0x1A, 0xFC);
 583                mvv_write(0x1B, 0x00);
 584                if(height>fg_height)
 585                        pms_vertdeci(240,240);
 586                else
 587                        pms_vertdeci(fg_height,240);
 588        }
 589        else
 590        {
 591                mvv_write(0x1A, 0x1A);
 592                mvv_write(0x1B, 0x01);
 593                if(fg_height>256)
 594                        pms_vertdeci(270,270);
 595                else
 596                        pms_vertdeci(fg_height, 270);
 597        }
 598        mvv_write(0x12,0);
 599        mvv_write(0x13, MVVMEMORYWIDTH);
 600        mvv_write(0x42, 0x00);
 601        mvv_write(0x43, 0x00);
 602        mvv_write(0x44, MVVMEMORYWIDTH);
 603
 604        mvv_write(0x22, width+8);
 605        mvv_write(0x23, (width+8)>> 8);
 606
 607        if(standard==1)
 608                pms_horzdeci(width,640);
 609        else
 610                pms_horzdeci(width+8, 768);
 611
 612        mvv_write(0x30, mvv_read(0x30)&0xFE);
 613        mvv_write(0x08, mvv_read(0x08)|0x01);
 614        mvv_write(0x01, mvv_read(0x01)&0xFD);
 615        mvv_write(0x32, 0x00);
 616        mvv_write(0x33, MVVMEMORYWIDTH);
 617}
 618
 619
 620/*
 621 *      Set Input
 622 */
 623
 624static void pms_vcrinput(short input)
 625{
 626        if(decoder==PHILIPS2)
 627                pms_i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7);
 628        else if(decoder==PHILIPS1)
 629                pms_i2c_andor(0x42,0x0D,0x7F,(input&1)<<7);
 630}
 631
 632
 633static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int count)
 634{
 635        int y;
 636        int dw = 2*dev->width;
 637
 638        char tmp[dw+32]; /* using a temp buffer is faster than direct  */
 639        int cnt = 0;
 640        int len=0;
 641        unsigned char r8 = 0x5;  /* value for reg8  */
 642
 643        if (rgb555)
 644                r8 |= 0x20; /* else use untranslated rgb = 565 */
 645        mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */
 646
 647/*      printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
 648
 649        for (y = 0; y < dev->height; y++ )
 650        {
 651                writeb(0, mem);  /* synchronisiert neue Zeile */
 652
 653                /*
 654                 *      This is in truth a fifo, be very careful as if you
 655                 *      forgot this odd things will occur 8)
 656                 */
 657
 658                memcpy_fromio(tmp, mem, dw+32); /* discard 16 word   */
 659                cnt -= dev->height;
 660                while (cnt <= 0)
 661                {
 662                        /*
 663                         *      Don't copy too far
 664                         */
 665                        int dt=dw;
 666                        if(dt+len>count)
 667                                dt=count-len;
 668                        cnt += dev->height;
 669                        if (copy_to_user(buf, tmp+32, dt))
 670                                return len ? len : -EFAULT;
 671                        buf += dt;
 672                        len += dt;
 673                }
 674        }
 675        return len;
 676}
 677
 678
 679/*
 680 *      Video4linux interfacing
 681 */
 682
 683static long pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 684{
 685        struct video_device *dev = video_devdata(file);
 686        struct pms_device *pd=(struct pms_device *)dev;
 687
 688        switch(cmd)
 689        {
 690                case VIDIOCGCAP:
 691                {
 692                        struct video_capability *b = arg;
 693                        strcpy(b->name, "Mediavision PMS");
 694                        b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
 695                        b->channels = 4;
 696                        b->audios = 0;
 697                        b->maxwidth = 640;
 698                        b->maxheight = 480;
 699                        b->minwidth = 16;
 700                        b->minheight = 16;
 701                        return 0;
 702                }
 703                case VIDIOCGCHAN:
 704                {
 705                        struct video_channel *v = arg;
 706                        if(v->channel<0 || v->channel>3)
 707                                return -EINVAL;
 708                        v->flags=0;
 709                        v->tuners=1;
 710                        /* Good question.. its composite or SVHS so.. */
 711                        v->type = VIDEO_TYPE_CAMERA;
 712                        switch(v->channel)
 713                        {
 714                                case 0:
 715                                        strcpy(v->name, "Composite");break;
 716                                case 1:
 717                                        strcpy(v->name, "SVideo");break;
 718                                case 2:
 719                                        strcpy(v->name, "Composite(VCR)");break;
 720                                case 3:
 721                                        strcpy(v->name, "SVideo(VCR)");break;
 722                        }
 723                        return 0;
 724                }
 725                case VIDIOCSCHAN:
 726                {
 727                        struct video_channel *v = arg;
 728                        if(v->channel<0 || v->channel>3)
 729                                return -EINVAL;
 730                        mutex_lock(&pd->lock);
 731                        pms_videosource(v->channel&1);
 732                        pms_vcrinput(v->channel>>1);
 733                        mutex_unlock(&pd->lock);
 734                        return 0;
 735                }
 736                case VIDIOCGTUNER:
 737                {
 738                        struct video_tuner *v = arg;
 739                        if(v->tuner)
 740                                return -EINVAL;
 741                        strcpy(v->name, "Format");
 742                        v->rangelow=0;
 743                        v->rangehigh=0;
 744                        v->flags= VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
 745                        switch(standard)
 746                        {
 747                                case 0:
 748                                        v->mode = VIDEO_MODE_AUTO;
 749                                        break;
 750                                case 1:
 751                                        v->mode = VIDEO_MODE_NTSC;
 752                                        break;
 753                                case 2:
 754                                        v->mode = VIDEO_MODE_PAL;
 755                                        break;
 756                                case 3:
 757                                        v->mode = VIDEO_MODE_SECAM;
 758                                        break;
 759                        }
 760                        return 0;
 761                }
 762                case VIDIOCSTUNER:
 763                {
 764                        struct video_tuner *v = arg;
 765                        if(v->tuner)
 766                                return -EINVAL;
 767                        mutex_lock(&pd->lock);
 768                        switch(v->mode)
 769                        {
 770                                case VIDEO_MODE_AUTO:
 771                                        pms_framerate(25);
 772                                        pms_secamcross(0);
 773                                        pms_format(0);
 774                                        break;
 775                                case VIDEO_MODE_NTSC:
 776                                        pms_framerate(30);
 777                                        pms_secamcross(0);
 778                                        pms_format(1);
 779                                        break;
 780                                case VIDEO_MODE_PAL:
 781                                        pms_framerate(25);
 782                                        pms_secamcross(0);
 783                                        pms_format(2);
 784                                        break;
 785                                case VIDEO_MODE_SECAM:
 786                                        pms_framerate(25);
 787                                        pms_secamcross(1);
 788                                        pms_format(2);
 789                                        break;
 790                                default:
 791                                        mutex_unlock(&pd->lock);
 792                                        return -EINVAL;
 793                        }
 794                        mutex_unlock(&pd->lock);
 795                        return 0;
 796                }
 797                case VIDIOCGPICT:
 798                {
 799                        struct video_picture *p = arg;
 800                        *p = pd->picture;
 801                        return 0;
 802                }
 803                case VIDIOCSPICT:
 804                {
 805                        struct video_picture *p = arg;
 806                        if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
 807                            ||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
 808                                return -EINVAL;
 809                        pd->picture= *p;
 810
 811                        /*
 812                         *      Now load the card.
 813                         */
 814
 815                        mutex_lock(&pd->lock);
 816                        pms_brightness(p->brightness>>8);
 817                        pms_hue(p->hue>>8);
 818                        pms_colour(p->colour>>8);
 819                        pms_contrast(p->contrast>>8);
 820                        mutex_unlock(&pd->lock);
 821                        return 0;
 822                }
 823                case VIDIOCSWIN:
 824                {
 825                        struct video_window *vw = arg;
 826                        if(vw->flags)
 827                                return -EINVAL;
 828                        if(vw->clipcount)
 829                                return -EINVAL;
 830                        if(vw->height<16||vw->height>480)
 831                                return -EINVAL;
 832                        if(vw->width<16||vw->width>640)
 833                                return -EINVAL;
 834                        pd->width=vw->width;
 835                        pd->height=vw->height;
 836                        mutex_lock(&pd->lock);
 837                        pms_resolution(pd->width, pd->height);
 838                        mutex_unlock(&pd->lock);                        /* Ok we figured out what to use from our wide choice */
 839                        return 0;
 840                }
 841                case VIDIOCGWIN:
 842                {
 843                        struct video_window *vw = arg;
 844                        memset(vw,0,sizeof(*vw));
 845                        vw->width=pd->width;
 846                        vw->height=pd->height;
 847                        return 0;
 848                }
 849                case VIDIOCKEY:
 850                        return 0;
 851                case VIDIOCCAPTURE:
 852                case VIDIOCGFBUF:
 853                case VIDIOCSFBUF:
 854                case VIDIOCGFREQ:
 855                case VIDIOCSFREQ:
 856                case VIDIOCGAUDIO:
 857                case VIDIOCSAUDIO:
 858                        return -EINVAL;
 859                default:
 860                        return -ENOIOCTLCMD;
 861        }
 862        return 0;
 863}
 864
 865static long pms_ioctl(struct file *file,
 866                     unsigned int cmd, unsigned long arg)
 867{
 868        return video_usercopy(file, cmd, arg, pms_do_ioctl);
 869}
 870
 871static ssize_t pms_read(struct file *file, char __user *buf,
 872                    size_t count, loff_t *ppos)
 873{
 874        struct video_device *v = video_devdata(file);
 875        struct pms_device *pd=(struct pms_device *)v;
 876        int len;
 877
 878        mutex_lock(&pd->lock);
 879        len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
 880        mutex_unlock(&pd->lock);
 881        return len;
 882}
 883
 884static int pms_exclusive_open(struct file *file)
 885{
 886        struct video_device *v = video_devdata(file);
 887        struct pms_device *pd = (struct pms_device *)v;
 888
 889        return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0;
 890}
 891
 892static int pms_exclusive_release(struct file *file)
 893{
 894        struct video_device *v = video_devdata(file);
 895        struct pms_device *pd = (struct pms_device *)v;
 896
 897        clear_bit(0, &pd->in_use);
 898        return 0;
 899}
 900
 901static const struct v4l2_file_operations pms_fops = {
 902        .owner          = THIS_MODULE,
 903        .open           = pms_exclusive_open,
 904        .release        = pms_exclusive_release,
 905        .ioctl          = pms_ioctl,
 906        .read           = pms_read,
 907};
 908
 909static struct video_device pms_template=
 910{
 911        .name           = "Mediavision PMS",
 912        .fops           = &pms_fops,
 913        .release        = video_device_release_empty,
 914};
 915
 916static struct pms_device pms_device;
 917
 918
 919/*
 920 *      Probe for and initialise the Mediavision PMS
 921 */
 922
 923static int init_mediavision(void)
 924{
 925        int id;
 926        int idec, decst;
 927        int i;
 928
 929        unsigned char i2c_defs[]={
 930                0x4C,0x30,0x00,0xE8,
 931                0xB6,0xE2,0x00,0x00,
 932                0xFF,0xFF,0x00,0x00,
 933                0x00,0x00,0x78,0x98,
 934                0x00,0x00,0x00,0x00,
 935                0x34,0x0A,0xF4,0xCE,
 936                0xE4
 937        };
 938
 939        mem = ioremap(mem_base, 0x800);
 940        if (!mem)
 941                return -ENOMEM;
 942
 943        if (!request_region(0x9A01, 1, "Mediavision PMS config"))
 944        {
 945                printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
 946                iounmap(mem);
 947                return -EBUSY;
 948        }
 949        if (!request_region(io_port, 3, "Mediavision PMS"))
 950        {
 951                printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port);
 952                release_region(0x9A01, 1);
 953                iounmap(mem);
 954                return -EBUSY;
 955        }
 956        outb(0xB8, 0x9A01);             /* Unlock */
 957        outb(io_port>>4, 0x9A01);       /* Set IO port */
 958
 959
 960        id=mvv_read(3);
 961        decst=pms_i2c_stat(0x43);
 962
 963        if(decst!=-1)
 964                idec=2;
 965        else if(pms_i2c_stat(0xb9)!=-1)
 966                idec=3;
 967        else if(pms_i2c_stat(0x8b)!=-1)
 968                idec=1;
 969        else
 970                idec=0;
 971
 972        printk(KERN_INFO "PMS type is %d\n", idec);
 973        if(idec == 0) {
 974                release_region(io_port, 3);
 975                release_region(0x9A01, 1);
 976                iounmap(mem);
 977                return -ENODEV;
 978        }
 979
 980        /*
 981         *      Ok we have a PMS of some sort
 982         */
 983
 984        mvv_write(0x04, mem_base>>12);  /* Set the memory area */
 985
 986        /* Ok now load the defaults */
 987
 988        for(i=0;i<0x19;i++)
 989        {
 990                if(i2c_defs[i]==0xFF)
 991                        pms_i2c_andor(0x8A, i, 0x07,0x00);
 992                else
 993                        pms_i2c_write(0x8A, i, i2c_defs[i]);
 994        }
 995
 996        pms_i2c_write(0xB8,0x00,0x12);
 997        pms_i2c_write(0xB8,0x04,0x00);
 998        pms_i2c_write(0xB8,0x07,0x00);
 999        pms_i2c_write(0xB8,0x08,0x00);
1000        pms_i2c_write(0xB8,0x09,0xFF);
1001        pms_i2c_write(0xB8,0x0A,0x00);
1002        pms_i2c_write(0xB8,0x0B,0x10);
1003        pms_i2c_write(0xB8,0x10,0x03);
1004
1005        mvv_write(0x01, 0x00);
1006        mvv_write(0x05, 0xA0);
1007        mvv_write(0x08, 0x25);
1008        mvv_write(0x09, 0x00);
1009        mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);
1010
1011        mvv_write(0x10, 0x02);
1012        mvv_write(0x1E, 0x0C);
1013        mvv_write(0x1F, 0x03);
1014        mvv_write(0x26, 0x06);
1015
1016        mvv_write(0x2B, 0x00);
1017        mvv_write(0x2C, 0x20);
1018        mvv_write(0x2D, 0x00);
1019        mvv_write(0x2F, 0x70);
1020        mvv_write(0x32, 0x00);
1021        mvv_write(0x33, MVVMEMORYWIDTH);
1022        mvv_write(0x34, 0x00);
1023        mvv_write(0x35, 0x00);
1024        mvv_write(0x3A, 0x80);
1025        mvv_write(0x3B, 0x10);
1026        mvv_write(0x20, 0x00);
1027        mvv_write(0x21, 0x00);
1028        mvv_write(0x30, 0x22);
1029        return 0;
1030}
1031
1032/*
1033 *      Initialization and module stuff
1034 */
1035
1036#ifndef MODULE
1037static int enable;
1038module_param(enable, int, 0);
1039#endif
1040
1041static int __init init_pms_cards(void)
1042{
1043        printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
1044
1045#ifndef MODULE
1046        if (!enable) {
1047                printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
1048                                 "probe\n");
1049                return -ENODEV;
1050        }
1051#endif
1052
1053        data_port = io_port +1;
1054
1055        if(init_mediavision())
1056        {
1057                printk(KERN_INFO "Board not found.\n");
1058                return -ENODEV;
1059        }
1060        memcpy(&pms_device, &pms_template, sizeof(pms_template));
1061        mutex_init(&pms_device.lock);
1062        pms_device.height=240;
1063        pms_device.width=320;
1064        pms_swsense(75);
1065        pms_resolution(320,240);
1066        return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr);
1067}
1068
1069module_param(io_port, int, 0);
1070module_param(mem_base, int, 0);
1071module_param(video_nr, int, 0);
1072MODULE_LICENSE("GPL");
1073
1074
1075static void __exit shutdown_mediavision(void)
1076{
1077        release_region(io_port,3);
1078        release_region(0x9A01, 1);
1079}
1080
1081static void __exit cleanup_pms_module(void)
1082{
1083        shutdown_mediavision();
1084        video_unregister_device((struct video_device *)&pms_device);
1085        iounmap(mem);
1086}
1087
1088module_init(init_pms_cards);
1089module_exit(cleanup_pms_module);
1090
1091