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