]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/video/pms.c
Merge branch 'bkl_removal' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[mirror_ubuntu-jammy-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.
d9b01449
AC
13 * His driver works so send any reports to alan@lxorguk.ukuu.org.uk
14 * unless the userspace driver also doesn't work for you...
d56410e0 15 *
1da177e4 16 * Changes:
feba2f81
HV
17 * 25-11-2009 Hans Verkuil <hverkuil@xs4all.nl>
18 * - converted to version 2 of the V4L API.
19 * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
20 * - pms_capture: report back -EFAULT
1da177e4
LT
21 */
22
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/errno.h>
26#include <linux/fs.h>
27#include <linux/kernel.h>
1da177e4
LT
28#include <linux/mm.h>
29#include <linux/ioport.h>
30#include <linux/init.h>
feba2f81
HV
31#include <linux/version.h>
32#include <linux/mutex.h>
262ab9ac 33#include <linux/uaccess.h>
1da177e4 34#include <asm/io.h>
feba2f81
HV
35
36#include <linux/videodev2.h>
5e87efa3 37#include <media/v4l2-common.h>
35ea11ff 38#include <media/v4l2-ioctl.h>
1ce7981b 39#include <media/v4l2-device.h>
1da177e4 40
1ce7981b
HV
41MODULE_LICENSE("GPL");
42
1da177e4
LT
43
44#define MOTOROLA 1
feba2f81 45#define PHILIPS2 2 /* SAA7191 */
1da177e4
LT
46#define PHILIPS1 3
47#define MVVMEMORYWIDTH 0x40 /* 512 bytes */
48
1ce7981b 49struct i2c_info {
1da177e4
LT
50 u8 slave;
51 u8 sub;
52 u8 data;
53 u8 hits;
54};
55
1ce7981b
HV
56struct pms {
57 struct v4l2_device v4l2_dev;
58 struct video_device vdev;
1ce7981b
HV
59 int height;
60 int width;
feba2f81
HV
61 int depth;
62 int input;
63 s32 brightness, saturation, hue, contrast;
1ce7981b
HV
64 struct mutex lock;
65 int i2c_count;
66 struct i2c_info i2cinfo[64];
67
68 int decoder;
69 int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
feba2f81 70 v4l2_std_id std;
1ce7981b
HV
71 int io;
72 int data;
73 void __iomem *mem;
74};
1da177e4 75
1ce7981b 76static struct pms pms_card;
1da177e4
LT
77
78/*
79 * I/O ports and Shared Memory
80 */
d56410e0 81
1ce7981b
HV
82static int io_port = 0x250;
83module_param(io_port, int, 0);
84
85static int mem_base = 0xc8000;
86module_param(mem_base, int, 0);
1da177e4 87
1ce7981b
HV
88static int video_nr = -1;
89module_param(video_nr, int, 0);
d56410e0 90
1da177e4 91
1ce7981b 92static inline void mvv_write(struct pms *dev, u8 index, u8 value)
1da177e4 93{
1ce7981b 94 outw(index | (value << 8), dev->io);
1da177e4
LT
95}
96
1ce7981b 97static inline u8 mvv_read(struct pms *dev, u8 index)
1da177e4 98{
1ce7981b
HV
99 outb(index, dev->io);
100 return inb(dev->data);
1da177e4
LT
101}
102
1ce7981b 103static int pms_i2c_stat(struct pms *dev, u8 slave)
1da177e4 104{
1ce7981b 105 int counter = 0;
1da177e4 106 int i;
d56410e0 107
1ce7981b 108 outb(0x28, dev->io);
d56410e0 109
1ce7981b
HV
110 while ((inb(dev->data) & 0x01) == 0)
111 if (counter++ == 256)
1da177e4
LT
112 break;
113
1ce7981b
HV
114 while ((inb(dev->data) & 0x01) != 0)
115 if (counter++ == 256)
1da177e4 116 break;
d56410e0 117
1ce7981b 118 outb(slave, dev->io);
d56410e0 119
1ce7981b
HV
120 counter = 0;
121 while ((inb(dev->data) & 0x01) == 0)
122 if (counter++ == 256)
1da177e4
LT
123 break;
124
1ce7981b
HV
125 while ((inb(dev->data) & 0x01) != 0)
126 if (counter++ == 256)
1da177e4 127 break;
d56410e0 128
1ce7981b
HV
129 for (i = 0; i < 12; i++) {
130 char st = inb(dev->data);
131
132 if ((st & 2) != 0)
1da177e4 133 return -1;
1ce7981b 134 if ((st & 1) == 0)
1da177e4
LT
135 break;
136 }
1ce7981b
HV
137 outb(0x29, dev->io);
138 return inb(dev->data);
1da177e4
LT
139}
140
1ce7981b 141static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data)
1da177e4 142{
1ce7981b 143 int skip = 0;
1da177e4
LT
144 int count;
145 int i;
d56410e0 146
1ce7981b
HV
147 for (i = 0; i < dev->i2c_count; i++) {
148 if ((dev->i2cinfo[i].slave == slave) &&
149 (dev->i2cinfo[i].sub == sub)) {
150 if (dev->i2cinfo[i].data == data)
151 skip = 1;
152 dev->i2cinfo[i].data = data;
153 i = dev->i2c_count + 1;
1da177e4
LT
154 }
155 }
d56410e0 156
1ce7981b
HV
157 if (i == dev->i2c_count && dev->i2c_count < 64) {
158 dev->i2cinfo[dev->i2c_count].slave = slave;
159 dev->i2cinfo[dev->i2c_count].sub = sub;
160 dev->i2cinfo[dev->i2c_count].data = data;
161 dev->i2c_count++;
1da177e4 162 }
d56410e0 163
1ce7981b 164 if (skip)
1da177e4 165 return 0;
d56410e0 166
1ce7981b
HV
167 mvv_write(dev, 0x29, sub);
168 mvv_write(dev, 0x2A, data);
169 mvv_write(dev, 0x28, slave);
d56410e0 170
1ce7981b 171 outb(0x28, dev->io);
d56410e0 172
1ce7981b
HV
173 count = 0;
174 while ((inb(dev->data) & 1) == 0)
175 if (count > 255)
1da177e4 176 break;
1ce7981b
HV
177 while ((inb(dev->data) & 1) != 0)
178 if (count > 255)
1da177e4 179 break;
d56410e0 180
1ce7981b 181 count = inb(dev->data);
d56410e0 182
1ce7981b 183 if (count & 2)
1da177e4
LT
184 return -1;
185 return count;
186}
187
1ce7981b 188static int pms_i2c_read(struct pms *dev, int slave, int sub)
1da177e4 189{
1ce7981b
HV
190 int i;
191
192 for (i = 0; i < dev->i2c_count; i++) {
193 if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub)
194 return dev->i2cinfo[i].data;
1da177e4
LT
195 }
196 return 0;
197}
198
199
1ce7981b 200static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or)
1da177e4 201{
d56410e0
MCC
202 u8 tmp;
203
1ce7981b
HV
204 tmp = pms_i2c_read(dev, slave, sub);
205 tmp = (tmp & and) | or;
206 pms_i2c_write(dev, slave, sub, tmp);
1da177e4
LT
207}
208
209/*
210 * Control functions
211 */
d56410e0 212
1da177e4 213
1ce7981b 214static void pms_videosource(struct pms *dev, short source)
1da177e4 215{
feba2f81
HV
216 switch (dev->decoder) {
217 case MOTOROLA:
218 break;
219 case PHILIPS2:
220 pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0);
221 break;
222 case PHILIPS1:
223 break;
224 }
225 mvv_write(dev, 0x2E, 0x31);
226 /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
227 But could not make this work correctly. Only Composite input
228 worked for me. */
1da177e4
LT
229}
230
1ce7981b 231static void pms_hue(struct pms *dev, short hue)
1da177e4 232{
1ce7981b
HV
233 switch (dev->decoder) {
234 case MOTOROLA:
235 pms_i2c_write(dev, 0x8a, 0x00, hue);
236 break;
237 case PHILIPS2:
238 pms_i2c_write(dev, 0x8a, 0x07, hue);
239 break;
240 case PHILIPS1:
241 pms_i2c_write(dev, 0x42, 0x07, hue);
242 break;
1da177e4
LT
243 }
244}
245
feba2f81 246static void pms_saturation(struct pms *dev, short sat)
1da177e4 247{
1ce7981b
HV
248 switch (dev->decoder) {
249 case MOTOROLA:
feba2f81 250 pms_i2c_write(dev, 0x8a, 0x00, sat);
1ce7981b
HV
251 break;
252 case PHILIPS1:
feba2f81 253 pms_i2c_write(dev, 0x42, 0x12, sat);
1ce7981b 254 break;
1da177e4
LT
255 }
256}
d56410e0
MCC
257
258
1ce7981b 259static void pms_contrast(struct pms *dev, short contrast)
1da177e4 260{
1ce7981b
HV
261 switch (dev->decoder) {
262 case MOTOROLA:
263 pms_i2c_write(dev, 0x8a, 0x00, contrast);
264 break;
265 case PHILIPS1:
266 pms_i2c_write(dev, 0x42, 0x13, contrast);
267 break;
1da177e4
LT
268 }
269}
270
1ce7981b 271static void pms_brightness(struct pms *dev, short brightness)
1da177e4 272{
1ce7981b
HV
273 switch (dev->decoder) {
274 case MOTOROLA:
275 pms_i2c_write(dev, 0x8a, 0x00, brightness);
276 pms_i2c_write(dev, 0x8a, 0x00, brightness);
277 pms_i2c_write(dev, 0x8a, 0x00, brightness);
278 break;
279 case PHILIPS1:
280 pms_i2c_write(dev, 0x42, 0x19, brightness);
281 break;
1da177e4
LT
282 }
283}
284
285
1ce7981b 286static void pms_format(struct pms *dev, short format)
1da177e4
LT
287{
288 int target;
d56410e0 289
1ce7981b
HV
290 dev->standard = format;
291
292 if (dev->decoder == PHILIPS1)
293 target = 0x42;
294 else if (dev->decoder == PHILIPS2)
295 target = 0x8a;
1da177e4
LT
296 else
297 return;
d56410e0 298
1ce7981b
HV
299 switch (format) {
300 case 0: /* Auto */
301 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
302 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80);
303 break;
304 case 1: /* NTSC */
305 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
306 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40);
307 break;
308 case 2: /* PAL */
309 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
310 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
311 break;
312 case 3: /* SECAM */
313 pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01);
314 pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
315 break;
1da177e4
LT
316 }
317}
318
319#ifdef FOR_FUTURE_EXPANSION
320
321/*
322 * These features of the PMS card are not currently exposes. They
d56410e0 323 * could become a private v4l ioctl for PMSCONFIG or somesuch if
1da177e4
LT
324 * people need it. We also don't yet use the PMS interrupt.
325 */
326
1ce7981b 327static void pms_hstart(struct pms *dev, short start)
1da177e4 328{
1ce7981b
HV
329 switch (dev->decoder) {
330 case PHILIPS1:
331 pms_i2c_write(dev, 0x8a, 0x05, start);
332 pms_i2c_write(dev, 0x8a, 0x18, start);
333 break;
334 case PHILIPS2:
335 pms_i2c_write(dev, 0x42, 0x05, start);
336 pms_i2c_write(dev, 0x42, 0x18, start);
337 break;
1da177e4
LT
338 }
339}
340
341/*
342 * Bandpass filters
343 */
d56410e0 344
1ce7981b 345static void pms_bandpass(struct pms *dev, short pass)
1da177e4 346{
1ce7981b
HV
347 if (dev->decoder == PHILIPS2)
348 pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4);
349 else if (dev->decoder == PHILIPS1)
350 pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4);
1da177e4
LT
351}
352
1ce7981b 353static void pms_antisnow(struct pms *dev, short snow)
1da177e4 354{
1ce7981b
HV
355 if (dev->decoder == PHILIPS2)
356 pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2);
357 else if (dev->decoder == PHILIPS1)
358 pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2);
1da177e4
LT
359}
360
1ce7981b 361static void pms_sharpness(struct pms *dev, short sharp)
1da177e4 362{
1ce7981b
HV
363 if (dev->decoder == PHILIPS2)
364 pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03);
365 else if (dev->decoder == PHILIPS1)
366 pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03);
1da177e4
LT
367}
368
1ce7981b 369static void pms_chromaagc(struct pms *dev, short agc)
1da177e4 370{
1ce7981b
HV
371 if (dev->decoder == PHILIPS2)
372 pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5);
373 else if (dev->decoder == PHILIPS1)
374 pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5);
1da177e4
LT
375}
376
1ce7981b 377static void pms_vertnoise(struct pms *dev, short noise)
1da177e4 378{
1ce7981b
HV
379 if (dev->decoder == PHILIPS2)
380 pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3);
381 else if (dev->decoder == PHILIPS1)
382 pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3);
1da177e4
LT
383}
384
1ce7981b 385static void pms_forcecolour(struct pms *dev, short colour)
1da177e4 386{
1ce7981b
HV
387 if (dev->decoder == PHILIPS2)
388 pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7);
389 else if (dev->decoder == PHILIPS1)
390 pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7);
1da177e4
LT
391}
392
1ce7981b 393static void pms_antigamma(struct pms *dev, short gamma)
1da177e4 394{
1ce7981b
HV
395 if (dev->decoder == PHILIPS2)
396 pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7);
397 else if (dev->decoder == PHILIPS1)
398 pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7);
1da177e4
LT
399}
400
1ce7981b 401static void pms_prefilter(struct pms *dev, short filter)
1da177e4 402{
1ce7981b
HV
403 if (dev->decoder == PHILIPS2)
404 pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6);
405 else if (dev->decoder == PHILIPS1)
406 pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6);
1da177e4
LT
407}
408
1ce7981b 409static void pms_hfilter(struct pms *dev, short filter)
1da177e4 410{
1ce7981b
HV
411 if (dev->decoder == PHILIPS2)
412 pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5);
413 else if (dev->decoder == PHILIPS1)
414 pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5);
1da177e4
LT
415}
416
1ce7981b 417static void pms_vfilter(struct pms *dev, short filter)
1da177e4 418{
1ce7981b
HV
419 if (dev->decoder == PHILIPS2)
420 pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5);
421 else if (dev->decoder == PHILIPS1)
422 pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5);
1da177e4
LT
423}
424
1ce7981b 425static void pms_killcolour(struct pms *dev, short colour)
1da177e4 426{
1ce7981b
HV
427 if (dev->decoder == PHILIPS2) {
428 pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3);
429 pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3);
430 } else if (dev->decoder == PHILIPS1) {
431 pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3);
432 pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3);
1da177e4
LT
433 }
434}
435
1ce7981b 436static void pms_chromagain(struct pms *dev, short chroma)
1da177e4 437{
1ce7981b
HV
438 if (dev->decoder == PHILIPS2)
439 pms_i2c_write(dev, 0x8a, 0x11, chroma);
440 else if (dev->decoder == PHILIPS1)
441 pms_i2c_write(dev, 0x42, 0x11, chroma);
1da177e4
LT
442}
443
444
1ce7981b 445static void pms_spacialcompl(struct pms *dev, short data)
1da177e4 446{
1ce7981b 447 mvv_write(dev, 0x3b, data);
1da177e4
LT
448}
449
1ce7981b 450static void pms_spacialcomph(struct pms *dev, short data)
1da177e4 451{
1ce7981b 452 mvv_write(dev, 0x3a, data);
1da177e4
LT
453}
454
1ce7981b 455static void pms_vstart(struct pms *dev, short start)
1da177e4 456{
1ce7981b
HV
457 mvv_write(dev, 0x16, start);
458 mvv_write(dev, 0x17, (start >> 8) & 0x01);
1da177e4
LT
459}
460
461#endif
462
1ce7981b 463static void pms_secamcross(struct pms *dev, short cross)
1da177e4 464{
1ce7981b
HV
465 if (dev->decoder == PHILIPS2)
466 pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5);
467 else if (dev->decoder == PHILIPS1)
468 pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5);
1da177e4
LT
469}
470
471
1ce7981b 472static void pms_swsense(struct pms *dev, short sense)
1da177e4 473{
1ce7981b
HV
474 if (dev->decoder == PHILIPS2) {
475 pms_i2c_write(dev, 0x8a, 0x0a, sense);
476 pms_i2c_write(dev, 0x8a, 0x0b, sense);
477 } else if (dev->decoder == PHILIPS1) {
478 pms_i2c_write(dev, 0x42, 0x0a, sense);
479 pms_i2c_write(dev, 0x42, 0x0b, sense);
1da177e4
LT
480 }
481}
482
483
1ce7981b 484static void pms_framerate(struct pms *dev, short frr)
1da177e4 485{
feba2f81 486 int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25;
1ce7981b
HV
487
488 if (frr == 0)
1da177e4 489 return;
1ce7981b
HV
490 fps = fps/frr;
491 mvv_write(dev, 0x14, 0x80 | fps);
492 mvv_write(dev, 0x15, 1);
1da177e4
LT
493}
494
1ce7981b 495static void pms_vert(struct pms *dev, u8 deciden, u8 decinum)
1da177e4 496{
1ce7981b
HV
497 mvv_write(dev, 0x1c, deciden); /* Denominator */
498 mvv_write(dev, 0x1d, decinum); /* Numerator */
1da177e4
LT
499}
500
501/*
502 * Turn 16bit ratios into best small ratio the chipset can grok
503 */
d56410e0 504
1ce7981b 505static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden)
1da177e4 506{
1ce7981b
HV
507 /* Knock it down by / 5 once */
508 if (decinum % 5 == 0) {
509 deciden /= 5;
510 decinum /= 5;
1da177e4
LT
511 }
512 /*
513 * 3's
514 */
1ce7981b
HV
515 while (decinum % 3 == 0 && deciden % 3 == 0) {
516 deciden /= 3;
517 decinum /= 3;
1da177e4
LT
518 }
519 /*
520 * 2's
521 */
1ce7981b
HV
522 while (decinum % 2 == 0 && deciden % 2 == 0) {
523 decinum /= 2;
524 deciden /= 2;
1da177e4
LT
525 }
526 /*
527 * Fudgyify
528 */
1ce7981b
HV
529 while (deciden > 32) {
530 deciden /= 2;
531 decinum = (decinum + 1) / 2;
1da177e4 532 }
1ce7981b 533 if (deciden == 32)
1da177e4 534 deciden--;
1ce7981b 535 pms_vert(dev, deciden, decinum);
1da177e4
LT
536}
537
1ce7981b 538static void pms_horzdeci(struct pms *dev, short decinum, short deciden)
1da177e4 539{
1ce7981b
HV
540 if (decinum <= 512) {
541 if (decinum % 5 == 0) {
542 decinum /= 5;
543 deciden /= 5;
1da177e4 544 }
1ce7981b
HV
545 } else {
546 decinum = 512;
547 deciden = 640; /* 768 would be ideal */
1da177e4 548 }
d56410e0 549
1ce7981b
HV
550 while (((decinum | deciden) & 1) == 0) {
551 decinum >>= 1;
552 deciden >>= 1;
1da177e4 553 }
1ce7981b
HV
554 while (deciden > 32) {
555 deciden >>= 1;
556 decinum = (decinum + 1) >> 1;
1da177e4 557 }
1ce7981b 558 if (deciden == 32)
1da177e4 559 deciden--;
d56410e0 560
1ce7981b
HV
561 mvv_write(dev, 0x24, 0x80 | deciden);
562 mvv_write(dev, 0x25, decinum);
1da177e4
LT
563}
564
1ce7981b 565static void pms_resolution(struct pms *dev, short width, short height)
1da177e4
LT
566{
567 int fg_height;
d56410e0 568
1ce7981b
HV
569 fg_height = height;
570 if (fg_height > 280)
571 fg_height = 280;
d56410e0 572
1ce7981b
HV
573 mvv_write(dev, 0x18, fg_height);
574 mvv_write(dev, 0x19, fg_height >> 8);
d56410e0 575
feba2f81 576 if (dev->std & V4L2_STD_525_60) {
1ce7981b
HV
577 mvv_write(dev, 0x1a, 0xfc);
578 mvv_write(dev, 0x1b, 0x00);
579 if (height > fg_height)
580 pms_vertdeci(dev, 240, 240);
1da177e4 581 else
1ce7981b
HV
582 pms_vertdeci(dev, fg_height, 240);
583 } else {
584 mvv_write(dev, 0x1a, 0x1a);
585 mvv_write(dev, 0x1b, 0x01);
586 if (fg_height > 256)
587 pms_vertdeci(dev, 270, 270);
1da177e4 588 else
1ce7981b 589 pms_vertdeci(dev, fg_height, 270);
1da177e4 590 }
1ce7981b
HV
591 mvv_write(dev, 0x12, 0);
592 mvv_write(dev, 0x13, MVVMEMORYWIDTH);
593 mvv_write(dev, 0x42, 0x00);
594 mvv_write(dev, 0x43, 0x00);
595 mvv_write(dev, 0x44, MVVMEMORYWIDTH);
d56410e0 596
1ce7981b
HV
597 mvv_write(dev, 0x22, width + 8);
598 mvv_write(dev, 0x23, (width + 8) >> 8);
1da177e4 599
feba2f81 600 if (dev->std & V4L2_STD_525_60)
1ce7981b 601 pms_horzdeci(dev, width, 640);
1da177e4 602 else
1ce7981b 603 pms_horzdeci(dev, width + 8, 768);
1da177e4 604
1ce7981b
HV
605 mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe);
606 mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01);
607 mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd);
608 mvv_write(dev, 0x32, 0x00);
609 mvv_write(dev, 0x33, MVVMEMORYWIDTH);
1da177e4
LT
610}
611
612
613/*
614 * Set Input
615 */
d56410e0 616
1ce7981b 617static void pms_vcrinput(struct pms *dev, short input)
1da177e4 618{
1ce7981b
HV
619 if (dev->decoder == PHILIPS2)
620 pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7);
621 else if (dev->decoder == PHILIPS1)
622 pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7);
1da177e4
LT
623}
624
625
1ce7981b 626static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
1da177e4
LT
627{
628 int y;
1ce7981b
HV
629 int dw = 2 * dev->width;
630 char tmp[dw + 32]; /* using a temp buffer is faster than direct */
1da177e4 631 int cnt = 0;
1ce7981b 632 int len = 0;
1da177e4
LT
633 unsigned char r8 = 0x5; /* value for reg8 */
634
635 if (rgb555)
636 r8 |= 0x20; /* else use untranslated rgb = 565 */
1ce7981b 637 mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
1da177e4
LT
638
639/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
d56410e0 640
1ce7981b
HV
641 for (y = 0; y < dev->height; y++) {
642 writeb(0, dev->mem); /* synchronisiert neue Zeile */
d56410e0 643
1da177e4
LT
644 /*
645 * This is in truth a fifo, be very careful as if you
646 * forgot this odd things will occur 8)
647 */
d56410e0 648
1ce7981b 649 memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */
1da177e4 650 cnt -= dev->height;
1ce7981b 651 while (cnt <= 0) {
1da177e4
LT
652 /*
653 * Don't copy too far
654 */
1ce7981b
HV
655 int dt = dw;
656 if (dt + len > count)
657 dt = count - len;
1da177e4 658 cnt += dev->height;
1ce7981b 659 if (copy_to_user(buf, tmp + 32, dt))
1da177e4 660 return len ? len : -EFAULT;
d56410e0 661 buf += dt;
1da177e4
LT
662 len += dt;
663 }
664 }
665 return len;
666}
667
668
669/*
670 * Video4linux interfacing
671 */
672
feba2f81
HV
673static int pms_querycap(struct file *file, void *priv,
674 struct v4l2_capability *vcap)
1da177e4 675{
1ce7981b
HV
676 struct pms *dev = video_drvdata(file);
677
feba2f81
HV
678 strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
679 strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
680 strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
681 vcap->version = KERNEL_VERSION(0, 0, 3);
682 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
683 return 0;
684}
1ce7981b 685
feba2f81
HV
686static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
687{
688 static const char *inputs[4] = {
689 "Composite",
690 "S-Video",
691 "Composite (VCR)",
692 "S-Video (VCR)"
693 };
1ce7981b 694
feba2f81
HV
695 if (vin->index > 3)
696 return -EINVAL;
697 strlcpy(vin->name, inputs[vin->index], sizeof(vin->name));
698 vin->type = V4L2_INPUT_TYPE_CAMERA;
699 vin->audioset = 0;
700 vin->tuner = 0;
701 vin->std = V4L2_STD_ALL;
702 vin->status = 0;
703 return 0;
704}
1ce7981b 705
feba2f81
HV
706static int pms_g_input(struct file *file, void *fh, unsigned int *inp)
707{
708 struct pms *dev = video_drvdata(file);
1ce7981b 709
feba2f81
HV
710 *inp = dev->input;
711 return 0;
712}
713
714static int pms_s_input(struct file *file, void *fh, unsigned int inp)
715{
716 struct pms *dev = video_drvdata(file);
717
718 if (inp > 3)
719 return -EINVAL;
720
721 mutex_lock(&dev->lock);
722 dev->input = inp;
723 pms_videosource(dev, inp & 1);
724 pms_vcrinput(dev, inp >> 1);
725 mutex_unlock(&dev->lock);
726 return 0;
727}
728
729static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
730{
731 struct pms *dev = video_drvdata(file);
732
733 *std = dev->std;
734 return 0;
735}
736
737static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
738{
739 struct pms *dev = video_drvdata(file);
740 int ret = 0;
741
742 dev->std = *std;
743 mutex_lock(&dev->lock);
744 if (dev->std & V4L2_STD_NTSC) {
745 pms_framerate(dev, 30);
746 pms_secamcross(dev, 0);
747 pms_format(dev, 1);
748 } else if (dev->std & V4L2_STD_PAL) {
749 pms_framerate(dev, 25);
750 pms_secamcross(dev, 0);
751 pms_format(dev, 2);
752 } else if (dev->std & V4L2_STD_SECAM) {
753 pms_framerate(dev, 25);
754 pms_secamcross(dev, 1);
755 pms_format(dev, 2);
756 } else {
757 ret = -EINVAL;
1ce7981b 758 }
feba2f81
HV
759 /*
760 switch (v->mode) {
761 case VIDEO_MODE_AUTO:
762 pms_framerate(dev, 25);
763 pms_secamcross(dev, 0);
764 pms_format(dev, 0);
765 break;
766 }*/
767 mutex_unlock(&dev->lock);
768 return 0;
769}
770
771static int pms_queryctrl(struct file *file, void *priv,
772 struct v4l2_queryctrl *qc)
773{
774 switch (qc->id) {
775 case V4L2_CID_BRIGHTNESS:
776 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139);
777 case V4L2_CID_CONTRAST:
778 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70);
779 case V4L2_CID_SATURATION:
780 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64);
781 case V4L2_CID_HUE:
782 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
1ce7981b 783 }
feba2f81
HV
784 return -EINVAL;
785}
1ce7981b 786
feba2f81
HV
787static int pms_g_ctrl(struct file *file, void *priv,
788 struct v4l2_control *ctrl)
789{
790 struct pms *dev = video_drvdata(file);
791 int ret = 0;
792
793 switch (ctrl->id) {
794 case V4L2_CID_BRIGHTNESS:
795 ctrl->value = dev->brightness;
796 break;
797 case V4L2_CID_CONTRAST:
798 ctrl->value = dev->contrast;
799 break;
800 case V4L2_CID_SATURATION:
801 ctrl->value = dev->saturation;
802 break;
803 case V4L2_CID_HUE:
804 ctrl->value = dev->hue;
805 break;
806 default:
807 ret = -EINVAL;
808 break;
1ce7981b 809 }
feba2f81
HV
810 return ret;
811}
812
813static int pms_s_ctrl(struct file *file, void *priv,
814 struct v4l2_control *ctrl)
815{
816 struct pms *dev = video_drvdata(file);
817 int ret = 0;
818
819 mutex_lock(&dev->lock);
820 switch (ctrl->id) {
821 case V4L2_CID_BRIGHTNESS:
822 dev->brightness = ctrl->value;
823 pms_brightness(dev, dev->brightness);
824 break;
825 case V4L2_CID_CONTRAST:
826 dev->contrast = ctrl->value;
827 pms_contrast(dev, dev->contrast);
828 break;
829 case V4L2_CID_SATURATION:
830 dev->saturation = ctrl->value;
831 pms_saturation(dev, dev->saturation);
832 break;
833 case V4L2_CID_HUE:
834 dev->hue = ctrl->value;
835 pms_hue(dev, dev->hue);
836 break;
1ce7981b 837 default:
feba2f81
HV
838 ret = -EINVAL;
839 break;
1da177e4 840 }
feba2f81
HV
841 mutex_unlock(&dev->lock);
842 return ret;
843}
844
845static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
846{
847 struct pms *dev = video_drvdata(file);
848 struct v4l2_pix_format *pix = &fmt->fmt.pix;
849
850 pix->width = dev->width;
851 pix->height = dev->height;
852 pix->pixelformat = dev->width == 15 ?
853 V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565;
854 pix->field = V4L2_FIELD_NONE;
855 pix->bytesperline = 2 * dev->width;
856 pix->sizeimage = 2 * dev->width * dev->height;
857 /* Just a guess */
858 pix->colorspace = V4L2_COLORSPACE_SRGB;
859 return 0;
860}
861
862static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
863{
864 struct v4l2_pix_format *pix = &fmt->fmt.pix;
865
866 if (pix->height < 16 || pix->height > 480)
867 return -EINVAL;
868 if (pix->width < 16 || pix->width > 640)
869 return -EINVAL;
870 if (pix->pixelformat != V4L2_PIX_FMT_RGB555 &&
871 pix->pixelformat != V4L2_PIX_FMT_RGB565)
872 return -EINVAL;
873 pix->field = V4L2_FIELD_NONE;
874 pix->bytesperline = 2 * pix->width;
875 pix->sizeimage = 2 * pix->width * pix->height;
876 /* Just a guess */
877 pix->colorspace = V4L2_COLORSPACE_SRGB;
1da177e4
LT
878 return 0;
879}
880
feba2f81 881static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
1da177e4 882{
feba2f81
HV
883 struct pms *dev = video_drvdata(file);
884 struct v4l2_pix_format *pix = &fmt->fmt.pix;
885 int ret = pms_try_fmt_vid_cap(file, fh, fmt);
886
887 if (ret)
888 return ret;
889 mutex_lock(&dev->lock);
890 dev->width = pix->width;
891 dev->height = pix->height;
892 dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
893 pms_resolution(dev, dev->width, dev->height);
894 /* Ok we figured out what to use from our wide choice */
895 mutex_unlock(&dev->lock);
896 return 0;
897}
898
899static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
900{
901 static struct v4l2_fmtdesc formats[] = {
902 { 0, 0, 0,
903 "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
904 { 0, 0, 0, 0 }
905 },
906 { 0, 0, 0,
907 "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
908 { 0, 0, 0, 0 }
909 },
910 };
911 enum v4l2_buf_type type = fmt->type;
912
913 if (fmt->index > 1)
914 return -EINVAL;
915
916 *fmt = formats[fmt->index];
917 fmt->type = type;
918 return 0;
1da177e4
LT
919}
920
921static ssize_t pms_read(struct file *file, char __user *buf,
922 size_t count, loff_t *ppos)
923{
1ce7981b 924 struct pms *dev = video_drvdata(file);
1da177e4 925 int len;
d56410e0 926
1ce7981b 927 mutex_lock(&dev->lock);
feba2f81 928 len = pms_capture(dev, buf, (dev->depth == 15), count);
1ce7981b 929 mutex_unlock(&dev->lock);
1da177e4
LT
930 return len;
931}
932
bec43661 933static const struct v4l2_file_operations pms_fops = {
1da177e4 934 .owner = THIS_MODULE,
61df3c9b 935 .unlocked_ioctl = video_ioctl2,
1da177e4 936 .read = pms_read,
1da177e4
LT
937};
938
feba2f81
HV
939static const struct v4l2_ioctl_ops pms_ioctl_ops = {
940 .vidioc_querycap = pms_querycap,
941 .vidioc_g_input = pms_g_input,
942 .vidioc_s_input = pms_s_input,
943 .vidioc_enum_input = pms_enum_input,
944 .vidioc_g_std = pms_g_std,
945 .vidioc_s_std = pms_s_std,
946 .vidioc_queryctrl = pms_queryctrl,
947 .vidioc_g_ctrl = pms_g_ctrl,
948 .vidioc_s_ctrl = pms_s_ctrl,
949 .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap,
950 .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap,
951 .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap,
952 .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap,
953};
1da177e4
LT
954
955/*
956 * Probe for and initialise the Mediavision PMS
957 */
d56410e0 958
1ce7981b 959static int init_mediavision(struct pms *dev)
1da177e4
LT
960{
961 int id;
962 int idec, decst;
963 int i;
1ce7981b
HV
964 static const unsigned char i2c_defs[] = {
965 0x4c, 0x30, 0x00, 0xe8,
966 0xb6, 0xe2, 0x00, 0x00,
967 0xff, 0xff, 0x00, 0x00,
968 0x00, 0x00, 0x78, 0x98,
969 0x00, 0x00, 0x00, 0x00,
970 0x34, 0x0a, 0xf4, 0xce,
971 0xe4
1da177e4
LT
972 };
973
1ce7981b
HV
974 dev->mem = ioremap(mem_base, 0x800);
975 if (!dev->mem)
1da177e4 976 return -ENOMEM;
d56410e0 977
1ce7981b
HV
978 if (!request_region(0x9a01, 1, "Mediavision PMS config")) {
979 printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n");
980 iounmap(dev->mem);
1da177e4
LT
981 return -EBUSY;
982 }
1ce7981b
HV
983 if (!request_region(dev->io, 3, "Mediavision PMS")) {
984 printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io);
985 release_region(0x9a01, 1);
986 iounmap(dev->mem);
1da177e4
LT
987 return -EBUSY;
988 }
1ce7981b
HV
989 outb(0xb8, 0x9a01); /* Unlock */
990 outb(dev->io >> 4, 0x9a01); /* Set IO port */
d56410e0
MCC
991
992
1ce7981b
HV
993 id = mvv_read(dev, 3);
994 decst = pms_i2c_stat(dev, 0x43);
d56410e0 995
1ce7981b
HV
996 if (decst != -1)
997 idec = 2;
998 else if (pms_i2c_stat(dev, 0xb9) != -1)
999 idec = 3;
1000 else if (pms_i2c_stat(dev, 0x8b) != -1)
1001 idec = 1;
d56410e0 1002 else
1ce7981b 1003 idec = 0;
1da177e4
LT
1004
1005 printk(KERN_INFO "PMS type is %d\n", idec);
1ce7981b
HV
1006 if (idec == 0) {
1007 release_region(dev->io, 3);
1008 release_region(0x9a01, 1);
1009 iounmap(dev->mem);
1da177e4
LT
1010 return -ENODEV;
1011 }
1012
1013 /*
1014 * Ok we have a PMS of some sort
1015 */
d56410e0 1016
1ce7981b 1017 mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */
d56410e0 1018
1da177e4 1019 /* Ok now load the defaults */
d56410e0 1020
1ce7981b
HV
1021 for (i = 0; i < 0x19; i++) {
1022 if (i2c_defs[i] == 0xff)
1023 pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00);
1da177e4 1024 else
1ce7981b 1025 pms_i2c_write(dev, 0x8a, i, i2c_defs[i]);
1da177e4 1026 }
d56410e0 1027
1ce7981b
HV
1028 pms_i2c_write(dev, 0xb8, 0x00, 0x12);
1029 pms_i2c_write(dev, 0xb8, 0x04, 0x00);
1030 pms_i2c_write(dev, 0xb8, 0x07, 0x00);
1031 pms_i2c_write(dev, 0xb8, 0x08, 0x00);
1032 pms_i2c_write(dev, 0xb8, 0x09, 0xff);
1033 pms_i2c_write(dev, 0xb8, 0x0a, 0x00);
1034 pms_i2c_write(dev, 0xb8, 0x0b, 0x10);
1035 pms_i2c_write(dev, 0xb8, 0x10, 0x03);
1036
1037 mvv_write(dev, 0x01, 0x00);
1038 mvv_write(dev, 0x05, 0xa0);
1039 mvv_write(dev, 0x08, 0x25);
1040 mvv_write(dev, 0x09, 0x00);
1041 mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH);
1042
1043 mvv_write(dev, 0x10, 0x02);
1044 mvv_write(dev, 0x1e, 0x0c);
1045 mvv_write(dev, 0x1f, 0x03);
1046 mvv_write(dev, 0x26, 0x06);
1047
1048 mvv_write(dev, 0x2b, 0x00);
1049 mvv_write(dev, 0x2c, 0x20);
1050 mvv_write(dev, 0x2d, 0x00);
1051 mvv_write(dev, 0x2f, 0x70);
1052 mvv_write(dev, 0x32, 0x00);
1053 mvv_write(dev, 0x33, MVVMEMORYWIDTH);
1054 mvv_write(dev, 0x34, 0x00);
1055 mvv_write(dev, 0x35, 0x00);
1056 mvv_write(dev, 0x3a, 0x80);
1057 mvv_write(dev, 0x3b, 0x10);
1058 mvv_write(dev, 0x20, 0x00);
1059 mvv_write(dev, 0x21, 0x00);
1060 mvv_write(dev, 0x30, 0x22);
1da177e4
LT
1061 return 0;
1062}
1063
1064/*
1065 * Initialization and module stuff
1066 */
d56410e0 1067
b54ff939
RH
1068#ifndef MODULE
1069static int enable;
1070module_param(enable, int, 0);
1071#endif
1072
1ce7981b 1073static int __init pms_init(void)
1da177e4 1074{
1ce7981b
HV
1075 struct pms *dev = &pms_card;
1076 struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
1077 int res;
1078
1079 strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name));
1080
1081 v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n");
d56410e0 1082
b54ff939
RH
1083#ifndef MODULE
1084 if (!enable) {
1ce7981b
HV
1085 v4l2_err(v4l2_dev,
1086 "PMS: not enabled, use pms.enable=1 to probe\n");
b54ff939
RH
1087 return -ENODEV;
1088 }
1089#endif
1090
1ce7981b
HV
1091 dev->decoder = PHILIPS2;
1092 dev->io = io_port;
1093 dev->data = io_port + 1;
d56410e0 1094
1ce7981b
HV
1095 if (init_mediavision(dev)) {
1096 v4l2_err(v4l2_dev, "Board not found.\n");
1da177e4
LT
1097 return -ENODEV;
1098 }
1da177e4 1099
1ce7981b
HV
1100 res = v4l2_device_register(NULL, v4l2_dev);
1101 if (res < 0) {
1102 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
1103 return res;
1104 }
1da177e4 1105
1ce7981b
HV
1106 strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
1107 dev->vdev.v4l2_dev = v4l2_dev;
1108 dev->vdev.fops = &pms_fops;
feba2f81 1109 dev->vdev.ioctl_ops = &pms_ioctl_ops;
1ce7981b
HV
1110 dev->vdev.release = video_device_release_empty;
1111 video_set_drvdata(&dev->vdev, dev);
1112 mutex_init(&dev->lock);
feba2f81 1113 dev->std = V4L2_STD_NTSC_M;
1ce7981b
HV
1114 dev->height = 240;
1115 dev->width = 320;
feba2f81
HV
1116 dev->depth = 15;
1117 dev->brightness = 139;
1118 dev->contrast = 70;
1119 dev->hue = 0;
1120 dev->saturation = 64;
1ce7981b
HV
1121 pms_swsense(dev, 75);
1122 pms_resolution(dev, 320, 240);
1123 pms_videosource(dev, 0);
1124 pms_vcrinput(dev, 0);
1125 if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
1126 v4l2_device_unregister(&dev->v4l2_dev);
1127 release_region(dev->io, 3);
1128 release_region(0x9a01, 1);
1129 iounmap(dev->mem);
1130 return -EINVAL;
1131 }
1132 return 0;
1da177e4
LT
1133}
1134
1ce7981b 1135static void __exit pms_exit(void)
1da177e4 1136{
1ce7981b 1137 struct pms *dev = &pms_card;
1da177e4 1138
1ce7981b
HV
1139 video_unregister_device(&dev->vdev);
1140 release_region(dev->io, 3);
1141 release_region(0x9a01, 1);
1142 iounmap(dev->mem);
1143}
1da177e4 1144
1ce7981b
HV
1145module_init(pms_init);
1146module_exit(pms_exit);