s2255drv.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,473 行 · 第 1/5 页

C
2,473
字号
/* *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device * *   Copyright (C) 2007-2008 by Sensoray Company Inc. *                              Dean Anderson * * Some video buffer code based on vivi driver: * * Sensoray 2255 device supports 4 simultaneous channels. * The channels are not "crossbar" inputs, they are physically * attached to separate video decoders. * * Because of USB2.0 bandwidth limitations. There is only a * certain amount of data which may be transferred at one time. * * Example maximum bandwidth utilization: * * -full size, color mode YUYV or YUV422P: 2 channels at once * * -full or half size Grey scale: all 4 channels at once * * -half size, color mode YUYV or YUV422P: all 4 channels at once * * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels *  at once. *  (TODO: Incorporate videodev2 frame rate(FR) enumeration, *  which is currently experimental.) * * 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. */#include <linux/module.h>#include <linux/firmware.h>#include <linux/kernel.h>#include <linux/mutex.h>#include <linux/videodev2.h>#include <linux/version.h>#include <linux/mm.h>#include <media/videobuf-vmalloc.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <linux/vmalloc.h>#include <linux/usb.h>#include "compat.h"#define FIRMWARE_FILE_NAME "f2255usb.bin"/* default JPEG quality */#define S2255_DEF_JPEG_QUAL     50/* vendor request in */#define S2255_VR_IN		0/* vendor request out */#define S2255_VR_OUT		1/* firmware query */#define S2255_VR_FW		0x30/* USB endpoint number for configuring the device */#define S2255_CONFIG_EP         2/* maximum time for DSP to start responding after last FW word loaded(ms) */#define S2255_DSP_BOOTTIME      800/* maximum time to wait for firmware to load (ms) */#define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)#define S2255_DEF_BUFS          16#define S2255_SETMODE_TIMEOUT   500#define MAX_CHANNELS		4#define S2255_MARKER_FRAME	0x2255DA4AL#define S2255_MARKER_RESPONSE	0x2255ACACL#define S2255_USB_XFER_SIZE	(16 * 1024)#define MAX_CHANNELS		4#define MAX_PIPE_BUFFERS	1#define SYS_FRAMES		4/* maximum size is PAL full size plus room for the marker header(s) */#define SYS_FRAMES_MAXSIZE	(720*288*2*2 + 4096)#define DEF_USB_BLOCK		S2255_USB_XFER_SIZE#define LINE_SZ_4CIFS_NTSC	640#define LINE_SZ_2CIFS_NTSC	640#define LINE_SZ_1CIFS_NTSC	320#define LINE_SZ_4CIFS_PAL	704#define LINE_SZ_2CIFS_PAL	704#define LINE_SZ_1CIFS_PAL	352#define NUM_LINES_4CIFS_NTSC	240#define NUM_LINES_2CIFS_NTSC	240#define NUM_LINES_1CIFS_NTSC	240#define NUM_LINES_4CIFS_PAL	288#define NUM_LINES_2CIFS_PAL	288#define NUM_LINES_1CIFS_PAL	288#define LINE_SZ_DEF		640#define NUM_LINES_DEF		240/* predefined settings */#define FORMAT_NTSC	1#define FORMAT_PAL	2#define SCALE_4CIFS	1	/* 640x480(NTSC) or 704x576(PAL) */#define SCALE_2CIFS	2	/* 640x240(NTSC) or 704x288(PAL) */#define SCALE_1CIFS	3	/* 320x240(NTSC) or 352x288(PAL) */#define COLOR_YUVPL	1	/* YUV planar */#define COLOR_YUVPK	2	/* YUV packed */#define COLOR_Y8	4	/* monochrome */#define COLOR_JPG       5       /* JPEG */#define MASK_COLOR      0xff#define MASK_JPG_QUALITY 0xff00/* frame decimation. Not implemented by V4L yet(experimental in V4L) */#define FDEC_1		1	/* capture every frame. default */#define FDEC_2		2	/* capture every 2nd frame */#define FDEC_3		3	/* capture every 3rd frame */#define FDEC_5		5	/* capture every 5th frame *//*------------------------------------------------------- * Default mode parameters. *-------------------------------------------------------*/#define DEF_SCALE	SCALE_4CIFS#define DEF_COLOR	COLOR_YUVPL#define DEF_FDEC	FDEC_1#define DEF_BRIGHT	0#define DEF_CONTRAST	0x5c#define DEF_SATURATION	0x80#define DEF_HUE		0/* usb config commands */#define IN_DATA_TOKEN	0x2255c0de#define CMD_2255	0xc2255000#define CMD_SET_MODE	(CMD_2255 | 0x10)#define CMD_START	(CMD_2255 | 0x20)#define CMD_STOP	(CMD_2255 | 0x30)#define CMD_STATUS	(CMD_2255 | 0x40)struct s2255_mode {	u32 format;	/* input video format (NTSC, PAL) */	u32 scale;	/* output video scale */	u32 color;	/* output video color format */	u32 fdec;	/* frame decimation */	u32 bright;	/* brightness */	u32 contrast;	/* contrast */	u32 saturation;	/* saturation */	u32 hue;	/* hue (NTSC only)*/	u32 single;	/* capture 1 frame at a time (!=0), continuously (==0)*/	u32 usb_block;	/* block size. should be 4096 of DEF_USB_BLOCK */	u32 restart;	/* if DSP requires restart */};#define S2255_READ_IDLE		0#define S2255_READ_FRAME	1/* frame structure */struct s2255_framei {	unsigned long size;	unsigned long ulState;	/* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/	void *lpvbits;		/* image data */	unsigned long cur_size;	/* current data copied to it */};/* image buffer structure */struct s2255_bufferi {	unsigned long dwFrames;			/* number of frames in buffer */	struct s2255_framei frame[SYS_FRAMES];	/* array of FRAME structures */};#define DEF_MODEI_NTSC_CONT	{FORMAT_NTSC, DEF_SCALE, DEF_COLOR,	\			DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \			DEF_HUE, 0, DEF_USB_BLOCK, 0}struct s2255_dmaqueue {	struct list_head	active;	/* thread for acquisition */	struct task_struct	*kthread;	int			frame;	struct s2255_dev	*dev;	int			channel;};/* for firmware loading, fw_state */#define S2255_FW_NOTLOADED	0#define S2255_FW_LOADED_DSPWAIT	1#define S2255_FW_SUCCESS	2#define S2255_FW_FAILED		3#define S2255_FW_DISCONNECTING  4#define S2255_FW_MARKER         0x22552f2f/* 2255 read states */#define S2255_READ_IDLE         0#define S2255_READ_FRAME        1struct s2255_fw {	int		      fw_loaded;	int		      fw_size;	struct urb	      *fw_urb;	atomic_t	      fw_state;	void		      *pfw_data;	wait_queue_head_t     wait_fw;	const struct firmware *fw;};struct s2255_pipeinfo {	u32 max_transfer_size;	u32 cur_transfer_size;	u8 *transfer_buffer;	u32 transfer_flags;;	u32 state;	u32 prev_state;	u32 urb_size;	void *stream_urb;	void *dev;	/* back pointer to s2255_dev struct*/	u32 err_count;	u32 buf_index;	u32 idx;	u32 priority_set;};struct s2255_fmt; /*forward declaration */struct s2255_dev {	int			frames;	int			users[MAX_CHANNELS];	struct mutex		lock;	struct mutex		open_lock;	int			resources[MAX_CHANNELS];	struct usb_device	*udev;	struct usb_interface	*interface;	u8			read_endpoint;	struct s2255_dmaqueue	vidq[MAX_CHANNELS];	struct video_device	*vdev[MAX_CHANNELS];	struct list_head	s2255_devlist;	struct timer_list	timer;	struct s2255_fw	*fw_data;	int			board_num;	int			is_open;	struct s2255_pipeinfo	pipes[MAX_PIPE_BUFFERS];	struct s2255_bufferi		buffer[MAX_CHANNELS];	struct s2255_mode	mode[MAX_CHANNELS];	/* jpeg compression */	struct v4l2_jpegcompression jc[MAX_CHANNELS];	const struct s2255_fmt	*cur_fmt[MAX_CHANNELS];	int			cur_frame[MAX_CHANNELS];	int			last_frame[MAX_CHANNELS];	u32			cc;	/* current channel */	int			b_acquire[MAX_CHANNELS];	/* allocated image size */	unsigned long		req_image_size[MAX_CHANNELS];	/* received packet size */	unsigned long		pkt_size[MAX_CHANNELS];	int			bad_payload[MAX_CHANNELS];	unsigned long		frame_count[MAX_CHANNELS];	int			frame_ready;	/* if JPEG image */	int                     jpg_size[MAX_CHANNELS];	/* if channel configured to default state */	int                     chn_configured[MAX_CHANNELS];	wait_queue_head_t       wait_setmode[MAX_CHANNELS];	int                     setmode_ready[MAX_CHANNELS];	int                     chn_ready;	struct kref		kref;	spinlock_t              slock;};#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref)struct s2255_fmt {	char *name;	u32 fourcc;	int depth;};/* buffer for one video frame */struct s2255_buffer {	/* common v4l buffer stuff -- must be first */	struct videobuf_buffer vb;	const struct s2255_fmt *fmt;};struct s2255_fh {	struct s2255_dev	*dev;	const struct s2255_fmt	*fmt;	unsigned int		width;	unsigned int		height;	struct videobuf_queue	vb_vidq;	enum v4l2_buf_type	type;	int			channel;	/* mode below is the desired mode.	   mode in s2255_dev is the current mode that was last set */	struct s2255_mode	mode;	int			resources[MAX_CHANNELS];};#define CUR_USB_FWVER	774	/* current cypress EEPROM firmware version */#define S2255_MAJOR_VERSION	1#define S2255_MINOR_VERSION	13#define S2255_RELEASE		0#define S2255_VERSION		KERNEL_VERSION(S2255_MAJOR_VERSION, \					       S2255_MINOR_VERSION, \					       S2255_RELEASE)/* vendor ids */#define USB_S2255_VENDOR_ID	0x1943#define USB_S2255_PRODUCT_ID	0x2255#define S2255_NORMS		(V4L2_STD_PAL | V4L2_STD_NTSC)/* frame prefix size (sent once every frame) */#define PREFIX_SIZE		512/* Channels on box are in reverse order */static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};static LIST_HEAD(s2255_devlist);static int debug;static int *s2255_debug = &debug;static int s2255_start_readpipe(struct s2255_dev *dev);static void s2255_stop_readpipe(struct s2255_dev *dev);static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,			   int chn, int jpgsize);static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,			  struct s2255_mode *mode);static int s2255_board_shutdown(struct s2255_dev *dev);static void s2255_exit_v4l(struct s2255_dev *dev);static void s2255_fwload_start(struct s2255_dev *dev, int reset);static void s2255_destroy(struct kref *kref);static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,			     u16 index, u16 value, void *buf,			     s32 buf_len, int bOut);#define dprintk(level, fmt, arg...)					\	do {								\		if (*s2255_debug >= (level)) {				\			printk(KERN_DEBUG "s2255: " fmt, ##arg);	\		}							\	} while (0)static struct usb_driver s2255_driver;/* Declare static vars that will be used as parameters */static unsigned int vid_limit = 16;	/* Video memory limit, in Mb *//* start video number */static int video_nr = -1;	/* /dev/videoN, -1 for autodetect */module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");module_param(vid_limit, int, 0644);MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");module_param(video_nr, int, 0644);MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");/* USB device table */static struct usb_device_id s2255_table[] = {	{USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)},	{ }			/* Terminating entry */};MODULE_DEVICE_TABLE(usb, s2255_table);#define BUFFER_TIMEOUT msecs_to_jiffies(400)/* supported controls */static struct v4l2_queryctrl s2255_qctrl[] = {	{	.id = V4L2_CID_BRIGHTNESS,	.type = V4L2_CTRL_TYPE_INTEGER,	.name = "Brightness",	.minimum = -127,	.maximum = 128,	.step = 1,	.default_value = 0,	.flags = 0,	}, {	.id = V4L2_CID_CONTRAST,	.type = V4L2_CTRL_TYPE_INTEGER,	.name = "Contrast",	.minimum = 0,	.maximum = 255,	.step = 0x1,	.default_value = DEF_CONTRAST,	.flags = 0,	}, {	.id = V4L2_CID_SATURATION,	.type = V4L2_CTRL_TYPE_INTEGER,	.name = "Saturation",	.minimum = 0,	.maximum = 255,	.step = 0x1,	.default_value = DEF_SATURATION,	.flags = 0,	}, {	.id = V4L2_CID_HUE,	.type = V4L2_CTRL_TYPE_INTEGER,	.name = "Hue",	.minimum = 0,	.maximum = 255,	.step = 0x1,	.default_value = DEF_HUE,	.flags = 0,	}};static int qctl_regs[ARRAY_SIZE(s2255_qctrl)];/* image formats.  */static const struct s2255_fmt formats[] = {	{		.name = "4:2:2, planar, YUV422P",		.fourcc = V4L2_PIX_FMT_YUV422P,		.depth = 16	}, {		.name = "4:2:2, packed, YUYV",		.fourcc = V4L2_PIX_FMT_YUYV,		.depth = 16	}, {		.name = "4:2:2, packed, UYVY",		.fourcc = V4L2_PIX_FMT_UYVY,		.depth = 16	}, {		.name = "JPG",		.fourcc = V4L2_PIX_FMT_JPEG,		.depth = 24	}, {		.name = "8bpp GREY",		.fourcc = V4L2_PIX_FMT_GREY,		.depth = 8	}};static int norm_maxw(struct video_device *vdev){	return (vdev->current_norm & V4L2_STD_NTSC) ?	    LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;}static int norm_maxh(struct video_device *vdev){	return (vdev->current_norm & V4L2_STD_NTSC) ?	    (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);}static int norm_minw(struct video_device *vdev){	return (vdev->current_norm & V4L2_STD_NTSC) ?	    LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;}static int norm_minh(struct video_device *vdev){	return (vdev->current_norm & V4L2_STD_NTSC) ?	    (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);}/* * TODO: fixme: move YUV reordering to hardware * converts 2255 planar format to yuyv or uyvy */static void planar422p_to_yuv_packed(const unsigned char *in,				     unsigned char *out,				     int width, int height,				     int fmt){	unsigned char *pY;	unsigned char *pCb;	unsigned char *pCr;	unsigned long size = height * width;	unsigned int i;	pY = (unsigned char *)in;	pCr = (unsigned char *)in + height * width;	pCb = (unsigned char *)in + height * width + (height * width / 2);	for (i = 0; i < size * 2; i += 4) {		out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;		out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;		out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;		out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;	}	return;}static void s2255_reset_dsppower(struct s2255_dev *dev)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?