Commit 23862a35 authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] v4l: usbvideo update

This patch adapts the usbvideo module to the videodev changes.  As with
all usb drivers, the unplug race fix is present here too.
parent b955c567
...@@ -934,6 +934,10 @@ void usbvideo_Disconnect(struct usb_device *dev, void *ptr) ...@@ -934,6 +934,10 @@ void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
usb_dec_dev_use(uvd->dev); usb_dec_dev_use(uvd->dev);
uvd->dev = NULL; /* USB device is no more */ uvd->dev = NULL; /* USB device is no more */
video_unregister_device(&uvd->vdev);
if (uvd->debug > 0)
info("%s: Video unregistered.", proc);
if (uvd->user) if (uvd->user)
info("%s: In use, disconnect pending.", proc); info("%s: In use, disconnect pending.", proc);
else else
...@@ -961,9 +965,6 @@ void usbvideo_CameraRelease(uvd_t *uvd) ...@@ -961,9 +965,6 @@ void usbvideo_CameraRelease(uvd_t *uvd)
err("%s: Illegal call", proc); err("%s: Illegal call", proc);
return; return;
} }
video_unregister_device(&uvd->vdev);
if (uvd->debug > 0)
info("%s: Video unregistered.", proc);
#if USES_PROC_FS #if USES_PROC_FS
assert(uvd->handle != NULL); assert(uvd->handle != NULL);
...@@ -1013,6 +1014,23 @@ static int usbvideo_find_struct(usbvideo_t *cams) ...@@ -1013,6 +1014,23 @@ static int usbvideo_find_struct(usbvideo_t *cams)
return rv; return rv;
} }
static struct file_operations usbvideo_fops = {
owner: THIS_MODULE,
open: usbvideo_v4l_open,
release: usbvideo_v4l_close,
read: usbvideo_v4l_read,
mmap: usbvideo_v4l_mmap,
ioctl: video_generic_ioctl,
llseek: no_llseek,
};
static struct video_device usbvideo_template = {
owner: THIS_MODULE,
type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_CPIA,
fops: &usbvideo_fops,
kernel_ioctl: usbvideo_v4l_ioctl,
};
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams) uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
{ {
int i, devnum; int i, devnum;
...@@ -1050,20 +1068,8 @@ uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams) ...@@ -1050,20 +1068,8 @@ uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
RingQueue_Initialize(&uvd->dp); RingQueue_Initialize(&uvd->dp);
/* Initialize video device structure */ /* Initialize video device structure */
memset(&uvd->vdev, 0, sizeof(uvd->vdev)); uvd->vdev = usbvideo_template;
i = sprintf(uvd->vdev.name, "%s USB Camera", cams->drvName); sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
if (i >= sizeof(uvd->vdev.name)) {
err("Wrote too much into uvd->vdev.name, expect trouble!");
}
uvd->vdev.type = VID_TYPE_CAPTURE;
uvd->vdev.hardware = VID_HARDWARE_CPIA;
uvd->vdev.open = usbvideo_v4l_open;
uvd->vdev.close = usbvideo_v4l_close;
uvd->vdev.read = usbvideo_v4l_read;
uvd->vdev.write = usbvideo_v4l_write;
uvd->vdev.ioctl = usbvideo_v4l_ioctl;
uvd->vdev.mmap = usbvideo_v4l_mmap;
uvd->vdev.initialize = usbvideo_v4l_initialize;
/* /*
* The client is free to overwrite those because we * The client is free to overwrite those because we
* return control to the client's probe function right now. * return control to the client's probe function right now.
...@@ -1136,21 +1142,11 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd) ...@@ -1136,21 +1142,11 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd)
/* ******************************************************************** */ /* ******************************************************************** */
int usbvideo_v4l_initialize(struct video_device *dev) int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
{
return 0;
}
long usbvideo_v4l_write(struct video_device *dev, const char *buf,
unsigned long count, int noblock)
{
return -EINVAL;
}
int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
{ {
uvd_t *uvd = (uvd_t *) dev; uvd_t *uvd = file->private_data;
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;
if (!CAMERA_IS_OPERATIONAL(uvd)) if (!CAMERA_IS_OPERATIONAL(uvd))
...@@ -1190,15 +1186,16 @@ int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, cons ...@@ -1190,15 +1186,16 @@ int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, cons
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/ */
int usbvideo_v4l_open(struct video_device *dev, int flags) int usbvideo_v4l_open(struct inode *inode, struct file *file)
{ {
static const char proc[] = "usbvideo_v4l_open"; static const char proc[] = "usbvideo_v4l_open";
struct video_device *dev = video_devdata(file);
uvd_t *uvd = (uvd_t *) dev; uvd_t *uvd = (uvd_t *) dev;
const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
int i, errCode = 0; int i, errCode = 0;
if (uvd->debug > 1) if (uvd->debug > 1)
info("%s($%p,$%08x", proc, dev, flags); info("%s($%p", proc, dev);
usbvideo_ClientIncModCount(uvd); usbvideo_ClientIncModCount(uvd);
down(&uvd->lock); down(&uvd->lock);
...@@ -1280,6 +1277,7 @@ int usbvideo_v4l_open(struct video_device *dev, int flags) ...@@ -1280,6 +1277,7 @@ int usbvideo_v4l_open(struct video_device *dev, int flags)
if (uvd->debug > 1) if (uvd->debug > 1)
info("%s: Open succeeded.", proc); info("%s: Open succeeded.", proc);
uvd->user++; uvd->user++;
file->private_data = uvd;
} }
} }
} }
...@@ -1303,10 +1301,11 @@ int usbvideo_v4l_open(struct video_device *dev, int flags) ...@@ -1303,10 +1301,11 @@ int usbvideo_v4l_open(struct video_device *dev, int flags)
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
*/ */
void usbvideo_v4l_close(struct video_device *dev) int usbvideo_v4l_close(struct inode *inode, struct file *file)
{ {
static const char proc[] = "usbvideo_v4l_close"; static const char proc[] = "usbvideo_v4l_close";
uvd_t *uvd = (uvd_t *)dev; struct video_device *dev = file->private_data;
uvd_t *uvd = (uvd_t *) dev;
int i; int i;
if (uvd->debug > 1) if (uvd->debug > 1)
...@@ -1338,6 +1337,8 @@ void usbvideo_v4l_close(struct video_device *dev) ...@@ -1338,6 +1337,8 @@ void usbvideo_v4l_close(struct video_device *dev)
if (uvd->debug > 1) if (uvd->debug > 1)
info("%s: Completed.", proc); info("%s: Completed.", proc);
file->private_data = NULL;
return 0;
} }
/* /*
...@@ -1348,118 +1349,103 @@ void usbvideo_v4l_close(struct video_device *dev) ...@@ -1348,118 +1349,103 @@ void usbvideo_v4l_close(struct video_device *dev)
* History: * History:
* 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
*/ */
int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{ {
uvd_t *uvd = (uvd_t *)dev; uvd_t *uvd = file->private_data;
if (!CAMERA_IS_OPERATIONAL(uvd)) if (!CAMERA_IS_OPERATIONAL(uvd))
return -EFAULT; return -EIO;
switch (cmd) { switch (cmd) {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
if (copy_to_user(arg, &uvd->vcap, sizeof(uvd->vcap))) struct video_capability *b = arg;
return -EFAULT; *b = uvd->vcap;
return 0; return 0;
} }
case VIDIOCGCHAN: case VIDIOCGCHAN:
{ {
if (copy_to_user(arg, &uvd->vchan, sizeof(uvd->vchan))) struct video_channel *v = arg;
return -EFAULT; *v = uvd->vchan;
return 0; return 0;
} }
case VIDIOCSCHAN: case VIDIOCSCHAN:
{ /* Not used but we return success */ {
int v; struct video_channel *v = arg;
if (copy_from_user(&v, arg, sizeof(v))) if (v->channel != 0)
return -EFAULT; return -EINVAL;
return 0; return 0;
} }
case VIDIOCGPICT: case VIDIOCGPICT:
{ {
if (copy_to_user(arg, &uvd->vpic, sizeof(uvd->vpic))) struct video_picture *pic = arg;
return -EFAULT; *pic = uvd->vpic;
return 0; return 0;
} }
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
struct video_picture tmp; struct video_picture *pic = arg;
/* /*
* Use temporary 'video_picture' structure to preserve our * Use temporary 'video_picture' structure to preserve our
* own settings (such as color depth, palette) that we * own settings (such as color depth, palette) that we
* aren't allowing everyone (V4L client) to change. * aren't allowing everyone (V4L client) to change.
*/ */
if (copy_from_user(&tmp, arg, sizeof(tmp))) uvd->vpic.brightness = pic->brightness;
return -EFAULT; uvd->vpic.hue = pic->hue;
uvd->vpic.brightness = tmp.brightness; uvd->vpic.colour = pic->colour;
uvd->vpic.hue = tmp.hue; uvd->vpic.contrast = pic->contrast;
uvd->vpic.colour = tmp.colour;
uvd->vpic.contrast = tmp.contrast;
uvd->settingsAdjusted = 0; /* Will force new settings */ uvd->settingsAdjusted = 0; /* Will force new settings */
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 != VIDEOSIZE_X(uvd->canvas)) if (vw->width != VIDEOSIZE_X(uvd->canvas))
return -EINVAL; return -EINVAL;
if (vw.height != VIDEOSIZE_Y(uvd->canvas)) if (vw->height != VIDEOSIZE_Y(uvd->canvas))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
case VIDIOCGWIN: case VIDIOCGWIN:
{ {
struct video_window vw; struct video_window *vw = arg;
vw.x = 0; vw->x = 0;
vw.y = 0; vw->y = 0;
vw.width = VIDEOSIZE_X(uvd->canvas); vw->width = VIDEOSIZE_X(uvd->canvas);
vw.height = VIDEOSIZE_Y(uvd->canvas); vw->height = VIDEOSIZE_Y(uvd->canvas);
vw.chromakey = 0; vw->chromakey = 0;
if (VALID_CALLBACK(uvd, getFPS)) if (VALID_CALLBACK(uvd, getFPS))
vw.flags = GET_CALLBACK(uvd, getFPS)(uvd); vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
else else
vw.flags = 10; /* FIXME: do better! */ vw->flags = 10; /* FIXME: do better! */
if (copy_to_user(arg, &vw, sizeof(vw)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGMBUF: case VIDIOCGMBUF:
{ {
struct video_mbuf vm; struct video_mbuf *vm = arg;
memset(&vm, 0, sizeof(vm));
vm.size = uvd->max_frame_size * 2;
vm.frames = 2;
vm.offsets[0] = 0;
vm.offsets[1] = uvd->max_frame_size;
if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
memset(vm, 0, sizeof(*vm));
vm->size = uvd->max_frame_size * 2;
vm->frames = 2;
vm->offsets[0] = 0;
vm->offsets[1] = uvd->max_frame_size;
return 0; return 0;
} }
case VIDIOCMCAPTURE: case VIDIOCMCAPTURE:
{ {
struct video_mmap vm; struct video_mmap *vm = arg;
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
err("VIDIOCMCAPTURE: copy_from_user() failed.");
return -EFAULT;
}
if (uvd->debug >= 1) { if (uvd->debug >= 1) {
info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
vm.frame, vm.width, vm.height, vm.format); vm->frame, vm->width, vm->height, vm->format);
} }
/* /*
* Check if the requested size is supported. If the requestor * Check if the requested size is supported. If the requestor
...@@ -1474,56 +1460,53 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ...@@ -1474,56 +1460,53 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
* what size we support (returned by VIDIOCGCAP). However vidcat, * what size we support (returned by VIDIOCGCAP). However vidcat,
* for one, does not care and allows to ask for any size. * for one, does not care and allows to ask for any size.
*/ */
if ((vm.width > VIDEOSIZE_X(uvd->canvas)) || if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
(vm.height > VIDEOSIZE_Y(uvd->canvas))) { (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
if (uvd->debug > 0) { if (uvd->debug > 0) {
info("VIDIOCMCAPTURE: Size=%dx%d too large; " info("VIDIOCMCAPTURE: Size=%dx%d too large; "
"allowed only up to %ldx%ld", vm.width, vm.height, "allowed only up to %ldx%ld", vm->width, vm->height,
VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
} }
return -EINVAL; return -EINVAL;
} }
/* Check if the palette is supported */ /* Check if the palette is supported */
if (((1L << vm.format) & uvd->paletteBits) == 0) { if (((1L << vm->format) & uvd->paletteBits) == 0) {
if (uvd->debug > 0) { if (uvd->debug > 0) {
info("VIDIOCMCAPTURE: format=%d. not supported" info("VIDIOCMCAPTURE: format=%d. not supported"
" (paletteBits=$%08lx)", " (paletteBits=$%08lx)",
vm.format, uvd->paletteBits); vm->format, uvd->paletteBits);
} }
return -EINVAL; return -EINVAL;
} }
if ((vm.frame != 0) && (vm.frame != 1)) { if ((vm->frame != 0) && (vm->frame != 1)) {
err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm.frame); err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm->frame);
return -EINVAL; return -EINVAL;
} }
if (uvd->frame[vm.frame].frameState == FrameState_Grabbing) { if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
/* Not an error - can happen */ /* Not an error - can happen */
} }
uvd->frame[vm.frame].request = VIDEOSIZE(vm.width, vm.height); uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
uvd->frame[vm.frame].palette = vm.format; uvd->frame[vm->frame].palette = vm->format;
/* Mark it as ready */ /* Mark it as ready */
uvd->frame[vm.frame].frameState = FrameState_Ready; uvd->frame[vm->frame].frameState = FrameState_Ready;
return usbvideo_NewFrame(uvd, vm.frame); return usbvideo_NewFrame(uvd, vm->frame);
} }
case VIDIOCSYNC: case VIDIOCSYNC:
{ {
int frameNum, ret; int *frameNum = arg;
int ret;
if (copy_from_user((void *)&frameNum, arg, sizeof(frameNum))) { if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
err("VIDIOCSYNC: copy_from_user() failed.");
return -EFAULT;
}
if(frameNum < 0 || frameNum >= USBVIDEO_NUMFRAMES)
return -EINVAL; return -EINVAL;
if (uvd->debug >= 1) if (uvd->debug >= 1)
info("VIDIOCSYNC: syncing to frame %d.", frameNum); info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
if (uvd->flags & FLAGS_NO_DECODING) if (uvd->flags & FLAGS_NO_DECODING)
ret = usbvideo_GetFrame(uvd, frameNum); ret = usbvideo_GetFrame(uvd, *frameNum);
else if (VALID_CALLBACK(uvd, getFrame)) { else if (VALID_CALLBACK(uvd, getFrame)) {
ret = GET_CALLBACK(uvd, getFrame)(uvd, frameNum); ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
if ((ret < 0) && (uvd->debug >= 1)) { if ((ret < 0) && (uvd->debug >= 1)) {
err("VIDIOCSYNC: getFrame() returned %d.", ret); err("VIDIOCSYNC: getFrame() returned %d.", ret);
} }
...@@ -1538,19 +1521,14 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ...@@ -1538,19 +1521,14 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
* the user space and it's up to the application to * the user space and it's up to the application to
* make use of it until it asks for another frame. * make use of it until it asks for another frame.
*/ */
uvd->frame[frameNum].frameState = FrameState_Unused; uvd->frame[*frameNum].frameState = FrameState_Unused;
return ret; return ret;
} }
case VIDIOCGFBUF: case VIDIOCGFBUF:
{ {
struct video_buffer vb; struct video_buffer *vb = arg;
memset(&vb, 0, sizeof(vb));
vb.base = NULL; /* frame buffer not supported, not used */
if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
return -EFAULT;
memset(vb, 0, sizeof(*vb));
return 0; return 0;
} }
case VIDIOCKEY: case VIDIOCKEY:
...@@ -1588,10 +1566,12 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ...@@ -1588,10 +1566,12 @@ int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
* 20-Oct-2000 Created. * 20-Oct-2000 Created.
* 01-Nov-2000 Added mutex (uvd->lock). * 01-Nov-2000 Added mutex (uvd->lock).
*/ */
long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, int noblock) int usbvideo_v4l_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{ {
static const char proc[] = "usbvideo_v4l_read"; static const char proc[] = "usbvideo_v4l_read";
uvd_t *uvd = (uvd_t *) dev; uvd_t *uvd = file->private_data;
int noblock = file->f_flags & O_NONBLOCK;
int frmx = -1; int frmx = -1;
usbvideo_frame_t *frame; usbvideo_frame_t *frame;
...@@ -1599,7 +1579,7 @@ long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, ...@@ -1599,7 +1579,7 @@ long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count,
return -EFAULT; return -EFAULT;
if (uvd->debug >= 1) if (uvd->debug >= 1)
info("%s: %ld. bytes, noblock=%d.", proc, count, noblock); info("%s: %d. bytes, noblock=%d.", proc, count, noblock);
down(&uvd->lock); down(&uvd->lock);
...@@ -1716,7 +1696,7 @@ long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, ...@@ -1716,7 +1696,7 @@ long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count,
/* Update last read position */ /* Update last read position */
frame->seqRead_Index += count; frame->seqRead_Index += count;
if (uvd->debug >= 1) { if (uvd->debug >= 1) {
err("%s: {copy} count used=%ld, new seqRead_Index=%ld", err("%s: {copy} count used=%d, new seqRead_Index=%ld",
proc, count, frame->seqRead_Index); proc, count, frame->seqRead_Index);
} }
......
...@@ -347,15 +347,14 @@ void usbvideo_Deregister(usbvideo_t **uvt); ...@@ -347,15 +347,14 @@ void usbvideo_Deregister(usbvideo_t **uvt);
void usbvideo_Disconnect(struct usb_device *dev, void *ptr); void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
void usbvideo_CameraRelease(uvd_t *uvd); void usbvideo_CameraRelease(uvd_t *uvd);
void usbvideo_v4l_close(struct video_device *dev); int usbvideo_v4l_close(struct inode *inode, struct file *file);
int usbvideo_v4l_initialize(struct video_device *dev); int usbvideo_v4l_initialize(struct video_device *dev);
int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg); int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size); unsigned int ioctlnr, void *arg);
int usbvideo_v4l_open(struct video_device *dev, int flags); int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
long usbvideo_v4l_read(struct video_device *dev, char *buf, int usbvideo_v4l_open(struct inode *inode, struct file *file);
unsigned long count, int noblock); int usbvideo_v4l_read(struct file *file, char *buf,
long usbvideo_v4l_write(struct video_device *dev, const char *buf, size_t count, loff_t *ppos);
unsigned long count, int noblock);
int usbvideo_GetFrame(uvd_t *uvd, int frameNum); int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
int usbvideo_NewFrame(uvd_t *uvd, int framenum); int usbvideo_NewFrame(uvd_t *uvd, int framenum);
......
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