From: Hans Verkuil Date: Sun, 12 Sep 2010 20:05:11 +0000 (-0300) Subject: V4L/DVB: pwc: fully convert driver to V4L2 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=479567ce3af7b99d645a3c53b8ca2fc65e46efdc;p=openwrt%2Fstaging%2Fblogic.git V4L/DVB: pwc: fully convert driver to V4L2 Remove the V4L1 API from this driver, making it fully V4L2. Also fix a bug where the /dev/videoX device was created too early, which led to initialization problems of the camera, making it unable to capture video. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig index 11980db22d31..8da42e4f1ba0 100644 --- a/drivers/media/video/pwc/Kconfig +++ b/drivers/media/video/pwc/Kconfig @@ -1,6 +1,6 @@ config USB_PWC tristate "USB Philips Cameras" - depends on VIDEO_V4L1 + depends on VIDEO_V4L2 ---help--- Say Y or M here if you want to use one of these Philips & OEM webcams: diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index f7f7e04cf485..6b8fbddc0747 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -261,7 +261,7 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); return ret; } - if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) + if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); pdev->cmd_len = 3; @@ -321,7 +321,7 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) pwc_dec23_init(pdev, pdev->type, buf); pdev->cmd_len = 13; @@ -356,7 +356,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i fps = (frames / 5) - 1; /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW) + if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420) { /* Only available in case the raw palette is selected or we have the decompressor available. This mode is @@ -394,7 +394,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) pwc_dec23_init(pdev, pdev->type, buf); pdev->cmd_len = 12; @@ -429,7 +429,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame { int ret, size; - PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); + PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); size = pwc_decode_size(pdev, width, height); if (size < 0) { PWC_DEBUG_MODULE("Could not find suitable size.\n"); @@ -519,13 +519,13 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev) { int i, factor = 0; - /* for PALETTE_YUV420P */ - switch(pdev->vpalette) - { - case VIDEO_PALETTE_YUV420P: + /* for V4L2_PIX_FMT_YUV420 */ + switch (pdev->pixfmt) { + case V4L2_PIX_FMT_YUV420: factor = 6; break; - case VIDEO_PALETTE_RAW: + case V4L2_PIX_FMT_PWC1: + case V4L2_PIX_FMT_PWC2: factor = 6; /* can be uncompressed YUV420P */ break; } diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index aea7e224cef6..d06e157657ac 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1365,7 +1365,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, } PWC_DEBUG_READ("Copying data to user space.\n"); - if (pdev->vpalette == VIDEO_PALETTE_RAW) + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame); else bytes_to_read = pdev->view.size; @@ -1800,13 +1800,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } pdev->vdev->release = video_device_release; - rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (rc < 0) { - PWC_ERROR("Failed to register as video device (%d).\n", rc); - goto err_video_release; - } - - PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); /* occupy slot */ if (hint < MAX_DEV_HINTS) @@ -1814,14 +1807,22 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata(intf, pdev); - rc = pwc_create_sysfs_files(pdev->vdev); - if (rc) - goto err_video_unreg; /* Set the leds off */ pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); + rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); + if (rc < 0) { + PWC_ERROR("Failed to register as video device (%d).\n", rc); + goto err_video_release; + } + rc = pwc_create_sysfs_files(pdev->vdev); + if (rc) + goto err_video_unreg; + + PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); + #ifdef CONFIG_USB_PWC_INPUT_EVDEV /* register webcam snapshot button input device */ pdev->button_dev = input_allocate_device(); diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c index 589c687439da..6af5bb538358 100644 --- a/drivers/media/video/pwc/pwc-misc.c +++ b/drivers/media/video/pwc/pwc-misc.c @@ -47,7 +47,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height) you don't have the decompressor loaded or use RAW mode, the maximum viewable size is smaller. */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) { if (width > pdev->abs_max.x || height > pdev->abs_max.y) { @@ -123,7 +123,7 @@ void pwc_construct(struct pwc_device *pdev) pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } - pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ + pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; /* length of image, in YUV format; always allocate enough memory. */ diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c index 5d82028ef942..3b73f295f032 100644 --- a/drivers/media/video/pwc/pwc-uncompress.c +++ b/drivers/media/video/pwc/pwc-uncompress.c @@ -54,7 +54,7 @@ int pwc_decompress(struct pwc_device *pdev) yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ /* Raw format; that's easy... */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) { struct pwc_raw_frame *raw_frame = image; raw_frame->type = cpu_to_le16(pdev->type); diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 62d89b3113a4..7061a03f5cf1 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -216,7 +216,7 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma f->fmt.pix.width = pdev->view.x; f->fmt.pix.height = pdev->view.y; f->fmt.pix.field = V4L2_FIELD_NONE; - if (pdev->vpalette == VIDEO_PALETTE_YUV420P) { + if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; @@ -304,10 +304,10 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) fps = pdev->vframes; } - if (pixelformat == V4L2_PIX_FMT_YUV420) - pdev->vpalette = VIDEO_PALETTE_YUV420P; - else - pdev->vpalette = VIDEO_PALETTE_RAW; + if (pixelformat != V4L2_PIX_FMT_YUV420 && + pixelformat != V4L2_PIX_FMT_PWC1 && + pixelformat != V4L2_PIX_FMT_PWC2) + return -EINVAL; PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d " "compression=%d snapshot=%d format=%c%c%c%c\n", @@ -330,6 +330,8 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) if (ret) return ret; + pdev->pixfmt = pixelformat; + pwc_vidioc_fill_fmt(pdev, f); return 0; @@ -357,152 +359,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { - /* Query cabapilities */ - case VIDIOCGCAP: - { - struct video_capability *caps = arg; - - strcpy(caps->name, vdev->name); - caps->type = VID_TYPE_CAPTURE; - caps->channels = 1; - caps->audios = 1; - caps->minwidth = pdev->view_min.x; - caps->minheight = pdev->view_min.y; - caps->maxwidth = pdev->view_max.x; - caps->maxheight = pdev->view_max.y; - break; - } - - /* Channel functions (simulate 1 channel) */ - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Webcam"); - return 0; - } - - case VIDIOCSCHAN: - { - /* The spec says the argument is an integer, but - the bttv driver uses a video_channel arg, which - makes sense becasue it also has the norm flag. - */ - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - - - /* Picture functions; contrast etc. */ - case VIDIOCGPICT: - { - struct video_picture *p = arg; - int val; - - val = pwc_get_brightness(pdev); - if (val >= 0) - p->brightness = (val<<9); - else - p->brightness = 0xffff; - val = pwc_get_contrast(pdev); - if (val >= 0) - p->contrast = (val<<10); - else - p->contrast = 0xffff; - /* Gamma, Whiteness, what's the difference? :) */ - val = pwc_get_gamma(pdev); - if (val >= 0) - p->whiteness = (val<<11); - else - p->whiteness = 0xffff; - if (pwc_get_saturation(pdev, &val)<0) - p->colour = 0xffff; - else - p->colour = 32768 + val * 327; - p->depth = 24; - p->palette = pdev->vpalette; - p->hue = 0xFFFF; /* N/A */ - break; - } - - case VIDIOCSPICT: - { - struct video_picture *p = arg; - /* - * FIXME: Suppose we are mid read - ANSWER: No problem: the firmware of the camera - can handle brightness/contrast/etc - changes at _any_ time, and the palette - is used exactly once in the uncompress - routine. - */ - pwc_set_brightness(pdev, p->brightness); - pwc_set_contrast(pdev, p->contrast); - pwc_set_gamma(pdev, p->whiteness); - pwc_set_saturation(pdev, (p->colour-32768)/327); - if (p->palette && p->palette != pdev->vpalette) { - switch (p->palette) { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - pdev->vpalette = p->palette; - return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - break; - default: - return -EINVAL; - break; - } - } - break; - } - - /* Window/size parameters */ - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = pdev->view.x; - vw->height = pdev->view.y; - vw->chromakey = 0; - vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | - (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); - break; - } - - case VIDIOCSWIN: - { - struct video_window *vw = arg; - int fps, snapshot, ret; - - fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - snapshot = vw->flags & PWC_FPS_SNAPSHOT; - if (fps == 0) - fps = pdev->vframes; - if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) - return 0; - ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); - if (ret) - return ret; - break; - } - - /* We don't have overlay support (yet) */ - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb,0,sizeof(*vb)); - break; - } - +#ifdef CONFIG_VIDEO_V4L1_COMPAT /* mmap() functions */ case VIDIOCGMBUF: { @@ -517,164 +374,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) vm->offsets[i] = i * pdev->len_per_image; break; } - - case VIDIOCMCAPTURE: - { - /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ - struct video_mmap *vm = arg; - - PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); - if (vm->frame < 0 || vm->frame >= pwc_mbufs) - return -EINVAL; - - /* xawtv is nasty. It probes the available palettes - by setting a very small image size and trying - various palettes... The driver doesn't support - such small images, so I'm working around it. - */ - if (vm->format) - { - switch (vm->format) - { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - break; - default: - return -EINVAL; - break; - } - } - - if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && - (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { - int ret; - - PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); - ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (ret) - return ret; - } /* ... size mismatch */ - - /* FIXME: should we lock here? */ - if (pdev->image_used[vm->frame]) - return -EBUSY; /* buffer wasn't available. Bummer */ - pdev->image_used[vm->frame] = 1; - - /* Okay, we're done here. In the SYNC call we wait until a - frame comes available, then expand image into the given - buffer. - In contrast to the CPiA cam the Philips cams deliver a - constant stream, almost like a grabber card. Also, - we have separate buffers for the rawdata and the image, - meaning we can nearly always expand into the requested buffer. - */ - PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n"); - break; - } - - case VIDIOCSYNC: - { - /* The doc says: "Whenever a buffer is used it should - call VIDIOCSYNC to free this frame up and continue." - - The only odd thing about this whole procedure is - that MCAPTURE flags the buffer as "in use", and - SYNC immediately unmarks it, while it isn't - after SYNC that you know that the buffer actually - got filled! So you better not start a CAPTURE in - the same frame immediately (use double buffering). - This is not a problem for this cam, since it has - extra intermediate buffers, but a hardware - grabber card will then overwrite the buffer - you're working on. - */ - int *mbuf = arg; - int ret; - - PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf); - - /* bounds check */ - if (*mbuf < 0 || *mbuf >= pwc_mbufs) - return -EINVAL; - /* check if this buffer was requested anyway */ - if (pdev->image_used[*mbuf] == 0) - return -EINVAL; - - /* Add ourselves to the frame wait-queue. - - FIXME: needs auditing for safety. - QUESTION: In what respect? I think that using the - frameq is safe now. - */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - /* Check for unplugged/etc. here */ - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; - } - - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* The frame is ready. Expand in the image buffer - requested by the user. I don't care if you - mmap() 5 buffers and request data in this order: - buffer 4 2 3 0 1 2 3 0 4 3 1 . . . - Grabber hardware may not be so forgiving. - */ - PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n"); - pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ - /* Decompress, etc */ - ret = pwc_handle_frame(pdev); - pdev->image_used[*mbuf] = 0; - if (ret) - return -EFAULT; - break; - } - - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - - strcpy(v->name, "Microphone"); - v->audio = -1; /* unknown audio minor */ - v->flags = 0; - v->mode = VIDEO_SOUND_MONO; - v->volume = 0; - v->bass = 0; - v->treble = 0; - v->balance = 0x8000; - v->step = 1; - break; - } - - case VIDIOCSAUDIO: - { - /* Dummy: nothing can be set */ - break; - } - - case VIDIOCGUNIT: - { - struct video_unit *vu = arg; - - vu->video = pdev->vdev->minor & 0x3F; - vu->audio = -1; /* not known yet */ - vu->vbi = -1; - vu->radio = -1; - vu->teletext = -1; - break; - } +#endif /* V4L2 Layer */ case VIDIOC_QUERYCAP: @@ -1081,7 +781,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->index = index; buf->m.offset = index * pdev->len_per_image; - if (pdev->vpalette == VIDEO_PALETTE_RAW) + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); else buf->bytesused = pdev->view.size; @@ -1158,7 +858,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); buf->index = pdev->fill_image; - if (pdev->vpalette == VIDEO_PALETTE_RAW) + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); else buf->bytesused = pdev->view.size; diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index f1b206632957..36a9c83b5f5d 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #ifdef CONFIG_USB_PWC_INPUT_EVDEV @@ -49,7 +49,7 @@ #define PWC_MINOR 0 #define PWC_EXTRAMINOR 12 #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) -#define PWC_VERSION "10.0.13" +#define PWC_VERSION "10.0.14" #define PWC_NAME "pwc" #define PFX PWC_NAME ": " @@ -180,7 +180,7 @@ struct pwc_device int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* palette: 420P, RAW or RGBBAYER */ + int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */ int vframe_count; /* received frames */ int vframes_dumped; /* counter for dumped frames */ int vframes_error; /* frames received in error */