[PATCH] lockdep: fix delayacct locking bug
[linux-2.6/verdex.git] / drivers / media / video / w9966.c
blob4bdc886abc4c69e5afa2ece884d5be8977392ce8
1 /*
2 Winbond w9966cf Webcam parport driver.
4 Version 0.32
6 Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
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.
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.
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.
23 Supported devices:
24 *Lifeview FlyCam Supra (using the Philips saa7111a chip)
26 Does any other model using the w9966 interface chip exist ?
28 Todo:
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)
33 *Add support for other ccd-control chips than the saa7111
34 please send me feedback on what kind of chips you have.
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.
40 *Add probing for onboard SRAM, port directions etc. (if possible)
42 *Add support for the hardware compressed modes (maybe using v4l2)
44 *Fix better support for the capture window (no skewed images, v4l
45 interface to capt. window)
47 *Probably some bugs that I don't know of
49 Please support me by sending feedback!
51 Changes:
53 Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE
54 and owner support for newer module locks
57 #include <linux/module.h>
58 #include <linux/init.h>
59 #include <linux/delay.h>
60 #include <linux/videodev.h>
61 #include <media/v4l2-common.h>
62 #include <linux/parport.h>
64 //#define DEBUG // Undef me for production
66 #ifdef DEBUG
67 #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __FUNCTION__ , ##a)
68 #else
69 #define DPRINTF(x...)
70 #endif
73 * Defines, simple typedefs etc.
76 #define W9966_DRIVERNAME "W9966CF Webcam"
77 #define W9966_MAXCAMS 4 // Maximum number of cameras
78 #define W9966_RBUFFER 2048 // Read buffer (must be an even number)
79 #define W9966_SRAMSIZE 131072 // 128kb
80 #define W9966_SRAMID 0x02 // check w9966cf.pdf
82 // Empirically determined window limits
83 #define W9966_WND_MIN_X 16
84 #define W9966_WND_MIN_Y 14
85 #define W9966_WND_MAX_X 705
86 #define W9966_WND_MAX_Y 253
87 #define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X)
88 #define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
90 // Keep track of our current state
91 #define W9966_STATE_PDEV 0x01
92 #define W9966_STATE_CLAIMED 0x02
93 #define W9966_STATE_VDEV 0x04
95 #define W9966_I2C_W_ID 0x48
96 #define W9966_I2C_R_ID 0x49
97 #define W9966_I2C_R_DATA 0x08
98 #define W9966_I2C_R_CLOCK 0x04
99 #define W9966_I2C_W_DATA 0x02
100 #define W9966_I2C_W_CLOCK 0x01
102 struct w9966_dev {
103 unsigned char dev_state;
104 unsigned char i2c_state;
105 unsigned short ppmode;
106 struct parport* pport;
107 struct pardevice* pdev;
108 struct video_device vdev;
109 unsigned short width;
110 unsigned short height;
111 unsigned char brightness;
112 signed char contrast;
113 signed char color;
114 signed char hue;
118 * Module specific properties
121 MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
122 MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
123 MODULE_LICENSE("GPL");
126 #ifdef MODULE
127 static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
128 #else
129 static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
130 #endif
131 module_param_array(pardev, charp, NULL, 0);
132 MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
133 \teach camera. 'aggressive' means brute-force search.\n\
134 \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
135 \tcam 1 to parport3 and search every parport for cam 2 etc...");
137 static int parmode = 0;
138 module_param(parmode, int, 0);
139 MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
141 static int video_nr = -1;
142 module_param(video_nr, int, 0);
145 * Private data
148 static struct w9966_dev w9966_cams[W9966_MAXCAMS];
151 * Private function declares
154 static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
155 static inline int w9966_getState(struct w9966_dev* cam, int mask, int val);
156 static inline void w9966_pdev_claim(struct w9966_dev *vdev);
157 static inline void w9966_pdev_release(struct w9966_dev *vdev);
159 static int w9966_rReg(struct w9966_dev* cam, int reg);
160 static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
161 #if 0
162 static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
163 #endif
164 static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
165 static int w9966_findlen(int near, int size, int maxlen);
166 static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
167 static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
169 static int w9966_init(struct w9966_dev* cam, struct parport* port);
170 static void w9966_term(struct w9966_dev* cam);
172 static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
173 static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state);
174 static inline int w9966_i2c_getsda(struct w9966_dev* cam);
175 static inline int w9966_i2c_getscl(struct w9966_dev* cam);
176 static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
177 #if 0
178 static int w9966_i2c_rbyte(struct w9966_dev* cam);
179 #endif
181 static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
182 unsigned int cmd, unsigned long arg);
183 static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
184 size_t count, loff_t *ppos);
186 static struct file_operations w9966_fops = {
187 .owner = THIS_MODULE,
188 .open = video_exclusive_open,
189 .release = video_exclusive_release,
190 .ioctl = w9966_v4l_ioctl,
191 .compat_ioctl = v4l_compat_ioctl32,
192 .read = w9966_v4l_read,
193 .llseek = no_llseek,
195 static struct video_device w9966_template = {
196 .owner = THIS_MODULE,
197 .name = W9966_DRIVERNAME,
198 .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
199 .hardware = VID_HARDWARE_W9966,
200 .fops = &w9966_fops,
204 * Private function defines
208 // Set camera phase flags, so we know what to uninit when terminating
209 static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
211 cam->dev_state = (cam->dev_state & ~mask) ^ val;
214 // Get camera phase flags
215 static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
217 return ((cam->dev_state & mask) == val);
220 // Claim parport for ourself
221 static inline void w9966_pdev_claim(struct w9966_dev* cam)
223 if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
224 return;
225 parport_claim_or_block(cam->pdev);
226 w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
229 // Release parport for others to use
230 static inline void w9966_pdev_release(struct w9966_dev* cam)
232 if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
233 return;
234 parport_release(cam->pdev);
235 w9966_setState(cam, W9966_STATE_CLAIMED, 0);
238 // Read register from W9966 interface-chip
239 // Expects a claimed pdev
240 // -1 on error, else register data (byte)
241 static int w9966_rReg(struct w9966_dev* cam, int reg)
243 // ECP, read, regtransfer, REG, REG, REG, REG, REG
244 const unsigned char addr = 0x80 | (reg & 0x1f);
245 unsigned char val;
247 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
248 return -1;
249 if (parport_write(cam->pport, &addr, 1) != 1)
250 return -1;
251 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
252 return -1;
253 if (parport_read(cam->pport, &val, 1) != 1)
254 return -1;
256 return val;
259 // Write register to W9966 interface-chip
260 // Expects a claimed pdev
261 // -1 on error
262 static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
264 // ECP, write, regtransfer, REG, REG, REG, REG, REG
265 const unsigned char addr = 0xc0 | (reg & 0x1f);
266 const unsigned char val = data;
268 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
269 return -1;
270 if (parport_write(cam->pport, &addr, 1) != 1)
271 return -1;
272 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
273 return -1;
274 if (parport_write(cam->pport, &val, 1) != 1)
275 return -1;
277 return 0;
280 // Initialize camera device. Setup all internal flags, set a
281 // default video mode, setup ccd-chip, register v4l device etc..
282 // Also used for 'probing' of hardware.
283 // -1 on error
284 static int w9966_init(struct w9966_dev* cam, struct parport* port)
286 if (cam->dev_state != 0)
287 return -1;
289 cam->pport = port;
290 cam->brightness = 128;
291 cam->contrast = 64;
292 cam->color = 64;
293 cam->hue = 0;
295 // Select requested transfer mode
296 switch(parmode)
298 default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
299 case 0:
300 if (port->modes & PARPORT_MODE_ECP)
301 cam->ppmode = IEEE1284_MODE_ECP;
302 else if (port->modes & PARPORT_MODE_EPP)
303 cam->ppmode = IEEE1284_MODE_EPP;
304 else
305 cam->ppmode = IEEE1284_MODE_ECP;
306 break;
307 case 1: // hw- or sw-ecp
308 cam->ppmode = IEEE1284_MODE_ECP;
309 break;
310 case 2: // hw- or sw-epp
311 cam->ppmode = IEEE1284_MODE_EPP;
312 break;
315 // Tell the parport driver that we exists
316 cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
317 if (cam->pdev == NULL) {
318 DPRINTF("parport_register_device() failed\n");
319 return -1;
321 w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
323 w9966_pdev_claim(cam);
325 // Setup a default capture mode
326 if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
327 DPRINTF("w9966_setup() failed.\n");
328 return -1;
331 w9966_pdev_release(cam);
333 // Fill in the video_device struct and register us to v4l
334 memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
335 cam->vdev.priv = cam;
337 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
338 return -1;
340 w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
342 // All ok
343 printk(
344 "w9966cf: Found and initialized a webcam on %s.\n",
345 cam->pport->name
347 return 0;
351 // Terminate everything gracefully
352 static void w9966_term(struct w9966_dev* cam)
354 // Unregister from v4l
355 if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
356 video_unregister_device(&cam->vdev);
357 w9966_setState(cam, W9966_STATE_VDEV, 0);
360 // Terminate from IEEE1284 mode and release pdev block
361 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
362 w9966_pdev_claim(cam);
363 parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
364 w9966_pdev_release(cam);
367 // Unregister from parport
368 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
369 parport_unregister_device(cam->pdev);
370 w9966_setState(cam, W9966_STATE_PDEV, 0);
375 // Find a good length for capture window (used both for W and H)
376 // A bit ugly but pretty functional. The capture length
377 // have to match the downscale
378 static int w9966_findlen(int near, int size, int maxlen)
380 int bestlen = size;
381 int besterr = abs(near - bestlen);
382 int len;
384 for(len = size+1;len < maxlen;len++)
386 int err;
387 if ( ((64*size) %len) != 0)
388 continue;
390 err = abs(near - len);
392 // Only continue as long as we keep getting better values
393 if (err > besterr)
394 break;
396 besterr = err;
397 bestlen = len;
400 return bestlen;
403 // Modify capture window (if necessary)
404 // and calculate downscaling
405 // Return -1 on error
406 static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
408 int maxlen = max - min;
409 int len = *end - *beg + 1;
410 int newlen = w9966_findlen(len, size, maxlen);
411 int err = newlen - len;
413 // Check for bad format
414 if (newlen > maxlen || newlen < size)
415 return -1;
417 // Set factor (6 bit fixed)
418 *factor = (64*size) / newlen;
419 if (*factor == 64)
420 *factor = 0x00; // downscale is disabled
421 else
422 *factor |= 0x80; // set downscale-enable bit
424 // Modify old beginning and end
425 *beg -= err / 2;
426 *end += err - (err / 2);
428 // Move window if outside borders
429 if (*beg < min) {
430 *end += min - *beg;
431 *beg += min - *beg;
433 if (*end > max) {
434 *beg -= *end - max;
435 *end -= *end - max;
438 return 0;
441 // Setup the cameras capture window etc.
442 // Expects a claimed pdev
443 // return -1 on error
444 static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
446 unsigned int i;
447 unsigned int enh_s, enh_e;
448 unsigned char scale_x, scale_y;
449 unsigned char regs[0x1c];
450 unsigned char saa7111_regs[] = {
451 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
452 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
453 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
458 if (w*h*2 > W9966_SRAMSIZE)
460 DPRINTF("capture window exceeds SRAM size!.\n");
461 w = 200; h = 160; // Pick default values
464 w &= ~0x1;
465 if (w < 2) w = 2;
466 if (h < 1) h = 1;
467 if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
468 if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
470 cam->width = w;
471 cam->height = h;
473 enh_s = 0;
474 enh_e = w*h*2;
476 // Modify capture window if necessary and calculate downscaling
477 if (
478 w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
479 w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
480 ) return -1;
482 DPRINTF(
483 "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
484 w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
487 // Setup registers
488 regs[0x00] = 0x00; // Set normal operation
489 regs[0x01] = 0x18; // Capture mode
490 regs[0x02] = scale_y; // V-scaling
491 regs[0x03] = scale_x; // H-scaling
493 // Capture window
494 regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits)
495 regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits)
496 regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits)
497 regs[0x07] = (y1 & 0x300)>>8; // Y-start (2 high bits)
498 regs[0x08] = (x2 & 0x0ff); // X-end (8 low bits)
499 regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits)
500 regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits)
502 regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb)
504 // Enhancement layer
505 regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7)
506 regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15)
507 regs[0x0f] = (enh_s& 0x70000)>>16; // Enh. start (16-17/18??)
508 regs[0x10] = (enh_e& 0x000ff); // Enh. end (0-7)
509 regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15)
510 regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??)
512 // Misc
513 regs[0x13] = 0x40; // VEE control (raw 4:2:2)
514 regs[0x17] = 0x00; // ???
515 regs[0x18] = cam->i2c_state = 0x00; // Serial bus
516 regs[0x19] = 0xff; // I/O port direction control
517 regs[0x1a] = 0xff; // I/O port data register
518 regs[0x1b] = 0x10; // ???
520 // SAA7111 chip settings
521 saa7111_regs[0x0a] = cam->brightness;
522 saa7111_regs[0x0b] = cam->contrast;
523 saa7111_regs[0x0c] = cam->color;
524 saa7111_regs[0x0d] = cam->hue;
526 // Reset (ECP-fifo & serial-bus)
527 if (w9966_wReg(cam, 0x00, 0x03) == -1)
528 return -1;
530 // Write regs to w9966cf chip
531 for (i = 0; i < 0x1c; i++)
532 if (w9966_wReg(cam, i, regs[i]) == -1)
533 return -1;
535 // Write regs to saa7111 chip
536 for (i = 0; i < 0x20; i++)
537 if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
538 return -1;
540 return 0;
544 * Ugly and primitive i2c protocol functions
547 // Sets the data line on the i2c bus.
548 // Expects a claimed pdev.
549 static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
551 if (state)
552 cam->i2c_state |= W9966_I2C_W_DATA;
553 else
554 cam->i2c_state &= ~W9966_I2C_W_DATA;
556 w9966_wReg(cam, 0x18, cam->i2c_state);
557 udelay(5);
560 // Get peripheral clock line
561 // Expects a claimed pdev.
562 static inline int w9966_i2c_getscl(struct w9966_dev* cam)
564 const unsigned char state = w9966_rReg(cam, 0x18);
565 return ((state & W9966_I2C_R_CLOCK) > 0);
568 // Sets the clock line on the i2c bus.
569 // Expects a claimed pdev. -1 on error
570 static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
572 unsigned long timeout;
574 if (state)
575 cam->i2c_state |= W9966_I2C_W_CLOCK;
576 else
577 cam->i2c_state &= ~W9966_I2C_W_CLOCK;
579 w9966_wReg(cam, 0x18, cam->i2c_state);
580 udelay(5);
582 // we go to high, we also expect the peripheral to ack.
583 if (state) {
584 timeout = jiffies + 100;
585 while (!w9966_i2c_getscl(cam)) {
586 if (time_after(jiffies, timeout))
587 return -1;
590 return 0;
593 // Get peripheral data line
594 // Expects a claimed pdev.
595 static inline int w9966_i2c_getsda(struct w9966_dev* cam)
597 const unsigned char state = w9966_rReg(cam, 0x18);
598 return ((state & W9966_I2C_R_DATA) > 0);
601 // Write a byte with ack to the i2c bus.
602 // Expects a claimed pdev. -1 on error
603 static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
605 int i;
606 for (i = 7; i >= 0; i--)
608 w9966_i2c_setsda(cam, (data >> i) & 0x01);
610 if (w9966_i2c_setscl(cam, 1) == -1)
611 return -1;
612 w9966_i2c_setscl(cam, 0);
615 w9966_i2c_setsda(cam, 1);
617 if (w9966_i2c_setscl(cam, 1) == -1)
618 return -1;
619 w9966_i2c_setscl(cam, 0);
621 return 0;
624 // Read a data byte with ack from the i2c-bus
625 // Expects a claimed pdev. -1 on error
626 #if 0
627 static int w9966_i2c_rbyte(struct w9966_dev* cam)
629 unsigned char data = 0x00;
630 int i;
632 w9966_i2c_setsda(cam, 1);
634 for (i = 0; i < 8; i++)
636 if (w9966_i2c_setscl(cam, 1) == -1)
637 return -1;
638 data = data << 1;
639 if (w9966_i2c_getsda(cam))
640 data |= 0x01;
642 w9966_i2c_setscl(cam, 0);
644 return data;
646 #endif
648 // Read a register from the i2c device.
649 // Expects claimed pdev. -1 on error
650 #if 0
651 static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
653 int data;
655 w9966_i2c_setsda(cam, 0);
656 w9966_i2c_setscl(cam, 0);
658 if (
659 w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
660 w9966_i2c_wbyte(cam, reg) == -1
662 return -1;
664 w9966_i2c_setsda(cam, 1);
665 if (w9966_i2c_setscl(cam, 1) == -1)
666 return -1;
667 w9966_i2c_setsda(cam, 0);
668 w9966_i2c_setscl(cam, 0);
670 if (
671 w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
672 (data = w9966_i2c_rbyte(cam)) == -1
674 return -1;
676 w9966_i2c_setsda(cam, 0);
678 if (w9966_i2c_setscl(cam, 1) == -1)
679 return -1;
680 w9966_i2c_setsda(cam, 1);
682 return data;
684 #endif
686 // Write a register to the i2c device.
687 // Expects claimed pdev. -1 on error
688 static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
690 w9966_i2c_setsda(cam, 0);
691 w9966_i2c_setscl(cam, 0);
693 if (
694 w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
695 w9966_i2c_wbyte(cam, reg) == -1 ||
696 w9966_i2c_wbyte(cam, data) == -1
698 return -1;
700 w9966_i2c_setsda(cam, 0);
701 if (w9966_i2c_setscl(cam, 1) == -1)
702 return -1;
704 w9966_i2c_setsda(cam, 1);
706 return 0;
710 * Video4linux interfacing
713 static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
714 unsigned int cmd, void *arg)
716 struct video_device *vdev = video_devdata(file);
717 struct w9966_dev *cam = vdev->priv;
719 switch(cmd)
721 case VIDIOCGCAP:
723 static struct video_capability vcap = {
724 .name = W9966_DRIVERNAME,
725 .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
726 .channels = 1,
727 .maxwidth = W9966_WND_MAX_W,
728 .maxheight = W9966_WND_MAX_H,
729 .minwidth = 2,
730 .minheight = 1,
732 struct video_capability *cap = arg;
733 *cap = vcap;
734 return 0;
736 case VIDIOCGCHAN:
738 struct video_channel *vch = arg;
739 if(vch->channel != 0) // We only support one channel (#0)
740 return -EINVAL;
741 memset(vch,0,sizeof(*vch));
742 strcpy(vch->name, "CCD-input");
743 vch->type = VIDEO_TYPE_CAMERA;
744 return 0;
746 case VIDIOCSCHAN:
748 struct video_channel *vch = arg;
749 if(vch->channel != 0)
750 return -EINVAL;
751 return 0;
753 case VIDIOCGTUNER:
755 struct video_tuner *vtune = arg;
756 if(vtune->tuner != 0)
757 return -EINVAL;
758 strcpy(vtune->name, "no tuner");
759 vtune->rangelow = 0;
760 vtune->rangehigh = 0;
761 vtune->flags = VIDEO_TUNER_NORM;
762 vtune->mode = VIDEO_MODE_AUTO;
763 vtune->signal = 0xffff;
764 return 0;
766 case VIDIOCSTUNER:
768 struct video_tuner *vtune = arg;
769 if (vtune->tuner != 0)
770 return -EINVAL;
771 if (vtune->mode != VIDEO_MODE_AUTO)
772 return -EINVAL;
773 return 0;
775 case VIDIOCGPICT:
777 struct video_picture vpic = {
778 cam->brightness << 8, // brightness
779 (cam->hue + 128) << 8, // hue
780 cam->color << 9, // color
781 cam->contrast << 9, // contrast
782 0x8000, // whiteness
783 16, VIDEO_PALETTE_YUV422// bpp, palette format
785 struct video_picture *pic = arg;
786 *pic = vpic;
787 return 0;
789 case VIDIOCSPICT:
791 struct video_picture *vpic = arg;
792 if (vpic->depth != 16 || vpic->palette != VIDEO_PALETTE_YUV422)
793 return -EINVAL;
795 cam->brightness = vpic->brightness >> 8;
796 cam->hue = (vpic->hue >> 8) - 128;
797 cam->color = vpic->colour >> 9;
798 cam->contrast = vpic->contrast >> 9;
800 w9966_pdev_claim(cam);
802 if (
803 w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
804 w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
805 w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
806 w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
808 w9966_pdev_release(cam);
809 return -EIO;
812 w9966_pdev_release(cam);
813 return 0;
815 case VIDIOCSWIN:
817 int ret;
818 struct video_window *vwin = arg;
820 if (vwin->flags != 0)
821 return -EINVAL;
822 if (vwin->clipcount != 0)
823 return -EINVAL;
824 if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
825 return -EINVAL;
826 if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
827 return -EINVAL;
829 // Update camera regs
830 w9966_pdev_claim(cam);
831 ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
832 w9966_pdev_release(cam);
834 if (ret != 0) {
835 DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
836 return -EIO;
839 return 0;
841 case VIDIOCGWIN:
843 struct video_window *vwin = arg;
844 memset(vwin, 0, sizeof(*vwin));
845 vwin->width = cam->width;
846 vwin->height = cam->height;
847 return 0;
849 // Unimplemented
850 case VIDIOCCAPTURE:
851 case VIDIOCGFBUF:
852 case VIDIOCSFBUF:
853 case VIDIOCKEY:
854 case VIDIOCGFREQ:
855 case VIDIOCSFREQ:
856 case VIDIOCGAUDIO:
857 case VIDIOCSAUDIO:
858 return -EINVAL;
859 default:
860 return -ENOIOCTLCMD;
862 return 0;
865 static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
866 unsigned int cmd, unsigned long arg)
868 return video_usercopy(inode, file, cmd, arg, w9966_v4l_do_ioctl);
871 // Capture data
872 static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
873 size_t count, loff_t *ppos)
875 struct video_device *vdev = video_devdata(file);
876 struct w9966_dev *cam = vdev->priv;
877 unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000
878 unsigned char __user *dest = (unsigned char __user *)buf;
879 unsigned long dleft = count;
880 unsigned char *tbuf;
882 // Why would anyone want more than this??
883 if (count > cam->width * cam->height * 2)
884 return -EINVAL;
886 w9966_pdev_claim(cam);
887 w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer
888 w9966_wReg(cam, 0x00, 0x00); // Return to normal operation
889 w9966_wReg(cam, 0x01, 0x98); // Enable capture
891 // write special capture-addr and negotiate into data transfer
892 if (
893 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )||
894 (parport_write(cam->pport, &addr, 1) != 1 )||
895 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 )
897 w9966_pdev_release(cam);
898 return -EFAULT;
901 tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
902 if (tbuf == NULL) {
903 count = -ENOMEM;
904 goto out;
907 while(dleft > 0)
909 unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
911 if (parport_read(cam->pport, tbuf, tsize) < tsize) {
912 count = -EFAULT;
913 goto out;
915 if (copy_to_user(dest, tbuf, tsize) != 0) {
916 count = -EFAULT;
917 goto out;
919 dest += tsize;
920 dleft -= tsize;
923 w9966_wReg(cam, 0x01, 0x18); // Disable capture
925 out:
926 kfree(tbuf);
927 w9966_pdev_release(cam);
929 return count;
933 // Called once for every parport on init
934 static void w9966_attach(struct parport *port)
936 int i;
938 for (i = 0; i < W9966_MAXCAMS; i++)
940 if (w9966_cams[i].dev_state != 0) // Cam is already assigned
941 continue;
942 if (
943 strcmp(pardev[i], "aggressive") == 0 ||
944 strcmp(pardev[i], port->name) == 0
946 if (w9966_init(&w9966_cams[i], port) != 0)
947 w9966_term(&w9966_cams[i]);
948 break; // return
953 // Called once for every parport on termination
954 static void w9966_detach(struct parport *port)
956 int i;
957 for (i = 0; i < W9966_MAXCAMS; i++)
958 if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
959 w9966_term(&w9966_cams[i]);
963 static struct parport_driver w9966_ppd = {
964 .name = W9966_DRIVERNAME,
965 .attach = w9966_attach,
966 .detach = w9966_detach,
969 // Module entry point
970 static int __init w9966_mod_init(void)
972 int i;
973 for (i = 0; i < W9966_MAXCAMS; i++)
974 w9966_cams[i].dev_state = 0;
976 return parport_register_driver(&w9966_ppd);
979 // Module cleanup
980 static void __exit w9966_mod_term(void)
982 parport_unregister_driver(&w9966_ppd);
985 module_init(w9966_mod_init);
986 module_exit(w9966_mod_term);