Commit da10fb31 authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] v4l: w9966 update

This patch updates the Winbond w9966cf parport webcam driver.
parent 4adae09a
...@@ -173,10 +173,27 @@ static inline int w9966_i2c_getscl(struct w9966_dev* cam); ...@@ -173,10 +173,27 @@ static inline int w9966_i2c_getscl(struct w9966_dev* cam);
static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
static int w9966_i2c_rbyte(struct w9966_dev* cam); static int w9966_i2c_rbyte(struct w9966_dev* cam);
static int w9966_v4l_open(struct video_device *vdev, int mode); static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
static void w9966_v4l_close(struct video_device *vdev); unsigned int cmd, void *arg);
static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); static int w9966_v4l_read(struct file *file, char *buf,
static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock); size_t count, loff_t *ppos);
static struct file_operations w9966_fops = {
owner: THIS_MODULE,
open: video_exclusive_open,
release: video_exclusive_release,
ioctl: video_generic_ioctl,
read: w9966_v4l_read,
llseek: no_llseek,
};
static struct video_device w9966_template = {
owner: THIS_MODULE,
name: W9966_DRIVERNAME,
type: VID_TYPE_CAPTURE | VID_TYPE_SCALES,
hardware: VID_HARDWARE_W9966,
fops: &w9966_fops,
kernel_ioctl: w9966_v4l_ioctl,
};
/* /*
* Private function defines * Private function defines
...@@ -309,16 +326,8 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port) ...@@ -309,16 +326,8 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
w9966_pdev_release(cam); w9966_pdev_release(cam);
// Fill in the video_device struct and register us to v4l // Fill in the video_device struct and register us to v4l
memset(&cam->vdev, 0, sizeof(struct video_device)); memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
strcpy(cam->vdev.name, W9966_DRIVERNAME);
cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->vdev.hardware = VID_HARDWARE_W9966;
cam->vdev.open = &w9966_v4l_open;
cam->vdev.close = &w9966_v4l_close;
cam->vdev.read = &w9966_v4l_read;
cam->vdev.ioctl = &w9966_v4l_ioctl;
cam->vdev.priv = (void*)cam; cam->vdev.priv = (void*)cam;
cam->vdev.owner = THIS_MODULE;
if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
return -1; return -1;
...@@ -691,101 +700,67 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) ...@@ -691,101 +700,67 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
* Video4linux interfacing * Video4linux interfacing
*/ */
static int w9966_v4l_open(struct video_device *vdev, int flags) static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
{ unsigned int cmd, void *arg)
return 0;
}
static void w9966_v4l_close(struct video_device *vdev)
{
}
static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{ {
struct video_device *vdev = video_devdata(file);
struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
switch(cmd) switch(cmd)
{ {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
struct video_capability vcap = { static struct video_capability vcap = {
W9966_DRIVERNAME, // name name: W9966_DRIVERNAME,
VID_TYPE_CAPTURE | VID_TYPE_SCALES, // type type: VID_TYPE_CAPTURE | VID_TYPE_SCALES,
1, 0, // vid, aud channels channels: 1,
W9966_WND_MAX_W, // max w audios: 0,
W9966_WND_MAX_H, // max h maxwidth: W9966_WND_MAX_W,
2, 1 // min w, min h maxheight: W9966_WND_MAX_H,
minwidth: 2,
minheight: 1,
}; };
struct video_capability *cap = arg;
if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0) *cap = vcap;
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGCHAN: case VIDIOCGCHAN:
{ {
struct video_channel vch; struct video_channel *vch = arg;
if(copy_from_user(&vch, arg, sizeof(vch)) != 0) if(vch->channel != 0) // We only support one channel (#0)
return -EFAULT;
if(vch.channel != 0) // We only support one channel (#0)
return -EINVAL; return -EINVAL;
memset(vch,0,sizeof(*vch));
strcpy(vch.name, "CCD-input"); strcpy(vch->name, "CCD-input");
vch.flags = 0; // We have no tuner or audio vch->type = VIDEO_TYPE_CAMERA;
vch.tuners = 0;
vch.type = VIDEO_TYPE_CAMERA;
vch.norm = 0; // ???
if(copy_to_user(arg, &vch, sizeof(vch)) != 0)
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSCHAN: case VIDIOCSCHAN:
{ {
struct video_channel vch; struct video_channel *vch = arg;
if(copy_from_user(&vch, arg, sizeof(vch) ) != 0) if(vch->channel != 0)
return -EFAULT;
if(vch.channel != 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
case VIDIOCGTUNER: case VIDIOCGTUNER:
{ {
struct video_tuner vtune; struct video_tuner *vtune = arg;
if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0) if(vtune->tuner != 0);
return -EFAULT;
if(vtune.tuner != 0);
return -EINVAL; return -EINVAL;
strcpy(vtune->name, "no tuner");
strcpy(vtune.name, "no tuner"); vtune->rangelow = 0;
vtune.rangelow = 0; vtune->rangehigh = 0;
vtune.rangehigh = 0; vtune->flags = VIDEO_TUNER_NORM;
vtune.flags = VIDEO_TUNER_NORM; vtune->mode = VIDEO_MODE_AUTO;
vtune.mode = VIDEO_MODE_AUTO; vtune->signal = 0xffff;
vtune.signal = 0xffff;
if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSTUNER: case VIDIOCSTUNER:
{ {
struct video_tuner vtune; struct video_tuner *vtune = arg;
if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0) if (vtune->tuner != 0)
return -EFAULT;
if (vtune.tuner != 0)
return -EINVAL; return -EINVAL;
if (vtune->mode != VIDEO_MODE_AUTO)
if (vtune.mode != VIDEO_MODE_AUTO)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
case VIDIOCGPICT: case VIDIOCGPICT:
...@@ -798,25 +773,20 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar ...@@ -798,25 +773,20 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar
0x8000, // whiteness 0x8000, // whiteness
16, VIDEO_PALETTE_YUV422// bpp, palette format 16, VIDEO_PALETTE_YUV422// bpp, palette format
}; };
struct video_picture *pic = arg;
if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0) *pic = vpic;
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
struct video_picture vpic; struct video_picture *vpic = arg;
if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0) if (vpic->depth != 16 || vpic->palette != VIDEO_PALETTE_YUV422)
return -EFAULT;
if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)
return -EINVAL; return -EINVAL;
cam->brightness = vpic.brightness >> 8; cam->brightness = vpic->brightness >> 8;
cam->hue = (vpic.hue >> 8) - 128; cam->hue = (vpic->hue >> 8) - 128;
cam->color = vpic.colour >> 9; cam->color = vpic->colour >> 9;
cam->contrast = vpic.contrast >> 9; cam->contrast = vpic->contrast >> 9;
w9966_pdev_claim(cam); w9966_pdev_claim(cam);
...@@ -827,7 +797,7 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar ...@@ -827,7 +797,7 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar
w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1 w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
) { ) {
w9966_pdev_release(cam); w9966_pdev_release(cam);
return -EFAULT; return -EIO;
} }
w9966_pdev_release(cam); w9966_pdev_release(cam);
...@@ -836,42 +806,35 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar ...@@ -836,42 +806,35 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar
case VIDIOCSWIN: case VIDIOCSWIN:
{ {
int ret; int ret;
struct video_window vwin; struct video_window *vwin = arg;
if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0) if (vwin->flags != 0)
return -EFAULT;
if (vwin.flags != 0)
return -EINVAL; return -EINVAL;
if (vwin.clipcount != 0) if (vwin->clipcount != 0)
return -EINVAL; return -EINVAL;
if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W) if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
return -EINVAL; return -EINVAL;
if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H) if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
return -EINVAL; return -EINVAL;
// Update camera regs // Update camera regs
w9966_pdev_claim(cam); w9966_pdev_claim(cam);
ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height); ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
w9966_pdev_release(cam); w9966_pdev_release(cam);
if (ret != 0) { if (ret != 0) {
DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
return -EFAULT; return -EIO;
} }
return 0; return 0;
} }
case VIDIOCGWIN: case VIDIOCGWIN:
{ {
struct video_window vwin; struct video_window *vwin = arg;
memset(&vwin, 0, sizeof(vwin)); memset(vwin, 0, sizeof(*vwin));
vwin->width = cam->width;
vwin.width = cam->width; vwin->height = cam->height;
vwin.height = cam->height;
if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)
return -EFAULT;
return 0; return 0;
} }
// Unimplemented // Unimplemented
...@@ -891,8 +854,10 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar ...@@ -891,8 +854,10 @@ static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *ar
} }
// Capture data // Capture data
static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock) static int w9966_v4l_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{ {
struct video_device *vdev = video_devdata(file);
struct w9966_dev *cam = (struct w9966_dev *)vdev->priv; struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;
unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000
unsigned char* dest = (unsigned char*)buf; unsigned char* dest = (unsigned char*)buf;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment