Commit 6c493f8b authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] cpia2: major overhaul to get it in a working state again

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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 04ef0524
......@@ -32,11 +32,12 @@
#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);
......
......@@ -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 ||
......
......@@ -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;
}
/******************************************************************************
*
......
......@@ -39,15 +39,15 @@
#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);
}
......
/****************************************************************************
*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment