📄 cpia2_v4l.c
字号:
/**************************************************************************** * * Filename: cpia2_v4l.c * * Copyright 2001, STMicrolectronics, Inc. * Contact: steve.miller@st.com * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> * * Description: * This is a USB driver for CPia2 based video cameras. * The infrastructure of this driver is based on the cpia usb driver by * Jochen Scharrlach and Johannes Erdfeldt. * * 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. * * Stripped of 2.4 stuff ready for main kernel submit by * Alan Cox <alan@redhat.com> ****************************************************************************/#include <linux/version.h>#include <linux/config.h>#include <linux/module.h>#include <linux/time.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/moduleparam.h>#include "cpia2.h"#include "cpia2dev.h"//#define _CPIA2_DEBUG_#define MAKE_STRING_1(x) #x#define MAKE_STRING(x) MAKE_STRING_1(x)static int video_nr = -1;module_param(video_nr, int, 0);MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");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)");static int num_buffers = 3;module_param(num_buffers, int, 0);MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)");static int alternate = DEFAULT_ALT;module_param(alternate, int, 0);MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" MAKE_STRING(USBIF_ISO_6) ", default " MAKE_STRING(DEFAULT_ALT) ")");static int flicker_freq = 60;module_param(flicker_freq, int, 0);MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" MAKE_STRING(60) ", default " MAKE_STRING(60) ")");static int flicker_mode = NEVER_FLICKER;module_param(flicker_mode, int, 0);MODULE_PARM_DESC(flicker_mode, "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" MAKE_STRING(ANTI_FLICKER_ON) ", default " MAKE_STRING(NEVER_FLICKER) ")");MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");MODULE_SUPPORTED_DEVICE("video");MODULE_LICENSE("GPL");#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"#ifndef VID_HARDWARE_CPIA2#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"#endifstruct 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 (sizeof(framerate_controls)/sizeof(framerate_controls[0]))static struct control_menu_info flicker_controls[] ={ { NEVER_FLICKER, "Off" }, { FLICKER_50, "50 Hz" }, { FLICKER_60, "60 Hz" },};#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))static struct control_menu_info lights_controls[] ={ { 0, "Off" }, { 64, "Top" }, { 128, "Bottom" }, { 192, "Both" },};#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))#define GPIO_LIGHTS_MASK 192static 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 (sizeof(controls)/sizeof(controls[0]))/****************************************************************************** * * cpia2_open * *****************************************************************************/static int cpia2_open(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); struct camera_data *cam = video_get_drvdata(dev); int retval = 0; if (!cam) { ERR("Internal error, camera_data not found!\n"); return -ENODEV; } if(mutex_lock_interruptible(&cam->busy_lock)) return -ERESTARTSYS; if(!cam->present) { retval = -ENODEV; goto err_return; } if (cam->open_count > 0) { goto skip_init; } if (cpia2_allocate_buffers(cam)) { retval = -ENOMEM; goto err_return; } /* reset the camera */ if (cpia2_reset_camera(cam) < 0) { retval = -EIO; goto err_return; } cam->APP_len = 0; cam->COM_len = 0;skip_init: { struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); if(!fh) { retval = -ENOMEM; goto err_return; } 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);err_return: mutex_unlock(&cam->busy_lock); return retval;}/****************************************************************************** * * cpia2_close * *****************************************************************************/static int cpia2_close(struct inode *inode, 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; mutex_lock(&cam->busy_lock); if (cam->present && (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD )) { cpia2_usb_stream_stop(cam); if(cam->open_count == 1) { /* save camera state for later open */ cpia2_save_camera_state(cam); cpia2_set_low_power(cam); cpia2_free_buffers(cam); } } { if(fh->mmapped) 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); } } mutex_unlock(&cam->busy_lock); return 0;}/****************************************************************************** * * cpia2_v4l_read * *****************************************************************************/static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *off){ struct video_device *dev = video_devdata(file); struct camera_data *cam = video_get_drvdata(dev); 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);}/****************************************************************************** * * cpia2_v4l_poll * *****************************************************************************/static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait){ struct video_device *dev = video_devdata(filp); struct camera_data *cam = video_get_drvdata(dev); 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);}/****************************************************************************** * * ioctl_cap_query * *****************************************************************************/static int ioctl_cap_query(void *arg, struct camera_data *cam){ struct video_capability *vc; int retval = 0; vc = arg; if (cam->params.pnp_id.product == 0x151) strcpy(vc->name, "QX5 Microscope"); else strcpy(vc->name, "CPiA2 Camera"); vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER; vc->channels = 1; vc->audios = 0; vc->minwidth = 176; /* VIDEOSIZE_QCIF */ vc->minheight = 144; switch (cam->params.version.sensor_flags) { case CPIA2_VP_SENSOR_FLAGS_500: vc->maxwidth = STV_IMAGE_VGA_COLS; vc->maxheight = STV_IMAGE_VGA_ROWS; break; case CPIA2_VP_SENSOR_FLAGS_410: vc->maxwidth = STV_IMAGE_CIF_COLS; vc->maxheight = STV_IMAGE_CIF_ROWS; break; default: return -EINVAL; } return retval;}/****************************************************************************** * * ioctl_get_channel * *****************************************************************************/static int ioctl_get_channel(void *arg){ int retval = 0; struct video_channel *v; v = arg; if (v->channel != 0) return -EINVAL; v->channel = 0; strcpy(v->name, "Camera"); v->tuners = 0; v->flags = 0; v->type = VIDEO_TYPE_CAMERA; v->norm = 0; return retval;}/****************************************************************************** * * ioctl_set_channel * *****************************************************************************/static int ioctl_set_channel(void *arg){ struct video_channel *v; int retval = 0; v = arg; if (retval == 0 && v->channel != 0) retval = -EINVAL; return retval;}/****************************************************************************** * * ioctl_set_image_prop * *****************************************************************************/static int ioctl_set_image_prop(void *arg, struct camera_data *cam){ struct video_picture *vp; int retval = 0; vp = arg; /* brightness, color, contrast need no check 0-65535 */ memcpy(&cam->vp, vp, sizeof(*vp)); /* update cam->params.colorParams */ cam->params.color_params.brightness = vp->brightness / 256; cam->params.color_params.saturation = vp->colour / 256; cam->params.color_params.contrast = vp->contrast / 256; DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n", cam->params.color_params.brightness, cam->params.color_params.saturation, cam->params.color_params.contrast); cpia2_set_color_params(cam); return retval;}static int sync(struct camera_data *cam, int frame_nr){ struct framebuf *frame = &cam->buffers[frame_nr]; while (1) { if (frame->status == FRAME_READY) return 0; if (!cam->streaming) { frame->status = FRAME_READY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -