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