xref: /openbmc/linux/drivers/media/usb/s2255/s2255drv.c (revision 0aa77f6c2954896b132f8b6f2e9f063c52800913)
1*0aa77f6cSMauro Carvalho Chehab /*
2*0aa77f6cSMauro Carvalho Chehab  *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device
3*0aa77f6cSMauro Carvalho Chehab  *
4*0aa77f6cSMauro Carvalho Chehab  *   Copyright (C) 2007-2010 by Sensoray Company Inc.
5*0aa77f6cSMauro Carvalho Chehab  *                              Dean Anderson
6*0aa77f6cSMauro Carvalho Chehab  *
7*0aa77f6cSMauro Carvalho Chehab  * Some video buffer code based on vivi driver:
8*0aa77f6cSMauro Carvalho Chehab  *
9*0aa77f6cSMauro Carvalho Chehab  * Sensoray 2255 device supports 4 simultaneous channels.
10*0aa77f6cSMauro Carvalho Chehab  * The channels are not "crossbar" inputs, they are physically
11*0aa77f6cSMauro Carvalho Chehab  * attached to separate video decoders.
12*0aa77f6cSMauro Carvalho Chehab  *
13*0aa77f6cSMauro Carvalho Chehab  * Because of USB2.0 bandwidth limitations. There is only a
14*0aa77f6cSMauro Carvalho Chehab  * certain amount of data which may be transferred at one time.
15*0aa77f6cSMauro Carvalho Chehab  *
16*0aa77f6cSMauro Carvalho Chehab  * Example maximum bandwidth utilization:
17*0aa77f6cSMauro Carvalho Chehab  *
18*0aa77f6cSMauro Carvalho Chehab  * -full size, color mode YUYV or YUV422P: 2 channels at once
19*0aa77f6cSMauro Carvalho Chehab  * -full or half size Grey scale: all 4 channels at once
20*0aa77f6cSMauro Carvalho Chehab  * -half size, color mode YUYV or YUV422P: all 4 channels at once
21*0aa77f6cSMauro Carvalho Chehab  * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
22*0aa77f6cSMauro Carvalho Chehab  *  at once.
23*0aa77f6cSMauro Carvalho Chehab  *
24*0aa77f6cSMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or modify
25*0aa77f6cSMauro Carvalho Chehab  * it under the terms of the GNU General Public License as published by
26*0aa77f6cSMauro Carvalho Chehab  * the Free Software Foundation; either version 2 of the License, or
27*0aa77f6cSMauro Carvalho Chehab  * (at your option) any later version.
28*0aa77f6cSMauro Carvalho Chehab  *
29*0aa77f6cSMauro Carvalho Chehab  * This program is distributed in the hope that it will be useful,
30*0aa77f6cSMauro Carvalho Chehab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31*0aa77f6cSMauro Carvalho Chehab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32*0aa77f6cSMauro Carvalho Chehab  * GNU General Public License for more details.
33*0aa77f6cSMauro Carvalho Chehab  *
34*0aa77f6cSMauro Carvalho Chehab  * You should have received a copy of the GNU General Public License
35*0aa77f6cSMauro Carvalho Chehab  * along with this program; if not, write to the Free Software
36*0aa77f6cSMauro Carvalho Chehab  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37*0aa77f6cSMauro Carvalho Chehab  */
38*0aa77f6cSMauro Carvalho Chehab 
39*0aa77f6cSMauro Carvalho Chehab #include <linux/module.h>
40*0aa77f6cSMauro Carvalho Chehab #include <linux/firmware.h>
41*0aa77f6cSMauro Carvalho Chehab #include <linux/kernel.h>
42*0aa77f6cSMauro Carvalho Chehab #include <linux/mutex.h>
43*0aa77f6cSMauro Carvalho Chehab #include <linux/slab.h>
44*0aa77f6cSMauro Carvalho Chehab #include <linux/videodev2.h>
45*0aa77f6cSMauro Carvalho Chehab #include <linux/mm.h>
46*0aa77f6cSMauro Carvalho Chehab #include <media/videobuf-vmalloc.h>
47*0aa77f6cSMauro Carvalho Chehab #include <media/v4l2-common.h>
48*0aa77f6cSMauro Carvalho Chehab #include <media/v4l2-device.h>
49*0aa77f6cSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
50*0aa77f6cSMauro Carvalho Chehab #include <linux/vmalloc.h>
51*0aa77f6cSMauro Carvalho Chehab #include <linux/usb.h>
52*0aa77f6cSMauro Carvalho Chehab 
53*0aa77f6cSMauro Carvalho Chehab #define S2255_VERSION		"1.22.1"
54*0aa77f6cSMauro Carvalho Chehab #define FIRMWARE_FILE_NAME "f2255usb.bin"
55*0aa77f6cSMauro Carvalho Chehab 
56*0aa77f6cSMauro Carvalho Chehab /* default JPEG quality */
57*0aa77f6cSMauro Carvalho Chehab #define S2255_DEF_JPEG_QUAL     50
58*0aa77f6cSMauro Carvalho Chehab /* vendor request in */
59*0aa77f6cSMauro Carvalho Chehab #define S2255_VR_IN		0
60*0aa77f6cSMauro Carvalho Chehab /* vendor request out */
61*0aa77f6cSMauro Carvalho Chehab #define S2255_VR_OUT		1
62*0aa77f6cSMauro Carvalho Chehab /* firmware query */
63*0aa77f6cSMauro Carvalho Chehab #define S2255_VR_FW		0x30
64*0aa77f6cSMauro Carvalho Chehab /* USB endpoint number for configuring the device */
65*0aa77f6cSMauro Carvalho Chehab #define S2255_CONFIG_EP         2
66*0aa77f6cSMauro Carvalho Chehab /* maximum time for DSP to start responding after last FW word loaded(ms) */
67*0aa77f6cSMauro Carvalho Chehab #define S2255_DSP_BOOTTIME      800
68*0aa77f6cSMauro Carvalho Chehab /* maximum time to wait for firmware to load (ms) */
69*0aa77f6cSMauro Carvalho Chehab #define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
70*0aa77f6cSMauro Carvalho Chehab #define S2255_DEF_BUFS          16
71*0aa77f6cSMauro Carvalho Chehab #define S2255_SETMODE_TIMEOUT   500
72*0aa77f6cSMauro Carvalho Chehab #define S2255_VIDSTATUS_TIMEOUT 350
73*0aa77f6cSMauro Carvalho Chehab #define S2255_MARKER_FRAME	cpu_to_le32(0x2255DA4AL)
74*0aa77f6cSMauro Carvalho Chehab #define S2255_MARKER_RESPONSE	cpu_to_le32(0x2255ACACL)
75*0aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_SETMODE  cpu_to_le32(0x01)
76*0aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_FW       cpu_to_le32(0x10)
77*0aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_STATUS   cpu_to_le32(0x20)
78*0aa77f6cSMauro Carvalho Chehab #define S2255_USB_XFER_SIZE	(16 * 1024)
79*0aa77f6cSMauro Carvalho Chehab #define MAX_CHANNELS		4
80*0aa77f6cSMauro Carvalho Chehab #define SYS_FRAMES		4
81*0aa77f6cSMauro Carvalho Chehab /* maximum size is PAL full size plus room for the marker header(s) */
82*0aa77f6cSMauro Carvalho Chehab #define SYS_FRAMES_MAXSIZE	(720*288*2*2 + 4096)
83*0aa77f6cSMauro Carvalho Chehab #define DEF_USB_BLOCK		S2255_USB_XFER_SIZE
84*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_4CIFS_NTSC	640
85*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_2CIFS_NTSC	640
86*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_1CIFS_NTSC	320
87*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_4CIFS_PAL	704
88*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_2CIFS_PAL	704
89*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_1CIFS_PAL	352
90*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_4CIFS_NTSC	240
91*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_2CIFS_NTSC	240
92*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_1CIFS_NTSC	240
93*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_4CIFS_PAL	288
94*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_2CIFS_PAL	288
95*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_1CIFS_PAL	288
96*0aa77f6cSMauro Carvalho Chehab #define LINE_SZ_DEF		640
97*0aa77f6cSMauro Carvalho Chehab #define NUM_LINES_DEF		240
98*0aa77f6cSMauro Carvalho Chehab 
99*0aa77f6cSMauro Carvalho Chehab 
100*0aa77f6cSMauro Carvalho Chehab /* predefined settings */
101*0aa77f6cSMauro Carvalho Chehab #define FORMAT_NTSC	1
102*0aa77f6cSMauro Carvalho Chehab #define FORMAT_PAL	2
103*0aa77f6cSMauro Carvalho Chehab 
104*0aa77f6cSMauro Carvalho Chehab #define SCALE_4CIFS	1	/* 640x480(NTSC) or 704x576(PAL) */
105*0aa77f6cSMauro Carvalho Chehab #define SCALE_2CIFS	2	/* 640x240(NTSC) or 704x288(PAL) */
106*0aa77f6cSMauro Carvalho Chehab #define SCALE_1CIFS	3	/* 320x240(NTSC) or 352x288(PAL) */
107*0aa77f6cSMauro Carvalho Chehab /* SCALE_4CIFSI is the 2 fields interpolated into one */
108*0aa77f6cSMauro Carvalho Chehab #define SCALE_4CIFSI	4	/* 640x480(NTSC) or 704x576(PAL) high quality */
109*0aa77f6cSMauro Carvalho Chehab 
110*0aa77f6cSMauro Carvalho Chehab #define COLOR_YUVPL	1	/* YUV planar */
111*0aa77f6cSMauro Carvalho Chehab #define COLOR_YUVPK	2	/* YUV packed */
112*0aa77f6cSMauro Carvalho Chehab #define COLOR_Y8	4	/* monochrome */
113*0aa77f6cSMauro Carvalho Chehab #define COLOR_JPG       5       /* JPEG */
114*0aa77f6cSMauro Carvalho Chehab 
115*0aa77f6cSMauro Carvalho Chehab #define MASK_COLOR       0x000000ff
116*0aa77f6cSMauro Carvalho Chehab #define MASK_JPG_QUALITY 0x0000ff00
117*0aa77f6cSMauro Carvalho Chehab #define MASK_INPUT_TYPE  0x000f0000
118*0aa77f6cSMauro Carvalho Chehab /* frame decimation. */
119*0aa77f6cSMauro Carvalho Chehab #define FDEC_1		1	/* capture every frame. default */
120*0aa77f6cSMauro Carvalho Chehab #define FDEC_2		2	/* capture every 2nd frame */
121*0aa77f6cSMauro Carvalho Chehab #define FDEC_3		3	/* capture every 3rd frame */
122*0aa77f6cSMauro Carvalho Chehab #define FDEC_5		5	/* capture every 5th frame */
123*0aa77f6cSMauro Carvalho Chehab 
124*0aa77f6cSMauro Carvalho Chehab /*-------------------------------------------------------
125*0aa77f6cSMauro Carvalho Chehab  * Default mode parameters.
126*0aa77f6cSMauro Carvalho Chehab  *-------------------------------------------------------*/
127*0aa77f6cSMauro Carvalho Chehab #define DEF_SCALE	SCALE_4CIFS
128*0aa77f6cSMauro Carvalho Chehab #define DEF_COLOR	COLOR_YUVPL
129*0aa77f6cSMauro Carvalho Chehab #define DEF_FDEC	FDEC_1
130*0aa77f6cSMauro Carvalho Chehab #define DEF_BRIGHT	0
131*0aa77f6cSMauro Carvalho Chehab #define DEF_CONTRAST	0x5c
132*0aa77f6cSMauro Carvalho Chehab #define DEF_SATURATION	0x80
133*0aa77f6cSMauro Carvalho Chehab #define DEF_HUE		0
134*0aa77f6cSMauro Carvalho Chehab 
135*0aa77f6cSMauro Carvalho Chehab /* usb config commands */
136*0aa77f6cSMauro Carvalho Chehab #define IN_DATA_TOKEN	cpu_to_le32(0x2255c0de)
137*0aa77f6cSMauro Carvalho Chehab #define CMD_2255	0xc2255000
138*0aa77f6cSMauro Carvalho Chehab #define CMD_SET_MODE	cpu_to_le32((CMD_2255 | 0x10))
139*0aa77f6cSMauro Carvalho Chehab #define CMD_START	cpu_to_le32((CMD_2255 | 0x20))
140*0aa77f6cSMauro Carvalho Chehab #define CMD_STOP	cpu_to_le32((CMD_2255 | 0x30))
141*0aa77f6cSMauro Carvalho Chehab #define CMD_STATUS	cpu_to_le32((CMD_2255 | 0x40))
142*0aa77f6cSMauro Carvalho Chehab 
143*0aa77f6cSMauro Carvalho Chehab struct s2255_mode {
144*0aa77f6cSMauro Carvalho Chehab 	u32 format;	/* input video format (NTSC, PAL) */
145*0aa77f6cSMauro Carvalho Chehab 	u32 scale;	/* output video scale */
146*0aa77f6cSMauro Carvalho Chehab 	u32 color;	/* output video color format */
147*0aa77f6cSMauro Carvalho Chehab 	u32 fdec;	/* frame decimation */
148*0aa77f6cSMauro Carvalho Chehab 	u32 bright;	/* brightness */
149*0aa77f6cSMauro Carvalho Chehab 	u32 contrast;	/* contrast */
150*0aa77f6cSMauro Carvalho Chehab 	u32 saturation;	/* saturation */
151*0aa77f6cSMauro Carvalho Chehab 	u32 hue;	/* hue (NTSC only)*/
152*0aa77f6cSMauro Carvalho Chehab 	u32 single;	/* capture 1 frame at a time (!=0), continuously (==0)*/
153*0aa77f6cSMauro Carvalho Chehab 	u32 usb_block;	/* block size. should be 4096 of DEF_USB_BLOCK */
154*0aa77f6cSMauro Carvalho Chehab 	u32 restart;	/* if DSP requires restart */
155*0aa77f6cSMauro Carvalho Chehab };
156*0aa77f6cSMauro Carvalho Chehab 
157*0aa77f6cSMauro Carvalho Chehab 
158*0aa77f6cSMauro Carvalho Chehab #define S2255_READ_IDLE		0
159*0aa77f6cSMauro Carvalho Chehab #define S2255_READ_FRAME	1
160*0aa77f6cSMauro Carvalho Chehab 
161*0aa77f6cSMauro Carvalho Chehab /* frame structure */
162*0aa77f6cSMauro Carvalho Chehab struct s2255_framei {
163*0aa77f6cSMauro Carvalho Chehab 	unsigned long size;
164*0aa77f6cSMauro Carvalho Chehab 	unsigned long ulState;	/* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
165*0aa77f6cSMauro Carvalho Chehab 	void *lpvbits;		/* image data */
166*0aa77f6cSMauro Carvalho Chehab 	unsigned long cur_size;	/* current data copied to it */
167*0aa77f6cSMauro Carvalho Chehab };
168*0aa77f6cSMauro Carvalho Chehab 
169*0aa77f6cSMauro Carvalho Chehab /* image buffer structure */
170*0aa77f6cSMauro Carvalho Chehab struct s2255_bufferi {
171*0aa77f6cSMauro Carvalho Chehab 	unsigned long dwFrames;			/* number of frames in buffer */
172*0aa77f6cSMauro Carvalho Chehab 	struct s2255_framei frame[SYS_FRAMES];	/* array of FRAME structures */
173*0aa77f6cSMauro Carvalho Chehab };
174*0aa77f6cSMauro Carvalho Chehab 
175*0aa77f6cSMauro Carvalho Chehab #define DEF_MODEI_NTSC_CONT	{FORMAT_NTSC, DEF_SCALE, DEF_COLOR,	\
176*0aa77f6cSMauro Carvalho Chehab 			DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
177*0aa77f6cSMauro Carvalho Chehab 			DEF_HUE, 0, DEF_USB_BLOCK, 0}
178*0aa77f6cSMauro Carvalho Chehab 
179*0aa77f6cSMauro Carvalho Chehab struct s2255_dmaqueue {
180*0aa77f6cSMauro Carvalho Chehab 	struct list_head	active;
181*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev	*dev;
182*0aa77f6cSMauro Carvalho Chehab };
183*0aa77f6cSMauro Carvalho Chehab 
184*0aa77f6cSMauro Carvalho Chehab /* for firmware loading, fw_state */
185*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_NOTLOADED	0
186*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_LOADED_DSPWAIT	1
187*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_SUCCESS	2
188*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_FAILED		3
189*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_DISCONNECTING  4
190*0aa77f6cSMauro Carvalho Chehab #define S2255_FW_MARKER		cpu_to_le32(0x22552f2f)
191*0aa77f6cSMauro Carvalho Chehab /* 2255 read states */
192*0aa77f6cSMauro Carvalho Chehab #define S2255_READ_IDLE         0
193*0aa77f6cSMauro Carvalho Chehab #define S2255_READ_FRAME        1
194*0aa77f6cSMauro Carvalho Chehab struct s2255_fw {
195*0aa77f6cSMauro Carvalho Chehab 	int		      fw_loaded;
196*0aa77f6cSMauro Carvalho Chehab 	int		      fw_size;
197*0aa77f6cSMauro Carvalho Chehab 	struct urb	      *fw_urb;
198*0aa77f6cSMauro Carvalho Chehab 	atomic_t	      fw_state;
199*0aa77f6cSMauro Carvalho Chehab 	void		      *pfw_data;
200*0aa77f6cSMauro Carvalho Chehab 	wait_queue_head_t     wait_fw;
201*0aa77f6cSMauro Carvalho Chehab 	const struct firmware *fw;
202*0aa77f6cSMauro Carvalho Chehab };
203*0aa77f6cSMauro Carvalho Chehab 
204*0aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo {
205*0aa77f6cSMauro Carvalho Chehab 	u32 max_transfer_size;
206*0aa77f6cSMauro Carvalho Chehab 	u32 cur_transfer_size;
207*0aa77f6cSMauro Carvalho Chehab 	u8 *transfer_buffer;
208*0aa77f6cSMauro Carvalho Chehab 	u32 state;
209*0aa77f6cSMauro Carvalho Chehab 	void *stream_urb;
210*0aa77f6cSMauro Carvalho Chehab 	void *dev;	/* back pointer to s2255_dev struct*/
211*0aa77f6cSMauro Carvalho Chehab 	u32 err_count;
212*0aa77f6cSMauro Carvalho Chehab 	u32 idx;
213*0aa77f6cSMauro Carvalho Chehab };
214*0aa77f6cSMauro Carvalho Chehab 
215*0aa77f6cSMauro Carvalho Chehab struct s2255_fmt; /*forward declaration */
216*0aa77f6cSMauro Carvalho Chehab struct s2255_dev;
217*0aa77f6cSMauro Carvalho Chehab 
218*0aa77f6cSMauro Carvalho Chehab struct s2255_channel {
219*0aa77f6cSMauro Carvalho Chehab 	struct video_device	vdev;
220*0aa77f6cSMauro Carvalho Chehab 	int			resources;
221*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dmaqueue	vidq;
222*0aa77f6cSMauro Carvalho Chehab 	struct s2255_bufferi	buffer;
223*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode	mode;
224*0aa77f6cSMauro Carvalho Chehab 	/* jpeg compression */
225*0aa77f6cSMauro Carvalho Chehab 	struct v4l2_jpegcompression jc;
226*0aa77f6cSMauro Carvalho Chehab 	/* capture parameters (for high quality mode full size) */
227*0aa77f6cSMauro Carvalho Chehab 	struct v4l2_captureparm cap_parm;
228*0aa77f6cSMauro Carvalho Chehab 	int			cur_frame;
229*0aa77f6cSMauro Carvalho Chehab 	int			last_frame;
230*0aa77f6cSMauro Carvalho Chehab 
231*0aa77f6cSMauro Carvalho Chehab 	int			b_acquire;
232*0aa77f6cSMauro Carvalho Chehab 	/* allocated image size */
233*0aa77f6cSMauro Carvalho Chehab 	unsigned long		req_image_size;
234*0aa77f6cSMauro Carvalho Chehab 	/* received packet size */
235*0aa77f6cSMauro Carvalho Chehab 	unsigned long		pkt_size;
236*0aa77f6cSMauro Carvalho Chehab 	int			bad_payload;
237*0aa77f6cSMauro Carvalho Chehab 	unsigned long		frame_count;
238*0aa77f6cSMauro Carvalho Chehab 	/* if JPEG image */
239*0aa77f6cSMauro Carvalho Chehab 	int                     jpg_size;
240*0aa77f6cSMauro Carvalho Chehab 	/* if channel configured to default state */
241*0aa77f6cSMauro Carvalho Chehab 	int                     configured;
242*0aa77f6cSMauro Carvalho Chehab 	wait_queue_head_t       wait_setmode;
243*0aa77f6cSMauro Carvalho Chehab 	int                     setmode_ready;
244*0aa77f6cSMauro Carvalho Chehab 	/* video status items */
245*0aa77f6cSMauro Carvalho Chehab 	int                     vidstatus;
246*0aa77f6cSMauro Carvalho Chehab 	wait_queue_head_t       wait_vidstatus;
247*0aa77f6cSMauro Carvalho Chehab 	int                     vidstatus_ready;
248*0aa77f6cSMauro Carvalho Chehab 	unsigned int		width;
249*0aa77f6cSMauro Carvalho Chehab 	unsigned int		height;
250*0aa77f6cSMauro Carvalho Chehab 	const struct s2255_fmt	*fmt;
251*0aa77f6cSMauro Carvalho Chehab 	int idx; /* channel number on device, 0-3 */
252*0aa77f6cSMauro Carvalho Chehab };
253*0aa77f6cSMauro Carvalho Chehab 
254*0aa77f6cSMauro Carvalho Chehab 
255*0aa77f6cSMauro Carvalho Chehab struct s2255_dev {
256*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel    channel[MAX_CHANNELS];
257*0aa77f6cSMauro Carvalho Chehab 	struct v4l2_device 	v4l2_dev;
258*0aa77f6cSMauro Carvalho Chehab 	atomic_t                num_channels;
259*0aa77f6cSMauro Carvalho Chehab 	int			frames;
260*0aa77f6cSMauro Carvalho Chehab 	struct mutex		lock;	/* channels[].vdev.lock */
261*0aa77f6cSMauro Carvalho Chehab 	struct usb_device	*udev;
262*0aa77f6cSMauro Carvalho Chehab 	struct usb_interface	*interface;
263*0aa77f6cSMauro Carvalho Chehab 	u8			read_endpoint;
264*0aa77f6cSMauro Carvalho Chehab 	struct timer_list	timer;
265*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fw	*fw_data;
266*0aa77f6cSMauro Carvalho Chehab 	struct s2255_pipeinfo	pipe;
267*0aa77f6cSMauro Carvalho Chehab 	u32			cc;	/* current channel */
268*0aa77f6cSMauro Carvalho Chehab 	int			frame_ready;
269*0aa77f6cSMauro Carvalho Chehab 	int                     chn_ready;
270*0aa77f6cSMauro Carvalho Chehab 	spinlock_t              slock;
271*0aa77f6cSMauro Carvalho Chehab 	/* dsp firmware version (f2255usb.bin) */
272*0aa77f6cSMauro Carvalho Chehab 	int                     dsp_fw_ver;
273*0aa77f6cSMauro Carvalho Chehab 	u16                     pid; /* product id */
274*0aa77f6cSMauro Carvalho Chehab };
275*0aa77f6cSMauro Carvalho Chehab 
276*0aa77f6cSMauro Carvalho Chehab static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
277*0aa77f6cSMauro Carvalho Chehab {
278*0aa77f6cSMauro Carvalho Chehab 	return container_of(v4l2_dev, struct s2255_dev, v4l2_dev);
279*0aa77f6cSMauro Carvalho Chehab }
280*0aa77f6cSMauro Carvalho Chehab 
281*0aa77f6cSMauro Carvalho Chehab struct s2255_fmt {
282*0aa77f6cSMauro Carvalho Chehab 	char *name;
283*0aa77f6cSMauro Carvalho Chehab 	u32 fourcc;
284*0aa77f6cSMauro Carvalho Chehab 	int depth;
285*0aa77f6cSMauro Carvalho Chehab };
286*0aa77f6cSMauro Carvalho Chehab 
287*0aa77f6cSMauro Carvalho Chehab /* buffer for one video frame */
288*0aa77f6cSMauro Carvalho Chehab struct s2255_buffer {
289*0aa77f6cSMauro Carvalho Chehab 	/* common v4l buffer stuff -- must be first */
290*0aa77f6cSMauro Carvalho Chehab 	struct videobuf_buffer vb;
291*0aa77f6cSMauro Carvalho Chehab 	const struct s2255_fmt *fmt;
292*0aa77f6cSMauro Carvalho Chehab };
293*0aa77f6cSMauro Carvalho Chehab 
294*0aa77f6cSMauro Carvalho Chehab struct s2255_fh {
295*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev	*dev;
296*0aa77f6cSMauro Carvalho Chehab 	struct videobuf_queue	vb_vidq;
297*0aa77f6cSMauro Carvalho Chehab 	enum v4l2_buf_type	type;
298*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel	*channel;
299*0aa77f6cSMauro Carvalho Chehab 	int			resources;
300*0aa77f6cSMauro Carvalho Chehab };
301*0aa77f6cSMauro Carvalho Chehab 
302*0aa77f6cSMauro Carvalho Chehab /* current cypress EEPROM firmware version */
303*0aa77f6cSMauro Carvalho Chehab #define S2255_CUR_USB_FWVER	((3 << 8) | 12)
304*0aa77f6cSMauro Carvalho Chehab /* current DSP FW version */
305*0aa77f6cSMauro Carvalho Chehab #define S2255_CUR_DSP_FWVER     10104
306*0aa77f6cSMauro Carvalho Chehab /* Need DSP version 5+ for video status feature */
307*0aa77f6cSMauro Carvalho Chehab #define S2255_MIN_DSP_STATUS      5
308*0aa77f6cSMauro Carvalho Chehab #define S2255_MIN_DSP_COLORFILTER 8
309*0aa77f6cSMauro Carvalho Chehab #define S2255_NORMS		(V4L2_STD_PAL | V4L2_STD_NTSC)
310*0aa77f6cSMauro Carvalho Chehab 
311*0aa77f6cSMauro Carvalho Chehab /* private V4L2 controls */
312*0aa77f6cSMauro Carvalho Chehab 
313*0aa77f6cSMauro Carvalho Chehab /*
314*0aa77f6cSMauro Carvalho Chehab  * The following chart displays how COLORFILTER should be set
315*0aa77f6cSMauro Carvalho Chehab  *  =========================================================
316*0aa77f6cSMauro Carvalho Chehab  *  =     fourcc              =     COLORFILTER             =
317*0aa77f6cSMauro Carvalho Chehab  *  =                         ===============================
318*0aa77f6cSMauro Carvalho Chehab  *  =                         =   0             =    1      =
319*0aa77f6cSMauro Carvalho Chehab  *  =========================================================
320*0aa77f6cSMauro Carvalho Chehab  *  =  V4L2_PIX_FMT_GREY(Y8)  = monochrome from = monochrome=
321*0aa77f6cSMauro Carvalho Chehab  *  =                         = s-video or      = composite =
322*0aa77f6cSMauro Carvalho Chehab  *  =                         = B/W camera      = input     =
323*0aa77f6cSMauro Carvalho Chehab  *  =========================================================
324*0aa77f6cSMauro Carvalho Chehab  *  =    other                = color, svideo   = color,    =
325*0aa77f6cSMauro Carvalho Chehab  *  =                         =                 = composite =
326*0aa77f6cSMauro Carvalho Chehab  *  =========================================================
327*0aa77f6cSMauro Carvalho Chehab  *
328*0aa77f6cSMauro Carvalho Chehab  * Notes:
329*0aa77f6cSMauro Carvalho Chehab  *   channels 0-3 on 2255 are composite
330*0aa77f6cSMauro Carvalho Chehab  *   channels 0-1 on 2257 are composite, 2-3 are s-video
331*0aa77f6cSMauro Carvalho Chehab  * If COLORFILTER is 0 with a composite color camera connected,
332*0aa77f6cSMauro Carvalho Chehab  * the output will appear monochrome but hatching
333*0aa77f6cSMauro Carvalho Chehab  * will occur.
334*0aa77f6cSMauro Carvalho Chehab  * COLORFILTER is different from "color killer" and "color effects"
335*0aa77f6cSMauro Carvalho Chehab  * for reasons above.
336*0aa77f6cSMauro Carvalho Chehab  */
337*0aa77f6cSMauro Carvalho Chehab #define S2255_V4L2_YC_ON  1
338*0aa77f6cSMauro Carvalho Chehab #define S2255_V4L2_YC_OFF 0
339*0aa77f6cSMauro Carvalho Chehab #define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0)
340*0aa77f6cSMauro Carvalho Chehab 
341*0aa77f6cSMauro Carvalho Chehab /* frame prefix size (sent once every frame) */
342*0aa77f6cSMauro Carvalho Chehab #define PREFIX_SIZE		512
343*0aa77f6cSMauro Carvalho Chehab 
344*0aa77f6cSMauro Carvalho Chehab /* Channels on box are in reverse order */
345*0aa77f6cSMauro Carvalho Chehab static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
346*0aa77f6cSMauro Carvalho Chehab 
347*0aa77f6cSMauro Carvalho Chehab static int debug;
348*0aa77f6cSMauro Carvalho Chehab static int *s2255_debug = &debug;
349*0aa77f6cSMauro Carvalho Chehab 
350*0aa77f6cSMauro Carvalho Chehab static int s2255_start_readpipe(struct s2255_dev *dev);
351*0aa77f6cSMauro Carvalho Chehab static void s2255_stop_readpipe(struct s2255_dev *dev);
352*0aa77f6cSMauro Carvalho Chehab static int s2255_start_acquire(struct s2255_channel *channel);
353*0aa77f6cSMauro Carvalho Chehab static int s2255_stop_acquire(struct s2255_channel *channel);
354*0aa77f6cSMauro Carvalho Chehab static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
355*0aa77f6cSMauro Carvalho Chehab 			   int jpgsize);
356*0aa77f6cSMauro Carvalho Chehab static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
357*0aa77f6cSMauro Carvalho Chehab static int s2255_board_shutdown(struct s2255_dev *dev);
358*0aa77f6cSMauro Carvalho Chehab static void s2255_fwload_start(struct s2255_dev *dev, int reset);
359*0aa77f6cSMauro Carvalho Chehab static void s2255_destroy(struct s2255_dev *dev);
360*0aa77f6cSMauro Carvalho Chehab static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
361*0aa77f6cSMauro Carvalho Chehab 			     u16 index, u16 value, void *buf,
362*0aa77f6cSMauro Carvalho Chehab 			     s32 buf_len, int bOut);
363*0aa77f6cSMauro Carvalho Chehab 
364*0aa77f6cSMauro Carvalho Chehab /* dev_err macro with driver name */
365*0aa77f6cSMauro Carvalho Chehab #define S2255_DRIVER_NAME "s2255"
366*0aa77f6cSMauro Carvalho Chehab #define s2255_dev_err(dev, fmt, arg...)					\
367*0aa77f6cSMauro Carvalho Chehab 		dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
368*0aa77f6cSMauro Carvalho Chehab 
369*0aa77f6cSMauro Carvalho Chehab #define dprintk(level, fmt, arg...)					\
370*0aa77f6cSMauro Carvalho Chehab 	do {								\
371*0aa77f6cSMauro Carvalho Chehab 		if (*s2255_debug >= (level)) {				\
372*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_DEBUG S2255_DRIVER_NAME		\
373*0aa77f6cSMauro Carvalho Chehab 				": " fmt, ##arg);			\
374*0aa77f6cSMauro Carvalho Chehab 		}							\
375*0aa77f6cSMauro Carvalho Chehab 	} while (0)
376*0aa77f6cSMauro Carvalho Chehab 
377*0aa77f6cSMauro Carvalho Chehab static struct usb_driver s2255_driver;
378*0aa77f6cSMauro Carvalho Chehab 
379*0aa77f6cSMauro Carvalho Chehab /* Declare static vars that will be used as parameters */
380*0aa77f6cSMauro Carvalho Chehab static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
381*0aa77f6cSMauro Carvalho Chehab 
382*0aa77f6cSMauro Carvalho Chehab /* start video number */
383*0aa77f6cSMauro Carvalho Chehab static int video_nr = -1;	/* /dev/videoN, -1 for autodetect */
384*0aa77f6cSMauro Carvalho Chehab 
385*0aa77f6cSMauro Carvalho Chehab /* Enable jpeg capture. */
386*0aa77f6cSMauro Carvalho Chehab static int jpeg_enable = 1;
387*0aa77f6cSMauro Carvalho Chehab 
388*0aa77f6cSMauro Carvalho Chehab module_param(debug, int, 0644);
389*0aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
390*0aa77f6cSMauro Carvalho Chehab module_param(vid_limit, int, 0644);
391*0aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
392*0aa77f6cSMauro Carvalho Chehab module_param(video_nr, int, 0644);
393*0aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
394*0aa77f6cSMauro Carvalho Chehab module_param(jpeg_enable, int, 0644);
395*0aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
396*0aa77f6cSMauro Carvalho Chehab 
397*0aa77f6cSMauro Carvalho Chehab /* USB device table */
398*0aa77f6cSMauro Carvalho Chehab #define USB_SENSORAY_VID	0x1943
399*0aa77f6cSMauro Carvalho Chehab static struct usb_device_id s2255_table[] = {
400*0aa77f6cSMauro Carvalho Chehab 	{USB_DEVICE(USB_SENSORAY_VID, 0x2255)},
401*0aa77f6cSMauro Carvalho Chehab 	{USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/
402*0aa77f6cSMauro Carvalho Chehab 	{ }			/* Terminating entry */
403*0aa77f6cSMauro Carvalho Chehab };
404*0aa77f6cSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, s2255_table);
405*0aa77f6cSMauro Carvalho Chehab 
406*0aa77f6cSMauro Carvalho Chehab #define BUFFER_TIMEOUT msecs_to_jiffies(400)
407*0aa77f6cSMauro Carvalho Chehab 
408*0aa77f6cSMauro Carvalho Chehab /* image formats.  */
409*0aa77f6cSMauro Carvalho Chehab /* JPEG formats must be defined last to support jpeg_enable parameter */
410*0aa77f6cSMauro Carvalho Chehab static const struct s2255_fmt formats[] = {
411*0aa77f6cSMauro Carvalho Chehab 	{
412*0aa77f6cSMauro Carvalho Chehab 		.name = "4:2:2, planar, YUV422P",
413*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_YUV422P,
414*0aa77f6cSMauro Carvalho Chehab 		.depth = 16
415*0aa77f6cSMauro Carvalho Chehab 
416*0aa77f6cSMauro Carvalho Chehab 	}, {
417*0aa77f6cSMauro Carvalho Chehab 		.name = "4:2:2, packed, YUYV",
418*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_YUYV,
419*0aa77f6cSMauro Carvalho Chehab 		.depth = 16
420*0aa77f6cSMauro Carvalho Chehab 
421*0aa77f6cSMauro Carvalho Chehab 	}, {
422*0aa77f6cSMauro Carvalho Chehab 		.name = "4:2:2, packed, UYVY",
423*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_UYVY,
424*0aa77f6cSMauro Carvalho Chehab 		.depth = 16
425*0aa77f6cSMauro Carvalho Chehab 	}, {
426*0aa77f6cSMauro Carvalho Chehab 		.name = "8bpp GREY",
427*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_GREY,
428*0aa77f6cSMauro Carvalho Chehab 		.depth = 8
429*0aa77f6cSMauro Carvalho Chehab 	}, {
430*0aa77f6cSMauro Carvalho Chehab 		.name = "JPG",
431*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_JPEG,
432*0aa77f6cSMauro Carvalho Chehab 		.depth = 24
433*0aa77f6cSMauro Carvalho Chehab 	}, {
434*0aa77f6cSMauro Carvalho Chehab 		.name = "MJPG",
435*0aa77f6cSMauro Carvalho Chehab 		.fourcc = V4L2_PIX_FMT_MJPEG,
436*0aa77f6cSMauro Carvalho Chehab 		.depth = 24
437*0aa77f6cSMauro Carvalho Chehab 	}
438*0aa77f6cSMauro Carvalho Chehab };
439*0aa77f6cSMauro Carvalho Chehab 
440*0aa77f6cSMauro Carvalho Chehab static int norm_maxw(struct video_device *vdev)
441*0aa77f6cSMauro Carvalho Chehab {
442*0aa77f6cSMauro Carvalho Chehab 	return (vdev->current_norm & V4L2_STD_NTSC) ?
443*0aa77f6cSMauro Carvalho Chehab 	    LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
444*0aa77f6cSMauro Carvalho Chehab }
445*0aa77f6cSMauro Carvalho Chehab 
446*0aa77f6cSMauro Carvalho Chehab static int norm_maxh(struct video_device *vdev)
447*0aa77f6cSMauro Carvalho Chehab {
448*0aa77f6cSMauro Carvalho Chehab 	return (vdev->current_norm & V4L2_STD_NTSC) ?
449*0aa77f6cSMauro Carvalho Chehab 	    (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
450*0aa77f6cSMauro Carvalho Chehab }
451*0aa77f6cSMauro Carvalho Chehab 
452*0aa77f6cSMauro Carvalho Chehab static int norm_minw(struct video_device *vdev)
453*0aa77f6cSMauro Carvalho Chehab {
454*0aa77f6cSMauro Carvalho Chehab 	return (vdev->current_norm & V4L2_STD_NTSC) ?
455*0aa77f6cSMauro Carvalho Chehab 	    LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
456*0aa77f6cSMauro Carvalho Chehab }
457*0aa77f6cSMauro Carvalho Chehab 
458*0aa77f6cSMauro Carvalho Chehab static int norm_minh(struct video_device *vdev)
459*0aa77f6cSMauro Carvalho Chehab {
460*0aa77f6cSMauro Carvalho Chehab 	return (vdev->current_norm & V4L2_STD_NTSC) ?
461*0aa77f6cSMauro Carvalho Chehab 	    (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
462*0aa77f6cSMauro Carvalho Chehab }
463*0aa77f6cSMauro Carvalho Chehab 
464*0aa77f6cSMauro Carvalho Chehab 
465*0aa77f6cSMauro Carvalho Chehab /*
466*0aa77f6cSMauro Carvalho Chehab  * TODO: fixme: move YUV reordering to hardware
467*0aa77f6cSMauro Carvalho Chehab  * converts 2255 planar format to yuyv or uyvy
468*0aa77f6cSMauro Carvalho Chehab  */
469*0aa77f6cSMauro Carvalho Chehab static void planar422p_to_yuv_packed(const unsigned char *in,
470*0aa77f6cSMauro Carvalho Chehab 				     unsigned char *out,
471*0aa77f6cSMauro Carvalho Chehab 				     int width, int height,
472*0aa77f6cSMauro Carvalho Chehab 				     int fmt)
473*0aa77f6cSMauro Carvalho Chehab {
474*0aa77f6cSMauro Carvalho Chehab 	unsigned char *pY;
475*0aa77f6cSMauro Carvalho Chehab 	unsigned char *pCb;
476*0aa77f6cSMauro Carvalho Chehab 	unsigned char *pCr;
477*0aa77f6cSMauro Carvalho Chehab 	unsigned long size = height * width;
478*0aa77f6cSMauro Carvalho Chehab 	unsigned int i;
479*0aa77f6cSMauro Carvalho Chehab 	pY = (unsigned char *)in;
480*0aa77f6cSMauro Carvalho Chehab 	pCr = (unsigned char *)in + height * width;
481*0aa77f6cSMauro Carvalho Chehab 	pCb = (unsigned char *)in + height * width + (height * width / 2);
482*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < size * 2; i += 4) {
483*0aa77f6cSMauro Carvalho Chehab 		out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;
484*0aa77f6cSMauro Carvalho Chehab 		out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;
485*0aa77f6cSMauro Carvalho Chehab 		out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;
486*0aa77f6cSMauro Carvalho Chehab 		out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;
487*0aa77f6cSMauro Carvalho Chehab 	}
488*0aa77f6cSMauro Carvalho Chehab 	return;
489*0aa77f6cSMauro Carvalho Chehab }
490*0aa77f6cSMauro Carvalho Chehab 
491*0aa77f6cSMauro Carvalho Chehab static void s2255_reset_dsppower(struct s2255_dev *dev)
492*0aa77f6cSMauro Carvalho Chehab {
493*0aa77f6cSMauro Carvalho Chehab 	s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
494*0aa77f6cSMauro Carvalho Chehab 	msleep(10);
495*0aa77f6cSMauro Carvalho Chehab 	s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
496*0aa77f6cSMauro Carvalho Chehab 	msleep(600);
497*0aa77f6cSMauro Carvalho Chehab 	s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
498*0aa77f6cSMauro Carvalho Chehab 	return;
499*0aa77f6cSMauro Carvalho Chehab }
500*0aa77f6cSMauro Carvalho Chehab 
501*0aa77f6cSMauro Carvalho Chehab /* kickstarts the firmware loading. from probe
502*0aa77f6cSMauro Carvalho Chehab  */
503*0aa77f6cSMauro Carvalho Chehab static void s2255_timer(unsigned long user_data)
504*0aa77f6cSMauro Carvalho Chehab {
505*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fw *data = (struct s2255_fw *)user_data;
506*0aa77f6cSMauro Carvalho Chehab 	dprintk(100, "%s\n", __func__);
507*0aa77f6cSMauro Carvalho Chehab 	if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
508*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "s2255: can't submit urb\n");
509*0aa77f6cSMauro Carvalho Chehab 		atomic_set(&data->fw_state, S2255_FW_FAILED);
510*0aa77f6cSMauro Carvalho Chehab 		/* wake up anything waiting for the firmware */
511*0aa77f6cSMauro Carvalho Chehab 		wake_up(&data->wait_fw);
512*0aa77f6cSMauro Carvalho Chehab 		return;
513*0aa77f6cSMauro Carvalho Chehab 	}
514*0aa77f6cSMauro Carvalho Chehab }
515*0aa77f6cSMauro Carvalho Chehab 
516*0aa77f6cSMauro Carvalho Chehab 
517*0aa77f6cSMauro Carvalho Chehab /* this loads the firmware asynchronously.
518*0aa77f6cSMauro Carvalho Chehab    Originally this was done synchroously in probe.
519*0aa77f6cSMauro Carvalho Chehab    But it is better to load it asynchronously here than block
520*0aa77f6cSMauro Carvalho Chehab    inside the probe function. Blocking inside probe affects boot time.
521*0aa77f6cSMauro Carvalho Chehab    FW loading is triggered by the timer in the probe function
522*0aa77f6cSMauro Carvalho Chehab */
523*0aa77f6cSMauro Carvalho Chehab static void s2255_fwchunk_complete(struct urb *urb)
524*0aa77f6cSMauro Carvalho Chehab {
525*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fw *data = urb->context;
526*0aa77f6cSMauro Carvalho Chehab 	struct usb_device *udev = urb->dev;
527*0aa77f6cSMauro Carvalho Chehab 	int len;
528*0aa77f6cSMauro Carvalho Chehab 	dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
529*0aa77f6cSMauro Carvalho Chehab 	if (urb->status) {
530*0aa77f6cSMauro Carvalho Chehab 		dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
531*0aa77f6cSMauro Carvalho Chehab 		atomic_set(&data->fw_state, S2255_FW_FAILED);
532*0aa77f6cSMauro Carvalho Chehab 		/* wake up anything waiting for the firmware */
533*0aa77f6cSMauro Carvalho Chehab 		wake_up(&data->wait_fw);
534*0aa77f6cSMauro Carvalho Chehab 		return;
535*0aa77f6cSMauro Carvalho Chehab 	}
536*0aa77f6cSMauro Carvalho Chehab 	if (data->fw_urb == NULL) {
537*0aa77f6cSMauro Carvalho Chehab 		s2255_dev_err(&udev->dev, "disconnected\n");
538*0aa77f6cSMauro Carvalho Chehab 		atomic_set(&data->fw_state, S2255_FW_FAILED);
539*0aa77f6cSMauro Carvalho Chehab 		/* wake up anything waiting for the firmware */
540*0aa77f6cSMauro Carvalho Chehab 		wake_up(&data->wait_fw);
541*0aa77f6cSMauro Carvalho Chehab 		return;
542*0aa77f6cSMauro Carvalho Chehab 	}
543*0aa77f6cSMauro Carvalho Chehab #define CHUNK_SIZE 512
544*0aa77f6cSMauro Carvalho Chehab 	/* all USB transfers must be done with continuous kernel memory.
545*0aa77f6cSMauro Carvalho Chehab 	   can't allocate more than 128k in current linux kernel, so
546*0aa77f6cSMauro Carvalho Chehab 	   upload the firmware in chunks
547*0aa77f6cSMauro Carvalho Chehab 	 */
548*0aa77f6cSMauro Carvalho Chehab 	if (data->fw_loaded < data->fw_size) {
549*0aa77f6cSMauro Carvalho Chehab 		len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ?
550*0aa77f6cSMauro Carvalho Chehab 		    data->fw_size % CHUNK_SIZE : CHUNK_SIZE;
551*0aa77f6cSMauro Carvalho Chehab 
552*0aa77f6cSMauro Carvalho Chehab 		if (len < CHUNK_SIZE)
553*0aa77f6cSMauro Carvalho Chehab 			memset(data->pfw_data, 0, CHUNK_SIZE);
554*0aa77f6cSMauro Carvalho Chehab 
555*0aa77f6cSMauro Carvalho Chehab 		dprintk(100, "completed len %d, loaded %d \n", len,
556*0aa77f6cSMauro Carvalho Chehab 			data->fw_loaded);
557*0aa77f6cSMauro Carvalho Chehab 
558*0aa77f6cSMauro Carvalho Chehab 		memcpy(data->pfw_data,
559*0aa77f6cSMauro Carvalho Chehab 		       (char *) data->fw->data + data->fw_loaded, len);
560*0aa77f6cSMauro Carvalho Chehab 
561*0aa77f6cSMauro Carvalho Chehab 		usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2),
562*0aa77f6cSMauro Carvalho Chehab 				  data->pfw_data, CHUNK_SIZE,
563*0aa77f6cSMauro Carvalho Chehab 				  s2255_fwchunk_complete, data);
564*0aa77f6cSMauro Carvalho Chehab 		if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
565*0aa77f6cSMauro Carvalho Chehab 			dev_err(&udev->dev, "failed submit URB\n");
566*0aa77f6cSMauro Carvalho Chehab 			atomic_set(&data->fw_state, S2255_FW_FAILED);
567*0aa77f6cSMauro Carvalho Chehab 			/* wake up anything waiting for the firmware */
568*0aa77f6cSMauro Carvalho Chehab 			wake_up(&data->wait_fw);
569*0aa77f6cSMauro Carvalho Chehab 			return;
570*0aa77f6cSMauro Carvalho Chehab 		}
571*0aa77f6cSMauro Carvalho Chehab 		data->fw_loaded += len;
572*0aa77f6cSMauro Carvalho Chehab 	} else {
573*0aa77f6cSMauro Carvalho Chehab 		atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
574*0aa77f6cSMauro Carvalho Chehab 		dprintk(100, "%s: firmware upload complete\n", __func__);
575*0aa77f6cSMauro Carvalho Chehab 	}
576*0aa77f6cSMauro Carvalho Chehab 	return;
577*0aa77f6cSMauro Carvalho Chehab 
578*0aa77f6cSMauro Carvalho Chehab }
579*0aa77f6cSMauro Carvalho Chehab 
580*0aa77f6cSMauro Carvalho Chehab static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
581*0aa77f6cSMauro Carvalho Chehab {
582*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dmaqueue *dma_q = &channel->vidq;
583*0aa77f6cSMauro Carvalho Chehab 	struct s2255_buffer *buf;
584*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
585*0aa77f6cSMauro Carvalho Chehab 	unsigned long flags = 0;
586*0aa77f6cSMauro Carvalho Chehab 	int rc = 0;
587*0aa77f6cSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->slock, flags);
588*0aa77f6cSMauro Carvalho Chehab 	if (list_empty(&dma_q->active)) {
589*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "No active queue to serve\n");
590*0aa77f6cSMauro Carvalho Chehab 		rc = -1;
591*0aa77f6cSMauro Carvalho Chehab 		goto unlock;
592*0aa77f6cSMauro Carvalho Chehab 	}
593*0aa77f6cSMauro Carvalho Chehab 	buf = list_entry(dma_q->active.next,
594*0aa77f6cSMauro Carvalho Chehab 			 struct s2255_buffer, vb.queue);
595*0aa77f6cSMauro Carvalho Chehab 	list_del(&buf->vb.queue);
596*0aa77f6cSMauro Carvalho Chehab 	do_gettimeofday(&buf->vb.ts);
597*0aa77f6cSMauro Carvalho Chehab 	s2255_fillbuff(channel, buf, jpgsize);
598*0aa77f6cSMauro Carvalho Chehab 	wake_up(&buf->vb.done);
599*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
600*0aa77f6cSMauro Carvalho Chehab unlock:
601*0aa77f6cSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->slock, flags);
602*0aa77f6cSMauro Carvalho Chehab 	return rc;
603*0aa77f6cSMauro Carvalho Chehab }
604*0aa77f6cSMauro Carvalho Chehab 
605*0aa77f6cSMauro Carvalho Chehab static const struct s2255_fmt *format_by_fourcc(int fourcc)
606*0aa77f6cSMauro Carvalho Chehab {
607*0aa77f6cSMauro Carvalho Chehab 	unsigned int i;
608*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(formats); i++) {
609*0aa77f6cSMauro Carvalho Chehab 		if (-1 == formats[i].fourcc)
610*0aa77f6cSMauro Carvalho Chehab 			continue;
611*0aa77f6cSMauro Carvalho Chehab 	if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
612*0aa77f6cSMauro Carvalho Chehab 			     (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
613*0aa77f6cSMauro Carvalho Chehab 	    continue;
614*0aa77f6cSMauro Carvalho Chehab 		if (formats[i].fourcc == fourcc)
615*0aa77f6cSMauro Carvalho Chehab 			return formats + i;
616*0aa77f6cSMauro Carvalho Chehab 	}
617*0aa77f6cSMauro Carvalho Chehab 	return NULL;
618*0aa77f6cSMauro Carvalho Chehab }
619*0aa77f6cSMauro Carvalho Chehab 
620*0aa77f6cSMauro Carvalho Chehab /* video buffer vmalloc implementation based partly on VIVI driver which is
621*0aa77f6cSMauro Carvalho Chehab  *          Copyright (c) 2006 by
622*0aa77f6cSMauro Carvalho Chehab  *                  Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
623*0aa77f6cSMauro Carvalho Chehab  *                  Ted Walther <ted--a.t--enumera.com>
624*0aa77f6cSMauro Carvalho Chehab  *                  John Sokol <sokol--a.t--videotechnology.com>
625*0aa77f6cSMauro Carvalho Chehab  *                  http://v4l.videotechnology.com/
626*0aa77f6cSMauro Carvalho Chehab  *
627*0aa77f6cSMauro Carvalho Chehab  */
628*0aa77f6cSMauro Carvalho Chehab static void s2255_fillbuff(struct s2255_channel *channel,
629*0aa77f6cSMauro Carvalho Chehab 			   struct s2255_buffer *buf, int jpgsize)
630*0aa77f6cSMauro Carvalho Chehab {
631*0aa77f6cSMauro Carvalho Chehab 	int pos = 0;
632*0aa77f6cSMauro Carvalho Chehab 	struct timeval ts;
633*0aa77f6cSMauro Carvalho Chehab 	const char *tmpbuf;
634*0aa77f6cSMauro Carvalho Chehab 	char *vbuf = videobuf_to_vmalloc(&buf->vb);
635*0aa77f6cSMauro Carvalho Chehab 	unsigned long last_frame;
636*0aa77f6cSMauro Carvalho Chehab 
637*0aa77f6cSMauro Carvalho Chehab 	if (!vbuf)
638*0aa77f6cSMauro Carvalho Chehab 		return;
639*0aa77f6cSMauro Carvalho Chehab 	last_frame = channel->last_frame;
640*0aa77f6cSMauro Carvalho Chehab 	if (last_frame != -1) {
641*0aa77f6cSMauro Carvalho Chehab 		tmpbuf =
642*0aa77f6cSMauro Carvalho Chehab 		    (const char *)channel->buffer.frame[last_frame].lpvbits;
643*0aa77f6cSMauro Carvalho Chehab 		switch (buf->fmt->fourcc) {
644*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_YUYV:
645*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_UYVY:
646*0aa77f6cSMauro Carvalho Chehab 			planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
647*0aa77f6cSMauro Carvalho Chehab 						 vbuf, buf->vb.width,
648*0aa77f6cSMauro Carvalho Chehab 						 buf->vb.height,
649*0aa77f6cSMauro Carvalho Chehab 						 buf->fmt->fourcc);
650*0aa77f6cSMauro Carvalho Chehab 			break;
651*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_GREY:
652*0aa77f6cSMauro Carvalho Chehab 			memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
653*0aa77f6cSMauro Carvalho Chehab 			break;
654*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_JPEG:
655*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_MJPEG:
656*0aa77f6cSMauro Carvalho Chehab 			buf->vb.size = jpgsize;
657*0aa77f6cSMauro Carvalho Chehab 			memcpy(vbuf, tmpbuf, buf->vb.size);
658*0aa77f6cSMauro Carvalho Chehab 			break;
659*0aa77f6cSMauro Carvalho Chehab 		case V4L2_PIX_FMT_YUV422P:
660*0aa77f6cSMauro Carvalho Chehab 			memcpy(vbuf, tmpbuf,
661*0aa77f6cSMauro Carvalho Chehab 			       buf->vb.width * buf->vb.height * 2);
662*0aa77f6cSMauro Carvalho Chehab 			break;
663*0aa77f6cSMauro Carvalho Chehab 		default:
664*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_DEBUG "s2255: unknown format?\n");
665*0aa77f6cSMauro Carvalho Chehab 		}
666*0aa77f6cSMauro Carvalho Chehab 		channel->last_frame = -1;
667*0aa77f6cSMauro Carvalho Chehab 	} else {
668*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "s2255: =======no frame\n");
669*0aa77f6cSMauro Carvalho Chehab 		return;
670*0aa77f6cSMauro Carvalho Chehab 
671*0aa77f6cSMauro Carvalho Chehab 	}
672*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
673*0aa77f6cSMauro Carvalho Chehab 		(unsigned long)vbuf, pos);
674*0aa77f6cSMauro Carvalho Chehab 	/* tell v4l buffer was filled */
675*0aa77f6cSMauro Carvalho Chehab 
676*0aa77f6cSMauro Carvalho Chehab 	buf->vb.field_count = channel->frame_count * 2;
677*0aa77f6cSMauro Carvalho Chehab 	do_gettimeofday(&ts);
678*0aa77f6cSMauro Carvalho Chehab 	buf->vb.ts = ts;
679*0aa77f6cSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_DONE;
680*0aa77f6cSMauro Carvalho Chehab }
681*0aa77f6cSMauro Carvalho Chehab 
682*0aa77f6cSMauro Carvalho Chehab 
683*0aa77f6cSMauro Carvalho Chehab /* ------------------------------------------------------------------
684*0aa77f6cSMauro Carvalho Chehab    Videobuf operations
685*0aa77f6cSMauro Carvalho Chehab    ------------------------------------------------------------------*/
686*0aa77f6cSMauro Carvalho Chehab 
687*0aa77f6cSMauro Carvalho Chehab static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
688*0aa77f6cSMauro Carvalho Chehab 			unsigned int *size)
689*0aa77f6cSMauro Carvalho Chehab {
690*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = vq->priv_data;
691*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
692*0aa77f6cSMauro Carvalho Chehab 	*size = channel->width * channel->height * (channel->fmt->depth >> 3);
693*0aa77f6cSMauro Carvalho Chehab 
694*0aa77f6cSMauro Carvalho Chehab 	if (0 == *count)
695*0aa77f6cSMauro Carvalho Chehab 		*count = S2255_DEF_BUFS;
696*0aa77f6cSMauro Carvalho Chehab 
697*0aa77f6cSMauro Carvalho Chehab 	if (*size * *count > vid_limit * 1024 * 1024)
698*0aa77f6cSMauro Carvalho Chehab 		*count = (vid_limit * 1024 * 1024) / *size;
699*0aa77f6cSMauro Carvalho Chehab 
700*0aa77f6cSMauro Carvalho Chehab 	return 0;
701*0aa77f6cSMauro Carvalho Chehab }
702*0aa77f6cSMauro Carvalho Chehab 
703*0aa77f6cSMauro Carvalho Chehab static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
704*0aa77f6cSMauro Carvalho Chehab {
705*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s\n", __func__);
706*0aa77f6cSMauro Carvalho Chehab 
707*0aa77f6cSMauro Carvalho Chehab 	videobuf_vmalloc_free(&buf->vb);
708*0aa77f6cSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
709*0aa77f6cSMauro Carvalho Chehab }
710*0aa77f6cSMauro Carvalho Chehab 
711*0aa77f6cSMauro Carvalho Chehab static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
712*0aa77f6cSMauro Carvalho Chehab 			  enum v4l2_field field)
713*0aa77f6cSMauro Carvalho Chehab {
714*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = vq->priv_data;
715*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
716*0aa77f6cSMauro Carvalho Chehab 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
717*0aa77f6cSMauro Carvalho Chehab 	int rc;
718*0aa77f6cSMauro Carvalho Chehab 	int w = channel->width;
719*0aa77f6cSMauro Carvalho Chehab 	int h = channel->height;
720*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, field=%d\n", __func__, field);
721*0aa77f6cSMauro Carvalho Chehab 	if (channel->fmt == NULL)
722*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
723*0aa77f6cSMauro Carvalho Chehab 
724*0aa77f6cSMauro Carvalho Chehab 	if ((w < norm_minw(&channel->vdev)) ||
725*0aa77f6cSMauro Carvalho Chehab 	    (w > norm_maxw(&channel->vdev)) ||
726*0aa77f6cSMauro Carvalho Chehab 	    (h < norm_minh(&channel->vdev)) ||
727*0aa77f6cSMauro Carvalho Chehab 	    (h > norm_maxh(&channel->vdev))) {
728*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "invalid buffer prepare\n");
729*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
730*0aa77f6cSMauro Carvalho Chehab 	}
731*0aa77f6cSMauro Carvalho Chehab 	buf->vb.size = w * h * (channel->fmt->depth >> 3);
732*0aa77f6cSMauro Carvalho Chehab 	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
733*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "invalid buffer prepare\n");
734*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
735*0aa77f6cSMauro Carvalho Chehab 	}
736*0aa77f6cSMauro Carvalho Chehab 
737*0aa77f6cSMauro Carvalho Chehab 	buf->fmt = channel->fmt;
738*0aa77f6cSMauro Carvalho Chehab 	buf->vb.width = w;
739*0aa77f6cSMauro Carvalho Chehab 	buf->vb.height = h;
740*0aa77f6cSMauro Carvalho Chehab 	buf->vb.field = field;
741*0aa77f6cSMauro Carvalho Chehab 
742*0aa77f6cSMauro Carvalho Chehab 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
743*0aa77f6cSMauro Carvalho Chehab 		rc = videobuf_iolock(vq, &buf->vb, NULL);
744*0aa77f6cSMauro Carvalho Chehab 		if (rc < 0)
745*0aa77f6cSMauro Carvalho Chehab 			goto fail;
746*0aa77f6cSMauro Carvalho Chehab 	}
747*0aa77f6cSMauro Carvalho Chehab 
748*0aa77f6cSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_PREPARED;
749*0aa77f6cSMauro Carvalho Chehab 	return 0;
750*0aa77f6cSMauro Carvalho Chehab fail:
751*0aa77f6cSMauro Carvalho Chehab 	free_buffer(vq, buf);
752*0aa77f6cSMauro Carvalho Chehab 	return rc;
753*0aa77f6cSMauro Carvalho Chehab }
754*0aa77f6cSMauro Carvalho Chehab 
755*0aa77f6cSMauro Carvalho Chehab static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
756*0aa77f6cSMauro Carvalho Chehab {
757*0aa77f6cSMauro Carvalho Chehab 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
758*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = vq->priv_data;
759*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
760*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dmaqueue *vidq = &channel->vidq;
761*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s\n", __func__);
762*0aa77f6cSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_QUEUED;
763*0aa77f6cSMauro Carvalho Chehab 	list_add_tail(&buf->vb.queue, &vidq->active);
764*0aa77f6cSMauro Carvalho Chehab }
765*0aa77f6cSMauro Carvalho Chehab 
766*0aa77f6cSMauro Carvalho Chehab static void buffer_release(struct videobuf_queue *vq,
767*0aa77f6cSMauro Carvalho Chehab 			   struct videobuf_buffer *vb)
768*0aa77f6cSMauro Carvalho Chehab {
769*0aa77f6cSMauro Carvalho Chehab 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
770*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = vq->priv_data;
771*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s %d\n", __func__, fh->channel->idx);
772*0aa77f6cSMauro Carvalho Chehab 	free_buffer(vq, buf);
773*0aa77f6cSMauro Carvalho Chehab }
774*0aa77f6cSMauro Carvalho Chehab 
775*0aa77f6cSMauro Carvalho Chehab static struct videobuf_queue_ops s2255_video_qops = {
776*0aa77f6cSMauro Carvalho Chehab 	.buf_setup = buffer_setup,
777*0aa77f6cSMauro Carvalho Chehab 	.buf_prepare = buffer_prepare,
778*0aa77f6cSMauro Carvalho Chehab 	.buf_queue = buffer_queue,
779*0aa77f6cSMauro Carvalho Chehab 	.buf_release = buffer_release,
780*0aa77f6cSMauro Carvalho Chehab };
781*0aa77f6cSMauro Carvalho Chehab 
782*0aa77f6cSMauro Carvalho Chehab 
783*0aa77f6cSMauro Carvalho Chehab static int res_get(struct s2255_fh *fh)
784*0aa77f6cSMauro Carvalho Chehab {
785*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
786*0aa77f6cSMauro Carvalho Chehab 	/* is it free? */
787*0aa77f6cSMauro Carvalho Chehab 	if (channel->resources)
788*0aa77f6cSMauro Carvalho Chehab 		return 0; /* no, someone else uses it */
789*0aa77f6cSMauro Carvalho Chehab 	/* it's free, grab it */
790*0aa77f6cSMauro Carvalho Chehab 	channel->resources = 1;
791*0aa77f6cSMauro Carvalho Chehab 	fh->resources = 1;
792*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "s2255: res: get\n");
793*0aa77f6cSMauro Carvalho Chehab 	return 1;
794*0aa77f6cSMauro Carvalho Chehab }
795*0aa77f6cSMauro Carvalho Chehab 
796*0aa77f6cSMauro Carvalho Chehab static int res_locked(struct s2255_fh *fh)
797*0aa77f6cSMauro Carvalho Chehab {
798*0aa77f6cSMauro Carvalho Chehab 	return fh->channel->resources;
799*0aa77f6cSMauro Carvalho Chehab }
800*0aa77f6cSMauro Carvalho Chehab 
801*0aa77f6cSMauro Carvalho Chehab static int res_check(struct s2255_fh *fh)
802*0aa77f6cSMauro Carvalho Chehab {
803*0aa77f6cSMauro Carvalho Chehab 	return fh->resources;
804*0aa77f6cSMauro Carvalho Chehab }
805*0aa77f6cSMauro Carvalho Chehab 
806*0aa77f6cSMauro Carvalho Chehab 
807*0aa77f6cSMauro Carvalho Chehab static void res_free(struct s2255_fh *fh)
808*0aa77f6cSMauro Carvalho Chehab {
809*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
810*0aa77f6cSMauro Carvalho Chehab 	channel->resources = 0;
811*0aa77f6cSMauro Carvalho Chehab 	fh->resources = 0;
812*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "res: put\n");
813*0aa77f6cSMauro Carvalho Chehab }
814*0aa77f6cSMauro Carvalho Chehab 
815*0aa77f6cSMauro Carvalho Chehab static int vidioc_querymenu(struct file *file, void *priv,
816*0aa77f6cSMauro Carvalho Chehab 			    struct v4l2_querymenu *qmenu)
817*0aa77f6cSMauro Carvalho Chehab {
818*0aa77f6cSMauro Carvalho Chehab 	static const char *colorfilter[] = {
819*0aa77f6cSMauro Carvalho Chehab 		"Off",
820*0aa77f6cSMauro Carvalho Chehab 		"On",
821*0aa77f6cSMauro Carvalho Chehab 		NULL
822*0aa77f6cSMauro Carvalho Chehab 	};
823*0aa77f6cSMauro Carvalho Chehab 	if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) {
824*0aa77f6cSMauro Carvalho Chehab 		int i;
825*0aa77f6cSMauro Carvalho Chehab 		const char **menu_items = colorfilter;
826*0aa77f6cSMauro Carvalho Chehab 		for (i = 0; i < qmenu->index && menu_items[i]; i++)
827*0aa77f6cSMauro Carvalho Chehab 			; /* do nothing (from v4l2-common.c) */
828*0aa77f6cSMauro Carvalho Chehab 		if (menu_items[i] == NULL || menu_items[i][0] == '\0')
829*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
830*0aa77f6cSMauro Carvalho Chehab 		strlcpy(qmenu->name, menu_items[qmenu->index],
831*0aa77f6cSMauro Carvalho Chehab 			sizeof(qmenu->name));
832*0aa77f6cSMauro Carvalho Chehab 		return 0;
833*0aa77f6cSMauro Carvalho Chehab 	}
834*0aa77f6cSMauro Carvalho Chehab 	return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
835*0aa77f6cSMauro Carvalho Chehab }
836*0aa77f6cSMauro Carvalho Chehab 
837*0aa77f6cSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void *priv,
838*0aa77f6cSMauro Carvalho Chehab 			   struct v4l2_capability *cap)
839*0aa77f6cSMauro Carvalho Chehab {
840*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = file->private_data;
841*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
842*0aa77f6cSMauro Carvalho Chehab 	strlcpy(cap->driver, "s2255", sizeof(cap->driver));
843*0aa77f6cSMauro Carvalho Chehab 	strlcpy(cap->card, "s2255", sizeof(cap->card));
844*0aa77f6cSMauro Carvalho Chehab 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
845*0aa77f6cSMauro Carvalho Chehab 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
846*0aa77f6cSMauro Carvalho Chehab 	return 0;
847*0aa77f6cSMauro Carvalho Chehab }
848*0aa77f6cSMauro Carvalho Chehab 
849*0aa77f6cSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
850*0aa77f6cSMauro Carvalho Chehab 			       struct v4l2_fmtdesc *f)
851*0aa77f6cSMauro Carvalho Chehab {
852*0aa77f6cSMauro Carvalho Chehab 	int index = f->index;
853*0aa77f6cSMauro Carvalho Chehab 
854*0aa77f6cSMauro Carvalho Chehab 	if (index >= ARRAY_SIZE(formats))
855*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
856*0aa77f6cSMauro Carvalho Chehab 	if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
857*0aa77f6cSMauro Carvalho Chehab 			(formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
858*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
859*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "name %s\n", formats[index].name);
860*0aa77f6cSMauro Carvalho Chehab 	strlcpy(f->description, formats[index].name, sizeof(f->description));
861*0aa77f6cSMauro Carvalho Chehab 	f->pixelformat = formats[index].fourcc;
862*0aa77f6cSMauro Carvalho Chehab 	return 0;
863*0aa77f6cSMauro Carvalho Chehab }
864*0aa77f6cSMauro Carvalho Chehab 
865*0aa77f6cSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
866*0aa77f6cSMauro Carvalho Chehab 			    struct v4l2_format *f)
867*0aa77f6cSMauro Carvalho Chehab {
868*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
869*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
870*0aa77f6cSMauro Carvalho Chehab 
871*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.width = channel->width;
872*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.height = channel->height;
873*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.field = fh->vb_vidq.field;
874*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.pixelformat = channel->fmt->fourcc;
875*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
876*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
877*0aa77f6cSMauro Carvalho Chehab 	return 0;
878*0aa77f6cSMauro Carvalho Chehab }
879*0aa77f6cSMauro Carvalho Chehab 
880*0aa77f6cSMauro Carvalho Chehab static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
881*0aa77f6cSMauro Carvalho Chehab 			      struct v4l2_format *f)
882*0aa77f6cSMauro Carvalho Chehab {
883*0aa77f6cSMauro Carvalho Chehab 	const struct s2255_fmt *fmt;
884*0aa77f6cSMauro Carvalho Chehab 	enum v4l2_field field;
885*0aa77f6cSMauro Carvalho Chehab 	int  b_any_field = 0;
886*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
887*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
888*0aa77f6cSMauro Carvalho Chehab 	int is_ntsc;
889*0aa77f6cSMauro Carvalho Chehab 	is_ntsc =
890*0aa77f6cSMauro Carvalho Chehab 		(channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
891*0aa77f6cSMauro Carvalho Chehab 
892*0aa77f6cSMauro Carvalho Chehab 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
893*0aa77f6cSMauro Carvalho Chehab 
894*0aa77f6cSMauro Carvalho Chehab 	if (fmt == NULL)
895*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
896*0aa77f6cSMauro Carvalho Chehab 
897*0aa77f6cSMauro Carvalho Chehab 	field = f->fmt.pix.field;
898*0aa77f6cSMauro Carvalho Chehab 	if (field == V4L2_FIELD_ANY)
899*0aa77f6cSMauro Carvalho Chehab 		b_any_field = 1;
900*0aa77f6cSMauro Carvalho Chehab 
901*0aa77f6cSMauro Carvalho Chehab 	dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
902*0aa77f6cSMauro Carvalho Chehab 		__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
903*0aa77f6cSMauro Carvalho Chehab 	if (is_ntsc) {
904*0aa77f6cSMauro Carvalho Chehab 		/* NTSC */
905*0aa77f6cSMauro Carvalho Chehab 		if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
906*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
907*0aa77f6cSMauro Carvalho Chehab 			if (b_any_field) {
908*0aa77f6cSMauro Carvalho Chehab 				field = V4L2_FIELD_SEQ_TB;
909*0aa77f6cSMauro Carvalho Chehab 			} else if (!((field == V4L2_FIELD_INTERLACED) ||
910*0aa77f6cSMauro Carvalho Chehab 				      (field == V4L2_FIELD_SEQ_TB) ||
911*0aa77f6cSMauro Carvalho Chehab 				      (field == V4L2_FIELD_INTERLACED_TB))) {
912*0aa77f6cSMauro Carvalho Chehab 				dprintk(1, "unsupported field setting\n");
913*0aa77f6cSMauro Carvalho Chehab 				return -EINVAL;
914*0aa77f6cSMauro Carvalho Chehab 			}
915*0aa77f6cSMauro Carvalho Chehab 		} else {
916*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
917*0aa77f6cSMauro Carvalho Chehab 			if (b_any_field) {
918*0aa77f6cSMauro Carvalho Chehab 				field = V4L2_FIELD_TOP;
919*0aa77f6cSMauro Carvalho Chehab 			} else if (!((field == V4L2_FIELD_TOP) ||
920*0aa77f6cSMauro Carvalho Chehab 				      (field == V4L2_FIELD_BOTTOM))) {
921*0aa77f6cSMauro Carvalho Chehab 				dprintk(1, "unsupported field setting\n");
922*0aa77f6cSMauro Carvalho Chehab 				return -EINVAL;
923*0aa77f6cSMauro Carvalho Chehab 			}
924*0aa77f6cSMauro Carvalho Chehab 
925*0aa77f6cSMauro Carvalho Chehab 		}
926*0aa77f6cSMauro Carvalho Chehab 		if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
927*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
928*0aa77f6cSMauro Carvalho Chehab 		else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
929*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
930*0aa77f6cSMauro Carvalho Chehab 		else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
931*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
932*0aa77f6cSMauro Carvalho Chehab 		else
933*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
934*0aa77f6cSMauro Carvalho Chehab 	} else {
935*0aa77f6cSMauro Carvalho Chehab 		/* PAL */
936*0aa77f6cSMauro Carvalho Chehab 		if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
937*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
938*0aa77f6cSMauro Carvalho Chehab 			if (b_any_field) {
939*0aa77f6cSMauro Carvalho Chehab 				field = V4L2_FIELD_SEQ_TB;
940*0aa77f6cSMauro Carvalho Chehab 			} else if (!((field == V4L2_FIELD_INTERLACED) ||
941*0aa77f6cSMauro Carvalho Chehab 				      (field == V4L2_FIELD_SEQ_TB) ||
942*0aa77f6cSMauro Carvalho Chehab 				      (field == V4L2_FIELD_INTERLACED_TB))) {
943*0aa77f6cSMauro Carvalho Chehab 				dprintk(1, "unsupported field setting\n");
944*0aa77f6cSMauro Carvalho Chehab 				return -EINVAL;
945*0aa77f6cSMauro Carvalho Chehab 			}
946*0aa77f6cSMauro Carvalho Chehab 		} else {
947*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
948*0aa77f6cSMauro Carvalho Chehab 			if (b_any_field) {
949*0aa77f6cSMauro Carvalho Chehab 				field = V4L2_FIELD_TOP;
950*0aa77f6cSMauro Carvalho Chehab 			} else if (!((field == V4L2_FIELD_TOP) ||
951*0aa77f6cSMauro Carvalho Chehab 				     (field == V4L2_FIELD_BOTTOM))) {
952*0aa77f6cSMauro Carvalho Chehab 				dprintk(1, "unsupported field setting\n");
953*0aa77f6cSMauro Carvalho Chehab 				return -EINVAL;
954*0aa77f6cSMauro Carvalho Chehab 			}
955*0aa77f6cSMauro Carvalho Chehab 		}
956*0aa77f6cSMauro Carvalho Chehab 		if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
957*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
958*0aa77f6cSMauro Carvalho Chehab 			field = V4L2_FIELD_SEQ_TB;
959*0aa77f6cSMauro Carvalho Chehab 		} else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
960*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
961*0aa77f6cSMauro Carvalho Chehab 			field = V4L2_FIELD_TOP;
962*0aa77f6cSMauro Carvalho Chehab 		} else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
963*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
964*0aa77f6cSMauro Carvalho Chehab 			field = V4L2_FIELD_TOP;
965*0aa77f6cSMauro Carvalho Chehab 		} else {
966*0aa77f6cSMauro Carvalho Chehab 			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
967*0aa77f6cSMauro Carvalho Chehab 			field = V4L2_FIELD_TOP;
968*0aa77f6cSMauro Carvalho Chehab 		}
969*0aa77f6cSMauro Carvalho Chehab 	}
970*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.field = field;
971*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
972*0aa77f6cSMauro Carvalho Chehab 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
973*0aa77f6cSMauro Carvalho Chehab 	dprintk(50, "%s: set width %d height %d field %d\n", __func__,
974*0aa77f6cSMauro Carvalho Chehab 		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
975*0aa77f6cSMauro Carvalho Chehab 	return 0;
976*0aa77f6cSMauro Carvalho Chehab }
977*0aa77f6cSMauro Carvalho Chehab 
978*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
979*0aa77f6cSMauro Carvalho Chehab 			    struct v4l2_format *f)
980*0aa77f6cSMauro Carvalho Chehab {
981*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
982*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
983*0aa77f6cSMauro Carvalho Chehab 	const struct s2255_fmt *fmt;
984*0aa77f6cSMauro Carvalho Chehab 	struct videobuf_queue *q = &fh->vb_vidq;
985*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode mode;
986*0aa77f6cSMauro Carvalho Chehab 	int ret;
987*0aa77f6cSMauro Carvalho Chehab 
988*0aa77f6cSMauro Carvalho Chehab 	ret = vidioc_try_fmt_vid_cap(file, fh, f);
989*0aa77f6cSMauro Carvalho Chehab 
990*0aa77f6cSMauro Carvalho Chehab 	if (ret < 0)
991*0aa77f6cSMauro Carvalho Chehab 		return ret;
992*0aa77f6cSMauro Carvalho Chehab 
993*0aa77f6cSMauro Carvalho Chehab 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
994*0aa77f6cSMauro Carvalho Chehab 
995*0aa77f6cSMauro Carvalho Chehab 	if (fmt == NULL)
996*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
997*0aa77f6cSMauro Carvalho Chehab 
998*0aa77f6cSMauro Carvalho Chehab 	mutex_lock(&q->vb_lock);
999*0aa77f6cSMauro Carvalho Chehab 
1000*0aa77f6cSMauro Carvalho Chehab 	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
1001*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "queue busy\n");
1002*0aa77f6cSMauro Carvalho Chehab 		ret = -EBUSY;
1003*0aa77f6cSMauro Carvalho Chehab 		goto out_s_fmt;
1004*0aa77f6cSMauro Carvalho Chehab 	}
1005*0aa77f6cSMauro Carvalho Chehab 
1006*0aa77f6cSMauro Carvalho Chehab 	if (res_locked(fh)) {
1007*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "%s: channel busy\n", __func__);
1008*0aa77f6cSMauro Carvalho Chehab 		ret = -EBUSY;
1009*0aa77f6cSMauro Carvalho Chehab 		goto out_s_fmt;
1010*0aa77f6cSMauro Carvalho Chehab 	}
1011*0aa77f6cSMauro Carvalho Chehab 	mode = channel->mode;
1012*0aa77f6cSMauro Carvalho Chehab 	channel->fmt = fmt;
1013*0aa77f6cSMauro Carvalho Chehab 	channel->width = f->fmt.pix.width;
1014*0aa77f6cSMauro Carvalho Chehab 	channel->height = f->fmt.pix.height;
1015*0aa77f6cSMauro Carvalho Chehab 	fh->vb_vidq.field = f->fmt.pix.field;
1016*0aa77f6cSMauro Carvalho Chehab 	fh->type = f->type;
1017*0aa77f6cSMauro Carvalho Chehab 	if (channel->width > norm_minw(&channel->vdev)) {
1018*0aa77f6cSMauro Carvalho Chehab 		if (channel->height > norm_minh(&channel->vdev)) {
1019*0aa77f6cSMauro Carvalho Chehab 			if (channel->cap_parm.capturemode &
1020*0aa77f6cSMauro Carvalho Chehab 			    V4L2_MODE_HIGHQUALITY)
1021*0aa77f6cSMauro Carvalho Chehab 				mode.scale = SCALE_4CIFSI;
1022*0aa77f6cSMauro Carvalho Chehab 			else
1023*0aa77f6cSMauro Carvalho Chehab 				mode.scale = SCALE_4CIFS;
1024*0aa77f6cSMauro Carvalho Chehab 		} else
1025*0aa77f6cSMauro Carvalho Chehab 			mode.scale = SCALE_2CIFS;
1026*0aa77f6cSMauro Carvalho Chehab 
1027*0aa77f6cSMauro Carvalho Chehab 	} else {
1028*0aa77f6cSMauro Carvalho Chehab 		mode.scale = SCALE_1CIFS;
1029*0aa77f6cSMauro Carvalho Chehab 	}
1030*0aa77f6cSMauro Carvalho Chehab 	/* color mode */
1031*0aa77f6cSMauro Carvalho Chehab 	switch (channel->fmt->fourcc) {
1032*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_GREY:
1033*0aa77f6cSMauro Carvalho Chehab 		mode.color &= ~MASK_COLOR;
1034*0aa77f6cSMauro Carvalho Chehab 		mode.color |= COLOR_Y8;
1035*0aa77f6cSMauro Carvalho Chehab 		break;
1036*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_JPEG:
1037*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_MJPEG:
1038*0aa77f6cSMauro Carvalho Chehab 		mode.color &= ~MASK_COLOR;
1039*0aa77f6cSMauro Carvalho Chehab 		mode.color |= COLOR_JPG;
1040*0aa77f6cSMauro Carvalho Chehab 		mode.color |= (channel->jc.quality << 8);
1041*0aa77f6cSMauro Carvalho Chehab 		break;
1042*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_YUV422P:
1043*0aa77f6cSMauro Carvalho Chehab 		mode.color &= ~MASK_COLOR;
1044*0aa77f6cSMauro Carvalho Chehab 		mode.color |= COLOR_YUVPL;
1045*0aa77f6cSMauro Carvalho Chehab 		break;
1046*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_YUYV:
1047*0aa77f6cSMauro Carvalho Chehab 	case V4L2_PIX_FMT_UYVY:
1048*0aa77f6cSMauro Carvalho Chehab 	default:
1049*0aa77f6cSMauro Carvalho Chehab 		mode.color &= ~MASK_COLOR;
1050*0aa77f6cSMauro Carvalho Chehab 		mode.color |= COLOR_YUVPK;
1051*0aa77f6cSMauro Carvalho Chehab 		break;
1052*0aa77f6cSMauro Carvalho Chehab 	}
1053*0aa77f6cSMauro Carvalho Chehab 	if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
1054*0aa77f6cSMauro Carvalho Chehab 		mode.restart = 1;
1055*0aa77f6cSMauro Carvalho Chehab 	else if (mode.scale != channel->mode.scale)
1056*0aa77f6cSMauro Carvalho Chehab 		mode.restart = 1;
1057*0aa77f6cSMauro Carvalho Chehab 	else if (mode.format != channel->mode.format)
1058*0aa77f6cSMauro Carvalho Chehab 		mode.restart = 1;
1059*0aa77f6cSMauro Carvalho Chehab 	channel->mode = mode;
1060*0aa77f6cSMauro Carvalho Chehab 	(void) s2255_set_mode(channel, &mode);
1061*0aa77f6cSMauro Carvalho Chehab 	ret = 0;
1062*0aa77f6cSMauro Carvalho Chehab out_s_fmt:
1063*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&q->vb_lock);
1064*0aa77f6cSMauro Carvalho Chehab 	return ret;
1065*0aa77f6cSMauro Carvalho Chehab }
1066*0aa77f6cSMauro Carvalho Chehab 
1067*0aa77f6cSMauro Carvalho Chehab static int vidioc_reqbufs(struct file *file, void *priv,
1068*0aa77f6cSMauro Carvalho Chehab 			  struct v4l2_requestbuffers *p)
1069*0aa77f6cSMauro Carvalho Chehab {
1070*0aa77f6cSMauro Carvalho Chehab 	int rc;
1071*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1072*0aa77f6cSMauro Carvalho Chehab 	rc = videobuf_reqbufs(&fh->vb_vidq, p);
1073*0aa77f6cSMauro Carvalho Chehab 	return rc;
1074*0aa77f6cSMauro Carvalho Chehab }
1075*0aa77f6cSMauro Carvalho Chehab 
1076*0aa77f6cSMauro Carvalho Chehab static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
1077*0aa77f6cSMauro Carvalho Chehab {
1078*0aa77f6cSMauro Carvalho Chehab 	int rc;
1079*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1080*0aa77f6cSMauro Carvalho Chehab 	rc = videobuf_querybuf(&fh->vb_vidq, p);
1081*0aa77f6cSMauro Carvalho Chehab 	return rc;
1082*0aa77f6cSMauro Carvalho Chehab }
1083*0aa77f6cSMauro Carvalho Chehab 
1084*0aa77f6cSMauro Carvalho Chehab static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
1085*0aa77f6cSMauro Carvalho Chehab {
1086*0aa77f6cSMauro Carvalho Chehab 	int rc;
1087*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1088*0aa77f6cSMauro Carvalho Chehab 	rc = videobuf_qbuf(&fh->vb_vidq, p);
1089*0aa77f6cSMauro Carvalho Chehab 	return rc;
1090*0aa77f6cSMauro Carvalho Chehab }
1091*0aa77f6cSMauro Carvalho Chehab 
1092*0aa77f6cSMauro Carvalho Chehab static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
1093*0aa77f6cSMauro Carvalho Chehab {
1094*0aa77f6cSMauro Carvalho Chehab 	int rc;
1095*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1096*0aa77f6cSMauro Carvalho Chehab 	rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
1097*0aa77f6cSMauro Carvalho Chehab 	return rc;
1098*0aa77f6cSMauro Carvalho Chehab }
1099*0aa77f6cSMauro Carvalho Chehab 
1100*0aa77f6cSMauro Carvalho Chehab /* write to the configuration pipe, synchronously */
1101*0aa77f6cSMauro Carvalho Chehab static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
1102*0aa77f6cSMauro Carvalho Chehab 			      int size)
1103*0aa77f6cSMauro Carvalho Chehab {
1104*0aa77f6cSMauro Carvalho Chehab 	int pipe;
1105*0aa77f6cSMauro Carvalho Chehab 	int done;
1106*0aa77f6cSMauro Carvalho Chehab 	long retval = -1;
1107*0aa77f6cSMauro Carvalho Chehab 	if (udev) {
1108*0aa77f6cSMauro Carvalho Chehab 		pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP);
1109*0aa77f6cSMauro Carvalho Chehab 		retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500);
1110*0aa77f6cSMauro Carvalho Chehab 	}
1111*0aa77f6cSMauro Carvalho Chehab 	return retval;
1112*0aa77f6cSMauro Carvalho Chehab }
1113*0aa77f6cSMauro Carvalho Chehab 
1114*0aa77f6cSMauro Carvalho Chehab static u32 get_transfer_size(struct s2255_mode *mode)
1115*0aa77f6cSMauro Carvalho Chehab {
1116*0aa77f6cSMauro Carvalho Chehab 	int linesPerFrame = LINE_SZ_DEF;
1117*0aa77f6cSMauro Carvalho Chehab 	int pixelsPerLine = NUM_LINES_DEF;
1118*0aa77f6cSMauro Carvalho Chehab 	u32 outImageSize;
1119*0aa77f6cSMauro Carvalho Chehab 	u32 usbInSize;
1120*0aa77f6cSMauro Carvalho Chehab 	unsigned int mask_mult;
1121*0aa77f6cSMauro Carvalho Chehab 
1122*0aa77f6cSMauro Carvalho Chehab 	if (mode == NULL)
1123*0aa77f6cSMauro Carvalho Chehab 		return 0;
1124*0aa77f6cSMauro Carvalho Chehab 
1125*0aa77f6cSMauro Carvalho Chehab 	if (mode->format == FORMAT_NTSC) {
1126*0aa77f6cSMauro Carvalho Chehab 		switch (mode->scale) {
1127*0aa77f6cSMauro Carvalho Chehab 		case SCALE_4CIFS:
1128*0aa77f6cSMauro Carvalho Chehab 		case SCALE_4CIFSI:
1129*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
1130*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_4CIFS_NTSC;
1131*0aa77f6cSMauro Carvalho Chehab 			break;
1132*0aa77f6cSMauro Carvalho Chehab 		case SCALE_2CIFS:
1133*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_2CIFS_NTSC;
1134*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_2CIFS_NTSC;
1135*0aa77f6cSMauro Carvalho Chehab 			break;
1136*0aa77f6cSMauro Carvalho Chehab 		case SCALE_1CIFS:
1137*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_1CIFS_NTSC;
1138*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_1CIFS_NTSC;
1139*0aa77f6cSMauro Carvalho Chehab 			break;
1140*0aa77f6cSMauro Carvalho Chehab 		default:
1141*0aa77f6cSMauro Carvalho Chehab 			break;
1142*0aa77f6cSMauro Carvalho Chehab 		}
1143*0aa77f6cSMauro Carvalho Chehab 	} else if (mode->format == FORMAT_PAL) {
1144*0aa77f6cSMauro Carvalho Chehab 		switch (mode->scale) {
1145*0aa77f6cSMauro Carvalho Chehab 		case SCALE_4CIFS:
1146*0aa77f6cSMauro Carvalho Chehab 		case SCALE_4CIFSI:
1147*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
1148*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_4CIFS_PAL;
1149*0aa77f6cSMauro Carvalho Chehab 			break;
1150*0aa77f6cSMauro Carvalho Chehab 		case SCALE_2CIFS:
1151*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_2CIFS_PAL;
1152*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_2CIFS_PAL;
1153*0aa77f6cSMauro Carvalho Chehab 			break;
1154*0aa77f6cSMauro Carvalho Chehab 		case SCALE_1CIFS:
1155*0aa77f6cSMauro Carvalho Chehab 			linesPerFrame = NUM_LINES_1CIFS_PAL;
1156*0aa77f6cSMauro Carvalho Chehab 			pixelsPerLine = LINE_SZ_1CIFS_PAL;
1157*0aa77f6cSMauro Carvalho Chehab 			break;
1158*0aa77f6cSMauro Carvalho Chehab 		default:
1159*0aa77f6cSMauro Carvalho Chehab 			break;
1160*0aa77f6cSMauro Carvalho Chehab 		}
1161*0aa77f6cSMauro Carvalho Chehab 	}
1162*0aa77f6cSMauro Carvalho Chehab 	outImageSize = linesPerFrame * pixelsPerLine;
1163*0aa77f6cSMauro Carvalho Chehab 	if ((mode->color & MASK_COLOR) != COLOR_Y8) {
1164*0aa77f6cSMauro Carvalho Chehab 		/* 2 bytes/pixel if not monochrome */
1165*0aa77f6cSMauro Carvalho Chehab 		outImageSize *= 2;
1166*0aa77f6cSMauro Carvalho Chehab 	}
1167*0aa77f6cSMauro Carvalho Chehab 
1168*0aa77f6cSMauro Carvalho Chehab 	/* total bytes to send including prefix and 4K padding;
1169*0aa77f6cSMauro Carvalho Chehab 	   must be a multiple of USB_READ_SIZE */
1170*0aa77f6cSMauro Carvalho Chehab 	usbInSize = outImageSize + PREFIX_SIZE;	/* always send prefix */
1171*0aa77f6cSMauro Carvalho Chehab 	mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1;
1172*0aa77f6cSMauro Carvalho Chehab 	/* if size not a multiple of USB_READ_SIZE */
1173*0aa77f6cSMauro Carvalho Chehab 	if (usbInSize & ~mask_mult)
1174*0aa77f6cSMauro Carvalho Chehab 		usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK);
1175*0aa77f6cSMauro Carvalho Chehab 	return usbInSize;
1176*0aa77f6cSMauro Carvalho Chehab }
1177*0aa77f6cSMauro Carvalho Chehab 
1178*0aa77f6cSMauro Carvalho Chehab static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
1179*0aa77f6cSMauro Carvalho Chehab {
1180*0aa77f6cSMauro Carvalho Chehab 	struct device *dev = &sdev->udev->dev;
1181*0aa77f6cSMauro Carvalho Chehab 	dev_info(dev, "------------------------------------------------\n");
1182*0aa77f6cSMauro Carvalho Chehab 	dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
1183*0aa77f6cSMauro Carvalho Chehab 	dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
1184*0aa77f6cSMauro Carvalho Chehab 	dev_info(dev, "bright: 0x%x\n", mode->bright);
1185*0aa77f6cSMauro Carvalho Chehab 	dev_info(dev, "------------------------------------------------\n");
1186*0aa77f6cSMauro Carvalho Chehab }
1187*0aa77f6cSMauro Carvalho Chehab 
1188*0aa77f6cSMauro Carvalho Chehab /*
1189*0aa77f6cSMauro Carvalho Chehab  * set mode is the function which controls the DSP.
1190*0aa77f6cSMauro Carvalho Chehab  * the restart parameter in struct s2255_mode should be set whenever
1191*0aa77f6cSMauro Carvalho Chehab  * the image size could change via color format, video system or image
1192*0aa77f6cSMauro Carvalho Chehab  * size.
1193*0aa77f6cSMauro Carvalho Chehab  * When the restart parameter is set, we sleep for ONE frame to allow the
1194*0aa77f6cSMauro Carvalho Chehab  * DSP time to get the new frame
1195*0aa77f6cSMauro Carvalho Chehab  */
1196*0aa77f6cSMauro Carvalho Chehab static int s2255_set_mode(struct s2255_channel *channel,
1197*0aa77f6cSMauro Carvalho Chehab 			  struct s2255_mode *mode)
1198*0aa77f6cSMauro Carvalho Chehab {
1199*0aa77f6cSMauro Carvalho Chehab 	int res;
1200*0aa77f6cSMauro Carvalho Chehab 	__le32 *buffer;
1201*0aa77f6cSMauro Carvalho Chehab 	unsigned long chn_rev;
1202*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
1203*0aa77f6cSMauro Carvalho Chehab 	chn_rev = G_chnmap[channel->idx];
1204*0aa77f6cSMauro Carvalho Chehab 	dprintk(3, "%s channel: %d\n", __func__, channel->idx);
1205*0aa77f6cSMauro Carvalho Chehab 	/* if JPEG, set the quality */
1206*0aa77f6cSMauro Carvalho Chehab 	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
1207*0aa77f6cSMauro Carvalho Chehab 		mode->color &= ~MASK_COLOR;
1208*0aa77f6cSMauro Carvalho Chehab 		mode->color |= COLOR_JPG;
1209*0aa77f6cSMauro Carvalho Chehab 		mode->color &= ~MASK_JPG_QUALITY;
1210*0aa77f6cSMauro Carvalho Chehab 		mode->color |= (channel->jc.quality << 8);
1211*0aa77f6cSMauro Carvalho Chehab 	}
1212*0aa77f6cSMauro Carvalho Chehab 	/* save the mode */
1213*0aa77f6cSMauro Carvalho Chehab 	channel->mode = *mode;
1214*0aa77f6cSMauro Carvalho Chehab 	channel->req_image_size = get_transfer_size(mode);
1215*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
1216*0aa77f6cSMauro Carvalho Chehab 	buffer = kzalloc(512, GFP_KERNEL);
1217*0aa77f6cSMauro Carvalho Chehab 	if (buffer == NULL) {
1218*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "out of mem\n");
1219*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
1220*0aa77f6cSMauro Carvalho Chehab 	}
1221*0aa77f6cSMauro Carvalho Chehab 	/* set the mode */
1222*0aa77f6cSMauro Carvalho Chehab 	buffer[0] = IN_DATA_TOKEN;
1223*0aa77f6cSMauro Carvalho Chehab 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
1224*0aa77f6cSMauro Carvalho Chehab 	buffer[2] = CMD_SET_MODE;
1225*0aa77f6cSMauro Carvalho Chehab 	memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
1226*0aa77f6cSMauro Carvalho Chehab 	channel->setmode_ready = 0;
1227*0aa77f6cSMauro Carvalho Chehab 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
1228*0aa77f6cSMauro Carvalho Chehab 	if (debug)
1229*0aa77f6cSMauro Carvalho Chehab 		s2255_print_cfg(dev, mode);
1230*0aa77f6cSMauro Carvalho Chehab 	kfree(buffer);
1231*0aa77f6cSMauro Carvalho Chehab 	/* wait at least 3 frames before continuing */
1232*0aa77f6cSMauro Carvalho Chehab 	if (mode->restart) {
1233*0aa77f6cSMauro Carvalho Chehab 		wait_event_timeout(channel->wait_setmode,
1234*0aa77f6cSMauro Carvalho Chehab 				   (channel->setmode_ready != 0),
1235*0aa77f6cSMauro Carvalho Chehab 				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
1236*0aa77f6cSMauro Carvalho Chehab 		if (channel->setmode_ready != 1) {
1237*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_DEBUG "s2255: no set mode response\n");
1238*0aa77f6cSMauro Carvalho Chehab 			res = -EFAULT;
1239*0aa77f6cSMauro Carvalho Chehab 		}
1240*0aa77f6cSMauro Carvalho Chehab 	}
1241*0aa77f6cSMauro Carvalho Chehab 	/* clear the restart flag */
1242*0aa77f6cSMauro Carvalho Chehab 	channel->mode.restart = 0;
1243*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
1244*0aa77f6cSMauro Carvalho Chehab 	return res;
1245*0aa77f6cSMauro Carvalho Chehab }
1246*0aa77f6cSMauro Carvalho Chehab 
1247*0aa77f6cSMauro Carvalho Chehab static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
1248*0aa77f6cSMauro Carvalho Chehab {
1249*0aa77f6cSMauro Carvalho Chehab 	int res;
1250*0aa77f6cSMauro Carvalho Chehab 	__le32 *buffer;
1251*0aa77f6cSMauro Carvalho Chehab 	u32 chn_rev;
1252*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
1253*0aa77f6cSMauro Carvalho Chehab 	chn_rev = G_chnmap[channel->idx];
1254*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s chan %d\n", __func__, channel->idx);
1255*0aa77f6cSMauro Carvalho Chehab 	buffer = kzalloc(512, GFP_KERNEL);
1256*0aa77f6cSMauro Carvalho Chehab 	if (buffer == NULL) {
1257*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "out of mem\n");
1258*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
1259*0aa77f6cSMauro Carvalho Chehab 	}
1260*0aa77f6cSMauro Carvalho Chehab 	/* form the get vid status command */
1261*0aa77f6cSMauro Carvalho Chehab 	buffer[0] = IN_DATA_TOKEN;
1262*0aa77f6cSMauro Carvalho Chehab 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
1263*0aa77f6cSMauro Carvalho Chehab 	buffer[2] = CMD_STATUS;
1264*0aa77f6cSMauro Carvalho Chehab 	*pstatus = 0;
1265*0aa77f6cSMauro Carvalho Chehab 	channel->vidstatus_ready = 0;
1266*0aa77f6cSMauro Carvalho Chehab 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
1267*0aa77f6cSMauro Carvalho Chehab 	kfree(buffer);
1268*0aa77f6cSMauro Carvalho Chehab 	wait_event_timeout(channel->wait_vidstatus,
1269*0aa77f6cSMauro Carvalho Chehab 			   (channel->vidstatus_ready != 0),
1270*0aa77f6cSMauro Carvalho Chehab 			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
1271*0aa77f6cSMauro Carvalho Chehab 	if (channel->vidstatus_ready != 1) {
1272*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_DEBUG "s2255: no vidstatus response\n");
1273*0aa77f6cSMauro Carvalho Chehab 		res = -EFAULT;
1274*0aa77f6cSMauro Carvalho Chehab 	}
1275*0aa77f6cSMauro Carvalho Chehab 	*pstatus = channel->vidstatus;
1276*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
1277*0aa77f6cSMauro Carvalho Chehab 	return res;
1278*0aa77f6cSMauro Carvalho Chehab }
1279*0aa77f6cSMauro Carvalho Chehab 
1280*0aa77f6cSMauro Carvalho Chehab static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
1281*0aa77f6cSMauro Carvalho Chehab {
1282*0aa77f6cSMauro Carvalho Chehab 	int res;
1283*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1284*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1285*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1286*0aa77f6cSMauro Carvalho Chehab 	int j;
1287*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s\n", __func__);
1288*0aa77f6cSMauro Carvalho Chehab 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1289*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "invalid fh type0\n");
1290*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1291*0aa77f6cSMauro Carvalho Chehab 	}
1292*0aa77f6cSMauro Carvalho Chehab 	if (i != fh->type) {
1293*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "invalid fh type1\n");
1294*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1295*0aa77f6cSMauro Carvalho Chehab 	}
1296*0aa77f6cSMauro Carvalho Chehab 
1297*0aa77f6cSMauro Carvalho Chehab 	if (!res_get(fh)) {
1298*0aa77f6cSMauro Carvalho Chehab 		s2255_dev_err(&dev->udev->dev, "stream busy\n");
1299*0aa77f6cSMauro Carvalho Chehab 		return -EBUSY;
1300*0aa77f6cSMauro Carvalho Chehab 	}
1301*0aa77f6cSMauro Carvalho Chehab 	channel->last_frame = -1;
1302*0aa77f6cSMauro Carvalho Chehab 	channel->bad_payload = 0;
1303*0aa77f6cSMauro Carvalho Chehab 	channel->cur_frame = 0;
1304*0aa77f6cSMauro Carvalho Chehab 	channel->frame_count = 0;
1305*0aa77f6cSMauro Carvalho Chehab 	for (j = 0; j < SYS_FRAMES; j++) {
1306*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[j].ulState = S2255_READ_IDLE;
1307*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[j].cur_size = 0;
1308*0aa77f6cSMauro Carvalho Chehab 	}
1309*0aa77f6cSMauro Carvalho Chehab 	res = videobuf_streamon(&fh->vb_vidq);
1310*0aa77f6cSMauro Carvalho Chehab 	if (res == 0) {
1311*0aa77f6cSMauro Carvalho Chehab 		s2255_start_acquire(channel);
1312*0aa77f6cSMauro Carvalho Chehab 		channel->b_acquire = 1;
1313*0aa77f6cSMauro Carvalho Chehab 	} else
1314*0aa77f6cSMauro Carvalho Chehab 		res_free(fh);
1315*0aa77f6cSMauro Carvalho Chehab 
1316*0aa77f6cSMauro Carvalho Chehab 	return res;
1317*0aa77f6cSMauro Carvalho Chehab }
1318*0aa77f6cSMauro Carvalho Chehab 
1319*0aa77f6cSMauro Carvalho Chehab static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
1320*0aa77f6cSMauro Carvalho Chehab {
1321*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1322*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
1323*0aa77f6cSMauro Carvalho Chehab 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1324*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "invalid fh type0\n");
1325*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1326*0aa77f6cSMauro Carvalho Chehab 	}
1327*0aa77f6cSMauro Carvalho Chehab 	if (i != fh->type) {
1328*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "invalid type i\n");
1329*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1330*0aa77f6cSMauro Carvalho Chehab 	}
1331*0aa77f6cSMauro Carvalho Chehab 	s2255_stop_acquire(fh->channel);
1332*0aa77f6cSMauro Carvalho Chehab 	videobuf_streamoff(&fh->vb_vidq);
1333*0aa77f6cSMauro Carvalho Chehab 	res_free(fh);
1334*0aa77f6cSMauro Carvalho Chehab 	return 0;
1335*0aa77f6cSMauro Carvalho Chehab }
1336*0aa77f6cSMauro Carvalho Chehab 
1337*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
1338*0aa77f6cSMauro Carvalho Chehab {
1339*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1340*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode mode;
1341*0aa77f6cSMauro Carvalho Chehab 	struct videobuf_queue *q = &fh->vb_vidq;
1342*0aa77f6cSMauro Carvalho Chehab 	int ret = 0;
1343*0aa77f6cSMauro Carvalho Chehab 	mutex_lock(&q->vb_lock);
1344*0aa77f6cSMauro Carvalho Chehab 	if (videobuf_queue_is_busy(q)) {
1345*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "queue busy\n");
1346*0aa77f6cSMauro Carvalho Chehab 		ret = -EBUSY;
1347*0aa77f6cSMauro Carvalho Chehab 		goto out_s_std;
1348*0aa77f6cSMauro Carvalho Chehab 	}
1349*0aa77f6cSMauro Carvalho Chehab 	if (res_locked(fh)) {
1350*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "can't change standard after started\n");
1351*0aa77f6cSMauro Carvalho Chehab 		ret = -EBUSY;
1352*0aa77f6cSMauro Carvalho Chehab 		goto out_s_std;
1353*0aa77f6cSMauro Carvalho Chehab 	}
1354*0aa77f6cSMauro Carvalho Chehab 	mode = fh->channel->mode;
1355*0aa77f6cSMauro Carvalho Chehab 	if (*i & V4L2_STD_NTSC) {
1356*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "%s NTSC\n", __func__);
1357*0aa77f6cSMauro Carvalho Chehab 		/* if changing format, reset frame decimation/intervals */
1358*0aa77f6cSMauro Carvalho Chehab 		if (mode.format != FORMAT_NTSC) {
1359*0aa77f6cSMauro Carvalho Chehab 			mode.restart = 1;
1360*0aa77f6cSMauro Carvalho Chehab 			mode.format = FORMAT_NTSC;
1361*0aa77f6cSMauro Carvalho Chehab 			mode.fdec = FDEC_1;
1362*0aa77f6cSMauro Carvalho Chehab 		}
1363*0aa77f6cSMauro Carvalho Chehab 	} else if (*i & V4L2_STD_PAL) {
1364*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "%s PAL\n", __func__);
1365*0aa77f6cSMauro Carvalho Chehab 		if (mode.format != FORMAT_PAL) {
1366*0aa77f6cSMauro Carvalho Chehab 			mode.restart = 1;
1367*0aa77f6cSMauro Carvalho Chehab 			mode.format = FORMAT_PAL;
1368*0aa77f6cSMauro Carvalho Chehab 			mode.fdec = FDEC_1;
1369*0aa77f6cSMauro Carvalho Chehab 		}
1370*0aa77f6cSMauro Carvalho Chehab 	} else {
1371*0aa77f6cSMauro Carvalho Chehab 		ret = -EINVAL;
1372*0aa77f6cSMauro Carvalho Chehab 	}
1373*0aa77f6cSMauro Carvalho Chehab 	if (mode.restart)
1374*0aa77f6cSMauro Carvalho Chehab 		s2255_set_mode(fh->channel, &mode);
1375*0aa77f6cSMauro Carvalho Chehab out_s_std:
1376*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&q->vb_lock);
1377*0aa77f6cSMauro Carvalho Chehab 	return ret;
1378*0aa77f6cSMauro Carvalho Chehab }
1379*0aa77f6cSMauro Carvalho Chehab 
1380*0aa77f6cSMauro Carvalho Chehab /* Sensoray 2255 is a multiple channel capture device.
1381*0aa77f6cSMauro Carvalho Chehab    It does not have a "crossbar" of inputs.
1382*0aa77f6cSMauro Carvalho Chehab    We use one V4L device per channel. The user must
1383*0aa77f6cSMauro Carvalho Chehab    be aware that certain combinations are not allowed.
1384*0aa77f6cSMauro Carvalho Chehab    For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
1385*0aa77f6cSMauro Carvalho Chehab    at once in color(you can do full fps on 4 channels with greyscale.
1386*0aa77f6cSMauro Carvalho Chehab */
1387*0aa77f6cSMauro Carvalho Chehab static int vidioc_enum_input(struct file *file, void *priv,
1388*0aa77f6cSMauro Carvalho Chehab 			     struct v4l2_input *inp)
1389*0aa77f6cSMauro Carvalho Chehab {
1390*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1391*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1392*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1393*0aa77f6cSMauro Carvalho Chehab 	u32 status = 0;
1394*0aa77f6cSMauro Carvalho Chehab 	if (inp->index != 0)
1395*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1396*0aa77f6cSMauro Carvalho Chehab 	inp->type = V4L2_INPUT_TYPE_CAMERA;
1397*0aa77f6cSMauro Carvalho Chehab 	inp->std = S2255_NORMS;
1398*0aa77f6cSMauro Carvalho Chehab 	inp->status = 0;
1399*0aa77f6cSMauro Carvalho Chehab 	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
1400*0aa77f6cSMauro Carvalho Chehab 		int rc;
1401*0aa77f6cSMauro Carvalho Chehab 		rc = s2255_cmd_status(fh->channel, &status);
1402*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
1403*0aa77f6cSMauro Carvalho Chehab 		if (rc == 0)
1404*0aa77f6cSMauro Carvalho Chehab 			inp->status =  (status & 0x01) ? 0
1405*0aa77f6cSMauro Carvalho Chehab 				: V4L2_IN_ST_NO_SIGNAL;
1406*0aa77f6cSMauro Carvalho Chehab 	}
1407*0aa77f6cSMauro Carvalho Chehab 	switch (dev->pid) {
1408*0aa77f6cSMauro Carvalho Chehab 	case 0x2255:
1409*0aa77f6cSMauro Carvalho Chehab 	default:
1410*0aa77f6cSMauro Carvalho Chehab 		strlcpy(inp->name, "Composite", sizeof(inp->name));
1411*0aa77f6cSMauro Carvalho Chehab 		break;
1412*0aa77f6cSMauro Carvalho Chehab 	case 0x2257:
1413*0aa77f6cSMauro Carvalho Chehab 		strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
1414*0aa77f6cSMauro Carvalho Chehab 			sizeof(inp->name));
1415*0aa77f6cSMauro Carvalho Chehab 		break;
1416*0aa77f6cSMauro Carvalho Chehab 	}
1417*0aa77f6cSMauro Carvalho Chehab 	return 0;
1418*0aa77f6cSMauro Carvalho Chehab }
1419*0aa77f6cSMauro Carvalho Chehab 
1420*0aa77f6cSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1421*0aa77f6cSMauro Carvalho Chehab {
1422*0aa77f6cSMauro Carvalho Chehab 	*i = 0;
1423*0aa77f6cSMauro Carvalho Chehab 	return 0;
1424*0aa77f6cSMauro Carvalho Chehab }
1425*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1426*0aa77f6cSMauro Carvalho Chehab {
1427*0aa77f6cSMauro Carvalho Chehab 	if (i > 0)
1428*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1429*0aa77f6cSMauro Carvalho Chehab 	return 0;
1430*0aa77f6cSMauro Carvalho Chehab }
1431*0aa77f6cSMauro Carvalho Chehab 
1432*0aa77f6cSMauro Carvalho Chehab /* --- controls ---------------------------------------------- */
1433*0aa77f6cSMauro Carvalho Chehab static int vidioc_queryctrl(struct file *file, void *priv,
1434*0aa77f6cSMauro Carvalho Chehab 			    struct v4l2_queryctrl *qc)
1435*0aa77f6cSMauro Carvalho Chehab {
1436*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1437*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1438*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1439*0aa77f6cSMauro Carvalho Chehab 	switch (qc->id) {
1440*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
1441*0aa77f6cSMauro Carvalho Chehab 		v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT);
1442*0aa77f6cSMauro Carvalho Chehab 		break;
1443*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
1444*0aa77f6cSMauro Carvalho Chehab 		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST);
1445*0aa77f6cSMauro Carvalho Chehab 		break;
1446*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
1447*0aa77f6cSMauro Carvalho Chehab 		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION);
1448*0aa77f6cSMauro Carvalho Chehab 		break;
1449*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_HUE:
1450*0aa77f6cSMauro Carvalho Chehab 		v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE);
1451*0aa77f6cSMauro Carvalho Chehab 		break;
1452*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_COLORFILTER:
1453*0aa77f6cSMauro Carvalho Chehab 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
1454*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1455*0aa77f6cSMauro Carvalho Chehab 		if ((dev->pid == 0x2257) && (channel->idx > 1))
1456*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1457*0aa77f6cSMauro Carvalho Chehab 		strlcpy(qc->name, "Color Filter", sizeof(qc->name));
1458*0aa77f6cSMauro Carvalho Chehab 		qc->type = V4L2_CTRL_TYPE_MENU;
1459*0aa77f6cSMauro Carvalho Chehab 		qc->minimum = 0;
1460*0aa77f6cSMauro Carvalho Chehab 		qc->maximum = 1;
1461*0aa77f6cSMauro Carvalho Chehab 		qc->step = 1;
1462*0aa77f6cSMauro Carvalho Chehab 		qc->default_value = 1;
1463*0aa77f6cSMauro Carvalho Chehab 		qc->flags = 0;
1464*0aa77f6cSMauro Carvalho Chehab 		break;
1465*0aa77f6cSMauro Carvalho Chehab 	default:
1466*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1467*0aa77f6cSMauro Carvalho Chehab 	}
1468*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, id %d\n", __func__, qc->id);
1469*0aa77f6cSMauro Carvalho Chehab 	return 0;
1470*0aa77f6cSMauro Carvalho Chehab }
1471*0aa77f6cSMauro Carvalho Chehab 
1472*0aa77f6cSMauro Carvalho Chehab static int vidioc_g_ctrl(struct file *file, void *priv,
1473*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_control *ctrl)
1474*0aa77f6cSMauro Carvalho Chehab {
1475*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1476*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1477*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1478*0aa77f6cSMauro Carvalho Chehab 	switch (ctrl->id) {
1479*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
1480*0aa77f6cSMauro Carvalho Chehab 		ctrl->value = channel->mode.bright;
1481*0aa77f6cSMauro Carvalho Chehab 		break;
1482*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
1483*0aa77f6cSMauro Carvalho Chehab 		ctrl->value = channel->mode.contrast;
1484*0aa77f6cSMauro Carvalho Chehab 		break;
1485*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
1486*0aa77f6cSMauro Carvalho Chehab 		ctrl->value = channel->mode.saturation;
1487*0aa77f6cSMauro Carvalho Chehab 		break;
1488*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_HUE:
1489*0aa77f6cSMauro Carvalho Chehab 		ctrl->value = channel->mode.hue;
1490*0aa77f6cSMauro Carvalho Chehab 		break;
1491*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_COLORFILTER:
1492*0aa77f6cSMauro Carvalho Chehab 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
1493*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1494*0aa77f6cSMauro Carvalho Chehab 		if ((dev->pid == 0x2257) && (channel->idx > 1))
1495*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1496*0aa77f6cSMauro Carvalho Chehab 		ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
1497*0aa77f6cSMauro Carvalho Chehab 		break;
1498*0aa77f6cSMauro Carvalho Chehab 	default:
1499*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1500*0aa77f6cSMauro Carvalho Chehab 	}
1501*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value);
1502*0aa77f6cSMauro Carvalho Chehab 	return 0;
1503*0aa77f6cSMauro Carvalho Chehab }
1504*0aa77f6cSMauro Carvalho Chehab 
1505*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_ctrl(struct file *file, void *priv,
1506*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_control *ctrl)
1507*0aa77f6cSMauro Carvalho Chehab {
1508*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1509*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1510*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
1511*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode mode;
1512*0aa77f6cSMauro Carvalho Chehab 	mode = channel->mode;
1513*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s\n", __func__);
1514*0aa77f6cSMauro Carvalho Chehab 	/* update the mode to the corresponding value */
1515*0aa77f6cSMauro Carvalho Chehab 	switch (ctrl->id) {
1516*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
1517*0aa77f6cSMauro Carvalho Chehab 		mode.bright = ctrl->value;
1518*0aa77f6cSMauro Carvalho Chehab 		break;
1519*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
1520*0aa77f6cSMauro Carvalho Chehab 		mode.contrast = ctrl->value;
1521*0aa77f6cSMauro Carvalho Chehab 		break;
1522*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_HUE:
1523*0aa77f6cSMauro Carvalho Chehab 		mode.hue = ctrl->value;
1524*0aa77f6cSMauro Carvalho Chehab 		break;
1525*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
1526*0aa77f6cSMauro Carvalho Chehab 		mode.saturation = ctrl->value;
1527*0aa77f6cSMauro Carvalho Chehab 		break;
1528*0aa77f6cSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_COLORFILTER:
1529*0aa77f6cSMauro Carvalho Chehab 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
1530*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1531*0aa77f6cSMauro Carvalho Chehab 		if ((dev->pid == 0x2257) && (channel->idx > 1))
1532*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1533*0aa77f6cSMauro Carvalho Chehab 		mode.color &= ~MASK_INPUT_TYPE;
1534*0aa77f6cSMauro Carvalho Chehab 		mode.color |= ((ctrl->value ? 0 : 1) << 16);
1535*0aa77f6cSMauro Carvalho Chehab 		break;
1536*0aa77f6cSMauro Carvalho Chehab 	default:
1537*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1538*0aa77f6cSMauro Carvalho Chehab 	}
1539*0aa77f6cSMauro Carvalho Chehab 	mode.restart = 0;
1540*0aa77f6cSMauro Carvalho Chehab 	/* set mode here.  Note: stream does not need restarted.
1541*0aa77f6cSMauro Carvalho Chehab 	   some V4L programs restart stream unnecessarily
1542*0aa77f6cSMauro Carvalho Chehab 	   after a s_crtl.
1543*0aa77f6cSMauro Carvalho Chehab 	*/
1544*0aa77f6cSMauro Carvalho Chehab 	s2255_set_mode(fh->channel, &mode);
1545*0aa77f6cSMauro Carvalho Chehab 	return 0;
1546*0aa77f6cSMauro Carvalho Chehab }
1547*0aa77f6cSMauro Carvalho Chehab 
1548*0aa77f6cSMauro Carvalho Chehab static int vidioc_g_jpegcomp(struct file *file, void *priv,
1549*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_jpegcompression *jc)
1550*0aa77f6cSMauro Carvalho Chehab {
1551*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1552*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1553*0aa77f6cSMauro Carvalho Chehab 	*jc = channel->jc;
1554*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
1555*0aa77f6cSMauro Carvalho Chehab 	return 0;
1556*0aa77f6cSMauro Carvalho Chehab }
1557*0aa77f6cSMauro Carvalho Chehab 
1558*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_jpegcomp(struct file *file, void *priv,
1559*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_jpegcompression *jc)
1560*0aa77f6cSMauro Carvalho Chehab {
1561*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1562*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1563*0aa77f6cSMauro Carvalho Chehab 	if (jc->quality < 0 || jc->quality > 100)
1564*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1565*0aa77f6cSMauro Carvalho Chehab 	channel->jc.quality = jc->quality;
1566*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
1567*0aa77f6cSMauro Carvalho Chehab 	return 0;
1568*0aa77f6cSMauro Carvalho Chehab }
1569*0aa77f6cSMauro Carvalho Chehab 
1570*0aa77f6cSMauro Carvalho Chehab static int vidioc_g_parm(struct file *file, void *priv,
1571*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_streamparm *sp)
1572*0aa77f6cSMauro Carvalho Chehab {
1573*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1574*0aa77f6cSMauro Carvalho Chehab 	__u32 def_num, def_dem;
1575*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1576*0aa77f6cSMauro Carvalho Chehab 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1577*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1578*0aa77f6cSMauro Carvalho Chehab 	memset(sp, 0, sizeof(struct v4l2_streamparm));
1579*0aa77f6cSMauro Carvalho Chehab 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1580*0aa77f6cSMauro Carvalho Chehab 	sp->parm.capture.capturemode = channel->cap_parm.capturemode;
1581*0aa77f6cSMauro Carvalho Chehab 	def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
1582*0aa77f6cSMauro Carvalho Chehab 	def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
1583*0aa77f6cSMauro Carvalho Chehab 	sp->parm.capture.timeperframe.denominator = def_dem;
1584*0aa77f6cSMauro Carvalho Chehab 	switch (channel->mode.fdec) {
1585*0aa77f6cSMauro Carvalho Chehab 	default:
1586*0aa77f6cSMauro Carvalho Chehab 	case FDEC_1:
1587*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num;
1588*0aa77f6cSMauro Carvalho Chehab 		break;
1589*0aa77f6cSMauro Carvalho Chehab 	case FDEC_2:
1590*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 2;
1591*0aa77f6cSMauro Carvalho Chehab 		break;
1592*0aa77f6cSMauro Carvalho Chehab 	case FDEC_3:
1593*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 3;
1594*0aa77f6cSMauro Carvalho Chehab 		break;
1595*0aa77f6cSMauro Carvalho Chehab 	case FDEC_5:
1596*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 5;
1597*0aa77f6cSMauro Carvalho Chehab 		break;
1598*0aa77f6cSMauro Carvalho Chehab 	}
1599*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
1600*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.capturemode,
1601*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator,
1602*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.denominator);
1603*0aa77f6cSMauro Carvalho Chehab 	return 0;
1604*0aa77f6cSMauro Carvalho Chehab }
1605*0aa77f6cSMauro Carvalho Chehab 
1606*0aa77f6cSMauro Carvalho Chehab static int vidioc_s_parm(struct file *file, void *priv,
1607*0aa77f6cSMauro Carvalho Chehab 			 struct v4l2_streamparm *sp)
1608*0aa77f6cSMauro Carvalho Chehab {
1609*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = priv;
1610*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1611*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode mode;
1612*0aa77f6cSMauro Carvalho Chehab 	int fdec = FDEC_1;
1613*0aa77f6cSMauro Carvalho Chehab 	__u32 def_num, def_dem;
1614*0aa77f6cSMauro Carvalho Chehab 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1615*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1616*0aa77f6cSMauro Carvalho Chehab 	mode = channel->mode;
1617*0aa77f6cSMauro Carvalho Chehab 	/* high quality capture mode requires a stream restart */
1618*0aa77f6cSMauro Carvalho Chehab 	if (channel->cap_parm.capturemode
1619*0aa77f6cSMauro Carvalho Chehab 	    != sp->parm.capture.capturemode && res_locked(fh))
1620*0aa77f6cSMauro Carvalho Chehab 		return -EBUSY;
1621*0aa77f6cSMauro Carvalho Chehab 	def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
1622*0aa77f6cSMauro Carvalho Chehab 	def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
1623*0aa77f6cSMauro Carvalho Chehab 	if (def_dem != sp->parm.capture.timeperframe.denominator)
1624*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num;
1625*0aa77f6cSMauro Carvalho Chehab 	else if (sp->parm.capture.timeperframe.numerator <= def_num)
1626*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num;
1627*0aa77f6cSMauro Carvalho Chehab 	else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) {
1628*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 2;
1629*0aa77f6cSMauro Carvalho Chehab 		fdec = FDEC_2;
1630*0aa77f6cSMauro Carvalho Chehab 	} else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) {
1631*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 3;
1632*0aa77f6cSMauro Carvalho Chehab 		fdec = FDEC_3;
1633*0aa77f6cSMauro Carvalho Chehab 	} else {
1634*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator = def_num * 5;
1635*0aa77f6cSMauro Carvalho Chehab 		fdec = FDEC_5;
1636*0aa77f6cSMauro Carvalho Chehab 	}
1637*0aa77f6cSMauro Carvalho Chehab 	mode.fdec = fdec;
1638*0aa77f6cSMauro Carvalho Chehab 	sp->parm.capture.timeperframe.denominator = def_dem;
1639*0aa77f6cSMauro Carvalho Chehab 	s2255_set_mode(channel, &mode);
1640*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
1641*0aa77f6cSMauro Carvalho Chehab 		__func__,
1642*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.capturemode,
1643*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.numerator,
1644*0aa77f6cSMauro Carvalho Chehab 		sp->parm.capture.timeperframe.denominator, fdec);
1645*0aa77f6cSMauro Carvalho Chehab 	return 0;
1646*0aa77f6cSMauro Carvalho Chehab }
1647*0aa77f6cSMauro Carvalho Chehab 
1648*0aa77f6cSMauro Carvalho Chehab static int vidioc_enum_frameintervals(struct file *file, void *priv,
1649*0aa77f6cSMauro Carvalho Chehab 			    struct v4l2_frmivalenum *fe)
1650*0aa77f6cSMauro Carvalho Chehab {
1651*0aa77f6cSMauro Carvalho Chehab 	int is_ntsc = 0;
1652*0aa77f6cSMauro Carvalho Chehab #define NUM_FRAME_ENUMS 4
1653*0aa77f6cSMauro Carvalho Chehab 	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
1654*0aa77f6cSMauro Carvalho Chehab 	if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS)
1655*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1656*0aa77f6cSMauro Carvalho Chehab 	switch (fe->width) {
1657*0aa77f6cSMauro Carvalho Chehab 	case 640:
1658*0aa77f6cSMauro Carvalho Chehab 		if (fe->height != 240 && fe->height != 480)
1659*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1660*0aa77f6cSMauro Carvalho Chehab 		is_ntsc = 1;
1661*0aa77f6cSMauro Carvalho Chehab 		break;
1662*0aa77f6cSMauro Carvalho Chehab 	case 320:
1663*0aa77f6cSMauro Carvalho Chehab 		if (fe->height != 240)
1664*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1665*0aa77f6cSMauro Carvalho Chehab 		is_ntsc = 1;
1666*0aa77f6cSMauro Carvalho Chehab 		break;
1667*0aa77f6cSMauro Carvalho Chehab 	case 704:
1668*0aa77f6cSMauro Carvalho Chehab 		if (fe->height != 288 && fe->height != 576)
1669*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1670*0aa77f6cSMauro Carvalho Chehab 		break;
1671*0aa77f6cSMauro Carvalho Chehab 	case 352:
1672*0aa77f6cSMauro Carvalho Chehab 		if (fe->height != 288)
1673*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
1674*0aa77f6cSMauro Carvalho Chehab 		break;
1675*0aa77f6cSMauro Carvalho Chehab 	default:
1676*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
1677*0aa77f6cSMauro Carvalho Chehab 	}
1678*0aa77f6cSMauro Carvalho Chehab 	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1679*0aa77f6cSMauro Carvalho Chehab 	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
1680*0aa77f6cSMauro Carvalho Chehab 	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
1681*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
1682*0aa77f6cSMauro Carvalho Chehab 		fe->discrete.denominator);
1683*0aa77f6cSMauro Carvalho Chehab 	return 0;
1684*0aa77f6cSMauro Carvalho Chehab }
1685*0aa77f6cSMauro Carvalho Chehab 
1686*0aa77f6cSMauro Carvalho Chehab static int __s2255_open(struct file *file)
1687*0aa77f6cSMauro Carvalho Chehab {
1688*0aa77f6cSMauro Carvalho Chehab 	struct video_device *vdev = video_devdata(file);
1689*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = video_drvdata(file);
1690*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
1691*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh;
1692*0aa77f6cSMauro Carvalho Chehab 	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1693*0aa77f6cSMauro Carvalho Chehab 	int state;
1694*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "s2255: open called (dev=%s)\n",
1695*0aa77f6cSMauro Carvalho Chehab 		video_device_node_name(vdev));
1696*0aa77f6cSMauro Carvalho Chehab 	state = atomic_read(&dev->fw_data->fw_state);
1697*0aa77f6cSMauro Carvalho Chehab 	switch (state) {
1698*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_DISCONNECTING:
1699*0aa77f6cSMauro Carvalho Chehab 		return -ENODEV;
1700*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_FAILED:
1701*0aa77f6cSMauro Carvalho Chehab 		s2255_dev_err(&dev->udev->dev,
1702*0aa77f6cSMauro Carvalho Chehab 			"firmware load failed. retrying.\n");
1703*0aa77f6cSMauro Carvalho Chehab 		s2255_fwload_start(dev, 1);
1704*0aa77f6cSMauro Carvalho Chehab 		wait_event_timeout(dev->fw_data->wait_fw,
1705*0aa77f6cSMauro Carvalho Chehab 				   ((atomic_read(&dev->fw_data->fw_state)
1706*0aa77f6cSMauro Carvalho Chehab 				     == S2255_FW_SUCCESS) ||
1707*0aa77f6cSMauro Carvalho Chehab 				    (atomic_read(&dev->fw_data->fw_state)
1708*0aa77f6cSMauro Carvalho Chehab 				     == S2255_FW_DISCONNECTING)),
1709*0aa77f6cSMauro Carvalho Chehab 				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
1710*0aa77f6cSMauro Carvalho Chehab 		/* state may have changed, re-read */
1711*0aa77f6cSMauro Carvalho Chehab 		state = atomic_read(&dev->fw_data->fw_state);
1712*0aa77f6cSMauro Carvalho Chehab 		break;
1713*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_NOTLOADED:
1714*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_LOADED_DSPWAIT:
1715*0aa77f6cSMauro Carvalho Chehab 		/* give S2255_LOAD_TIMEOUT time for firmware to load in case
1716*0aa77f6cSMauro Carvalho Chehab 		   driver loaded and then device immediately opened */
1717*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "%s waiting for firmware load\n", __func__);
1718*0aa77f6cSMauro Carvalho Chehab 		wait_event_timeout(dev->fw_data->wait_fw,
1719*0aa77f6cSMauro Carvalho Chehab 				   ((atomic_read(&dev->fw_data->fw_state)
1720*0aa77f6cSMauro Carvalho Chehab 				     == S2255_FW_SUCCESS) ||
1721*0aa77f6cSMauro Carvalho Chehab 				    (atomic_read(&dev->fw_data->fw_state)
1722*0aa77f6cSMauro Carvalho Chehab 				     == S2255_FW_DISCONNECTING)),
1723*0aa77f6cSMauro Carvalho Chehab 				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
1724*0aa77f6cSMauro Carvalho Chehab 		/* state may have changed, re-read */
1725*0aa77f6cSMauro Carvalho Chehab 		state = atomic_read(&dev->fw_data->fw_state);
1726*0aa77f6cSMauro Carvalho Chehab 		break;
1727*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_SUCCESS:
1728*0aa77f6cSMauro Carvalho Chehab 	default:
1729*0aa77f6cSMauro Carvalho Chehab 		break;
1730*0aa77f6cSMauro Carvalho Chehab 	}
1731*0aa77f6cSMauro Carvalho Chehab 	/* state may have changed in above switch statement */
1732*0aa77f6cSMauro Carvalho Chehab 	switch (state) {
1733*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_SUCCESS:
1734*0aa77f6cSMauro Carvalho Chehab 		break;
1735*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_FAILED:
1736*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "2255 firmware load failed.\n");
1737*0aa77f6cSMauro Carvalho Chehab 		return -ENODEV;
1738*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_DISCONNECTING:
1739*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "%s: disconnecting\n", __func__);
1740*0aa77f6cSMauro Carvalho Chehab 		return -ENODEV;
1741*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_LOADED_DSPWAIT:
1742*0aa77f6cSMauro Carvalho Chehab 	case S2255_FW_NOTLOADED:
1743*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "%s: firmware not loaded yet"
1744*0aa77f6cSMauro Carvalho Chehab 		       "please try again later\n",
1745*0aa77f6cSMauro Carvalho Chehab 		       __func__);
1746*0aa77f6cSMauro Carvalho Chehab 		/*
1747*0aa77f6cSMauro Carvalho Chehab 		 * Timeout on firmware load means device unusable.
1748*0aa77f6cSMauro Carvalho Chehab 		 * Set firmware failure state.
1749*0aa77f6cSMauro Carvalho Chehab 		 * On next s2255_open the firmware will be reloaded.
1750*0aa77f6cSMauro Carvalho Chehab 		 */
1751*0aa77f6cSMauro Carvalho Chehab 		atomic_set(&dev->fw_data->fw_state,
1752*0aa77f6cSMauro Carvalho Chehab 			   S2255_FW_FAILED);
1753*0aa77f6cSMauro Carvalho Chehab 		return -EAGAIN;
1754*0aa77f6cSMauro Carvalho Chehab 	default:
1755*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "%s: unknown state\n", __func__);
1756*0aa77f6cSMauro Carvalho Chehab 		return -EFAULT;
1757*0aa77f6cSMauro Carvalho Chehab 	}
1758*0aa77f6cSMauro Carvalho Chehab 	/* allocate + initialize per filehandle data */
1759*0aa77f6cSMauro Carvalho Chehab 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1760*0aa77f6cSMauro Carvalho Chehab 	if (NULL == fh)
1761*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
1762*0aa77f6cSMauro Carvalho Chehab 	file->private_data = fh;
1763*0aa77f6cSMauro Carvalho Chehab 	fh->dev = dev;
1764*0aa77f6cSMauro Carvalho Chehab 	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1765*0aa77f6cSMauro Carvalho Chehab 	fh->channel = channel;
1766*0aa77f6cSMauro Carvalho Chehab 	if (!channel->configured) {
1767*0aa77f6cSMauro Carvalho Chehab 		/* configure channel to default state */
1768*0aa77f6cSMauro Carvalho Chehab 		channel->fmt = &formats[0];
1769*0aa77f6cSMauro Carvalho Chehab 		s2255_set_mode(channel, &channel->mode);
1770*0aa77f6cSMauro Carvalho Chehab 		channel->configured = 1;
1771*0aa77f6cSMauro Carvalho Chehab 	}
1772*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s: dev=%s type=%s\n", __func__,
1773*0aa77f6cSMauro Carvalho Chehab 		video_device_node_name(vdev), v4l2_type_names[type]);
1774*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
1775*0aa77f6cSMauro Carvalho Chehab 		(unsigned long)fh, (unsigned long)dev,
1776*0aa77f6cSMauro Carvalho Chehab 		(unsigned long)&channel->vidq);
1777*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s: list_empty active=%d\n", __func__,
1778*0aa77f6cSMauro Carvalho Chehab 		list_empty(&channel->vidq.active));
1779*0aa77f6cSMauro Carvalho Chehab 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
1780*0aa77f6cSMauro Carvalho Chehab 				    NULL, &dev->slock,
1781*0aa77f6cSMauro Carvalho Chehab 				    fh->type,
1782*0aa77f6cSMauro Carvalho Chehab 				    V4L2_FIELD_INTERLACED,
1783*0aa77f6cSMauro Carvalho Chehab 				    sizeof(struct s2255_buffer),
1784*0aa77f6cSMauro Carvalho Chehab 				    fh, vdev->lock);
1785*0aa77f6cSMauro Carvalho Chehab 	return 0;
1786*0aa77f6cSMauro Carvalho Chehab }
1787*0aa77f6cSMauro Carvalho Chehab 
1788*0aa77f6cSMauro Carvalho Chehab static int s2255_open(struct file *file)
1789*0aa77f6cSMauro Carvalho Chehab {
1790*0aa77f6cSMauro Carvalho Chehab 	struct video_device *vdev = video_devdata(file);
1791*0aa77f6cSMauro Carvalho Chehab 	int ret;
1792*0aa77f6cSMauro Carvalho Chehab 
1793*0aa77f6cSMauro Carvalho Chehab 	if (mutex_lock_interruptible(vdev->lock))
1794*0aa77f6cSMauro Carvalho Chehab 		return -ERESTARTSYS;
1795*0aa77f6cSMauro Carvalho Chehab 	ret = __s2255_open(file);
1796*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(vdev->lock);
1797*0aa77f6cSMauro Carvalho Chehab 	return ret;
1798*0aa77f6cSMauro Carvalho Chehab }
1799*0aa77f6cSMauro Carvalho Chehab 
1800*0aa77f6cSMauro Carvalho Chehab static unsigned int s2255_poll(struct file *file,
1801*0aa77f6cSMauro Carvalho Chehab 			       struct poll_table_struct *wait)
1802*0aa77f6cSMauro Carvalho Chehab {
1803*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = file->private_data;
1804*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1805*0aa77f6cSMauro Carvalho Chehab 	int rc;
1806*0aa77f6cSMauro Carvalho Chehab 	dprintk(100, "%s\n", __func__);
1807*0aa77f6cSMauro Carvalho Chehab 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1808*0aa77f6cSMauro Carvalho Chehab 		return POLLERR;
1809*0aa77f6cSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
1810*0aa77f6cSMauro Carvalho Chehab 	rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
1811*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
1812*0aa77f6cSMauro Carvalho Chehab 	return rc;
1813*0aa77f6cSMauro Carvalho Chehab }
1814*0aa77f6cSMauro Carvalho Chehab 
1815*0aa77f6cSMauro Carvalho Chehab static void s2255_destroy(struct s2255_dev *dev)
1816*0aa77f6cSMauro Carvalho Chehab {
1817*0aa77f6cSMauro Carvalho Chehab 	/* board shutdown stops the read pipe if it is running */
1818*0aa77f6cSMauro Carvalho Chehab 	s2255_board_shutdown(dev);
1819*0aa77f6cSMauro Carvalho Chehab 	/* make sure firmware still not trying to load */
1820*0aa77f6cSMauro Carvalho Chehab 	del_timer(&dev->timer);  /* only started in .probe and .open */
1821*0aa77f6cSMauro Carvalho Chehab 	if (dev->fw_data->fw_urb) {
1822*0aa77f6cSMauro Carvalho Chehab 		usb_kill_urb(dev->fw_data->fw_urb);
1823*0aa77f6cSMauro Carvalho Chehab 		usb_free_urb(dev->fw_data->fw_urb);
1824*0aa77f6cSMauro Carvalho Chehab 		dev->fw_data->fw_urb = NULL;
1825*0aa77f6cSMauro Carvalho Chehab 	}
1826*0aa77f6cSMauro Carvalho Chehab 	release_firmware(dev->fw_data->fw);
1827*0aa77f6cSMauro Carvalho Chehab 	kfree(dev->fw_data->pfw_data);
1828*0aa77f6cSMauro Carvalho Chehab 	kfree(dev->fw_data);
1829*0aa77f6cSMauro Carvalho Chehab 	/* reset the DSP so firmware can be reloaded next time */
1830*0aa77f6cSMauro Carvalho Chehab 	s2255_reset_dsppower(dev);
1831*0aa77f6cSMauro Carvalho Chehab 	mutex_destroy(&dev->lock);
1832*0aa77f6cSMauro Carvalho Chehab 	usb_put_dev(dev->udev);
1833*0aa77f6cSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
1834*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s", __func__);
1835*0aa77f6cSMauro Carvalho Chehab 	kfree(dev);
1836*0aa77f6cSMauro Carvalho Chehab }
1837*0aa77f6cSMauro Carvalho Chehab 
1838*0aa77f6cSMauro Carvalho Chehab static int s2255_release(struct file *file)
1839*0aa77f6cSMauro Carvalho Chehab {
1840*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = file->private_data;
1841*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1842*0aa77f6cSMauro Carvalho Chehab 	struct video_device *vdev = video_devdata(file);
1843*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel = fh->channel;
1844*0aa77f6cSMauro Carvalho Chehab 	if (!dev)
1845*0aa77f6cSMauro Carvalho Chehab 		return -ENODEV;
1846*0aa77f6cSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
1847*0aa77f6cSMauro Carvalho Chehab 	/* turn off stream */
1848*0aa77f6cSMauro Carvalho Chehab 	if (res_check(fh)) {
1849*0aa77f6cSMauro Carvalho Chehab 		if (channel->b_acquire)
1850*0aa77f6cSMauro Carvalho Chehab 			s2255_stop_acquire(fh->channel);
1851*0aa77f6cSMauro Carvalho Chehab 		videobuf_streamoff(&fh->vb_vidq);
1852*0aa77f6cSMauro Carvalho Chehab 		res_free(fh);
1853*0aa77f6cSMauro Carvalho Chehab 	}
1854*0aa77f6cSMauro Carvalho Chehab 	videobuf_mmap_free(&fh->vb_vidq);
1855*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
1856*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
1857*0aa77f6cSMauro Carvalho Chehab 	kfree(fh);
1858*0aa77f6cSMauro Carvalho Chehab 	return 0;
1859*0aa77f6cSMauro Carvalho Chehab }
1860*0aa77f6cSMauro Carvalho Chehab 
1861*0aa77f6cSMauro Carvalho Chehab static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
1862*0aa77f6cSMauro Carvalho Chehab {
1863*0aa77f6cSMauro Carvalho Chehab 	struct s2255_fh *fh = file->private_data;
1864*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = fh->dev;
1865*0aa77f6cSMauro Carvalho Chehab 	int ret;
1866*0aa77f6cSMauro Carvalho Chehab 
1867*0aa77f6cSMauro Carvalho Chehab 	if (!fh)
1868*0aa77f6cSMauro Carvalho Chehab 		return -ENODEV;
1869*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
1870*0aa77f6cSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dev->lock))
1871*0aa77f6cSMauro Carvalho Chehab 		return -ERESTARTSYS;
1872*0aa77f6cSMauro Carvalho Chehab 	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
1873*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
1874*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
1875*0aa77f6cSMauro Carvalho Chehab 		(unsigned long)vma->vm_start,
1876*0aa77f6cSMauro Carvalho Chehab 		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
1877*0aa77f6cSMauro Carvalho Chehab 	return ret;
1878*0aa77f6cSMauro Carvalho Chehab }
1879*0aa77f6cSMauro Carvalho Chehab 
1880*0aa77f6cSMauro Carvalho Chehab static const struct v4l2_file_operations s2255_fops_v4l = {
1881*0aa77f6cSMauro Carvalho Chehab 	.owner = THIS_MODULE,
1882*0aa77f6cSMauro Carvalho Chehab 	.open = s2255_open,
1883*0aa77f6cSMauro Carvalho Chehab 	.release = s2255_release,
1884*0aa77f6cSMauro Carvalho Chehab 	.poll = s2255_poll,
1885*0aa77f6cSMauro Carvalho Chehab 	.unlocked_ioctl = video_ioctl2,	/* V4L2 ioctl handler */
1886*0aa77f6cSMauro Carvalho Chehab 	.mmap = s2255_mmap_v4l,
1887*0aa77f6cSMauro Carvalho Chehab };
1888*0aa77f6cSMauro Carvalho Chehab 
1889*0aa77f6cSMauro Carvalho Chehab static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
1890*0aa77f6cSMauro Carvalho Chehab 	.vidioc_querymenu = vidioc_querymenu,
1891*0aa77f6cSMauro Carvalho Chehab 	.vidioc_querycap = vidioc_querycap,
1892*0aa77f6cSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1893*0aa77f6cSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1894*0aa77f6cSMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1895*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1896*0aa77f6cSMauro Carvalho Chehab 	.vidioc_reqbufs = vidioc_reqbufs,
1897*0aa77f6cSMauro Carvalho Chehab 	.vidioc_querybuf = vidioc_querybuf,
1898*0aa77f6cSMauro Carvalho Chehab 	.vidioc_qbuf = vidioc_qbuf,
1899*0aa77f6cSMauro Carvalho Chehab 	.vidioc_dqbuf = vidioc_dqbuf,
1900*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_std = vidioc_s_std,
1901*0aa77f6cSMauro Carvalho Chehab 	.vidioc_enum_input = vidioc_enum_input,
1902*0aa77f6cSMauro Carvalho Chehab 	.vidioc_g_input = vidioc_g_input,
1903*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_input = vidioc_s_input,
1904*0aa77f6cSMauro Carvalho Chehab 	.vidioc_queryctrl = vidioc_queryctrl,
1905*0aa77f6cSMauro Carvalho Chehab 	.vidioc_g_ctrl = vidioc_g_ctrl,
1906*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_ctrl = vidioc_s_ctrl,
1907*0aa77f6cSMauro Carvalho Chehab 	.vidioc_streamon = vidioc_streamon,
1908*0aa77f6cSMauro Carvalho Chehab 	.vidioc_streamoff = vidioc_streamoff,
1909*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
1910*0aa77f6cSMauro Carvalho Chehab 	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
1911*0aa77f6cSMauro Carvalho Chehab 	.vidioc_s_parm = vidioc_s_parm,
1912*0aa77f6cSMauro Carvalho Chehab 	.vidioc_g_parm = vidioc_g_parm,
1913*0aa77f6cSMauro Carvalho Chehab 	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
1914*0aa77f6cSMauro Carvalho Chehab };
1915*0aa77f6cSMauro Carvalho Chehab 
1916*0aa77f6cSMauro Carvalho Chehab static void s2255_video_device_release(struct video_device *vdev)
1917*0aa77f6cSMauro Carvalho Chehab {
1918*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
1919*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s, chnls: %d \n", __func__,
1920*0aa77f6cSMauro Carvalho Chehab 		atomic_read(&dev->num_channels));
1921*0aa77f6cSMauro Carvalho Chehab 	if (atomic_dec_and_test(&dev->num_channels))
1922*0aa77f6cSMauro Carvalho Chehab 		s2255_destroy(dev);
1923*0aa77f6cSMauro Carvalho Chehab 	return;
1924*0aa77f6cSMauro Carvalho Chehab }
1925*0aa77f6cSMauro Carvalho Chehab 
1926*0aa77f6cSMauro Carvalho Chehab static struct video_device template = {
1927*0aa77f6cSMauro Carvalho Chehab 	.name = "s2255v",
1928*0aa77f6cSMauro Carvalho Chehab 	.fops = &s2255_fops_v4l,
1929*0aa77f6cSMauro Carvalho Chehab 	.ioctl_ops = &s2255_ioctl_ops,
1930*0aa77f6cSMauro Carvalho Chehab 	.release = s2255_video_device_release,
1931*0aa77f6cSMauro Carvalho Chehab 	.tvnorms = S2255_NORMS,
1932*0aa77f6cSMauro Carvalho Chehab 	.current_norm = V4L2_STD_NTSC_M,
1933*0aa77f6cSMauro Carvalho Chehab };
1934*0aa77f6cSMauro Carvalho Chehab 
1935*0aa77f6cSMauro Carvalho Chehab static int s2255_probe_v4l(struct s2255_dev *dev)
1936*0aa77f6cSMauro Carvalho Chehab {
1937*0aa77f6cSMauro Carvalho Chehab 	int ret;
1938*0aa77f6cSMauro Carvalho Chehab 	int i;
1939*0aa77f6cSMauro Carvalho Chehab 	int cur_nr = video_nr;
1940*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel;
1941*0aa77f6cSMauro Carvalho Chehab 	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
1942*0aa77f6cSMauro Carvalho Chehab 	if (ret)
1943*0aa77f6cSMauro Carvalho Chehab 		return ret;
1944*0aa77f6cSMauro Carvalho Chehab 	/* initialize all video 4 linux */
1945*0aa77f6cSMauro Carvalho Chehab 	/* register 4 video devices */
1946*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < MAX_CHANNELS; i++) {
1947*0aa77f6cSMauro Carvalho Chehab 		channel = &dev->channel[i];
1948*0aa77f6cSMauro Carvalho Chehab 		INIT_LIST_HEAD(&channel->vidq.active);
1949*0aa77f6cSMauro Carvalho Chehab 		channel->vidq.dev = dev;
1950*0aa77f6cSMauro Carvalho Chehab 		/* register 4 video devices */
1951*0aa77f6cSMauro Carvalho Chehab 		channel->vdev = template;
1952*0aa77f6cSMauro Carvalho Chehab 		channel->vdev.lock = &dev->lock;
1953*0aa77f6cSMauro Carvalho Chehab 		channel->vdev.v4l2_dev = &dev->v4l2_dev;
1954*0aa77f6cSMauro Carvalho Chehab 		video_set_drvdata(&channel->vdev, channel);
1955*0aa77f6cSMauro Carvalho Chehab 		if (video_nr == -1)
1956*0aa77f6cSMauro Carvalho Chehab 			ret = video_register_device(&channel->vdev,
1957*0aa77f6cSMauro Carvalho Chehab 						    VFL_TYPE_GRABBER,
1958*0aa77f6cSMauro Carvalho Chehab 						    video_nr);
1959*0aa77f6cSMauro Carvalho Chehab 		else
1960*0aa77f6cSMauro Carvalho Chehab 			ret = video_register_device(&channel->vdev,
1961*0aa77f6cSMauro Carvalho Chehab 						    VFL_TYPE_GRABBER,
1962*0aa77f6cSMauro Carvalho Chehab 						    cur_nr + i);
1963*0aa77f6cSMauro Carvalho Chehab 
1964*0aa77f6cSMauro Carvalho Chehab 		if (ret) {
1965*0aa77f6cSMauro Carvalho Chehab 			dev_err(&dev->udev->dev,
1966*0aa77f6cSMauro Carvalho Chehab 				"failed to register video device!\n");
1967*0aa77f6cSMauro Carvalho Chehab 			break;
1968*0aa77f6cSMauro Carvalho Chehab 		}
1969*0aa77f6cSMauro Carvalho Chehab 		atomic_inc(&dev->num_channels);
1970*0aa77f6cSMauro Carvalho Chehab 		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
1971*0aa77f6cSMauro Carvalho Chehab 			  video_device_node_name(&channel->vdev));
1972*0aa77f6cSMauro Carvalho Chehab 
1973*0aa77f6cSMauro Carvalho Chehab 	}
1974*0aa77f6cSMauro Carvalho Chehab 	printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
1975*0aa77f6cSMauro Carvalho Chehab 	       S2255_VERSION);
1976*0aa77f6cSMauro Carvalho Chehab 	/* if no channels registered, return error and probe will fail*/
1977*0aa77f6cSMauro Carvalho Chehab 	if (atomic_read(&dev->num_channels) == 0) {
1978*0aa77f6cSMauro Carvalho Chehab 		v4l2_device_unregister(&dev->v4l2_dev);
1979*0aa77f6cSMauro Carvalho Chehab 		return ret;
1980*0aa77f6cSMauro Carvalho Chehab 	}
1981*0aa77f6cSMauro Carvalho Chehab 	if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
1982*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_WARNING "s2255: Not all channels available.\n");
1983*0aa77f6cSMauro Carvalho Chehab 	return 0;
1984*0aa77f6cSMauro Carvalho Chehab }
1985*0aa77f6cSMauro Carvalho Chehab 
1986*0aa77f6cSMauro Carvalho Chehab /* this function moves the usb stream read pipe data
1987*0aa77f6cSMauro Carvalho Chehab  * into the system buffers.
1988*0aa77f6cSMauro Carvalho Chehab  * returns 0 on success, EAGAIN if more data to process( call this
1989*0aa77f6cSMauro Carvalho Chehab  * function again).
1990*0aa77f6cSMauro Carvalho Chehab  *
1991*0aa77f6cSMauro Carvalho Chehab  * Received frame structure:
1992*0aa77f6cSMauro Carvalho Chehab  * bytes 0-3:  marker : 0x2255DA4AL (S2255_MARKER_FRAME)
1993*0aa77f6cSMauro Carvalho Chehab  * bytes 4-7:  channel: 0-3
1994*0aa77f6cSMauro Carvalho Chehab  * bytes 8-11: payload size:  size of the frame
1995*0aa77f6cSMauro Carvalho Chehab  * bytes 12-payloadsize+12:  frame data
1996*0aa77f6cSMauro Carvalho Chehab  */
1997*0aa77f6cSMauro Carvalho Chehab static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
1998*0aa77f6cSMauro Carvalho Chehab {
1999*0aa77f6cSMauro Carvalho Chehab 	char *pdest;
2000*0aa77f6cSMauro Carvalho Chehab 	u32 offset = 0;
2001*0aa77f6cSMauro Carvalho Chehab 	int bframe = 0;
2002*0aa77f6cSMauro Carvalho Chehab 	char *psrc;
2003*0aa77f6cSMauro Carvalho Chehab 	unsigned long copy_size;
2004*0aa77f6cSMauro Carvalho Chehab 	unsigned long size;
2005*0aa77f6cSMauro Carvalho Chehab 	s32 idx = -1;
2006*0aa77f6cSMauro Carvalho Chehab 	struct s2255_framei *frm;
2007*0aa77f6cSMauro Carvalho Chehab 	unsigned char *pdata;
2008*0aa77f6cSMauro Carvalho Chehab 	struct s2255_channel *channel;
2009*0aa77f6cSMauro Carvalho Chehab 	dprintk(100, "buffer to user\n");
2010*0aa77f6cSMauro Carvalho Chehab 	channel = &dev->channel[dev->cc];
2011*0aa77f6cSMauro Carvalho Chehab 	idx = channel->cur_frame;
2012*0aa77f6cSMauro Carvalho Chehab 	frm = &channel->buffer.frame[idx];
2013*0aa77f6cSMauro Carvalho Chehab 	if (frm->ulState == S2255_READ_IDLE) {
2014*0aa77f6cSMauro Carvalho Chehab 		int jj;
2015*0aa77f6cSMauro Carvalho Chehab 		unsigned int cc;
2016*0aa77f6cSMauro Carvalho Chehab 		__le32 *pdword; /*data from dsp is little endian */
2017*0aa77f6cSMauro Carvalho Chehab 		int payload;
2018*0aa77f6cSMauro Carvalho Chehab 		/* search for marker codes */
2019*0aa77f6cSMauro Carvalho Chehab 		pdata = (unsigned char *)pipe_info->transfer_buffer;
2020*0aa77f6cSMauro Carvalho Chehab 		pdword = (__le32 *)pdata;
2021*0aa77f6cSMauro Carvalho Chehab 		for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
2022*0aa77f6cSMauro Carvalho Chehab 			switch (*pdword) {
2023*0aa77f6cSMauro Carvalho Chehab 			case S2255_MARKER_FRAME:
2024*0aa77f6cSMauro Carvalho Chehab 				dprintk(4, "found frame marker at offset:"
2025*0aa77f6cSMauro Carvalho Chehab 					" %d [%x %x]\n", jj, pdata[0],
2026*0aa77f6cSMauro Carvalho Chehab 					pdata[1]);
2027*0aa77f6cSMauro Carvalho Chehab 				offset = jj + PREFIX_SIZE;
2028*0aa77f6cSMauro Carvalho Chehab 				bframe = 1;
2029*0aa77f6cSMauro Carvalho Chehab 				cc = le32_to_cpu(pdword[1]);
2030*0aa77f6cSMauro Carvalho Chehab 				if (cc >= MAX_CHANNELS) {
2031*0aa77f6cSMauro Carvalho Chehab 					printk(KERN_ERR
2032*0aa77f6cSMauro Carvalho Chehab 					       "bad channel\n");
2033*0aa77f6cSMauro Carvalho Chehab 					return -EINVAL;
2034*0aa77f6cSMauro Carvalho Chehab 				}
2035*0aa77f6cSMauro Carvalho Chehab 				/* reverse it */
2036*0aa77f6cSMauro Carvalho Chehab 				dev->cc = G_chnmap[cc];
2037*0aa77f6cSMauro Carvalho Chehab 				channel = &dev->channel[dev->cc];
2038*0aa77f6cSMauro Carvalho Chehab 				payload =  le32_to_cpu(pdword[3]);
2039*0aa77f6cSMauro Carvalho Chehab 				if (payload > channel->req_image_size) {
2040*0aa77f6cSMauro Carvalho Chehab 					channel->bad_payload++;
2041*0aa77f6cSMauro Carvalho Chehab 					/* discard the bad frame */
2042*0aa77f6cSMauro Carvalho Chehab 					return -EINVAL;
2043*0aa77f6cSMauro Carvalho Chehab 				}
2044*0aa77f6cSMauro Carvalho Chehab 				channel->pkt_size = payload;
2045*0aa77f6cSMauro Carvalho Chehab 				channel->jpg_size = le32_to_cpu(pdword[4]);
2046*0aa77f6cSMauro Carvalho Chehab 				break;
2047*0aa77f6cSMauro Carvalho Chehab 			case S2255_MARKER_RESPONSE:
2048*0aa77f6cSMauro Carvalho Chehab 
2049*0aa77f6cSMauro Carvalho Chehab 				pdata += DEF_USB_BLOCK;
2050*0aa77f6cSMauro Carvalho Chehab 				jj += DEF_USB_BLOCK;
2051*0aa77f6cSMauro Carvalho Chehab 				if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
2052*0aa77f6cSMauro Carvalho Chehab 					break;
2053*0aa77f6cSMauro Carvalho Chehab 				cc = G_chnmap[le32_to_cpu(pdword[1])];
2054*0aa77f6cSMauro Carvalho Chehab 				if (cc >= MAX_CHANNELS)
2055*0aa77f6cSMauro Carvalho Chehab 					break;
2056*0aa77f6cSMauro Carvalho Chehab 				channel = &dev->channel[cc];
2057*0aa77f6cSMauro Carvalho Chehab 				switch (pdword[2]) {
2058*0aa77f6cSMauro Carvalho Chehab 				case S2255_RESPONSE_SETMODE:
2059*0aa77f6cSMauro Carvalho Chehab 					/* check if channel valid */
2060*0aa77f6cSMauro Carvalho Chehab 					/* set mode ready */
2061*0aa77f6cSMauro Carvalho Chehab 					channel->setmode_ready = 1;
2062*0aa77f6cSMauro Carvalho Chehab 					wake_up(&channel->wait_setmode);
2063*0aa77f6cSMauro Carvalho Chehab 					dprintk(5, "setmode ready %d\n", cc);
2064*0aa77f6cSMauro Carvalho Chehab 					break;
2065*0aa77f6cSMauro Carvalho Chehab 				case S2255_RESPONSE_FW:
2066*0aa77f6cSMauro Carvalho Chehab 					dev->chn_ready |= (1 << cc);
2067*0aa77f6cSMauro Carvalho Chehab 					if ((dev->chn_ready & 0x0f) != 0x0f)
2068*0aa77f6cSMauro Carvalho Chehab 						break;
2069*0aa77f6cSMauro Carvalho Chehab 					/* all channels ready */
2070*0aa77f6cSMauro Carvalho Chehab 					printk(KERN_INFO "s2255: fw loaded\n");
2071*0aa77f6cSMauro Carvalho Chehab 					atomic_set(&dev->fw_data->fw_state,
2072*0aa77f6cSMauro Carvalho Chehab 						   S2255_FW_SUCCESS);
2073*0aa77f6cSMauro Carvalho Chehab 					wake_up(&dev->fw_data->wait_fw);
2074*0aa77f6cSMauro Carvalho Chehab 					break;
2075*0aa77f6cSMauro Carvalho Chehab 				case S2255_RESPONSE_STATUS:
2076*0aa77f6cSMauro Carvalho Chehab 					channel->vidstatus = le32_to_cpu(pdword[3]);
2077*0aa77f6cSMauro Carvalho Chehab 					channel->vidstatus_ready = 1;
2078*0aa77f6cSMauro Carvalho Chehab 					wake_up(&channel->wait_vidstatus);
2079*0aa77f6cSMauro Carvalho Chehab 					dprintk(5, "got vidstatus %x chan %d\n",
2080*0aa77f6cSMauro Carvalho Chehab 						le32_to_cpu(pdword[3]), cc);
2081*0aa77f6cSMauro Carvalho Chehab 					break;
2082*0aa77f6cSMauro Carvalho Chehab 				default:
2083*0aa77f6cSMauro Carvalho Chehab 					printk(KERN_INFO "s2255 unknown resp\n");
2084*0aa77f6cSMauro Carvalho Chehab 				}
2085*0aa77f6cSMauro Carvalho Chehab 			default:
2086*0aa77f6cSMauro Carvalho Chehab 				pdata++;
2087*0aa77f6cSMauro Carvalho Chehab 				break;
2088*0aa77f6cSMauro Carvalho Chehab 			}
2089*0aa77f6cSMauro Carvalho Chehab 			if (bframe)
2090*0aa77f6cSMauro Carvalho Chehab 				break;
2091*0aa77f6cSMauro Carvalho Chehab 		} /* for */
2092*0aa77f6cSMauro Carvalho Chehab 		if (!bframe)
2093*0aa77f6cSMauro Carvalho Chehab 			return -EINVAL;
2094*0aa77f6cSMauro Carvalho Chehab 	}
2095*0aa77f6cSMauro Carvalho Chehab 	channel = &dev->channel[dev->cc];
2096*0aa77f6cSMauro Carvalho Chehab 	idx = channel->cur_frame;
2097*0aa77f6cSMauro Carvalho Chehab 	frm = &channel->buffer.frame[idx];
2098*0aa77f6cSMauro Carvalho Chehab 	/* search done.  now find out if should be acquiring on this channel */
2099*0aa77f6cSMauro Carvalho Chehab 	if (!channel->b_acquire) {
2100*0aa77f6cSMauro Carvalho Chehab 		/* we found a frame, but this channel is turned off */
2101*0aa77f6cSMauro Carvalho Chehab 		frm->ulState = S2255_READ_IDLE;
2102*0aa77f6cSMauro Carvalho Chehab 		return -EINVAL;
2103*0aa77f6cSMauro Carvalho Chehab 	}
2104*0aa77f6cSMauro Carvalho Chehab 
2105*0aa77f6cSMauro Carvalho Chehab 	if (frm->ulState == S2255_READ_IDLE) {
2106*0aa77f6cSMauro Carvalho Chehab 		frm->ulState = S2255_READ_FRAME;
2107*0aa77f6cSMauro Carvalho Chehab 		frm->cur_size = 0;
2108*0aa77f6cSMauro Carvalho Chehab 	}
2109*0aa77f6cSMauro Carvalho Chehab 
2110*0aa77f6cSMauro Carvalho Chehab 	/* skip the marker 512 bytes (and offset if out of sync) */
2111*0aa77f6cSMauro Carvalho Chehab 	psrc = (u8 *)pipe_info->transfer_buffer + offset;
2112*0aa77f6cSMauro Carvalho Chehab 
2113*0aa77f6cSMauro Carvalho Chehab 
2114*0aa77f6cSMauro Carvalho Chehab 	if (frm->lpvbits == NULL) {
2115*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
2116*0aa77f6cSMauro Carvalho Chehab 			frm, dev, dev->cc, idx);
2117*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2118*0aa77f6cSMauro Carvalho Chehab 	}
2119*0aa77f6cSMauro Carvalho Chehab 
2120*0aa77f6cSMauro Carvalho Chehab 	pdest = frm->lpvbits + frm->cur_size;
2121*0aa77f6cSMauro Carvalho Chehab 
2122*0aa77f6cSMauro Carvalho Chehab 	copy_size = (pipe_info->cur_transfer_size - offset);
2123*0aa77f6cSMauro Carvalho Chehab 
2124*0aa77f6cSMauro Carvalho Chehab 	size = channel->pkt_size - PREFIX_SIZE;
2125*0aa77f6cSMauro Carvalho Chehab 
2126*0aa77f6cSMauro Carvalho Chehab 	/* sanity check on pdest */
2127*0aa77f6cSMauro Carvalho Chehab 	if ((copy_size + frm->cur_size) < channel->req_image_size)
2128*0aa77f6cSMauro Carvalho Chehab 		memcpy(pdest, psrc, copy_size);
2129*0aa77f6cSMauro Carvalho Chehab 
2130*0aa77f6cSMauro Carvalho Chehab 	frm->cur_size += copy_size;
2131*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
2132*0aa77f6cSMauro Carvalho Chehab 
2133*0aa77f6cSMauro Carvalho Chehab 	if (frm->cur_size >= size) {
2134*0aa77f6cSMauro Carvalho Chehab 		dprintk(2, "****************[%d]Buffer[%d]full*************\n",
2135*0aa77f6cSMauro Carvalho Chehab 			dev->cc, idx);
2136*0aa77f6cSMauro Carvalho Chehab 		channel->last_frame = channel->cur_frame;
2137*0aa77f6cSMauro Carvalho Chehab 		channel->cur_frame++;
2138*0aa77f6cSMauro Carvalho Chehab 		/* end of system frame ring buffer, start at zero */
2139*0aa77f6cSMauro Carvalho Chehab 		if ((channel->cur_frame == SYS_FRAMES) ||
2140*0aa77f6cSMauro Carvalho Chehab 		    (channel->cur_frame == channel->buffer.dwFrames))
2141*0aa77f6cSMauro Carvalho Chehab 			channel->cur_frame = 0;
2142*0aa77f6cSMauro Carvalho Chehab 		/* frame ready */
2143*0aa77f6cSMauro Carvalho Chehab 		if (channel->b_acquire)
2144*0aa77f6cSMauro Carvalho Chehab 			s2255_got_frame(channel, channel->jpg_size);
2145*0aa77f6cSMauro Carvalho Chehab 		channel->frame_count++;
2146*0aa77f6cSMauro Carvalho Chehab 		frm->ulState = S2255_READ_IDLE;
2147*0aa77f6cSMauro Carvalho Chehab 		frm->cur_size = 0;
2148*0aa77f6cSMauro Carvalho Chehab 
2149*0aa77f6cSMauro Carvalho Chehab 	}
2150*0aa77f6cSMauro Carvalho Chehab 	/* done successfully */
2151*0aa77f6cSMauro Carvalho Chehab 	return 0;
2152*0aa77f6cSMauro Carvalho Chehab }
2153*0aa77f6cSMauro Carvalho Chehab 
2154*0aa77f6cSMauro Carvalho Chehab static void s2255_read_video_callback(struct s2255_dev *dev,
2155*0aa77f6cSMauro Carvalho Chehab 				      struct s2255_pipeinfo *pipe_info)
2156*0aa77f6cSMauro Carvalho Chehab {
2157*0aa77f6cSMauro Carvalho Chehab 	int res;
2158*0aa77f6cSMauro Carvalho Chehab 	dprintk(50, "callback read video \n");
2159*0aa77f6cSMauro Carvalho Chehab 
2160*0aa77f6cSMauro Carvalho Chehab 	if (dev->cc >= MAX_CHANNELS) {
2161*0aa77f6cSMauro Carvalho Chehab 		dev->cc = 0;
2162*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "invalid channel\n");
2163*0aa77f6cSMauro Carvalho Chehab 		return;
2164*0aa77f6cSMauro Carvalho Chehab 	}
2165*0aa77f6cSMauro Carvalho Chehab 	/* otherwise copy to the system buffers */
2166*0aa77f6cSMauro Carvalho Chehab 	res = save_frame(dev, pipe_info);
2167*0aa77f6cSMauro Carvalho Chehab 	if (res != 0)
2168*0aa77f6cSMauro Carvalho Chehab 		dprintk(4, "s2255: read callback failed\n");
2169*0aa77f6cSMauro Carvalho Chehab 
2170*0aa77f6cSMauro Carvalho Chehab 	dprintk(50, "callback read video done\n");
2171*0aa77f6cSMauro Carvalho Chehab 	return;
2172*0aa77f6cSMauro Carvalho Chehab }
2173*0aa77f6cSMauro Carvalho Chehab 
2174*0aa77f6cSMauro Carvalho Chehab static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
2175*0aa77f6cSMauro Carvalho Chehab 			     u16 Index, u16 Value, void *TransferBuffer,
2176*0aa77f6cSMauro Carvalho Chehab 			     s32 TransferBufferLength, int bOut)
2177*0aa77f6cSMauro Carvalho Chehab {
2178*0aa77f6cSMauro Carvalho Chehab 	int r;
2179*0aa77f6cSMauro Carvalho Chehab 	if (!bOut) {
2180*0aa77f6cSMauro Carvalho Chehab 		r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
2181*0aa77f6cSMauro Carvalho Chehab 				    Request,
2182*0aa77f6cSMauro Carvalho Chehab 				    USB_TYPE_VENDOR | USB_RECIP_DEVICE |
2183*0aa77f6cSMauro Carvalho Chehab 				    USB_DIR_IN,
2184*0aa77f6cSMauro Carvalho Chehab 				    Value, Index, TransferBuffer,
2185*0aa77f6cSMauro Carvalho Chehab 				    TransferBufferLength, HZ * 5);
2186*0aa77f6cSMauro Carvalho Chehab 	} else {
2187*0aa77f6cSMauro Carvalho Chehab 		r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
2188*0aa77f6cSMauro Carvalho Chehab 				    Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
2189*0aa77f6cSMauro Carvalho Chehab 				    Value, Index, TransferBuffer,
2190*0aa77f6cSMauro Carvalho Chehab 				    TransferBufferLength, HZ * 5);
2191*0aa77f6cSMauro Carvalho Chehab 	}
2192*0aa77f6cSMauro Carvalho Chehab 	return r;
2193*0aa77f6cSMauro Carvalho Chehab }
2194*0aa77f6cSMauro Carvalho Chehab 
2195*0aa77f6cSMauro Carvalho Chehab /*
2196*0aa77f6cSMauro Carvalho Chehab  * retrieve FX2 firmware version. future use.
2197*0aa77f6cSMauro Carvalho Chehab  * @param dev pointer to device extension
2198*0aa77f6cSMauro Carvalho Chehab  * @return -1 for fail, else returns firmware version as an int(16 bits)
2199*0aa77f6cSMauro Carvalho Chehab  */
2200*0aa77f6cSMauro Carvalho Chehab static int s2255_get_fx2fw(struct s2255_dev *dev)
2201*0aa77f6cSMauro Carvalho Chehab {
2202*0aa77f6cSMauro Carvalho Chehab 	int fw;
2203*0aa77f6cSMauro Carvalho Chehab 	int ret;
2204*0aa77f6cSMauro Carvalho Chehab 	unsigned char transBuffer[64];
2205*0aa77f6cSMauro Carvalho Chehab 	ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
2206*0aa77f6cSMauro Carvalho Chehab 			       S2255_VR_IN);
2207*0aa77f6cSMauro Carvalho Chehab 	if (ret < 0)
2208*0aa77f6cSMauro Carvalho Chehab 		dprintk(2, "get fw error: %x\n", ret);
2209*0aa77f6cSMauro Carvalho Chehab 	fw = transBuffer[0] + (transBuffer[1] << 8);
2210*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
2211*0aa77f6cSMauro Carvalho Chehab 	return fw;
2212*0aa77f6cSMauro Carvalho Chehab }
2213*0aa77f6cSMauro Carvalho Chehab 
2214*0aa77f6cSMauro Carvalho Chehab /*
2215*0aa77f6cSMauro Carvalho Chehab  * Create the system ring buffer to copy frames into from the
2216*0aa77f6cSMauro Carvalho Chehab  * usb read pipe.
2217*0aa77f6cSMauro Carvalho Chehab  */
2218*0aa77f6cSMauro Carvalho Chehab static int s2255_create_sys_buffers(struct s2255_channel *channel)
2219*0aa77f6cSMauro Carvalho Chehab {
2220*0aa77f6cSMauro Carvalho Chehab 	unsigned long i;
2221*0aa77f6cSMauro Carvalho Chehab 	unsigned long reqsize;
2222*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "create sys buffers\n");
2223*0aa77f6cSMauro Carvalho Chehab 	channel->buffer.dwFrames = SYS_FRAMES;
2224*0aa77f6cSMauro Carvalho Chehab 	/* always allocate maximum size(PAL) for system buffers */
2225*0aa77f6cSMauro Carvalho Chehab 	reqsize = SYS_FRAMES_MAXSIZE;
2226*0aa77f6cSMauro Carvalho Chehab 
2227*0aa77f6cSMauro Carvalho Chehab 	if (reqsize > SYS_FRAMES_MAXSIZE)
2228*0aa77f6cSMauro Carvalho Chehab 		reqsize = SYS_FRAMES_MAXSIZE;
2229*0aa77f6cSMauro Carvalho Chehab 
2230*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < SYS_FRAMES; i++) {
2231*0aa77f6cSMauro Carvalho Chehab 		/* allocate the frames */
2232*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
2233*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
2234*0aa77f6cSMauro Carvalho Chehab 			&channel->buffer.frame[i], channel->idx, i,
2235*0aa77f6cSMauro Carvalho Chehab 			channel->buffer.frame[i].lpvbits);
2236*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[i].size = reqsize;
2237*0aa77f6cSMauro Carvalho Chehab 		if (channel->buffer.frame[i].lpvbits == NULL) {
2238*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_INFO "out of memory.  using less frames\n");
2239*0aa77f6cSMauro Carvalho Chehab 			channel->buffer.dwFrames = i;
2240*0aa77f6cSMauro Carvalho Chehab 			break;
2241*0aa77f6cSMauro Carvalho Chehab 		}
2242*0aa77f6cSMauro Carvalho Chehab 	}
2243*0aa77f6cSMauro Carvalho Chehab 
2244*0aa77f6cSMauro Carvalho Chehab 	/* make sure internal states are set */
2245*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < SYS_FRAMES; i++) {
2246*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[i].ulState = 0;
2247*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[i].cur_size = 0;
2248*0aa77f6cSMauro Carvalho Chehab 	}
2249*0aa77f6cSMauro Carvalho Chehab 
2250*0aa77f6cSMauro Carvalho Chehab 	channel->cur_frame = 0;
2251*0aa77f6cSMauro Carvalho Chehab 	channel->last_frame = -1;
2252*0aa77f6cSMauro Carvalho Chehab 	return 0;
2253*0aa77f6cSMauro Carvalho Chehab }
2254*0aa77f6cSMauro Carvalho Chehab 
2255*0aa77f6cSMauro Carvalho Chehab static int s2255_release_sys_buffers(struct s2255_channel *channel)
2256*0aa77f6cSMauro Carvalho Chehab {
2257*0aa77f6cSMauro Carvalho Chehab 	unsigned long i;
2258*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "release sys buffers\n");
2259*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < SYS_FRAMES; i++) {
2260*0aa77f6cSMauro Carvalho Chehab 		if (channel->buffer.frame[i].lpvbits) {
2261*0aa77f6cSMauro Carvalho Chehab 			dprintk(1, "vfree %p\n",
2262*0aa77f6cSMauro Carvalho Chehab 				channel->buffer.frame[i].lpvbits);
2263*0aa77f6cSMauro Carvalho Chehab 			vfree(channel->buffer.frame[i].lpvbits);
2264*0aa77f6cSMauro Carvalho Chehab 		}
2265*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[i].lpvbits = NULL;
2266*0aa77f6cSMauro Carvalho Chehab 	}
2267*0aa77f6cSMauro Carvalho Chehab 	return 0;
2268*0aa77f6cSMauro Carvalho Chehab }
2269*0aa77f6cSMauro Carvalho Chehab 
2270*0aa77f6cSMauro Carvalho Chehab static int s2255_board_init(struct s2255_dev *dev)
2271*0aa77f6cSMauro Carvalho Chehab {
2272*0aa77f6cSMauro Carvalho Chehab 	struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
2273*0aa77f6cSMauro Carvalho Chehab 	int fw_ver;
2274*0aa77f6cSMauro Carvalho Chehab 	int j;
2275*0aa77f6cSMauro Carvalho Chehab 	struct s2255_pipeinfo *pipe = &dev->pipe;
2276*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "board init: %p", dev);
2277*0aa77f6cSMauro Carvalho Chehab 	memset(pipe, 0, sizeof(*pipe));
2278*0aa77f6cSMauro Carvalho Chehab 	pipe->dev = dev;
2279*0aa77f6cSMauro Carvalho Chehab 	pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
2280*0aa77f6cSMauro Carvalho Chehab 	pipe->max_transfer_size = S2255_USB_XFER_SIZE;
2281*0aa77f6cSMauro Carvalho Chehab 
2282*0aa77f6cSMauro Carvalho Chehab 	pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
2283*0aa77f6cSMauro Carvalho Chehab 					GFP_KERNEL);
2284*0aa77f6cSMauro Carvalho Chehab 	if (pipe->transfer_buffer == NULL) {
2285*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "out of memory!\n");
2286*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2287*0aa77f6cSMauro Carvalho Chehab 	}
2288*0aa77f6cSMauro Carvalho Chehab 	/* query the firmware */
2289*0aa77f6cSMauro Carvalho Chehab 	fw_ver = s2255_get_fx2fw(dev);
2290*0aa77f6cSMauro Carvalho Chehab 
2291*0aa77f6cSMauro Carvalho Chehab 	printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
2292*0aa77f6cSMauro Carvalho Chehab 	       (fw_ver >> 8) & 0xff,
2293*0aa77f6cSMauro Carvalho Chehab 	       fw_ver & 0xff);
2294*0aa77f6cSMauro Carvalho Chehab 
2295*0aa77f6cSMauro Carvalho Chehab 	if (fw_ver < S2255_CUR_USB_FWVER)
2296*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "s2255: newer USB firmware available\n");
2297*0aa77f6cSMauro Carvalho Chehab 
2298*0aa77f6cSMauro Carvalho Chehab 	for (j = 0; j < MAX_CHANNELS; j++) {
2299*0aa77f6cSMauro Carvalho Chehab 		struct s2255_channel *channel = &dev->channel[j];
2300*0aa77f6cSMauro Carvalho Chehab 		channel->b_acquire = 0;
2301*0aa77f6cSMauro Carvalho Chehab 		channel->mode = mode_def;
2302*0aa77f6cSMauro Carvalho Chehab 		if (dev->pid == 0x2257 && j > 1)
2303*0aa77f6cSMauro Carvalho Chehab 			channel->mode.color |= (1 << 16);
2304*0aa77f6cSMauro Carvalho Chehab 		channel->jc.quality = S2255_DEF_JPEG_QUAL;
2305*0aa77f6cSMauro Carvalho Chehab 		channel->width = LINE_SZ_4CIFS_NTSC;
2306*0aa77f6cSMauro Carvalho Chehab 		channel->height = NUM_LINES_4CIFS_NTSC * 2;
2307*0aa77f6cSMauro Carvalho Chehab 		channel->fmt = &formats[0];
2308*0aa77f6cSMauro Carvalho Chehab 		channel->mode.restart = 1;
2309*0aa77f6cSMauro Carvalho Chehab 		channel->req_image_size = get_transfer_size(&mode_def);
2310*0aa77f6cSMauro Carvalho Chehab 		channel->frame_count = 0;
2311*0aa77f6cSMauro Carvalho Chehab 		/* create the system buffers */
2312*0aa77f6cSMauro Carvalho Chehab 		s2255_create_sys_buffers(channel);
2313*0aa77f6cSMauro Carvalho Chehab 	}
2314*0aa77f6cSMauro Carvalho Chehab 	/* start read pipe */
2315*0aa77f6cSMauro Carvalho Chehab 	s2255_start_readpipe(dev);
2316*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s: success\n", __func__);
2317*0aa77f6cSMauro Carvalho Chehab 	return 0;
2318*0aa77f6cSMauro Carvalho Chehab }
2319*0aa77f6cSMauro Carvalho Chehab 
2320*0aa77f6cSMauro Carvalho Chehab static int s2255_board_shutdown(struct s2255_dev *dev)
2321*0aa77f6cSMauro Carvalho Chehab {
2322*0aa77f6cSMauro Carvalho Chehab 	u32 i;
2323*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "%s: dev: %p", __func__,  dev);
2324*0aa77f6cSMauro Carvalho Chehab 
2325*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < MAX_CHANNELS; i++) {
2326*0aa77f6cSMauro Carvalho Chehab 		if (dev->channel[i].b_acquire)
2327*0aa77f6cSMauro Carvalho Chehab 			s2255_stop_acquire(&dev->channel[i]);
2328*0aa77f6cSMauro Carvalho Chehab 	}
2329*0aa77f6cSMauro Carvalho Chehab 	s2255_stop_readpipe(dev);
2330*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < MAX_CHANNELS; i++)
2331*0aa77f6cSMauro Carvalho Chehab 		s2255_release_sys_buffers(&dev->channel[i]);
2332*0aa77f6cSMauro Carvalho Chehab 	/* release transfer buffer */
2333*0aa77f6cSMauro Carvalho Chehab 	kfree(dev->pipe.transfer_buffer);
2334*0aa77f6cSMauro Carvalho Chehab 	return 0;
2335*0aa77f6cSMauro Carvalho Chehab }
2336*0aa77f6cSMauro Carvalho Chehab 
2337*0aa77f6cSMauro Carvalho Chehab static void read_pipe_completion(struct urb *purb)
2338*0aa77f6cSMauro Carvalho Chehab {
2339*0aa77f6cSMauro Carvalho Chehab 	struct s2255_pipeinfo *pipe_info;
2340*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev;
2341*0aa77f6cSMauro Carvalho Chehab 	int status;
2342*0aa77f6cSMauro Carvalho Chehab 	int pipe;
2343*0aa77f6cSMauro Carvalho Chehab 	pipe_info = purb->context;
2344*0aa77f6cSMauro Carvalho Chehab 	dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
2345*0aa77f6cSMauro Carvalho Chehab 		purb->status);
2346*0aa77f6cSMauro Carvalho Chehab 	if (pipe_info == NULL) {
2347*0aa77f6cSMauro Carvalho Chehab 		dev_err(&purb->dev->dev, "no context!\n");
2348*0aa77f6cSMauro Carvalho Chehab 		return;
2349*0aa77f6cSMauro Carvalho Chehab 	}
2350*0aa77f6cSMauro Carvalho Chehab 
2351*0aa77f6cSMauro Carvalho Chehab 	dev = pipe_info->dev;
2352*0aa77f6cSMauro Carvalho Chehab 	if (dev == NULL) {
2353*0aa77f6cSMauro Carvalho Chehab 		dev_err(&purb->dev->dev, "no context!\n");
2354*0aa77f6cSMauro Carvalho Chehab 		return;
2355*0aa77f6cSMauro Carvalho Chehab 	}
2356*0aa77f6cSMauro Carvalho Chehab 	status = purb->status;
2357*0aa77f6cSMauro Carvalho Chehab 	/* if shutting down, do not resubmit, exit immediately */
2358*0aa77f6cSMauro Carvalho Chehab 	if (status == -ESHUTDOWN) {
2359*0aa77f6cSMauro Carvalho Chehab 		dprintk(2, "%s: err shutdown\n", __func__);
2360*0aa77f6cSMauro Carvalho Chehab 		pipe_info->err_count++;
2361*0aa77f6cSMauro Carvalho Chehab 		return;
2362*0aa77f6cSMauro Carvalho Chehab 	}
2363*0aa77f6cSMauro Carvalho Chehab 
2364*0aa77f6cSMauro Carvalho Chehab 	if (pipe_info->state == 0) {
2365*0aa77f6cSMauro Carvalho Chehab 		dprintk(2, "%s: exiting USB pipe", __func__);
2366*0aa77f6cSMauro Carvalho Chehab 		return;
2367*0aa77f6cSMauro Carvalho Chehab 	}
2368*0aa77f6cSMauro Carvalho Chehab 
2369*0aa77f6cSMauro Carvalho Chehab 	if (status == 0)
2370*0aa77f6cSMauro Carvalho Chehab 		s2255_read_video_callback(dev, pipe_info);
2371*0aa77f6cSMauro Carvalho Chehab 	else {
2372*0aa77f6cSMauro Carvalho Chehab 		pipe_info->err_count++;
2373*0aa77f6cSMauro Carvalho Chehab 		dprintk(1, "%s: failed URB %d\n", __func__, status);
2374*0aa77f6cSMauro Carvalho Chehab 	}
2375*0aa77f6cSMauro Carvalho Chehab 
2376*0aa77f6cSMauro Carvalho Chehab 	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
2377*0aa77f6cSMauro Carvalho Chehab 	/* reuse urb */
2378*0aa77f6cSMauro Carvalho Chehab 	usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
2379*0aa77f6cSMauro Carvalho Chehab 			  pipe,
2380*0aa77f6cSMauro Carvalho Chehab 			  pipe_info->transfer_buffer,
2381*0aa77f6cSMauro Carvalho Chehab 			  pipe_info->cur_transfer_size,
2382*0aa77f6cSMauro Carvalho Chehab 			  read_pipe_completion, pipe_info);
2383*0aa77f6cSMauro Carvalho Chehab 
2384*0aa77f6cSMauro Carvalho Chehab 	if (pipe_info->state != 0) {
2385*0aa77f6cSMauro Carvalho Chehab 		if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
2386*0aa77f6cSMauro Carvalho Chehab 			dev_err(&dev->udev->dev, "error submitting urb\n");
2387*0aa77f6cSMauro Carvalho Chehab 		}
2388*0aa77f6cSMauro Carvalho Chehab 	} else {
2389*0aa77f6cSMauro Carvalho Chehab 		dprintk(2, "%s :complete state 0\n", __func__);
2390*0aa77f6cSMauro Carvalho Chehab 	}
2391*0aa77f6cSMauro Carvalho Chehab 	return;
2392*0aa77f6cSMauro Carvalho Chehab }
2393*0aa77f6cSMauro Carvalho Chehab 
2394*0aa77f6cSMauro Carvalho Chehab static int s2255_start_readpipe(struct s2255_dev *dev)
2395*0aa77f6cSMauro Carvalho Chehab {
2396*0aa77f6cSMauro Carvalho Chehab 	int pipe;
2397*0aa77f6cSMauro Carvalho Chehab 	int retval;
2398*0aa77f6cSMauro Carvalho Chehab 	struct s2255_pipeinfo *pipe_info = &dev->pipe;
2399*0aa77f6cSMauro Carvalho Chehab 	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
2400*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
2401*0aa77f6cSMauro Carvalho Chehab 	pipe_info->state = 1;
2402*0aa77f6cSMauro Carvalho Chehab 	pipe_info->err_count = 0;
2403*0aa77f6cSMauro Carvalho Chehab 	pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
2404*0aa77f6cSMauro Carvalho Chehab 	if (!pipe_info->stream_urb) {
2405*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev,
2406*0aa77f6cSMauro Carvalho Chehab 			"ReadStream: Unable to alloc URB\n");
2407*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2408*0aa77f6cSMauro Carvalho Chehab 	}
2409*0aa77f6cSMauro Carvalho Chehab 	/* transfer buffer allocated in board_init */
2410*0aa77f6cSMauro Carvalho Chehab 	usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
2411*0aa77f6cSMauro Carvalho Chehab 			  pipe,
2412*0aa77f6cSMauro Carvalho Chehab 			  pipe_info->transfer_buffer,
2413*0aa77f6cSMauro Carvalho Chehab 			  pipe_info->cur_transfer_size,
2414*0aa77f6cSMauro Carvalho Chehab 			  read_pipe_completion, pipe_info);
2415*0aa77f6cSMauro Carvalho Chehab 	retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
2416*0aa77f6cSMauro Carvalho Chehab 	if (retval) {
2417*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "s2255: start read pipe failed\n");
2418*0aa77f6cSMauro Carvalho Chehab 		return retval;
2419*0aa77f6cSMauro Carvalho Chehab 	}
2420*0aa77f6cSMauro Carvalho Chehab 	return 0;
2421*0aa77f6cSMauro Carvalho Chehab }
2422*0aa77f6cSMauro Carvalho Chehab 
2423*0aa77f6cSMauro Carvalho Chehab /* starts acquisition process */
2424*0aa77f6cSMauro Carvalho Chehab static int s2255_start_acquire(struct s2255_channel *channel)
2425*0aa77f6cSMauro Carvalho Chehab {
2426*0aa77f6cSMauro Carvalho Chehab 	unsigned char *buffer;
2427*0aa77f6cSMauro Carvalho Chehab 	int res;
2428*0aa77f6cSMauro Carvalho Chehab 	unsigned long chn_rev;
2429*0aa77f6cSMauro Carvalho Chehab 	int j;
2430*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
2431*0aa77f6cSMauro Carvalho Chehab 	chn_rev = G_chnmap[channel->idx];
2432*0aa77f6cSMauro Carvalho Chehab 	buffer = kzalloc(512, GFP_KERNEL);
2433*0aa77f6cSMauro Carvalho Chehab 	if (buffer == NULL) {
2434*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "out of mem\n");
2435*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2436*0aa77f6cSMauro Carvalho Chehab 	}
2437*0aa77f6cSMauro Carvalho Chehab 
2438*0aa77f6cSMauro Carvalho Chehab 	channel->last_frame = -1;
2439*0aa77f6cSMauro Carvalho Chehab 	channel->bad_payload = 0;
2440*0aa77f6cSMauro Carvalho Chehab 	channel->cur_frame = 0;
2441*0aa77f6cSMauro Carvalho Chehab 	for (j = 0; j < SYS_FRAMES; j++) {
2442*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[j].ulState = 0;
2443*0aa77f6cSMauro Carvalho Chehab 		channel->buffer.frame[j].cur_size = 0;
2444*0aa77f6cSMauro Carvalho Chehab 	}
2445*0aa77f6cSMauro Carvalho Chehab 
2446*0aa77f6cSMauro Carvalho Chehab 	/* send the start command */
2447*0aa77f6cSMauro Carvalho Chehab 	*(__le32 *) buffer = IN_DATA_TOKEN;
2448*0aa77f6cSMauro Carvalho Chehab 	*((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
2449*0aa77f6cSMauro Carvalho Chehab 	*((__le32 *) buffer + 2) = CMD_START;
2450*0aa77f6cSMauro Carvalho Chehab 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
2451*0aa77f6cSMauro Carvalho Chehab 	if (res != 0)
2452*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "CMD_START error\n");
2453*0aa77f6cSMauro Carvalho Chehab 
2454*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
2455*0aa77f6cSMauro Carvalho Chehab 	kfree(buffer);
2456*0aa77f6cSMauro Carvalho Chehab 	return 0;
2457*0aa77f6cSMauro Carvalho Chehab }
2458*0aa77f6cSMauro Carvalho Chehab 
2459*0aa77f6cSMauro Carvalho Chehab static int s2255_stop_acquire(struct s2255_channel *channel)
2460*0aa77f6cSMauro Carvalho Chehab {
2461*0aa77f6cSMauro Carvalho Chehab 	unsigned char *buffer;
2462*0aa77f6cSMauro Carvalho Chehab 	int res;
2463*0aa77f6cSMauro Carvalho Chehab 	unsigned long chn_rev;
2464*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
2465*0aa77f6cSMauro Carvalho Chehab 	chn_rev = G_chnmap[channel->idx];
2466*0aa77f6cSMauro Carvalho Chehab 	buffer = kzalloc(512, GFP_KERNEL);
2467*0aa77f6cSMauro Carvalho Chehab 	if (buffer == NULL) {
2468*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "out of mem\n");
2469*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2470*0aa77f6cSMauro Carvalho Chehab 	}
2471*0aa77f6cSMauro Carvalho Chehab 	/* send the stop command */
2472*0aa77f6cSMauro Carvalho Chehab 	*(__le32 *) buffer = IN_DATA_TOKEN;
2473*0aa77f6cSMauro Carvalho Chehab 	*((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
2474*0aa77f6cSMauro Carvalho Chehab 	*((__le32 *) buffer + 2) = CMD_STOP;
2475*0aa77f6cSMauro Carvalho Chehab 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
2476*0aa77f6cSMauro Carvalho Chehab 	if (res != 0)
2477*0aa77f6cSMauro Carvalho Chehab 		dev_err(&dev->udev->dev, "CMD_STOP error\n");
2478*0aa77f6cSMauro Carvalho Chehab 	kfree(buffer);
2479*0aa77f6cSMauro Carvalho Chehab 	channel->b_acquire = 0;
2480*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
2481*0aa77f6cSMauro Carvalho Chehab 	return res;
2482*0aa77f6cSMauro Carvalho Chehab }
2483*0aa77f6cSMauro Carvalho Chehab 
2484*0aa77f6cSMauro Carvalho Chehab static void s2255_stop_readpipe(struct s2255_dev *dev)
2485*0aa77f6cSMauro Carvalho Chehab {
2486*0aa77f6cSMauro Carvalho Chehab 	struct s2255_pipeinfo *pipe = &dev->pipe;
2487*0aa77f6cSMauro Carvalho Chehab 
2488*0aa77f6cSMauro Carvalho Chehab 	pipe->state = 0;
2489*0aa77f6cSMauro Carvalho Chehab 	if (pipe->stream_urb) {
2490*0aa77f6cSMauro Carvalho Chehab 		/* cancel urb */
2491*0aa77f6cSMauro Carvalho Chehab 		usb_kill_urb(pipe->stream_urb);
2492*0aa77f6cSMauro Carvalho Chehab 		usb_free_urb(pipe->stream_urb);
2493*0aa77f6cSMauro Carvalho Chehab 		pipe->stream_urb = NULL;
2494*0aa77f6cSMauro Carvalho Chehab 	}
2495*0aa77f6cSMauro Carvalho Chehab 	dprintk(4, "%s", __func__);
2496*0aa77f6cSMauro Carvalho Chehab 	return;
2497*0aa77f6cSMauro Carvalho Chehab }
2498*0aa77f6cSMauro Carvalho Chehab 
2499*0aa77f6cSMauro Carvalho Chehab static void s2255_fwload_start(struct s2255_dev *dev, int reset)
2500*0aa77f6cSMauro Carvalho Chehab {
2501*0aa77f6cSMauro Carvalho Chehab 	if (reset)
2502*0aa77f6cSMauro Carvalho Chehab 		s2255_reset_dsppower(dev);
2503*0aa77f6cSMauro Carvalho Chehab 	dev->fw_data->fw_size = dev->fw_data->fw->size;
2504*0aa77f6cSMauro Carvalho Chehab 	atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
2505*0aa77f6cSMauro Carvalho Chehab 	memcpy(dev->fw_data->pfw_data,
2506*0aa77f6cSMauro Carvalho Chehab 	       dev->fw_data->fw->data, CHUNK_SIZE);
2507*0aa77f6cSMauro Carvalho Chehab 	dev->fw_data->fw_loaded = CHUNK_SIZE;
2508*0aa77f6cSMauro Carvalho Chehab 	usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev,
2509*0aa77f6cSMauro Carvalho Chehab 			  usb_sndbulkpipe(dev->udev, 2),
2510*0aa77f6cSMauro Carvalho Chehab 			  dev->fw_data->pfw_data,
2511*0aa77f6cSMauro Carvalho Chehab 			  CHUNK_SIZE, s2255_fwchunk_complete,
2512*0aa77f6cSMauro Carvalho Chehab 			  dev->fw_data);
2513*0aa77f6cSMauro Carvalho Chehab 	mod_timer(&dev->timer, jiffies + HZ);
2514*0aa77f6cSMauro Carvalho Chehab }
2515*0aa77f6cSMauro Carvalho Chehab 
2516*0aa77f6cSMauro Carvalho Chehab /* standard usb probe function */
2517*0aa77f6cSMauro Carvalho Chehab static int s2255_probe(struct usb_interface *interface,
2518*0aa77f6cSMauro Carvalho Chehab 		       const struct usb_device_id *id)
2519*0aa77f6cSMauro Carvalho Chehab {
2520*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = NULL;
2521*0aa77f6cSMauro Carvalho Chehab 	struct usb_host_interface *iface_desc;
2522*0aa77f6cSMauro Carvalho Chehab 	struct usb_endpoint_descriptor *endpoint;
2523*0aa77f6cSMauro Carvalho Chehab 	int i;
2524*0aa77f6cSMauro Carvalho Chehab 	int retval = -ENOMEM;
2525*0aa77f6cSMauro Carvalho Chehab 	__le32 *pdata;
2526*0aa77f6cSMauro Carvalho Chehab 	int fw_size;
2527*0aa77f6cSMauro Carvalho Chehab 	dprintk(2, "%s\n", __func__);
2528*0aa77f6cSMauro Carvalho Chehab 	/* allocate memory for our device state and initialize it to zero */
2529*0aa77f6cSMauro Carvalho Chehab 	dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
2530*0aa77f6cSMauro Carvalho Chehab 	if (dev == NULL) {
2531*0aa77f6cSMauro Carvalho Chehab 		s2255_dev_err(&interface->dev, "out of memory\n");
2532*0aa77f6cSMauro Carvalho Chehab 		return -ENOMEM;
2533*0aa77f6cSMauro Carvalho Chehab 	}
2534*0aa77f6cSMauro Carvalho Chehab 	atomic_set(&dev->num_channels, 0);
2535*0aa77f6cSMauro Carvalho Chehab 	dev->pid = id->idProduct;
2536*0aa77f6cSMauro Carvalho Chehab 	dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
2537*0aa77f6cSMauro Carvalho Chehab 	if (!dev->fw_data)
2538*0aa77f6cSMauro Carvalho Chehab 		goto errorFWDATA1;
2539*0aa77f6cSMauro Carvalho Chehab 	mutex_init(&dev->lock);
2540*0aa77f6cSMauro Carvalho Chehab 	/* grab usb_device and save it */
2541*0aa77f6cSMauro Carvalho Chehab 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
2542*0aa77f6cSMauro Carvalho Chehab 	if (dev->udev == NULL) {
2543*0aa77f6cSMauro Carvalho Chehab 		dev_err(&interface->dev, "null usb device\n");
2544*0aa77f6cSMauro Carvalho Chehab 		retval = -ENODEV;
2545*0aa77f6cSMauro Carvalho Chehab 		goto errorUDEV;
2546*0aa77f6cSMauro Carvalho Chehab 	}
2547*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "dev: %p, udev %p interface %p\n", dev,
2548*0aa77f6cSMauro Carvalho Chehab 		dev->udev, interface);
2549*0aa77f6cSMauro Carvalho Chehab 	dev->interface = interface;
2550*0aa77f6cSMauro Carvalho Chehab 	/* set up the endpoint information  */
2551*0aa77f6cSMauro Carvalho Chehab 	iface_desc = interface->cur_altsetting;
2552*0aa77f6cSMauro Carvalho Chehab 	dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
2553*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
2554*0aa77f6cSMauro Carvalho Chehab 		endpoint = &iface_desc->endpoint[i].desc;
2555*0aa77f6cSMauro Carvalho Chehab 		if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
2556*0aa77f6cSMauro Carvalho Chehab 			/* we found the bulk in endpoint */
2557*0aa77f6cSMauro Carvalho Chehab 			dev->read_endpoint = endpoint->bEndpointAddress;
2558*0aa77f6cSMauro Carvalho Chehab 		}
2559*0aa77f6cSMauro Carvalho Chehab 	}
2560*0aa77f6cSMauro Carvalho Chehab 
2561*0aa77f6cSMauro Carvalho Chehab 	if (!dev->read_endpoint) {
2562*0aa77f6cSMauro Carvalho Chehab 		dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
2563*0aa77f6cSMauro Carvalho Chehab 		goto errorEP;
2564*0aa77f6cSMauro Carvalho Chehab 	}
2565*0aa77f6cSMauro Carvalho Chehab 	init_timer(&dev->timer);
2566*0aa77f6cSMauro Carvalho Chehab 	dev->timer.function = s2255_timer;
2567*0aa77f6cSMauro Carvalho Chehab 	dev->timer.data = (unsigned long)dev->fw_data;
2568*0aa77f6cSMauro Carvalho Chehab 	init_waitqueue_head(&dev->fw_data->wait_fw);
2569*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < MAX_CHANNELS; i++) {
2570*0aa77f6cSMauro Carvalho Chehab 		struct s2255_channel *channel = &dev->channel[i];
2571*0aa77f6cSMauro Carvalho Chehab 		dev->channel[i].idx = i;
2572*0aa77f6cSMauro Carvalho Chehab 		init_waitqueue_head(&channel->wait_setmode);
2573*0aa77f6cSMauro Carvalho Chehab 		init_waitqueue_head(&channel->wait_vidstatus);
2574*0aa77f6cSMauro Carvalho Chehab 	}
2575*0aa77f6cSMauro Carvalho Chehab 
2576*0aa77f6cSMauro Carvalho Chehab 	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
2577*0aa77f6cSMauro Carvalho Chehab 	if (!dev->fw_data->fw_urb) {
2578*0aa77f6cSMauro Carvalho Chehab 		dev_err(&interface->dev, "out of memory!\n");
2579*0aa77f6cSMauro Carvalho Chehab 		goto errorFWURB;
2580*0aa77f6cSMauro Carvalho Chehab 	}
2581*0aa77f6cSMauro Carvalho Chehab 
2582*0aa77f6cSMauro Carvalho Chehab 	dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
2583*0aa77f6cSMauro Carvalho Chehab 	if (!dev->fw_data->pfw_data) {
2584*0aa77f6cSMauro Carvalho Chehab 		dev_err(&interface->dev, "out of memory!\n");
2585*0aa77f6cSMauro Carvalho Chehab 		goto errorFWDATA2;
2586*0aa77f6cSMauro Carvalho Chehab 	}
2587*0aa77f6cSMauro Carvalho Chehab 	/* load the first chunk */
2588*0aa77f6cSMauro Carvalho Chehab 	if (request_firmware(&dev->fw_data->fw,
2589*0aa77f6cSMauro Carvalho Chehab 			     FIRMWARE_FILE_NAME, &dev->udev->dev)) {
2590*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
2591*0aa77f6cSMauro Carvalho Chehab 		goto errorREQFW;
2592*0aa77f6cSMauro Carvalho Chehab 	}
2593*0aa77f6cSMauro Carvalho Chehab 	/* check the firmware is valid */
2594*0aa77f6cSMauro Carvalho Chehab 	fw_size = dev->fw_data->fw->size;
2595*0aa77f6cSMauro Carvalho Chehab 	pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
2596*0aa77f6cSMauro Carvalho Chehab 
2597*0aa77f6cSMauro Carvalho Chehab 	if (*pdata != S2255_FW_MARKER) {
2598*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "Firmware invalid.\n");
2599*0aa77f6cSMauro Carvalho Chehab 		retval = -ENODEV;
2600*0aa77f6cSMauro Carvalho Chehab 		goto errorFWMARKER;
2601*0aa77f6cSMauro Carvalho Chehab 	} else {
2602*0aa77f6cSMauro Carvalho Chehab 		/* make sure firmware is the latest */
2603*0aa77f6cSMauro Carvalho Chehab 		__le32 *pRel;
2604*0aa77f6cSMauro Carvalho Chehab 		pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
2605*0aa77f6cSMauro Carvalho Chehab 		printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
2606*0aa77f6cSMauro Carvalho Chehab 		dev->dsp_fw_ver = le32_to_cpu(*pRel);
2607*0aa77f6cSMauro Carvalho Chehab 		if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
2608*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
2609*0aa77f6cSMauro Carvalho Chehab 		if (dev->pid == 0x2257 &&
2610*0aa77f6cSMauro Carvalho Chehab 				dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
2611*0aa77f6cSMauro Carvalho Chehab 			printk(KERN_WARNING "s2255: 2257 requires firmware %d"
2612*0aa77f6cSMauro Carvalho Chehab 			       " or above.\n", S2255_MIN_DSP_COLORFILTER);
2613*0aa77f6cSMauro Carvalho Chehab 	}
2614*0aa77f6cSMauro Carvalho Chehab 	usb_reset_device(dev->udev);
2615*0aa77f6cSMauro Carvalho Chehab 	/* load 2255 board specific */
2616*0aa77f6cSMauro Carvalho Chehab 	retval = s2255_board_init(dev);
2617*0aa77f6cSMauro Carvalho Chehab 	if (retval)
2618*0aa77f6cSMauro Carvalho Chehab 		goto errorBOARDINIT;
2619*0aa77f6cSMauro Carvalho Chehab 	spin_lock_init(&dev->slock);
2620*0aa77f6cSMauro Carvalho Chehab 	s2255_fwload_start(dev, 0);
2621*0aa77f6cSMauro Carvalho Chehab 	/* loads v4l specific */
2622*0aa77f6cSMauro Carvalho Chehab 	retval = s2255_probe_v4l(dev);
2623*0aa77f6cSMauro Carvalho Chehab 	if (retval)
2624*0aa77f6cSMauro Carvalho Chehab 		goto errorBOARDINIT;
2625*0aa77f6cSMauro Carvalho Chehab 	dev_info(&interface->dev, "Sensoray 2255 detected\n");
2626*0aa77f6cSMauro Carvalho Chehab 	return 0;
2627*0aa77f6cSMauro Carvalho Chehab errorBOARDINIT:
2628*0aa77f6cSMauro Carvalho Chehab 	s2255_board_shutdown(dev);
2629*0aa77f6cSMauro Carvalho Chehab errorFWMARKER:
2630*0aa77f6cSMauro Carvalho Chehab 	release_firmware(dev->fw_data->fw);
2631*0aa77f6cSMauro Carvalho Chehab errorREQFW:
2632*0aa77f6cSMauro Carvalho Chehab 	kfree(dev->fw_data->pfw_data);
2633*0aa77f6cSMauro Carvalho Chehab errorFWDATA2:
2634*0aa77f6cSMauro Carvalho Chehab 	usb_free_urb(dev->fw_data->fw_urb);
2635*0aa77f6cSMauro Carvalho Chehab errorFWURB:
2636*0aa77f6cSMauro Carvalho Chehab 	del_timer(&dev->timer);
2637*0aa77f6cSMauro Carvalho Chehab errorEP:
2638*0aa77f6cSMauro Carvalho Chehab 	usb_put_dev(dev->udev);
2639*0aa77f6cSMauro Carvalho Chehab errorUDEV:
2640*0aa77f6cSMauro Carvalho Chehab 	kfree(dev->fw_data);
2641*0aa77f6cSMauro Carvalho Chehab 	mutex_destroy(&dev->lock);
2642*0aa77f6cSMauro Carvalho Chehab errorFWDATA1:
2643*0aa77f6cSMauro Carvalho Chehab 	kfree(dev);
2644*0aa77f6cSMauro Carvalho Chehab 	printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
2645*0aa77f6cSMauro Carvalho Chehab 	return retval;
2646*0aa77f6cSMauro Carvalho Chehab }
2647*0aa77f6cSMauro Carvalho Chehab 
2648*0aa77f6cSMauro Carvalho Chehab /* disconnect routine. when board is removed physically or with rmmod */
2649*0aa77f6cSMauro Carvalho Chehab static void s2255_disconnect(struct usb_interface *interface)
2650*0aa77f6cSMauro Carvalho Chehab {
2651*0aa77f6cSMauro Carvalho Chehab 	struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
2652*0aa77f6cSMauro Carvalho Chehab 	int i;
2653*0aa77f6cSMauro Carvalho Chehab 	int channels = atomic_read(&dev->num_channels);
2654*0aa77f6cSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
2655*0aa77f6cSMauro Carvalho Chehab 	v4l2_device_disconnect(&dev->v4l2_dev);
2656*0aa77f6cSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
2657*0aa77f6cSMauro Carvalho Chehab 	/*see comments in the uvc_driver.c usb disconnect function */
2658*0aa77f6cSMauro Carvalho Chehab 	atomic_inc(&dev->num_channels);
2659*0aa77f6cSMauro Carvalho Chehab 	/* unregister each video device. */
2660*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < channels; i++)
2661*0aa77f6cSMauro Carvalho Chehab 		video_unregister_device(&dev->channel[i].vdev);
2662*0aa77f6cSMauro Carvalho Chehab 	/* wake up any of our timers */
2663*0aa77f6cSMauro Carvalho Chehab 	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
2664*0aa77f6cSMauro Carvalho Chehab 	wake_up(&dev->fw_data->wait_fw);
2665*0aa77f6cSMauro Carvalho Chehab 	for (i = 0; i < MAX_CHANNELS; i++) {
2666*0aa77f6cSMauro Carvalho Chehab 		dev->channel[i].setmode_ready = 1;
2667*0aa77f6cSMauro Carvalho Chehab 		wake_up(&dev->channel[i].wait_setmode);
2668*0aa77f6cSMauro Carvalho Chehab 		dev->channel[i].vidstatus_ready = 1;
2669*0aa77f6cSMauro Carvalho Chehab 		wake_up(&dev->channel[i].wait_vidstatus);
2670*0aa77f6cSMauro Carvalho Chehab 	}
2671*0aa77f6cSMauro Carvalho Chehab 	if (atomic_dec_and_test(&dev->num_channels))
2672*0aa77f6cSMauro Carvalho Chehab 		s2255_destroy(dev);
2673*0aa77f6cSMauro Carvalho Chehab 	dev_info(&interface->dev, "%s\n", __func__);
2674*0aa77f6cSMauro Carvalho Chehab }
2675*0aa77f6cSMauro Carvalho Chehab 
2676*0aa77f6cSMauro Carvalho Chehab static struct usb_driver s2255_driver = {
2677*0aa77f6cSMauro Carvalho Chehab 	.name = S2255_DRIVER_NAME,
2678*0aa77f6cSMauro Carvalho Chehab 	.probe = s2255_probe,
2679*0aa77f6cSMauro Carvalho Chehab 	.disconnect = s2255_disconnect,
2680*0aa77f6cSMauro Carvalho Chehab 	.id_table = s2255_table,
2681*0aa77f6cSMauro Carvalho Chehab };
2682*0aa77f6cSMauro Carvalho Chehab 
2683*0aa77f6cSMauro Carvalho Chehab module_usb_driver(s2255_driver);
2684*0aa77f6cSMauro Carvalho Chehab 
2685*0aa77f6cSMauro Carvalho Chehab MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
2686*0aa77f6cSMauro Carvalho Chehab MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
2687*0aa77f6cSMauro Carvalho Chehab MODULE_LICENSE("GPL");
2688*0aa77f6cSMauro Carvalho Chehab MODULE_VERSION(S2255_VERSION);
2689*0aa77f6cSMauro Carvalho Chehab MODULE_FIRMWARE(FIRMWARE_FILE_NAME);
2690