]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/media/video/pms.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[mirror_ubuntu-zesty-kernel.git] / drivers / media / video / pms.c
CommitLineData
1da177e4
LT
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...
d56410e0 15 *
1da177e4
LT
16 * Changes:
17 * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
d56410e0 18 * - pms_capture: report back -EFAULT
1da177e4
LT
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>
1da177e4 31#include <linux/videodev.h>
5e87efa3 32#include <media/v4l2-common.h>
3593cab5
IM
33#include <linux/mutex.h>
34
1da177e4
LT
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;
3593cab5 49 struct mutex lock;
1da177e4
LT
50};
51
52struct i2c_info
53{
54 u8 slave;
55 u8 sub;
56 u8 data;
57 u8 hits;
58};
59
ff699e6b 60static int i2c_count;
1da177e4
LT
61static struct i2c_info i2cinfo[64];
62
63static int decoder = PHILIPS2;
ff699e6b 64static int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
1da177e4
LT
65
66/*
67 * I/O ports and Shared Memory
68 */
d56410e0 69
1da177e4
LT
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
d56410e0 76
1da177e4
LT
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;
d56410e0 93
1da177e4 94 outb(0x28, io_port);
d56410e0 95
1da177e4
LT
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;
d56410e0 104
1da177e4 105 outb(slave, io_port);
d56410e0 106
1da177e4
LT
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;
d56410e0 115
1da177e4
LT
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);
d56410e0 125 return inb(data_port);
1da177e4
LT
126}
127
128static int pms_i2c_write(u16 slave, u16 sub, u16 data)
129{
130 int skip=0;
131 int count;
132 int i;
d56410e0 133
1da177e4
LT
134 for(i=0;i<i2c_count;i++)
135 {
136 if((i2cinfo[i].slave==slave) &&
137 (i2cinfo[i].sub == sub))
138 {
d56410e0
MCC
139 if(i2cinfo[i].data==data)
140 skip=1;
141 i2cinfo[i].data=data;
142 i=i2c_count+1;
1da177e4
LT
143 }
144 }
d56410e0 145
1da177e4
LT
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 }
d56410e0 153
1da177e4
LT
154 if(skip)
155 return 0;
d56410e0 156
1da177e4
LT
157 mvv_write(0x29, sub);
158 mvv_write(0x2A, data);
159 mvv_write(0x28, slave);
d56410e0 160
1da177e4 161 outb(0x28, io_port);
d56410e0 162
1da177e4
LT
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;
d56410e0 170
1da177e4 171 count=inb(data_port);
d56410e0 172
1da177e4
LT
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{
d56410e0
MCC
192 u8 tmp;
193
1da177e4
LT
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 */
d56410e0 202
1da177e4
LT
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}
d56410e0
MCC
237
238
1da177e4
LT
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;
d56410e0 272
1da177e4
LT
273 if(decoder==PHILIPS1)
274 target=0x42;
275 else if(decoder==PHILIPS2)
276 target=0x8A;
277 else
278 return;
d56410e0 279
1da177e4
LT
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
d56410e0 305 * could become a private v4l ioctl for PMSCONFIG or somesuch if
1da177e4
LT
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 */
d56410e0 327
1da177e4
LT
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 */
d56410e0 496
1da177e4
LT
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 }
d56410e0 549
1da177e4
LT
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--;
d56410e0 562
1da177e4
LT
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;
d56410e0 570
1da177e4
LT
571 fg_height=height;
572 if(fg_height>280)
573 fg_height=280;
d56410e0 574
1da177e4
LT
575 mvv_write(0x18, fg_height);
576 mvv_write(0x19, fg_height>>8);
d56410e0 577
1da177e4
LT
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);
d56410e0 601
1da177e4
LT
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 */
d56410e0 621
1da177e4
LT
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); */
d56410e0
MCC
646
647 for (y = 0; y < dev->height; y++ )
1da177e4
LT
648 {
649 writeb(0, mem); /* synchronisiert neue Zeile */
d56410e0 650
1da177e4
LT
651 /*
652 * This is in truth a fifo, be very careful as if you
653 * forgot this odd things will occur 8)
654 */
d56410e0 655
1da177e4
LT
656 memcpy_fromio(tmp, mem, dw+32); /* discard 16 word */
657 cnt -= dev->height;
d56410e0
MCC
658 while (cnt <= 0)
659 {
1da177e4
LT
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;
d56410e0 669 buf += dt;
1da177e4
LT
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;
d56410e0 686
1da177e4
LT
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;
3593cab5 729 mutex_lock(&pd->lock);
1da177e4
LT
730 pms_videosource(v->channel&1);
731 pms_vcrinput(v->channel>>1);
3593cab5 732 mutex_unlock(&pd->lock);
1da177e4
LT
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;
3593cab5 766 mutex_lock(&pd->lock);
1da177e4
LT
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:
3593cab5 790 mutex_unlock(&pd->lock);
1da177e4
LT
791 return -EINVAL;
792 }
3593cab5 793 mutex_unlock(&pd->lock);
1da177e4
LT
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)))
657de3cd 807 return -EINVAL;
1da177e4 808 pd->picture= *p;
d56410e0 809
1da177e4
LT
810 /*
811 * Now load the card.
812 */
813
3593cab5 814 mutex_lock(&pd->lock);
1da177e4
LT
815 pms_brightness(p->brightness>>8);
816 pms_hue(p->hue>>8);
817 pms_colour(p->colour>>8);
d56410e0 818 pms_contrast(p->contrast>>8);
3593cab5 819 mutex_unlock(&pd->lock);
1da177e4
LT
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;
3593cab5 835 mutex_lock(&pd->lock);
1da177e4 836 pms_resolution(pd->width, pd->height);
3593cab5 837 mutex_unlock(&pd->lock); /* Ok we figured out what to use from our wide choice */
1da177e4
LT
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;
d56410e0 876
3593cab5 877 mutex_lock(&pd->lock);
1da177e4 878 len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
3593cab5 879 mutex_unlock(&pd->lock);
1da177e4
LT
880 return len;
881}
882
fa027c2a 883static const struct file_operations pms_fops = {
1da177e4
LT
884 .owner = THIS_MODULE,
885 .open = video_exclusive_open,
886 .release = video_exclusive_release,
887 .ioctl = pms_ioctl,
078ff795 888#ifdef CONFIG_COMPAT
0d0fbf81 889 .compat_ioctl = v4l_compat_ioctl32,
078ff795 890#endif
1da177e4
LT
891 .read = pms_read,
892 .llseek = no_llseek,
893};
894
895static struct video_device pms_template=
896{
897 .owner = THIS_MODULE,
898 .name = "Mediavision PMS",
899 .type = VID_TYPE_CAPTURE,
1da177e4
LT
900 .fops = &pms_fops,
901};
902
903static struct pms_device pms_device;
904
905
906/*
907 * Probe for and initialise the Mediavision PMS
908 */
d56410e0 909
1da177e4
LT
910static int init_mediavision(void)
911{
912 int id;
913 int idec, decst;
914 int i;
d56410e0 915
1da177e4
LT
916 unsigned char i2c_defs[]={
917 0x4C,0x30,0x00,0xE8,
918 0xB6,0xE2,0x00,0x00,
919 0xFF,0xFF,0x00,0x00,
920 0x00,0x00,0x78,0x98,
921 0x00,0x00,0x00,0x00,
922 0x34,0x0A,0xF4,0xCE,
923 0xE4
924 };
925
926 mem = ioremap(mem_base, 0x800);
927 if (!mem)
928 return -ENOMEM;
d56410e0 929
1da177e4
LT
930 if (!request_region(0x9A01, 1, "Mediavision PMS config"))
931 {
932 printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
933 iounmap(mem);
934 return -EBUSY;
935 }
936 if (!request_region(io_port, 3, "Mediavision PMS"))
937 {
938 printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port);
939 release_region(0x9A01, 1);
940 iounmap(mem);
941 return -EBUSY;
942 }
943 outb(0xB8, 0x9A01); /* Unlock */
944 outb(io_port>>4, 0x9A01); /* Set IO port */
d56410e0
MCC
945
946
1da177e4
LT
947 id=mvv_read(3);
948 decst=pms_i2c_stat(0x43);
d56410e0 949
1da177e4
LT
950 if(decst!=-1)
951 idec=2;
952 else if(pms_i2c_stat(0xb9)!=-1)
953 idec=3;
954 else if(pms_i2c_stat(0x8b)!=-1)
955 idec=1;
d56410e0 956 else
1da177e4
LT
957 idec=0;
958
959 printk(KERN_INFO "PMS type is %d\n", idec);
960 if(idec == 0) {
961 release_region(io_port, 3);
962 release_region(0x9A01, 1);
963 iounmap(mem);
964 return -ENODEV;
965 }
966
967 /*
968 * Ok we have a PMS of some sort
969 */
d56410e0 970
1da177e4 971 mvv_write(0x04, mem_base>>12); /* Set the memory area */
d56410e0 972
1da177e4 973 /* Ok now load the defaults */
d56410e0 974
1da177e4
LT
975 for(i=0;i<0x19;i++)
976 {
977 if(i2c_defs[i]==0xFF)
978 pms_i2c_andor(0x8A, i, 0x07,0x00);
979 else
980 pms_i2c_write(0x8A, i, i2c_defs[i]);
981 }
d56410e0 982
1da177e4
LT
983 pms_i2c_write(0xB8,0x00,0x12);
984 pms_i2c_write(0xB8,0x04,0x00);
985 pms_i2c_write(0xB8,0x07,0x00);
986 pms_i2c_write(0xB8,0x08,0x00);
987 pms_i2c_write(0xB8,0x09,0xFF);
988 pms_i2c_write(0xB8,0x0A,0x00);
989 pms_i2c_write(0xB8,0x0B,0x10);
990 pms_i2c_write(0xB8,0x10,0x03);
d56410e0 991
1da177e4
LT
992 mvv_write(0x01, 0x00);
993 mvv_write(0x05, 0xA0);
994 mvv_write(0x08, 0x25);
995 mvv_write(0x09, 0x00);
d56410e0
MCC
996 mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);
997
1da177e4
LT
998 mvv_write(0x10, 0x02);
999 mvv_write(0x1E, 0x0C);
1000 mvv_write(0x1F, 0x03);
1001 mvv_write(0x26, 0x06);
d56410e0 1002
1da177e4
LT
1003 mvv_write(0x2B, 0x00);
1004 mvv_write(0x2C, 0x20);
1005 mvv_write(0x2D, 0x00);
1006 mvv_write(0x2F, 0x70);
1007 mvv_write(0x32, 0x00);
1008 mvv_write(0x33, MVVMEMORYWIDTH);
1009 mvv_write(0x34, 0x00);
1010 mvv_write(0x35, 0x00);
1011 mvv_write(0x3A, 0x80);
1012 mvv_write(0x3B, 0x10);
1013 mvv_write(0x20, 0x00);
1014 mvv_write(0x21, 0x00);
1015 mvv_write(0x30, 0x22);
1016 return 0;
1017}
1018
1019/*
1020 * Initialization and module stuff
1021 */
d56410e0 1022
1da177e4
LT
1023static int __init init_pms_cards(void)
1024{
1025 printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
d56410e0 1026
1da177e4 1027 data_port = io_port +1;
d56410e0 1028
1da177e4
LT
1029 if(init_mediavision())
1030 {
1031 printk(KERN_INFO "Board not found.\n");
1032 return -ENODEV;
1033 }
1034 memcpy(&pms_device, &pms_template, sizeof(pms_template));
3593cab5 1035 mutex_init(&pms_device.lock);
1da177e4
LT
1036 pms_device.height=240;
1037 pms_device.width=320;
1038 pms_swsense(75);
1039 pms_resolution(320,240);
1040 return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr);
1041}
1042
1043module_param(io_port, int, 0);
1044module_param(mem_base, int, 0);
1045module_param(video_nr, int, 0);
1046MODULE_LICENSE("GPL");
1047
1048
1049static void __exit shutdown_mediavision(void)
1050{
1051 release_region(io_port,3);
1052 release_region(0x9A01, 1);
1053}
1054
1055static void __exit cleanup_pms_module(void)
1056{
1057 shutdown_mediavision();
1058 video_unregister_device((struct video_device *)&pms_device);
1059 iounmap(mem);
1060}
1061
1062module_init(init_pms_cards);
1063module_exit(cleanup_pms_module);
1064