V4L/DVB: w9966: reorganize the order of functions
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / media / video / w9966.c
CommitLineData
1da177e4
LT
1/*
2 Winbond w9966cf Webcam parport driver.
3
4 Version 0.32
5
6 Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23 Supported devices:
24 *Lifeview FlyCam Supra (using the Philips saa7111a chip)
25
26 Does any other model using the w9966 interface chip exist ?
27
28 Todo:
d56410e0 29
1da177e4
LT
30 *Add a working EPP mode, since DMA ECP read isn't implemented
31 in the parport drivers. (That's why it's so sloow)
32
33 *Add support for other ccd-control chips than the saa7111
34 please send me feedback on what kind of chips you have.
35
36 *Add proper probing. I don't know what's wrong with the IEEE1284
37 parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
38 and nibble read seems to be broken for some peripherals.
39
40 *Add probing for onboard SRAM, port directions etc. (if possible)
41
42 *Add support for the hardware compressed modes (maybe using v4l2)
43
44 *Fix better support for the capture window (no skewed images, v4l
45 interface to capt. window)
46
47 *Probably some bugs that I don't know of
48
49 Please support me by sending feedback!
d56410e0 50
1da177e4 51 Changes:
d56410e0 52
1da177e4
LT
53 Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE
54 and owner support for newer module locks
55*/
56
57#include <linux/module.h>
58#include <linux/init.h>
59#include <linux/delay.h>
7e0a16f6 60#include <linux/videodev.h>
5a0e3ad6 61#include <linux/slab.h>
5e87efa3 62#include <media/v4l2-common.h>
35ea11ff 63#include <media/v4l2-ioctl.h>
1da177e4
LT
64#include <linux/parport.h>
65
ff699e6b 66/*#define DEBUG*/ /* Undef me for production */
1da177e4
LT
67
68#ifdef DEBUG
7e28adb2 69#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
1da177e4
LT
70#else
71#define DPRINTF(x...)
72#endif
73
74/*
75 * Defines, simple typedefs etc.
76 */
77
78#define W9966_DRIVERNAME "W9966CF Webcam"
4bfdd586
HV
79#define W9966_MAXCAMS 4 /* Maximum number of cameras */
80#define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */
81#define W9966_SRAMSIZE 131072 /* 128kb */
82#define W9966_SRAMID 0x02 /* check w9966cf.pdf */
1da177e4 83
4bfdd586 84/* Empirically determined window limits */
1da177e4
LT
85#define W9966_WND_MIN_X 16
86#define W9966_WND_MIN_Y 14
87#define W9966_WND_MAX_X 705
88#define W9966_WND_MAX_Y 253
89#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X)
90#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
91
4bfdd586 92/* Keep track of our current state */
1da177e4
LT
93#define W9966_STATE_PDEV 0x01
94#define W9966_STATE_CLAIMED 0x02
95#define W9966_STATE_VDEV 0x04
96
97#define W9966_I2C_W_ID 0x48
98#define W9966_I2C_R_ID 0x49
99#define W9966_I2C_R_DATA 0x08
100#define W9966_I2C_R_CLOCK 0x04
101#define W9966_I2C_W_DATA 0x02
102#define W9966_I2C_W_CLOCK 0x01
103
104struct w9966_dev {
105 unsigned char dev_state;
106 unsigned char i2c_state;
107 unsigned short ppmode;
4bfdd586
HV
108 struct parport *pport;
109 struct pardevice *pdev;
1da177e4
LT
110 struct video_device vdev;
111 unsigned short width;
112 unsigned short height;
113 unsigned char brightness;
114 signed char contrast;
115 signed char color;
116 signed char hue;
7d43cd53 117 unsigned long in_use;
1da177e4
LT
118};
119
120/*
121 * Module specific properties
122 */
123
124MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
125MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
126MODULE_LICENSE("GPL");
127
128
129#ifdef MODULE
4bfdd586 130static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
1da177e4 131#else
4bfdd586 132static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
1da177e4
LT
133#endif
134module_param_array(pardev, charp, NULL, 0);
4bfdd586
HV
135MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
136 "\teach camera. 'aggressive' means brute-force search.\n"
137 "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n"
138 "\tcam 1 to parport3 and search every parport for cam 2 etc...");
1da177e4 139
ff699e6b 140static int parmode;
1da177e4
LT
141module_param(parmode, int, 0);
142MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
143
144static int video_nr = -1;
145module_param(video_nr, int, 0);
146
1da177e4
LT
147static struct w9966_dev w9966_cams[W9966_MAXCAMS];
148
1da177e4
LT
149/*
150 * Private function defines
151 */
152
153
4bfdd586
HV
154/* Set camera phase flags, so we know what to uninit when terminating */
155static inline void w9966_setState(struct w9966_dev *cam, int mask, int val)
1da177e4
LT
156{
157 cam->dev_state = (cam->dev_state & ~mask) ^ val;
158}
159
4bfdd586
HV
160/* Get camera phase flags */
161static inline int w9966_getState(struct w9966_dev *cam, int mask, int val)
1da177e4
LT
162{
163 return ((cam->dev_state & mask) == val);
164}
165
4bfdd586 166/* Claim parport for ourself */
271922c0 167static void w9966_pdev_claim(struct w9966_dev *cam)
1da177e4
LT
168{
169 if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
170 return;
171 parport_claim_or_block(cam->pdev);
172 w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
173}
174
4bfdd586 175/* Release parport for others to use */
271922c0 176static void w9966_pdev_release(struct w9966_dev *cam)
1da177e4
LT
177{
178 if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
179 return;
180 parport_release(cam->pdev);
181 w9966_setState(cam, W9966_STATE_CLAIMED, 0);
182}
d56410e0 183
4bfdd586
HV
184/* Read register from W9966 interface-chip
185 Expects a claimed pdev
186 -1 on error, else register data (byte) */
187static int w9966_rReg(struct w9966_dev *cam, int reg)
1da177e4 188{
4bfdd586 189 /* ECP, read, regtransfer, REG, REG, REG, REG, REG */
1da177e4
LT
190 const unsigned char addr = 0x80 | (reg & 0x1f);
191 unsigned char val;
d56410e0 192
1da177e4
LT
193 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
194 return -1;
195 if (parport_write(cam->pport, &addr, 1) != 1)
196 return -1;
197 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
198 return -1;
199 if (parport_read(cam->pport, &val, 1) != 1)
200 return -1;
201
202 return val;
203}
204
4bfdd586
HV
205/* Write register to W9966 interface-chip
206 Expects a claimed pdev
207 -1 on error */
208static int w9966_wReg(struct w9966_dev *cam, int reg, int data)
1da177e4 209{
4bfdd586 210 /* ECP, write, regtransfer, REG, REG, REG, REG, REG */
1da177e4
LT
211 const unsigned char addr = 0xc0 | (reg & 0x1f);
212 const unsigned char val = data;
d56410e0 213
1da177e4
LT
214 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
215 return -1;
216 if (parport_write(cam->pport, &addr, 1) != 1)
217 return -1;
218 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
219 return -1;
220 if (parport_write(cam->pport, &val, 1) != 1)
221 return -1;
222
223 return 0;
224}
225
271922c0
HV
226/*
227 * Ugly and primitive i2c protocol functions
228 */
229
230/* Sets the data line on the i2c bus.
231 Expects a claimed pdev. */
232static void w9966_i2c_setsda(struct w9966_dev *cam, int state)
1da177e4 233{
271922c0
HV
234 if (state)
235 cam->i2c_state |= W9966_I2C_W_DATA;
236 else
237 cam->i2c_state &= ~W9966_I2C_W_DATA;
d56410e0 238
271922c0
HV
239 w9966_wReg(cam, 0x18, cam->i2c_state);
240 udelay(5);
241}
1da177e4 242
271922c0
HV
243/* Get peripheral clock line
244 Expects a claimed pdev. */
245static int w9966_i2c_getscl(struct w9966_dev *cam)
246{
247 const unsigned char state = w9966_rReg(cam, 0x18);
248 return ((state & W9966_I2C_R_CLOCK) > 0);
249}
250
251/* Sets the clock line on the i2c bus.
252 Expects a claimed pdev. -1 on error */
253static int w9966_i2c_setscl(struct w9966_dev *cam, int state)
254{
255 unsigned long timeout;
256
257 if (state)
258 cam->i2c_state |= W9966_I2C_W_CLOCK;
259 else
260 cam->i2c_state &= ~W9966_I2C_W_CLOCK;
261
262 w9966_wReg(cam, 0x18, cam->i2c_state);
263 udelay(5);
264
265 /* we go to high, we also expect the peripheral to ack. */
266 if (state) {
267 timeout = jiffies + 100;
268 while (!w9966_i2c_getscl(cam)) {
269 if (time_after(jiffies, timeout))
270 return -1;
271 }
1da177e4 272 }
271922c0
HV
273 return 0;
274}
d56410e0 275
271922c0
HV
276#if 0
277/* Get peripheral data line
278 Expects a claimed pdev. */
279static int w9966_i2c_getsda(struct w9966_dev *cam)
280{
281 const unsigned char state = w9966_rReg(cam, 0x18);
282 return ((state & W9966_I2C_R_DATA) > 0);
283}
284#endif
285
286/* Write a byte with ack to the i2c bus.
287 Expects a claimed pdev. -1 on error */
288static int w9966_i2c_wbyte(struct w9966_dev *cam, int data)
289{
290 int i;
291
292 for (i = 7; i >= 0; i--) {
293 w9966_i2c_setsda(cam, (data >> i) & 0x01);
294
295 if (w9966_i2c_setscl(cam, 1) == -1)
296 return -1;
297 w9966_i2c_setscl(cam, 0);
1da177e4 298 }
1da177e4 299
271922c0 300 w9966_i2c_setsda(cam, 1);
d56410e0 301
271922c0 302 if (w9966_i2c_setscl(cam, 1) == -1)
1da177e4 303 return -1;
271922c0
HV
304 w9966_i2c_setscl(cam, 0);
305
306 return 0;
307}
308
309/* Read a data byte with ack from the i2c-bus
310 Expects a claimed pdev. -1 on error */
311#if 0
312static int w9966_i2c_rbyte(struct w9966_dev *cam)
313{
314 unsigned char data = 0x00;
315 int i;
316
317 w9966_i2c_setsda(cam, 1);
318
319 for (i = 0; i < 8; i++) {
320 if (w9966_i2c_setscl(cam, 1) == -1)
321 return -1;
322 data = data << 1;
323 if (w9966_i2c_getsda(cam))
324 data |= 0x01;
325
326 w9966_i2c_setscl(cam, 0);
1da177e4 327 }
271922c0
HV
328 return data;
329}
330#endif
1da177e4 331
271922c0
HV
332/* Read a register from the i2c device.
333 Expects claimed pdev. -1 on error */
334#if 0
335static int w9966_rReg_i2c(struct w9966_dev *cam, int reg)
336{
337 int data;
1da177e4 338
271922c0
HV
339 w9966_i2c_setsda(cam, 0);
340 w9966_i2c_setscl(cam, 0);
1da177e4 341
271922c0
HV
342 if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
343 w9966_i2c_wbyte(cam, reg) == -1)
1da177e4 344 return -1;
d56410e0 345
271922c0
HV
346 w9966_i2c_setsda(cam, 1);
347 if (w9966_i2c_setscl(cam, 1) == -1)
348 return -1;
349 w9966_i2c_setsda(cam, 0);
350 w9966_i2c_setscl(cam, 0);
d56410e0 351
271922c0
HV
352 if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1)
353 return -1;
354 data = w9966_i2c_rbyte(cam);
355 if (data == -1)
356 return -1;
1da177e4 357
271922c0 358 w9966_i2c_setsda(cam, 0);
1da177e4 359
271922c0
HV
360 if (w9966_i2c_setscl(cam, 1) == -1)
361 return -1;
362 w9966_i2c_setsda(cam, 1);
363
364 return data;
365}
366#endif
367
368/* Write a register to the i2c device.
369 Expects claimed pdev. -1 on error */
370static int w9966_wReg_i2c(struct w9966_dev *cam, int reg, int data)
1da177e4 371{
271922c0
HV
372 w9966_i2c_setsda(cam, 0);
373 w9966_i2c_setscl(cam, 0);
1da177e4 374
271922c0
HV
375 if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
376 w9966_i2c_wbyte(cam, reg) == -1 ||
377 w9966_i2c_wbyte(cam, data) == -1)
378 return -1;
1da177e4 379
271922c0
HV
380 w9966_i2c_setsda(cam, 0);
381 if (w9966_i2c_setscl(cam, 1) == -1)
382 return -1;
383
384 w9966_i2c_setsda(cam, 1);
1da177e4 385
271922c0
HV
386 return 0;
387}
1da177e4 388
4bfdd586
HV
389/* Find a good length for capture window (used both for W and H)
390 A bit ugly but pretty functional. The capture length
391 have to match the downscale */
1da177e4
LT
392static int w9966_findlen(int near, int size, int maxlen)
393{
394 int bestlen = size;
395 int besterr = abs(near - bestlen);
396 int len;
397
4bfdd586 398 for (len = size + 1; len < maxlen; len++) {
1da177e4 399 int err;
4bfdd586 400 if (((64 * size) % len) != 0)
1da177e4
LT
401 continue;
402
403 err = abs(near - len);
404
4bfdd586 405 /* Only continue as long as we keep getting better values */
1da177e4
LT
406 if (err > besterr)
407 break;
d56410e0 408
1da177e4
LT
409 besterr = err;
410 bestlen = len;
411 }
412
413 return bestlen;
414}
415
4bfdd586
HV
416/* Modify capture window (if necessary)
417 and calculate downscaling
418 Return -1 on error */
419static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor)
1da177e4
LT
420{
421 int maxlen = max - min;
422 int len = *end - *beg + 1;
423 int newlen = w9966_findlen(len, size, maxlen);
d56410e0 424 int err = newlen - len;
1da177e4 425
4bfdd586 426 /* Check for bad format */
1da177e4
LT
427 if (newlen > maxlen || newlen < size)
428 return -1;
429
4bfdd586
HV
430 /* Set factor (6 bit fixed) */
431 *factor = (64 * size) / newlen;
1da177e4 432 if (*factor == 64)
4bfdd586 433 *factor = 0x00; /* downscale is disabled */
1da177e4 434 else
4bfdd586 435 *factor |= 0x80; /* set downscale-enable bit */
1da177e4 436
4bfdd586 437 /* Modify old beginning and end */
1da177e4
LT
438 *beg -= err / 2;
439 *end += err - (err / 2);
440
4bfdd586 441 /* Move window if outside borders */
1da177e4
LT
442 if (*beg < min) {
443 *end += min - *beg;
444 *beg += min - *beg;
445 }
446 if (*end > max) {
447 *beg -= *end - max;
448 *end -= *end - max;
449 }
450
451 return 0;
452}
453
4bfdd586
HV
454/* Setup the cameras capture window etc.
455 Expects a claimed pdev
456 return -1 on error */
457static int w9966_setup(struct w9966_dev *cam, int x1, int y1, int x2, int y2, int w, int h)
1da177e4
LT
458{
459 unsigned int i;
460 unsigned int enh_s, enh_e;
461 unsigned char scale_x, scale_y;
462 unsigned char regs[0x1c];
463 unsigned char saa7111_regs[] = {
464 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
465 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
466 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
468 };
d56410e0
MCC
469
470
4bfdd586 471 if (w * h * 2 > W9966_SRAMSIZE) {
1da177e4 472 DPRINTF("capture window exceeds SRAM size!.\n");
4bfdd586 473 w = 200; h = 160; /* Pick default values */
1da177e4
LT
474 }
475
476 w &= ~0x1;
4bfdd586
HV
477 if (w < 2)
478 w = 2;
479 if (h < 1)
480 h = 1;
481 if (w > W9966_WND_MAX_W)
482 w = W9966_WND_MAX_W;
483 if (h > W9966_WND_MAX_H)
484 h = W9966_WND_MAX_H;
1da177e4
LT
485
486 cam->width = w;
487 cam->height = h;
488
d56410e0 489 enh_s = 0;
4bfdd586
HV
490 enh_e = w * h * 2;
491
492/* Modify capture window if necessary and calculate downscaling */
493 if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
494 w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0)
495 return -1;
496
497 DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
498 w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80);
499
500/* Setup registers */
501 regs[0x00] = 0x00; /* Set normal operation */
502 regs[0x01] = 0x18; /* Capture mode */
503 regs[0x02] = scale_y; /* V-scaling */
504 regs[0x03] = scale_x; /* H-scaling */
505
506 /* Capture window */
507 regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */
508 regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */
509 regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */
510 regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */
511 regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */
512 regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */
513 regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */
514
515 regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */
516
517 /* Enhancement layer */
518 regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */
519 regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */
520 regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */
521 regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */
522 regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */
523 regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */
524
525 /* Misc */
526 regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */
527 regs[0x17] = 0x00; /* ??? */
528 regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */
529 regs[0x19] = 0xff; /* I/O port direction control */
530 regs[0x1a] = 0xff; /* I/O port data register */
531 regs[0x1b] = 0x10; /* ??? */
532
533 /* SAA7111 chip settings */
1da177e4
LT
534 saa7111_regs[0x0a] = cam->brightness;
535 saa7111_regs[0x0b] = cam->contrast;
536 saa7111_regs[0x0c] = cam->color;
537 saa7111_regs[0x0d] = cam->hue;
538
4bfdd586 539/* Reset (ECP-fifo & serial-bus) */
1da177e4
LT
540 if (w9966_wReg(cam, 0x00, 0x03) == -1)
541 return -1;
542
4bfdd586 543/* Write regs to w9966cf chip */
1da177e4
LT
544 for (i = 0; i < 0x1c; i++)
545 if (w9966_wReg(cam, i, regs[i]) == -1)
546 return -1;
547
4bfdd586 548/* Write regs to saa7111 chip */
1da177e4
LT
549 for (i = 0; i < 0x20; i++)
550 if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
551 return -1;
552
553 return 0;
554}
555
556/*
271922c0 557 * Video4linux interfacing
1da177e4
LT
558 */
559
271922c0 560static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
1da177e4 561{
c170ecf4 562 struct w9966_dev *cam = video_drvdata(file);
d56410e0 563
4bfdd586 564 switch (cmd) {
1da177e4
LT
565 case VIDIOCGCAP:
566 {
567 static struct video_capability vcap = {
568 .name = W9966_DRIVERNAME,
569 .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
570 .channels = 1,
571 .maxwidth = W9966_WND_MAX_W,
572 .maxheight = W9966_WND_MAX_H,
573 .minwidth = 2,
574 .minheight = 1,
575 };
576 struct video_capability *cap = arg;
577 *cap = vcap;
578 return 0;
579 }
580 case VIDIOCGCHAN:
581 {
582 struct video_channel *vch = arg;
4bfdd586 583 if (vch->channel != 0) /* We only support one channel (#0) */
1da177e4 584 return -EINVAL;
4bfdd586 585 memset(vch, 0, sizeof(*vch));
1da177e4
LT
586 strcpy(vch->name, "CCD-input");
587 vch->type = VIDEO_TYPE_CAMERA;
588 return 0;
589 }
590 case VIDIOCSCHAN:
591 {
592 struct video_channel *vch = arg;
4bfdd586 593 if (vch->channel != 0)
1da177e4
LT
594 return -EINVAL;
595 return 0;
596 }
597 case VIDIOCGTUNER:
598 {
599 struct video_tuner *vtune = arg;
4bfdd586 600 if (vtune->tuner != 0)
1da177e4
LT
601 return -EINVAL;
602 strcpy(vtune->name, "no tuner");
603 vtune->rangelow = 0;
604 vtune->rangehigh = 0;
605 vtune->flags = VIDEO_TUNER_NORM;
606 vtune->mode = VIDEO_MODE_AUTO;
607 vtune->signal = 0xffff;
608 return 0;
609 }
610 case VIDIOCSTUNER:
611 {
612 struct video_tuner *vtune = arg;
613 if (vtune->tuner != 0)
614 return -EINVAL;
615 if (vtune->mode != VIDEO_MODE_AUTO)
616 return -EINVAL;
617 return 0;
618 }
619 case VIDIOCGPICT:
620 {
621 struct video_picture vpic = {
4bfdd586
HV
622 cam->brightness << 8, /* brightness */
623 (cam->hue + 128) << 8, /* hue */
624 cam->color << 9, /* color */
625 cam->contrast << 9, /* contrast */
626 0x8000, /* whiteness */
627 16, VIDEO_PALETTE_YUV422/* bpp, palette format */
1da177e4
LT
628 };
629 struct video_picture *pic = arg;
630 *pic = vpic;
631 return 0;
632 }
633 case VIDIOCSPICT:
634 {
635 struct video_picture *vpic = arg;
2485eb0a 636 if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
1da177e4 637 return -EINVAL;
d56410e0 638
1da177e4
LT
639 cam->brightness = vpic->brightness >> 8;
640 cam->hue = (vpic->hue >> 8) - 128;
641 cam->color = vpic->colour >> 9;
642 cam->contrast = vpic->contrast >> 9;
643
644 w9966_pdev_claim(cam);
d56410e0 645
1da177e4
LT
646 if (
647 w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
648 w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
649 w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
650 w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
651 ) {
652 w9966_pdev_release(cam);
653 return -EIO;
654 }
d56410e0 655
1da177e4
LT
656 w9966_pdev_release(cam);
657 return 0;
658 }
659 case VIDIOCSWIN:
660 {
661 int ret;
662 struct video_window *vwin = arg;
d56410e0 663
1da177e4
LT
664 if (vwin->flags != 0)
665 return -EINVAL;
666 if (vwin->clipcount != 0)
667 return -EINVAL;
668 if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
d56410e0 669 return -EINVAL;
1da177e4
LT
670 if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
671 return -EINVAL;
672
4bfdd586 673 /* Update camera regs */
1da177e4
LT
674 w9966_pdev_claim(cam);
675 ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
676 w9966_pdev_release(cam);
d56410e0 677
1da177e4
LT
678 if (ret != 0) {
679 DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
680 return -EIO;
681 }
d56410e0 682
1da177e4
LT
683 return 0;
684 }
685 case VIDIOCGWIN:
686 {
687 struct video_window *vwin = arg;
688 memset(vwin, 0, sizeof(*vwin));
689 vwin->width = cam->width;
690 vwin->height = cam->height;
691 return 0;
692 }
4bfdd586 693 /* Unimplemented */
d56410e0 694 case VIDIOCCAPTURE:
1da177e4
LT
695 case VIDIOCGFBUF:
696 case VIDIOCSFBUF:
697 case VIDIOCKEY:
698 case VIDIOCGFREQ:
699 case VIDIOCSFREQ:
700 case VIDIOCGAUDIO:
701 case VIDIOCSAUDIO:
702 return -EINVAL;
703 default:
704 return -ENOIOCTLCMD;
705 }
706 return 0;
707}
708
069b7479 709static long w9966_v4l_ioctl(struct file *file,
1da177e4
LT
710 unsigned int cmd, unsigned long arg)
711{
f473bf76 712 return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
1da177e4
LT
713}
714
4bfdd586 715/* Capture data */
1da177e4
LT
716static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
717 size_t count, loff_t *ppos)
718{
c170ecf4 719 struct w9966_dev *cam = video_drvdata(file);
4bfdd586 720 unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */
1da177e4
LT
721 unsigned char __user *dest = (unsigned char __user *)buf;
722 unsigned long dleft = count;
723 unsigned char *tbuf;
d56410e0 724
4bfdd586 725 /* Why would anyone want more than this?? */
1da177e4
LT
726 if (count > cam->width * cam->height * 2)
727 return -EINVAL;
d56410e0 728
1da177e4 729 w9966_pdev_claim(cam);
4bfdd586
HV
730 w9966_wReg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */
731 w9966_wReg(cam, 0x00, 0x00); /* Return to normal operation */
732 w9966_wReg(cam, 0x01, 0x98); /* Enable capture */
733
734 /* write special capture-addr and negotiate into data transfer */
735 if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) ||
736 (parport_write(cam->pport, &addr, 1) != 1) ||
737 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
1da177e4
LT
738 w9966_pdev_release(cam);
739 return -EFAULT;
740 }
741
742 tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
743 if (tbuf == NULL) {
744 count = -ENOMEM;
745 goto out;
746 }
747
4bfdd586 748 while (dleft > 0) {
1da177e4 749 unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
d56410e0 750
1da177e4
LT
751 if (parport_read(cam->pport, tbuf, tsize) < tsize) {
752 count = -EFAULT;
753 goto out;
754 }
755 if (copy_to_user(dest, tbuf, tsize) != 0) {
756 count = -EFAULT;
757 goto out;
758 }
759 dest += tsize;
760 dleft -= tsize;
761 }
762
4bfdd586 763 w9966_wReg(cam, 0x01, 0x18); /* Disable capture */
1da177e4
LT
764
765out:
766 kfree(tbuf);
767 w9966_pdev_release(cam);
768
769 return count;
770}
771
271922c0
HV
772static int w9966_exclusive_open(struct file *file)
773{
774 struct w9966_dev *cam = video_drvdata(file);
775
776 return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
777}
778
779static int w9966_exclusive_release(struct file *file)
780{
781 struct w9966_dev *cam = video_drvdata(file);
782
783 clear_bit(0, &cam->in_use);
784 return 0;
785}
786
787static const struct v4l2_file_operations w9966_fops = {
788 .owner = THIS_MODULE,
789 .open = w9966_exclusive_open,
790 .release = w9966_exclusive_release,
791 .ioctl = w9966_v4l_ioctl,
792 .read = w9966_v4l_read,
793};
794
795static struct video_device w9966_template = {
796 .name = W9966_DRIVERNAME,
797 .fops = &w9966_fops,
798 .release = video_device_release_empty,
799};
800
801
802/* Initialize camera device. Setup all internal flags, set a
803 default video mode, setup ccd-chip, register v4l device etc..
804 Also used for 'probing' of hardware.
805 -1 on error */
806static int w9966_init(struct w9966_dev *cam, struct parport* port)
807{
808 if (cam->dev_state != 0)
809 return -1;
810
811 cam->pport = port;
812 cam->brightness = 128;
813 cam->contrast = 64;
814 cam->color = 64;
815 cam->hue = 0;
816
817/* Select requested transfer mode */
818 switch (parmode) {
819 default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */
820 case 0:
821 if (port->modes & PARPORT_MODE_ECP)
822 cam->ppmode = IEEE1284_MODE_ECP;
823 else if (port->modes & PARPORT_MODE_EPP)
824 cam->ppmode = IEEE1284_MODE_EPP;
825 else
826 cam->ppmode = IEEE1284_MODE_ECP;
827 break;
828 case 1: /* hw- or sw-ecp */
829 cam->ppmode = IEEE1284_MODE_ECP;
830 break;
831 case 2: /* hw- or sw-epp */
832 cam->ppmode = IEEE1284_MODE_EPP;
833 break;
834 }
835
836/* Tell the parport driver that we exists */
837 cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
838 if (cam->pdev == NULL) {
839 DPRINTF("parport_register_device() failed\n");
840 return -1;
841 }
842 w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
843
844 w9966_pdev_claim(cam);
845
846/* Setup a default capture mode */
847 if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
848 DPRINTF("w9966_setup() failed.\n");
849 return -1;
850 }
851
852 w9966_pdev_release(cam);
853
854/* Fill in the video_device struct and register us to v4l */
855 memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
856 video_set_drvdata(&cam->vdev, cam);
857
858 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
859 return -1;
860
861 w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
862
863 /* All ok */
864 printk(KERN_INFO "w9966cf: Found and initialized a webcam on %s.\n",
865 cam->pport->name);
866 return 0;
867}
868
869
870/* Terminate everything gracefully */
871static void w9966_term(struct w9966_dev *cam)
872{
873/* Unregister from v4l */
874 if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
875 video_unregister_device(&cam->vdev);
876 w9966_setState(cam, W9966_STATE_VDEV, 0);
877 }
878
879/* Terminate from IEEE1284 mode and release pdev block */
880 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
881 w9966_pdev_claim(cam);
882 parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
883 w9966_pdev_release(cam);
884 }
885
886/* Unregister from parport */
887 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
888 parport_unregister_device(cam->pdev);
889 w9966_setState(cam, W9966_STATE_PDEV, 0);
890 }
891}
892
1da177e4 893
4bfdd586 894/* Called once for every parport on init */
1da177e4
LT
895static void w9966_attach(struct parport *port)
896{
897 int i;
d56410e0 898
4bfdd586
HV
899 for (i = 0; i < W9966_MAXCAMS; i++) {
900 if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */
1da177e4 901 continue;
4bfdd586 902 if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) {
1da177e4 903 if (w9966_init(&w9966_cams[i], port) != 0)
4bfdd586
HV
904 w9966_term(&w9966_cams[i]);
905 break; /* return */
1da177e4
LT
906 }
907 }
908}
909
4bfdd586 910/* Called once for every parport on termination */
1da177e4
LT
911static void w9966_detach(struct parport *port)
912{
913 int i;
4bfdd586 914
1da177e4 915 for (i = 0; i < W9966_MAXCAMS; i++)
4bfdd586
HV
916 if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
917 w9966_term(&w9966_cams[i]);
1da177e4
LT
918}
919
920
921static struct parport_driver w9966_ppd = {
922 .name = W9966_DRIVERNAME,
923 .attach = w9966_attach,
924 .detach = w9966_detach,
925};
926
4bfdd586 927/* Module entry point */
1da177e4
LT
928static int __init w9966_mod_init(void)
929{
930 int i;
4bfdd586 931
1da177e4
LT
932 for (i = 0; i < W9966_MAXCAMS; i++)
933 w9966_cams[i].dev_state = 0;
934
935 return parport_register_driver(&w9966_ppd);
936}
937
4bfdd586 938/* Module cleanup */
1da177e4
LT
939static void __exit w9966_mod_term(void)
940{
941 parport_unregister_driver(&w9966_ppd);
942}
943
944module_init(w9966_mod_init);
945module_exit(w9966_mod_term);