r5u870

Ricoh R5U870 Linux Driver
git clone https://logand.com/git/r5u870.git/
Log | Files | Refs | README | LICENSE

commit 8b04dd28855cb232391a87e6b03a1b5373c94404
parent bf523ae9d68ea89d532d63490fd5f45776fa6e75
Author: alex <alex@022568fa-442e-4ef8-a3e8-54dcafdb011a>
Date:   Thu, 17 Jan 2008 05:43:44 +0000

Less breakage wrt driver info ioctls.


git-svn-id: http://svn.mediati.org/svn/r5u870/trunk@39 022568fa-442e-4ef8-a3e8-54dcafdb011a

Diffstat:
Musbcam/usbcam_fops.c | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 143 insertions(+), 2 deletions(-)

diff --git a/usbcam/usbcam_fops.c b/usbcam/usbcam_fops.c @@ -184,6 +184,117 @@ static int usbcam_v4l_mmap(struct file *filp, struct vm_area_struct * vma) return videobuf_mmap_mapper(&ufp->ufh_vbq, vma); } +/* Intercept calls to minidriver V4L handler thing. */ +static int usbcam_v4l_int_ioctl(struct inode *inodep, struct file *filp, + unsigned int cmd, void *arg) +{ + struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data; + struct usbcam_dev *udp = ufp->ufh_dev; + + if (cmd == VIDIOCGCAP) { + struct video_capability *cap = (struct video_capability *) arg; + + usbcam_lock(udp); + + strlcpy(cap->name, udp->ud_vdev.name, sizeof(cap->name)); + cap->type = VID_TYPE_CAPTURE; + cap->audios = 0; + cap->channels = 1; /* only one input source, the camera */ + + cap->maxwidth = udp->ud_format.width; + cap->maxheight = udp->ud_format.height; + + /* + * We lie, here. These values normally return 640x480, which is + * actually the maximum, not the minimum. Minimum is usually + * 160x120. It's sort of useful to lie since lots of software + * just stick with the minimum - we want higher res for the + * user where possible. + */ + + cap->minwidth = udp->ud_format.width; + cap->minheight = udp->ud_format.height; + + usbcam_unlock(udp); + return 0; + } + else if (cmd == VIDIOCGFBUF) { + struct video_buffer *buf = (struct video_buffer *) arg; + + usbcam_lock(udp); + buf->base = NULL; /* no physical frame buffer access */ + buf->height = udp->ud_format.height; + buf->width = udp->ud_format.width; + + // graciously stolen from drivers/media/video/v4l1-compat.c + // and modified slightly. + switch (udp->ud_format.pixelformat) { + case V4L2_PIX_FMT_RGB332: + buf->depth = 8; + break; + case V4L2_PIX_FMT_RGB555: + buf->depth = 15; + break; + case V4L2_PIX_FMT_RGB565: + buf->depth = 16; + break; + case V4L2_PIX_FMT_BGR24: + buf->depth = 24; + break; + case V4L2_PIX_FMT_BGR32: + buf->depth = 32; + break; + default: + buf->depth = 0; + } + + if (udp->ud_format.bytesperline) { + buf->bytesperline = udp->ud_format.bytesperline; + + /* typically comes out at 16 bit depth as non-rgb */ + if (!buf->depth && buf->width) + buf->depth = ((udp->ud_format.bytesperline<<3) + + (buf->width-1) ) + /buf->width; + } else { + buf->bytesperline = + (buf->width * buf->depth + 7) & 7; + buf->bytesperline >>= 3; + } + + usbcam_unlock(udp); + return 0; + } + else { + usbcam_warn(udp, "usbcam_v4l_int_ioctl called without valid ioctl"); + return -ENOIOCTLCMD; + } +} + +static int usbcam_v4l_ioctl (struct inode *inodep, struct file *file, + unsigned int cmd, unsigned long arg) +{ +#ifdef CONFIG_VIDEO_V4L1_COMPAT + if (cmd == VIDIOCGCAP || cmd == VIDIOCGFBUF) + { + // run our own internal ioctl handler for these V4L compat commands. + return video_usercopy(inodep, file, cmd, arg, usbcam_v4l_int_ioctl); + } +#endif + + /*if (cmd != VIDIOCGMBUF && _IOC_TYPE(cmd) == 'v') + { + // send the command off to the compat translator if it's any other v4l1 + return v4l_compat_translate_ioctl(inodep, file, cmd, arg, + usbcam_v4l_int_ioctl); + } + else + {*/ + // normal v4l2 command + return video_ioctl2(inodep, file, cmd, arg); + //} +} + /* * The template file_operations structure * @@ -202,7 +313,8 @@ struct file_operations usbcam_v4l_fops_template = { .read = usbcam_v4l_read, .poll = usbcam_v4l_poll, .mmap = usbcam_v4l_mmap, - .ioctl = video_ioctl2, + /*.ioctl = video_ioctl2,*/ + .ioctl = usbcam_v4l_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, #endif @@ -272,7 +384,34 @@ static int usbcam_v4l_vidiocgmbuf(struct file *filp, void *fh, req.count = 2; req.memory = V4L2_MEMORY_MMAP; res = videobuf_reqbufs(&ufp->ufh_vbq, &req); - if (res) { + if (res == -EBUSY) + { + usbcam_dbg(udp, IOCTL_BUF, + "VIDIOCGMBUF reqbufs failed: device was busy" + " - closing and trying again."); + + res = videobuf_streamoff(&ufp->ufh_vbq); + if (res < 0) + { + usbcam_dbg(udp, IOCTL_BUF, + "VIDIOCGMBUF reqbufs failed:" + "couldn't free previous buffer."); + return -EBUSY; + } + else + { + // we freed previous reqbuf OK. + usbcam_lock(udp); + ufp->ufh_flags |= USBCAM_FH_USE_FIXED_FB; + usbcam_unlock(udp); + + req.type = ufp->ufh_vbq.type; + req.count = 2; + req.memory = V4L2_MEMORY_MMAP; + res = videobuf_reqbufs(&ufp->ufh_vbq, &req); + } + } + else if (res < 0) { usbcam_dbg(udp, IOCTL_BUF, "VIDIOCGMBUF reqbufs failed: %d", res); return res; @@ -822,6 +961,8 @@ static int usbcam_v4l_vidioc_s_input(struct file *filp, void *fh, * Each usbcam_dev contains its own copy of this. The minidriver is * free to install its own handlers for each interface, although it * should take care not to screw up the frame buffer handling. + * + * This gets installed via video_register_device() from usb_usbcam_probe(). */ struct video_device usbcam_videodev_template = {