[media] cpia2: major overhaul to get it in a working state again
authorHans Verkuil <hans.verkuil@cisco.com>
Sun, 29 Apr 2012 11:44:44 +0000 (08:44 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 7 May 2012 19:21:05 +0000 (16:21 -0300)
This driver was severely broken. This patch makes it work again, and updates
it to the latest V4L2 frameworks (except for videobuf2). It passes the
v4l2-compliance tests and it now handles suspend/resume correctly.

Several custom controls are replaced by new standard controls, only the
USB_ALTERNATE control remains.

Tested with the Hanse HVS-CM500PC USB microscope.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_usb.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cpia2/cpia2dev.h [deleted file]

index ab25218..cdef677 100644 (file)
 #define __CPIA2_H__
 
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
-#include "cpia2dev.h"
 #include "cpia2_registers.h"
 
 /* define for verbose debug output */
@@ -65,7 +66,6 @@
 
 /* Flicker Modes */
 #define NEVER_FLICKER   0
-#define ANTI_FLICKER_ON 1
 #define FLICKER_60      60
 #define FLICKER_50      50
 
@@ -148,7 +148,6 @@ enum {
 #define DEFAULT_BRIGHTNESS 0x46
 #define DEFAULT_CONTRAST 0x93
 #define DEFAULT_SATURATION 0x7f
-#define DEFAULT_TARGET_KB 0x30
 
 /* Power state */
 #define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
@@ -287,7 +286,6 @@ struct camera_params {
        struct {
                u8 cam_register;
                u8 flicker_mode_req;    /* 1 if flicker on, else never flicker */
-               int mains_frequency;
        } flicker_control;
 
        struct {
@@ -337,7 +335,7 @@ struct camera_params {
                u8 vc_control;
                u8 vc_mp_direction;
                u8 vc_mp_data;
-               u8 target_kb;
+               u8 quality;
        } vc_params;
 
        struct {
@@ -366,23 +364,23 @@ struct framebuf {
        struct framebuf *next;
 };
 
-struct cpia2_fh {
-       enum v4l2_priority prio;
-       u8 mmapped;
-};
-
 struct camera_data {
        /* locks */
+       struct v4l2_device v4l2_dev;
        struct mutex v4l2_lock; /* serialize file operations */
-       struct v4l2_prio_state prio;
+       struct v4l2_ctrl_handler hdl;
+       struct {
+               /* Lights control cluster */
+               struct v4l2_ctrl *top_light;
+               struct v4l2_ctrl *bottom_light;
+       };
+       struct v4l2_ctrl *usb_alt;
 
        /* camera status */
-       volatile int present;   /* Is the camera still present? */
-       int open_count;         /* # of process that have camera open */
        int first_image_seen;
-       u8 mains_freq;          /* for flicker control */
        enum sensors sensor_type;
        u8 flush;
+       struct v4l2_fh *stream_fh;
        u8 mmapped;
        int streaming;          /* 0 = no, 1 = yes */
        int xfer_mode;          /* XFER_BULK or XFER_ISOC */
@@ -390,7 +388,7 @@ struct camera_data {
 
        /* v4l */
        int video_size;                 /* VIDEO_SIZE_ */
-       struct video_device *vdev;      /* v4l videodev */
+       struct video_device vdev;       /* v4l videodev */
        u32 width;
        u32 height;                     /* Its size */
        __u32 pixelformat;       /* Format fourcc      */
@@ -425,6 +423,7 @@ struct camera_data {
 /* v4l */
 int cpia2_register_camera(struct camera_data *cam);
 void cpia2_unregister_camera(struct camera_data *cam);
+void cpia2_camera_release(struct v4l2_device *v4l2_dev);
 
 /* core */
 int cpia2_reset_camera(struct camera_data *cam);
@@ -443,7 +442,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
 int cpia2_do_command(struct camera_data *cam,
                     unsigned int command,
                     unsigned char direction, unsigned char param);
-struct camera_data *cpia2_init_camera_struct(void);
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
 int cpia2_init_camera(struct camera_data *cam);
 int cpia2_allocate_buffers(struct camera_data *cam);
 void cpia2_free_buffers(struct camera_data *cam);
@@ -454,7 +453,6 @@ unsigned int cpia2_poll(struct camera_data *cam,
 int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
 void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
 void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
 int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
 int cpia2_set_fps(struct camera_data *cam, int framerate);
 
index ee91e29..17188e2 100644 (file)
@@ -66,7 +66,6 @@ static int config_sensor_410(struct camera_data *cam,
 static int config_sensor_500(struct camera_data *cam,
                            int reqwidth, int reqheight);
 static int set_all_properties(struct camera_data *cam);
-static void get_color_params(struct camera_data *cam);
 static void wake_system(struct camera_data *cam);
 static void set_lowlight_boost(struct camera_data *cam);
 static void reset_camera_struct(struct camera_data *cam);
@@ -453,15 +452,6 @@ int cpia2_do_command(struct camera_data *cam,
                cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
                cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
                break;
-       case CPIA2_CMD_GET_VP_BRIGHTNESS:
-               cam->params.color_params.brightness = cmd.buffer.block_data[0];
-               break;
-       case CPIA2_CMD_GET_CONTRAST:
-               cam->params.color_params.contrast = cmd.buffer.block_data[0];
-               break;
-       case CPIA2_CMD_GET_VP_SATURATION:
-               cam->params.color_params.saturation = cmd.buffer.block_data[0];
-               break;
        case CPIA2_CMD_GET_VP_GPIO_DATA:
                cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
                break;
@@ -617,6 +607,7 @@ int cpia2_reset_camera(struct camera_data *cam)
 {
        u8 tmp_reg;
        int retval = 0;
+       int target_kb;
        int i;
        struct cpia2_command cmd;
 
@@ -800,9 +791,16 @@ int cpia2_reset_camera(struct camera_data *cam)
        }
        cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
 
-       /* Set target size (kb) on vc */
+       /* Set target size (kb) on vc
+          This is a heuristic based on the quality parameter and the raw
+          framesize in kB divided by 16 (the compression factor when the
+          quality is 100%) */
+       target_kb = (cam->width * cam->height * 2 / 16384) *
+                               cam->params.vc_params.quality / 100;
+       if (target_kb < 1)
+               target_kb = 1;
        cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
-                        TRANSFER_WRITE, cam->params.vc_params.target_kb);
+                        TRANSFER_WRITE, target_kb);
 
        /* Wiggle VC Reset */
        /***
@@ -1538,23 +1536,17 @@ static int set_all_properties(struct camera_data *cam)
         * framerate and user_mode were already set (set_default_user_mode).
         **/
 
-       cpia2_set_color_params(cam);
-
        cpia2_usb_change_streaming_alternate(cam,
                                          cam->params.camera_state.stream_mode);
 
-       cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
-                        cam->params.vp_params.user_effects);
-
-       cpia2_set_flicker_mode(cam,
-                              cam->params.flicker_control.flicker_mode_req);
-
        cpia2_do_command(cam,
                         CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
                         TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
        cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
                         cam->params.vp_params.gpio_data);
 
+       v4l2_ctrl_handler_setup(&cam->hdl);
+
        wake_system(cam);
 
        set_lowlight_boost(cam);
@@ -1569,7 +1561,6 @@ static int set_all_properties(struct camera_data *cam)
  *****************************************************************************/
 void cpia2_save_camera_state(struct camera_data *cam)
 {
-       get_color_params(cam);
        cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
        cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
                         0);
@@ -1577,30 +1568,6 @@ void cpia2_save_camera_state(struct camera_data *cam)
        /* Don't get framerate or target_kb. Trust the values we already have */
 }
 
-/******************************************************************************
- *
- *  get_color_params
- *
- *****************************************************************************/
-static void get_color_params(struct camera_data *cam)
-{
-       cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
-       cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
-       cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
-}
-
-/******************************************************************************
- *
- *  cpia2_set_color_params
- *
- *****************************************************************************/
-void cpia2_set_color_params(struct camera_data *cam)
-{
-       DBG("Setting color params\n");
-       cpia2_set_brightness(cam, cam->params.color_params.brightness);
-       cpia2_set_contrast(cam, cam->params.color_params.contrast);
-       cpia2_set_saturation(cam, cam->params.color_params.saturation);
-}
 
 /******************************************************************************
  *
@@ -1664,15 +1631,9 @@ int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
 
        switch(mode) {
        case NEVER_FLICKER:
-               cam->params.flicker_control.flicker_mode_req = mode;
-               break;
        case FLICKER_60:
-               cam->params.flicker_control.flicker_mode_req = mode;
-               cam->params.flicker_control.mains_frequency = 60;
-               break;
        case FLICKER_50:
                cam->params.flicker_control.flicker_mode_req = mode;
-               cam->params.flicker_control.mains_frequency = 50;
                break;
        default:
                err = -EINVAL;
@@ -1701,6 +1662,7 @@ void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
        {
                cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
        }
+       cam->params.vp_params.user_effects = cam_reg;
        cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
                         cam_reg);
 }
@@ -1725,35 +1687,11 @@ void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
        {
                cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
        }
+       cam->params.vp_params.user_effects = cam_reg;
        cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
                         cam_reg);
 }
 
-/******************************************************************************
- *
- *  set_target_kb
- *
- *  The new Target KB is set in cam->params.vc_params.target_kb and
- *  activates on reset.
- *****************************************************************************/
-
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
-{
-       DBG("Requested target_kb = %d\n", value);
-       if (value != cam->params.vc_params.target_kb) {
-
-               cpia2_usb_stream_pause(cam);
-
-               /* reset camera for new target_kb */
-               cam->params.vc_params.target_kb = value;
-               cpia2_reset_camera(cam);
-
-               cpia2_usb_stream_resume(cam);
-       }
-
-       return 0;
-}
-
 /******************************************************************************
  *
  *  cpia2_set_gpio
@@ -1843,7 +1781,7 @@ void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
        if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
                value++;
        DBG("Setting brightness to %d (0x%0x)\n", value, value);
-       cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+       cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
 }
 
 /******************************************************************************
@@ -1854,7 +1792,6 @@ void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
 void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
 {
        DBG("Setting contrast to %d (0x%0x)\n", value, value);
-       cam->params.color_params.contrast = value;
        cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
 }
 
@@ -1866,7 +1803,6 @@ void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
 void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
 {
        DBG("Setting saturation to %d (0x%0x)\n", value, value);
-       cam->params.color_params.saturation = value;
        cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
 }
 
@@ -2168,14 +2104,10 @@ static void reset_camera_struct(struct camera_data *cam)
        /***
         * The following parameter values are the defaults from the register map.
         ***/
-       cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
-       cam->params.color_params.contrast = DEFAULT_CONTRAST;
-       cam->params.color_params.saturation = DEFAULT_SATURATION;
        cam->params.vp_params.lowlight_boost = 0;
 
        /* FlickerModes */
        cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
-       cam->params.flicker_control.mains_frequency = 60;
 
        /* jpeg params */
        cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
@@ -2188,7 +2120,7 @@ static void reset_camera_struct(struct camera_data *cam)
        cam->params.vp_params.gpio_data = 0;
 
        /* Target kb params */
-       cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+       cam->params.vc_params.quality = 100;
 
        /***
         * Set Sensor FPS as fast as possible.
@@ -2228,7 +2160,7 @@ static void reset_camera_struct(struct camera_data *cam)
  *
  *  Initializes camera struct, does not call reset to fill in defaults.
  *****************************************************************************/
-struct camera_data *cpia2_init_camera_struct(void)
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
 {
        struct camera_data *cam;
 
@@ -2239,8 +2171,13 @@ struct camera_data *cpia2_init_camera_struct(void)
                return NULL;
        }
 
+       cam->v4l2_dev.release = cpia2_camera_release;
+       if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
+               v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
+               kfree(cam);
+               return NULL;
+       }
 
-       cam->present = 1;
        mutex_init(&cam->v4l2_lock);
        init_waitqueue_head(&cam->wq_stream);
 
@@ -2373,11 +2310,6 @@ long cpia2_read(struct camera_data *cam,
                return -EINVAL;
        }
 
-       if (!cam->present) {
-               LOG("%s: camera removed\n",__func__);
-               return 0;       /* EOF */
-       }
-
        if (!cam->streaming) {
                /* Start streaming */
                cpia2_usb_stream_start(cam,
@@ -2393,12 +2325,12 @@ long cpia2_read(struct camera_data *cam,
        if (frame->status != FRAME_READY) {
                mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
-                              !cam->present ||
+                              !video_is_registered(&cam->vdev) ||
                               (frame = cam->curbuff)->status == FRAME_READY);
                mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               if (!cam->present)
+               if (!video_is_registered(&cam->vdev))
                        return 0;
        }
 
@@ -2423,17 +2355,10 @@ long cpia2_read(struct camera_data *cam,
 unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
                        poll_table *wait)
 {
-       unsigned int status=0;
+       unsigned int status = v4l2_ctrl_poll(filp, wait);
 
-       if (!cam) {
-               ERR("%s: Internal error, camera_data not found!\n",__func__);
-               return POLLERR;
-       }
-
-       if (!cam->present)
-               return POLLHUP;
-
-       if(!cam->streaming) {
+       if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
+                       !cam->streaming) {
                /* Start streaming */
                cpia2_usb_stream_start(cam,
                                       cam->params.camera_state.stream_mode);
@@ -2441,10 +2366,8 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
 
        poll_wait(filp, &cam->wq_stream, wait);
 
-       if(!cam->present)
-               status = POLLHUP;
-       else if(cam->curbuff->status == FRAME_READY)
-               status = POLLIN | POLLRDNORM;
+       if (cam->curbuff->status == FRAME_READY)
+               status |= POLLIN | POLLRDNORM;
 
        return status;
 }
@@ -2462,12 +2385,9 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
        unsigned long start = (unsigned long) adr;
        unsigned long page, pos;
 
-       if (!cam)
-               return -ENODEV;
-
        DBG("mmap offset:%ld size:%ld\n", start_offset, size);
 
-       if (!cam->present)
+       if (!video_is_registered(&cam->vdev))
                return -ENODEV;
 
        if (size > cam->frame_size*cam->num_frames  ||
index 59c797c..95b5d6e 100644 (file)
@@ -54,6 +54,8 @@ static void cpia2_usb_complete(struct urb *urb);
 static int cpia2_usb_probe(struct usb_interface *intf,
                           const struct usb_device_id *id);
 static void cpia2_usb_disconnect(struct usb_interface *intf);
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int cpia2_usb_resume(struct usb_interface *intf);
 
 static void free_sbufs(struct camera_data *cam);
 static void add_APPn(struct camera_data *cam);
@@ -74,6 +76,9 @@ static struct usb_driver cpia2_driver = {
        .name           = "cpia2",
        .probe          = cpia2_usb_probe,
        .disconnect     = cpia2_usb_disconnect,
+       .suspend        = cpia2_usb_suspend,
+       .resume         = cpia2_usb_resume,
+       .reset_resume   = cpia2_usb_resume,
        .id_table       = cpia2_id_table
 };
 
@@ -218,10 +223,9 @@ static void cpia2_usb_complete(struct urb *urb)
                return;
        }
 
-       if (!cam->streaming || !cam->present || cam->open_count == 0) {
-               LOG("Will now stop the streaming: streaming = %d, "
-                   "present=%d, open_count=%d\n",
-                   cam->streaming, cam->present, cam->open_count);
+       if (!cam->streaming || !video_is_registered(&cam->vdev)) {
+               LOG("Will now stop the streaming: streaming = %d, present=%d\n",
+                   cam->streaming, video_is_registered(&cam->vdev));
                return;
        }
 
@@ -392,7 +396,7 @@ static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
        struct cpia2_command cmd;
        unsigned char reg;
 
-       if(!cam->present)
+       if (!video_is_registered(&cam->vdev))
                return -ENODEV;
 
        /***
@@ -752,8 +756,8 @@ int cpia2_usb_stream_pause(struct camera_data *cam)
 {
        int ret = 0;
        if(cam->streaming) {
-               ret = set_alternate(cam, USBIF_CMDONLY);
                free_sbufs(cam);
+               ret = set_alternate(cam, USBIF_CMDONLY);
        }
        return ret;
 }
@@ -770,6 +774,10 @@ int cpia2_usb_stream_resume(struct camera_data *cam)
                cam->first_image_seen = 0;
                ret = set_alternate(cam, cam->params.camera_state.stream_mode);
                if(ret == 0) {
+                       /* for some reason the user effects need to be set
+                          again when starting streaming. */
+                       cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+                                       cam->params.vp_params.user_effects);
                        ret = submit_urbs(cam);
                }
        }
@@ -784,6 +792,7 @@ int cpia2_usb_stream_resume(struct camera_data *cam)
 int cpia2_usb_stream_stop(struct camera_data *cam)
 {
        int ret;
+
        ret = cpia2_usb_stream_pause(cam);
        cam->streaming = 0;
        configure_transfer_mode(cam, 0);
@@ -812,7 +821,8 @@ static int cpia2_usb_probe(struct usb_interface *intf,
        /* If we get to this point, we found a CPiA2 camera */
        LOG("CPiA2 USB camera found\n");
 
-       if((cam = cpia2_init_camera_struct()) == NULL)
+       cam = cpia2_init_camera_struct(intf);
+       if (cam == NULL)
                return -ENOMEM;
 
        cam->dev = udev;
@@ -825,16 +835,9 @@ static int cpia2_usb_probe(struct usb_interface *intf,
                return ret;
        }
 
-       if ((ret = cpia2_register_camera(cam)) < 0) {
-               ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
-               kfree(cam);
-               return ret;
-       }
-
 
        if((ret = cpia2_init_camera(cam)) < 0) {
                ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
-               cpia2_unregister_camera(cam);
                kfree(cam);
                return ret;
        }
@@ -853,6 +856,13 @@ static int cpia2_usb_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, cam);
 
+       ret = cpia2_register_camera(cam);
+       if (ret < 0) {
+               ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+               kfree(cam);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -865,13 +875,16 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
 {
        struct camera_data *cam = usb_get_intfdata(intf);
        usb_set_intfdata(intf, NULL);
-       cam->present = 0;
 
        DBG("Stopping stream\n");
        cpia2_usb_stream_stop(cam);
 
+       mutex_lock(&cam->v4l2_lock);
        DBG("Unregistering camera\n");
        cpia2_unregister_camera(cam);
+       v4l2_device_disconnect(&cam->v4l2_dev);
+       mutex_unlock(&cam->v4l2_lock);
+       v4l2_device_put(&cam->v4l2_dev);
 
        if(cam->buffers) {
                DBG("Wakeup waiting processes\n");
@@ -884,14 +897,41 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
        DBG("Releasing interface\n");
        usb_driver_release_interface(&cpia2_driver, intf);
 
-       if (cam->open_count == 0) {
-               DBG("Freeing camera structure\n");
-               kfree(cam);
+       LOG("CPiA2 camera disconnected.\n");
+}
+
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct camera_data *cam = usb_get_intfdata(intf);
+
+       mutex_lock(&cam->v4l2_lock);
+       if (cam->streaming) {
+               cpia2_usb_stream_stop(cam);
+               cam->streaming = 1;
        }
+       mutex_unlock(&cam->v4l2_lock);
 
-       LOG("CPiA2 camera disconnected.\n");
+       dev_info(&intf->dev, "going into suspend..\n");
+       return 0;
 }
 
+/* Resume device - start device. */
+static int cpia2_usb_resume(struct usb_interface *intf)
+{
+       struct camera_data *cam = usb_get_intfdata(intf);
+
+       mutex_lock(&cam->v4l2_lock);
+       v4l2_ctrl_handler_setup(&cam->hdl);
+       if (cam->streaming) {
+               cam->streaming = 0;
+               cpia2_usb_stream_start(cam,
+                               cam->params.camera_state.stream_mode);
+       }
+       mutex_unlock(&cam->v4l2_lock);
+
+       dev_info(&intf->dev, "coming out of suspend..\n");
+       return 0;
+}
 
 /******************************************************************************
  *
index 077eb1d..bb4f1d0 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/stringify.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 
 #include "cpia2.h"
-#include "cpia2dev.h"
 
 static int video_nr = -1;
 module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
 
-static int buffer_size = 68*1024;
+static int buffer_size = 68 * 1024;
 module_param(buffer_size, int, 0);
 MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
 
@@ -62,18 +62,10 @@ MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
                 __stringify(USBIF_ISO_6) ", default "
                 __stringify(DEFAULT_ALT) ")");
 
-static int flicker_freq = 60;
-module_param(flicker_freq, int, 0);
-MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or"
-                __stringify(60) ", default "
-                __stringify(60) ")");
-
-static int flicker_mode = NEVER_FLICKER;
+static int flicker_mode;
 module_param(flicker_mode, int, 0);
-MODULE_PARM_DESC(flicker_mode,
-                "Flicker supression (" __stringify(NEVER_FLICKER) "or"
-                __stringify(ANTI_FLICKER_ON) ", default "
-                __stringify(NEVER_FLICKER) ")");
+MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
+                __stringify(60) ", default 0)");
 
 MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
@@ -82,153 +74,7 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(CPIA_VERSION);
 
 #define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-
-struct control_menu_info {
-       int value;
-       char name[32];
-};
-
-static struct control_menu_info framerate_controls[] =
-{
-       { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
-       { CPIA2_VP_FRAMERATE_7_5,  "7.5 fps"  },
-       { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
-       { CPIA2_VP_FRAMERATE_15,   "15 fps"   },
-       { CPIA2_VP_FRAMERATE_25,   "25 fps"   },
-       { CPIA2_VP_FRAMERATE_30,   "30 fps"   },
-};
-#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
-
-static struct control_menu_info flicker_controls[] =
-{
-       { NEVER_FLICKER, "Off" },
-       { FLICKER_50,    "50 Hz" },
-       { FLICKER_60,    "60 Hz"  },
-};
-#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
-
-static struct control_menu_info lights_controls[] =
-{
-       { 0,   "Off" },
-       { 64,  "Top" },
-       { 128, "Bottom"  },
-       { 192, "Both"  },
-};
-#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
-#define GPIO_LIGHTS_MASK 192
-
-static struct v4l2_queryctrl controls[] = {
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = DEFAULT_BRIGHTNESS,
-       },
-       {
-               .id            = V4L2_CID_CONTRAST,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = DEFAULT_CONTRAST,
-       },
-       {
-               .id            = V4L2_CID_SATURATION,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = DEFAULT_SATURATION,
-       },
-       {
-               .id            = V4L2_CID_HFLIP,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               .name          = "Mirror Horizontally",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 0,
-       },
-       {
-               .id            = V4L2_CID_VFLIP,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               .name          = "Flip Vertically",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 0,
-       },
-       {
-               .id            = CPIA2_CID_TARGET_KB,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Target KB",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = DEFAULT_TARGET_KB,
-       },
-       {
-               .id            = CPIA2_CID_GPIO,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "GPIO",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 0,
-       },
-       {
-               .id            = CPIA2_CID_FLICKER_MODE,
-               .type          = V4L2_CTRL_TYPE_MENU,
-               .name          = "Flicker Reduction",
-               .minimum       = 0,
-               .maximum       = NUM_FLICKER_CONTROLS-1,
-               .step          = 1,
-               .default_value = 0,
-       },
-       {
-               .id            = CPIA2_CID_FRAMERATE,
-               .type          = V4L2_CTRL_TYPE_MENU,
-               .name          = "Framerate",
-               .minimum       = 0,
-               .maximum       = NUM_FRAMERATE_CONTROLS-1,
-               .step          = 1,
-               .default_value = NUM_FRAMERATE_CONTROLS-1,
-       },
-       {
-               .id            = CPIA2_CID_USB_ALT,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "USB Alternate",
-               .minimum       = USBIF_ISO_1,
-               .maximum       = USBIF_ISO_6,
-               .step          = 1,
-               .default_value = DEFAULT_ALT,
-       },
-       {
-               .id            = CPIA2_CID_LIGHTS,
-               .type          = V4L2_CTRL_TYPE_MENU,
-               .name          = "Lights",
-               .minimum       = 0,
-               .maximum       = NUM_LIGHTS_CONTROLS-1,
-               .step          = 1,
-               .default_value = 0,
-       },
-       {
-               .id            = CPIA2_CID_RESET_CAMERA,
-               .type          = V4L2_CTRL_TYPE_BUTTON,
-               .name          = "Reset Camera",
-               .minimum       = 0,
-               .maximum       = 0,
-               .step          = 0,
-               .default_value = 0,
-       },
-};
-#define NUM_CONTROLS (ARRAY_SIZE(controls))
-
+#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
 
 /******************************************************************************
  *
@@ -238,38 +84,27 @@ static struct v4l2_queryctrl controls[] = {
 static int cpia2_open(struct file *file)
 {
        struct camera_data *cam = video_drvdata(file);
-       struct cpia2_fh *fh;
-
-       if (!cam) {
-               ERR("Internal error, camera_data not found!\n");
-               return -ENODEV;
-       }
+       int retval = v4l2_fh_open(file);
 
-       if (!cam->present)
-               return -ENODEV;
+       if (retval)
+               return retval;
 
-       if (cam->open_count == 0) {
-               if (cpia2_allocate_buffers(cam))
+       if (v4l2_fh_is_singular_file(file)) {
+               if (cpia2_allocate_buffers(cam)) {
+                       v4l2_fh_release(file);
                        return -ENOMEM;
+               }
 
                /* reset the camera */
-               if (cpia2_reset_camera(cam) < 0)
+               if (cpia2_reset_camera(cam) < 0) {
+                       v4l2_fh_release(file);
                        return -EIO;
+               }
 
                cam->APP_len = 0;
                cam->COM_len = 0;
        }
 
-       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-       if (!fh)
-               return -ENOMEM;
-       file->private_data = fh;
-       fh->prio = V4L2_PRIORITY_UNSET;
-       v4l2_prio_open(&cam->prio, &fh->prio);
-       fh->mmapped = 0;
-
-       ++cam->open_count;
-
        cpia2_dbg_dump_registers(cam);
        return 0;
 }
@@ -283,37 +118,22 @@ static int cpia2_close(struct file *file)
 {
        struct video_device *dev = video_devdata(file);
        struct camera_data *cam = video_get_drvdata(dev);
-       struct cpia2_fh *fh = file->private_data;
 
-       if (cam->present &&
-           (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
+       if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
                cpia2_usb_stream_stop(cam);
 
-               if (cam->open_count == 1) {
-                       /* save camera state for later open */
-                       cpia2_save_camera_state(cam);
+               /* save camera state for later open */
+               cpia2_save_camera_state(cam);
 
-                       cpia2_set_low_power(cam);
-                       cpia2_free_buffers(cam);
-               }
+               cpia2_set_low_power(cam);
+               cpia2_free_buffers(cam);
        }
 
-       if (fh->mmapped)
+       if (cam->stream_fh == file->private_data) {
+               cam->stream_fh = NULL;
                cam->mmapped = 0;
-       v4l2_prio_close(&cam->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       if (--cam->open_count == 0) {
-               cpia2_free_buffers(cam);
-               if (!cam->present) {
-                       video_unregister_device(dev);
-                       kfree(cam);
-                       return 0;
-               }
        }
-
-       return 0;
+       return v4l2_fh_release(file);
 }
 
 /******************************************************************************
@@ -327,16 +147,9 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
        struct camera_data *cam = video_drvdata(file);
        int noblock = file->f_flags&O_NONBLOCK;
 
-       struct cpia2_fh *fh = file->private_data;
-
        if(!cam)
                return -EINVAL;
 
-       /* Priority check */
-       if(fh->prio != V4L2_PRIORITY_RECORD) {
-               return -EBUSY;
-       }
-
        return cpia2_read(cam, buf, count, noblock);
 }
 
@@ -349,15 +162,6 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
 static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
 {
        struct camera_data *cam = video_drvdata(filp);
-       struct cpia2_fh *fh = filp->private_data;
-
-       if(!cam)
-               return POLLERR;
-
-       /* Priority check */
-       if(fh->prio != V4L2_PRIORITY_RECORD) {
-               return POLLERR;
-       }
 
        return cpia2_poll(cam, filp, wait);
 }
@@ -384,34 +188,11 @@ static int sync(struct camera_data *cam, int frame_nr)
                mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               if(!cam->present)
+               if (!video_is_registered(&cam->vdev))
                        return -ENOTTY;
        }
 }
 
-/******************************************************************************
- *
- *  ioctl_set_gpio
- *
- *****************************************************************************/
-
-static long cpia2_default(struct file *file, void *fh, bool valid_prio,
-                         int cmd, void *arg)
-{
-       struct camera_data *cam = video_drvdata(file);
-       __u32 gpio_val;
-
-       if (cmd != CPIA2_CID_GPIO)
-               return -EINVAL;
-
-       gpio_val = *(__u32*) arg;
-
-       if (gpio_val &~ 0xFFU)
-               return -EINVAL;
-
-       return cpia2_set_gpio(cam, (unsigned char)gpio_val);
-}
-
 /******************************************************************************
  *
  *  ioctl_querycap
@@ -465,9 +246,11 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
        if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
                memset(vc->bus_info,0, sizeof(vc->bus_info));
 
-       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+       vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_READWRITE |
                           V4L2_CAP_STREAMING;
+       vc->capabilities = vc->device_caps |
+                          V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
@@ -610,22 +393,12 @@ static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
                                        struct v4l2_format *f)
 {
        struct camera_data *cam = video_drvdata(file);
-       struct cpia2_fh *fh = _fh;
        int err, frame;
 
-       err = v4l2_prio_check(&cam->prio, fh->prio);
-       if (err)
-               return err;
        err = cpia2_try_fmt_vid_cap(file, _fh, f);
        if(err != 0)
                return err;
 
-       /* Ensure that only this process can change the format. */
-       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
-       if(err != 0) {
-               return err;
-       }
-
        cam->pixelformat = f->fmt.pix.pixelformat;
 
        /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
@@ -713,240 +486,126 @@ static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
        return 0;
 }
 
-/******************************************************************************
- *
- *  ioctl_queryctrl
- *
- *  V4L2 query possible control variables
- *
- *****************************************************************************/
+struct framerate_info {
+       int value;
+       struct v4l2_fract period;
+};
 
-static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+static const struct framerate_info framerate_controls[] = {
+       { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
+       { CPIA2_VP_FRAMERATE_7_5,  { 2, 15 } },
+       { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
+       { CPIA2_VP_FRAMERATE_15,   { 1, 15 } },
+       { CPIA2_VP_FRAMERATE_25,   { 1, 25 } },
+       { CPIA2_VP_FRAMERATE_30,   { 1, 30 } },
+};
+
+static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
 {
        struct camera_data *cam = video_drvdata(file);
+       struct v4l2_captureparm *cap = &p->parm.capture;
        int i;
 
-       for(i=0; i<NUM_CONTROLS; ++i) {
-               if(c->id == controls[i].id) {
-                       memcpy(c, controls+i, sizeof(*c));
-                       break;
-               }
-       }
-
-       if(i == NUM_CONTROLS)
+       if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       /* Some devices have additional limitations */
-       switch(c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               /***
-                * Don't let the register be set to zero - bug in VP4
-                * flash of full brightness
-                ***/
-               if (cam->params.pnp_id.device_type == DEVICE_STV_672)
-                       c->minimum = 1;
-               break;
-       case V4L2_CID_VFLIP:
-               // VP5 Only
-               if(cam->params.pnp_id.device_type == DEVICE_STV_672)
-                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
-               break;
-       case CPIA2_CID_FRAMERATE:
-               if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
-                  cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
-                       // Maximum 15fps
-                       for(i=0; i<c->maximum; ++i) {
-                               if(framerate_controls[i].value ==
-                                  CPIA2_VP_FRAMERATE_15) {
-                                       c->maximum = i;
-                                       c->default_value = i;
-                               }
-                       }
+       cap->capability = V4L2_CAP_TIMEPERFRAME;
+       cap->readbuffers = cam->num_frames;
+       for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
+               if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
+                       cap->timeperframe = framerate_controls[i].period;
+                       break;
                }
-               break;
-       case CPIA2_CID_FLICKER_MODE:
-               // Flicker control only valid for 672.
-               if(cam->params.pnp_id.device_type != DEVICE_STV_672)
-                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
-               break;
-       case CPIA2_CID_LIGHTS:
-               // Light control only valid for the QX5 Microscope.
-               if(cam->params.pnp_id.product != 0x151)
-                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
-               break;
-       default:
-               break;
-       }
-
        return 0;
 }
 
-/******************************************************************************
- *
- *  ioctl_querymenu
- *
- *  V4L2 query possible control variables
- *
- *****************************************************************************/
-
-static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m)
+static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
 {
        struct camera_data *cam = video_drvdata(file);
+       struct v4l2_captureparm *cap = &p->parm.capture;
+       struct v4l2_fract tpf = cap->timeperframe;
+       int max = ARRAY_SIZE(framerate_controls) - 1;
+       int ret;
+       int i;
 
-       switch(m->id) {
-       case CPIA2_CID_FLICKER_MODE:
-               if (m->index >= NUM_FLICKER_CONTROLS)
-                       return -EINVAL;
+       ret = cpia2_g_parm(file, fh, p);
+       if (ret || !tpf.denominator || !tpf.numerator)
+               return ret;
+
+       /* Maximum 15 fps for this model */
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+           cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+               max -= 2;
+       for (i = 0; i <= max; i++) {
+               struct v4l2_fract f1 = tpf;
+               struct v4l2_fract f2 = framerate_controls[i].period;
+
+               f1.numerator *= f2.denominator;
+               f2.numerator *= f1.denominator;
+               if (f1.numerator >= f2.numerator)
+                       break;
+       }
+       if (i > max)
+               i = max;
+       cap->timeperframe = framerate_controls[i].period;
+       return cpia2_set_fps(cam, framerate_controls[i].value);
+}
 
-               strcpy(m->name, flicker_controls[m->index].name);
-               break;
-       case CPIA2_CID_FRAMERATE:
-           {
-               int maximum = NUM_FRAMERATE_CONTROLS - 1;
-               if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
-                  cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
-                       // Maximum 15fps
-                       int i;
-                       for(i=0; i<maximum; ++i) {
-                               if(framerate_controls[i].value ==
-                                  CPIA2_VP_FRAMERATE_15)
-                                       maximum = i;
-                       }
-               }
-               if (m->index > maximum)
-                       return -EINVAL;
+static const struct {
+       u32 width;
+       u32 height;
+} cpia2_framesizes[] = {
+       { 640, 480 },
+       { 352, 288 },
+       { 320, 240 },
+       { 288, 216 },
+       { 256, 192 },
+       { 224, 168 },
+       { 192, 144 },
+       { 176, 144 },
+};
 
-               strcpy(m->name, framerate_controls[m->index].name);
-               break;
-           }
-       case CPIA2_CID_LIGHTS:
-               if (m->index >= NUM_LIGHTS_CONTROLS)
-                       return -EINVAL;
+static int cpia2_enum_framesizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
 
-               strcpy(m->name, lights_controls[m->index].name);
-               break;
-       default:
+       if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
+           fsize->pixel_format != V4L2_PIX_FMT_JPEG)
                return -EINVAL;
-       }
+       if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
+               return -EINVAL;
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       fsize->discrete.width = cpia2_framesizes[fsize->index].width;
+       fsize->discrete.height = cpia2_framesizes[fsize->index].height;
 
        return 0;
 }
 
-/******************************************************************************
- *
- *  ioctl_g_ctrl
- *
- *  V4L2 get the value of a control variable
- *
- *****************************************************************************/
-
-static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int cpia2_enum_frameintervals(struct file *file, void *fh,
+                                          struct v4l2_frmivalenum *fival)
 {
        struct camera_data *cam = video_drvdata(file);
+       int max = ARRAY_SIZE(framerate_controls) - 1;
+       int i;
 
-       switch(c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
-                                TRANSFER_READ, 0);
-               c->value = cam->params.color_params.brightness;
-               break;
-       case V4L2_CID_CONTRAST:
-               cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
-                                TRANSFER_READ, 0);
-               c->value = cam->params.color_params.contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
-                                TRANSFER_READ, 0);
-               c->value = cam->params.color_params.saturation;
-               break;
-       case V4L2_CID_HFLIP:
-               cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
-                                TRANSFER_READ, 0);
-               c->value = (cam->params.vp_params.user_effects &
-                           CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
-               break;
-       case V4L2_CID_VFLIP:
-               cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
-                                TRANSFER_READ, 0);
-               c->value = (cam->params.vp_params.user_effects &
-                           CPIA2_VP_USER_EFFECTS_FLIP) != 0;
-               break;
-       case CPIA2_CID_TARGET_KB:
-               c->value = cam->params.vc_params.target_kb;
-               break;
-       case CPIA2_CID_GPIO:
-               cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
-                                TRANSFER_READ, 0);
-               c->value = cam->params.vp_params.gpio_data;
-               break;
-       case CPIA2_CID_FLICKER_MODE:
-       {
-               int i, mode;
-               cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
-                                TRANSFER_READ, 0);
-               if(cam->params.flicker_control.cam_register &
-                  CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
-                       mode = NEVER_FLICKER;
-               } else {
-                   if(cam->params.flicker_control.cam_register &
-                      CPIA2_VP_FLICKER_MODES_50HZ) {
-                       mode = FLICKER_50;
-                   } else {
-                       mode = FLICKER_60;
-                   }
-               }
-               for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
-                       if(flicker_controls[i].value == mode) {
-                               c->value = i;
-                               break;
-                       }
-               }
-               if(i == NUM_FLICKER_CONTROLS)
-                       return -EINVAL;
-               break;
-       }
-       case CPIA2_CID_FRAMERATE:
-       {
-               int maximum = NUM_FRAMERATE_CONTROLS - 1;
-               int i;
-               for(i=0; i<= maximum; i++) {
-                       if(cam->params.vp_params.frame_rate ==
-                          framerate_controls[i].value)
-                               break;
-               }
-               if(i > maximum)
-                       return -EINVAL;
-               c->value = i;
-               break;
-       }
-       case CPIA2_CID_USB_ALT:
-               c->value = cam->params.camera_state.stream_mode;
-               break;
-       case CPIA2_CID_LIGHTS:
-       {
-               int i;
-               cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
-                                TRANSFER_READ, 0);
-               for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
-                       if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
-                          lights_controls[i].value) {
-                               break;
-                       }
-               }
-               if(i == NUM_LIGHTS_CONTROLS)
-                       return -EINVAL;
-               c->value = i;
-               break;
-       }
-       case CPIA2_CID_RESET_CAMERA:
+       if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
+           fival->pixel_format != V4L2_PIX_FMT_JPEG)
                return -EINVAL;
-       default:
-               return -EINVAL;
-       }
-
-       DBG("Get control id:%d, value:%d\n", c->id, c->value);
 
+       /* Maximum 15 fps for this model */
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+           cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+               max -= 2;
+       if (fival->index > max)
+               return -EINVAL;
+       for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
+               if (fival->width == cpia2_framesizes[i].width &&
+                   fival->height == cpia2_framesizes[i].height)
+                       break;
+       if (i == ARRAY_SIZE(cpia2_framesizes))
+               return -EINVAL;
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete = framerate_controls[fival->index].period;
        return 0;
 }
 
@@ -958,72 +617,54 @@ static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
  *
  *****************************************************************************/
 
-static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct camera_data *cam = video_drvdata(file);
-       int i;
-       int retval = 0;
+       struct camera_data *cam =
+               container_of(ctrl->handler, struct camera_data, hdl);
+       static const int flicker_table[] = {
+               NEVER_FLICKER,
+               FLICKER_50,
+               FLICKER_60,
+       };
 
-       DBG("Set control id:%d, value:%d\n", c->id, c->value);
-
-       /* Check that the value is in range */
-       for(i=0; i<NUM_CONTROLS; i++) {
-               if(c->id == controls[i].id) {
-                       if(c->value < controls[i].minimum ||
-                          c->value > controls[i].maximum) {
-                               return -EINVAL;
-                       }
-                       break;
-               }
-       }
-       if(i == NUM_CONTROLS)
-               return -EINVAL;
+       DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
 
-       switch(c->id) {
+       switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               cpia2_set_brightness(cam, c->value);
+               cpia2_set_brightness(cam, ctrl->val);
                break;
        case V4L2_CID_CONTRAST:
-               cpia2_set_contrast(cam, c->value);
+               cpia2_set_contrast(cam, ctrl->val);
                break;
        case V4L2_CID_SATURATION:
-               cpia2_set_saturation(cam, c->value);
+               cpia2_set_saturation(cam, ctrl->val);
                break;
        case V4L2_CID_HFLIP:
-               cpia2_set_property_mirror(cam, c->value);
+               cpia2_set_property_mirror(cam, ctrl->val);
                break;
        case V4L2_CID_VFLIP:
-               cpia2_set_property_flip(cam, c->value);
+               cpia2_set_property_flip(cam, ctrl->val);
                break;
-       case CPIA2_CID_TARGET_KB:
-               retval = cpia2_set_target_kb(cam, c->value);
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
+       case V4L2_CID_ILLUMINATORS_1:
+               return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
+                                          (cam->bottom_light->val << 7));
+       case V4L2_CID_JPEG_ACTIVE_MARKER:
+               cam->params.compression.inhibit_htables =
+                       !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
                break;
-       case CPIA2_CID_GPIO:
-               retval = cpia2_set_gpio(cam, c->value);
-               break;
-       case CPIA2_CID_FLICKER_MODE:
-               retval = cpia2_set_flicker_mode(cam,
-                                             flicker_controls[c->value].value);
-               break;
-       case CPIA2_CID_FRAMERATE:
-               retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+               cam->params.vc_params.quality = ctrl->val;
                break;
        case CPIA2_CID_USB_ALT:
-               retval = cpia2_usb_change_streaming_alternate(cam, c->value);
-               break;
-       case CPIA2_CID_LIGHTS:
-               retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
-               break;
-       case CPIA2_CID_RESET_CAMERA:
-               cpia2_usb_stream_pause(cam);
-               cpia2_reset_camera(cam);
-               cpia2_usb_stream_resume(cam);
+               cam->params.camera_state.stream_mode = ctrl->val;
                break;
        default:
-               retval = -EINVAL;
+               return -EINVAL;
        }
 
-       return retval;
+       return 0;
 }
 
 /******************************************************************************
@@ -1084,6 +725,8 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
 
        cam->params.compression.inhibit_htables =
                !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+       parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
+                              V4L2_JPEG_MARKER_DHT;
 
        if(parms->APP_len != 0) {
                if(parms->APP_len > 0 &&
@@ -1270,12 +913,12 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
                struct framebuf *cb=cam->curbuff;
                mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
-                                        !cam->present ||
+                                        !video_is_registered(&cam->vdev) ||
                                         (cb=cam->curbuff)->status == FRAME_READY);
                mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               if(!cam->present)
+               if (!video_is_registered(&cam->vdev))
                        return -ENOTTY;
                frame = cb->num;
        }
@@ -1299,56 +942,39 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        return 0;
 }
 
-static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
-{
-       struct cpia2_fh *fh = _fh;
-
-       *p = fh->prio;
-       return 0;
-}
-
-static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
-{
-       struct camera_data *cam = video_drvdata(file);
-       struct cpia2_fh *fh = _fh;
-
-       if (cam->streaming && prio != fh->prio &&
-                       fh->prio == V4L2_PRIORITY_RECORD)
-               /* Can't drop record priority while streaming */
-               return -EBUSY;
-
-       if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio &&
-                       v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD)
-               /* Only one program can record at a time */
-               return -EBUSY;
-       return v4l2_prio_change(&cam->prio, &fh->prio, prio);
-}
-
 static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 {
        struct camera_data *cam = video_drvdata(file);
+       int ret = -EINVAL;
 
        DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
        if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       if (!cam->streaming)
-               return cpia2_usb_stream_start(cam,
+       if (!cam->streaming) {
+               ret = cpia2_usb_stream_start(cam,
                                cam->params.camera_state.stream_mode);
-       return -EINVAL;
+               if (!ret)
+                       v4l2_ctrl_grab(cam->usb_alt, true);
+       }
+       return ret;
 }
 
 static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 {
        struct camera_data *cam = video_drvdata(file);
+       int ret = -EINVAL;
 
        DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
        if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       if (cam->streaming)
-               return cpia2_usb_stream_stop(cam);
-       return -EINVAL;
+       if (cam->streaming) {
+               ret = cpia2_usb_stream_stop(cam);
+               if (!ret)
+                       v4l2_ctrl_grab(cam->usb_alt, false);
+       }
+       return ret;
 }
 
 /******************************************************************************
@@ -1361,16 +987,10 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
        struct camera_data *cam = video_drvdata(file);
        int retval;
 
-       /* Priority check */
-       struct cpia2_fh *fh = file->private_data;
-       if(fh->prio != V4L2_PRIORITY_RECORD) {
-               return -EBUSY;
-       }
-
        retval = cpia2_remap_buffer(cam, area);
 
        if(!retval)
-               fh->mmapped = 1;
+               cam->stream_fh = file->private_data;
        return retval;
 }
 
@@ -1388,15 +1008,13 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
        cam->frame_size = buffer_size;
        cam->num_frames = num_buffers;
 
-       /* FlickerModes */
+       /* Flicker modes */
        cam->params.flicker_control.flicker_mode_req = flicker_mode;
-       cam->params.flicker_control.mains_frequency = flicker_freq;
 
-       /* streamMode */
+       /* stream modes */
        cam->params.camera_state.stream_mode = alternate;
 
        cam->pixelformat = V4L2_PIX_FMT_JPEG;
-       v4l2_prio_init(&cam->prio);
 }
 
 static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
@@ -1408,10 +1026,6 @@ static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
        .vidioc_g_fmt_vid_cap               = cpia2_g_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap               = cpia2_s_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap             = cpia2_try_fmt_vid_cap,
-       .vidioc_queryctrl                   = cpia2_queryctrl,
-       .vidioc_querymenu                   = cpia2_querymenu,
-       .vidioc_g_ctrl                      = cpia2_g_ctrl,
-       .vidioc_s_ctrl                      = cpia2_s_ctrl,
        .vidioc_g_jpegcomp                  = cpia2_g_jpegcomp,
        .vidioc_s_jpegcomp                  = cpia2_s_jpegcomp,
        .vidioc_cropcap                     = cpia2_cropcap,
@@ -1421,9 +1035,12 @@ static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
        .vidioc_dqbuf                       = cpia2_dqbuf,
        .vidioc_streamon                    = cpia2_streamon,
        .vidioc_streamoff                   = cpia2_streamoff,
-       .vidioc_g_priority                  = cpia2_g_priority,
-       .vidioc_s_priority                  = cpia2_s_priority,
-       .vidioc_default                     = cpia2_default,
+       .vidioc_s_parm                      = cpia2_s_parm,
+       .vidioc_g_parm                      = cpia2_g_parm,
+       .vidioc_enum_framesizes             = cpia2_enum_framesizes,
+       .vidioc_enum_frameintervals         = cpia2_enum_frameintervals,
+       .vidioc_subscribe_event             = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event           = v4l2_event_unsubscribe,
 };
 
 /***
@@ -1444,7 +1061,21 @@ static struct video_device cpia2_template = {
        .name =         "CPiA2 Camera",
        .fops =         &cpia2_fops,
        .ioctl_ops =    &cpia2_ioctl_ops,
-       .release =      video_device_release,
+       .release =      video_device_release_empty,
+};
+
+void cpia2_camera_release(struct v4l2_device *v4l2_dev)
+{
+       struct camera_data *cam =
+               container_of(v4l2_dev, struct camera_data, v4l2_dev);
+
+       v4l2_ctrl_handler_free(&cam->hdl);
+       v4l2_device_unregister(&cam->v4l2_dev);
+       kfree(cam);
+}
+
+static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
+       .s_ctrl = cpia2_s_ctrl,
 };
 
 /******************************************************************************
@@ -1454,20 +1085,74 @@ static struct video_device cpia2_template = {
  *****************************************************************************/
 int cpia2_register_camera(struct camera_data *cam)
 {
-       cam->vdev = video_device_alloc();
-       if(!cam->vdev)
-               return -ENOMEM;
+       struct v4l2_ctrl_handler *hdl = &cam->hdl;
+       struct v4l2_ctrl_config cpia2_usb_alt = {
+               .ops = &cpia2_ctrl_ops,
+               .id = CPIA2_CID_USB_ALT,
+               .name = "USB Alternate",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = USBIF_ISO_1,
+               .max = USBIF_ISO_6,
+               .step = 1,
+       };
+       int ret;
+
+       v4l2_ctrl_handler_init(hdl, 12);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS,
+                       cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+                       255, 1, DEFAULT_BRIGHTNESS);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+                       V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+                       V4L2_JPEG_ACTIVE_MARKER_DHT);
+       v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+                       100, 1, 100);
+       cpia2_usb_alt.def = alternate;
+       cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
+       /* VP5 Only */
+       if (cam->params.pnp_id.device_type != DEVICE_STV_672)
+               v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       /* Flicker control only valid for 672 */
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+               v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
+                       V4L2_CID_POWER_LINE_FREQUENCY,
+                       V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+       /* Light control only valid for the QX5 Microscope */
+       if (cam->params.pnp_id.product == 0x151) {
+               cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                               V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+               cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+                               V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+               v4l2_ctrl_cluster(2, &cam->top_light);
+       }
 
-       memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
-       video_set_drvdata(cam->vdev, cam);
-       cam->vdev->lock = &cam->v4l2_lock;
+       if (hdl->error) {
+               ret = hdl->error;
+               v4l2_ctrl_handler_free(hdl);
+               return ret;
+       }
+
+       cam->vdev = cpia2_template;
+       video_set_drvdata(&cam->vdev, cam);
+       cam->vdev.lock = &cam->v4l2_lock;
+       cam->vdev.ctrl_handler = hdl;
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
 
        reset_camera_struct_v4l(cam);
 
        /* register v4l device */
-       if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                ERR("video_register_device failed\n");
-               video_device_release(cam->vdev);
                return -ENODEV;
        }
 
@@ -1481,13 +1166,7 @@ int cpia2_register_camera(struct camera_data *cam)
  *****************************************************************************/
 void cpia2_unregister_camera(struct camera_data *cam)
 {
-       if (!cam->open_count) {
-               video_unregister_device(cam->vdev);
-       } else {
-               LOG("%s removed while open, deferring "
-                   "video_unregister_device\n",
-                   video_device_node_name(cam->vdev));
-       }
+       video_unregister_device(&cam->vdev);
 }
 
 /******************************************************************************
@@ -1524,23 +1203,12 @@ static void __init check_parameters(void)
                LOG("alternate specified is invalid, using %d\n", alternate);
        }
 
-       if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
-               flicker_mode = NEVER_FLICKER;
+       if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
+               flicker_mode = 0;
                LOG("Flicker mode specified is invalid, using %d\n",
                    flicker_mode);
        }
 
-       if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
-               flicker_freq = FLICKER_60;
-               LOG("Flicker mode specified is invalid, using %d\n",
-                   flicker_freq);
-       }
-
-       if(video_nr < -1 || video_nr > 64) {
-               video_nr = -1;
-               LOG("invalid video_nr specified, must be -1 to 64\n");
-       }
-
        DBG("Using %d buffers, each %d bytes, alternate=%d\n",
            num_buffers, buffer_size, alternate);
 }
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
deleted file mode 100644 (file)
index f66691f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************************
- *
- *  Filename: cpia2dev.h
- *
- *  Copyright 2001, STMicrolectronics, Inc.
- *
- *  Contact:  steve.miller@st.com
- *
- *  Description:
- *     This file provides definitions for applications wanting to use the
- *     cpia2 driver beyond the generic v4l capabilities.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-#ifndef CPIA2_DEV_HEADER
-#define CPIA2_DEV_HEADER
-
-#include <linux/videodev2.h>
-
-/***
- * The following defines are ioctl numbers based on video4linux private ioctls,
- * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
- * args
- */
-#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
-
-/* V4L2 driver specific controls */
-#define CPIA2_CID_TARGET_KB     (V4L2_CID_PRIVATE_BASE+0)
-#define CPIA2_CID_GPIO          (V4L2_CID_PRIVATE_BASE+1)
-#define CPIA2_CID_FLICKER_MODE  (V4L2_CID_PRIVATE_BASE+2)
-#define CPIA2_CID_FRAMERATE     (V4L2_CID_PRIVATE_BASE+3)
-#define CPIA2_CID_USB_ALT       (V4L2_CID_PRIVATE_BASE+4)
-#define CPIA2_CID_LIGHTS        (V4L2_CID_PRIVATE_BASE+5)
-#define CPIA2_CID_RESET_CAMERA  (V4L2_CID_PRIVATE_BASE+6)
-
-#endif