10aa77f6cSMauro Carvalho Chehab /* 20aa77f6cSMauro Carvalho Chehab * s2255drv.c - a driver for the Sensoray 2255 USB video capture device 30aa77f6cSMauro Carvalho Chehab * 40aa77f6cSMauro Carvalho Chehab * Copyright (C) 2007-2010 by Sensoray Company Inc. 50aa77f6cSMauro Carvalho Chehab * Dean Anderson 60aa77f6cSMauro Carvalho Chehab * 70aa77f6cSMauro Carvalho Chehab * Some video buffer code based on vivi driver: 80aa77f6cSMauro Carvalho Chehab * 90aa77f6cSMauro Carvalho Chehab * Sensoray 2255 device supports 4 simultaneous channels. 100aa77f6cSMauro Carvalho Chehab * The channels are not "crossbar" inputs, they are physically 110aa77f6cSMauro Carvalho Chehab * attached to separate video decoders. 120aa77f6cSMauro Carvalho Chehab * 130aa77f6cSMauro Carvalho Chehab * Because of USB2.0 bandwidth limitations. There is only a 140aa77f6cSMauro Carvalho Chehab * certain amount of data which may be transferred at one time. 150aa77f6cSMauro Carvalho Chehab * 160aa77f6cSMauro Carvalho Chehab * Example maximum bandwidth utilization: 170aa77f6cSMauro Carvalho Chehab * 180aa77f6cSMauro Carvalho Chehab * -full size, color mode YUYV or YUV422P: 2 channels at once 190aa77f6cSMauro Carvalho Chehab * -full or half size Grey scale: all 4 channels at once 200aa77f6cSMauro Carvalho Chehab * -half size, color mode YUYV or YUV422P: all 4 channels at once 210aa77f6cSMauro Carvalho Chehab * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels 220aa77f6cSMauro Carvalho Chehab * at once. 230aa77f6cSMauro Carvalho Chehab * 240aa77f6cSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 250aa77f6cSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 260aa77f6cSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 270aa77f6cSMauro Carvalho Chehab * (at your option) any later version. 280aa77f6cSMauro Carvalho Chehab * 290aa77f6cSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 300aa77f6cSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 310aa77f6cSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 320aa77f6cSMauro Carvalho Chehab * GNU General Public License for more details. 330aa77f6cSMauro Carvalho Chehab * 340aa77f6cSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 350aa77f6cSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 360aa77f6cSMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 370aa77f6cSMauro Carvalho Chehab */ 380aa77f6cSMauro Carvalho Chehab 390aa77f6cSMauro Carvalho Chehab #include <linux/module.h> 400aa77f6cSMauro Carvalho Chehab #include <linux/firmware.h> 410aa77f6cSMauro Carvalho Chehab #include <linux/kernel.h> 420aa77f6cSMauro Carvalho Chehab #include <linux/mutex.h> 430aa77f6cSMauro Carvalho Chehab #include <linux/slab.h> 440aa77f6cSMauro Carvalho Chehab #include <linux/videodev2.h> 450aa77f6cSMauro Carvalho Chehab #include <linux/mm.h> 460aa77f6cSMauro Carvalho Chehab #include <media/videobuf-vmalloc.h> 470aa77f6cSMauro Carvalho Chehab #include <media/v4l2-common.h> 480aa77f6cSMauro Carvalho Chehab #include <media/v4l2-device.h> 490aa77f6cSMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 50192f1e78SHans Verkuil #include <media/v4l2-ctrls.h> 510aa77f6cSMauro Carvalho Chehab #include <linux/vmalloc.h> 520aa77f6cSMauro Carvalho Chehab #include <linux/usb.h> 530aa77f6cSMauro Carvalho Chehab 540aa77f6cSMauro Carvalho Chehab #define S2255_VERSION "1.22.1" 550aa77f6cSMauro Carvalho Chehab #define FIRMWARE_FILE_NAME "f2255usb.bin" 560aa77f6cSMauro Carvalho Chehab 570aa77f6cSMauro Carvalho Chehab /* default JPEG quality */ 580aa77f6cSMauro Carvalho Chehab #define S2255_DEF_JPEG_QUAL 50 590aa77f6cSMauro Carvalho Chehab /* vendor request in */ 600aa77f6cSMauro Carvalho Chehab #define S2255_VR_IN 0 610aa77f6cSMauro Carvalho Chehab /* vendor request out */ 620aa77f6cSMauro Carvalho Chehab #define S2255_VR_OUT 1 630aa77f6cSMauro Carvalho Chehab /* firmware query */ 640aa77f6cSMauro Carvalho Chehab #define S2255_VR_FW 0x30 650aa77f6cSMauro Carvalho Chehab /* USB endpoint number for configuring the device */ 660aa77f6cSMauro Carvalho Chehab #define S2255_CONFIG_EP 2 670aa77f6cSMauro Carvalho Chehab /* maximum time for DSP to start responding after last FW word loaded(ms) */ 680aa77f6cSMauro Carvalho Chehab #define S2255_DSP_BOOTTIME 800 690aa77f6cSMauro Carvalho Chehab /* maximum time to wait for firmware to load (ms) */ 700aa77f6cSMauro Carvalho Chehab #define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) 710aa77f6cSMauro Carvalho Chehab #define S2255_DEF_BUFS 16 720aa77f6cSMauro Carvalho Chehab #define S2255_SETMODE_TIMEOUT 500 730aa77f6cSMauro Carvalho Chehab #define S2255_VIDSTATUS_TIMEOUT 350 740aa77f6cSMauro Carvalho Chehab #define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL) 750aa77f6cSMauro Carvalho Chehab #define S2255_MARKER_RESPONSE cpu_to_le32(0x2255ACACL) 760aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_SETMODE cpu_to_le32(0x01) 770aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_FW cpu_to_le32(0x10) 780aa77f6cSMauro Carvalho Chehab #define S2255_RESPONSE_STATUS cpu_to_le32(0x20) 790aa77f6cSMauro Carvalho Chehab #define S2255_USB_XFER_SIZE (16 * 1024) 800aa77f6cSMauro Carvalho Chehab #define MAX_CHANNELS 4 810aa77f6cSMauro Carvalho Chehab #define SYS_FRAMES 4 820aa77f6cSMauro Carvalho Chehab /* maximum size is PAL full size plus room for the marker header(s) */ 830aa77f6cSMauro Carvalho Chehab #define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) 840aa77f6cSMauro Carvalho Chehab #define DEF_USB_BLOCK S2255_USB_XFER_SIZE 850aa77f6cSMauro Carvalho Chehab #define LINE_SZ_4CIFS_NTSC 640 860aa77f6cSMauro Carvalho Chehab #define LINE_SZ_2CIFS_NTSC 640 870aa77f6cSMauro Carvalho Chehab #define LINE_SZ_1CIFS_NTSC 320 880aa77f6cSMauro Carvalho Chehab #define LINE_SZ_4CIFS_PAL 704 890aa77f6cSMauro Carvalho Chehab #define LINE_SZ_2CIFS_PAL 704 900aa77f6cSMauro Carvalho Chehab #define LINE_SZ_1CIFS_PAL 352 910aa77f6cSMauro Carvalho Chehab #define NUM_LINES_4CIFS_NTSC 240 920aa77f6cSMauro Carvalho Chehab #define NUM_LINES_2CIFS_NTSC 240 930aa77f6cSMauro Carvalho Chehab #define NUM_LINES_1CIFS_NTSC 240 940aa77f6cSMauro Carvalho Chehab #define NUM_LINES_4CIFS_PAL 288 950aa77f6cSMauro Carvalho Chehab #define NUM_LINES_2CIFS_PAL 288 960aa77f6cSMauro Carvalho Chehab #define NUM_LINES_1CIFS_PAL 288 970aa77f6cSMauro Carvalho Chehab #define LINE_SZ_DEF 640 980aa77f6cSMauro Carvalho Chehab #define NUM_LINES_DEF 240 990aa77f6cSMauro Carvalho Chehab 1000aa77f6cSMauro Carvalho Chehab 1010aa77f6cSMauro Carvalho Chehab /* predefined settings */ 1020aa77f6cSMauro Carvalho Chehab #define FORMAT_NTSC 1 1030aa77f6cSMauro Carvalho Chehab #define FORMAT_PAL 2 1040aa77f6cSMauro Carvalho Chehab 1050aa77f6cSMauro Carvalho Chehab #define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ 1060aa77f6cSMauro Carvalho Chehab #define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ 1070aa77f6cSMauro Carvalho Chehab #define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ 1080aa77f6cSMauro Carvalho Chehab /* SCALE_4CIFSI is the 2 fields interpolated into one */ 1090aa77f6cSMauro Carvalho Chehab #define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ 1100aa77f6cSMauro Carvalho Chehab 1110aa77f6cSMauro Carvalho Chehab #define COLOR_YUVPL 1 /* YUV planar */ 1120aa77f6cSMauro Carvalho Chehab #define COLOR_YUVPK 2 /* YUV packed */ 1130aa77f6cSMauro Carvalho Chehab #define COLOR_Y8 4 /* monochrome */ 1140aa77f6cSMauro Carvalho Chehab #define COLOR_JPG 5 /* JPEG */ 1150aa77f6cSMauro Carvalho Chehab 1160aa77f6cSMauro Carvalho Chehab #define MASK_COLOR 0x000000ff 1170aa77f6cSMauro Carvalho Chehab #define MASK_JPG_QUALITY 0x0000ff00 1180aa77f6cSMauro Carvalho Chehab #define MASK_INPUT_TYPE 0x000f0000 1190aa77f6cSMauro Carvalho Chehab /* frame decimation. */ 1200aa77f6cSMauro Carvalho Chehab #define FDEC_1 1 /* capture every frame. default */ 1210aa77f6cSMauro Carvalho Chehab #define FDEC_2 2 /* capture every 2nd frame */ 1220aa77f6cSMauro Carvalho Chehab #define FDEC_3 3 /* capture every 3rd frame */ 1230aa77f6cSMauro Carvalho Chehab #define FDEC_5 5 /* capture every 5th frame */ 1240aa77f6cSMauro Carvalho Chehab 1250aa77f6cSMauro Carvalho Chehab /*------------------------------------------------------- 1260aa77f6cSMauro Carvalho Chehab * Default mode parameters. 1270aa77f6cSMauro Carvalho Chehab *-------------------------------------------------------*/ 1280aa77f6cSMauro Carvalho Chehab #define DEF_SCALE SCALE_4CIFS 1290aa77f6cSMauro Carvalho Chehab #define DEF_COLOR COLOR_YUVPL 1300aa77f6cSMauro Carvalho Chehab #define DEF_FDEC FDEC_1 1310aa77f6cSMauro Carvalho Chehab #define DEF_BRIGHT 0 1320aa77f6cSMauro Carvalho Chehab #define DEF_CONTRAST 0x5c 1330aa77f6cSMauro Carvalho Chehab #define DEF_SATURATION 0x80 1340aa77f6cSMauro Carvalho Chehab #define DEF_HUE 0 1350aa77f6cSMauro Carvalho Chehab 1360aa77f6cSMauro Carvalho Chehab /* usb config commands */ 1370aa77f6cSMauro Carvalho Chehab #define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) 1380aa77f6cSMauro Carvalho Chehab #define CMD_2255 0xc2255000 1390aa77f6cSMauro Carvalho Chehab #define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) 1400aa77f6cSMauro Carvalho Chehab #define CMD_START cpu_to_le32((CMD_2255 | 0x20)) 1410aa77f6cSMauro Carvalho Chehab #define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) 1420aa77f6cSMauro Carvalho Chehab #define CMD_STATUS cpu_to_le32((CMD_2255 | 0x40)) 1430aa77f6cSMauro Carvalho Chehab 1440aa77f6cSMauro Carvalho Chehab struct s2255_mode { 1450aa77f6cSMauro Carvalho Chehab u32 format; /* input video format (NTSC, PAL) */ 1460aa77f6cSMauro Carvalho Chehab u32 scale; /* output video scale */ 1470aa77f6cSMauro Carvalho Chehab u32 color; /* output video color format */ 1480aa77f6cSMauro Carvalho Chehab u32 fdec; /* frame decimation */ 1490aa77f6cSMauro Carvalho Chehab u32 bright; /* brightness */ 1500aa77f6cSMauro Carvalho Chehab u32 contrast; /* contrast */ 1510aa77f6cSMauro Carvalho Chehab u32 saturation; /* saturation */ 1520aa77f6cSMauro Carvalho Chehab u32 hue; /* hue (NTSC only)*/ 1530aa77f6cSMauro Carvalho Chehab u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ 1540aa77f6cSMauro Carvalho Chehab u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ 1550aa77f6cSMauro Carvalho Chehab u32 restart; /* if DSP requires restart */ 1560aa77f6cSMauro Carvalho Chehab }; 1570aa77f6cSMauro Carvalho Chehab 1580aa77f6cSMauro Carvalho Chehab 1590aa77f6cSMauro Carvalho Chehab #define S2255_READ_IDLE 0 1600aa77f6cSMauro Carvalho Chehab #define S2255_READ_FRAME 1 1610aa77f6cSMauro Carvalho Chehab 1620aa77f6cSMauro Carvalho Chehab /* frame structure */ 1630aa77f6cSMauro Carvalho Chehab struct s2255_framei { 1640aa77f6cSMauro Carvalho Chehab unsigned long size; 1650aa77f6cSMauro Carvalho Chehab unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ 1660aa77f6cSMauro Carvalho Chehab void *lpvbits; /* image data */ 1670aa77f6cSMauro Carvalho Chehab unsigned long cur_size; /* current data copied to it */ 1680aa77f6cSMauro Carvalho Chehab }; 1690aa77f6cSMauro Carvalho Chehab 1700aa77f6cSMauro Carvalho Chehab /* image buffer structure */ 1710aa77f6cSMauro Carvalho Chehab struct s2255_bufferi { 1720aa77f6cSMauro Carvalho Chehab unsigned long dwFrames; /* number of frames in buffer */ 1730aa77f6cSMauro Carvalho Chehab struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ 1740aa77f6cSMauro Carvalho Chehab }; 1750aa77f6cSMauro Carvalho Chehab 1760aa77f6cSMauro Carvalho Chehab #define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ 1770aa77f6cSMauro Carvalho Chehab DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ 1780aa77f6cSMauro Carvalho Chehab DEF_HUE, 0, DEF_USB_BLOCK, 0} 1790aa77f6cSMauro Carvalho Chehab 1800aa77f6cSMauro Carvalho Chehab struct s2255_dmaqueue { 1810aa77f6cSMauro Carvalho Chehab struct list_head active; 1820aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev; 1830aa77f6cSMauro Carvalho Chehab }; 1840aa77f6cSMauro Carvalho Chehab 1850aa77f6cSMauro Carvalho Chehab /* for firmware loading, fw_state */ 1860aa77f6cSMauro Carvalho Chehab #define S2255_FW_NOTLOADED 0 1870aa77f6cSMauro Carvalho Chehab #define S2255_FW_LOADED_DSPWAIT 1 1880aa77f6cSMauro Carvalho Chehab #define S2255_FW_SUCCESS 2 1890aa77f6cSMauro Carvalho Chehab #define S2255_FW_FAILED 3 1900aa77f6cSMauro Carvalho Chehab #define S2255_FW_DISCONNECTING 4 1910aa77f6cSMauro Carvalho Chehab #define S2255_FW_MARKER cpu_to_le32(0x22552f2f) 1920aa77f6cSMauro Carvalho Chehab /* 2255 read states */ 1930aa77f6cSMauro Carvalho Chehab #define S2255_READ_IDLE 0 1940aa77f6cSMauro Carvalho Chehab #define S2255_READ_FRAME 1 1950aa77f6cSMauro Carvalho Chehab struct s2255_fw { 1960aa77f6cSMauro Carvalho Chehab int fw_loaded; 1970aa77f6cSMauro Carvalho Chehab int fw_size; 1980aa77f6cSMauro Carvalho Chehab struct urb *fw_urb; 1990aa77f6cSMauro Carvalho Chehab atomic_t fw_state; 2000aa77f6cSMauro Carvalho Chehab void *pfw_data; 2010aa77f6cSMauro Carvalho Chehab wait_queue_head_t wait_fw; 2020aa77f6cSMauro Carvalho Chehab const struct firmware *fw; 2030aa77f6cSMauro Carvalho Chehab }; 2040aa77f6cSMauro Carvalho Chehab 2050aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo { 2060aa77f6cSMauro Carvalho Chehab u32 max_transfer_size; 2070aa77f6cSMauro Carvalho Chehab u32 cur_transfer_size; 2080aa77f6cSMauro Carvalho Chehab u8 *transfer_buffer; 2090aa77f6cSMauro Carvalho Chehab u32 state; 2100aa77f6cSMauro Carvalho Chehab void *stream_urb; 2110aa77f6cSMauro Carvalho Chehab void *dev; /* back pointer to s2255_dev struct*/ 2120aa77f6cSMauro Carvalho Chehab u32 err_count; 2130aa77f6cSMauro Carvalho Chehab u32 idx; 2140aa77f6cSMauro Carvalho Chehab }; 2150aa77f6cSMauro Carvalho Chehab 2160aa77f6cSMauro Carvalho Chehab struct s2255_fmt; /*forward declaration */ 2170aa77f6cSMauro Carvalho Chehab struct s2255_dev; 2180aa77f6cSMauro Carvalho Chehab 2190aa77f6cSMauro Carvalho Chehab struct s2255_channel { 2200aa77f6cSMauro Carvalho Chehab struct video_device vdev; 221192f1e78SHans Verkuil struct v4l2_ctrl_handler hdl; 222*7041dec7SHans Verkuil struct v4l2_ctrl *jpegqual_ctrl; 2230aa77f6cSMauro Carvalho Chehab int resources; 2240aa77f6cSMauro Carvalho Chehab struct s2255_dmaqueue vidq; 2250aa77f6cSMauro Carvalho Chehab struct s2255_bufferi buffer; 2260aa77f6cSMauro Carvalho Chehab struct s2255_mode mode; 2270aa77f6cSMauro Carvalho Chehab /* jpeg compression */ 228*7041dec7SHans Verkuil unsigned jpegqual; 2290aa77f6cSMauro Carvalho Chehab /* capture parameters (for high quality mode full size) */ 2300aa77f6cSMauro Carvalho Chehab struct v4l2_captureparm cap_parm; 2310aa77f6cSMauro Carvalho Chehab int cur_frame; 2320aa77f6cSMauro Carvalho Chehab int last_frame; 2330aa77f6cSMauro Carvalho Chehab 2340aa77f6cSMauro Carvalho Chehab int b_acquire; 2350aa77f6cSMauro Carvalho Chehab /* allocated image size */ 2360aa77f6cSMauro Carvalho Chehab unsigned long req_image_size; 2370aa77f6cSMauro Carvalho Chehab /* received packet size */ 2380aa77f6cSMauro Carvalho Chehab unsigned long pkt_size; 2390aa77f6cSMauro Carvalho Chehab int bad_payload; 2400aa77f6cSMauro Carvalho Chehab unsigned long frame_count; 2410aa77f6cSMauro Carvalho Chehab /* if JPEG image */ 2420aa77f6cSMauro Carvalho Chehab int jpg_size; 2430aa77f6cSMauro Carvalho Chehab /* if channel configured to default state */ 2440aa77f6cSMauro Carvalho Chehab int configured; 2450aa77f6cSMauro Carvalho Chehab wait_queue_head_t wait_setmode; 2460aa77f6cSMauro Carvalho Chehab int setmode_ready; 2470aa77f6cSMauro Carvalho Chehab /* video status items */ 2480aa77f6cSMauro Carvalho Chehab int vidstatus; 2490aa77f6cSMauro Carvalho Chehab wait_queue_head_t wait_vidstatus; 2500aa77f6cSMauro Carvalho Chehab int vidstatus_ready; 2510aa77f6cSMauro Carvalho Chehab unsigned int width; 2520aa77f6cSMauro Carvalho Chehab unsigned int height; 2530aa77f6cSMauro Carvalho Chehab const struct s2255_fmt *fmt; 2540aa77f6cSMauro Carvalho Chehab int idx; /* channel number on device, 0-3 */ 2550aa77f6cSMauro Carvalho Chehab }; 2560aa77f6cSMauro Carvalho Chehab 2570aa77f6cSMauro Carvalho Chehab 2580aa77f6cSMauro Carvalho Chehab struct s2255_dev { 2590aa77f6cSMauro Carvalho Chehab struct s2255_channel channel[MAX_CHANNELS]; 2600aa77f6cSMauro Carvalho Chehab struct v4l2_device v4l2_dev; 2610aa77f6cSMauro Carvalho Chehab atomic_t num_channels; 2620aa77f6cSMauro Carvalho Chehab int frames; 2630aa77f6cSMauro Carvalho Chehab struct mutex lock; /* channels[].vdev.lock */ 2640aa77f6cSMauro Carvalho Chehab struct usb_device *udev; 2650aa77f6cSMauro Carvalho Chehab struct usb_interface *interface; 2660aa77f6cSMauro Carvalho Chehab u8 read_endpoint; 2670aa77f6cSMauro Carvalho Chehab struct timer_list timer; 2680aa77f6cSMauro Carvalho Chehab struct s2255_fw *fw_data; 2690aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo pipe; 2700aa77f6cSMauro Carvalho Chehab u32 cc; /* current channel */ 2710aa77f6cSMauro Carvalho Chehab int frame_ready; 2720aa77f6cSMauro Carvalho Chehab int chn_ready; 2730aa77f6cSMauro Carvalho Chehab spinlock_t slock; 2740aa77f6cSMauro Carvalho Chehab /* dsp firmware version (f2255usb.bin) */ 2750aa77f6cSMauro Carvalho Chehab int dsp_fw_ver; 2760aa77f6cSMauro Carvalho Chehab u16 pid; /* product id */ 2770aa77f6cSMauro Carvalho Chehab }; 2780aa77f6cSMauro Carvalho Chehab 2790aa77f6cSMauro Carvalho Chehab static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev) 2800aa77f6cSMauro Carvalho Chehab { 2810aa77f6cSMauro Carvalho Chehab return container_of(v4l2_dev, struct s2255_dev, v4l2_dev); 2820aa77f6cSMauro Carvalho Chehab } 2830aa77f6cSMauro Carvalho Chehab 2840aa77f6cSMauro Carvalho Chehab struct s2255_fmt { 2850aa77f6cSMauro Carvalho Chehab char *name; 2860aa77f6cSMauro Carvalho Chehab u32 fourcc; 2870aa77f6cSMauro Carvalho Chehab int depth; 2880aa77f6cSMauro Carvalho Chehab }; 2890aa77f6cSMauro Carvalho Chehab 2900aa77f6cSMauro Carvalho Chehab /* buffer for one video frame */ 2910aa77f6cSMauro Carvalho Chehab struct s2255_buffer { 2920aa77f6cSMauro Carvalho Chehab /* common v4l buffer stuff -- must be first */ 2930aa77f6cSMauro Carvalho Chehab struct videobuf_buffer vb; 2940aa77f6cSMauro Carvalho Chehab const struct s2255_fmt *fmt; 2950aa77f6cSMauro Carvalho Chehab }; 2960aa77f6cSMauro Carvalho Chehab 2970aa77f6cSMauro Carvalho Chehab struct s2255_fh { 2980aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev; 2990aa77f6cSMauro Carvalho Chehab struct videobuf_queue vb_vidq; 3000aa77f6cSMauro Carvalho Chehab enum v4l2_buf_type type; 3010aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel; 3020aa77f6cSMauro Carvalho Chehab int resources; 3030aa77f6cSMauro Carvalho Chehab }; 3040aa77f6cSMauro Carvalho Chehab 3050aa77f6cSMauro Carvalho Chehab /* current cypress EEPROM firmware version */ 3060aa77f6cSMauro Carvalho Chehab #define S2255_CUR_USB_FWVER ((3 << 8) | 12) 3070aa77f6cSMauro Carvalho Chehab /* current DSP FW version */ 3080aa77f6cSMauro Carvalho Chehab #define S2255_CUR_DSP_FWVER 10104 3090aa77f6cSMauro Carvalho Chehab /* Need DSP version 5+ for video status feature */ 3100aa77f6cSMauro Carvalho Chehab #define S2255_MIN_DSP_STATUS 5 3110aa77f6cSMauro Carvalho Chehab #define S2255_MIN_DSP_COLORFILTER 8 3120aa77f6cSMauro Carvalho Chehab #define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC) 3130aa77f6cSMauro Carvalho Chehab 3140aa77f6cSMauro Carvalho Chehab /* private V4L2 controls */ 3150aa77f6cSMauro Carvalho Chehab 3160aa77f6cSMauro Carvalho Chehab /* 3170aa77f6cSMauro Carvalho Chehab * The following chart displays how COLORFILTER should be set 3180aa77f6cSMauro Carvalho Chehab * ========================================================= 3190aa77f6cSMauro Carvalho Chehab * = fourcc = COLORFILTER = 3200aa77f6cSMauro Carvalho Chehab * = =============================== 3210aa77f6cSMauro Carvalho Chehab * = = 0 = 1 = 3220aa77f6cSMauro Carvalho Chehab * ========================================================= 3230aa77f6cSMauro Carvalho Chehab * = V4L2_PIX_FMT_GREY(Y8) = monochrome from = monochrome= 3240aa77f6cSMauro Carvalho Chehab * = = s-video or = composite = 3250aa77f6cSMauro Carvalho Chehab * = = B/W camera = input = 3260aa77f6cSMauro Carvalho Chehab * ========================================================= 3270aa77f6cSMauro Carvalho Chehab * = other = color, svideo = color, = 3280aa77f6cSMauro Carvalho Chehab * = = = composite = 3290aa77f6cSMauro Carvalho Chehab * ========================================================= 3300aa77f6cSMauro Carvalho Chehab * 3310aa77f6cSMauro Carvalho Chehab * Notes: 3320aa77f6cSMauro Carvalho Chehab * channels 0-3 on 2255 are composite 3330aa77f6cSMauro Carvalho Chehab * channels 0-1 on 2257 are composite, 2-3 are s-video 3340aa77f6cSMauro Carvalho Chehab * If COLORFILTER is 0 with a composite color camera connected, 3350aa77f6cSMauro Carvalho Chehab * the output will appear monochrome but hatching 3360aa77f6cSMauro Carvalho Chehab * will occur. 3370aa77f6cSMauro Carvalho Chehab * COLORFILTER is different from "color killer" and "color effects" 3380aa77f6cSMauro Carvalho Chehab * for reasons above. 3390aa77f6cSMauro Carvalho Chehab */ 3400aa77f6cSMauro Carvalho Chehab #define S2255_V4L2_YC_ON 1 3410aa77f6cSMauro Carvalho Chehab #define S2255_V4L2_YC_OFF 0 342192f1e78SHans Verkuil #define V4L2_CID_S2255_COLORFILTER (V4L2_CID_USER_S2255_BASE + 0) 3430aa77f6cSMauro Carvalho Chehab 3440aa77f6cSMauro Carvalho Chehab /* frame prefix size (sent once every frame) */ 3450aa77f6cSMauro Carvalho Chehab #define PREFIX_SIZE 512 3460aa77f6cSMauro Carvalho Chehab 3470aa77f6cSMauro Carvalho Chehab /* Channels on box are in reverse order */ 3480aa77f6cSMauro Carvalho Chehab static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; 3490aa77f6cSMauro Carvalho Chehab 3500aa77f6cSMauro Carvalho Chehab static int debug; 3510aa77f6cSMauro Carvalho Chehab static int *s2255_debug = &debug; 3520aa77f6cSMauro Carvalho Chehab 3530aa77f6cSMauro Carvalho Chehab static int s2255_start_readpipe(struct s2255_dev *dev); 3540aa77f6cSMauro Carvalho Chehab static void s2255_stop_readpipe(struct s2255_dev *dev); 3550aa77f6cSMauro Carvalho Chehab static int s2255_start_acquire(struct s2255_channel *channel); 3560aa77f6cSMauro Carvalho Chehab static int s2255_stop_acquire(struct s2255_channel *channel); 3570aa77f6cSMauro Carvalho Chehab static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf, 3580aa77f6cSMauro Carvalho Chehab int jpgsize); 3590aa77f6cSMauro Carvalho Chehab static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode); 3600aa77f6cSMauro Carvalho Chehab static int s2255_board_shutdown(struct s2255_dev *dev); 3610aa77f6cSMauro Carvalho Chehab static void s2255_fwload_start(struct s2255_dev *dev, int reset); 3620aa77f6cSMauro Carvalho Chehab static void s2255_destroy(struct s2255_dev *dev); 3630aa77f6cSMauro Carvalho Chehab static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, 3640aa77f6cSMauro Carvalho Chehab u16 index, u16 value, void *buf, 3650aa77f6cSMauro Carvalho Chehab s32 buf_len, int bOut); 3660aa77f6cSMauro Carvalho Chehab 3670aa77f6cSMauro Carvalho Chehab /* dev_err macro with driver name */ 3680aa77f6cSMauro Carvalho Chehab #define S2255_DRIVER_NAME "s2255" 3690aa77f6cSMauro Carvalho Chehab #define s2255_dev_err(dev, fmt, arg...) \ 3700aa77f6cSMauro Carvalho Chehab dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) 3710aa77f6cSMauro Carvalho Chehab 3720aa77f6cSMauro Carvalho Chehab #define dprintk(level, fmt, arg...) \ 3730aa77f6cSMauro Carvalho Chehab do { \ 3740aa77f6cSMauro Carvalho Chehab if (*s2255_debug >= (level)) { \ 3750aa77f6cSMauro Carvalho Chehab printk(KERN_DEBUG S2255_DRIVER_NAME \ 3760aa77f6cSMauro Carvalho Chehab ": " fmt, ##arg); \ 3770aa77f6cSMauro Carvalho Chehab } \ 3780aa77f6cSMauro Carvalho Chehab } while (0) 3790aa77f6cSMauro Carvalho Chehab 3800aa77f6cSMauro Carvalho Chehab static struct usb_driver s2255_driver; 3810aa77f6cSMauro Carvalho Chehab 3820aa77f6cSMauro Carvalho Chehab /* Declare static vars that will be used as parameters */ 3830aa77f6cSMauro Carvalho Chehab static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ 3840aa77f6cSMauro Carvalho Chehab 3850aa77f6cSMauro Carvalho Chehab /* start video number */ 3860aa77f6cSMauro Carvalho Chehab static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ 3870aa77f6cSMauro Carvalho Chehab 3880aa77f6cSMauro Carvalho Chehab /* Enable jpeg capture. */ 3890aa77f6cSMauro Carvalho Chehab static int jpeg_enable = 1; 3900aa77f6cSMauro Carvalho Chehab 3910aa77f6cSMauro Carvalho Chehab module_param(debug, int, 0644); 3920aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); 3930aa77f6cSMauro Carvalho Chehab module_param(vid_limit, int, 0644); 3940aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); 3950aa77f6cSMauro Carvalho Chehab module_param(video_nr, int, 0644); 3960aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); 3970aa77f6cSMauro Carvalho Chehab module_param(jpeg_enable, int, 0644); 3980aa77f6cSMauro Carvalho Chehab MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1"); 3990aa77f6cSMauro Carvalho Chehab 4000aa77f6cSMauro Carvalho Chehab /* USB device table */ 4010aa77f6cSMauro Carvalho Chehab #define USB_SENSORAY_VID 0x1943 4020aa77f6cSMauro Carvalho Chehab static struct usb_device_id s2255_table[] = { 4030aa77f6cSMauro Carvalho Chehab {USB_DEVICE(USB_SENSORAY_VID, 0x2255)}, 4040aa77f6cSMauro Carvalho Chehab {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/ 4050aa77f6cSMauro Carvalho Chehab { } /* Terminating entry */ 4060aa77f6cSMauro Carvalho Chehab }; 4070aa77f6cSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, s2255_table); 4080aa77f6cSMauro Carvalho Chehab 4090aa77f6cSMauro Carvalho Chehab #define BUFFER_TIMEOUT msecs_to_jiffies(400) 4100aa77f6cSMauro Carvalho Chehab 4110aa77f6cSMauro Carvalho Chehab /* image formats. */ 4120aa77f6cSMauro Carvalho Chehab /* JPEG formats must be defined last to support jpeg_enable parameter */ 4130aa77f6cSMauro Carvalho Chehab static const struct s2255_fmt formats[] = { 4140aa77f6cSMauro Carvalho Chehab { 4150aa77f6cSMauro Carvalho Chehab .name = "4:2:2, planar, YUV422P", 4160aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUV422P, 4170aa77f6cSMauro Carvalho Chehab .depth = 16 4180aa77f6cSMauro Carvalho Chehab 4190aa77f6cSMauro Carvalho Chehab }, { 4200aa77f6cSMauro Carvalho Chehab .name = "4:2:2, packed, YUYV", 4210aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_YUYV, 4220aa77f6cSMauro Carvalho Chehab .depth = 16 4230aa77f6cSMauro Carvalho Chehab 4240aa77f6cSMauro Carvalho Chehab }, { 4250aa77f6cSMauro Carvalho Chehab .name = "4:2:2, packed, UYVY", 4260aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_UYVY, 4270aa77f6cSMauro Carvalho Chehab .depth = 16 4280aa77f6cSMauro Carvalho Chehab }, { 4290aa77f6cSMauro Carvalho Chehab .name = "8bpp GREY", 4300aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_GREY, 4310aa77f6cSMauro Carvalho Chehab .depth = 8 4320aa77f6cSMauro Carvalho Chehab }, { 4330aa77f6cSMauro Carvalho Chehab .name = "JPG", 4340aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_JPEG, 4350aa77f6cSMauro Carvalho Chehab .depth = 24 4360aa77f6cSMauro Carvalho Chehab }, { 4370aa77f6cSMauro Carvalho Chehab .name = "MJPG", 4380aa77f6cSMauro Carvalho Chehab .fourcc = V4L2_PIX_FMT_MJPEG, 4390aa77f6cSMauro Carvalho Chehab .depth = 24 4400aa77f6cSMauro Carvalho Chehab } 4410aa77f6cSMauro Carvalho Chehab }; 4420aa77f6cSMauro Carvalho Chehab 4430aa77f6cSMauro Carvalho Chehab static int norm_maxw(struct video_device *vdev) 4440aa77f6cSMauro Carvalho Chehab { 4450aa77f6cSMauro Carvalho Chehab return (vdev->current_norm & V4L2_STD_NTSC) ? 4460aa77f6cSMauro Carvalho Chehab LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; 4470aa77f6cSMauro Carvalho Chehab } 4480aa77f6cSMauro Carvalho Chehab 4490aa77f6cSMauro Carvalho Chehab static int norm_maxh(struct video_device *vdev) 4500aa77f6cSMauro Carvalho Chehab { 4510aa77f6cSMauro Carvalho Chehab return (vdev->current_norm & V4L2_STD_NTSC) ? 4520aa77f6cSMauro Carvalho Chehab (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); 4530aa77f6cSMauro Carvalho Chehab } 4540aa77f6cSMauro Carvalho Chehab 4550aa77f6cSMauro Carvalho Chehab static int norm_minw(struct video_device *vdev) 4560aa77f6cSMauro Carvalho Chehab { 4570aa77f6cSMauro Carvalho Chehab return (vdev->current_norm & V4L2_STD_NTSC) ? 4580aa77f6cSMauro Carvalho Chehab LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; 4590aa77f6cSMauro Carvalho Chehab } 4600aa77f6cSMauro Carvalho Chehab 4610aa77f6cSMauro Carvalho Chehab static int norm_minh(struct video_device *vdev) 4620aa77f6cSMauro Carvalho Chehab { 4630aa77f6cSMauro Carvalho Chehab return (vdev->current_norm & V4L2_STD_NTSC) ? 4640aa77f6cSMauro Carvalho Chehab (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); 4650aa77f6cSMauro Carvalho Chehab } 4660aa77f6cSMauro Carvalho Chehab 4670aa77f6cSMauro Carvalho Chehab 4680aa77f6cSMauro Carvalho Chehab /* 4690aa77f6cSMauro Carvalho Chehab * TODO: fixme: move YUV reordering to hardware 4700aa77f6cSMauro Carvalho Chehab * converts 2255 planar format to yuyv or uyvy 4710aa77f6cSMauro Carvalho Chehab */ 4720aa77f6cSMauro Carvalho Chehab static void planar422p_to_yuv_packed(const unsigned char *in, 4730aa77f6cSMauro Carvalho Chehab unsigned char *out, 4740aa77f6cSMauro Carvalho Chehab int width, int height, 4750aa77f6cSMauro Carvalho Chehab int fmt) 4760aa77f6cSMauro Carvalho Chehab { 4770aa77f6cSMauro Carvalho Chehab unsigned char *pY; 4780aa77f6cSMauro Carvalho Chehab unsigned char *pCb; 4790aa77f6cSMauro Carvalho Chehab unsigned char *pCr; 4800aa77f6cSMauro Carvalho Chehab unsigned long size = height * width; 4810aa77f6cSMauro Carvalho Chehab unsigned int i; 4820aa77f6cSMauro Carvalho Chehab pY = (unsigned char *)in; 4830aa77f6cSMauro Carvalho Chehab pCr = (unsigned char *)in + height * width; 4840aa77f6cSMauro Carvalho Chehab pCb = (unsigned char *)in + height * width + (height * width / 2); 4850aa77f6cSMauro Carvalho Chehab for (i = 0; i < size * 2; i += 4) { 4860aa77f6cSMauro Carvalho Chehab out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; 4870aa77f6cSMauro Carvalho Chehab out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; 4880aa77f6cSMauro Carvalho Chehab out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; 4890aa77f6cSMauro Carvalho Chehab out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; 4900aa77f6cSMauro Carvalho Chehab } 4910aa77f6cSMauro Carvalho Chehab return; 4920aa77f6cSMauro Carvalho Chehab } 4930aa77f6cSMauro Carvalho Chehab 4940aa77f6cSMauro Carvalho Chehab static void s2255_reset_dsppower(struct s2255_dev *dev) 4950aa77f6cSMauro Carvalho Chehab { 4960aa77f6cSMauro Carvalho Chehab s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1); 4970aa77f6cSMauro Carvalho Chehab msleep(10); 4980aa77f6cSMauro Carvalho Chehab s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); 4990aa77f6cSMauro Carvalho Chehab msleep(600); 5000aa77f6cSMauro Carvalho Chehab s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); 5010aa77f6cSMauro Carvalho Chehab return; 5020aa77f6cSMauro Carvalho Chehab } 5030aa77f6cSMauro Carvalho Chehab 5040aa77f6cSMauro Carvalho Chehab /* kickstarts the firmware loading. from probe 5050aa77f6cSMauro Carvalho Chehab */ 5060aa77f6cSMauro Carvalho Chehab static void s2255_timer(unsigned long user_data) 5070aa77f6cSMauro Carvalho Chehab { 5080aa77f6cSMauro Carvalho Chehab struct s2255_fw *data = (struct s2255_fw *)user_data; 5090aa77f6cSMauro Carvalho Chehab dprintk(100, "%s\n", __func__); 5100aa77f6cSMauro Carvalho Chehab if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { 5110aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "s2255: can't submit urb\n"); 5120aa77f6cSMauro Carvalho Chehab atomic_set(&data->fw_state, S2255_FW_FAILED); 5130aa77f6cSMauro Carvalho Chehab /* wake up anything waiting for the firmware */ 5140aa77f6cSMauro Carvalho Chehab wake_up(&data->wait_fw); 5150aa77f6cSMauro Carvalho Chehab return; 5160aa77f6cSMauro Carvalho Chehab } 5170aa77f6cSMauro Carvalho Chehab } 5180aa77f6cSMauro Carvalho Chehab 5190aa77f6cSMauro Carvalho Chehab 5200aa77f6cSMauro Carvalho Chehab /* this loads the firmware asynchronously. 5210aa77f6cSMauro Carvalho Chehab Originally this was done synchroously in probe. 5220aa77f6cSMauro Carvalho Chehab But it is better to load it asynchronously here than block 5230aa77f6cSMauro Carvalho Chehab inside the probe function. Blocking inside probe affects boot time. 5240aa77f6cSMauro Carvalho Chehab FW loading is triggered by the timer in the probe function 5250aa77f6cSMauro Carvalho Chehab */ 5260aa77f6cSMauro Carvalho Chehab static void s2255_fwchunk_complete(struct urb *urb) 5270aa77f6cSMauro Carvalho Chehab { 5280aa77f6cSMauro Carvalho Chehab struct s2255_fw *data = urb->context; 5290aa77f6cSMauro Carvalho Chehab struct usb_device *udev = urb->dev; 5300aa77f6cSMauro Carvalho Chehab int len; 5310aa77f6cSMauro Carvalho Chehab dprintk(100, "%s: udev %p urb %p", __func__, udev, urb); 5320aa77f6cSMauro Carvalho Chehab if (urb->status) { 5330aa77f6cSMauro Carvalho Chehab dev_err(&udev->dev, "URB failed with status %d\n", urb->status); 5340aa77f6cSMauro Carvalho Chehab atomic_set(&data->fw_state, S2255_FW_FAILED); 5350aa77f6cSMauro Carvalho Chehab /* wake up anything waiting for the firmware */ 5360aa77f6cSMauro Carvalho Chehab wake_up(&data->wait_fw); 5370aa77f6cSMauro Carvalho Chehab return; 5380aa77f6cSMauro Carvalho Chehab } 5390aa77f6cSMauro Carvalho Chehab if (data->fw_urb == NULL) { 5400aa77f6cSMauro Carvalho Chehab s2255_dev_err(&udev->dev, "disconnected\n"); 5410aa77f6cSMauro Carvalho Chehab atomic_set(&data->fw_state, S2255_FW_FAILED); 5420aa77f6cSMauro Carvalho Chehab /* wake up anything waiting for the firmware */ 5430aa77f6cSMauro Carvalho Chehab wake_up(&data->wait_fw); 5440aa77f6cSMauro Carvalho Chehab return; 5450aa77f6cSMauro Carvalho Chehab } 5460aa77f6cSMauro Carvalho Chehab #define CHUNK_SIZE 512 5470aa77f6cSMauro Carvalho Chehab /* all USB transfers must be done with continuous kernel memory. 5480aa77f6cSMauro Carvalho Chehab can't allocate more than 128k in current linux kernel, so 5490aa77f6cSMauro Carvalho Chehab upload the firmware in chunks 5500aa77f6cSMauro Carvalho Chehab */ 5510aa77f6cSMauro Carvalho Chehab if (data->fw_loaded < data->fw_size) { 5520aa77f6cSMauro Carvalho Chehab len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? 5530aa77f6cSMauro Carvalho Chehab data->fw_size % CHUNK_SIZE : CHUNK_SIZE; 5540aa77f6cSMauro Carvalho Chehab 5550aa77f6cSMauro Carvalho Chehab if (len < CHUNK_SIZE) 5560aa77f6cSMauro Carvalho Chehab memset(data->pfw_data, 0, CHUNK_SIZE); 5570aa77f6cSMauro Carvalho Chehab 5580aa77f6cSMauro Carvalho Chehab dprintk(100, "completed len %d, loaded %d \n", len, 5590aa77f6cSMauro Carvalho Chehab data->fw_loaded); 5600aa77f6cSMauro Carvalho Chehab 5610aa77f6cSMauro Carvalho Chehab memcpy(data->pfw_data, 5620aa77f6cSMauro Carvalho Chehab (char *) data->fw->data + data->fw_loaded, len); 5630aa77f6cSMauro Carvalho Chehab 5640aa77f6cSMauro Carvalho Chehab usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), 5650aa77f6cSMauro Carvalho Chehab data->pfw_data, CHUNK_SIZE, 5660aa77f6cSMauro Carvalho Chehab s2255_fwchunk_complete, data); 5670aa77f6cSMauro Carvalho Chehab if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { 5680aa77f6cSMauro Carvalho Chehab dev_err(&udev->dev, "failed submit URB\n"); 5690aa77f6cSMauro Carvalho Chehab atomic_set(&data->fw_state, S2255_FW_FAILED); 5700aa77f6cSMauro Carvalho Chehab /* wake up anything waiting for the firmware */ 5710aa77f6cSMauro Carvalho Chehab wake_up(&data->wait_fw); 5720aa77f6cSMauro Carvalho Chehab return; 5730aa77f6cSMauro Carvalho Chehab } 5740aa77f6cSMauro Carvalho Chehab data->fw_loaded += len; 5750aa77f6cSMauro Carvalho Chehab } else { 5760aa77f6cSMauro Carvalho Chehab atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); 5770aa77f6cSMauro Carvalho Chehab dprintk(100, "%s: firmware upload complete\n", __func__); 5780aa77f6cSMauro Carvalho Chehab } 5790aa77f6cSMauro Carvalho Chehab return; 5800aa77f6cSMauro Carvalho Chehab 5810aa77f6cSMauro Carvalho Chehab } 5820aa77f6cSMauro Carvalho Chehab 5830aa77f6cSMauro Carvalho Chehab static int s2255_got_frame(struct s2255_channel *channel, int jpgsize) 5840aa77f6cSMauro Carvalho Chehab { 5850aa77f6cSMauro Carvalho Chehab struct s2255_dmaqueue *dma_q = &channel->vidq; 5860aa77f6cSMauro Carvalho Chehab struct s2255_buffer *buf; 5870aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); 5880aa77f6cSMauro Carvalho Chehab unsigned long flags = 0; 5890aa77f6cSMauro Carvalho Chehab int rc = 0; 5900aa77f6cSMauro Carvalho Chehab spin_lock_irqsave(&dev->slock, flags); 5910aa77f6cSMauro Carvalho Chehab if (list_empty(&dma_q->active)) { 5920aa77f6cSMauro Carvalho Chehab dprintk(1, "No active queue to serve\n"); 5930aa77f6cSMauro Carvalho Chehab rc = -1; 5940aa77f6cSMauro Carvalho Chehab goto unlock; 5950aa77f6cSMauro Carvalho Chehab } 5960aa77f6cSMauro Carvalho Chehab buf = list_entry(dma_q->active.next, 5970aa77f6cSMauro Carvalho Chehab struct s2255_buffer, vb.queue); 5980aa77f6cSMauro Carvalho Chehab list_del(&buf->vb.queue); 5998e6057b5SSakari Ailus v4l2_get_timestamp(&buf->vb.ts); 6000aa77f6cSMauro Carvalho Chehab s2255_fillbuff(channel, buf, jpgsize); 6010aa77f6cSMauro Carvalho Chehab wake_up(&buf->vb.done); 6020aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i); 6030aa77f6cSMauro Carvalho Chehab unlock: 6040aa77f6cSMauro Carvalho Chehab spin_unlock_irqrestore(&dev->slock, flags); 6050aa77f6cSMauro Carvalho Chehab return rc; 6060aa77f6cSMauro Carvalho Chehab } 6070aa77f6cSMauro Carvalho Chehab 6080aa77f6cSMauro Carvalho Chehab static const struct s2255_fmt *format_by_fourcc(int fourcc) 6090aa77f6cSMauro Carvalho Chehab { 6100aa77f6cSMauro Carvalho Chehab unsigned int i; 6110aa77f6cSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(formats); i++) { 6120aa77f6cSMauro Carvalho Chehab if (-1 == formats[i].fourcc) 6130aa77f6cSMauro Carvalho Chehab continue; 6140aa77f6cSMauro Carvalho Chehab if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || 6150aa77f6cSMauro Carvalho Chehab (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) 6160aa77f6cSMauro Carvalho Chehab continue; 6170aa77f6cSMauro Carvalho Chehab if (formats[i].fourcc == fourcc) 6180aa77f6cSMauro Carvalho Chehab return formats + i; 6190aa77f6cSMauro Carvalho Chehab } 6200aa77f6cSMauro Carvalho Chehab return NULL; 6210aa77f6cSMauro Carvalho Chehab } 6220aa77f6cSMauro Carvalho Chehab 6230aa77f6cSMauro Carvalho Chehab /* video buffer vmalloc implementation based partly on VIVI driver which is 6240aa77f6cSMauro Carvalho Chehab * Copyright (c) 2006 by 6250aa77f6cSMauro Carvalho Chehab * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> 6260aa77f6cSMauro Carvalho Chehab * Ted Walther <ted--a.t--enumera.com> 6270aa77f6cSMauro Carvalho Chehab * John Sokol <sokol--a.t--videotechnology.com> 6280aa77f6cSMauro Carvalho Chehab * http://v4l.videotechnology.com/ 6290aa77f6cSMauro Carvalho Chehab * 6300aa77f6cSMauro Carvalho Chehab */ 6310aa77f6cSMauro Carvalho Chehab static void s2255_fillbuff(struct s2255_channel *channel, 6320aa77f6cSMauro Carvalho Chehab struct s2255_buffer *buf, int jpgsize) 6330aa77f6cSMauro Carvalho Chehab { 6340aa77f6cSMauro Carvalho Chehab int pos = 0; 6350aa77f6cSMauro Carvalho Chehab const char *tmpbuf; 6360aa77f6cSMauro Carvalho Chehab char *vbuf = videobuf_to_vmalloc(&buf->vb); 6370aa77f6cSMauro Carvalho Chehab unsigned long last_frame; 6380aa77f6cSMauro Carvalho Chehab 6390aa77f6cSMauro Carvalho Chehab if (!vbuf) 6400aa77f6cSMauro Carvalho Chehab return; 6410aa77f6cSMauro Carvalho Chehab last_frame = channel->last_frame; 6420aa77f6cSMauro Carvalho Chehab if (last_frame != -1) { 6430aa77f6cSMauro Carvalho Chehab tmpbuf = 6440aa77f6cSMauro Carvalho Chehab (const char *)channel->buffer.frame[last_frame].lpvbits; 6450aa77f6cSMauro Carvalho Chehab switch (buf->fmt->fourcc) { 6460aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_YUYV: 6470aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY: 6480aa77f6cSMauro Carvalho Chehab planar422p_to_yuv_packed((const unsigned char *)tmpbuf, 6490aa77f6cSMauro Carvalho Chehab vbuf, buf->vb.width, 6500aa77f6cSMauro Carvalho Chehab buf->vb.height, 6510aa77f6cSMauro Carvalho Chehab buf->fmt->fourcc); 6520aa77f6cSMauro Carvalho Chehab break; 6530aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_GREY: 6540aa77f6cSMauro Carvalho Chehab memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); 6550aa77f6cSMauro Carvalho Chehab break; 6560aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_JPEG: 6570aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_MJPEG: 6580aa77f6cSMauro Carvalho Chehab buf->vb.size = jpgsize; 6590aa77f6cSMauro Carvalho Chehab memcpy(vbuf, tmpbuf, buf->vb.size); 6600aa77f6cSMauro Carvalho Chehab break; 6610aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P: 6620aa77f6cSMauro Carvalho Chehab memcpy(vbuf, tmpbuf, 6630aa77f6cSMauro Carvalho Chehab buf->vb.width * buf->vb.height * 2); 6640aa77f6cSMauro Carvalho Chehab break; 6650aa77f6cSMauro Carvalho Chehab default: 6660aa77f6cSMauro Carvalho Chehab printk(KERN_DEBUG "s2255: unknown format?\n"); 6670aa77f6cSMauro Carvalho Chehab } 6680aa77f6cSMauro Carvalho Chehab channel->last_frame = -1; 6690aa77f6cSMauro Carvalho Chehab } else { 6700aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "s2255: =======no frame\n"); 6710aa77f6cSMauro Carvalho Chehab return; 6720aa77f6cSMauro Carvalho Chehab 6730aa77f6cSMauro Carvalho Chehab } 6740aa77f6cSMauro Carvalho Chehab dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n", 6750aa77f6cSMauro Carvalho Chehab (unsigned long)vbuf, pos); 6760aa77f6cSMauro Carvalho Chehab /* tell v4l buffer was filled */ 6770aa77f6cSMauro Carvalho Chehab 6780aa77f6cSMauro Carvalho Chehab buf->vb.field_count = channel->frame_count * 2; 6798e6057b5SSakari Ailus v4l2_get_timestamp(&buf->vb.ts); 6800aa77f6cSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_DONE; 6810aa77f6cSMauro Carvalho Chehab } 6820aa77f6cSMauro Carvalho Chehab 6830aa77f6cSMauro Carvalho Chehab 6840aa77f6cSMauro Carvalho Chehab /* ------------------------------------------------------------------ 6850aa77f6cSMauro Carvalho Chehab Videobuf operations 6860aa77f6cSMauro Carvalho Chehab ------------------------------------------------------------------*/ 6870aa77f6cSMauro Carvalho Chehab 6880aa77f6cSMauro Carvalho Chehab static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, 6890aa77f6cSMauro Carvalho Chehab unsigned int *size) 6900aa77f6cSMauro Carvalho Chehab { 6910aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = vq->priv_data; 6920aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 6930aa77f6cSMauro Carvalho Chehab *size = channel->width * channel->height * (channel->fmt->depth >> 3); 6940aa77f6cSMauro Carvalho Chehab 6950aa77f6cSMauro Carvalho Chehab if (0 == *count) 6960aa77f6cSMauro Carvalho Chehab *count = S2255_DEF_BUFS; 6970aa77f6cSMauro Carvalho Chehab 6980aa77f6cSMauro Carvalho Chehab if (*size * *count > vid_limit * 1024 * 1024) 6990aa77f6cSMauro Carvalho Chehab *count = (vid_limit * 1024 * 1024) / *size; 7000aa77f6cSMauro Carvalho Chehab 7010aa77f6cSMauro Carvalho Chehab return 0; 7020aa77f6cSMauro Carvalho Chehab } 7030aa77f6cSMauro Carvalho Chehab 7040aa77f6cSMauro Carvalho Chehab static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) 7050aa77f6cSMauro Carvalho Chehab { 7060aa77f6cSMauro Carvalho Chehab dprintk(4, "%s\n", __func__); 7070aa77f6cSMauro Carvalho Chehab 7080aa77f6cSMauro Carvalho Chehab videobuf_vmalloc_free(&buf->vb); 7090aa77f6cSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_NEEDS_INIT; 7100aa77f6cSMauro Carvalho Chehab } 7110aa77f6cSMauro Carvalho Chehab 7120aa77f6cSMauro Carvalho Chehab static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, 7130aa77f6cSMauro Carvalho Chehab enum v4l2_field field) 7140aa77f6cSMauro Carvalho Chehab { 7150aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = vq->priv_data; 7160aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 7170aa77f6cSMauro Carvalho Chehab struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); 7180aa77f6cSMauro Carvalho Chehab int rc; 7190aa77f6cSMauro Carvalho Chehab int w = channel->width; 7200aa77f6cSMauro Carvalho Chehab int h = channel->height; 7210aa77f6cSMauro Carvalho Chehab dprintk(4, "%s, field=%d\n", __func__, field); 7220aa77f6cSMauro Carvalho Chehab if (channel->fmt == NULL) 7230aa77f6cSMauro Carvalho Chehab return -EINVAL; 7240aa77f6cSMauro Carvalho Chehab 7250aa77f6cSMauro Carvalho Chehab if ((w < norm_minw(&channel->vdev)) || 7260aa77f6cSMauro Carvalho Chehab (w > norm_maxw(&channel->vdev)) || 7270aa77f6cSMauro Carvalho Chehab (h < norm_minh(&channel->vdev)) || 7280aa77f6cSMauro Carvalho Chehab (h > norm_maxh(&channel->vdev))) { 7290aa77f6cSMauro Carvalho Chehab dprintk(4, "invalid buffer prepare\n"); 7300aa77f6cSMauro Carvalho Chehab return -EINVAL; 7310aa77f6cSMauro Carvalho Chehab } 7320aa77f6cSMauro Carvalho Chehab buf->vb.size = w * h * (channel->fmt->depth >> 3); 7330aa77f6cSMauro Carvalho Chehab if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) { 7340aa77f6cSMauro Carvalho Chehab dprintk(4, "invalid buffer prepare\n"); 7350aa77f6cSMauro Carvalho Chehab return -EINVAL; 7360aa77f6cSMauro Carvalho Chehab } 7370aa77f6cSMauro Carvalho Chehab 7380aa77f6cSMauro Carvalho Chehab buf->fmt = channel->fmt; 7390aa77f6cSMauro Carvalho Chehab buf->vb.width = w; 7400aa77f6cSMauro Carvalho Chehab buf->vb.height = h; 7410aa77f6cSMauro Carvalho Chehab buf->vb.field = field; 7420aa77f6cSMauro Carvalho Chehab 7430aa77f6cSMauro Carvalho Chehab if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { 7440aa77f6cSMauro Carvalho Chehab rc = videobuf_iolock(vq, &buf->vb, NULL); 7450aa77f6cSMauro Carvalho Chehab if (rc < 0) 7460aa77f6cSMauro Carvalho Chehab goto fail; 7470aa77f6cSMauro Carvalho Chehab } 7480aa77f6cSMauro Carvalho Chehab 7490aa77f6cSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_PREPARED; 7500aa77f6cSMauro Carvalho Chehab return 0; 7510aa77f6cSMauro Carvalho Chehab fail: 7520aa77f6cSMauro Carvalho Chehab free_buffer(vq, buf); 7530aa77f6cSMauro Carvalho Chehab return rc; 7540aa77f6cSMauro Carvalho Chehab } 7550aa77f6cSMauro Carvalho Chehab 7560aa77f6cSMauro Carvalho Chehab static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 7570aa77f6cSMauro Carvalho Chehab { 7580aa77f6cSMauro Carvalho Chehab struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); 7590aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = vq->priv_data; 7600aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 7610aa77f6cSMauro Carvalho Chehab struct s2255_dmaqueue *vidq = &channel->vidq; 7620aa77f6cSMauro Carvalho Chehab dprintk(1, "%s\n", __func__); 7630aa77f6cSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_QUEUED; 7640aa77f6cSMauro Carvalho Chehab list_add_tail(&buf->vb.queue, &vidq->active); 7650aa77f6cSMauro Carvalho Chehab } 7660aa77f6cSMauro Carvalho Chehab 7670aa77f6cSMauro Carvalho Chehab static void buffer_release(struct videobuf_queue *vq, 7680aa77f6cSMauro Carvalho Chehab struct videobuf_buffer *vb) 7690aa77f6cSMauro Carvalho Chehab { 7700aa77f6cSMauro Carvalho Chehab struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); 7710aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = vq->priv_data; 7720aa77f6cSMauro Carvalho Chehab dprintk(4, "%s %d\n", __func__, fh->channel->idx); 7730aa77f6cSMauro Carvalho Chehab free_buffer(vq, buf); 7740aa77f6cSMauro Carvalho Chehab } 7750aa77f6cSMauro Carvalho Chehab 7760aa77f6cSMauro Carvalho Chehab static struct videobuf_queue_ops s2255_video_qops = { 7770aa77f6cSMauro Carvalho Chehab .buf_setup = buffer_setup, 7780aa77f6cSMauro Carvalho Chehab .buf_prepare = buffer_prepare, 7790aa77f6cSMauro Carvalho Chehab .buf_queue = buffer_queue, 7800aa77f6cSMauro Carvalho Chehab .buf_release = buffer_release, 7810aa77f6cSMauro Carvalho Chehab }; 7820aa77f6cSMauro Carvalho Chehab 7830aa77f6cSMauro Carvalho Chehab 7840aa77f6cSMauro Carvalho Chehab static int res_get(struct s2255_fh *fh) 7850aa77f6cSMauro Carvalho Chehab { 7860aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 7870aa77f6cSMauro Carvalho Chehab /* is it free? */ 7880aa77f6cSMauro Carvalho Chehab if (channel->resources) 7890aa77f6cSMauro Carvalho Chehab return 0; /* no, someone else uses it */ 7900aa77f6cSMauro Carvalho Chehab /* it's free, grab it */ 7910aa77f6cSMauro Carvalho Chehab channel->resources = 1; 7920aa77f6cSMauro Carvalho Chehab fh->resources = 1; 7930aa77f6cSMauro Carvalho Chehab dprintk(1, "s2255: res: get\n"); 7940aa77f6cSMauro Carvalho Chehab return 1; 7950aa77f6cSMauro Carvalho Chehab } 7960aa77f6cSMauro Carvalho Chehab 7970aa77f6cSMauro Carvalho Chehab static int res_locked(struct s2255_fh *fh) 7980aa77f6cSMauro Carvalho Chehab { 7990aa77f6cSMauro Carvalho Chehab return fh->channel->resources; 8000aa77f6cSMauro Carvalho Chehab } 8010aa77f6cSMauro Carvalho Chehab 8020aa77f6cSMauro Carvalho Chehab static int res_check(struct s2255_fh *fh) 8030aa77f6cSMauro Carvalho Chehab { 8040aa77f6cSMauro Carvalho Chehab return fh->resources; 8050aa77f6cSMauro Carvalho Chehab } 8060aa77f6cSMauro Carvalho Chehab 8070aa77f6cSMauro Carvalho Chehab 8080aa77f6cSMauro Carvalho Chehab static void res_free(struct s2255_fh *fh) 8090aa77f6cSMauro Carvalho Chehab { 8100aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 8110aa77f6cSMauro Carvalho Chehab channel->resources = 0; 8120aa77f6cSMauro Carvalho Chehab fh->resources = 0; 8130aa77f6cSMauro Carvalho Chehab dprintk(1, "res: put\n"); 8140aa77f6cSMauro Carvalho Chehab } 8150aa77f6cSMauro Carvalho Chehab 8160aa77f6cSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void *priv, 8170aa77f6cSMauro Carvalho Chehab struct v4l2_capability *cap) 8180aa77f6cSMauro Carvalho Chehab { 8190aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = file->private_data; 8200aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = fh->dev; 8210aa77f6cSMauro Carvalho Chehab strlcpy(cap->driver, "s2255", sizeof(cap->driver)); 8220aa77f6cSMauro Carvalho Chehab strlcpy(cap->card, "s2255", sizeof(cap->card)); 8230aa77f6cSMauro Carvalho Chehab usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); 8240aa77f6cSMauro Carvalho Chehab cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 8250aa77f6cSMauro Carvalho Chehab return 0; 8260aa77f6cSMauro Carvalho Chehab } 8270aa77f6cSMauro Carvalho Chehab 8280aa77f6cSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 8290aa77f6cSMauro Carvalho Chehab struct v4l2_fmtdesc *f) 8300aa77f6cSMauro Carvalho Chehab { 8310aa77f6cSMauro Carvalho Chehab int index = f->index; 8320aa77f6cSMauro Carvalho Chehab 8330aa77f6cSMauro Carvalho Chehab if (index >= ARRAY_SIZE(formats)) 8340aa77f6cSMauro Carvalho Chehab return -EINVAL; 8350aa77f6cSMauro Carvalho Chehab if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || 8360aa77f6cSMauro Carvalho Chehab (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) 8370aa77f6cSMauro Carvalho Chehab return -EINVAL; 8380aa77f6cSMauro Carvalho Chehab dprintk(4, "name %s\n", formats[index].name); 8390aa77f6cSMauro Carvalho Chehab strlcpy(f->description, formats[index].name, sizeof(f->description)); 8400aa77f6cSMauro Carvalho Chehab f->pixelformat = formats[index].fourcc; 8410aa77f6cSMauro Carvalho Chehab return 0; 8420aa77f6cSMauro Carvalho Chehab } 8430aa77f6cSMauro Carvalho Chehab 8440aa77f6cSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 8450aa77f6cSMauro Carvalho Chehab struct v4l2_format *f) 8460aa77f6cSMauro Carvalho Chehab { 8470aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 8480aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 8490aa77f6cSMauro Carvalho Chehab 8500aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = channel->width; 8510aa77f6cSMauro Carvalho Chehab f->fmt.pix.height = channel->height; 8520aa77f6cSMauro Carvalho Chehab f->fmt.pix.field = fh->vb_vidq.field; 8530aa77f6cSMauro Carvalho Chehab f->fmt.pix.pixelformat = channel->fmt->fourcc; 8540aa77f6cSMauro Carvalho Chehab f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3); 8550aa77f6cSMauro Carvalho Chehab f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 8560aa77f6cSMauro Carvalho Chehab return 0; 8570aa77f6cSMauro Carvalho Chehab } 8580aa77f6cSMauro Carvalho Chehab 8590aa77f6cSMauro Carvalho Chehab static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 8600aa77f6cSMauro Carvalho Chehab struct v4l2_format *f) 8610aa77f6cSMauro Carvalho Chehab { 8620aa77f6cSMauro Carvalho Chehab const struct s2255_fmt *fmt; 8630aa77f6cSMauro Carvalho Chehab enum v4l2_field field; 8640aa77f6cSMauro Carvalho Chehab int b_any_field = 0; 8650aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 8660aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 8670aa77f6cSMauro Carvalho Chehab int is_ntsc; 8680aa77f6cSMauro Carvalho Chehab is_ntsc = 8690aa77f6cSMauro Carvalho Chehab (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0; 8700aa77f6cSMauro Carvalho Chehab 8710aa77f6cSMauro Carvalho Chehab fmt = format_by_fourcc(f->fmt.pix.pixelformat); 8720aa77f6cSMauro Carvalho Chehab 8730aa77f6cSMauro Carvalho Chehab if (fmt == NULL) 8740aa77f6cSMauro Carvalho Chehab return -EINVAL; 8750aa77f6cSMauro Carvalho Chehab 8760aa77f6cSMauro Carvalho Chehab field = f->fmt.pix.field; 8770aa77f6cSMauro Carvalho Chehab if (field == V4L2_FIELD_ANY) 8780aa77f6cSMauro Carvalho Chehab b_any_field = 1; 8790aa77f6cSMauro Carvalho Chehab 8800aa77f6cSMauro Carvalho Chehab dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n", 8810aa77f6cSMauro Carvalho Chehab __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); 8820aa77f6cSMauro Carvalho Chehab if (is_ntsc) { 8830aa77f6cSMauro Carvalho Chehab /* NTSC */ 8840aa77f6cSMauro Carvalho Chehab if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) { 8850aa77f6cSMauro Carvalho Chehab f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2; 8860aa77f6cSMauro Carvalho Chehab if (b_any_field) { 8870aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_SEQ_TB; 8880aa77f6cSMauro Carvalho Chehab } else if (!((field == V4L2_FIELD_INTERLACED) || 8890aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_SEQ_TB) || 8900aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_INTERLACED_TB))) { 8910aa77f6cSMauro Carvalho Chehab dprintk(1, "unsupported field setting\n"); 8920aa77f6cSMauro Carvalho Chehab return -EINVAL; 8930aa77f6cSMauro Carvalho Chehab } 8940aa77f6cSMauro Carvalho Chehab } else { 8950aa77f6cSMauro Carvalho Chehab f->fmt.pix.height = NUM_LINES_1CIFS_NTSC; 8960aa77f6cSMauro Carvalho Chehab if (b_any_field) { 8970aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_TOP; 8980aa77f6cSMauro Carvalho Chehab } else if (!((field == V4L2_FIELD_TOP) || 8990aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_BOTTOM))) { 9000aa77f6cSMauro Carvalho Chehab dprintk(1, "unsupported field setting\n"); 9010aa77f6cSMauro Carvalho Chehab return -EINVAL; 9020aa77f6cSMauro Carvalho Chehab } 9030aa77f6cSMauro Carvalho Chehab 9040aa77f6cSMauro Carvalho Chehab } 9050aa77f6cSMauro Carvalho Chehab if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) 9060aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; 9070aa77f6cSMauro Carvalho Chehab else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC) 9080aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_2CIFS_NTSC; 9090aa77f6cSMauro Carvalho Chehab else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC) 9100aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; 9110aa77f6cSMauro Carvalho Chehab else 9120aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; 9130aa77f6cSMauro Carvalho Chehab } else { 9140aa77f6cSMauro Carvalho Chehab /* PAL */ 9150aa77f6cSMauro Carvalho Chehab if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) { 9160aa77f6cSMauro Carvalho Chehab f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2; 9170aa77f6cSMauro Carvalho Chehab if (b_any_field) { 9180aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_SEQ_TB; 9190aa77f6cSMauro Carvalho Chehab } else if (!((field == V4L2_FIELD_INTERLACED) || 9200aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_SEQ_TB) || 9210aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_INTERLACED_TB))) { 9220aa77f6cSMauro Carvalho Chehab dprintk(1, "unsupported field setting\n"); 9230aa77f6cSMauro Carvalho Chehab return -EINVAL; 9240aa77f6cSMauro Carvalho Chehab } 9250aa77f6cSMauro Carvalho Chehab } else { 9260aa77f6cSMauro Carvalho Chehab f->fmt.pix.height = NUM_LINES_1CIFS_PAL; 9270aa77f6cSMauro Carvalho Chehab if (b_any_field) { 9280aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_TOP; 9290aa77f6cSMauro Carvalho Chehab } else if (!((field == V4L2_FIELD_TOP) || 9300aa77f6cSMauro Carvalho Chehab (field == V4L2_FIELD_BOTTOM))) { 9310aa77f6cSMauro Carvalho Chehab dprintk(1, "unsupported field setting\n"); 9320aa77f6cSMauro Carvalho Chehab return -EINVAL; 9330aa77f6cSMauro Carvalho Chehab } 9340aa77f6cSMauro Carvalho Chehab } 9350aa77f6cSMauro Carvalho Chehab if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) { 9360aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_4CIFS_PAL; 9370aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_SEQ_TB; 9380aa77f6cSMauro Carvalho Chehab } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) { 9390aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_2CIFS_PAL; 9400aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_TOP; 9410aa77f6cSMauro Carvalho Chehab } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) { 9420aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_1CIFS_PAL; 9430aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_TOP; 9440aa77f6cSMauro Carvalho Chehab } else { 9450aa77f6cSMauro Carvalho Chehab f->fmt.pix.width = LINE_SZ_1CIFS_PAL; 9460aa77f6cSMauro Carvalho Chehab field = V4L2_FIELD_TOP; 9470aa77f6cSMauro Carvalho Chehab } 9480aa77f6cSMauro Carvalho Chehab } 9490aa77f6cSMauro Carvalho Chehab f->fmt.pix.field = field; 9500aa77f6cSMauro Carvalho Chehab f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; 9510aa77f6cSMauro Carvalho Chehab f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 9520aa77f6cSMauro Carvalho Chehab dprintk(50, "%s: set width %d height %d field %d\n", __func__, 9530aa77f6cSMauro Carvalho Chehab f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); 9540aa77f6cSMauro Carvalho Chehab return 0; 9550aa77f6cSMauro Carvalho Chehab } 9560aa77f6cSMauro Carvalho Chehab 9570aa77f6cSMauro Carvalho Chehab static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 9580aa77f6cSMauro Carvalho Chehab struct v4l2_format *f) 9590aa77f6cSMauro Carvalho Chehab { 9600aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 9610aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 9620aa77f6cSMauro Carvalho Chehab const struct s2255_fmt *fmt; 9630aa77f6cSMauro Carvalho Chehab struct videobuf_queue *q = &fh->vb_vidq; 9640aa77f6cSMauro Carvalho Chehab struct s2255_mode mode; 9650aa77f6cSMauro Carvalho Chehab int ret; 9660aa77f6cSMauro Carvalho Chehab 9670aa77f6cSMauro Carvalho Chehab ret = vidioc_try_fmt_vid_cap(file, fh, f); 9680aa77f6cSMauro Carvalho Chehab 9690aa77f6cSMauro Carvalho Chehab if (ret < 0) 9700aa77f6cSMauro Carvalho Chehab return ret; 9710aa77f6cSMauro Carvalho Chehab 9720aa77f6cSMauro Carvalho Chehab fmt = format_by_fourcc(f->fmt.pix.pixelformat); 9730aa77f6cSMauro Carvalho Chehab 9740aa77f6cSMauro Carvalho Chehab if (fmt == NULL) 9750aa77f6cSMauro Carvalho Chehab return -EINVAL; 9760aa77f6cSMauro Carvalho Chehab 9770aa77f6cSMauro Carvalho Chehab mutex_lock(&q->vb_lock); 9780aa77f6cSMauro Carvalho Chehab 9790aa77f6cSMauro Carvalho Chehab if (videobuf_queue_is_busy(&fh->vb_vidq)) { 9800aa77f6cSMauro Carvalho Chehab dprintk(1, "queue busy\n"); 9810aa77f6cSMauro Carvalho Chehab ret = -EBUSY; 9820aa77f6cSMauro Carvalho Chehab goto out_s_fmt; 9830aa77f6cSMauro Carvalho Chehab } 9840aa77f6cSMauro Carvalho Chehab 9850aa77f6cSMauro Carvalho Chehab if (res_locked(fh)) { 9860aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: channel busy\n", __func__); 9870aa77f6cSMauro Carvalho Chehab ret = -EBUSY; 9880aa77f6cSMauro Carvalho Chehab goto out_s_fmt; 9890aa77f6cSMauro Carvalho Chehab } 9900aa77f6cSMauro Carvalho Chehab mode = channel->mode; 9910aa77f6cSMauro Carvalho Chehab channel->fmt = fmt; 9920aa77f6cSMauro Carvalho Chehab channel->width = f->fmt.pix.width; 9930aa77f6cSMauro Carvalho Chehab channel->height = f->fmt.pix.height; 9940aa77f6cSMauro Carvalho Chehab fh->vb_vidq.field = f->fmt.pix.field; 9950aa77f6cSMauro Carvalho Chehab fh->type = f->type; 9960aa77f6cSMauro Carvalho Chehab if (channel->width > norm_minw(&channel->vdev)) { 9970aa77f6cSMauro Carvalho Chehab if (channel->height > norm_minh(&channel->vdev)) { 9980aa77f6cSMauro Carvalho Chehab if (channel->cap_parm.capturemode & 9990aa77f6cSMauro Carvalho Chehab V4L2_MODE_HIGHQUALITY) 10000aa77f6cSMauro Carvalho Chehab mode.scale = SCALE_4CIFSI; 10010aa77f6cSMauro Carvalho Chehab else 10020aa77f6cSMauro Carvalho Chehab mode.scale = SCALE_4CIFS; 10030aa77f6cSMauro Carvalho Chehab } else 10040aa77f6cSMauro Carvalho Chehab mode.scale = SCALE_2CIFS; 10050aa77f6cSMauro Carvalho Chehab 10060aa77f6cSMauro Carvalho Chehab } else { 10070aa77f6cSMauro Carvalho Chehab mode.scale = SCALE_1CIFS; 10080aa77f6cSMauro Carvalho Chehab } 10090aa77f6cSMauro Carvalho Chehab /* color mode */ 10100aa77f6cSMauro Carvalho Chehab switch (channel->fmt->fourcc) { 10110aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_GREY: 10120aa77f6cSMauro Carvalho Chehab mode.color &= ~MASK_COLOR; 10130aa77f6cSMauro Carvalho Chehab mode.color |= COLOR_Y8; 10140aa77f6cSMauro Carvalho Chehab break; 10150aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_JPEG: 10160aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_MJPEG: 10170aa77f6cSMauro Carvalho Chehab mode.color &= ~MASK_COLOR; 10180aa77f6cSMauro Carvalho Chehab mode.color |= COLOR_JPG; 1019*7041dec7SHans Verkuil mode.color |= (channel->jpegqual << 8); 10200aa77f6cSMauro Carvalho Chehab break; 10210aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_YUV422P: 10220aa77f6cSMauro Carvalho Chehab mode.color &= ~MASK_COLOR; 10230aa77f6cSMauro Carvalho Chehab mode.color |= COLOR_YUVPL; 10240aa77f6cSMauro Carvalho Chehab break; 10250aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_YUYV: 10260aa77f6cSMauro Carvalho Chehab case V4L2_PIX_FMT_UYVY: 10270aa77f6cSMauro Carvalho Chehab default: 10280aa77f6cSMauro Carvalho Chehab mode.color &= ~MASK_COLOR; 10290aa77f6cSMauro Carvalho Chehab mode.color |= COLOR_YUVPK; 10300aa77f6cSMauro Carvalho Chehab break; 10310aa77f6cSMauro Carvalho Chehab } 10320aa77f6cSMauro Carvalho Chehab if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR)) 10330aa77f6cSMauro Carvalho Chehab mode.restart = 1; 10340aa77f6cSMauro Carvalho Chehab else if (mode.scale != channel->mode.scale) 10350aa77f6cSMauro Carvalho Chehab mode.restart = 1; 10360aa77f6cSMauro Carvalho Chehab else if (mode.format != channel->mode.format) 10370aa77f6cSMauro Carvalho Chehab mode.restart = 1; 10380aa77f6cSMauro Carvalho Chehab channel->mode = mode; 10390aa77f6cSMauro Carvalho Chehab (void) s2255_set_mode(channel, &mode); 10400aa77f6cSMauro Carvalho Chehab ret = 0; 10410aa77f6cSMauro Carvalho Chehab out_s_fmt: 10420aa77f6cSMauro Carvalho Chehab mutex_unlock(&q->vb_lock); 10430aa77f6cSMauro Carvalho Chehab return ret; 10440aa77f6cSMauro Carvalho Chehab } 10450aa77f6cSMauro Carvalho Chehab 10460aa77f6cSMauro Carvalho Chehab static int vidioc_reqbufs(struct file *file, void *priv, 10470aa77f6cSMauro Carvalho Chehab struct v4l2_requestbuffers *p) 10480aa77f6cSMauro Carvalho Chehab { 10490aa77f6cSMauro Carvalho Chehab int rc; 10500aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 10510aa77f6cSMauro Carvalho Chehab rc = videobuf_reqbufs(&fh->vb_vidq, p); 10520aa77f6cSMauro Carvalho Chehab return rc; 10530aa77f6cSMauro Carvalho Chehab } 10540aa77f6cSMauro Carvalho Chehab 10550aa77f6cSMauro Carvalho Chehab static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) 10560aa77f6cSMauro Carvalho Chehab { 10570aa77f6cSMauro Carvalho Chehab int rc; 10580aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 10590aa77f6cSMauro Carvalho Chehab rc = videobuf_querybuf(&fh->vb_vidq, p); 10600aa77f6cSMauro Carvalho Chehab return rc; 10610aa77f6cSMauro Carvalho Chehab } 10620aa77f6cSMauro Carvalho Chehab 10630aa77f6cSMauro Carvalho Chehab static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) 10640aa77f6cSMauro Carvalho Chehab { 10650aa77f6cSMauro Carvalho Chehab int rc; 10660aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 10670aa77f6cSMauro Carvalho Chehab rc = videobuf_qbuf(&fh->vb_vidq, p); 10680aa77f6cSMauro Carvalho Chehab return rc; 10690aa77f6cSMauro Carvalho Chehab } 10700aa77f6cSMauro Carvalho Chehab 10710aa77f6cSMauro Carvalho Chehab static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) 10720aa77f6cSMauro Carvalho Chehab { 10730aa77f6cSMauro Carvalho Chehab int rc; 10740aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 10750aa77f6cSMauro Carvalho Chehab rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK); 10760aa77f6cSMauro Carvalho Chehab return rc; 10770aa77f6cSMauro Carvalho Chehab } 10780aa77f6cSMauro Carvalho Chehab 10790aa77f6cSMauro Carvalho Chehab /* write to the configuration pipe, synchronously */ 10800aa77f6cSMauro Carvalho Chehab static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, 10810aa77f6cSMauro Carvalho Chehab int size) 10820aa77f6cSMauro Carvalho Chehab { 10830aa77f6cSMauro Carvalho Chehab int pipe; 10840aa77f6cSMauro Carvalho Chehab int done; 10850aa77f6cSMauro Carvalho Chehab long retval = -1; 10860aa77f6cSMauro Carvalho Chehab if (udev) { 10870aa77f6cSMauro Carvalho Chehab pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); 10880aa77f6cSMauro Carvalho Chehab retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); 10890aa77f6cSMauro Carvalho Chehab } 10900aa77f6cSMauro Carvalho Chehab return retval; 10910aa77f6cSMauro Carvalho Chehab } 10920aa77f6cSMauro Carvalho Chehab 10930aa77f6cSMauro Carvalho Chehab static u32 get_transfer_size(struct s2255_mode *mode) 10940aa77f6cSMauro Carvalho Chehab { 10950aa77f6cSMauro Carvalho Chehab int linesPerFrame = LINE_SZ_DEF; 10960aa77f6cSMauro Carvalho Chehab int pixelsPerLine = NUM_LINES_DEF; 10970aa77f6cSMauro Carvalho Chehab u32 outImageSize; 10980aa77f6cSMauro Carvalho Chehab u32 usbInSize; 10990aa77f6cSMauro Carvalho Chehab unsigned int mask_mult; 11000aa77f6cSMauro Carvalho Chehab 11010aa77f6cSMauro Carvalho Chehab if (mode == NULL) 11020aa77f6cSMauro Carvalho Chehab return 0; 11030aa77f6cSMauro Carvalho Chehab 11040aa77f6cSMauro Carvalho Chehab if (mode->format == FORMAT_NTSC) { 11050aa77f6cSMauro Carvalho Chehab switch (mode->scale) { 11060aa77f6cSMauro Carvalho Chehab case SCALE_4CIFS: 11070aa77f6cSMauro Carvalho Chehab case SCALE_4CIFSI: 11080aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; 11090aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_4CIFS_NTSC; 11100aa77f6cSMauro Carvalho Chehab break; 11110aa77f6cSMauro Carvalho Chehab case SCALE_2CIFS: 11120aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_2CIFS_NTSC; 11130aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_2CIFS_NTSC; 11140aa77f6cSMauro Carvalho Chehab break; 11150aa77f6cSMauro Carvalho Chehab case SCALE_1CIFS: 11160aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_1CIFS_NTSC; 11170aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_1CIFS_NTSC; 11180aa77f6cSMauro Carvalho Chehab break; 11190aa77f6cSMauro Carvalho Chehab default: 11200aa77f6cSMauro Carvalho Chehab break; 11210aa77f6cSMauro Carvalho Chehab } 11220aa77f6cSMauro Carvalho Chehab } else if (mode->format == FORMAT_PAL) { 11230aa77f6cSMauro Carvalho Chehab switch (mode->scale) { 11240aa77f6cSMauro Carvalho Chehab case SCALE_4CIFS: 11250aa77f6cSMauro Carvalho Chehab case SCALE_4CIFSI: 11260aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_4CIFS_PAL * 2; 11270aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_4CIFS_PAL; 11280aa77f6cSMauro Carvalho Chehab break; 11290aa77f6cSMauro Carvalho Chehab case SCALE_2CIFS: 11300aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_2CIFS_PAL; 11310aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_2CIFS_PAL; 11320aa77f6cSMauro Carvalho Chehab break; 11330aa77f6cSMauro Carvalho Chehab case SCALE_1CIFS: 11340aa77f6cSMauro Carvalho Chehab linesPerFrame = NUM_LINES_1CIFS_PAL; 11350aa77f6cSMauro Carvalho Chehab pixelsPerLine = LINE_SZ_1CIFS_PAL; 11360aa77f6cSMauro Carvalho Chehab break; 11370aa77f6cSMauro Carvalho Chehab default: 11380aa77f6cSMauro Carvalho Chehab break; 11390aa77f6cSMauro Carvalho Chehab } 11400aa77f6cSMauro Carvalho Chehab } 11410aa77f6cSMauro Carvalho Chehab outImageSize = linesPerFrame * pixelsPerLine; 11420aa77f6cSMauro Carvalho Chehab if ((mode->color & MASK_COLOR) != COLOR_Y8) { 11430aa77f6cSMauro Carvalho Chehab /* 2 bytes/pixel if not monochrome */ 11440aa77f6cSMauro Carvalho Chehab outImageSize *= 2; 11450aa77f6cSMauro Carvalho Chehab } 11460aa77f6cSMauro Carvalho Chehab 11470aa77f6cSMauro Carvalho Chehab /* total bytes to send including prefix and 4K padding; 11480aa77f6cSMauro Carvalho Chehab must be a multiple of USB_READ_SIZE */ 11490aa77f6cSMauro Carvalho Chehab usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ 11500aa77f6cSMauro Carvalho Chehab mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; 11510aa77f6cSMauro Carvalho Chehab /* if size not a multiple of USB_READ_SIZE */ 11520aa77f6cSMauro Carvalho Chehab if (usbInSize & ~mask_mult) 11530aa77f6cSMauro Carvalho Chehab usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); 11540aa77f6cSMauro Carvalho Chehab return usbInSize; 11550aa77f6cSMauro Carvalho Chehab } 11560aa77f6cSMauro Carvalho Chehab 11570aa77f6cSMauro Carvalho Chehab static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) 11580aa77f6cSMauro Carvalho Chehab { 11590aa77f6cSMauro Carvalho Chehab struct device *dev = &sdev->udev->dev; 11600aa77f6cSMauro Carvalho Chehab dev_info(dev, "------------------------------------------------\n"); 11610aa77f6cSMauro Carvalho Chehab dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale); 11620aa77f6cSMauro Carvalho Chehab dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color); 11630aa77f6cSMauro Carvalho Chehab dev_info(dev, "bright: 0x%x\n", mode->bright); 11640aa77f6cSMauro Carvalho Chehab dev_info(dev, "------------------------------------------------\n"); 11650aa77f6cSMauro Carvalho Chehab } 11660aa77f6cSMauro Carvalho Chehab 11670aa77f6cSMauro Carvalho Chehab /* 11680aa77f6cSMauro Carvalho Chehab * set mode is the function which controls the DSP. 11690aa77f6cSMauro Carvalho Chehab * the restart parameter in struct s2255_mode should be set whenever 11700aa77f6cSMauro Carvalho Chehab * the image size could change via color format, video system or image 11710aa77f6cSMauro Carvalho Chehab * size. 11720aa77f6cSMauro Carvalho Chehab * When the restart parameter is set, we sleep for ONE frame to allow the 11730aa77f6cSMauro Carvalho Chehab * DSP time to get the new frame 11740aa77f6cSMauro Carvalho Chehab */ 11750aa77f6cSMauro Carvalho Chehab static int s2255_set_mode(struct s2255_channel *channel, 11760aa77f6cSMauro Carvalho Chehab struct s2255_mode *mode) 11770aa77f6cSMauro Carvalho Chehab { 11780aa77f6cSMauro Carvalho Chehab int res; 11790aa77f6cSMauro Carvalho Chehab __le32 *buffer; 11800aa77f6cSMauro Carvalho Chehab unsigned long chn_rev; 11810aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); 11820aa77f6cSMauro Carvalho Chehab chn_rev = G_chnmap[channel->idx]; 11830aa77f6cSMauro Carvalho Chehab dprintk(3, "%s channel: %d\n", __func__, channel->idx); 11840aa77f6cSMauro Carvalho Chehab /* if JPEG, set the quality */ 11850aa77f6cSMauro Carvalho Chehab if ((mode->color & MASK_COLOR) == COLOR_JPG) { 11860aa77f6cSMauro Carvalho Chehab mode->color &= ~MASK_COLOR; 11870aa77f6cSMauro Carvalho Chehab mode->color |= COLOR_JPG; 11880aa77f6cSMauro Carvalho Chehab mode->color &= ~MASK_JPG_QUALITY; 1189*7041dec7SHans Verkuil mode->color |= (channel->jpegqual << 8); 11900aa77f6cSMauro Carvalho Chehab } 11910aa77f6cSMauro Carvalho Chehab /* save the mode */ 11920aa77f6cSMauro Carvalho Chehab channel->mode = *mode; 11930aa77f6cSMauro Carvalho Chehab channel->req_image_size = get_transfer_size(mode); 11940aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size); 11950aa77f6cSMauro Carvalho Chehab buffer = kzalloc(512, GFP_KERNEL); 11960aa77f6cSMauro Carvalho Chehab if (buffer == NULL) { 11970aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "out of mem\n"); 11980aa77f6cSMauro Carvalho Chehab return -ENOMEM; 11990aa77f6cSMauro Carvalho Chehab } 12000aa77f6cSMauro Carvalho Chehab /* set the mode */ 12010aa77f6cSMauro Carvalho Chehab buffer[0] = IN_DATA_TOKEN; 12020aa77f6cSMauro Carvalho Chehab buffer[1] = (__le32) cpu_to_le32(chn_rev); 12030aa77f6cSMauro Carvalho Chehab buffer[2] = CMD_SET_MODE; 12040aa77f6cSMauro Carvalho Chehab memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode)); 12050aa77f6cSMauro Carvalho Chehab channel->setmode_ready = 0; 12060aa77f6cSMauro Carvalho Chehab res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 12070aa77f6cSMauro Carvalho Chehab if (debug) 12080aa77f6cSMauro Carvalho Chehab s2255_print_cfg(dev, mode); 12090aa77f6cSMauro Carvalho Chehab kfree(buffer); 12100aa77f6cSMauro Carvalho Chehab /* wait at least 3 frames before continuing */ 12110aa77f6cSMauro Carvalho Chehab if (mode->restart) { 12120aa77f6cSMauro Carvalho Chehab wait_event_timeout(channel->wait_setmode, 12130aa77f6cSMauro Carvalho Chehab (channel->setmode_ready != 0), 12140aa77f6cSMauro Carvalho Chehab msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); 12150aa77f6cSMauro Carvalho Chehab if (channel->setmode_ready != 1) { 12160aa77f6cSMauro Carvalho Chehab printk(KERN_DEBUG "s2255: no set mode response\n"); 12170aa77f6cSMauro Carvalho Chehab res = -EFAULT; 12180aa77f6cSMauro Carvalho Chehab } 12190aa77f6cSMauro Carvalho Chehab } 12200aa77f6cSMauro Carvalho Chehab /* clear the restart flag */ 12210aa77f6cSMauro Carvalho Chehab channel->mode.restart = 0; 12220aa77f6cSMauro Carvalho Chehab dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res); 12230aa77f6cSMauro Carvalho Chehab return res; 12240aa77f6cSMauro Carvalho Chehab } 12250aa77f6cSMauro Carvalho Chehab 12260aa77f6cSMauro Carvalho Chehab static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus) 12270aa77f6cSMauro Carvalho Chehab { 12280aa77f6cSMauro Carvalho Chehab int res; 12290aa77f6cSMauro Carvalho Chehab __le32 *buffer; 12300aa77f6cSMauro Carvalho Chehab u32 chn_rev; 12310aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); 12320aa77f6cSMauro Carvalho Chehab chn_rev = G_chnmap[channel->idx]; 12330aa77f6cSMauro Carvalho Chehab dprintk(4, "%s chan %d\n", __func__, channel->idx); 12340aa77f6cSMauro Carvalho Chehab buffer = kzalloc(512, GFP_KERNEL); 12350aa77f6cSMauro Carvalho Chehab if (buffer == NULL) { 12360aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "out of mem\n"); 12370aa77f6cSMauro Carvalho Chehab return -ENOMEM; 12380aa77f6cSMauro Carvalho Chehab } 12390aa77f6cSMauro Carvalho Chehab /* form the get vid status command */ 12400aa77f6cSMauro Carvalho Chehab buffer[0] = IN_DATA_TOKEN; 12410aa77f6cSMauro Carvalho Chehab buffer[1] = (__le32) cpu_to_le32(chn_rev); 12420aa77f6cSMauro Carvalho Chehab buffer[2] = CMD_STATUS; 12430aa77f6cSMauro Carvalho Chehab *pstatus = 0; 12440aa77f6cSMauro Carvalho Chehab channel->vidstatus_ready = 0; 12450aa77f6cSMauro Carvalho Chehab res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 12460aa77f6cSMauro Carvalho Chehab kfree(buffer); 12470aa77f6cSMauro Carvalho Chehab wait_event_timeout(channel->wait_vidstatus, 12480aa77f6cSMauro Carvalho Chehab (channel->vidstatus_ready != 0), 12490aa77f6cSMauro Carvalho Chehab msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT)); 12500aa77f6cSMauro Carvalho Chehab if (channel->vidstatus_ready != 1) { 12510aa77f6cSMauro Carvalho Chehab printk(KERN_DEBUG "s2255: no vidstatus response\n"); 12520aa77f6cSMauro Carvalho Chehab res = -EFAULT; 12530aa77f6cSMauro Carvalho Chehab } 12540aa77f6cSMauro Carvalho Chehab *pstatus = channel->vidstatus; 12550aa77f6cSMauro Carvalho Chehab dprintk(4, "%s, vid status %d\n", __func__, *pstatus); 12560aa77f6cSMauro Carvalho Chehab return res; 12570aa77f6cSMauro Carvalho Chehab } 12580aa77f6cSMauro Carvalho Chehab 12590aa77f6cSMauro Carvalho Chehab static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) 12600aa77f6cSMauro Carvalho Chehab { 12610aa77f6cSMauro Carvalho Chehab int res; 12620aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 12630aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = fh->dev; 12640aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 12650aa77f6cSMauro Carvalho Chehab int j; 12660aa77f6cSMauro Carvalho Chehab dprintk(4, "%s\n", __func__); 12670aa77f6cSMauro Carvalho Chehab if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 12680aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "invalid fh type0\n"); 12690aa77f6cSMauro Carvalho Chehab return -EINVAL; 12700aa77f6cSMauro Carvalho Chehab } 12710aa77f6cSMauro Carvalho Chehab if (i != fh->type) { 12720aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "invalid fh type1\n"); 12730aa77f6cSMauro Carvalho Chehab return -EINVAL; 12740aa77f6cSMauro Carvalho Chehab } 12750aa77f6cSMauro Carvalho Chehab 12760aa77f6cSMauro Carvalho Chehab if (!res_get(fh)) { 12770aa77f6cSMauro Carvalho Chehab s2255_dev_err(&dev->udev->dev, "stream busy\n"); 12780aa77f6cSMauro Carvalho Chehab return -EBUSY; 12790aa77f6cSMauro Carvalho Chehab } 12800aa77f6cSMauro Carvalho Chehab channel->last_frame = -1; 12810aa77f6cSMauro Carvalho Chehab channel->bad_payload = 0; 12820aa77f6cSMauro Carvalho Chehab channel->cur_frame = 0; 12830aa77f6cSMauro Carvalho Chehab channel->frame_count = 0; 12840aa77f6cSMauro Carvalho Chehab for (j = 0; j < SYS_FRAMES; j++) { 12850aa77f6cSMauro Carvalho Chehab channel->buffer.frame[j].ulState = S2255_READ_IDLE; 12860aa77f6cSMauro Carvalho Chehab channel->buffer.frame[j].cur_size = 0; 12870aa77f6cSMauro Carvalho Chehab } 12880aa77f6cSMauro Carvalho Chehab res = videobuf_streamon(&fh->vb_vidq); 12890aa77f6cSMauro Carvalho Chehab if (res == 0) { 12900aa77f6cSMauro Carvalho Chehab s2255_start_acquire(channel); 12910aa77f6cSMauro Carvalho Chehab channel->b_acquire = 1; 12920aa77f6cSMauro Carvalho Chehab } else 12930aa77f6cSMauro Carvalho Chehab res_free(fh); 12940aa77f6cSMauro Carvalho Chehab 12950aa77f6cSMauro Carvalho Chehab return res; 12960aa77f6cSMauro Carvalho Chehab } 12970aa77f6cSMauro Carvalho Chehab 12980aa77f6cSMauro Carvalho Chehab static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) 12990aa77f6cSMauro Carvalho Chehab { 13000aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 13010aa77f6cSMauro Carvalho Chehab dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx); 13020aa77f6cSMauro Carvalho Chehab if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 13030aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "invalid fh type0\n"); 13040aa77f6cSMauro Carvalho Chehab return -EINVAL; 13050aa77f6cSMauro Carvalho Chehab } 13060aa77f6cSMauro Carvalho Chehab if (i != fh->type) { 13070aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "invalid type i\n"); 13080aa77f6cSMauro Carvalho Chehab return -EINVAL; 13090aa77f6cSMauro Carvalho Chehab } 13100aa77f6cSMauro Carvalho Chehab s2255_stop_acquire(fh->channel); 13110aa77f6cSMauro Carvalho Chehab videobuf_streamoff(&fh->vb_vidq); 13120aa77f6cSMauro Carvalho Chehab res_free(fh); 13130aa77f6cSMauro Carvalho Chehab return 0; 13140aa77f6cSMauro Carvalho Chehab } 13150aa77f6cSMauro Carvalho Chehab 13160aa77f6cSMauro Carvalho Chehab static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) 13170aa77f6cSMauro Carvalho Chehab { 13180aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 13190aa77f6cSMauro Carvalho Chehab struct s2255_mode mode; 13200aa77f6cSMauro Carvalho Chehab struct videobuf_queue *q = &fh->vb_vidq; 13210aa77f6cSMauro Carvalho Chehab int ret = 0; 13220aa77f6cSMauro Carvalho Chehab mutex_lock(&q->vb_lock); 13230aa77f6cSMauro Carvalho Chehab if (videobuf_queue_is_busy(q)) { 13240aa77f6cSMauro Carvalho Chehab dprintk(1, "queue busy\n"); 13250aa77f6cSMauro Carvalho Chehab ret = -EBUSY; 13260aa77f6cSMauro Carvalho Chehab goto out_s_std; 13270aa77f6cSMauro Carvalho Chehab } 13280aa77f6cSMauro Carvalho Chehab if (res_locked(fh)) { 13290aa77f6cSMauro Carvalho Chehab dprintk(1, "can't change standard after started\n"); 13300aa77f6cSMauro Carvalho Chehab ret = -EBUSY; 13310aa77f6cSMauro Carvalho Chehab goto out_s_std; 13320aa77f6cSMauro Carvalho Chehab } 13330aa77f6cSMauro Carvalho Chehab mode = fh->channel->mode; 13340aa77f6cSMauro Carvalho Chehab if (*i & V4L2_STD_NTSC) { 13350aa77f6cSMauro Carvalho Chehab dprintk(4, "%s NTSC\n", __func__); 13360aa77f6cSMauro Carvalho Chehab /* if changing format, reset frame decimation/intervals */ 13370aa77f6cSMauro Carvalho Chehab if (mode.format != FORMAT_NTSC) { 13380aa77f6cSMauro Carvalho Chehab mode.restart = 1; 13390aa77f6cSMauro Carvalho Chehab mode.format = FORMAT_NTSC; 13400aa77f6cSMauro Carvalho Chehab mode.fdec = FDEC_1; 13410aa77f6cSMauro Carvalho Chehab } 13420aa77f6cSMauro Carvalho Chehab } else if (*i & V4L2_STD_PAL) { 13430aa77f6cSMauro Carvalho Chehab dprintk(4, "%s PAL\n", __func__); 13440aa77f6cSMauro Carvalho Chehab if (mode.format != FORMAT_PAL) { 13450aa77f6cSMauro Carvalho Chehab mode.restart = 1; 13460aa77f6cSMauro Carvalho Chehab mode.format = FORMAT_PAL; 13470aa77f6cSMauro Carvalho Chehab mode.fdec = FDEC_1; 13480aa77f6cSMauro Carvalho Chehab } 13490aa77f6cSMauro Carvalho Chehab } else { 13500aa77f6cSMauro Carvalho Chehab ret = -EINVAL; 13510aa77f6cSMauro Carvalho Chehab } 13520aa77f6cSMauro Carvalho Chehab if (mode.restart) 13530aa77f6cSMauro Carvalho Chehab s2255_set_mode(fh->channel, &mode); 13540aa77f6cSMauro Carvalho Chehab out_s_std: 13550aa77f6cSMauro Carvalho Chehab mutex_unlock(&q->vb_lock); 13560aa77f6cSMauro Carvalho Chehab return ret; 13570aa77f6cSMauro Carvalho Chehab } 13580aa77f6cSMauro Carvalho Chehab 13590aa77f6cSMauro Carvalho Chehab /* Sensoray 2255 is a multiple channel capture device. 13600aa77f6cSMauro Carvalho Chehab It does not have a "crossbar" of inputs. 13610aa77f6cSMauro Carvalho Chehab We use one V4L device per channel. The user must 13620aa77f6cSMauro Carvalho Chehab be aware that certain combinations are not allowed. 13630aa77f6cSMauro Carvalho Chehab For instance, you cannot do full FPS on more than 2 channels(2 videodevs) 13640aa77f6cSMauro Carvalho Chehab at once in color(you can do full fps on 4 channels with greyscale. 13650aa77f6cSMauro Carvalho Chehab */ 13660aa77f6cSMauro Carvalho Chehab static int vidioc_enum_input(struct file *file, void *priv, 13670aa77f6cSMauro Carvalho Chehab struct v4l2_input *inp) 13680aa77f6cSMauro Carvalho Chehab { 13690aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 13700aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = fh->dev; 13710aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 13720aa77f6cSMauro Carvalho Chehab u32 status = 0; 13730aa77f6cSMauro Carvalho Chehab if (inp->index != 0) 13740aa77f6cSMauro Carvalho Chehab return -EINVAL; 13750aa77f6cSMauro Carvalho Chehab inp->type = V4L2_INPUT_TYPE_CAMERA; 13760aa77f6cSMauro Carvalho Chehab inp->std = S2255_NORMS; 13770aa77f6cSMauro Carvalho Chehab inp->status = 0; 13780aa77f6cSMauro Carvalho Chehab if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { 13790aa77f6cSMauro Carvalho Chehab int rc; 13800aa77f6cSMauro Carvalho Chehab rc = s2255_cmd_status(fh->channel, &status); 13810aa77f6cSMauro Carvalho Chehab dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status); 13820aa77f6cSMauro Carvalho Chehab if (rc == 0) 13830aa77f6cSMauro Carvalho Chehab inp->status = (status & 0x01) ? 0 13840aa77f6cSMauro Carvalho Chehab : V4L2_IN_ST_NO_SIGNAL; 13850aa77f6cSMauro Carvalho Chehab } 13860aa77f6cSMauro Carvalho Chehab switch (dev->pid) { 13870aa77f6cSMauro Carvalho Chehab case 0x2255: 13880aa77f6cSMauro Carvalho Chehab default: 13890aa77f6cSMauro Carvalho Chehab strlcpy(inp->name, "Composite", sizeof(inp->name)); 13900aa77f6cSMauro Carvalho Chehab break; 13910aa77f6cSMauro Carvalho Chehab case 0x2257: 13920aa77f6cSMauro Carvalho Chehab strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video", 13930aa77f6cSMauro Carvalho Chehab sizeof(inp->name)); 13940aa77f6cSMauro Carvalho Chehab break; 13950aa77f6cSMauro Carvalho Chehab } 13960aa77f6cSMauro Carvalho Chehab return 0; 13970aa77f6cSMauro Carvalho Chehab } 13980aa77f6cSMauro Carvalho Chehab 13990aa77f6cSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) 14000aa77f6cSMauro Carvalho Chehab { 14010aa77f6cSMauro Carvalho Chehab *i = 0; 14020aa77f6cSMauro Carvalho Chehab return 0; 14030aa77f6cSMauro Carvalho Chehab } 14040aa77f6cSMauro Carvalho Chehab static int vidioc_s_input(struct file *file, void *priv, unsigned int i) 14050aa77f6cSMauro Carvalho Chehab { 14060aa77f6cSMauro Carvalho Chehab if (i > 0) 14070aa77f6cSMauro Carvalho Chehab return -EINVAL; 14080aa77f6cSMauro Carvalho Chehab return 0; 14090aa77f6cSMauro Carvalho Chehab } 14100aa77f6cSMauro Carvalho Chehab 1411192f1e78SHans Verkuil static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) 14120aa77f6cSMauro Carvalho Chehab { 1413192f1e78SHans Verkuil struct s2255_channel *channel = 1414192f1e78SHans Verkuil container_of(ctrl->handler, struct s2255_channel, hdl); 14150aa77f6cSMauro Carvalho Chehab struct s2255_mode mode; 1416192f1e78SHans Verkuil 14170aa77f6cSMauro Carvalho Chehab mode = channel->mode; 14180aa77f6cSMauro Carvalho Chehab dprintk(4, "%s\n", __func__); 1419192f1e78SHans Verkuil 14200aa77f6cSMauro Carvalho Chehab /* update the mode to the corresponding value */ 14210aa77f6cSMauro Carvalho Chehab switch (ctrl->id) { 14220aa77f6cSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 1423192f1e78SHans Verkuil mode.bright = ctrl->val; 14240aa77f6cSMauro Carvalho Chehab break; 14250aa77f6cSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 1426192f1e78SHans Verkuil mode.contrast = ctrl->val; 14270aa77f6cSMauro Carvalho Chehab break; 14280aa77f6cSMauro Carvalho Chehab case V4L2_CID_HUE: 1429192f1e78SHans Verkuil mode.hue = ctrl->val; 14300aa77f6cSMauro Carvalho Chehab break; 14310aa77f6cSMauro Carvalho Chehab case V4L2_CID_SATURATION: 1432192f1e78SHans Verkuil mode.saturation = ctrl->val; 14330aa77f6cSMauro Carvalho Chehab break; 1434192f1e78SHans Verkuil case V4L2_CID_S2255_COLORFILTER: 14350aa77f6cSMauro Carvalho Chehab mode.color &= ~MASK_INPUT_TYPE; 1436192f1e78SHans Verkuil mode.color |= !ctrl->val << 16; 14370aa77f6cSMauro Carvalho Chehab break; 1438*7041dec7SHans Verkuil case V4L2_CID_JPEG_COMPRESSION_QUALITY: 1439*7041dec7SHans Verkuil channel->jpegqual = ctrl->val; 1440*7041dec7SHans Verkuil return 0; 14410aa77f6cSMauro Carvalho Chehab default: 14420aa77f6cSMauro Carvalho Chehab return -EINVAL; 14430aa77f6cSMauro Carvalho Chehab } 14440aa77f6cSMauro Carvalho Chehab mode.restart = 0; 14450aa77f6cSMauro Carvalho Chehab /* set mode here. Note: stream does not need restarted. 14460aa77f6cSMauro Carvalho Chehab some V4L programs restart stream unnecessarily 14470aa77f6cSMauro Carvalho Chehab after a s_crtl. 14480aa77f6cSMauro Carvalho Chehab */ 1449192f1e78SHans Verkuil s2255_set_mode(channel, &mode); 14500aa77f6cSMauro Carvalho Chehab return 0; 14510aa77f6cSMauro Carvalho Chehab } 14520aa77f6cSMauro Carvalho Chehab 14530aa77f6cSMauro Carvalho Chehab static int vidioc_g_jpegcomp(struct file *file, void *priv, 14540aa77f6cSMauro Carvalho Chehab struct v4l2_jpegcompression *jc) 14550aa77f6cSMauro Carvalho Chehab { 14560aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 14570aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 1458*7041dec7SHans Verkuil 1459*7041dec7SHans Verkuil memset(jc, 0, sizeof(*jc)); 1460*7041dec7SHans Verkuil jc->quality = channel->jpegqual; 14610aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: quality %d\n", __func__, jc->quality); 14620aa77f6cSMauro Carvalho Chehab return 0; 14630aa77f6cSMauro Carvalho Chehab } 14640aa77f6cSMauro Carvalho Chehab 14650aa77f6cSMauro Carvalho Chehab static int vidioc_s_jpegcomp(struct file *file, void *priv, 1466d88aab53SHans Verkuil const struct v4l2_jpegcompression *jc) 14670aa77f6cSMauro Carvalho Chehab { 14680aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 14690aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 14700aa77f6cSMauro Carvalho Chehab if (jc->quality < 0 || jc->quality > 100) 14710aa77f6cSMauro Carvalho Chehab return -EINVAL; 1472*7041dec7SHans Verkuil v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality); 14730aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: quality %d\n", __func__, jc->quality); 14740aa77f6cSMauro Carvalho Chehab return 0; 14750aa77f6cSMauro Carvalho Chehab } 14760aa77f6cSMauro Carvalho Chehab 14770aa77f6cSMauro Carvalho Chehab static int vidioc_g_parm(struct file *file, void *priv, 14780aa77f6cSMauro Carvalho Chehab struct v4l2_streamparm *sp) 14790aa77f6cSMauro Carvalho Chehab { 14800aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 14810aa77f6cSMauro Carvalho Chehab __u32 def_num, def_dem; 14820aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 14830aa77f6cSMauro Carvalho Chehab if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 14840aa77f6cSMauro Carvalho Chehab return -EINVAL; 14850aa77f6cSMauro Carvalho Chehab memset(sp, 0, sizeof(struct v4l2_streamparm)); 14860aa77f6cSMauro Carvalho Chehab sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 14870aa77f6cSMauro Carvalho Chehab sp->parm.capture.capturemode = channel->cap_parm.capturemode; 14880aa77f6cSMauro Carvalho Chehab def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000; 14890aa77f6cSMauro Carvalho Chehab def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000; 14900aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.denominator = def_dem; 14910aa77f6cSMauro Carvalho Chehab switch (channel->mode.fdec) { 14920aa77f6cSMauro Carvalho Chehab default: 14930aa77f6cSMauro Carvalho Chehab case FDEC_1: 14940aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num; 14950aa77f6cSMauro Carvalho Chehab break; 14960aa77f6cSMauro Carvalho Chehab case FDEC_2: 14970aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 2; 14980aa77f6cSMauro Carvalho Chehab break; 14990aa77f6cSMauro Carvalho Chehab case FDEC_3: 15000aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 3; 15010aa77f6cSMauro Carvalho Chehab break; 15020aa77f6cSMauro Carvalho Chehab case FDEC_5: 15030aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 5; 15040aa77f6cSMauro Carvalho Chehab break; 15050aa77f6cSMauro Carvalho Chehab } 15060aa77f6cSMauro Carvalho Chehab dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__, 15070aa77f6cSMauro Carvalho Chehab sp->parm.capture.capturemode, 15080aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator, 15090aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.denominator); 15100aa77f6cSMauro Carvalho Chehab return 0; 15110aa77f6cSMauro Carvalho Chehab } 15120aa77f6cSMauro Carvalho Chehab 15130aa77f6cSMauro Carvalho Chehab static int vidioc_s_parm(struct file *file, void *priv, 15140aa77f6cSMauro Carvalho Chehab struct v4l2_streamparm *sp) 15150aa77f6cSMauro Carvalho Chehab { 15160aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = priv; 15170aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 15180aa77f6cSMauro Carvalho Chehab struct s2255_mode mode; 15190aa77f6cSMauro Carvalho Chehab int fdec = FDEC_1; 15200aa77f6cSMauro Carvalho Chehab __u32 def_num, def_dem; 15210aa77f6cSMauro Carvalho Chehab if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 15220aa77f6cSMauro Carvalho Chehab return -EINVAL; 15230aa77f6cSMauro Carvalho Chehab mode = channel->mode; 15240aa77f6cSMauro Carvalho Chehab /* high quality capture mode requires a stream restart */ 15250aa77f6cSMauro Carvalho Chehab if (channel->cap_parm.capturemode 15260aa77f6cSMauro Carvalho Chehab != sp->parm.capture.capturemode && res_locked(fh)) 15270aa77f6cSMauro Carvalho Chehab return -EBUSY; 15280aa77f6cSMauro Carvalho Chehab def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; 15290aa77f6cSMauro Carvalho Chehab def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; 15300aa77f6cSMauro Carvalho Chehab if (def_dem != sp->parm.capture.timeperframe.denominator) 15310aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num; 15320aa77f6cSMauro Carvalho Chehab else if (sp->parm.capture.timeperframe.numerator <= def_num) 15330aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num; 15340aa77f6cSMauro Carvalho Chehab else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { 15350aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 2; 15360aa77f6cSMauro Carvalho Chehab fdec = FDEC_2; 15370aa77f6cSMauro Carvalho Chehab } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) { 15380aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 3; 15390aa77f6cSMauro Carvalho Chehab fdec = FDEC_3; 15400aa77f6cSMauro Carvalho Chehab } else { 15410aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator = def_num * 5; 15420aa77f6cSMauro Carvalho Chehab fdec = FDEC_5; 15430aa77f6cSMauro Carvalho Chehab } 15440aa77f6cSMauro Carvalho Chehab mode.fdec = fdec; 15450aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.denominator = def_dem; 15460aa77f6cSMauro Carvalho Chehab s2255_set_mode(channel, &mode); 15470aa77f6cSMauro Carvalho Chehab dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", 15480aa77f6cSMauro Carvalho Chehab __func__, 15490aa77f6cSMauro Carvalho Chehab sp->parm.capture.capturemode, 15500aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.numerator, 15510aa77f6cSMauro Carvalho Chehab sp->parm.capture.timeperframe.denominator, fdec); 15520aa77f6cSMauro Carvalho Chehab return 0; 15530aa77f6cSMauro Carvalho Chehab } 15540aa77f6cSMauro Carvalho Chehab 15550aa77f6cSMauro Carvalho Chehab static int vidioc_enum_frameintervals(struct file *file, void *priv, 15560aa77f6cSMauro Carvalho Chehab struct v4l2_frmivalenum *fe) 15570aa77f6cSMauro Carvalho Chehab { 15580aa77f6cSMauro Carvalho Chehab int is_ntsc = 0; 15590aa77f6cSMauro Carvalho Chehab #define NUM_FRAME_ENUMS 4 15600aa77f6cSMauro Carvalho Chehab int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; 1561199ab8feSMauro Carvalho Chehab if (fe->index >= NUM_FRAME_ENUMS) 15620aa77f6cSMauro Carvalho Chehab return -EINVAL; 15630aa77f6cSMauro Carvalho Chehab switch (fe->width) { 15640aa77f6cSMauro Carvalho Chehab case 640: 15650aa77f6cSMauro Carvalho Chehab if (fe->height != 240 && fe->height != 480) 15660aa77f6cSMauro Carvalho Chehab return -EINVAL; 15670aa77f6cSMauro Carvalho Chehab is_ntsc = 1; 15680aa77f6cSMauro Carvalho Chehab break; 15690aa77f6cSMauro Carvalho Chehab case 320: 15700aa77f6cSMauro Carvalho Chehab if (fe->height != 240) 15710aa77f6cSMauro Carvalho Chehab return -EINVAL; 15720aa77f6cSMauro Carvalho Chehab is_ntsc = 1; 15730aa77f6cSMauro Carvalho Chehab break; 15740aa77f6cSMauro Carvalho Chehab case 704: 15750aa77f6cSMauro Carvalho Chehab if (fe->height != 288 && fe->height != 576) 15760aa77f6cSMauro Carvalho Chehab return -EINVAL; 15770aa77f6cSMauro Carvalho Chehab break; 15780aa77f6cSMauro Carvalho Chehab case 352: 15790aa77f6cSMauro Carvalho Chehab if (fe->height != 288) 15800aa77f6cSMauro Carvalho Chehab return -EINVAL; 15810aa77f6cSMauro Carvalho Chehab break; 15820aa77f6cSMauro Carvalho Chehab default: 15830aa77f6cSMauro Carvalho Chehab return -EINVAL; 15840aa77f6cSMauro Carvalho Chehab } 15850aa77f6cSMauro Carvalho Chehab fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; 15860aa77f6cSMauro Carvalho Chehab fe->discrete.denominator = is_ntsc ? 30000 : 25000; 15870aa77f6cSMauro Carvalho Chehab fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; 15880aa77f6cSMauro Carvalho Chehab dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator, 15890aa77f6cSMauro Carvalho Chehab fe->discrete.denominator); 15900aa77f6cSMauro Carvalho Chehab return 0; 15910aa77f6cSMauro Carvalho Chehab } 15920aa77f6cSMauro Carvalho Chehab 15930aa77f6cSMauro Carvalho Chehab static int __s2255_open(struct file *file) 15940aa77f6cSMauro Carvalho Chehab { 15950aa77f6cSMauro Carvalho Chehab struct video_device *vdev = video_devdata(file); 15960aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = video_drvdata(file); 15970aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); 15980aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh; 15990aa77f6cSMauro Carvalho Chehab enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 16000aa77f6cSMauro Carvalho Chehab int state; 16010aa77f6cSMauro Carvalho Chehab dprintk(1, "s2255: open called (dev=%s)\n", 16020aa77f6cSMauro Carvalho Chehab video_device_node_name(vdev)); 16030aa77f6cSMauro Carvalho Chehab state = atomic_read(&dev->fw_data->fw_state); 16040aa77f6cSMauro Carvalho Chehab switch (state) { 16050aa77f6cSMauro Carvalho Chehab case S2255_FW_DISCONNECTING: 16060aa77f6cSMauro Carvalho Chehab return -ENODEV; 16070aa77f6cSMauro Carvalho Chehab case S2255_FW_FAILED: 16080aa77f6cSMauro Carvalho Chehab s2255_dev_err(&dev->udev->dev, 16090aa77f6cSMauro Carvalho Chehab "firmware load failed. retrying.\n"); 16100aa77f6cSMauro Carvalho Chehab s2255_fwload_start(dev, 1); 16110aa77f6cSMauro Carvalho Chehab wait_event_timeout(dev->fw_data->wait_fw, 16120aa77f6cSMauro Carvalho Chehab ((atomic_read(&dev->fw_data->fw_state) 16130aa77f6cSMauro Carvalho Chehab == S2255_FW_SUCCESS) || 16140aa77f6cSMauro Carvalho Chehab (atomic_read(&dev->fw_data->fw_state) 16150aa77f6cSMauro Carvalho Chehab == S2255_FW_DISCONNECTING)), 16160aa77f6cSMauro Carvalho Chehab msecs_to_jiffies(S2255_LOAD_TIMEOUT)); 16170aa77f6cSMauro Carvalho Chehab /* state may have changed, re-read */ 16180aa77f6cSMauro Carvalho Chehab state = atomic_read(&dev->fw_data->fw_state); 16190aa77f6cSMauro Carvalho Chehab break; 16200aa77f6cSMauro Carvalho Chehab case S2255_FW_NOTLOADED: 16210aa77f6cSMauro Carvalho Chehab case S2255_FW_LOADED_DSPWAIT: 16220aa77f6cSMauro Carvalho Chehab /* give S2255_LOAD_TIMEOUT time for firmware to load in case 16230aa77f6cSMauro Carvalho Chehab driver loaded and then device immediately opened */ 16240aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "%s waiting for firmware load\n", __func__); 16250aa77f6cSMauro Carvalho Chehab wait_event_timeout(dev->fw_data->wait_fw, 16260aa77f6cSMauro Carvalho Chehab ((atomic_read(&dev->fw_data->fw_state) 16270aa77f6cSMauro Carvalho Chehab == S2255_FW_SUCCESS) || 16280aa77f6cSMauro Carvalho Chehab (atomic_read(&dev->fw_data->fw_state) 16290aa77f6cSMauro Carvalho Chehab == S2255_FW_DISCONNECTING)), 16300aa77f6cSMauro Carvalho Chehab msecs_to_jiffies(S2255_LOAD_TIMEOUT)); 16310aa77f6cSMauro Carvalho Chehab /* state may have changed, re-read */ 16320aa77f6cSMauro Carvalho Chehab state = atomic_read(&dev->fw_data->fw_state); 16330aa77f6cSMauro Carvalho Chehab break; 16340aa77f6cSMauro Carvalho Chehab case S2255_FW_SUCCESS: 16350aa77f6cSMauro Carvalho Chehab default: 16360aa77f6cSMauro Carvalho Chehab break; 16370aa77f6cSMauro Carvalho Chehab } 16380aa77f6cSMauro Carvalho Chehab /* state may have changed in above switch statement */ 16390aa77f6cSMauro Carvalho Chehab switch (state) { 16400aa77f6cSMauro Carvalho Chehab case S2255_FW_SUCCESS: 16410aa77f6cSMauro Carvalho Chehab break; 16420aa77f6cSMauro Carvalho Chehab case S2255_FW_FAILED: 16430aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "2255 firmware load failed.\n"); 16440aa77f6cSMauro Carvalho Chehab return -ENODEV; 16450aa77f6cSMauro Carvalho Chehab case S2255_FW_DISCONNECTING: 16460aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "%s: disconnecting\n", __func__); 16470aa77f6cSMauro Carvalho Chehab return -ENODEV; 16480aa77f6cSMauro Carvalho Chehab case S2255_FW_LOADED_DSPWAIT: 16490aa77f6cSMauro Carvalho Chehab case S2255_FW_NOTLOADED: 16500aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "%s: firmware not loaded yet" 16510aa77f6cSMauro Carvalho Chehab "please try again later\n", 16520aa77f6cSMauro Carvalho Chehab __func__); 16530aa77f6cSMauro Carvalho Chehab /* 16540aa77f6cSMauro Carvalho Chehab * Timeout on firmware load means device unusable. 16550aa77f6cSMauro Carvalho Chehab * Set firmware failure state. 16560aa77f6cSMauro Carvalho Chehab * On next s2255_open the firmware will be reloaded. 16570aa77f6cSMauro Carvalho Chehab */ 16580aa77f6cSMauro Carvalho Chehab atomic_set(&dev->fw_data->fw_state, 16590aa77f6cSMauro Carvalho Chehab S2255_FW_FAILED); 16600aa77f6cSMauro Carvalho Chehab return -EAGAIN; 16610aa77f6cSMauro Carvalho Chehab default: 16620aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "%s: unknown state\n", __func__); 16630aa77f6cSMauro Carvalho Chehab return -EFAULT; 16640aa77f6cSMauro Carvalho Chehab } 16650aa77f6cSMauro Carvalho Chehab /* allocate + initialize per filehandle data */ 16660aa77f6cSMauro Carvalho Chehab fh = kzalloc(sizeof(*fh), GFP_KERNEL); 16670aa77f6cSMauro Carvalho Chehab if (NULL == fh) 16680aa77f6cSMauro Carvalho Chehab return -ENOMEM; 16690aa77f6cSMauro Carvalho Chehab file->private_data = fh; 16700aa77f6cSMauro Carvalho Chehab fh->dev = dev; 16710aa77f6cSMauro Carvalho Chehab fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 16720aa77f6cSMauro Carvalho Chehab fh->channel = channel; 16730aa77f6cSMauro Carvalho Chehab if (!channel->configured) { 16740aa77f6cSMauro Carvalho Chehab /* configure channel to default state */ 16750aa77f6cSMauro Carvalho Chehab channel->fmt = &formats[0]; 16760aa77f6cSMauro Carvalho Chehab s2255_set_mode(channel, &channel->mode); 16770aa77f6cSMauro Carvalho Chehab channel->configured = 1; 16780aa77f6cSMauro Carvalho Chehab } 16790aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: dev=%s type=%s\n", __func__, 16800aa77f6cSMauro Carvalho Chehab video_device_node_name(vdev), v4l2_type_names[type]); 16810aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__, 16820aa77f6cSMauro Carvalho Chehab (unsigned long)fh, (unsigned long)dev, 16830aa77f6cSMauro Carvalho Chehab (unsigned long)&channel->vidq); 16840aa77f6cSMauro Carvalho Chehab dprintk(4, "%s: list_empty active=%d\n", __func__, 16850aa77f6cSMauro Carvalho Chehab list_empty(&channel->vidq.active)); 16860aa77f6cSMauro Carvalho Chehab videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops, 16870aa77f6cSMauro Carvalho Chehab NULL, &dev->slock, 16880aa77f6cSMauro Carvalho Chehab fh->type, 16890aa77f6cSMauro Carvalho Chehab V4L2_FIELD_INTERLACED, 16900aa77f6cSMauro Carvalho Chehab sizeof(struct s2255_buffer), 16910aa77f6cSMauro Carvalho Chehab fh, vdev->lock); 16920aa77f6cSMauro Carvalho Chehab return 0; 16930aa77f6cSMauro Carvalho Chehab } 16940aa77f6cSMauro Carvalho Chehab 16950aa77f6cSMauro Carvalho Chehab static int s2255_open(struct file *file) 16960aa77f6cSMauro Carvalho Chehab { 16970aa77f6cSMauro Carvalho Chehab struct video_device *vdev = video_devdata(file); 16980aa77f6cSMauro Carvalho Chehab int ret; 16990aa77f6cSMauro Carvalho Chehab 17000aa77f6cSMauro Carvalho Chehab if (mutex_lock_interruptible(vdev->lock)) 17010aa77f6cSMauro Carvalho Chehab return -ERESTARTSYS; 17020aa77f6cSMauro Carvalho Chehab ret = __s2255_open(file); 17030aa77f6cSMauro Carvalho Chehab mutex_unlock(vdev->lock); 17040aa77f6cSMauro Carvalho Chehab return ret; 17050aa77f6cSMauro Carvalho Chehab } 17060aa77f6cSMauro Carvalho Chehab 17070aa77f6cSMauro Carvalho Chehab static unsigned int s2255_poll(struct file *file, 17080aa77f6cSMauro Carvalho Chehab struct poll_table_struct *wait) 17090aa77f6cSMauro Carvalho Chehab { 17100aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = file->private_data; 17110aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = fh->dev; 17120aa77f6cSMauro Carvalho Chehab int rc; 17130aa77f6cSMauro Carvalho Chehab dprintk(100, "%s\n", __func__); 17140aa77f6cSMauro Carvalho Chehab if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) 17150aa77f6cSMauro Carvalho Chehab return POLLERR; 17160aa77f6cSMauro Carvalho Chehab mutex_lock(&dev->lock); 17170aa77f6cSMauro Carvalho Chehab rc = videobuf_poll_stream(file, &fh->vb_vidq, wait); 17180aa77f6cSMauro Carvalho Chehab mutex_unlock(&dev->lock); 17190aa77f6cSMauro Carvalho Chehab return rc; 17200aa77f6cSMauro Carvalho Chehab } 17210aa77f6cSMauro Carvalho Chehab 17220aa77f6cSMauro Carvalho Chehab static void s2255_destroy(struct s2255_dev *dev) 17230aa77f6cSMauro Carvalho Chehab { 17240aa77f6cSMauro Carvalho Chehab /* board shutdown stops the read pipe if it is running */ 17250aa77f6cSMauro Carvalho Chehab s2255_board_shutdown(dev); 17260aa77f6cSMauro Carvalho Chehab /* make sure firmware still not trying to load */ 17270aa77f6cSMauro Carvalho Chehab del_timer(&dev->timer); /* only started in .probe and .open */ 17280aa77f6cSMauro Carvalho Chehab if (dev->fw_data->fw_urb) { 17290aa77f6cSMauro Carvalho Chehab usb_kill_urb(dev->fw_data->fw_urb); 17300aa77f6cSMauro Carvalho Chehab usb_free_urb(dev->fw_data->fw_urb); 17310aa77f6cSMauro Carvalho Chehab dev->fw_data->fw_urb = NULL; 17320aa77f6cSMauro Carvalho Chehab } 17330aa77f6cSMauro Carvalho Chehab release_firmware(dev->fw_data->fw); 17340aa77f6cSMauro Carvalho Chehab kfree(dev->fw_data->pfw_data); 17350aa77f6cSMauro Carvalho Chehab kfree(dev->fw_data); 17360aa77f6cSMauro Carvalho Chehab /* reset the DSP so firmware can be reloaded next time */ 17370aa77f6cSMauro Carvalho Chehab s2255_reset_dsppower(dev); 17380aa77f6cSMauro Carvalho Chehab mutex_destroy(&dev->lock); 17390aa77f6cSMauro Carvalho Chehab usb_put_dev(dev->udev); 17400aa77f6cSMauro Carvalho Chehab v4l2_device_unregister(&dev->v4l2_dev); 17410aa77f6cSMauro Carvalho Chehab dprintk(1, "%s", __func__); 17420aa77f6cSMauro Carvalho Chehab kfree(dev); 17430aa77f6cSMauro Carvalho Chehab } 17440aa77f6cSMauro Carvalho Chehab 17450aa77f6cSMauro Carvalho Chehab static int s2255_release(struct file *file) 17460aa77f6cSMauro Carvalho Chehab { 17470aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = file->private_data; 17480aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = fh->dev; 17490aa77f6cSMauro Carvalho Chehab struct video_device *vdev = video_devdata(file); 17500aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = fh->channel; 17510aa77f6cSMauro Carvalho Chehab if (!dev) 17520aa77f6cSMauro Carvalho Chehab return -ENODEV; 17530aa77f6cSMauro Carvalho Chehab mutex_lock(&dev->lock); 17540aa77f6cSMauro Carvalho Chehab /* turn off stream */ 17550aa77f6cSMauro Carvalho Chehab if (res_check(fh)) { 17560aa77f6cSMauro Carvalho Chehab if (channel->b_acquire) 17570aa77f6cSMauro Carvalho Chehab s2255_stop_acquire(fh->channel); 17580aa77f6cSMauro Carvalho Chehab videobuf_streamoff(&fh->vb_vidq); 17590aa77f6cSMauro Carvalho Chehab res_free(fh); 17600aa77f6cSMauro Carvalho Chehab } 17610aa77f6cSMauro Carvalho Chehab videobuf_mmap_free(&fh->vb_vidq); 17620aa77f6cSMauro Carvalho Chehab mutex_unlock(&dev->lock); 17630aa77f6cSMauro Carvalho Chehab dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev)); 17640aa77f6cSMauro Carvalho Chehab kfree(fh); 17650aa77f6cSMauro Carvalho Chehab return 0; 17660aa77f6cSMauro Carvalho Chehab } 17670aa77f6cSMauro Carvalho Chehab 17680aa77f6cSMauro Carvalho Chehab static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) 17690aa77f6cSMauro Carvalho Chehab { 17700aa77f6cSMauro Carvalho Chehab struct s2255_fh *fh = file->private_data; 1771e839776fSJulia Lawall struct s2255_dev *dev; 17720aa77f6cSMauro Carvalho Chehab int ret; 17730aa77f6cSMauro Carvalho Chehab 17740aa77f6cSMauro Carvalho Chehab if (!fh) 17750aa77f6cSMauro Carvalho Chehab return -ENODEV; 1776e839776fSJulia Lawall dev = fh->dev; 17770aa77f6cSMauro Carvalho Chehab dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma); 17780aa77f6cSMauro Carvalho Chehab if (mutex_lock_interruptible(&dev->lock)) 17790aa77f6cSMauro Carvalho Chehab return -ERESTARTSYS; 17800aa77f6cSMauro Carvalho Chehab ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); 17810aa77f6cSMauro Carvalho Chehab mutex_unlock(&dev->lock); 17820aa77f6cSMauro Carvalho Chehab dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__, 17830aa77f6cSMauro Carvalho Chehab (unsigned long)vma->vm_start, 17840aa77f6cSMauro Carvalho Chehab (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); 17850aa77f6cSMauro Carvalho Chehab return ret; 17860aa77f6cSMauro Carvalho Chehab } 17870aa77f6cSMauro Carvalho Chehab 17880aa77f6cSMauro Carvalho Chehab static const struct v4l2_file_operations s2255_fops_v4l = { 17890aa77f6cSMauro Carvalho Chehab .owner = THIS_MODULE, 17900aa77f6cSMauro Carvalho Chehab .open = s2255_open, 17910aa77f6cSMauro Carvalho Chehab .release = s2255_release, 17920aa77f6cSMauro Carvalho Chehab .poll = s2255_poll, 17930aa77f6cSMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ 17940aa77f6cSMauro Carvalho Chehab .mmap = s2255_mmap_v4l, 17950aa77f6cSMauro Carvalho Chehab }; 17960aa77f6cSMauro Carvalho Chehab 17970aa77f6cSMauro Carvalho Chehab static const struct v4l2_ioctl_ops s2255_ioctl_ops = { 17980aa77f6cSMauro Carvalho Chehab .vidioc_querycap = vidioc_querycap, 17990aa77f6cSMauro Carvalho Chehab .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 18000aa77f6cSMauro Carvalho Chehab .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 18010aa77f6cSMauro Carvalho Chehab .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 18020aa77f6cSMauro Carvalho Chehab .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 18030aa77f6cSMauro Carvalho Chehab .vidioc_reqbufs = vidioc_reqbufs, 18040aa77f6cSMauro Carvalho Chehab .vidioc_querybuf = vidioc_querybuf, 18050aa77f6cSMauro Carvalho Chehab .vidioc_qbuf = vidioc_qbuf, 18060aa77f6cSMauro Carvalho Chehab .vidioc_dqbuf = vidioc_dqbuf, 18070aa77f6cSMauro Carvalho Chehab .vidioc_s_std = vidioc_s_std, 18080aa77f6cSMauro Carvalho Chehab .vidioc_enum_input = vidioc_enum_input, 18090aa77f6cSMauro Carvalho Chehab .vidioc_g_input = vidioc_g_input, 18100aa77f6cSMauro Carvalho Chehab .vidioc_s_input = vidioc_s_input, 18110aa77f6cSMauro Carvalho Chehab .vidioc_streamon = vidioc_streamon, 18120aa77f6cSMauro Carvalho Chehab .vidioc_streamoff = vidioc_streamoff, 18130aa77f6cSMauro Carvalho Chehab .vidioc_s_jpegcomp = vidioc_s_jpegcomp, 18140aa77f6cSMauro Carvalho Chehab .vidioc_g_jpegcomp = vidioc_g_jpegcomp, 18150aa77f6cSMauro Carvalho Chehab .vidioc_s_parm = vidioc_s_parm, 18160aa77f6cSMauro Carvalho Chehab .vidioc_g_parm = vidioc_g_parm, 18170aa77f6cSMauro Carvalho Chehab .vidioc_enum_frameintervals = vidioc_enum_frameintervals, 18180aa77f6cSMauro Carvalho Chehab }; 18190aa77f6cSMauro Carvalho Chehab 18200aa77f6cSMauro Carvalho Chehab static void s2255_video_device_release(struct video_device *vdev) 18210aa77f6cSMauro Carvalho Chehab { 18220aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); 1823192f1e78SHans Verkuil struct s2255_channel *channel = 1824192f1e78SHans Verkuil container_of(vdev, struct s2255_channel, vdev); 1825192f1e78SHans Verkuil 1826192f1e78SHans Verkuil v4l2_ctrl_handler_free(&channel->hdl); 18270aa77f6cSMauro Carvalho Chehab dprintk(4, "%s, chnls: %d\n", __func__, 18280aa77f6cSMauro Carvalho Chehab atomic_read(&dev->num_channels)); 1829192f1e78SHans Verkuil 18300aa77f6cSMauro Carvalho Chehab if (atomic_dec_and_test(&dev->num_channels)) 18310aa77f6cSMauro Carvalho Chehab s2255_destroy(dev); 18320aa77f6cSMauro Carvalho Chehab return; 18330aa77f6cSMauro Carvalho Chehab } 18340aa77f6cSMauro Carvalho Chehab 18350aa77f6cSMauro Carvalho Chehab static struct video_device template = { 18360aa77f6cSMauro Carvalho Chehab .name = "s2255v", 18370aa77f6cSMauro Carvalho Chehab .fops = &s2255_fops_v4l, 18380aa77f6cSMauro Carvalho Chehab .ioctl_ops = &s2255_ioctl_ops, 18390aa77f6cSMauro Carvalho Chehab .release = s2255_video_device_release, 18400aa77f6cSMauro Carvalho Chehab .tvnorms = S2255_NORMS, 18410aa77f6cSMauro Carvalho Chehab .current_norm = V4L2_STD_NTSC_M, 18420aa77f6cSMauro Carvalho Chehab }; 18430aa77f6cSMauro Carvalho Chehab 1844192f1e78SHans Verkuil static const struct v4l2_ctrl_ops s2255_ctrl_ops = { 1845192f1e78SHans Verkuil .s_ctrl = s2255_s_ctrl, 1846192f1e78SHans Verkuil }; 1847192f1e78SHans Verkuil 1848192f1e78SHans Verkuil static const struct v4l2_ctrl_config color_filter_ctrl = { 1849192f1e78SHans Verkuil .ops = &s2255_ctrl_ops, 1850192f1e78SHans Verkuil .name = "Color Filter", 1851192f1e78SHans Verkuil .id = V4L2_CID_S2255_COLORFILTER, 1852192f1e78SHans Verkuil .type = V4L2_CTRL_TYPE_BOOLEAN, 1853192f1e78SHans Verkuil .max = 1, 1854192f1e78SHans Verkuil .step = 1, 1855192f1e78SHans Verkuil .def = 1, 1856192f1e78SHans Verkuil }; 1857192f1e78SHans Verkuil 18580aa77f6cSMauro Carvalho Chehab static int s2255_probe_v4l(struct s2255_dev *dev) 18590aa77f6cSMauro Carvalho Chehab { 18600aa77f6cSMauro Carvalho Chehab int ret; 18610aa77f6cSMauro Carvalho Chehab int i; 18620aa77f6cSMauro Carvalho Chehab int cur_nr = video_nr; 18630aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel; 18640aa77f6cSMauro Carvalho Chehab ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev); 18650aa77f6cSMauro Carvalho Chehab if (ret) 18660aa77f6cSMauro Carvalho Chehab return ret; 18670aa77f6cSMauro Carvalho Chehab /* initialize all video 4 linux */ 18680aa77f6cSMauro Carvalho Chehab /* register 4 video devices */ 18690aa77f6cSMauro Carvalho Chehab for (i = 0; i < MAX_CHANNELS; i++) { 18700aa77f6cSMauro Carvalho Chehab channel = &dev->channel[i]; 18710aa77f6cSMauro Carvalho Chehab INIT_LIST_HEAD(&channel->vidq.active); 1872192f1e78SHans Verkuil 1873*7041dec7SHans Verkuil v4l2_ctrl_handler_init(&channel->hdl, 6); 1874192f1e78SHans Verkuil v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, 1875192f1e78SHans Verkuil V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); 1876192f1e78SHans Verkuil v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, 1877192f1e78SHans Verkuil V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); 1878192f1e78SHans Verkuil v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, 1879192f1e78SHans Verkuil V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); 1880192f1e78SHans Verkuil v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, 1881192f1e78SHans Verkuil V4L2_CID_HUE, 0, 255, 1, DEF_HUE); 1882*7041dec7SHans Verkuil channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl, 1883*7041dec7SHans Verkuil &s2255_ctrl_ops, 1884*7041dec7SHans Verkuil V4L2_CID_JPEG_COMPRESSION_QUALITY, 1885*7041dec7SHans Verkuil 0, 100, 1, S2255_DEF_JPEG_QUAL); 1886192f1e78SHans Verkuil if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && 1887192f1e78SHans Verkuil (dev->pid != 0x2257 || channel->idx <= 1)) 1888192f1e78SHans Verkuil v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); 1889192f1e78SHans Verkuil if (channel->hdl.error) { 1890192f1e78SHans Verkuil ret = channel->hdl.error; 1891192f1e78SHans Verkuil v4l2_ctrl_handler_free(&channel->hdl); 1892192f1e78SHans Verkuil dev_err(&dev->udev->dev, "couldn't register control\n"); 1893192f1e78SHans Verkuil break; 1894192f1e78SHans Verkuil } 18950aa77f6cSMauro Carvalho Chehab channel->vidq.dev = dev; 18960aa77f6cSMauro Carvalho Chehab /* register 4 video devices */ 18970aa77f6cSMauro Carvalho Chehab channel->vdev = template; 1898192f1e78SHans Verkuil channel->vdev.ctrl_handler = &channel->hdl; 18990aa77f6cSMauro Carvalho Chehab channel->vdev.lock = &dev->lock; 19000aa77f6cSMauro Carvalho Chehab channel->vdev.v4l2_dev = &dev->v4l2_dev; 19010aa77f6cSMauro Carvalho Chehab video_set_drvdata(&channel->vdev, channel); 19020aa77f6cSMauro Carvalho Chehab if (video_nr == -1) 19030aa77f6cSMauro Carvalho Chehab ret = video_register_device(&channel->vdev, 19040aa77f6cSMauro Carvalho Chehab VFL_TYPE_GRABBER, 19050aa77f6cSMauro Carvalho Chehab video_nr); 19060aa77f6cSMauro Carvalho Chehab else 19070aa77f6cSMauro Carvalho Chehab ret = video_register_device(&channel->vdev, 19080aa77f6cSMauro Carvalho Chehab VFL_TYPE_GRABBER, 19090aa77f6cSMauro Carvalho Chehab cur_nr + i); 19100aa77f6cSMauro Carvalho Chehab 19110aa77f6cSMauro Carvalho Chehab if (ret) { 19120aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, 19130aa77f6cSMauro Carvalho Chehab "failed to register video device!\n"); 19140aa77f6cSMauro Carvalho Chehab break; 19150aa77f6cSMauro Carvalho Chehab } 19160aa77f6cSMauro Carvalho Chehab atomic_inc(&dev->num_channels); 19170aa77f6cSMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", 19180aa77f6cSMauro Carvalho Chehab video_device_node_name(&channel->vdev)); 19190aa77f6cSMauro Carvalho Chehab 19200aa77f6cSMauro Carvalho Chehab } 19210aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n", 19220aa77f6cSMauro Carvalho Chehab S2255_VERSION); 19230aa77f6cSMauro Carvalho Chehab /* if no channels registered, return error and probe will fail*/ 19240aa77f6cSMauro Carvalho Chehab if (atomic_read(&dev->num_channels) == 0) { 19250aa77f6cSMauro Carvalho Chehab v4l2_device_unregister(&dev->v4l2_dev); 19260aa77f6cSMauro Carvalho Chehab return ret; 19270aa77f6cSMauro Carvalho Chehab } 19280aa77f6cSMauro Carvalho Chehab if (atomic_read(&dev->num_channels) != MAX_CHANNELS) 19290aa77f6cSMauro Carvalho Chehab printk(KERN_WARNING "s2255: Not all channels available.\n"); 19300aa77f6cSMauro Carvalho Chehab return 0; 19310aa77f6cSMauro Carvalho Chehab } 19320aa77f6cSMauro Carvalho Chehab 19330aa77f6cSMauro Carvalho Chehab /* this function moves the usb stream read pipe data 19340aa77f6cSMauro Carvalho Chehab * into the system buffers. 19350aa77f6cSMauro Carvalho Chehab * returns 0 on success, EAGAIN if more data to process( call this 19360aa77f6cSMauro Carvalho Chehab * function again). 19370aa77f6cSMauro Carvalho Chehab * 19380aa77f6cSMauro Carvalho Chehab * Received frame structure: 19390aa77f6cSMauro Carvalho Chehab * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME) 19400aa77f6cSMauro Carvalho Chehab * bytes 4-7: channel: 0-3 19410aa77f6cSMauro Carvalho Chehab * bytes 8-11: payload size: size of the frame 19420aa77f6cSMauro Carvalho Chehab * bytes 12-payloadsize+12: frame data 19430aa77f6cSMauro Carvalho Chehab */ 19440aa77f6cSMauro Carvalho Chehab static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) 19450aa77f6cSMauro Carvalho Chehab { 19460aa77f6cSMauro Carvalho Chehab char *pdest; 19470aa77f6cSMauro Carvalho Chehab u32 offset = 0; 19480aa77f6cSMauro Carvalho Chehab int bframe = 0; 19490aa77f6cSMauro Carvalho Chehab char *psrc; 19500aa77f6cSMauro Carvalho Chehab unsigned long copy_size; 19510aa77f6cSMauro Carvalho Chehab unsigned long size; 19520aa77f6cSMauro Carvalho Chehab s32 idx = -1; 19530aa77f6cSMauro Carvalho Chehab struct s2255_framei *frm; 19540aa77f6cSMauro Carvalho Chehab unsigned char *pdata; 19550aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel; 19560aa77f6cSMauro Carvalho Chehab dprintk(100, "buffer to user\n"); 19570aa77f6cSMauro Carvalho Chehab channel = &dev->channel[dev->cc]; 19580aa77f6cSMauro Carvalho Chehab idx = channel->cur_frame; 19590aa77f6cSMauro Carvalho Chehab frm = &channel->buffer.frame[idx]; 19600aa77f6cSMauro Carvalho Chehab if (frm->ulState == S2255_READ_IDLE) { 19610aa77f6cSMauro Carvalho Chehab int jj; 19620aa77f6cSMauro Carvalho Chehab unsigned int cc; 19630aa77f6cSMauro Carvalho Chehab __le32 *pdword; /*data from dsp is little endian */ 19640aa77f6cSMauro Carvalho Chehab int payload; 19650aa77f6cSMauro Carvalho Chehab /* search for marker codes */ 19660aa77f6cSMauro Carvalho Chehab pdata = (unsigned char *)pipe_info->transfer_buffer; 19670aa77f6cSMauro Carvalho Chehab pdword = (__le32 *)pdata; 19680aa77f6cSMauro Carvalho Chehab for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { 19690aa77f6cSMauro Carvalho Chehab switch (*pdword) { 19700aa77f6cSMauro Carvalho Chehab case S2255_MARKER_FRAME: 19710aa77f6cSMauro Carvalho Chehab dprintk(4, "found frame marker at offset:" 19720aa77f6cSMauro Carvalho Chehab " %d [%x %x]\n", jj, pdata[0], 19730aa77f6cSMauro Carvalho Chehab pdata[1]); 19740aa77f6cSMauro Carvalho Chehab offset = jj + PREFIX_SIZE; 19750aa77f6cSMauro Carvalho Chehab bframe = 1; 19760aa77f6cSMauro Carvalho Chehab cc = le32_to_cpu(pdword[1]); 19770aa77f6cSMauro Carvalho Chehab if (cc >= MAX_CHANNELS) { 19780aa77f6cSMauro Carvalho Chehab printk(KERN_ERR 19790aa77f6cSMauro Carvalho Chehab "bad channel\n"); 19800aa77f6cSMauro Carvalho Chehab return -EINVAL; 19810aa77f6cSMauro Carvalho Chehab } 19820aa77f6cSMauro Carvalho Chehab /* reverse it */ 19830aa77f6cSMauro Carvalho Chehab dev->cc = G_chnmap[cc]; 19840aa77f6cSMauro Carvalho Chehab channel = &dev->channel[dev->cc]; 19850aa77f6cSMauro Carvalho Chehab payload = le32_to_cpu(pdword[3]); 19860aa77f6cSMauro Carvalho Chehab if (payload > channel->req_image_size) { 19870aa77f6cSMauro Carvalho Chehab channel->bad_payload++; 19880aa77f6cSMauro Carvalho Chehab /* discard the bad frame */ 19890aa77f6cSMauro Carvalho Chehab return -EINVAL; 19900aa77f6cSMauro Carvalho Chehab } 19910aa77f6cSMauro Carvalho Chehab channel->pkt_size = payload; 19920aa77f6cSMauro Carvalho Chehab channel->jpg_size = le32_to_cpu(pdword[4]); 19930aa77f6cSMauro Carvalho Chehab break; 19940aa77f6cSMauro Carvalho Chehab case S2255_MARKER_RESPONSE: 19950aa77f6cSMauro Carvalho Chehab 19960aa77f6cSMauro Carvalho Chehab pdata += DEF_USB_BLOCK; 19970aa77f6cSMauro Carvalho Chehab jj += DEF_USB_BLOCK; 19980aa77f6cSMauro Carvalho Chehab if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS) 19990aa77f6cSMauro Carvalho Chehab break; 20000aa77f6cSMauro Carvalho Chehab cc = G_chnmap[le32_to_cpu(pdword[1])]; 20010aa77f6cSMauro Carvalho Chehab if (cc >= MAX_CHANNELS) 20020aa77f6cSMauro Carvalho Chehab break; 20030aa77f6cSMauro Carvalho Chehab channel = &dev->channel[cc]; 20040aa77f6cSMauro Carvalho Chehab switch (pdword[2]) { 20050aa77f6cSMauro Carvalho Chehab case S2255_RESPONSE_SETMODE: 20060aa77f6cSMauro Carvalho Chehab /* check if channel valid */ 20070aa77f6cSMauro Carvalho Chehab /* set mode ready */ 20080aa77f6cSMauro Carvalho Chehab channel->setmode_ready = 1; 20090aa77f6cSMauro Carvalho Chehab wake_up(&channel->wait_setmode); 20100aa77f6cSMauro Carvalho Chehab dprintk(5, "setmode ready %d\n", cc); 20110aa77f6cSMauro Carvalho Chehab break; 20120aa77f6cSMauro Carvalho Chehab case S2255_RESPONSE_FW: 20130aa77f6cSMauro Carvalho Chehab dev->chn_ready |= (1 << cc); 20140aa77f6cSMauro Carvalho Chehab if ((dev->chn_ready & 0x0f) != 0x0f) 20150aa77f6cSMauro Carvalho Chehab break; 20160aa77f6cSMauro Carvalho Chehab /* all channels ready */ 20170aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255: fw loaded\n"); 20180aa77f6cSMauro Carvalho Chehab atomic_set(&dev->fw_data->fw_state, 20190aa77f6cSMauro Carvalho Chehab S2255_FW_SUCCESS); 20200aa77f6cSMauro Carvalho Chehab wake_up(&dev->fw_data->wait_fw); 20210aa77f6cSMauro Carvalho Chehab break; 20220aa77f6cSMauro Carvalho Chehab case S2255_RESPONSE_STATUS: 20230aa77f6cSMauro Carvalho Chehab channel->vidstatus = le32_to_cpu(pdword[3]); 20240aa77f6cSMauro Carvalho Chehab channel->vidstatus_ready = 1; 20250aa77f6cSMauro Carvalho Chehab wake_up(&channel->wait_vidstatus); 20260aa77f6cSMauro Carvalho Chehab dprintk(5, "got vidstatus %x chan %d\n", 20270aa77f6cSMauro Carvalho Chehab le32_to_cpu(pdword[3]), cc); 20280aa77f6cSMauro Carvalho Chehab break; 20290aa77f6cSMauro Carvalho Chehab default: 20300aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255 unknown resp\n"); 20310aa77f6cSMauro Carvalho Chehab } 20320aa77f6cSMauro Carvalho Chehab default: 20330aa77f6cSMauro Carvalho Chehab pdata++; 20340aa77f6cSMauro Carvalho Chehab break; 20350aa77f6cSMauro Carvalho Chehab } 20360aa77f6cSMauro Carvalho Chehab if (bframe) 20370aa77f6cSMauro Carvalho Chehab break; 20380aa77f6cSMauro Carvalho Chehab } /* for */ 20390aa77f6cSMauro Carvalho Chehab if (!bframe) 20400aa77f6cSMauro Carvalho Chehab return -EINVAL; 20410aa77f6cSMauro Carvalho Chehab } 20420aa77f6cSMauro Carvalho Chehab channel = &dev->channel[dev->cc]; 20430aa77f6cSMauro Carvalho Chehab idx = channel->cur_frame; 20440aa77f6cSMauro Carvalho Chehab frm = &channel->buffer.frame[idx]; 20450aa77f6cSMauro Carvalho Chehab /* search done. now find out if should be acquiring on this channel */ 20460aa77f6cSMauro Carvalho Chehab if (!channel->b_acquire) { 20470aa77f6cSMauro Carvalho Chehab /* we found a frame, but this channel is turned off */ 20480aa77f6cSMauro Carvalho Chehab frm->ulState = S2255_READ_IDLE; 20490aa77f6cSMauro Carvalho Chehab return -EINVAL; 20500aa77f6cSMauro Carvalho Chehab } 20510aa77f6cSMauro Carvalho Chehab 20520aa77f6cSMauro Carvalho Chehab if (frm->ulState == S2255_READ_IDLE) { 20530aa77f6cSMauro Carvalho Chehab frm->ulState = S2255_READ_FRAME; 20540aa77f6cSMauro Carvalho Chehab frm->cur_size = 0; 20550aa77f6cSMauro Carvalho Chehab } 20560aa77f6cSMauro Carvalho Chehab 20570aa77f6cSMauro Carvalho Chehab /* skip the marker 512 bytes (and offset if out of sync) */ 20580aa77f6cSMauro Carvalho Chehab psrc = (u8 *)pipe_info->transfer_buffer + offset; 20590aa77f6cSMauro Carvalho Chehab 20600aa77f6cSMauro Carvalho Chehab 20610aa77f6cSMauro Carvalho Chehab if (frm->lpvbits == NULL) { 20620aa77f6cSMauro Carvalho Chehab dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", 20630aa77f6cSMauro Carvalho Chehab frm, dev, dev->cc, idx); 20640aa77f6cSMauro Carvalho Chehab return -ENOMEM; 20650aa77f6cSMauro Carvalho Chehab } 20660aa77f6cSMauro Carvalho Chehab 20670aa77f6cSMauro Carvalho Chehab pdest = frm->lpvbits + frm->cur_size; 20680aa77f6cSMauro Carvalho Chehab 20690aa77f6cSMauro Carvalho Chehab copy_size = (pipe_info->cur_transfer_size - offset); 20700aa77f6cSMauro Carvalho Chehab 20710aa77f6cSMauro Carvalho Chehab size = channel->pkt_size - PREFIX_SIZE; 20720aa77f6cSMauro Carvalho Chehab 20730aa77f6cSMauro Carvalho Chehab /* sanity check on pdest */ 20740aa77f6cSMauro Carvalho Chehab if ((copy_size + frm->cur_size) < channel->req_image_size) 20750aa77f6cSMauro Carvalho Chehab memcpy(pdest, psrc, copy_size); 20760aa77f6cSMauro Carvalho Chehab 20770aa77f6cSMauro Carvalho Chehab frm->cur_size += copy_size; 20780aa77f6cSMauro Carvalho Chehab dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size); 20790aa77f6cSMauro Carvalho Chehab 20800aa77f6cSMauro Carvalho Chehab if (frm->cur_size >= size) { 20810aa77f6cSMauro Carvalho Chehab dprintk(2, "****************[%d]Buffer[%d]full*************\n", 20820aa77f6cSMauro Carvalho Chehab dev->cc, idx); 20830aa77f6cSMauro Carvalho Chehab channel->last_frame = channel->cur_frame; 20840aa77f6cSMauro Carvalho Chehab channel->cur_frame++; 20850aa77f6cSMauro Carvalho Chehab /* end of system frame ring buffer, start at zero */ 20860aa77f6cSMauro Carvalho Chehab if ((channel->cur_frame == SYS_FRAMES) || 20870aa77f6cSMauro Carvalho Chehab (channel->cur_frame == channel->buffer.dwFrames)) 20880aa77f6cSMauro Carvalho Chehab channel->cur_frame = 0; 20890aa77f6cSMauro Carvalho Chehab /* frame ready */ 20900aa77f6cSMauro Carvalho Chehab if (channel->b_acquire) 20910aa77f6cSMauro Carvalho Chehab s2255_got_frame(channel, channel->jpg_size); 20920aa77f6cSMauro Carvalho Chehab channel->frame_count++; 20930aa77f6cSMauro Carvalho Chehab frm->ulState = S2255_READ_IDLE; 20940aa77f6cSMauro Carvalho Chehab frm->cur_size = 0; 20950aa77f6cSMauro Carvalho Chehab 20960aa77f6cSMauro Carvalho Chehab } 20970aa77f6cSMauro Carvalho Chehab /* done successfully */ 20980aa77f6cSMauro Carvalho Chehab return 0; 20990aa77f6cSMauro Carvalho Chehab } 21000aa77f6cSMauro Carvalho Chehab 21010aa77f6cSMauro Carvalho Chehab static void s2255_read_video_callback(struct s2255_dev *dev, 21020aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo *pipe_info) 21030aa77f6cSMauro Carvalho Chehab { 21040aa77f6cSMauro Carvalho Chehab int res; 21050aa77f6cSMauro Carvalho Chehab dprintk(50, "callback read video \n"); 21060aa77f6cSMauro Carvalho Chehab 21070aa77f6cSMauro Carvalho Chehab if (dev->cc >= MAX_CHANNELS) { 21080aa77f6cSMauro Carvalho Chehab dev->cc = 0; 21090aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "invalid channel\n"); 21100aa77f6cSMauro Carvalho Chehab return; 21110aa77f6cSMauro Carvalho Chehab } 21120aa77f6cSMauro Carvalho Chehab /* otherwise copy to the system buffers */ 21130aa77f6cSMauro Carvalho Chehab res = save_frame(dev, pipe_info); 21140aa77f6cSMauro Carvalho Chehab if (res != 0) 21150aa77f6cSMauro Carvalho Chehab dprintk(4, "s2255: read callback failed\n"); 21160aa77f6cSMauro Carvalho Chehab 21170aa77f6cSMauro Carvalho Chehab dprintk(50, "callback read video done\n"); 21180aa77f6cSMauro Carvalho Chehab return; 21190aa77f6cSMauro Carvalho Chehab } 21200aa77f6cSMauro Carvalho Chehab 21210aa77f6cSMauro Carvalho Chehab static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, 21220aa77f6cSMauro Carvalho Chehab u16 Index, u16 Value, void *TransferBuffer, 21230aa77f6cSMauro Carvalho Chehab s32 TransferBufferLength, int bOut) 21240aa77f6cSMauro Carvalho Chehab { 21250aa77f6cSMauro Carvalho Chehab int r; 21260aa77f6cSMauro Carvalho Chehab if (!bOut) { 21270aa77f6cSMauro Carvalho Chehab r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), 21280aa77f6cSMauro Carvalho Chehab Request, 21290aa77f6cSMauro Carvalho Chehab USB_TYPE_VENDOR | USB_RECIP_DEVICE | 21300aa77f6cSMauro Carvalho Chehab USB_DIR_IN, 21310aa77f6cSMauro Carvalho Chehab Value, Index, TransferBuffer, 21320aa77f6cSMauro Carvalho Chehab TransferBufferLength, HZ * 5); 21330aa77f6cSMauro Carvalho Chehab } else { 21340aa77f6cSMauro Carvalho Chehab r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 21350aa77f6cSMauro Carvalho Chehab Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 21360aa77f6cSMauro Carvalho Chehab Value, Index, TransferBuffer, 21370aa77f6cSMauro Carvalho Chehab TransferBufferLength, HZ * 5); 21380aa77f6cSMauro Carvalho Chehab } 21390aa77f6cSMauro Carvalho Chehab return r; 21400aa77f6cSMauro Carvalho Chehab } 21410aa77f6cSMauro Carvalho Chehab 21420aa77f6cSMauro Carvalho Chehab /* 21430aa77f6cSMauro Carvalho Chehab * retrieve FX2 firmware version. future use. 21440aa77f6cSMauro Carvalho Chehab * @param dev pointer to device extension 21450aa77f6cSMauro Carvalho Chehab * @return -1 for fail, else returns firmware version as an int(16 bits) 21460aa77f6cSMauro Carvalho Chehab */ 21470aa77f6cSMauro Carvalho Chehab static int s2255_get_fx2fw(struct s2255_dev *dev) 21480aa77f6cSMauro Carvalho Chehab { 21490aa77f6cSMauro Carvalho Chehab int fw; 21500aa77f6cSMauro Carvalho Chehab int ret; 21510aa77f6cSMauro Carvalho Chehab unsigned char transBuffer[64]; 21520aa77f6cSMauro Carvalho Chehab ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, 21530aa77f6cSMauro Carvalho Chehab S2255_VR_IN); 21540aa77f6cSMauro Carvalho Chehab if (ret < 0) 21550aa77f6cSMauro Carvalho Chehab dprintk(2, "get fw error: %x\n", ret); 21560aa77f6cSMauro Carvalho Chehab fw = transBuffer[0] + (transBuffer[1] << 8); 21570aa77f6cSMauro Carvalho Chehab dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); 21580aa77f6cSMauro Carvalho Chehab return fw; 21590aa77f6cSMauro Carvalho Chehab } 21600aa77f6cSMauro Carvalho Chehab 21610aa77f6cSMauro Carvalho Chehab /* 21620aa77f6cSMauro Carvalho Chehab * Create the system ring buffer to copy frames into from the 21630aa77f6cSMauro Carvalho Chehab * usb read pipe. 21640aa77f6cSMauro Carvalho Chehab */ 21650aa77f6cSMauro Carvalho Chehab static int s2255_create_sys_buffers(struct s2255_channel *channel) 21660aa77f6cSMauro Carvalho Chehab { 21670aa77f6cSMauro Carvalho Chehab unsigned long i; 21680aa77f6cSMauro Carvalho Chehab unsigned long reqsize; 21690aa77f6cSMauro Carvalho Chehab dprintk(1, "create sys buffers\n"); 21700aa77f6cSMauro Carvalho Chehab channel->buffer.dwFrames = SYS_FRAMES; 21710aa77f6cSMauro Carvalho Chehab /* always allocate maximum size(PAL) for system buffers */ 21720aa77f6cSMauro Carvalho Chehab reqsize = SYS_FRAMES_MAXSIZE; 21730aa77f6cSMauro Carvalho Chehab 21740aa77f6cSMauro Carvalho Chehab if (reqsize > SYS_FRAMES_MAXSIZE) 21750aa77f6cSMauro Carvalho Chehab reqsize = SYS_FRAMES_MAXSIZE; 21760aa77f6cSMauro Carvalho Chehab 21770aa77f6cSMauro Carvalho Chehab for (i = 0; i < SYS_FRAMES; i++) { 21780aa77f6cSMauro Carvalho Chehab /* allocate the frames */ 21790aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].lpvbits = vmalloc(reqsize); 21800aa77f6cSMauro Carvalho Chehab dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n", 21810aa77f6cSMauro Carvalho Chehab &channel->buffer.frame[i], channel->idx, i, 21820aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].lpvbits); 21830aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].size = reqsize; 21840aa77f6cSMauro Carvalho Chehab if (channel->buffer.frame[i].lpvbits == NULL) { 21850aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "out of memory. using less frames\n"); 21860aa77f6cSMauro Carvalho Chehab channel->buffer.dwFrames = i; 21870aa77f6cSMauro Carvalho Chehab break; 21880aa77f6cSMauro Carvalho Chehab } 21890aa77f6cSMauro Carvalho Chehab } 21900aa77f6cSMauro Carvalho Chehab 21910aa77f6cSMauro Carvalho Chehab /* make sure internal states are set */ 21920aa77f6cSMauro Carvalho Chehab for (i = 0; i < SYS_FRAMES; i++) { 21930aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].ulState = 0; 21940aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].cur_size = 0; 21950aa77f6cSMauro Carvalho Chehab } 21960aa77f6cSMauro Carvalho Chehab 21970aa77f6cSMauro Carvalho Chehab channel->cur_frame = 0; 21980aa77f6cSMauro Carvalho Chehab channel->last_frame = -1; 21990aa77f6cSMauro Carvalho Chehab return 0; 22000aa77f6cSMauro Carvalho Chehab } 22010aa77f6cSMauro Carvalho Chehab 22020aa77f6cSMauro Carvalho Chehab static int s2255_release_sys_buffers(struct s2255_channel *channel) 22030aa77f6cSMauro Carvalho Chehab { 22040aa77f6cSMauro Carvalho Chehab unsigned long i; 22050aa77f6cSMauro Carvalho Chehab dprintk(1, "release sys buffers\n"); 22060aa77f6cSMauro Carvalho Chehab for (i = 0; i < SYS_FRAMES; i++) { 22070aa77f6cSMauro Carvalho Chehab if (channel->buffer.frame[i].lpvbits) { 22080aa77f6cSMauro Carvalho Chehab dprintk(1, "vfree %p\n", 22090aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].lpvbits); 22100aa77f6cSMauro Carvalho Chehab vfree(channel->buffer.frame[i].lpvbits); 22110aa77f6cSMauro Carvalho Chehab } 22120aa77f6cSMauro Carvalho Chehab channel->buffer.frame[i].lpvbits = NULL; 22130aa77f6cSMauro Carvalho Chehab } 22140aa77f6cSMauro Carvalho Chehab return 0; 22150aa77f6cSMauro Carvalho Chehab } 22160aa77f6cSMauro Carvalho Chehab 22170aa77f6cSMauro Carvalho Chehab static int s2255_board_init(struct s2255_dev *dev) 22180aa77f6cSMauro Carvalho Chehab { 22190aa77f6cSMauro Carvalho Chehab struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT; 22200aa77f6cSMauro Carvalho Chehab int fw_ver; 22210aa77f6cSMauro Carvalho Chehab int j; 22220aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo *pipe = &dev->pipe; 22230aa77f6cSMauro Carvalho Chehab dprintk(4, "board init: %p", dev); 22240aa77f6cSMauro Carvalho Chehab memset(pipe, 0, sizeof(*pipe)); 22250aa77f6cSMauro Carvalho Chehab pipe->dev = dev; 22260aa77f6cSMauro Carvalho Chehab pipe->cur_transfer_size = S2255_USB_XFER_SIZE; 22270aa77f6cSMauro Carvalho Chehab pipe->max_transfer_size = S2255_USB_XFER_SIZE; 22280aa77f6cSMauro Carvalho Chehab 22290aa77f6cSMauro Carvalho Chehab pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, 22300aa77f6cSMauro Carvalho Chehab GFP_KERNEL); 22310aa77f6cSMauro Carvalho Chehab if (pipe->transfer_buffer == NULL) { 22320aa77f6cSMauro Carvalho Chehab dprintk(1, "out of memory!\n"); 22330aa77f6cSMauro Carvalho Chehab return -ENOMEM; 22340aa77f6cSMauro Carvalho Chehab } 22350aa77f6cSMauro Carvalho Chehab /* query the firmware */ 22360aa77f6cSMauro Carvalho Chehab fw_ver = s2255_get_fx2fw(dev); 22370aa77f6cSMauro Carvalho Chehab 22380aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255: usb firmware version %d.%d\n", 22390aa77f6cSMauro Carvalho Chehab (fw_ver >> 8) & 0xff, 22400aa77f6cSMauro Carvalho Chehab fw_ver & 0xff); 22410aa77f6cSMauro Carvalho Chehab 22420aa77f6cSMauro Carvalho Chehab if (fw_ver < S2255_CUR_USB_FWVER) 22430aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255: newer USB firmware available\n"); 22440aa77f6cSMauro Carvalho Chehab 22450aa77f6cSMauro Carvalho Chehab for (j = 0; j < MAX_CHANNELS; j++) { 22460aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = &dev->channel[j]; 22470aa77f6cSMauro Carvalho Chehab channel->b_acquire = 0; 22480aa77f6cSMauro Carvalho Chehab channel->mode = mode_def; 22490aa77f6cSMauro Carvalho Chehab if (dev->pid == 0x2257 && j > 1) 22500aa77f6cSMauro Carvalho Chehab channel->mode.color |= (1 << 16); 2251*7041dec7SHans Verkuil channel->jpegqual = S2255_DEF_JPEG_QUAL; 22520aa77f6cSMauro Carvalho Chehab channel->width = LINE_SZ_4CIFS_NTSC; 22530aa77f6cSMauro Carvalho Chehab channel->height = NUM_LINES_4CIFS_NTSC * 2; 22540aa77f6cSMauro Carvalho Chehab channel->fmt = &formats[0]; 22550aa77f6cSMauro Carvalho Chehab channel->mode.restart = 1; 22560aa77f6cSMauro Carvalho Chehab channel->req_image_size = get_transfer_size(&mode_def); 22570aa77f6cSMauro Carvalho Chehab channel->frame_count = 0; 22580aa77f6cSMauro Carvalho Chehab /* create the system buffers */ 22590aa77f6cSMauro Carvalho Chehab s2255_create_sys_buffers(channel); 22600aa77f6cSMauro Carvalho Chehab } 22610aa77f6cSMauro Carvalho Chehab /* start read pipe */ 22620aa77f6cSMauro Carvalho Chehab s2255_start_readpipe(dev); 22630aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: success\n", __func__); 22640aa77f6cSMauro Carvalho Chehab return 0; 22650aa77f6cSMauro Carvalho Chehab } 22660aa77f6cSMauro Carvalho Chehab 22670aa77f6cSMauro Carvalho Chehab static int s2255_board_shutdown(struct s2255_dev *dev) 22680aa77f6cSMauro Carvalho Chehab { 22690aa77f6cSMauro Carvalho Chehab u32 i; 22700aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: dev: %p", __func__, dev); 22710aa77f6cSMauro Carvalho Chehab 22720aa77f6cSMauro Carvalho Chehab for (i = 0; i < MAX_CHANNELS; i++) { 22730aa77f6cSMauro Carvalho Chehab if (dev->channel[i].b_acquire) 22740aa77f6cSMauro Carvalho Chehab s2255_stop_acquire(&dev->channel[i]); 22750aa77f6cSMauro Carvalho Chehab } 22760aa77f6cSMauro Carvalho Chehab s2255_stop_readpipe(dev); 22770aa77f6cSMauro Carvalho Chehab for (i = 0; i < MAX_CHANNELS; i++) 22780aa77f6cSMauro Carvalho Chehab s2255_release_sys_buffers(&dev->channel[i]); 22790aa77f6cSMauro Carvalho Chehab /* release transfer buffer */ 22800aa77f6cSMauro Carvalho Chehab kfree(dev->pipe.transfer_buffer); 22810aa77f6cSMauro Carvalho Chehab return 0; 22820aa77f6cSMauro Carvalho Chehab } 22830aa77f6cSMauro Carvalho Chehab 22840aa77f6cSMauro Carvalho Chehab static void read_pipe_completion(struct urb *purb) 22850aa77f6cSMauro Carvalho Chehab { 22860aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo *pipe_info; 22870aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev; 22880aa77f6cSMauro Carvalho Chehab int status; 22890aa77f6cSMauro Carvalho Chehab int pipe; 22900aa77f6cSMauro Carvalho Chehab pipe_info = purb->context; 22910aa77f6cSMauro Carvalho Chehab dprintk(100, "%s: urb:%p, status %d\n", __func__, purb, 22920aa77f6cSMauro Carvalho Chehab purb->status); 22930aa77f6cSMauro Carvalho Chehab if (pipe_info == NULL) { 22940aa77f6cSMauro Carvalho Chehab dev_err(&purb->dev->dev, "no context!\n"); 22950aa77f6cSMauro Carvalho Chehab return; 22960aa77f6cSMauro Carvalho Chehab } 22970aa77f6cSMauro Carvalho Chehab 22980aa77f6cSMauro Carvalho Chehab dev = pipe_info->dev; 22990aa77f6cSMauro Carvalho Chehab if (dev == NULL) { 23000aa77f6cSMauro Carvalho Chehab dev_err(&purb->dev->dev, "no context!\n"); 23010aa77f6cSMauro Carvalho Chehab return; 23020aa77f6cSMauro Carvalho Chehab } 23030aa77f6cSMauro Carvalho Chehab status = purb->status; 23040aa77f6cSMauro Carvalho Chehab /* if shutting down, do not resubmit, exit immediately */ 23050aa77f6cSMauro Carvalho Chehab if (status == -ESHUTDOWN) { 23060aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: err shutdown\n", __func__); 23070aa77f6cSMauro Carvalho Chehab pipe_info->err_count++; 23080aa77f6cSMauro Carvalho Chehab return; 23090aa77f6cSMauro Carvalho Chehab } 23100aa77f6cSMauro Carvalho Chehab 23110aa77f6cSMauro Carvalho Chehab if (pipe_info->state == 0) { 23120aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: exiting USB pipe", __func__); 23130aa77f6cSMauro Carvalho Chehab return; 23140aa77f6cSMauro Carvalho Chehab } 23150aa77f6cSMauro Carvalho Chehab 23160aa77f6cSMauro Carvalho Chehab if (status == 0) 23170aa77f6cSMauro Carvalho Chehab s2255_read_video_callback(dev, pipe_info); 23180aa77f6cSMauro Carvalho Chehab else { 23190aa77f6cSMauro Carvalho Chehab pipe_info->err_count++; 23200aa77f6cSMauro Carvalho Chehab dprintk(1, "%s: failed URB %d\n", __func__, status); 23210aa77f6cSMauro Carvalho Chehab } 23220aa77f6cSMauro Carvalho Chehab 23230aa77f6cSMauro Carvalho Chehab pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); 23240aa77f6cSMauro Carvalho Chehab /* reuse urb */ 23250aa77f6cSMauro Carvalho Chehab usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, 23260aa77f6cSMauro Carvalho Chehab pipe, 23270aa77f6cSMauro Carvalho Chehab pipe_info->transfer_buffer, 23280aa77f6cSMauro Carvalho Chehab pipe_info->cur_transfer_size, 23290aa77f6cSMauro Carvalho Chehab read_pipe_completion, pipe_info); 23300aa77f6cSMauro Carvalho Chehab 23310aa77f6cSMauro Carvalho Chehab if (pipe_info->state != 0) { 23320aa77f6cSMauro Carvalho Chehab if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) { 23330aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "error submitting urb\n"); 23340aa77f6cSMauro Carvalho Chehab } 23350aa77f6cSMauro Carvalho Chehab } else { 23360aa77f6cSMauro Carvalho Chehab dprintk(2, "%s :complete state 0\n", __func__); 23370aa77f6cSMauro Carvalho Chehab } 23380aa77f6cSMauro Carvalho Chehab return; 23390aa77f6cSMauro Carvalho Chehab } 23400aa77f6cSMauro Carvalho Chehab 23410aa77f6cSMauro Carvalho Chehab static int s2255_start_readpipe(struct s2255_dev *dev) 23420aa77f6cSMauro Carvalho Chehab { 23430aa77f6cSMauro Carvalho Chehab int pipe; 23440aa77f6cSMauro Carvalho Chehab int retval; 23450aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo *pipe_info = &dev->pipe; 23460aa77f6cSMauro Carvalho Chehab pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); 23470aa77f6cSMauro Carvalho Chehab dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint); 23480aa77f6cSMauro Carvalho Chehab pipe_info->state = 1; 23490aa77f6cSMauro Carvalho Chehab pipe_info->err_count = 0; 23500aa77f6cSMauro Carvalho Chehab pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); 23510aa77f6cSMauro Carvalho Chehab if (!pipe_info->stream_urb) { 23520aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, 23530aa77f6cSMauro Carvalho Chehab "ReadStream: Unable to alloc URB\n"); 23540aa77f6cSMauro Carvalho Chehab return -ENOMEM; 23550aa77f6cSMauro Carvalho Chehab } 23560aa77f6cSMauro Carvalho Chehab /* transfer buffer allocated in board_init */ 23570aa77f6cSMauro Carvalho Chehab usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, 23580aa77f6cSMauro Carvalho Chehab pipe, 23590aa77f6cSMauro Carvalho Chehab pipe_info->transfer_buffer, 23600aa77f6cSMauro Carvalho Chehab pipe_info->cur_transfer_size, 23610aa77f6cSMauro Carvalho Chehab read_pipe_completion, pipe_info); 23620aa77f6cSMauro Carvalho Chehab retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); 23630aa77f6cSMauro Carvalho Chehab if (retval) { 23640aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "s2255: start read pipe failed\n"); 23650aa77f6cSMauro Carvalho Chehab return retval; 23660aa77f6cSMauro Carvalho Chehab } 23670aa77f6cSMauro Carvalho Chehab return 0; 23680aa77f6cSMauro Carvalho Chehab } 23690aa77f6cSMauro Carvalho Chehab 23700aa77f6cSMauro Carvalho Chehab /* starts acquisition process */ 23710aa77f6cSMauro Carvalho Chehab static int s2255_start_acquire(struct s2255_channel *channel) 23720aa77f6cSMauro Carvalho Chehab { 23730aa77f6cSMauro Carvalho Chehab unsigned char *buffer; 23740aa77f6cSMauro Carvalho Chehab int res; 23750aa77f6cSMauro Carvalho Chehab unsigned long chn_rev; 23760aa77f6cSMauro Carvalho Chehab int j; 23770aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); 23780aa77f6cSMauro Carvalho Chehab chn_rev = G_chnmap[channel->idx]; 23790aa77f6cSMauro Carvalho Chehab buffer = kzalloc(512, GFP_KERNEL); 23800aa77f6cSMauro Carvalho Chehab if (buffer == NULL) { 23810aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "out of mem\n"); 23820aa77f6cSMauro Carvalho Chehab return -ENOMEM; 23830aa77f6cSMauro Carvalho Chehab } 23840aa77f6cSMauro Carvalho Chehab 23850aa77f6cSMauro Carvalho Chehab channel->last_frame = -1; 23860aa77f6cSMauro Carvalho Chehab channel->bad_payload = 0; 23870aa77f6cSMauro Carvalho Chehab channel->cur_frame = 0; 23880aa77f6cSMauro Carvalho Chehab for (j = 0; j < SYS_FRAMES; j++) { 23890aa77f6cSMauro Carvalho Chehab channel->buffer.frame[j].ulState = 0; 23900aa77f6cSMauro Carvalho Chehab channel->buffer.frame[j].cur_size = 0; 23910aa77f6cSMauro Carvalho Chehab } 23920aa77f6cSMauro Carvalho Chehab 23930aa77f6cSMauro Carvalho Chehab /* send the start command */ 23940aa77f6cSMauro Carvalho Chehab *(__le32 *) buffer = IN_DATA_TOKEN; 23950aa77f6cSMauro Carvalho Chehab *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); 23960aa77f6cSMauro Carvalho Chehab *((__le32 *) buffer + 2) = CMD_START; 23970aa77f6cSMauro Carvalho Chehab res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 23980aa77f6cSMauro Carvalho Chehab if (res != 0) 23990aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "CMD_START error\n"); 24000aa77f6cSMauro Carvalho Chehab 24010aa77f6cSMauro Carvalho Chehab dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res); 24020aa77f6cSMauro Carvalho Chehab kfree(buffer); 24030aa77f6cSMauro Carvalho Chehab return 0; 24040aa77f6cSMauro Carvalho Chehab } 24050aa77f6cSMauro Carvalho Chehab 24060aa77f6cSMauro Carvalho Chehab static int s2255_stop_acquire(struct s2255_channel *channel) 24070aa77f6cSMauro Carvalho Chehab { 24080aa77f6cSMauro Carvalho Chehab unsigned char *buffer; 24090aa77f6cSMauro Carvalho Chehab int res; 24100aa77f6cSMauro Carvalho Chehab unsigned long chn_rev; 24110aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); 24120aa77f6cSMauro Carvalho Chehab chn_rev = G_chnmap[channel->idx]; 24130aa77f6cSMauro Carvalho Chehab buffer = kzalloc(512, GFP_KERNEL); 24140aa77f6cSMauro Carvalho Chehab if (buffer == NULL) { 24150aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "out of mem\n"); 24160aa77f6cSMauro Carvalho Chehab return -ENOMEM; 24170aa77f6cSMauro Carvalho Chehab } 24180aa77f6cSMauro Carvalho Chehab /* send the stop command */ 24190aa77f6cSMauro Carvalho Chehab *(__le32 *) buffer = IN_DATA_TOKEN; 24200aa77f6cSMauro Carvalho Chehab *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); 24210aa77f6cSMauro Carvalho Chehab *((__le32 *) buffer + 2) = CMD_STOP; 24220aa77f6cSMauro Carvalho Chehab res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 24230aa77f6cSMauro Carvalho Chehab if (res != 0) 24240aa77f6cSMauro Carvalho Chehab dev_err(&dev->udev->dev, "CMD_STOP error\n"); 24250aa77f6cSMauro Carvalho Chehab kfree(buffer); 24260aa77f6cSMauro Carvalho Chehab channel->b_acquire = 0; 24270aa77f6cSMauro Carvalho Chehab dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res); 24280aa77f6cSMauro Carvalho Chehab return res; 24290aa77f6cSMauro Carvalho Chehab } 24300aa77f6cSMauro Carvalho Chehab 24310aa77f6cSMauro Carvalho Chehab static void s2255_stop_readpipe(struct s2255_dev *dev) 24320aa77f6cSMauro Carvalho Chehab { 24330aa77f6cSMauro Carvalho Chehab struct s2255_pipeinfo *pipe = &dev->pipe; 24340aa77f6cSMauro Carvalho Chehab 24350aa77f6cSMauro Carvalho Chehab pipe->state = 0; 24360aa77f6cSMauro Carvalho Chehab if (pipe->stream_urb) { 24370aa77f6cSMauro Carvalho Chehab /* cancel urb */ 24380aa77f6cSMauro Carvalho Chehab usb_kill_urb(pipe->stream_urb); 24390aa77f6cSMauro Carvalho Chehab usb_free_urb(pipe->stream_urb); 24400aa77f6cSMauro Carvalho Chehab pipe->stream_urb = NULL; 24410aa77f6cSMauro Carvalho Chehab } 24420aa77f6cSMauro Carvalho Chehab dprintk(4, "%s", __func__); 24430aa77f6cSMauro Carvalho Chehab return; 24440aa77f6cSMauro Carvalho Chehab } 24450aa77f6cSMauro Carvalho Chehab 24460aa77f6cSMauro Carvalho Chehab static void s2255_fwload_start(struct s2255_dev *dev, int reset) 24470aa77f6cSMauro Carvalho Chehab { 24480aa77f6cSMauro Carvalho Chehab if (reset) 24490aa77f6cSMauro Carvalho Chehab s2255_reset_dsppower(dev); 24500aa77f6cSMauro Carvalho Chehab dev->fw_data->fw_size = dev->fw_data->fw->size; 24510aa77f6cSMauro Carvalho Chehab atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED); 24520aa77f6cSMauro Carvalho Chehab memcpy(dev->fw_data->pfw_data, 24530aa77f6cSMauro Carvalho Chehab dev->fw_data->fw->data, CHUNK_SIZE); 24540aa77f6cSMauro Carvalho Chehab dev->fw_data->fw_loaded = CHUNK_SIZE; 24550aa77f6cSMauro Carvalho Chehab usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, 24560aa77f6cSMauro Carvalho Chehab usb_sndbulkpipe(dev->udev, 2), 24570aa77f6cSMauro Carvalho Chehab dev->fw_data->pfw_data, 24580aa77f6cSMauro Carvalho Chehab CHUNK_SIZE, s2255_fwchunk_complete, 24590aa77f6cSMauro Carvalho Chehab dev->fw_data); 24600aa77f6cSMauro Carvalho Chehab mod_timer(&dev->timer, jiffies + HZ); 24610aa77f6cSMauro Carvalho Chehab } 24620aa77f6cSMauro Carvalho Chehab 24630aa77f6cSMauro Carvalho Chehab /* standard usb probe function */ 24640aa77f6cSMauro Carvalho Chehab static int s2255_probe(struct usb_interface *interface, 24650aa77f6cSMauro Carvalho Chehab const struct usb_device_id *id) 24660aa77f6cSMauro Carvalho Chehab { 24670aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = NULL; 24680aa77f6cSMauro Carvalho Chehab struct usb_host_interface *iface_desc; 24690aa77f6cSMauro Carvalho Chehab struct usb_endpoint_descriptor *endpoint; 24700aa77f6cSMauro Carvalho Chehab int i; 24710aa77f6cSMauro Carvalho Chehab int retval = -ENOMEM; 24720aa77f6cSMauro Carvalho Chehab __le32 *pdata; 24730aa77f6cSMauro Carvalho Chehab int fw_size; 24740aa77f6cSMauro Carvalho Chehab dprintk(2, "%s\n", __func__); 24750aa77f6cSMauro Carvalho Chehab /* allocate memory for our device state and initialize it to zero */ 24760aa77f6cSMauro Carvalho Chehab dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); 24770aa77f6cSMauro Carvalho Chehab if (dev == NULL) { 24780aa77f6cSMauro Carvalho Chehab s2255_dev_err(&interface->dev, "out of memory\n"); 24790aa77f6cSMauro Carvalho Chehab return -ENOMEM; 24800aa77f6cSMauro Carvalho Chehab } 24810aa77f6cSMauro Carvalho Chehab atomic_set(&dev->num_channels, 0); 24820aa77f6cSMauro Carvalho Chehab dev->pid = id->idProduct; 24830aa77f6cSMauro Carvalho Chehab dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); 24840aa77f6cSMauro Carvalho Chehab if (!dev->fw_data) 24850aa77f6cSMauro Carvalho Chehab goto errorFWDATA1; 24860aa77f6cSMauro Carvalho Chehab mutex_init(&dev->lock); 24870aa77f6cSMauro Carvalho Chehab /* grab usb_device and save it */ 24880aa77f6cSMauro Carvalho Chehab dev->udev = usb_get_dev(interface_to_usbdev(interface)); 24890aa77f6cSMauro Carvalho Chehab if (dev->udev == NULL) { 24900aa77f6cSMauro Carvalho Chehab dev_err(&interface->dev, "null usb device\n"); 24910aa77f6cSMauro Carvalho Chehab retval = -ENODEV; 24920aa77f6cSMauro Carvalho Chehab goto errorUDEV; 24930aa77f6cSMauro Carvalho Chehab } 24940aa77f6cSMauro Carvalho Chehab dprintk(1, "dev: %p, udev %p interface %p\n", dev, 24950aa77f6cSMauro Carvalho Chehab dev->udev, interface); 24960aa77f6cSMauro Carvalho Chehab dev->interface = interface; 24970aa77f6cSMauro Carvalho Chehab /* set up the endpoint information */ 24980aa77f6cSMauro Carvalho Chehab iface_desc = interface->cur_altsetting; 24990aa77f6cSMauro Carvalho Chehab dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); 25000aa77f6cSMauro Carvalho Chehab for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 25010aa77f6cSMauro Carvalho Chehab endpoint = &iface_desc->endpoint[i].desc; 25020aa77f6cSMauro Carvalho Chehab if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { 25030aa77f6cSMauro Carvalho Chehab /* we found the bulk in endpoint */ 25040aa77f6cSMauro Carvalho Chehab dev->read_endpoint = endpoint->bEndpointAddress; 25050aa77f6cSMauro Carvalho Chehab } 25060aa77f6cSMauro Carvalho Chehab } 25070aa77f6cSMauro Carvalho Chehab 25080aa77f6cSMauro Carvalho Chehab if (!dev->read_endpoint) { 25090aa77f6cSMauro Carvalho Chehab dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); 25100aa77f6cSMauro Carvalho Chehab goto errorEP; 25110aa77f6cSMauro Carvalho Chehab } 25120aa77f6cSMauro Carvalho Chehab init_timer(&dev->timer); 25130aa77f6cSMauro Carvalho Chehab dev->timer.function = s2255_timer; 25140aa77f6cSMauro Carvalho Chehab dev->timer.data = (unsigned long)dev->fw_data; 25150aa77f6cSMauro Carvalho Chehab init_waitqueue_head(&dev->fw_data->wait_fw); 25160aa77f6cSMauro Carvalho Chehab for (i = 0; i < MAX_CHANNELS; i++) { 25170aa77f6cSMauro Carvalho Chehab struct s2255_channel *channel = &dev->channel[i]; 25180aa77f6cSMauro Carvalho Chehab dev->channel[i].idx = i; 25190aa77f6cSMauro Carvalho Chehab init_waitqueue_head(&channel->wait_setmode); 25200aa77f6cSMauro Carvalho Chehab init_waitqueue_head(&channel->wait_vidstatus); 25210aa77f6cSMauro Carvalho Chehab } 25220aa77f6cSMauro Carvalho Chehab 25230aa77f6cSMauro Carvalho Chehab dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); 25240aa77f6cSMauro Carvalho Chehab if (!dev->fw_data->fw_urb) { 25250aa77f6cSMauro Carvalho Chehab dev_err(&interface->dev, "out of memory!\n"); 25260aa77f6cSMauro Carvalho Chehab goto errorFWURB; 25270aa77f6cSMauro Carvalho Chehab } 25280aa77f6cSMauro Carvalho Chehab 25290aa77f6cSMauro Carvalho Chehab dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); 25300aa77f6cSMauro Carvalho Chehab if (!dev->fw_data->pfw_data) { 25310aa77f6cSMauro Carvalho Chehab dev_err(&interface->dev, "out of memory!\n"); 25320aa77f6cSMauro Carvalho Chehab goto errorFWDATA2; 25330aa77f6cSMauro Carvalho Chehab } 25340aa77f6cSMauro Carvalho Chehab /* load the first chunk */ 25350aa77f6cSMauro Carvalho Chehab if (request_firmware(&dev->fw_data->fw, 25360aa77f6cSMauro Carvalho Chehab FIRMWARE_FILE_NAME, &dev->udev->dev)) { 25370aa77f6cSMauro Carvalho Chehab printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); 25380aa77f6cSMauro Carvalho Chehab goto errorREQFW; 25390aa77f6cSMauro Carvalho Chehab } 25400aa77f6cSMauro Carvalho Chehab /* check the firmware is valid */ 25410aa77f6cSMauro Carvalho Chehab fw_size = dev->fw_data->fw->size; 25420aa77f6cSMauro Carvalho Chehab pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; 25430aa77f6cSMauro Carvalho Chehab 25440aa77f6cSMauro Carvalho Chehab if (*pdata != S2255_FW_MARKER) { 25450aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "Firmware invalid.\n"); 25460aa77f6cSMauro Carvalho Chehab retval = -ENODEV; 25470aa77f6cSMauro Carvalho Chehab goto errorFWMARKER; 25480aa77f6cSMauro Carvalho Chehab } else { 25490aa77f6cSMauro Carvalho Chehab /* make sure firmware is the latest */ 25500aa77f6cSMauro Carvalho Chehab __le32 *pRel; 25510aa77f6cSMauro Carvalho Chehab pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; 25520aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); 25530aa77f6cSMauro Carvalho Chehab dev->dsp_fw_ver = le32_to_cpu(*pRel); 25540aa77f6cSMauro Carvalho Chehab if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) 25550aa77f6cSMauro Carvalho Chehab printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); 25560aa77f6cSMauro Carvalho Chehab if (dev->pid == 0x2257 && 25570aa77f6cSMauro Carvalho Chehab dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) 25580aa77f6cSMauro Carvalho Chehab printk(KERN_WARNING "s2255: 2257 requires firmware %d" 25590aa77f6cSMauro Carvalho Chehab " or above.\n", S2255_MIN_DSP_COLORFILTER); 25600aa77f6cSMauro Carvalho Chehab } 25610aa77f6cSMauro Carvalho Chehab usb_reset_device(dev->udev); 25620aa77f6cSMauro Carvalho Chehab /* load 2255 board specific */ 25630aa77f6cSMauro Carvalho Chehab retval = s2255_board_init(dev); 25640aa77f6cSMauro Carvalho Chehab if (retval) 25650aa77f6cSMauro Carvalho Chehab goto errorBOARDINIT; 25660aa77f6cSMauro Carvalho Chehab spin_lock_init(&dev->slock); 25670aa77f6cSMauro Carvalho Chehab s2255_fwload_start(dev, 0); 25680aa77f6cSMauro Carvalho Chehab /* loads v4l specific */ 25690aa77f6cSMauro Carvalho Chehab retval = s2255_probe_v4l(dev); 25700aa77f6cSMauro Carvalho Chehab if (retval) 25710aa77f6cSMauro Carvalho Chehab goto errorBOARDINIT; 25720aa77f6cSMauro Carvalho Chehab dev_info(&interface->dev, "Sensoray 2255 detected\n"); 25730aa77f6cSMauro Carvalho Chehab return 0; 25740aa77f6cSMauro Carvalho Chehab errorBOARDINIT: 25750aa77f6cSMauro Carvalho Chehab s2255_board_shutdown(dev); 25760aa77f6cSMauro Carvalho Chehab errorFWMARKER: 25770aa77f6cSMauro Carvalho Chehab release_firmware(dev->fw_data->fw); 25780aa77f6cSMauro Carvalho Chehab errorREQFW: 25790aa77f6cSMauro Carvalho Chehab kfree(dev->fw_data->pfw_data); 25800aa77f6cSMauro Carvalho Chehab errorFWDATA2: 25810aa77f6cSMauro Carvalho Chehab usb_free_urb(dev->fw_data->fw_urb); 25820aa77f6cSMauro Carvalho Chehab errorFWURB: 25830aa77f6cSMauro Carvalho Chehab del_timer(&dev->timer); 25840aa77f6cSMauro Carvalho Chehab errorEP: 25850aa77f6cSMauro Carvalho Chehab usb_put_dev(dev->udev); 25860aa77f6cSMauro Carvalho Chehab errorUDEV: 25870aa77f6cSMauro Carvalho Chehab kfree(dev->fw_data); 25880aa77f6cSMauro Carvalho Chehab mutex_destroy(&dev->lock); 25890aa77f6cSMauro Carvalho Chehab errorFWDATA1: 25900aa77f6cSMauro Carvalho Chehab kfree(dev); 25910aa77f6cSMauro Carvalho Chehab printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval); 25920aa77f6cSMauro Carvalho Chehab return retval; 25930aa77f6cSMauro Carvalho Chehab } 25940aa77f6cSMauro Carvalho Chehab 25950aa77f6cSMauro Carvalho Chehab /* disconnect routine. when board is removed physically or with rmmod */ 25960aa77f6cSMauro Carvalho Chehab static void s2255_disconnect(struct usb_interface *interface) 25970aa77f6cSMauro Carvalho Chehab { 25980aa77f6cSMauro Carvalho Chehab struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); 25990aa77f6cSMauro Carvalho Chehab int i; 26000aa77f6cSMauro Carvalho Chehab int channels = atomic_read(&dev->num_channels); 26010aa77f6cSMauro Carvalho Chehab mutex_lock(&dev->lock); 26020aa77f6cSMauro Carvalho Chehab v4l2_device_disconnect(&dev->v4l2_dev); 26030aa77f6cSMauro Carvalho Chehab mutex_unlock(&dev->lock); 26040aa77f6cSMauro Carvalho Chehab /*see comments in the uvc_driver.c usb disconnect function */ 26050aa77f6cSMauro Carvalho Chehab atomic_inc(&dev->num_channels); 26060aa77f6cSMauro Carvalho Chehab /* unregister each video device. */ 26070aa77f6cSMauro Carvalho Chehab for (i = 0; i < channels; i++) 26080aa77f6cSMauro Carvalho Chehab video_unregister_device(&dev->channel[i].vdev); 26090aa77f6cSMauro Carvalho Chehab /* wake up any of our timers */ 26100aa77f6cSMauro Carvalho Chehab atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); 26110aa77f6cSMauro Carvalho Chehab wake_up(&dev->fw_data->wait_fw); 26120aa77f6cSMauro Carvalho Chehab for (i = 0; i < MAX_CHANNELS; i++) { 26130aa77f6cSMauro Carvalho Chehab dev->channel[i].setmode_ready = 1; 26140aa77f6cSMauro Carvalho Chehab wake_up(&dev->channel[i].wait_setmode); 26150aa77f6cSMauro Carvalho Chehab dev->channel[i].vidstatus_ready = 1; 26160aa77f6cSMauro Carvalho Chehab wake_up(&dev->channel[i].wait_vidstatus); 26170aa77f6cSMauro Carvalho Chehab } 26180aa77f6cSMauro Carvalho Chehab if (atomic_dec_and_test(&dev->num_channels)) 26190aa77f6cSMauro Carvalho Chehab s2255_destroy(dev); 26200aa77f6cSMauro Carvalho Chehab dev_info(&interface->dev, "%s\n", __func__); 26210aa77f6cSMauro Carvalho Chehab } 26220aa77f6cSMauro Carvalho Chehab 26230aa77f6cSMauro Carvalho Chehab static struct usb_driver s2255_driver = { 26240aa77f6cSMauro Carvalho Chehab .name = S2255_DRIVER_NAME, 26250aa77f6cSMauro Carvalho Chehab .probe = s2255_probe, 26260aa77f6cSMauro Carvalho Chehab .disconnect = s2255_disconnect, 26270aa77f6cSMauro Carvalho Chehab .id_table = s2255_table, 26280aa77f6cSMauro Carvalho Chehab }; 26290aa77f6cSMauro Carvalho Chehab 26300aa77f6cSMauro Carvalho Chehab module_usb_driver(s2255_driver); 26310aa77f6cSMauro Carvalho Chehab 26320aa77f6cSMauro Carvalho Chehab MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); 26330aa77f6cSMauro Carvalho Chehab MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)"); 26340aa77f6cSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 26350aa77f6cSMauro Carvalho Chehab MODULE_VERSION(S2255_VERSION); 26360aa77f6cSMauro Carvalho Chehab MODULE_FIRMWARE(FIRMWARE_FILE_NAME); 2637