2 Winbond w9966cf Webcam parport driver.
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.
24 *Lifeview FlyCam Supra (using the Philips saa7111a chip)
26 Does any other model using the w9966 interface chip exist ?
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!
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/videodev2.h>
61 #include <media/v4l2-common.h>
62 #include <media/v4l2-ioctl.h>
63 #include <linux/parport.h>
65 /*#define DEBUG*/ /* Undef me for production */
68 #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
74 * Defines, simple typedefs etc.
77 #define W9966_DRIVERNAME "W9966CF Webcam"
78 #define W9966_MAXCAMS 4 // Maximum number of cameras
79 #define W9966_RBUFFER 2048 // Read buffer (must be an even number)
80 #define W9966_SRAMSIZE 131072 // 128kb
81 #define W9966_SRAMID 0x02 // check w9966cf.pdf
83 // Empirically determined window limits
84 #define W9966_WND_MIN_X 16
85 #define W9966_WND_MIN_Y 14
86 #define W9966_WND_MAX_X 705
87 #define W9966_WND_MAX_Y 253
88 #define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X)
89 #define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
91 // Keep track of our current state
92 #define W9966_STATE_PDEV 0x01
93 #define W9966_STATE_CLAIMED 0x02
94 #define W9966_STATE_VDEV 0x04
96 #define W9966_I2C_W_ID 0x48
97 #define W9966_I2C_R_ID 0x49
98 #define W9966_I2C_R_DATA 0x08
99 #define W9966_I2C_R_CLOCK 0x04
100 #define W9966_I2C_W_DATA 0x02
101 #define W9966_I2C_W_CLOCK 0x01
104 unsigned char dev_state
;
105 unsigned char i2c_state
;
106 unsigned short ppmode
;
107 struct parport
* pport
;
108 struct pardevice
* pdev
;
109 struct video_device vdev
;
110 unsigned short width
;
111 unsigned short height
;
112 unsigned char brightness
;
113 signed char contrast
;
119 * Module specific properties
122 MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
123 MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
124 MODULE_LICENSE("GPL");
128 static const char* pardev
[] = {[0 ... W9966_MAXCAMS
] = ""};
130 static const char* pardev
[] = {[0 ... W9966_MAXCAMS
] = "aggressive"};
132 module_param_array(pardev
, charp
, NULL
, 0);
133 MODULE_PARM_DESC(pardev
, "pardev: where to search for\n\
134 \teach camera. 'aggressive' means brute-force search.\n\
135 \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
136 \tcam 1 to parport3 and search every parport for cam 2 etc...");
139 module_param(parmode
, int, 0);
140 MODULE_PARM_DESC(parmode
, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
142 static int video_nr
= -1;
143 module_param(video_nr
, int, 0);
149 static struct w9966_dev w9966_cams
[W9966_MAXCAMS
];
152 * Private function declares
155 static inline void w9966_setState(struct w9966_dev
* cam
, int mask
, int val
);
156 static inline int w9966_getState(struct w9966_dev
* cam
, int mask
, int val
);
157 static inline void w9966_pdev_claim(struct w9966_dev
*vdev
);
158 static inline void w9966_pdev_release(struct w9966_dev
*vdev
);
160 static int w9966_rReg(struct w9966_dev
* cam
, int reg
);
161 static int w9966_wReg(struct w9966_dev
* cam
, int reg
, int data
);
163 static int w9966_rReg_i2c(struct w9966_dev
* cam
, int reg
);
165 static int w9966_wReg_i2c(struct w9966_dev
* cam
, int reg
, int data
);
166 static int w9966_findlen(int near
, int size
, int maxlen
);
167 static int w9966_calcscale(int size
, int min
, int max
, int* beg
, int* end
, unsigned char* factor
);
168 static int w9966_setup(struct w9966_dev
* cam
, int x1
, int y1
, int x2
, int y2
, int w
, int h
);
170 static int w9966_init(struct w9966_dev
* cam
, struct parport
* port
);
171 static void w9966_term(struct w9966_dev
* cam
);
173 static inline void w9966_i2c_setsda(struct w9966_dev
* cam
, int state
);
174 static inline int w9966_i2c_setscl(struct w9966_dev
* cam
, int state
);
175 static inline int w9966_i2c_getsda(struct w9966_dev
* cam
);
176 static inline int w9966_i2c_getscl(struct w9966_dev
* cam
);
177 static int w9966_i2c_wbyte(struct w9966_dev
* cam
, int data
);
179 static int w9966_i2c_rbyte(struct w9966_dev
* cam
);
182 static int w9966_v4l_ioctl(struct inode
*inode
, struct file
*file
,
183 unsigned int cmd
, unsigned long arg
);
184 static ssize_t
w9966_v4l_read(struct file
*file
, char __user
*buf
,
185 size_t count
, loff_t
*ppos
);
187 static const struct file_operations w9966_fops
= {
188 .owner
= THIS_MODULE
,
189 .open
= video_exclusive_open
,
190 .release
= video_exclusive_release
,
191 .ioctl
= w9966_v4l_ioctl
,
193 .compat_ioctl
= v4l_compat_ioctl32
,
195 .read
= w9966_v4l_read
,
198 static struct video_device w9966_template
= {
199 .name
= W9966_DRIVERNAME
,
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
))
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))
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);
247 if (parport_negotiate(cam
->pport
, cam
->ppmode
| IEEE1284_ADDR
) != 0)
249 if (parport_write(cam
->pport
, &addr
, 1) != 1)
251 if (parport_negotiate(cam
->pport
, cam
->ppmode
| IEEE1284_DATA
) != 0)
253 if (parport_read(cam
->pport
, &val
, 1) != 1)
259 // Write register to W9966 interface-chip
260 // Expects a claimed pdev
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)
270 if (parport_write(cam
->pport
, &addr
, 1) != 1)
272 if (parport_negotiate(cam
->pport
, cam
->ppmode
| IEEE1284_DATA
) != 0)
274 if (parport_write(cam
->pport
, &val
, 1) != 1)
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.
284 static int w9966_init(struct w9966_dev
* cam
, struct parport
* port
)
286 if (cam
->dev_state
!= 0)
290 cam
->brightness
= 128;
295 // Select requested transfer mode
298 default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
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
;
305 cam
->ppmode
= IEEE1284_MODE_ECP
;
307 case 1: // hw- or sw-ecp
308 cam
->ppmode
= IEEE1284_MODE_ECP
;
310 case 2: // hw- or sw-epp
311 cam
->ppmode
= IEEE1284_MODE_EPP
;
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");
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");
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)
340 w9966_setState(cam
, W9966_STATE_VDEV
, W9966_STATE_VDEV
);
344 "w9966cf: Found and initialized a webcam on %s.\n",
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
)
381 int besterr
= abs(near
- bestlen
);
384 for(len
= size
+1;len
< maxlen
;len
++)
387 if ( ((64*size
) %len
) != 0)
390 err
= abs(near
- len
);
392 // Only continue as long as we keep getting better values
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
)
417 // Set factor (6 bit fixed)
418 *factor
= (64*size
) / newlen
;
420 *factor
= 0x00; // downscale is disabled
422 *factor
|= 0x80; // set downscale-enable bit
424 // Modify old beginning and end
426 *end
+= err
- (err
/ 2);
428 // Move window if outside borders
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
)
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
467 if (w
> W9966_WND_MAX_W
) w
= W9966_WND_MAX_W
;
468 if (h
> W9966_WND_MAX_H
) h
= W9966_WND_MAX_H
;
476 // Modify capture window if necessary and calculate downscaling
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
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
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
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)
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??)
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)
530 // Write regs to w9966cf chip
531 for (i
= 0; i
< 0x1c; i
++)
532 if (w9966_wReg(cam
, i
, regs
[i
]) == -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)
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
)
552 cam
->i2c_state
|= W9966_I2C_W_DATA
;
554 cam
->i2c_state
&= ~W9966_I2C_W_DATA
;
556 w9966_wReg(cam
, 0x18, cam
->i2c_state
);
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
;
575 cam
->i2c_state
|= W9966_I2C_W_CLOCK
;
577 cam
->i2c_state
&= ~W9966_I2C_W_CLOCK
;
579 w9966_wReg(cam
, 0x18, cam
->i2c_state
);
582 // we go to high, we also expect the peripheral to ack.
584 timeout
= jiffies
+ 100;
585 while (!w9966_i2c_getscl(cam
)) {
586 if (time_after(jiffies
, timeout
))
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
)
606 for (i
= 7; i
>= 0; i
--)
608 w9966_i2c_setsda(cam
, (data
>> i
) & 0x01);
610 if (w9966_i2c_setscl(cam
, 1) == -1)
612 w9966_i2c_setscl(cam
, 0);
615 w9966_i2c_setsda(cam
, 1);
617 if (w9966_i2c_setscl(cam
, 1) == -1)
619 w9966_i2c_setscl(cam
, 0);
624 // Read a data byte with ack from the i2c-bus
625 // Expects a claimed pdev. -1 on error
627 static int w9966_i2c_rbyte(struct w9966_dev
* cam
)
629 unsigned char data
= 0x00;
632 w9966_i2c_setsda(cam
, 1);
634 for (i
= 0; i
< 8; i
++)
636 if (w9966_i2c_setscl(cam
, 1) == -1)
639 if (w9966_i2c_getsda(cam
))
642 w9966_i2c_setscl(cam
, 0);
648 // Read a register from the i2c device.
649 // Expects claimed pdev. -1 on error
651 static int w9966_rReg_i2c(struct w9966_dev
* cam
, int reg
)
655 w9966_i2c_setsda(cam
, 0);
656 w9966_i2c_setscl(cam
, 0);
659 w9966_i2c_wbyte(cam
, W9966_I2C_W_ID
) == -1 ||
660 w9966_i2c_wbyte(cam
, reg
) == -1
664 w9966_i2c_setsda(cam
, 1);
665 if (w9966_i2c_setscl(cam
, 1) == -1)
667 w9966_i2c_setsda(cam
, 0);
668 w9966_i2c_setscl(cam
, 0);
671 w9966_i2c_wbyte(cam
, W9966_I2C_R_ID
) == -1 ||
672 (data
= w9966_i2c_rbyte(cam
)) == -1
676 w9966_i2c_setsda(cam
, 0);
678 if (w9966_i2c_setscl(cam
, 1) == -1)
680 w9966_i2c_setsda(cam
, 1);
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);
694 w9966_i2c_wbyte(cam
, W9966_I2C_W_ID
) == -1 ||
695 w9966_i2c_wbyte(cam
, reg
) == -1 ||
696 w9966_i2c_wbyte(cam
, data
) == -1
700 w9966_i2c_setsda(cam
, 0);
701 if (w9966_i2c_setscl(cam
, 1) == -1)
704 w9966_i2c_setsda(cam
, 1);
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
;
723 static struct video_capability vcap
= {
724 .name
= W9966_DRIVERNAME
,
725 .type
= VID_TYPE_CAPTURE
| VID_TYPE_SCALES
,
727 .maxwidth
= W9966_WND_MAX_W
,
728 .maxheight
= W9966_WND_MAX_H
,
732 struct video_capability
*cap
= arg
;
738 struct video_channel
*vch
= arg
;
739 if(vch
->channel
!= 0) // We only support one channel (#0)
741 memset(vch
,0,sizeof(*vch
));
742 strcpy(vch
->name
, "CCD-input");
743 vch
->type
= VIDEO_TYPE_CAMERA
;
748 struct video_channel
*vch
= arg
;
749 if(vch
->channel
!= 0)
755 struct video_tuner
*vtune
= arg
;
756 if(vtune
->tuner
!= 0)
758 strcpy(vtune
->name
, "no tuner");
760 vtune
->rangehigh
= 0;
761 vtune
->flags
= VIDEO_TUNER_NORM
;
762 vtune
->mode
= VIDEO_MODE_AUTO
;
763 vtune
->signal
= 0xffff;
768 struct video_tuner
*vtune
= arg
;
769 if (vtune
->tuner
!= 0)
771 if (vtune
->mode
!= VIDEO_MODE_AUTO
)
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
783 16, VIDEO_PALETTE_YUV422
// bpp, palette format
785 struct video_picture
*pic
= arg
;
791 struct video_picture
*vpic
= arg
;
792 if (vpic
->depth
!= 16 || (vpic
->palette
!= VIDEO_PALETTE_YUV422
&& vpic
->palette
!= VIDEO_PALETTE_YUYV
))
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
);
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
);
812 w9966_pdev_release(cam
);
818 struct video_window
*vwin
= arg
;
820 if (vwin
->flags
!= 0)
822 if (vwin
->clipcount
!= 0)
824 if (vwin
->width
< 2 || vwin
->width
> W9966_WND_MAX_W
)
826 if (vwin
->height
< 1 || vwin
->height
> W9966_WND_MAX_H
)
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
);
835 DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
843 struct video_window
*vwin
= arg
;
844 memset(vwin
, 0, sizeof(*vwin
));
845 vwin
->width
= cam
->width
;
846 vwin
->height
= cam
->height
;
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
);
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
;
882 // Why would anyone want more than this??
883 if (count
> cam
->width
* cam
->height
* 2)
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
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
);
901 tbuf
= kmalloc(W9966_RBUFFER
, GFP_KERNEL
);
909 unsigned long tsize
= (dleft
> W9966_RBUFFER
) ? W9966_RBUFFER
: dleft
;
911 if (parport_read(cam
->pport
, tbuf
, tsize
) < tsize
) {
915 if (copy_to_user(dest
, tbuf
, tsize
) != 0) {
923 w9966_wReg(cam
, 0x01, 0x18); // Disable capture
927 w9966_pdev_release(cam
);
933 // Called once for every parport on init
934 static void w9966_attach(struct parport
*port
)
938 for (i
= 0; i
< W9966_MAXCAMS
; i
++)
940 if (w9966_cams
[i
].dev_state
!= 0) // Cam is already assigned
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
]);
953 // Called once for every parport on termination
954 static void w9966_detach(struct parport
*port
)
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)
973 for (i
= 0; i
< W9966_MAXCAMS
; i
++)
974 w9966_cams
[i
].dev_state
= 0;
976 return parport_register_driver(&w9966_ppd
);
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
);