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