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

[PATCH] v4l: stv usb camera update

This patch adapts the stv usb camera driver to the videodev changes and
fixes the unplug race.
parent d269cea5
...@@ -1121,13 +1121,13 @@ static int stv680_newframe (struct usb_stv *stv680, int framenr) ...@@ -1121,13 +1121,13 @@ static int stv680_newframe (struct usb_stv *stv680, int framenr)
* Video4Linux * Video4Linux
*********************************************************************/ *********************************************************************/
static int stv_open (struct video_device *dev, int flags) static int stv_open (struct inode *inode, struct file *file)
{ {
struct video_device *dev = video_devdata(file);
struct usb_stv *stv680 = (struct usb_stv *) dev; struct usb_stv *stv680 = (struct usb_stv *) dev;
int err = 0; int err = 0;
/* we are called with the BKL held */ /* we are called with the BKL held */
MOD_INC_USE_COUNT;
stv680->user = 1; stv680->user = 1;
err = stv_init (stv680); /* main initialization routine for camera */ err = stv_init (stv680); /* main initialization routine for camera */
...@@ -1137,18 +1137,17 @@ static int stv_open (struct video_device *dev, int flags) ...@@ -1137,18 +1137,17 @@ static int stv_open (struct video_device *dev, int flags)
PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
err = -ENOMEM; err = -ENOMEM;
} }
file->private_data = dev;
} }
if (err) { if (err)
MOD_DEC_USE_COUNT;
stv680->user = 0; stv680->user = 0;
}
return err; return err;
} }
static void stv_close (struct video_device *dev) static int stv_close (struct inode *inode, struct file *file)
{ {
/* called with BKL held */ struct video_device *dev = file->private_data;
struct usb_stv *stv680 = (struct usb_stv *) dev; struct usb_stv *stv680 = (struct usb_stv *) dev;
int i; int i;
...@@ -1164,21 +1163,18 @@ static void stv_close (struct video_device *dev) ...@@ -1164,21 +1163,18 @@ static void stv_close (struct video_device *dev)
stv680->user = 0; stv680->user = 0;
if (stv680->removed) { if (stv680->removed) {
video_unregister_device (&stv680->vdev);
kfree (stv680); kfree (stv680);
stv680 = NULL; stv680 = NULL;
PDEBUG (0, "STV(i): device unregistered"); PDEBUG (0, "STV(i): device unregistered");
} }
MOD_DEC_USE_COUNT; file->private_data = NULL;
} return 0;
static long stv680_write (struct video_device *dev, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
} }
static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) static int stv680_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{ {
struct video_device *vdev = file->private_data;
struct usb_stv *stv680 = (struct usb_stv *) vdev; struct usb_stv *stv680 = (struct usb_stv *) vdev;
if (!stv680->udev) if (!stv680->udev)
...@@ -1186,89 +1182,57 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) ...@@ -1186,89 +1182,57 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
switch (cmd) { switch (cmd) {
case VIDIOCGCAP:{ case VIDIOCGCAP:{
struct video_capability b; struct video_capability *b = arg;
strcpy (b.name, stv680->camera_name); strcpy (b->name, stv680->camera_name);
b.type = VID_TYPE_CAPTURE; b->type = VID_TYPE_CAPTURE;
b.channels = 1; b->channels = 1;
b.audios = 0; b->audios = 0;
b.maxwidth = stv680->maxwidth; b->maxwidth = stv680->maxwidth;
b.maxheight = stv680->maxheight; b->maxheight = stv680->maxheight;
b.minwidth = stv680->maxwidth / 2; b->minwidth = stv680->maxwidth / 2;
b.minheight = stv680->maxheight / 2; b->minheight = stv680->maxheight / 2;
if (copy_to_user (arg, &b, sizeof (b))) {
PDEBUG (2, "STV(e): VIDIOCGGAP failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCGCHAN:{ case VIDIOCGCHAN:{
struct video_channel v; struct video_channel *v = arg;
if (copy_from_user (&v, arg, sizeof (v))) if (v->channel != 0)
return -EFAULT;
if (v.channel != 0)
return -EINVAL; return -EINVAL;
v->flags = 0;
v.flags = 0; v->tuners = 0;
v.tuners = 0; v->type = VIDEO_TYPE_CAMERA;
v.type = VIDEO_TYPE_CAMERA; strcpy (v->name, "STV Camera");
strcpy (v.name, "STV Camera");
if (copy_to_user (arg, &v, sizeof (v))) {
PDEBUG (2, "STV(e): VIDIOCGCHAN failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCSCHAN:{ case VIDIOCSCHAN:{
int v; struct video_channel *v = arg;
if (v->channel != 0)
if (copy_from_user (&v, arg, sizeof (v))) {
PDEBUG (2, "STV(e): VIDIOCSCHAN failed");
return -EFAULT;
}
if (v != 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
case VIDIOCGPICT:{ case VIDIOCGPICT:{
struct video_picture p; struct video_picture *p = arg;
stv680_get_pict (stv680, &p); stv680_get_pict (stv680, p);
if (copy_to_user (arg, &p, sizeof (p))) {
PDEBUG (2, "STV(e): VIDIOCGPICT failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCSPICT:{ case VIDIOCSPICT:{
struct video_picture p; struct video_picture *p = arg;
if (copy_from_user (&p, arg, sizeof (p))) { if (stv680_set_pict (stv680, p))
PDEBUG (2, "STV(e): VIDIOCSPICT failed");
return -EFAULT;
}
copy_from_user (&p, arg, sizeof (p));
PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
if (stv680_set_pict (stv680, &p))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
case VIDIOCSWIN:{ case VIDIOCSWIN:{
struct video_window vw; struct video_window *vw = arg;
if (copy_from_user (&vw, arg, sizeof (vw))) if (vw->flags)
return -EFAULT;
if (vw.flags)
return -EINVAL; return -EINVAL;
if (vw.clipcount) if (vw->clipcount)
return -EINVAL; return -EINVAL;
if (vw.width != stv680->vwidth) { if (vw->width != stv680->vwidth) {
if (stv680_set_size (stv680, vw.width, vw.height)) { if (stv680_set_size (stv680, vw->width, vw->height)) {
PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
return -EINVAL; return -EINVAL;
} }
...@@ -1276,74 +1240,59 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) ...@@ -1276,74 +1240,59 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
return 0; return 0;
} }
case VIDIOCGWIN:{ case VIDIOCGWIN:{
struct video_window vw; struct video_window *vw = arg;
vw.x = 0; /* FIXME */ vw->x = 0; /* FIXME */
vw.y = 0; vw->y = 0;
vw.chromakey = 0; vw->chromakey = 0;
vw.flags = 0; vw->flags = 0;
vw.clipcount = 0; vw->clipcount = 0;
vw.width = stv680->vwidth; vw->width = stv680->vwidth;
vw.height = stv680->vheight; vw->height = stv680->vheight;
if (copy_to_user (arg, &vw, sizeof (vw))) {
PDEBUG (2, "STV(e): VIDIOCGWIN failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCGMBUF:{ case VIDIOCGMBUF:{
struct video_mbuf vm; struct video_mbuf *vm = arg;
int i; int i;
memset (&vm, 0, sizeof (vm)); memset (vm, 0, sizeof (*vm));
vm.size = STV680_NUMFRAMES * stv680->maxframesize; vm->size = STV680_NUMFRAMES * stv680->maxframesize;
vm.frames = STV680_NUMFRAMES; vm->frames = STV680_NUMFRAMES;
for (i = 0; i < STV680_NUMFRAMES; i++) for (i = 0; i < STV680_NUMFRAMES; i++)
vm.offsets[i] = stv680->maxframesize * i; vm->offsets[i] = stv680->maxframesize * i;
if (copy_to_user ((void *) arg, (void *) &vm, sizeof (vm))) {
PDEBUG (2, "STV(e): VIDIOCGMBUF failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCMCAPTURE:{ case VIDIOCMCAPTURE:{
struct video_mmap vm; struct video_mmap *vm = arg;
if (copy_from_user (&vm, arg, sizeof (vm))) { if (vm->format != STV_VIDEO_PALETTE) {
PDEBUG (2, "STV(e): VIDIOCMCAPTURE failed");
return -EFAULT;
}
if (vm.format != STV_VIDEO_PALETTE) {
PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
vm.format, STV_VIDEO_PALETTE); vm->format, STV_VIDEO_PALETTE);
if ((vm.format == 3) && (swapRGB_on == 0)) { if ((vm->format == 3) && (swapRGB_on == 0)) {
PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
/* this may fix those apps (e.g., xawtv) that want BGR */ /* this may fix those apps (e.g., xawtv) that want BGR */
swapRGB = 1; swapRGB = 1;
} }
return -EINVAL; return -EINVAL;
} }
if (vm.frame >= STV680_NUMFRAMES) { if (vm->frame >= STV680_NUMFRAMES) {
PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
return -EINVAL; return -EINVAL;
} }
if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR) if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
|| (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) { || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
stv680->frame[vm.frame].grabstate); stv680->frame[vm->frame].grabstate);
return -EBUSY; return -EBUSY;
} }
/* Is this according to the v4l spec??? */ /* Is this according to the v4l spec??? */
if (stv680->vwidth != vm.width) { if (stv680->vwidth != vm->width) {
if (stv680_set_size (stv680, vm.width, vm.height)) { if (stv680_set_size (stv680, vm->width, vm->height)) {
PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
return -EINVAL; return -EINVAL;
} }
} }
stv680->frame[vm.frame].grabstate = FRAME_READY; stv680->frame[vm->frame].grabstate = FRAME_READY;
if (!stv680->streaming) if (!stv680->streaming)
stv680_start_stream (stv680); stv680_start_stream (stv680);
...@@ -1351,30 +1300,21 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) ...@@ -1351,30 +1300,21 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
return 0; return 0;
} }
case VIDIOCSYNC:{ case VIDIOCSYNC:{
int frame, ret = 0; int *frame = arg;
int ret = 0;
if (copy_from_user ((void *) &frame, arg, sizeof (int))) { if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
PDEBUG (2, "STV(e): VIDIOCSYNC failed");
return -EFAULT;
}
if (frame < 0 || frame >= STV680_NUMFRAMES) {
PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
return -EINVAL; return -EINVAL;
} }
ret = stv680_newframe (stv680, frame); ret = stv680_newframe (stv680, *frame);
stv680->frame[frame].grabstate = FRAME_UNUSED; stv680->frame[*frame].grabstate = FRAME_UNUSED;
return ret; return ret;
} }
case VIDIOCGFBUF:{ case VIDIOCGFBUF:{
struct video_buffer vb; struct video_buffer *vb = arg;
memset (&vb, 0, sizeof (vb)); memset (vb, 0, sizeof (*vb));
vb.base = NULL; /* frame buffer not supported, not used */
if (copy_to_user ((void *) arg, (void *) &vb, sizeof (vb))) {
PDEBUG (2, "STV(e): VIDIOCSYNC failed");
return -EFAULT;
}
return 0; return 0;
} }
case VIDIOCKEY: case VIDIOCKEY:
...@@ -1402,10 +1342,12 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) ...@@ -1402,10 +1342,12 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
return 0; return 0;
} }
static int stv680_mmap (struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size) static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
{ {
struct video_device *dev = file->private_data;
struct usb_stv *stv680 = (struct usb_stv *) dev; struct usb_stv *stv680 = (struct usb_stv *) dev;
unsigned long start = (unsigned long) adr; unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end-vma->vm_start;
unsigned long page, pos; unsigned long page, pos;
down (&stv680->lock); down (&stv680->lock);
...@@ -1438,8 +1380,10 @@ static int stv680_mmap (struct vm_area_struct *vma, struct video_device *dev, co ...@@ -1438,8 +1380,10 @@ static int stv680_mmap (struct vm_area_struct *vma, struct video_device *dev, co
return 0; return 0;
} }
static long stv680_read (struct video_device *dev, char *buf, unsigned long count, int noblock) static int stv680_read (struct file *file, char *buf,
size_t count, loff_t *ppos)
{ {
struct video_device *dev = file->private_data;
unsigned long int realcount = count; unsigned long int realcount = count;
int ret = 0; int ret = 0;
struct usb_stv *stv680 = (struct usb_stv *) dev; struct usb_stv *stv680 = (struct usb_stv *) dev;
...@@ -1484,28 +1428,22 @@ static long stv680_read (struct video_device *dev, char *buf, unsigned long coun ...@@ -1484,28 +1428,22 @@ static long stv680_read (struct video_device *dev, char *buf, unsigned long coun
return realcount; return realcount;
} /* stv680_read */ } /* stv680_read */
static int stv_init_done (struct video_device *dev) static struct file_operations stv680_fops = {
{ owner: THIS_MODULE,
open: stv_open,
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) release: stv_close,
if (create_proc_stv680_cam ((struct usb_stv *) dev) < 0) read: stv680_read,
return -1; mmap: stv680_mmap,
#endif ioctl: video_generic_ioctl,
return 0; llseek: no_llseek,
} };
static struct video_device stv680_template = { static struct video_device stv680_template = {
owner: THIS_MODULE, owner: THIS_MODULE,
name: "STV0680 USB camera", name: "STV0680 USB camera",
type: VID_TYPE_CAPTURE, type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_SE401, hardware: VID_HARDWARE_SE401,
open: stv_open, fops: &stv680_fops,
close: stv_close, kernel_ioctl: stv680_ioctl,
read: stv680_read,
write: stv680_write,
ioctl: stv680_ioctl,
mmap: stv680_mmap,
initialize: stv_init_done,
}; };
static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
...@@ -1552,6 +1490,9 @@ static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, ...@@ -1552,6 +1490,9 @@ static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum,
PDEBUG (0, "STV(e): video_register_device failed"); PDEBUG (0, "STV(e): video_register_device failed");
return NULL; return NULL;
} }
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
create_proc_stv680_cam (stv680);
#endif
PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor); PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor);
return stv680; return stv680;
...@@ -1593,15 +1534,13 @@ static void stv680_disconnect (struct usb_device *dev, void *ptr) ...@@ -1593,15 +1534,13 @@ static void stv680_disconnect (struct usb_device *dev, void *ptr)
{ {
struct usb_stv *stv680 = (struct usb_stv *) ptr; struct usb_stv *stv680 = (struct usb_stv *) ptr;
lock_kernel ();
/* We don't want people trying to open up the device */ /* We don't want people trying to open up the device */
video_unregister_device (&stv680->vdev);
if (!stv680->user) { if (!stv680->user) {
video_unregister_device (&stv680->vdev);
usb_stv680_remove_disconnected (stv680); usb_stv680_remove_disconnected (stv680);
} else { } else {
stv680->removed = 1; stv680->removed = 1;
} }
unlock_kernel ();
} }
static struct usb_driver stv680_driver = { static struct usb_driver stv680_driver = {
......
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