📄 usbvision-video.c
字号:
/* * USB USBVISION Video device driver 0.9.9 * * * * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> * * This module is part of usbvision driver project. * * 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. * * Let's call the version 0.... until compression decoding is completely * implemented. * * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach. * It was based on USB CPiA driver written by Peter Pregler, * Scott J. Bertin and Johannes Erdfelt * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler & * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink * Updates to driver completed by Dwaine P. Garden * * * TODO: * - use submit_urb for all setup packets * - Fix memory settings for nt1004. It is 4 times as big as the * nt1003 memory. * - Add audio on endpoint 3 for nt1004 chip. * Seems impossible, needs a codec interface. Which one? * - Clean up the driver. * - optimization for performance. * - Add Videotext capability (VBI). Working on it..... * - Check audio for other devices * */#include <linux/version.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/utsname.h>#include <linux/highmem.h>#include <linux/vmalloc.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/io.h>#include <linux/videodev2.h>#include <linux/video_decoder.h>#include <linux/i2c.h>#include <media/saa7115.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <media/tuner.h>#include <linux/workqueue.h>#include "usbvision.h"#include "usbvision-cards.h"#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\ Dwaine Garden <DwaineGarden@rogers.com>"#define DRIVER_NAME "usbvision"#define DRIVER_ALIAS "USBVision"#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"#define DRIVER_LICENSE "GPL"#define USBVISION_DRIVER_VERSION_MAJOR 0#define USBVISION_DRIVER_VERSION_MINOR 9#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\USBVISION_DRIVER_VERSION_MINOR,\USBVISION_DRIVER_VERSION_PATCHLEVEL)#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)#define ENABLE_HEXDUMP 0 /* Enable if you need it */#ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) { \ if (video_debug & (level)) \ printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ __func__, __LINE__ , ## args); \ }#else #define PDEBUG(level, fmt, args...) do {} while(0)#endif#define DBG_IO 1<<1#define DBG_PROBE 1<<2#define DBG_MMAP 1<<3//String operations#define rmspace(str) while(*str==' ') str++;#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;/* sequential number of usbvision device */static int usbvision_nr;static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }};/* Function prototypes */static void usbvision_release(struct usb_usbvision *usbvision);/* Default initialization of device driver parameters *//* Set the default format for ISOC endpoint */static int isocMode = ISOC_MODE_COMPRESS;/* Set the default Debug Mode of the device driver */static int video_debug;/* Set the default device to power on at startup */static int PowerOnAtOpen = 1;/* Sequential Number of Video Device */static int video_nr = -1;/* Sequential Number of Radio Device */static int radio_nr = -1;/* Sequential Number of VBI Device */static int vbi_nr = -1;/* Grab parameters for the device driver *//* Showing parameters under SYSFS */module_param(isocMode, int, 0444);module_param(video_debug, int, 0444);module_param(PowerOnAtOpen, int, 0444);module_param(video_nr, int, 0444);module_param(radio_nr, int, 0444);module_param(vbi_nr, int, 0444);MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)");MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)");// Misc stuffMODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE(DRIVER_LICENSE);MODULE_VERSION(USBVISION_VERSION_STRING);MODULE_ALIAS(DRIVER_ALIAS);/*****************************************************************************//* SYSFS Code - Copied from the stv680.c usb module. *//* Device information is located at /sys/class/video4linux/video0 *//* Device parameters information is located at /sys/module/usbvision *//* Device USB Information is located at *//* /sys/bus/usb/drivers/USBVision Video Grabber *//*****************************************************************************/#define YES_NO(x) ((x) ? "Yes" : "No")static inline struct usb_usbvision *cd_to_usbvision(struct device *cd){ struct video_device *vdev = container_of(cd, struct video_device, dev); return video_get_drvdata(vdev);}static ssize_t show_version(struct device *cd, struct device_attribute *attr, char *buf){ return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);}static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);static ssize_t show_model(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);}static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);static ssize_t show_hue(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_HUE; ctrl.value = 0; if(usbvision->user) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value);}static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);static ssize_t show_contrast(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_CONTRAST; ctrl.value = 0; if(usbvision->user) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value);}static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);static ssize_t show_brightness(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_BRIGHTNESS; ctrl.value = 0; if(usbvision->user) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value);}static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);static ssize_t show_saturation(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_SATURATION; ctrl.value = 0; if(usbvision->user) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value);}static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);static ssize_t show_streaming(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));}static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);static ssize_t show_compression(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));}static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);static ssize_t show_device_bridge(struct device *cd, struct device_attribute *attr, char *buf){ struct video_device *vdev = container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType);}static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);static void usbvision_create_sysfs(struct video_device *vdev){ int res; if (!vdev) return; do { res = device_create_file(&vdev->dev, &dev_attr_version); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_model); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_hue); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_contrast); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_brightness); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_saturation); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_streaming); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_compression); if (res<0) break; res = device_create_file(&vdev->dev, &dev_attr_bridge); if (res>=0) return; } while (0); err("%s error: %d\n", __func__, res);}static void usbvision_remove_sysfs(struct video_device *vdev){ if (vdev) { device_remove_file(&vdev->dev, &dev_attr_version); device_remove_file(&vdev->dev, &dev_attr_model); device_remove_file(&vdev->dev, &dev_attr_hue); device_remove_file(&vdev->dev, &dev_attr_contrast); device_remove_file(&vdev->dev, &dev_attr_brightness); device_remove_file(&vdev->dev, &dev_attr_saturation); device_remove_file(&vdev->dev, &dev_attr_streaming); device_remove_file(&vdev->dev, &dev_attr_compression); device_remove_file(&vdev->dev, &dev_attr_bridge); }}/* * usbvision_open() * * This is part of Video 4 Linux API. The driver can be opened by one * client only (checks internal counter 'usbvision->user'). The procedure * then allocates buffers needed for video processing. * */static int usbvision_v4l2_open(struct inode *inode, struct file *file){ struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, "open"); lock_kernel(); usbvision_reset_powerOffTimer(usbvision); if (usbvision->user) errCode = -EBUSY; else { /* Allocate memory for the scratch ring buffer */ errCode = usbvision_scratch_alloc(usbvision); if (isocMode==ISOC_MODE_COMPRESS) { /* Allocate intermediate decompression buffers only if needed */ errCode = usbvision_decompress_alloc(usbvision); } if (errCode) { /* Deallocate all buffers if trouble */ usbvision_scratch_free(usbvision); usbvision_decompress_free(usbvision); } } /* If so far no errors then we shall start the camera */ if (!errCode) { mutex_lock(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); } /* Send init sequence only once, it's large! */ if (!usbvision->initialized) { int setup_ok = 0; setup_ok = usbvision_setup(usbvision,isocMode); if (setup_ok) usbvision->initialized = 1; else errCode = -EBUSY; } if (!errCode) { usbvision_begin_streaming(usbvision); errCode = usbvision_init_isoc(usbvision); /* device must be initialized before isoc transfer */ usbvision_muxsel(usbvision,0); usbvision->user++; } else { if (PowerOnAtOpen) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } } mutex_unlock(&usbvision->lock); } /* prepare queues */ usbvision_empty_framequeues(usbvision); PDEBUG(DBG_IO, "success"); unlock_kernel(); return errCode;}/* * usbvision_v4l2_close() * * This is part of Video 4 Linux API. The procedure * stops streaming and deallocates all buffers that were earlier * allocated in usbvision_v4l2_open(). * */static int usbvision_v4l2_close(struct inode *inode, struct file *file){ struct usb_usbvision *usbvision = video_drvdata(file); PDEBUG(DBG_IO, "close"); mutex_lock(&usbvision->lock); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); usbvision_stop_isoc(usbvision); usbvision_decompress_free(usbvision); usbvision_frames_free(usbvision); usbvision_empty_framequeues(usbvision); usbvision_scratch_free(usbvision); usbvision->user--; if (PowerOnAtOpen) { /* power off in a little while to avoid off/on every close/open short sequences */ usbvision_set_powerOffTimer(usbvision); usbvision->initialized = 0; } mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); } PDEBUG(DBG_IO, "success"); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -