]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/media/video/pms.c
V4L/DVB (8387): Some cosmetic changes
[mirror_ubuntu-zesty-kernel.git] / drivers / media / video / pms.c
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
43 struct 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
52 struct i2c_info
53 {
54 u8 slave;
55 u8 sub;
56 u8 data;
57 u8 hits;
58 };
59
60 static int i2c_count;
61 static struct i2c_info i2cinfo[64];
62
63 static int decoder = PHILIPS2;
64 static int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
65
66 /*
67 * I/O ports and Shared Memory
68 */
69
70 static int io_port = 0x250;
71 static int data_port = 0x251;
72 static int mem_base = 0xC8000;
73 static void __iomem *mem;
74 static int video_nr = -1;
75
76
77
78 static inline void mvv_write(u8 index, u8 value)
79 {
80 outw(index|(value<<8), io_port);
81 }
82
83 static inline u8 mvv_read(u8 index)
84 {
85 outb(index, io_port);
86 return inb(data_port);
87 }
88
89 static 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
128 static 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
178 static 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
190 static 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
204 static void pms_videosource(short source)
205 {
206 mvv_write(0x2E, source?0x31:0x30);
207 }
208
209 static 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
225 static 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
239 static 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
252 static 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
268 static 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
309 static 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
328 static 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
336 static 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
344 static 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
352 static 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
360 static 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
368 static 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
376 static 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
384 static 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
392 static 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
400 static 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
408 static 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
422 static 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
435 static void pms_spacialcompl(short data)
436 {
437 mvv_write(0x3B, data);
438 }
439
440 static void pms_spacialcomph(short data)
441 {
442 mvv_write(0x3A, data);
443 }
444
445 static void pms_vstart(short start)
446 {
447 mvv_write(0x16, start);
448 mvv_write(0x17, (start>>8)&0x01);
449 }
450
451 #endif
452
453 static 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
462 static 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
477 static 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
487 static 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
497 static 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
534 static 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
567 static 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
622 static 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
631 static 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
681 static 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
864 static 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
870 static 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
883 static 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 #ifdef CONFIG_COMPAT
889 .compat_ioctl = v4l_compat_ioctl32,
890 #endif
891 .read = pms_read,
892 .llseek = no_llseek,
893 };
894
895 static struct video_device pms_template=
896 {
897 .owner = THIS_MODULE,
898 .name = "Mediavision PMS",
899 .type = VID_TYPE_CAPTURE,
900 .fops = &pms_fops,
901 };
902
903 static struct pms_device pms_device;
904
905
906 /*
907 * Probe for and initialise the Mediavision PMS
908 */
909
910 static int init_mediavision(void)
911 {
912 int id;
913 int idec, decst;
914 int i;
915
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;
929
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 */
945
946
947 id=mvv_read(3);
948 decst=pms_i2c_stat(0x43);
949
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;
956 else
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 */
970
971 mvv_write(0x04, mem_base>>12); /* Set the memory area */
972
973 /* Ok now load the defaults */
974
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 }
982
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);
991
992 mvv_write(0x01, 0x00);
993 mvv_write(0x05, 0xA0);
994 mvv_write(0x08, 0x25);
995 mvv_write(0x09, 0x00);
996 mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);
997
998 mvv_write(0x10, 0x02);
999 mvv_write(0x1E, 0x0C);
1000 mvv_write(0x1F, 0x03);
1001 mvv_write(0x26, 0x06);
1002
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 */
1022
1023 static int __init init_pms_cards(void)
1024 {
1025 printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
1026
1027 data_port = io_port +1;
1028
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));
1035 mutex_init(&pms_device.lock);
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
1043 module_param(io_port, int, 0);
1044 module_param(mem_base, int, 0);
1045 module_param(video_nr, int, 0);
1046 MODULE_LICENSE("GPL");
1047
1048
1049 static void __exit shutdown_mediavision(void)
1050 {
1051 release_region(io_port,3);
1052 release_region(0x9A01, 1);
1053 }
1054
1055 static void __exit cleanup_pms_module(void)
1056 {
1057 shutdown_mediavision();
1058 video_unregister_device((struct video_device *)&pms_device);
1059 iounmap(mem);
1060 }
1061
1062 module_init(init_pms_cards);
1063 module_exit(cleanup_pms_module);
1064