162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * s2255drv.c - a driver for the Sensoray 2255 USB video capture device 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007-2014 by Sensoray Company Inc. 662306a36Sopenharmony_ci * Dean Anderson 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Some video buffer code based on vivi driver: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Sensoray 2255 device supports 4 simultaneous channels. 1162306a36Sopenharmony_ci * The channels are not "crossbar" inputs, they are physically 1262306a36Sopenharmony_ci * attached to separate video decoders. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Because of USB2.0 bandwidth limitations. There is only a 1562306a36Sopenharmony_ci * certain amount of data which may be transferred at one time. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Example maximum bandwidth utilization: 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * -full size, color mode YUYV or YUV422P: 2 channels at once 2062306a36Sopenharmony_ci * -full or half size Grey scale: all 4 channels at once 2162306a36Sopenharmony_ci * -half size, color mode YUYV or YUV422P: all 4 channels at once 2262306a36Sopenharmony_ci * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels 2362306a36Sopenharmony_ci * at once. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/firmware.h> 2862306a36Sopenharmony_ci#include <linux/kernel.h> 2962306a36Sopenharmony_ci#include <linux/mutex.h> 3062306a36Sopenharmony_ci#include <linux/slab.h> 3162306a36Sopenharmony_ci#include <linux/videodev2.h> 3262306a36Sopenharmony_ci#include <linux/mm.h> 3362306a36Sopenharmony_ci#include <linux/vmalloc.h> 3462306a36Sopenharmony_ci#include <linux/usb.h> 3562306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h> 3662306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 3762306a36Sopenharmony_ci#include <media/v4l2-common.h> 3862306a36Sopenharmony_ci#include <media/v4l2-device.h> 3962306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 4062306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 4162306a36Sopenharmony_ci#include <media/v4l2-event.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define S2255_VERSION "1.25.1" 4462306a36Sopenharmony_ci#define FIRMWARE_FILE_NAME "f2255usb.bin" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* default JPEG quality */ 4762306a36Sopenharmony_ci#define S2255_DEF_JPEG_QUAL 50 4862306a36Sopenharmony_ci/* vendor request in */ 4962306a36Sopenharmony_ci#define S2255_VR_IN 0 5062306a36Sopenharmony_ci/* vendor request out */ 5162306a36Sopenharmony_ci#define S2255_VR_OUT 1 5262306a36Sopenharmony_ci/* firmware query */ 5362306a36Sopenharmony_ci#define S2255_VR_FW 0x30 5462306a36Sopenharmony_ci/* USB endpoint number for configuring the device */ 5562306a36Sopenharmony_ci#define S2255_CONFIG_EP 2 5662306a36Sopenharmony_ci/* maximum time for DSP to start responding after last FW word loaded(ms) */ 5762306a36Sopenharmony_ci#define S2255_DSP_BOOTTIME 800 5862306a36Sopenharmony_ci/* maximum time to wait for firmware to load (ms) */ 5962306a36Sopenharmony_ci#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) 6062306a36Sopenharmony_ci#define S2255_MIN_BUFS 2 6162306a36Sopenharmony_ci#define S2255_SETMODE_TIMEOUT 500 6262306a36Sopenharmony_ci#define S2255_VIDSTATUS_TIMEOUT 350 6362306a36Sopenharmony_ci#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL) 6462306a36Sopenharmony_ci#define S2255_MARKER_RESPONSE cpu_to_le32(0x2255ACACL) 6562306a36Sopenharmony_ci#define S2255_RESPONSE_SETMODE cpu_to_le32(0x01) 6662306a36Sopenharmony_ci#define S2255_RESPONSE_FW cpu_to_le32(0x10) 6762306a36Sopenharmony_ci#define S2255_RESPONSE_STATUS cpu_to_le32(0x20) 6862306a36Sopenharmony_ci#define S2255_USB_XFER_SIZE (16 * 1024) 6962306a36Sopenharmony_ci#define MAX_CHANNELS 4 7062306a36Sopenharmony_ci#define SYS_FRAMES 4 7162306a36Sopenharmony_ci/* maximum size is PAL full size plus room for the marker header(s) */ 7262306a36Sopenharmony_ci#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) 7362306a36Sopenharmony_ci#define DEF_USB_BLOCK S2255_USB_XFER_SIZE 7462306a36Sopenharmony_ci#define LINE_SZ_4CIFS_NTSC 640 7562306a36Sopenharmony_ci#define LINE_SZ_2CIFS_NTSC 640 7662306a36Sopenharmony_ci#define LINE_SZ_1CIFS_NTSC 320 7762306a36Sopenharmony_ci#define LINE_SZ_4CIFS_PAL 704 7862306a36Sopenharmony_ci#define LINE_SZ_2CIFS_PAL 704 7962306a36Sopenharmony_ci#define LINE_SZ_1CIFS_PAL 352 8062306a36Sopenharmony_ci#define NUM_LINES_4CIFS_NTSC 240 8162306a36Sopenharmony_ci#define NUM_LINES_2CIFS_NTSC 240 8262306a36Sopenharmony_ci#define NUM_LINES_1CIFS_NTSC 240 8362306a36Sopenharmony_ci#define NUM_LINES_4CIFS_PAL 288 8462306a36Sopenharmony_ci#define NUM_LINES_2CIFS_PAL 288 8562306a36Sopenharmony_ci#define NUM_LINES_1CIFS_PAL 288 8662306a36Sopenharmony_ci#define LINE_SZ_DEF 640 8762306a36Sopenharmony_ci#define NUM_LINES_DEF 240 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* predefined settings */ 9162306a36Sopenharmony_ci#define FORMAT_NTSC 1 9262306a36Sopenharmony_ci#define FORMAT_PAL 2 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ 9562306a36Sopenharmony_ci#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ 9662306a36Sopenharmony_ci#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ 9762306a36Sopenharmony_ci/* SCALE_4CIFSI is the 2 fields interpolated into one */ 9862306a36Sopenharmony_ci#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define COLOR_YUVPL 1 /* YUV planar */ 10162306a36Sopenharmony_ci#define COLOR_YUVPK 2 /* YUV packed */ 10262306a36Sopenharmony_ci#define COLOR_Y8 4 /* monochrome */ 10362306a36Sopenharmony_ci#define COLOR_JPG 5 /* JPEG */ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define MASK_COLOR 0x000000ff 10662306a36Sopenharmony_ci#define MASK_JPG_QUALITY 0x0000ff00 10762306a36Sopenharmony_ci#define MASK_INPUT_TYPE 0x000f0000 10862306a36Sopenharmony_ci/* frame decimation. */ 10962306a36Sopenharmony_ci#define FDEC_1 1 /* capture every frame. default */ 11062306a36Sopenharmony_ci#define FDEC_2 2 /* capture every 2nd frame */ 11162306a36Sopenharmony_ci#define FDEC_3 3 /* capture every 3rd frame */ 11262306a36Sopenharmony_ci#define FDEC_5 5 /* capture every 5th frame */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/*------------------------------------------------------- 11562306a36Sopenharmony_ci * Default mode parameters. 11662306a36Sopenharmony_ci *-------------------------------------------------------*/ 11762306a36Sopenharmony_ci#define DEF_SCALE SCALE_4CIFS 11862306a36Sopenharmony_ci#define DEF_COLOR COLOR_YUVPL 11962306a36Sopenharmony_ci#define DEF_FDEC FDEC_1 12062306a36Sopenharmony_ci#define DEF_BRIGHT 0 12162306a36Sopenharmony_ci#define DEF_CONTRAST 0x5c 12262306a36Sopenharmony_ci#define DEF_SATURATION 0x80 12362306a36Sopenharmony_ci#define DEF_HUE 0 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* usb config commands */ 12662306a36Sopenharmony_ci#define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) 12762306a36Sopenharmony_ci#define CMD_2255 0xc2255000 12862306a36Sopenharmony_ci#define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) 12962306a36Sopenharmony_ci#define CMD_START cpu_to_le32((CMD_2255 | 0x20)) 13062306a36Sopenharmony_ci#define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) 13162306a36Sopenharmony_ci#define CMD_STATUS cpu_to_le32((CMD_2255 | 0x40)) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct s2255_mode { 13462306a36Sopenharmony_ci u32 format; /* input video format (NTSC, PAL) */ 13562306a36Sopenharmony_ci u32 scale; /* output video scale */ 13662306a36Sopenharmony_ci u32 color; /* output video color format */ 13762306a36Sopenharmony_ci u32 fdec; /* frame decimation */ 13862306a36Sopenharmony_ci u32 bright; /* brightness */ 13962306a36Sopenharmony_ci u32 contrast; /* contrast */ 14062306a36Sopenharmony_ci u32 saturation; /* saturation */ 14162306a36Sopenharmony_ci u32 hue; /* hue (NTSC only)*/ 14262306a36Sopenharmony_ci u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ 14362306a36Sopenharmony_ci u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ 14462306a36Sopenharmony_ci u32 restart; /* if DSP requires restart */ 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define S2255_READ_IDLE 0 14962306a36Sopenharmony_ci#define S2255_READ_FRAME 1 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* frame structure */ 15262306a36Sopenharmony_cistruct s2255_framei { 15362306a36Sopenharmony_ci unsigned long size; 15462306a36Sopenharmony_ci unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ 15562306a36Sopenharmony_ci void *lpvbits; /* image data */ 15662306a36Sopenharmony_ci unsigned long cur_size; /* current data copied to it */ 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* image buffer structure */ 16062306a36Sopenharmony_cistruct s2255_bufferi { 16162306a36Sopenharmony_ci unsigned long dwFrames; /* number of frames in buffer */ 16262306a36Sopenharmony_ci struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ 16662306a36Sopenharmony_ci DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ 16762306a36Sopenharmony_ci DEF_HUE, 0, DEF_USB_BLOCK, 0} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* for firmware loading, fw_state */ 17062306a36Sopenharmony_ci#define S2255_FW_NOTLOADED 0 17162306a36Sopenharmony_ci#define S2255_FW_LOADED_DSPWAIT 1 17262306a36Sopenharmony_ci#define S2255_FW_SUCCESS 2 17362306a36Sopenharmony_ci#define S2255_FW_FAILED 3 17462306a36Sopenharmony_ci#define S2255_FW_DISCONNECTING 4 17562306a36Sopenharmony_ci#define S2255_FW_MARKER cpu_to_le32(0x22552f2f) 17662306a36Sopenharmony_ci/* 2255 read states */ 17762306a36Sopenharmony_ci#define S2255_READ_IDLE 0 17862306a36Sopenharmony_ci#define S2255_READ_FRAME 1 17962306a36Sopenharmony_cistruct s2255_fw { 18062306a36Sopenharmony_ci int fw_loaded; 18162306a36Sopenharmony_ci int fw_size; 18262306a36Sopenharmony_ci struct urb *fw_urb; 18362306a36Sopenharmony_ci atomic_t fw_state; 18462306a36Sopenharmony_ci void *pfw_data; 18562306a36Sopenharmony_ci wait_queue_head_t wait_fw; 18662306a36Sopenharmony_ci const struct firmware *fw; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistruct s2255_pipeinfo { 19062306a36Sopenharmony_ci u32 max_transfer_size; 19162306a36Sopenharmony_ci u32 cur_transfer_size; 19262306a36Sopenharmony_ci u8 *transfer_buffer; 19362306a36Sopenharmony_ci u32 state; 19462306a36Sopenharmony_ci void *stream_urb; 19562306a36Sopenharmony_ci void *dev; /* back pointer to s2255_dev struct*/ 19662306a36Sopenharmony_ci u32 err_count; 19762306a36Sopenharmony_ci u32 idx; 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistruct s2255_fmt; /*forward declaration */ 20162306a36Sopenharmony_cistruct s2255_dev; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 2255 video channel */ 20462306a36Sopenharmony_cistruct s2255_vc { 20562306a36Sopenharmony_ci struct s2255_dev *dev; 20662306a36Sopenharmony_ci struct video_device vdev; 20762306a36Sopenharmony_ci struct v4l2_ctrl_handler hdl; 20862306a36Sopenharmony_ci struct v4l2_ctrl *jpegqual_ctrl; 20962306a36Sopenharmony_ci int resources; 21062306a36Sopenharmony_ci struct list_head buf_list; 21162306a36Sopenharmony_ci struct s2255_bufferi buffer; 21262306a36Sopenharmony_ci struct s2255_mode mode; 21362306a36Sopenharmony_ci v4l2_std_id std; 21462306a36Sopenharmony_ci /* jpeg compression */ 21562306a36Sopenharmony_ci unsigned jpegqual; 21662306a36Sopenharmony_ci /* capture parameters (for high quality mode full size) */ 21762306a36Sopenharmony_ci struct v4l2_captureparm cap_parm; 21862306a36Sopenharmony_ci int cur_frame; 21962306a36Sopenharmony_ci int last_frame; 22062306a36Sopenharmony_ci /* allocated image size */ 22162306a36Sopenharmony_ci unsigned long req_image_size; 22262306a36Sopenharmony_ci /* received packet size */ 22362306a36Sopenharmony_ci unsigned long pkt_size; 22462306a36Sopenharmony_ci int bad_payload; 22562306a36Sopenharmony_ci unsigned long frame_count; 22662306a36Sopenharmony_ci /* if JPEG image */ 22762306a36Sopenharmony_ci int jpg_size; 22862306a36Sopenharmony_ci /* if channel configured to default state */ 22962306a36Sopenharmony_ci int configured; 23062306a36Sopenharmony_ci wait_queue_head_t wait_setmode; 23162306a36Sopenharmony_ci int setmode_ready; 23262306a36Sopenharmony_ci /* video status items */ 23362306a36Sopenharmony_ci int vidstatus; 23462306a36Sopenharmony_ci wait_queue_head_t wait_vidstatus; 23562306a36Sopenharmony_ci int vidstatus_ready; 23662306a36Sopenharmony_ci unsigned int width; 23762306a36Sopenharmony_ci unsigned int height; 23862306a36Sopenharmony_ci enum v4l2_field field; 23962306a36Sopenharmony_ci const struct s2255_fmt *fmt; 24062306a36Sopenharmony_ci int idx; /* channel number on device, 0-3 */ 24162306a36Sopenharmony_ci struct vb2_queue vb_vidq; 24262306a36Sopenharmony_ci struct mutex vb_lock; /* streaming lock */ 24362306a36Sopenharmony_ci spinlock_t qlock; 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistruct s2255_dev { 24862306a36Sopenharmony_ci struct s2255_vc vc[MAX_CHANNELS]; 24962306a36Sopenharmony_ci struct v4l2_device v4l2_dev; 25062306a36Sopenharmony_ci atomic_t num_channels; 25162306a36Sopenharmony_ci int frames; 25262306a36Sopenharmony_ci struct mutex lock; /* channels[].vdev.lock */ 25362306a36Sopenharmony_ci struct mutex cmdlock; /* protects cmdbuf */ 25462306a36Sopenharmony_ci struct usb_device *udev; 25562306a36Sopenharmony_ci struct usb_interface *interface; 25662306a36Sopenharmony_ci u8 read_endpoint; 25762306a36Sopenharmony_ci struct timer_list timer; 25862306a36Sopenharmony_ci struct s2255_fw *fw_data; 25962306a36Sopenharmony_ci struct s2255_pipeinfo pipe; 26062306a36Sopenharmony_ci u32 cc; /* current channel */ 26162306a36Sopenharmony_ci int frame_ready; 26262306a36Sopenharmony_ci int chn_ready; 26362306a36Sopenharmony_ci /* dsp firmware version (f2255usb.bin) */ 26462306a36Sopenharmony_ci int dsp_fw_ver; 26562306a36Sopenharmony_ci u16 pid; /* product id */ 26662306a36Sopenharmony_ci#define S2255_CMDBUF_SIZE 512 26762306a36Sopenharmony_ci __le32 *cmdbuf; 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci return container_of(v4l2_dev, struct s2255_dev, v4l2_dev); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistruct s2255_fmt { 27662306a36Sopenharmony_ci u32 fourcc; 27762306a36Sopenharmony_ci int depth; 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* buffer for one video frame */ 28162306a36Sopenharmony_cistruct s2255_buffer { 28262306a36Sopenharmony_ci /* common v4l buffer stuff -- must be first */ 28362306a36Sopenharmony_ci struct vb2_v4l2_buffer vb; 28462306a36Sopenharmony_ci struct list_head list; 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* current cypress EEPROM firmware version */ 28962306a36Sopenharmony_ci#define S2255_CUR_USB_FWVER ((3 << 8) | 12) 29062306a36Sopenharmony_ci/* current DSP FW version */ 29162306a36Sopenharmony_ci#define S2255_CUR_DSP_FWVER 10104 29262306a36Sopenharmony_ci/* Need DSP version 5+ for video status feature */ 29362306a36Sopenharmony_ci#define S2255_MIN_DSP_STATUS 5 29462306a36Sopenharmony_ci#define S2255_MIN_DSP_COLORFILTER 8 29562306a36Sopenharmony_ci#define S2255_NORMS (V4L2_STD_ALL) 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* private V4L2 controls */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * The following chart displays how COLORFILTER should be set 30162306a36Sopenharmony_ci * ========================================================= 30262306a36Sopenharmony_ci * = fourcc = COLORFILTER = 30362306a36Sopenharmony_ci * = =============================== 30462306a36Sopenharmony_ci * = = 0 = 1 = 30562306a36Sopenharmony_ci * ========================================================= 30662306a36Sopenharmony_ci * = V4L2_PIX_FMT_GREY(Y8) = monochrome from = monochrome= 30762306a36Sopenharmony_ci * = = s-video or = composite = 30862306a36Sopenharmony_ci * = = B/W camera = input = 30962306a36Sopenharmony_ci * ========================================================= 31062306a36Sopenharmony_ci * = other = color, svideo = color, = 31162306a36Sopenharmony_ci * = = = composite = 31262306a36Sopenharmony_ci * ========================================================= 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * Notes: 31562306a36Sopenharmony_ci * channels 0-3 on 2255 are composite 31662306a36Sopenharmony_ci * channels 0-1 on 2257 are composite, 2-3 are s-video 31762306a36Sopenharmony_ci * If COLORFILTER is 0 with a composite color camera connected, 31862306a36Sopenharmony_ci * the output will appear monochrome but hatching 31962306a36Sopenharmony_ci * will occur. 32062306a36Sopenharmony_ci * COLORFILTER is different from "color killer" and "color effects" 32162306a36Sopenharmony_ci * for reasons above. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci#define S2255_V4L2_YC_ON 1 32462306a36Sopenharmony_ci#define S2255_V4L2_YC_OFF 0 32562306a36Sopenharmony_ci#define V4L2_CID_S2255_COLORFILTER (V4L2_CID_USER_S2255_BASE + 0) 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* frame prefix size (sent once every frame) */ 32862306a36Sopenharmony_ci#define PREFIX_SIZE 512 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/* Channels on box are in reverse order */ 33162306a36Sopenharmony_cistatic unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int debug; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int s2255_start_readpipe(struct s2255_dev *dev); 33662306a36Sopenharmony_cistatic void s2255_stop_readpipe(struct s2255_dev *dev); 33762306a36Sopenharmony_cistatic int s2255_start_acquire(struct s2255_vc *vc); 33862306a36Sopenharmony_cistatic int s2255_stop_acquire(struct s2255_vc *vc); 33962306a36Sopenharmony_cistatic void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf, 34062306a36Sopenharmony_ci int jpgsize); 34162306a36Sopenharmony_cistatic int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode); 34262306a36Sopenharmony_cistatic int s2255_board_shutdown(struct s2255_dev *dev); 34362306a36Sopenharmony_cistatic void s2255_fwload_start(struct s2255_dev *dev); 34462306a36Sopenharmony_cistatic void s2255_destroy(struct s2255_dev *dev); 34562306a36Sopenharmony_cistatic long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, 34662306a36Sopenharmony_ci u16 index, u16 value, void *buf, 34762306a36Sopenharmony_ci s32 buf_len, int bOut); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* dev_err macro with driver name */ 35062306a36Sopenharmony_ci#define S2255_DRIVER_NAME "s2255" 35162306a36Sopenharmony_ci#define s2255_dev_err(dev, fmt, arg...) \ 35262306a36Sopenharmony_ci dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci#define dprintk(dev, level, fmt, arg...) \ 35562306a36Sopenharmony_ci v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic struct usb_driver s2255_driver; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* start video number */ 36062306a36Sopenharmony_cistatic int video_nr = -1; /* /dev/videoN, -1 for autodetect */ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* Enable jpeg capture. */ 36362306a36Sopenharmony_cistatic int jpeg_enable = 1; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cimodule_param(debug, int, 0644); 36662306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); 36762306a36Sopenharmony_cimodule_param(video_nr, int, 0644); 36862306a36Sopenharmony_ciMODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); 36962306a36Sopenharmony_cimodule_param(jpeg_enable, int, 0644); 37062306a36Sopenharmony_ciMODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* USB device table */ 37362306a36Sopenharmony_ci#define USB_SENSORAY_VID 0x1943 37462306a36Sopenharmony_cistatic const struct usb_device_id s2255_table[] = { 37562306a36Sopenharmony_ci {USB_DEVICE(USB_SENSORAY_VID, 0x2255)}, 37662306a36Sopenharmony_ci {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/ 37762306a36Sopenharmony_ci { } /* Terminating entry */ 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, s2255_table); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci#define BUFFER_TIMEOUT msecs_to_jiffies(400) 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* image formats. */ 38462306a36Sopenharmony_ci/* JPEG formats must be defined last to support jpeg_enable parameter */ 38562306a36Sopenharmony_cistatic const struct s2255_fmt formats[] = { 38662306a36Sopenharmony_ci { 38762306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUYV, 38862306a36Sopenharmony_ci .depth = 16 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci }, { 39162306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_UYVY, 39262306a36Sopenharmony_ci .depth = 16 39362306a36Sopenharmony_ci }, { 39462306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUV422P, 39562306a36Sopenharmony_ci .depth = 16 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci }, { 39862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_GREY, 39962306a36Sopenharmony_ci .depth = 8 40062306a36Sopenharmony_ci }, { 40162306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_JPEG, 40262306a36Sopenharmony_ci .depth = 24 40362306a36Sopenharmony_ci }, { 40462306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_MJPEG, 40562306a36Sopenharmony_ci .depth = 24 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int norm_maxw(struct s2255_vc *vc) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci return (vc->std & V4L2_STD_525_60) ? 41262306a36Sopenharmony_ci LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int norm_maxh(struct s2255_vc *vc) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci return (vc->std & V4L2_STD_525_60) ? 41862306a36Sopenharmony_ci (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int norm_minw(struct s2255_vc *vc) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci return (vc->std & V4L2_STD_525_60) ? 42462306a36Sopenharmony_ci LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic int norm_minh(struct s2255_vc *vc) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci return (vc->std & V4L2_STD_525_60) ? 43062306a36Sopenharmony_ci (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* 43562306a36Sopenharmony_ci * TODO: fixme: move YUV reordering to hardware 43662306a36Sopenharmony_ci * converts 2255 planar format to yuyv or uyvy 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cistatic void planar422p_to_yuv_packed(const unsigned char *in, 43962306a36Sopenharmony_ci unsigned char *out, 44062306a36Sopenharmony_ci int width, int height, 44162306a36Sopenharmony_ci int fmt) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci unsigned char *pY; 44462306a36Sopenharmony_ci unsigned char *pCb; 44562306a36Sopenharmony_ci unsigned char *pCr; 44662306a36Sopenharmony_ci unsigned long size = height * width; 44762306a36Sopenharmony_ci unsigned int i; 44862306a36Sopenharmony_ci pY = (unsigned char *)in; 44962306a36Sopenharmony_ci pCr = (unsigned char *)in + height * width; 45062306a36Sopenharmony_ci pCb = (unsigned char *)in + height * width + (height * width / 2); 45162306a36Sopenharmony_ci for (i = 0; i < size * 2; i += 4) { 45262306a36Sopenharmony_ci out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; 45362306a36Sopenharmony_ci out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; 45462306a36Sopenharmony_ci out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; 45562306a36Sopenharmony_ci out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void s2255_reset_dsppower(struct s2255_dev *dev) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1); 46362306a36Sopenharmony_ci msleep(50); 46462306a36Sopenharmony_ci s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); 46562306a36Sopenharmony_ci msleep(600); 46662306a36Sopenharmony_ci s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); 46762306a36Sopenharmony_ci return; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* kickstarts the firmware loading. from probe 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void s2255_timer(struct timer_list *t) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct s2255_dev *dev = from_timer(dev, t, timer); 47562306a36Sopenharmony_ci struct s2255_fw *data = dev->fw_data; 47662306a36Sopenharmony_ci if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { 47762306a36Sopenharmony_ci pr_err("s2255: can't submit urb\n"); 47862306a36Sopenharmony_ci atomic_set(&data->fw_state, S2255_FW_FAILED); 47962306a36Sopenharmony_ci /* wake up anything waiting for the firmware */ 48062306a36Sopenharmony_ci wake_up(&data->wait_fw); 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* this loads the firmware asynchronously. 48762306a36Sopenharmony_ci Originally this was done synchronously in probe. 48862306a36Sopenharmony_ci But it is better to load it asynchronously here than block 48962306a36Sopenharmony_ci inside the probe function. Blocking inside probe affects boot time. 49062306a36Sopenharmony_ci FW loading is triggered by the timer in the probe function 49162306a36Sopenharmony_ci*/ 49262306a36Sopenharmony_cistatic void s2255_fwchunk_complete(struct urb *urb) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct s2255_fw *data = urb->context; 49562306a36Sopenharmony_ci struct usb_device *udev = urb->dev; 49662306a36Sopenharmony_ci int len; 49762306a36Sopenharmony_ci if (urb->status) { 49862306a36Sopenharmony_ci dev_err(&udev->dev, "URB failed with status %d\n", urb->status); 49962306a36Sopenharmony_ci atomic_set(&data->fw_state, S2255_FW_FAILED); 50062306a36Sopenharmony_ci /* wake up anything waiting for the firmware */ 50162306a36Sopenharmony_ci wake_up(&data->wait_fw); 50262306a36Sopenharmony_ci return; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci if (data->fw_urb == NULL) { 50562306a36Sopenharmony_ci s2255_dev_err(&udev->dev, "disconnected\n"); 50662306a36Sopenharmony_ci atomic_set(&data->fw_state, S2255_FW_FAILED); 50762306a36Sopenharmony_ci /* wake up anything waiting for the firmware */ 50862306a36Sopenharmony_ci wake_up(&data->wait_fw); 50962306a36Sopenharmony_ci return; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci#define CHUNK_SIZE 512 51262306a36Sopenharmony_ci /* all USB transfers must be done with continuous kernel memory. 51362306a36Sopenharmony_ci can't allocate more than 128k in current linux kernel, so 51462306a36Sopenharmony_ci upload the firmware in chunks 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci if (data->fw_loaded < data->fw_size) { 51762306a36Sopenharmony_ci len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? 51862306a36Sopenharmony_ci data->fw_size % CHUNK_SIZE : CHUNK_SIZE; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (len < CHUNK_SIZE) 52162306a36Sopenharmony_ci memset(data->pfw_data, 0, CHUNK_SIZE); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci memcpy(data->pfw_data, 52462306a36Sopenharmony_ci (char *) data->fw->data + data->fw_loaded, len); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), 52762306a36Sopenharmony_ci data->pfw_data, CHUNK_SIZE, 52862306a36Sopenharmony_ci s2255_fwchunk_complete, data); 52962306a36Sopenharmony_ci if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { 53062306a36Sopenharmony_ci dev_err(&udev->dev, "failed submit URB\n"); 53162306a36Sopenharmony_ci atomic_set(&data->fw_state, S2255_FW_FAILED); 53262306a36Sopenharmony_ci /* wake up anything waiting for the firmware */ 53362306a36Sopenharmony_ci wake_up(&data->wait_fw); 53462306a36Sopenharmony_ci return; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci data->fw_loaded += len; 53762306a36Sopenharmony_ci } else 53862306a36Sopenharmony_ci atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); 53962306a36Sopenharmony_ci return; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic void s2255_got_frame(struct s2255_vc *vc, int jpgsize) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct s2255_buffer *buf; 54662306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); 54762306a36Sopenharmony_ci unsigned long flags = 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci spin_lock_irqsave(&vc->qlock, flags); 55062306a36Sopenharmony_ci if (list_empty(&vc->buf_list)) { 55162306a36Sopenharmony_ci dprintk(dev, 1, "No active queue to serve\n"); 55262306a36Sopenharmony_ci spin_unlock_irqrestore(&vc->qlock, flags); 55362306a36Sopenharmony_ci return; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci buf = list_entry(vc->buf_list.next, 55662306a36Sopenharmony_ci struct s2255_buffer, list); 55762306a36Sopenharmony_ci list_del(&buf->list); 55862306a36Sopenharmony_ci buf->vb.vb2_buf.timestamp = ktime_get_ns(); 55962306a36Sopenharmony_ci buf->vb.field = vc->field; 56062306a36Sopenharmony_ci buf->vb.sequence = vc->frame_count; 56162306a36Sopenharmony_ci spin_unlock_irqrestore(&vc->qlock, flags); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci s2255_fillbuff(vc, buf, jpgsize); 56462306a36Sopenharmony_ci /* tell v4l buffer was filled */ 56562306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); 56662306a36Sopenharmony_ci dprintk(dev, 2, "%s: [buf] [%p]\n", __func__, buf); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic const struct s2255_fmt *format_by_fourcc(int fourcc) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci unsigned int i; 57262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); i++) { 57362306a36Sopenharmony_ci if (-1 == formats[i].fourcc) 57462306a36Sopenharmony_ci continue; 57562306a36Sopenharmony_ci if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || 57662306a36Sopenharmony_ci (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) 57762306a36Sopenharmony_ci continue; 57862306a36Sopenharmony_ci if (formats[i].fourcc == fourcc) 57962306a36Sopenharmony_ci return formats + i; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci return NULL; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/* video buffer vmalloc implementation based partly on VIVI driver which is 58562306a36Sopenharmony_ci * Copyright (c) 2006 by 58662306a36Sopenharmony_ci * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> 58762306a36Sopenharmony_ci * Ted Walther <ted--a.t--enumera.com> 58862306a36Sopenharmony_ci * John Sokol <sokol--a.t--videotechnology.com> 58962306a36Sopenharmony_ci * http://v4l.videotechnology.com/ 59062306a36Sopenharmony_ci * 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_cistatic void s2255_fillbuff(struct s2255_vc *vc, 59362306a36Sopenharmony_ci struct s2255_buffer *buf, int jpgsize) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci int pos = 0; 59662306a36Sopenharmony_ci const char *tmpbuf; 59762306a36Sopenharmony_ci char *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 59862306a36Sopenharmony_ci unsigned long last_frame; 59962306a36Sopenharmony_ci struct s2255_dev *dev = vc->dev; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (!vbuf) 60262306a36Sopenharmony_ci return; 60362306a36Sopenharmony_ci last_frame = vc->last_frame; 60462306a36Sopenharmony_ci if (last_frame != -1) { 60562306a36Sopenharmony_ci tmpbuf = 60662306a36Sopenharmony_ci (const char *)vc->buffer.frame[last_frame].lpvbits; 60762306a36Sopenharmony_ci switch (vc->fmt->fourcc) { 60862306a36Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 60962306a36Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 61062306a36Sopenharmony_ci planar422p_to_yuv_packed((const unsigned char *)tmpbuf, 61162306a36Sopenharmony_ci vbuf, vc->width, 61262306a36Sopenharmony_ci vc->height, 61362306a36Sopenharmony_ci vc->fmt->fourcc); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case V4L2_PIX_FMT_GREY: 61662306a36Sopenharmony_ci memcpy(vbuf, tmpbuf, vc->width * vc->height); 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 61962306a36Sopenharmony_ci case V4L2_PIX_FMT_MJPEG: 62062306a36Sopenharmony_ci vb2_set_plane_payload(&buf->vb.vb2_buf, 0, jpgsize); 62162306a36Sopenharmony_ci memcpy(vbuf, tmpbuf, jpgsize); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 62462306a36Sopenharmony_ci memcpy(vbuf, tmpbuf, 62562306a36Sopenharmony_ci vc->width * vc->height * 2); 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci default: 62862306a36Sopenharmony_ci pr_info("s2255: unknown format?\n"); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci vc->last_frame = -1; 63162306a36Sopenharmony_ci } else { 63262306a36Sopenharmony_ci pr_err("s2255: =======no frame\n"); 63362306a36Sopenharmony_ci return; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci dprintk(dev, 2, "s2255fill at : Buffer %p size= %d\n", 63662306a36Sopenharmony_ci vbuf, pos); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* ------------------------------------------------------------------ 64162306a36Sopenharmony_ci Videobuf operations 64262306a36Sopenharmony_ci ------------------------------------------------------------------*/ 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int queue_setup(struct vb2_queue *vq, 64562306a36Sopenharmony_ci unsigned int *nbuffers, unsigned int *nplanes, 64662306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct s2255_vc *vc = vb2_get_drv_priv(vq); 64962306a36Sopenharmony_ci if (*nbuffers < S2255_MIN_BUFS) 65062306a36Sopenharmony_ci *nbuffers = S2255_MIN_BUFS; 65162306a36Sopenharmony_ci *nplanes = 1; 65262306a36Sopenharmony_ci sizes[0] = vc->width * vc->height * (vc->fmt->depth >> 3); 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int buffer_prepare(struct vb2_buffer *vb) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); 65962306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 66062306a36Sopenharmony_ci struct s2255_buffer *buf = container_of(vbuf, struct s2255_buffer, vb); 66162306a36Sopenharmony_ci int w = vc->width; 66262306a36Sopenharmony_ci int h = vc->height; 66362306a36Sopenharmony_ci unsigned long size; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s\n", __func__); 66662306a36Sopenharmony_ci if (vc->fmt == NULL) 66762306a36Sopenharmony_ci return -EINVAL; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if ((w < norm_minw(vc)) || 67062306a36Sopenharmony_ci (w > norm_maxw(vc)) || 67162306a36Sopenharmony_ci (h < norm_minh(vc)) || 67262306a36Sopenharmony_ci (h > norm_maxh(vc))) { 67362306a36Sopenharmony_ci dprintk(vc->dev, 4, "invalid buffer prepare\n"); 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci size = w * h * (vc->fmt->depth >> 3); 67762306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 67862306a36Sopenharmony_ci dprintk(vc->dev, 4, "invalid buffer prepare\n"); 67962306a36Sopenharmony_ci return -EINVAL; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 68962306a36Sopenharmony_ci struct s2255_buffer *buf = container_of(vbuf, struct s2255_buffer, vb); 69062306a36Sopenharmony_ci struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); 69162306a36Sopenharmony_ci unsigned long flags = 0; 69262306a36Sopenharmony_ci dprintk(vc->dev, 1, "%s\n", __func__); 69362306a36Sopenharmony_ci spin_lock_irqsave(&vc->qlock, flags); 69462306a36Sopenharmony_ci list_add_tail(&buf->list, &vc->buf_list); 69562306a36Sopenharmony_ci spin_unlock_irqrestore(&vc->qlock, flags); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int start_streaming(struct vb2_queue *vq, unsigned int count); 69962306a36Sopenharmony_cistatic void stop_streaming(struct vb2_queue *vq); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic const struct vb2_ops s2255_video_qops = { 70262306a36Sopenharmony_ci .queue_setup = queue_setup, 70362306a36Sopenharmony_ci .buf_prepare = buffer_prepare, 70462306a36Sopenharmony_ci .buf_queue = buffer_queue, 70562306a36Sopenharmony_ci .start_streaming = start_streaming, 70662306a36Sopenharmony_ci .stop_streaming = stop_streaming, 70762306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 70862306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 71262306a36Sopenharmony_ci struct v4l2_capability *cap) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 71562306a36Sopenharmony_ci struct s2255_dev *dev = vc->dev; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci strscpy(cap->driver, "s2255", sizeof(cap->driver)); 71862306a36Sopenharmony_ci strscpy(cap->card, "s2255", sizeof(cap->card)); 71962306a36Sopenharmony_ci usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 72462306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci int index = f->index; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (index >= ARRAY_SIZE(formats)) 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || 73162306a36Sopenharmony_ci (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) 73262306a36Sopenharmony_ci return -EINVAL; 73362306a36Sopenharmony_ci f->pixelformat = formats[index].fourcc; 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 73862306a36Sopenharmony_ci struct v4l2_format *f) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 74162306a36Sopenharmony_ci int is_ntsc = vc->std & V4L2_STD_525_60; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci f->fmt.pix.width = vc->width; 74462306a36Sopenharmony_ci f->fmt.pix.height = vc->height; 74562306a36Sopenharmony_ci if (f->fmt.pix.height >= 74662306a36Sopenharmony_ci (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2) 74762306a36Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 74862306a36Sopenharmony_ci else 74962306a36Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_TOP; 75062306a36Sopenharmony_ci f->fmt.pix.pixelformat = vc->fmt->fourcc; 75162306a36Sopenharmony_ci f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3); 75262306a36Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 75362306a36Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 75462306a36Sopenharmony_ci return 0; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 75862306a36Sopenharmony_ci struct v4l2_format *f) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci const struct s2255_fmt *fmt; 76162306a36Sopenharmony_ci enum v4l2_field field; 76262306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 76362306a36Sopenharmony_ci int is_ntsc = vc->std & V4L2_STD_525_60; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci fmt = format_by_fourcc(f->fmt.pix.pixelformat); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (fmt == NULL) 76862306a36Sopenharmony_ci return -EINVAL; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n", 77162306a36Sopenharmony_ci __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); 77262306a36Sopenharmony_ci if (is_ntsc) { 77362306a36Sopenharmony_ci /* NTSC */ 77462306a36Sopenharmony_ci if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) { 77562306a36Sopenharmony_ci f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2; 77662306a36Sopenharmony_ci field = V4L2_FIELD_INTERLACED; 77762306a36Sopenharmony_ci } else { 77862306a36Sopenharmony_ci f->fmt.pix.height = NUM_LINES_1CIFS_NTSC; 77962306a36Sopenharmony_ci field = V4L2_FIELD_TOP; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) 78262306a36Sopenharmony_ci f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; 78362306a36Sopenharmony_ci else 78462306a36Sopenharmony_ci f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; 78562306a36Sopenharmony_ci } else { 78662306a36Sopenharmony_ci /* PAL */ 78762306a36Sopenharmony_ci if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) { 78862306a36Sopenharmony_ci f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2; 78962306a36Sopenharmony_ci field = V4L2_FIELD_INTERLACED; 79062306a36Sopenharmony_ci } else { 79162306a36Sopenharmony_ci f->fmt.pix.height = NUM_LINES_1CIFS_PAL; 79262306a36Sopenharmony_ci field = V4L2_FIELD_TOP; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) 79562306a36Sopenharmony_ci f->fmt.pix.width = LINE_SZ_4CIFS_PAL; 79662306a36Sopenharmony_ci else 79762306a36Sopenharmony_ci f->fmt.pix.width = LINE_SZ_1CIFS_PAL; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci f->fmt.pix.field = field; 80062306a36Sopenharmony_ci f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; 80162306a36Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 80262306a36Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 80362306a36Sopenharmony_ci dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__, 80462306a36Sopenharmony_ci f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 80962306a36Sopenharmony_ci struct v4l2_format *f) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 81262306a36Sopenharmony_ci const struct s2255_fmt *fmt; 81362306a36Sopenharmony_ci struct vb2_queue *q = &vc->vb_vidq; 81462306a36Sopenharmony_ci struct s2255_mode mode; 81562306a36Sopenharmony_ci int ret; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci ret = vidioc_try_fmt_vid_cap(file, vc, f); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (ret < 0) 82062306a36Sopenharmony_ci return ret; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci fmt = format_by_fourcc(f->fmt.pix.pixelformat); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (fmt == NULL) 82562306a36Sopenharmony_ci return -EINVAL; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (vb2_is_busy(q)) { 82862306a36Sopenharmony_ci dprintk(vc->dev, 1, "queue busy\n"); 82962306a36Sopenharmony_ci return -EBUSY; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci mode = vc->mode; 83362306a36Sopenharmony_ci vc->fmt = fmt; 83462306a36Sopenharmony_ci vc->width = f->fmt.pix.width; 83562306a36Sopenharmony_ci vc->height = f->fmt.pix.height; 83662306a36Sopenharmony_ci vc->field = f->fmt.pix.field; 83762306a36Sopenharmony_ci if (vc->width > norm_minw(vc)) { 83862306a36Sopenharmony_ci if (vc->height > norm_minh(vc)) { 83962306a36Sopenharmony_ci if (vc->cap_parm.capturemode & 84062306a36Sopenharmony_ci V4L2_MODE_HIGHQUALITY) 84162306a36Sopenharmony_ci mode.scale = SCALE_4CIFSI; 84262306a36Sopenharmony_ci else 84362306a36Sopenharmony_ci mode.scale = SCALE_4CIFS; 84462306a36Sopenharmony_ci } else 84562306a36Sopenharmony_ci mode.scale = SCALE_2CIFS; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci } else { 84862306a36Sopenharmony_ci mode.scale = SCALE_1CIFS; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci /* color mode */ 85162306a36Sopenharmony_ci switch (vc->fmt->fourcc) { 85262306a36Sopenharmony_ci case V4L2_PIX_FMT_GREY: 85362306a36Sopenharmony_ci mode.color &= ~MASK_COLOR; 85462306a36Sopenharmony_ci mode.color |= COLOR_Y8; 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 85762306a36Sopenharmony_ci case V4L2_PIX_FMT_MJPEG: 85862306a36Sopenharmony_ci mode.color &= ~MASK_COLOR; 85962306a36Sopenharmony_ci mode.color |= COLOR_JPG; 86062306a36Sopenharmony_ci mode.color |= (vc->jpegqual << 8); 86162306a36Sopenharmony_ci break; 86262306a36Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 86362306a36Sopenharmony_ci mode.color &= ~MASK_COLOR; 86462306a36Sopenharmony_ci mode.color |= COLOR_YUVPL; 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 86762306a36Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 86862306a36Sopenharmony_ci default: 86962306a36Sopenharmony_ci mode.color &= ~MASK_COLOR; 87062306a36Sopenharmony_ci mode.color |= COLOR_YUVPK; 87162306a36Sopenharmony_ci break; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR)) 87462306a36Sopenharmony_ci mode.restart = 1; 87562306a36Sopenharmony_ci else if (mode.scale != vc->mode.scale) 87662306a36Sopenharmony_ci mode.restart = 1; 87762306a36Sopenharmony_ci else if (mode.format != vc->mode.format) 87862306a36Sopenharmony_ci mode.restart = 1; 87962306a36Sopenharmony_ci vc->mode = mode; 88062306a36Sopenharmony_ci (void) s2255_set_mode(vc, &mode); 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* write to the configuration pipe, synchronously */ 88662306a36Sopenharmony_cistatic int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, 88762306a36Sopenharmony_ci int size) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci int pipe; 89062306a36Sopenharmony_ci int done; 89162306a36Sopenharmony_ci long retval = -1; 89262306a36Sopenharmony_ci if (udev) { 89362306a36Sopenharmony_ci pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); 89462306a36Sopenharmony_ci retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci return retval; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic u32 get_transfer_size(struct s2255_mode *mode) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci int linesPerFrame = LINE_SZ_DEF; 90262306a36Sopenharmony_ci int pixelsPerLine = NUM_LINES_DEF; 90362306a36Sopenharmony_ci u32 outImageSize; 90462306a36Sopenharmony_ci u32 usbInSize; 90562306a36Sopenharmony_ci unsigned int mask_mult; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (mode == NULL) 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (mode->format == FORMAT_NTSC) { 91162306a36Sopenharmony_ci switch (mode->scale) { 91262306a36Sopenharmony_ci case SCALE_4CIFS: 91362306a36Sopenharmony_ci case SCALE_4CIFSI: 91462306a36Sopenharmony_ci linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; 91562306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_4CIFS_NTSC; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci case SCALE_2CIFS: 91862306a36Sopenharmony_ci linesPerFrame = NUM_LINES_2CIFS_NTSC; 91962306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_2CIFS_NTSC; 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci case SCALE_1CIFS: 92262306a36Sopenharmony_ci linesPerFrame = NUM_LINES_1CIFS_NTSC; 92362306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_1CIFS_NTSC; 92462306a36Sopenharmony_ci break; 92562306a36Sopenharmony_ci default: 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci } else if (mode->format == FORMAT_PAL) { 92962306a36Sopenharmony_ci switch (mode->scale) { 93062306a36Sopenharmony_ci case SCALE_4CIFS: 93162306a36Sopenharmony_ci case SCALE_4CIFSI: 93262306a36Sopenharmony_ci linesPerFrame = NUM_LINES_4CIFS_PAL * 2; 93362306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_4CIFS_PAL; 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci case SCALE_2CIFS: 93662306a36Sopenharmony_ci linesPerFrame = NUM_LINES_2CIFS_PAL; 93762306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_2CIFS_PAL; 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci case SCALE_1CIFS: 94062306a36Sopenharmony_ci linesPerFrame = NUM_LINES_1CIFS_PAL; 94162306a36Sopenharmony_ci pixelsPerLine = LINE_SZ_1CIFS_PAL; 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci default: 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci outImageSize = linesPerFrame * pixelsPerLine; 94862306a36Sopenharmony_ci if ((mode->color & MASK_COLOR) != COLOR_Y8) { 94962306a36Sopenharmony_ci /* 2 bytes/pixel if not monochrome */ 95062306a36Sopenharmony_ci outImageSize *= 2; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* total bytes to send including prefix and 4K padding; 95462306a36Sopenharmony_ci must be a multiple of USB_READ_SIZE */ 95562306a36Sopenharmony_ci usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ 95662306a36Sopenharmony_ci mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; 95762306a36Sopenharmony_ci /* if size not a multiple of USB_READ_SIZE */ 95862306a36Sopenharmony_ci if (usbInSize & ~mask_mult) 95962306a36Sopenharmony_ci usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); 96062306a36Sopenharmony_ci return usbInSize; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct device *dev = &sdev->udev->dev; 96662306a36Sopenharmony_ci dev_info(dev, "------------------------------------------------\n"); 96762306a36Sopenharmony_ci dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale); 96862306a36Sopenharmony_ci dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color); 96962306a36Sopenharmony_ci dev_info(dev, "bright: 0x%x\n", mode->bright); 97062306a36Sopenharmony_ci dev_info(dev, "------------------------------------------------\n"); 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/* 97462306a36Sopenharmony_ci * set mode is the function which controls the DSP. 97562306a36Sopenharmony_ci * the restart parameter in struct s2255_mode should be set whenever 97662306a36Sopenharmony_ci * the image size could change via color format, video system or image 97762306a36Sopenharmony_ci * size. 97862306a36Sopenharmony_ci * When the restart parameter is set, we sleep for ONE frame to allow the 97962306a36Sopenharmony_ci * DSP time to get the new frame 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_cistatic int s2255_set_mode(struct s2255_vc *vc, 98262306a36Sopenharmony_ci struct s2255_mode *mode) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int res; 98562306a36Sopenharmony_ci unsigned long chn_rev; 98662306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); 98762306a36Sopenharmony_ci int i; 98862306a36Sopenharmony_ci __le32 *buffer = dev->cmdbuf; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci mutex_lock(&dev->cmdlock); 99162306a36Sopenharmony_ci chn_rev = G_chnmap[vc->idx]; 99262306a36Sopenharmony_ci dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx); 99362306a36Sopenharmony_ci /* if JPEG, set the quality */ 99462306a36Sopenharmony_ci if ((mode->color & MASK_COLOR) == COLOR_JPG) { 99562306a36Sopenharmony_ci mode->color &= ~MASK_COLOR; 99662306a36Sopenharmony_ci mode->color |= COLOR_JPG; 99762306a36Sopenharmony_ci mode->color &= ~MASK_JPG_QUALITY; 99862306a36Sopenharmony_ci mode->color |= (vc->jpegqual << 8); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci /* save the mode */ 100162306a36Sopenharmony_ci vc->mode = *mode; 100262306a36Sopenharmony_ci vc->req_image_size = get_transfer_size(mode); 100362306a36Sopenharmony_ci dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size); 100462306a36Sopenharmony_ci /* set the mode */ 100562306a36Sopenharmony_ci buffer[0] = IN_DATA_TOKEN; 100662306a36Sopenharmony_ci buffer[1] = (__le32) cpu_to_le32(chn_rev); 100762306a36Sopenharmony_ci buffer[2] = CMD_SET_MODE; 100862306a36Sopenharmony_ci for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++) 100962306a36Sopenharmony_ci buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]); 101062306a36Sopenharmony_ci vc->setmode_ready = 0; 101162306a36Sopenharmony_ci res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 101262306a36Sopenharmony_ci if (debug) 101362306a36Sopenharmony_ci s2255_print_cfg(dev, mode); 101462306a36Sopenharmony_ci /* wait at least 3 frames before continuing */ 101562306a36Sopenharmony_ci if (mode->restart) { 101662306a36Sopenharmony_ci wait_event_timeout(vc->wait_setmode, 101762306a36Sopenharmony_ci (vc->setmode_ready != 0), 101862306a36Sopenharmony_ci msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); 101962306a36Sopenharmony_ci if (vc->setmode_ready != 1) { 102062306a36Sopenharmony_ci dprintk(dev, 0, "s2255: no set mode response\n"); 102162306a36Sopenharmony_ci res = -EFAULT; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci /* clear the restart flag */ 102562306a36Sopenharmony_ci vc->mode.restart = 0; 102662306a36Sopenharmony_ci dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res); 102762306a36Sopenharmony_ci mutex_unlock(&dev->cmdlock); 102862306a36Sopenharmony_ci return res; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci int res; 103462306a36Sopenharmony_ci u32 chn_rev; 103562306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); 103662306a36Sopenharmony_ci __le32 *buffer = dev->cmdbuf; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci mutex_lock(&dev->cmdlock); 103962306a36Sopenharmony_ci chn_rev = G_chnmap[vc->idx]; 104062306a36Sopenharmony_ci dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx); 104162306a36Sopenharmony_ci /* form the get vid status command */ 104262306a36Sopenharmony_ci buffer[0] = IN_DATA_TOKEN; 104362306a36Sopenharmony_ci buffer[1] = (__le32) cpu_to_le32(chn_rev); 104462306a36Sopenharmony_ci buffer[2] = CMD_STATUS; 104562306a36Sopenharmony_ci *pstatus = 0; 104662306a36Sopenharmony_ci vc->vidstatus_ready = 0; 104762306a36Sopenharmony_ci res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 104862306a36Sopenharmony_ci wait_event_timeout(vc->wait_vidstatus, 104962306a36Sopenharmony_ci (vc->vidstatus_ready != 0), 105062306a36Sopenharmony_ci msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT)); 105162306a36Sopenharmony_ci if (vc->vidstatus_ready != 1) { 105262306a36Sopenharmony_ci dprintk(dev, 0, "s2255: no vidstatus response\n"); 105362306a36Sopenharmony_ci res = -EFAULT; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci *pstatus = vc->vidstatus; 105662306a36Sopenharmony_ci dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus); 105762306a36Sopenharmony_ci mutex_unlock(&dev->cmdlock); 105862306a36Sopenharmony_ci return res; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int start_streaming(struct vb2_queue *vq, unsigned int count) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct s2255_vc *vc = vb2_get_drv_priv(vq); 106462306a36Sopenharmony_ci int j; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci vc->last_frame = -1; 106762306a36Sopenharmony_ci vc->bad_payload = 0; 106862306a36Sopenharmony_ci vc->cur_frame = 0; 106962306a36Sopenharmony_ci vc->frame_count = 0; 107062306a36Sopenharmony_ci for (j = 0; j < SYS_FRAMES; j++) { 107162306a36Sopenharmony_ci vc->buffer.frame[j].ulState = S2255_READ_IDLE; 107262306a36Sopenharmony_ci vc->buffer.frame[j].cur_size = 0; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci return s2255_start_acquire(vc); 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci/* abort streaming and wait for last buffer */ 107862306a36Sopenharmony_cistatic void stop_streaming(struct vb2_queue *vq) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct s2255_vc *vc = vb2_get_drv_priv(vq); 108162306a36Sopenharmony_ci struct s2255_buffer *buf, *node; 108262306a36Sopenharmony_ci unsigned long flags; 108362306a36Sopenharmony_ci (void) s2255_stop_acquire(vc); 108462306a36Sopenharmony_ci spin_lock_irqsave(&vc->qlock, flags); 108562306a36Sopenharmony_ci list_for_each_entry_safe(buf, node, &vc->buf_list, list) { 108662306a36Sopenharmony_ci list_del(&buf->list); 108762306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 108862306a36Sopenharmony_ci dprintk(vc->dev, 2, "[%p/%d] done\n", 108962306a36Sopenharmony_ci buf, buf->vb.vb2_buf.index); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci spin_unlock_irqrestore(&vc->qlock, flags); 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 109762306a36Sopenharmony_ci struct s2255_mode mode; 109862306a36Sopenharmony_ci struct vb2_queue *q = &vc->vb_vidq; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* 110162306a36Sopenharmony_ci * Changing the standard implies a format change, which is not allowed 110262306a36Sopenharmony_ci * while buffers for use with streaming have already been allocated. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci if (vb2_is_busy(q)) 110562306a36Sopenharmony_ci return -EBUSY; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci mode = vc->mode; 110862306a36Sopenharmony_ci if (i & V4L2_STD_525_60) { 110962306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s 60 Hz\n", __func__); 111062306a36Sopenharmony_ci /* if changing format, reset frame decimation/intervals */ 111162306a36Sopenharmony_ci if (mode.format != FORMAT_NTSC) { 111262306a36Sopenharmony_ci mode.restart = 1; 111362306a36Sopenharmony_ci mode.format = FORMAT_NTSC; 111462306a36Sopenharmony_ci mode.fdec = FDEC_1; 111562306a36Sopenharmony_ci vc->width = LINE_SZ_4CIFS_NTSC; 111662306a36Sopenharmony_ci vc->height = NUM_LINES_4CIFS_NTSC * 2; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci } else if (i & V4L2_STD_625_50) { 111962306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s 50 Hz\n", __func__); 112062306a36Sopenharmony_ci if (mode.format != FORMAT_PAL) { 112162306a36Sopenharmony_ci mode.restart = 1; 112262306a36Sopenharmony_ci mode.format = FORMAT_PAL; 112362306a36Sopenharmony_ci mode.fdec = FDEC_1; 112462306a36Sopenharmony_ci vc->width = LINE_SZ_4CIFS_PAL; 112562306a36Sopenharmony_ci vc->height = NUM_LINES_4CIFS_PAL * 2; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci } else 112862306a36Sopenharmony_ci return -EINVAL; 112962306a36Sopenharmony_ci vc->std = i; 113062306a36Sopenharmony_ci if (mode.restart) 113162306a36Sopenharmony_ci s2255_set_mode(vc, &mode); 113262306a36Sopenharmony_ci return 0; 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci *i = vc->std; 114062306a36Sopenharmony_ci return 0; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci/* Sensoray 2255 is a multiple channel capture device. 114462306a36Sopenharmony_ci It does not have a "crossbar" of inputs. 114562306a36Sopenharmony_ci We use one V4L device per channel. The user must 114662306a36Sopenharmony_ci be aware that certain combinations are not allowed. 114762306a36Sopenharmony_ci For instance, you cannot do full FPS on more than 2 channels(2 videodevs) 114862306a36Sopenharmony_ci at once in color(you can do full fps on 4 channels with greyscale. 114962306a36Sopenharmony_ci*/ 115062306a36Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *priv, 115162306a36Sopenharmony_ci struct v4l2_input *inp) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 115462306a36Sopenharmony_ci struct s2255_dev *dev = vc->dev; 115562306a36Sopenharmony_ci u32 status = 0; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (inp->index != 0) 115862306a36Sopenharmony_ci return -EINVAL; 115962306a36Sopenharmony_ci inp->type = V4L2_INPUT_TYPE_CAMERA; 116062306a36Sopenharmony_ci inp->std = S2255_NORMS; 116162306a36Sopenharmony_ci inp->status = 0; 116262306a36Sopenharmony_ci if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { 116362306a36Sopenharmony_ci int rc; 116462306a36Sopenharmony_ci rc = s2255_cmd_status(vc, &status); 116562306a36Sopenharmony_ci dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n", 116662306a36Sopenharmony_ci rc, status); 116762306a36Sopenharmony_ci if (rc == 0) 116862306a36Sopenharmony_ci inp->status = (status & 0x01) ? 0 116962306a36Sopenharmony_ci : V4L2_IN_ST_NO_SIGNAL; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci switch (dev->pid) { 117262306a36Sopenharmony_ci case 0x2255: 117362306a36Sopenharmony_ci default: 117462306a36Sopenharmony_ci strscpy(inp->name, "Composite", sizeof(inp->name)); 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case 0x2257: 117762306a36Sopenharmony_ci strscpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video", 117862306a36Sopenharmony_ci sizeof(inp->name)); 117962306a36Sopenharmony_ci break; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci return 0; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *priv, unsigned int *i) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci *i = 0; 118762306a36Sopenharmony_ci return 0; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *priv, unsigned int i) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci if (i > 0) 119262306a36Sopenharmony_ci return -EINVAL; 119362306a36Sopenharmony_ci return 0; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic int s2255_s_ctrl(struct v4l2_ctrl *ctrl) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct s2255_vc *vc = 119962306a36Sopenharmony_ci container_of(ctrl->handler, struct s2255_vc, hdl); 120062306a36Sopenharmony_ci struct s2255_mode mode; 120162306a36Sopenharmony_ci mode = vc->mode; 120262306a36Sopenharmony_ci /* update the mode to the corresponding value */ 120362306a36Sopenharmony_ci switch (ctrl->id) { 120462306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 120562306a36Sopenharmony_ci mode.bright = ctrl->val; 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 120862306a36Sopenharmony_ci mode.contrast = ctrl->val; 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci case V4L2_CID_HUE: 121162306a36Sopenharmony_ci mode.hue = ctrl->val; 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci case V4L2_CID_SATURATION: 121462306a36Sopenharmony_ci mode.saturation = ctrl->val; 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci case V4L2_CID_S2255_COLORFILTER: 121762306a36Sopenharmony_ci mode.color &= ~MASK_INPUT_TYPE; 121862306a36Sopenharmony_ci mode.color |= !ctrl->val << 16; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci case V4L2_CID_JPEG_COMPRESSION_QUALITY: 122162306a36Sopenharmony_ci vc->jpegqual = ctrl->val; 122262306a36Sopenharmony_ci return 0; 122362306a36Sopenharmony_ci default: 122462306a36Sopenharmony_ci return -EINVAL; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci mode.restart = 0; 122762306a36Sopenharmony_ci /* set mode here. Note: stream does not need restarted. 122862306a36Sopenharmony_ci some V4L programs restart stream unnecessarily 122962306a36Sopenharmony_ci after a s_crtl. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_ci s2255_set_mode(vc, &mode); 123262306a36Sopenharmony_ci return 0; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int vidioc_g_jpegcomp(struct file *file, void *priv, 123662306a36Sopenharmony_ci struct v4l2_jpegcompression *jc) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci memset(jc, 0, sizeof(*jc)); 124162306a36Sopenharmony_ci jc->quality = vc->jpegqual; 124262306a36Sopenharmony_ci dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality); 124362306a36Sopenharmony_ci return 0; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic int vidioc_s_jpegcomp(struct file *file, void *priv, 124762306a36Sopenharmony_ci const struct v4l2_jpegcompression *jc) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (jc->quality < 0 || jc->quality > 100) 125262306a36Sopenharmony_ci return -EINVAL; 125362306a36Sopenharmony_ci v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality); 125462306a36Sopenharmony_ci dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality); 125562306a36Sopenharmony_ci return 0; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic int vidioc_g_parm(struct file *file, void *priv, 125962306a36Sopenharmony_ci struct v4l2_streamparm *sp) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci __u32 def_num, def_dem; 126262306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 126562306a36Sopenharmony_ci return -EINVAL; 126662306a36Sopenharmony_ci sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 126762306a36Sopenharmony_ci sp->parm.capture.capturemode = vc->cap_parm.capturemode; 126862306a36Sopenharmony_ci sp->parm.capture.readbuffers = S2255_MIN_BUFS; 126962306a36Sopenharmony_ci def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000; 127062306a36Sopenharmony_ci def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000; 127162306a36Sopenharmony_ci sp->parm.capture.timeperframe.denominator = def_dem; 127262306a36Sopenharmony_ci switch (vc->mode.fdec) { 127362306a36Sopenharmony_ci default: 127462306a36Sopenharmony_ci case FDEC_1: 127562306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num; 127662306a36Sopenharmony_ci break; 127762306a36Sopenharmony_ci case FDEC_2: 127862306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 2; 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci case FDEC_3: 128162306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 3; 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci case FDEC_5: 128462306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 5; 128562306a36Sopenharmony_ci break; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n", 128862306a36Sopenharmony_ci __func__, 128962306a36Sopenharmony_ci sp->parm.capture.capturemode, 129062306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator, 129162306a36Sopenharmony_ci sp->parm.capture.timeperframe.denominator); 129262306a36Sopenharmony_ci return 0; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic int vidioc_s_parm(struct file *file, void *priv, 129662306a36Sopenharmony_ci struct v4l2_streamparm *sp) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 129962306a36Sopenharmony_ci struct s2255_mode mode; 130062306a36Sopenharmony_ci int fdec = FDEC_1; 130162306a36Sopenharmony_ci __u32 def_num, def_dem; 130262306a36Sopenharmony_ci if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 130362306a36Sopenharmony_ci return -EINVAL; 130462306a36Sopenharmony_ci mode = vc->mode; 130562306a36Sopenharmony_ci /* high quality capture mode requires a stream restart */ 130662306a36Sopenharmony_ci if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode) 130762306a36Sopenharmony_ci && vb2_is_streaming(&vc->vb_vidq)) 130862306a36Sopenharmony_ci return -EBUSY; 130962306a36Sopenharmony_ci def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; 131062306a36Sopenharmony_ci def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; 131162306a36Sopenharmony_ci if (def_dem != sp->parm.capture.timeperframe.denominator) 131262306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num; 131362306a36Sopenharmony_ci else if (sp->parm.capture.timeperframe.numerator <= def_num) 131462306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num; 131562306a36Sopenharmony_ci else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { 131662306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 2; 131762306a36Sopenharmony_ci fdec = FDEC_2; 131862306a36Sopenharmony_ci } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) { 131962306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 3; 132062306a36Sopenharmony_ci fdec = FDEC_3; 132162306a36Sopenharmony_ci } else { 132262306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator = def_num * 5; 132362306a36Sopenharmony_ci fdec = FDEC_5; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci mode.fdec = fdec; 132662306a36Sopenharmony_ci sp->parm.capture.timeperframe.denominator = def_dem; 132762306a36Sopenharmony_ci sp->parm.capture.readbuffers = S2255_MIN_BUFS; 132862306a36Sopenharmony_ci s2255_set_mode(vc, &mode); 132962306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", 133062306a36Sopenharmony_ci __func__, 133162306a36Sopenharmony_ci sp->parm.capture.capturemode, 133262306a36Sopenharmony_ci sp->parm.capture.timeperframe.numerator, 133362306a36Sopenharmony_ci sp->parm.capture.timeperframe.denominator, fdec); 133462306a36Sopenharmony_ci return 0; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci#define NUM_SIZE_ENUMS 3 133862306a36Sopenharmony_cistatic const struct v4l2_frmsize_discrete ntsc_sizes[] = { 133962306a36Sopenharmony_ci { 640, 480 }, 134062306a36Sopenharmony_ci { 640, 240 }, 134162306a36Sopenharmony_ci { 320, 240 }, 134262306a36Sopenharmony_ci}; 134362306a36Sopenharmony_cistatic const struct v4l2_frmsize_discrete pal_sizes[] = { 134462306a36Sopenharmony_ci { 704, 576 }, 134562306a36Sopenharmony_ci { 704, 288 }, 134662306a36Sopenharmony_ci { 352, 288 }, 134762306a36Sopenharmony_ci}; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic int vidioc_enum_framesizes(struct file *file, void *priv, 135062306a36Sopenharmony_ci struct v4l2_frmsizeenum *fe) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 135362306a36Sopenharmony_ci int is_ntsc = vc->std & V4L2_STD_525_60; 135462306a36Sopenharmony_ci const struct s2255_fmt *fmt; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (fe->index >= NUM_SIZE_ENUMS) 135762306a36Sopenharmony_ci return -EINVAL; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci fmt = format_by_fourcc(fe->pixel_format); 136062306a36Sopenharmony_ci if (fmt == NULL) 136162306a36Sopenharmony_ci return -EINVAL; 136262306a36Sopenharmony_ci fe->type = V4L2_FRMSIZE_TYPE_DISCRETE; 136362306a36Sopenharmony_ci fe->discrete = is_ntsc ? ntsc_sizes[fe->index] : pal_sizes[fe->index]; 136462306a36Sopenharmony_ci return 0; 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic int vidioc_enum_frameintervals(struct file *file, void *priv, 136862306a36Sopenharmony_ci struct v4l2_frmivalenum *fe) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 137162306a36Sopenharmony_ci const struct s2255_fmt *fmt; 137262306a36Sopenharmony_ci const struct v4l2_frmsize_discrete *sizes; 137362306a36Sopenharmony_ci int is_ntsc = vc->std & V4L2_STD_525_60; 137462306a36Sopenharmony_ci#define NUM_FRAME_ENUMS 4 137562306a36Sopenharmony_ci int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; 137662306a36Sopenharmony_ci int i; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (fe->index >= NUM_FRAME_ENUMS) 137962306a36Sopenharmony_ci return -EINVAL; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci fmt = format_by_fourcc(fe->pixel_format); 138262306a36Sopenharmony_ci if (fmt == NULL) 138362306a36Sopenharmony_ci return -EINVAL; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci sizes = is_ntsc ? ntsc_sizes : pal_sizes; 138662306a36Sopenharmony_ci for (i = 0; i < NUM_SIZE_ENUMS; i++, sizes++) 138762306a36Sopenharmony_ci if (fe->width == sizes->width && 138862306a36Sopenharmony_ci fe->height == sizes->height) 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci if (i == NUM_SIZE_ENUMS) 139162306a36Sopenharmony_ci return -EINVAL; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; 139462306a36Sopenharmony_ci fe->discrete.denominator = is_ntsc ? 30000 : 25000; 139562306a36Sopenharmony_ci fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; 139662306a36Sopenharmony_ci dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__, 139762306a36Sopenharmony_ci fe->discrete.numerator, 139862306a36Sopenharmony_ci fe->discrete.denominator); 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic int s2255_open(struct file *file) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct s2255_vc *vc = video_drvdata(file); 140562306a36Sopenharmony_ci struct s2255_dev *dev = vc->dev; 140662306a36Sopenharmony_ci int state; 140762306a36Sopenharmony_ci int rc = 0; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci rc = v4l2_fh_open(file); 141062306a36Sopenharmony_ci if (rc != 0) 141162306a36Sopenharmony_ci return rc; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci dprintk(dev, 1, "s2255: %s\n", __func__); 141462306a36Sopenharmony_ci state = atomic_read(&dev->fw_data->fw_state); 141562306a36Sopenharmony_ci switch (state) { 141662306a36Sopenharmony_ci case S2255_FW_DISCONNECTING: 141762306a36Sopenharmony_ci return -ENODEV; 141862306a36Sopenharmony_ci case S2255_FW_FAILED: 141962306a36Sopenharmony_ci s2255_dev_err(&dev->udev->dev, 142062306a36Sopenharmony_ci "firmware load failed. retrying.\n"); 142162306a36Sopenharmony_ci s2255_fwload_start(dev); 142262306a36Sopenharmony_ci wait_event_timeout(dev->fw_data->wait_fw, 142362306a36Sopenharmony_ci ((atomic_read(&dev->fw_data->fw_state) 142462306a36Sopenharmony_ci == S2255_FW_SUCCESS) || 142562306a36Sopenharmony_ci (atomic_read(&dev->fw_data->fw_state) 142662306a36Sopenharmony_ci == S2255_FW_DISCONNECTING)), 142762306a36Sopenharmony_ci msecs_to_jiffies(S2255_LOAD_TIMEOUT)); 142862306a36Sopenharmony_ci /* state may have changed, re-read */ 142962306a36Sopenharmony_ci state = atomic_read(&dev->fw_data->fw_state); 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci case S2255_FW_NOTLOADED: 143262306a36Sopenharmony_ci case S2255_FW_LOADED_DSPWAIT: 143362306a36Sopenharmony_ci /* give S2255_LOAD_TIMEOUT time for firmware to load in case 143462306a36Sopenharmony_ci driver loaded and then device immediately opened */ 143562306a36Sopenharmony_ci pr_info("%s waiting for firmware load\n", __func__); 143662306a36Sopenharmony_ci wait_event_timeout(dev->fw_data->wait_fw, 143762306a36Sopenharmony_ci ((atomic_read(&dev->fw_data->fw_state) 143862306a36Sopenharmony_ci == S2255_FW_SUCCESS) || 143962306a36Sopenharmony_ci (atomic_read(&dev->fw_data->fw_state) 144062306a36Sopenharmony_ci == S2255_FW_DISCONNECTING)), 144162306a36Sopenharmony_ci msecs_to_jiffies(S2255_LOAD_TIMEOUT)); 144262306a36Sopenharmony_ci /* state may have changed, re-read */ 144362306a36Sopenharmony_ci state = atomic_read(&dev->fw_data->fw_state); 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci case S2255_FW_SUCCESS: 144662306a36Sopenharmony_ci default: 144762306a36Sopenharmony_ci break; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci /* state may have changed in above switch statement */ 145062306a36Sopenharmony_ci switch (state) { 145162306a36Sopenharmony_ci case S2255_FW_SUCCESS: 145262306a36Sopenharmony_ci break; 145362306a36Sopenharmony_ci case S2255_FW_FAILED: 145462306a36Sopenharmony_ci pr_info("2255 firmware load failed.\n"); 145562306a36Sopenharmony_ci return -ENODEV; 145662306a36Sopenharmony_ci case S2255_FW_DISCONNECTING: 145762306a36Sopenharmony_ci pr_info("%s: disconnecting\n", __func__); 145862306a36Sopenharmony_ci return -ENODEV; 145962306a36Sopenharmony_ci case S2255_FW_LOADED_DSPWAIT: 146062306a36Sopenharmony_ci case S2255_FW_NOTLOADED: 146162306a36Sopenharmony_ci pr_info("%s: firmware not loaded, please retry\n", 146262306a36Sopenharmony_ci __func__); 146362306a36Sopenharmony_ci /* 146462306a36Sopenharmony_ci * Timeout on firmware load means device unusable. 146562306a36Sopenharmony_ci * Set firmware failure state. 146662306a36Sopenharmony_ci * On next s2255_open the firmware will be reloaded. 146762306a36Sopenharmony_ci */ 146862306a36Sopenharmony_ci atomic_set(&dev->fw_data->fw_state, 146962306a36Sopenharmony_ci S2255_FW_FAILED); 147062306a36Sopenharmony_ci return -EAGAIN; 147162306a36Sopenharmony_ci default: 147262306a36Sopenharmony_ci pr_info("%s: unknown state\n", __func__); 147362306a36Sopenharmony_ci return -EFAULT; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci if (!vc->configured) { 147662306a36Sopenharmony_ci /* configure channel to default state */ 147762306a36Sopenharmony_ci vc->fmt = &formats[0]; 147862306a36Sopenharmony_ci s2255_set_mode(vc, &vc->mode); 147962306a36Sopenharmony_ci vc->configured = 1; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci return 0; 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_cistatic void s2255_destroy(struct s2255_dev *dev) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci dprintk(dev, 1, "%s", __func__); 148762306a36Sopenharmony_ci /* board shutdown stops the read pipe if it is running */ 148862306a36Sopenharmony_ci s2255_board_shutdown(dev); 148962306a36Sopenharmony_ci /* make sure firmware still not trying to load */ 149062306a36Sopenharmony_ci timer_shutdown_sync(&dev->timer); /* only started in .probe and .open */ 149162306a36Sopenharmony_ci if (dev->fw_data->fw_urb) { 149262306a36Sopenharmony_ci usb_kill_urb(dev->fw_data->fw_urb); 149362306a36Sopenharmony_ci usb_free_urb(dev->fw_data->fw_urb); 149462306a36Sopenharmony_ci dev->fw_data->fw_urb = NULL; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci release_firmware(dev->fw_data->fw); 149762306a36Sopenharmony_ci kfree(dev->fw_data->pfw_data); 149862306a36Sopenharmony_ci kfree(dev->fw_data); 149962306a36Sopenharmony_ci /* reset the DSP so firmware can be reloaded next time */ 150062306a36Sopenharmony_ci s2255_reset_dsppower(dev); 150162306a36Sopenharmony_ci mutex_destroy(&dev->lock); 150262306a36Sopenharmony_ci usb_put_dev(dev->udev); 150362306a36Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 150462306a36Sopenharmony_ci kfree(dev->cmdbuf); 150562306a36Sopenharmony_ci kfree(dev); 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic const struct v4l2_file_operations s2255_fops_v4l = { 150962306a36Sopenharmony_ci .owner = THIS_MODULE, 151062306a36Sopenharmony_ci .open = s2255_open, 151162306a36Sopenharmony_ci .release = vb2_fop_release, 151262306a36Sopenharmony_ci .poll = vb2_fop_poll, 151362306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ 151462306a36Sopenharmony_ci .mmap = vb2_fop_mmap, 151562306a36Sopenharmony_ci .read = vb2_fop_read, 151662306a36Sopenharmony_ci}; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops s2255_ioctl_ops = { 151962306a36Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 152062306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 152162306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 152262306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 152362306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 152462306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 152562306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 152662306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 152762306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 152862306a36Sopenharmony_ci .vidioc_s_std = vidioc_s_std, 152962306a36Sopenharmony_ci .vidioc_g_std = vidioc_g_std, 153062306a36Sopenharmony_ci .vidioc_enum_input = vidioc_enum_input, 153162306a36Sopenharmony_ci .vidioc_g_input = vidioc_g_input, 153262306a36Sopenharmony_ci .vidioc_s_input = vidioc_s_input, 153362306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 153462306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 153562306a36Sopenharmony_ci .vidioc_s_jpegcomp = vidioc_s_jpegcomp, 153662306a36Sopenharmony_ci .vidioc_g_jpegcomp = vidioc_g_jpegcomp, 153762306a36Sopenharmony_ci .vidioc_s_parm = vidioc_s_parm, 153862306a36Sopenharmony_ci .vidioc_g_parm = vidioc_g_parm, 153962306a36Sopenharmony_ci .vidioc_enum_framesizes = vidioc_enum_framesizes, 154062306a36Sopenharmony_ci .vidioc_enum_frameintervals = vidioc_enum_frameintervals, 154162306a36Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 154262306a36Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 154362306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 154462306a36Sopenharmony_ci}; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic void s2255_video_device_release(struct video_device *vdev) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); 154962306a36Sopenharmony_ci struct s2255_vc *vc = 155062306a36Sopenharmony_ci container_of(vdev, struct s2255_vc, vdev); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci dprintk(dev, 4, "%s, chnls: %d\n", __func__, 155362306a36Sopenharmony_ci atomic_read(&dev->num_channels)); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci v4l2_ctrl_handler_free(&vc->hdl); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (atomic_dec_and_test(&dev->num_channels)) 155862306a36Sopenharmony_ci s2255_destroy(dev); 155962306a36Sopenharmony_ci return; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic const struct video_device template = { 156362306a36Sopenharmony_ci .name = "s2255v", 156462306a36Sopenharmony_ci .fops = &s2255_fops_v4l, 156562306a36Sopenharmony_ci .ioctl_ops = &s2255_ioctl_ops, 156662306a36Sopenharmony_ci .release = s2255_video_device_release, 156762306a36Sopenharmony_ci .tvnorms = S2255_NORMS, 156862306a36Sopenharmony_ci}; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops s2255_ctrl_ops = { 157162306a36Sopenharmony_ci .s_ctrl = s2255_s_ctrl, 157262306a36Sopenharmony_ci}; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic const struct v4l2_ctrl_config color_filter_ctrl = { 157562306a36Sopenharmony_ci .ops = &s2255_ctrl_ops, 157662306a36Sopenharmony_ci .name = "Color Filter", 157762306a36Sopenharmony_ci .id = V4L2_CID_S2255_COLORFILTER, 157862306a36Sopenharmony_ci .type = V4L2_CTRL_TYPE_BOOLEAN, 157962306a36Sopenharmony_ci .max = 1, 158062306a36Sopenharmony_ci .step = 1, 158162306a36Sopenharmony_ci .def = 1, 158262306a36Sopenharmony_ci}; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_cistatic int s2255_probe_v4l(struct s2255_dev *dev) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci int ret; 158762306a36Sopenharmony_ci int i; 158862306a36Sopenharmony_ci int cur_nr = video_nr; 158962306a36Sopenharmony_ci struct s2255_vc *vc; 159062306a36Sopenharmony_ci struct vb2_queue *q; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev); 159362306a36Sopenharmony_ci if (ret) 159462306a36Sopenharmony_ci return ret; 159562306a36Sopenharmony_ci /* initialize all video 4 linux */ 159662306a36Sopenharmony_ci /* register 4 video devices */ 159762306a36Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) { 159862306a36Sopenharmony_ci vc = &dev->vc[i]; 159962306a36Sopenharmony_ci INIT_LIST_HEAD(&vc->buf_list); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci v4l2_ctrl_handler_init(&vc->hdl, 6); 160262306a36Sopenharmony_ci v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, 160362306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); 160462306a36Sopenharmony_ci v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, 160562306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); 160662306a36Sopenharmony_ci v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, 160762306a36Sopenharmony_ci V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); 160862306a36Sopenharmony_ci v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, 160962306a36Sopenharmony_ci V4L2_CID_HUE, 0, 255, 1, DEF_HUE); 161062306a36Sopenharmony_ci vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl, 161162306a36Sopenharmony_ci &s2255_ctrl_ops, 161262306a36Sopenharmony_ci V4L2_CID_JPEG_COMPRESSION_QUALITY, 161362306a36Sopenharmony_ci 0, 100, 1, S2255_DEF_JPEG_QUAL); 161462306a36Sopenharmony_ci if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && 161562306a36Sopenharmony_ci (dev->pid != 0x2257 || vc->idx <= 1)) 161662306a36Sopenharmony_ci v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl, 161762306a36Sopenharmony_ci NULL); 161862306a36Sopenharmony_ci if (vc->hdl.error) { 161962306a36Sopenharmony_ci ret = vc->hdl.error; 162062306a36Sopenharmony_ci v4l2_ctrl_handler_free(&vc->hdl); 162162306a36Sopenharmony_ci dev_err(&dev->udev->dev, "couldn't register control\n"); 162262306a36Sopenharmony_ci break; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci q = &vc->vb_vidq; 162562306a36Sopenharmony_ci q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 162662306a36Sopenharmony_ci q->io_modes = VB2_MMAP | VB2_READ | VB2_USERPTR; 162762306a36Sopenharmony_ci q->drv_priv = vc; 162862306a36Sopenharmony_ci q->lock = &vc->vb_lock; 162962306a36Sopenharmony_ci q->buf_struct_size = sizeof(struct s2255_buffer); 163062306a36Sopenharmony_ci q->mem_ops = &vb2_vmalloc_memops; 163162306a36Sopenharmony_ci q->ops = &s2255_video_qops; 163262306a36Sopenharmony_ci q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 163362306a36Sopenharmony_ci ret = vb2_queue_init(q); 163462306a36Sopenharmony_ci if (ret != 0) { 163562306a36Sopenharmony_ci dev_err(&dev->udev->dev, 163662306a36Sopenharmony_ci "%s vb2_queue_init 0x%x\n", __func__, ret); 163762306a36Sopenharmony_ci break; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci /* register video devices */ 164062306a36Sopenharmony_ci vc->vdev = template; 164162306a36Sopenharmony_ci vc->vdev.queue = q; 164262306a36Sopenharmony_ci vc->vdev.ctrl_handler = &vc->hdl; 164362306a36Sopenharmony_ci vc->vdev.lock = &dev->lock; 164462306a36Sopenharmony_ci vc->vdev.v4l2_dev = &dev->v4l2_dev; 164562306a36Sopenharmony_ci vc->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | 164662306a36Sopenharmony_ci V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; 164762306a36Sopenharmony_ci video_set_drvdata(&vc->vdev, vc); 164862306a36Sopenharmony_ci if (video_nr == -1) 164962306a36Sopenharmony_ci ret = video_register_device(&vc->vdev, 165062306a36Sopenharmony_ci VFL_TYPE_VIDEO, 165162306a36Sopenharmony_ci video_nr); 165262306a36Sopenharmony_ci else 165362306a36Sopenharmony_ci ret = video_register_device(&vc->vdev, 165462306a36Sopenharmony_ci VFL_TYPE_VIDEO, 165562306a36Sopenharmony_ci cur_nr + i); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (ret) { 165862306a36Sopenharmony_ci dev_err(&dev->udev->dev, 165962306a36Sopenharmony_ci "failed to register video device!\n"); 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci atomic_inc(&dev->num_channels); 166362306a36Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", 166462306a36Sopenharmony_ci video_device_node_name(&vc->vdev)); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci pr_info("Sensoray 2255 V4L driver Revision: %s\n", 166862306a36Sopenharmony_ci S2255_VERSION); 166962306a36Sopenharmony_ci /* if no channels registered, return error and probe will fail*/ 167062306a36Sopenharmony_ci if (atomic_read(&dev->num_channels) == 0) { 167162306a36Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 167262306a36Sopenharmony_ci return ret; 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci if (atomic_read(&dev->num_channels) != MAX_CHANNELS) 167562306a36Sopenharmony_ci pr_warn("s2255: Not all channels available.\n"); 167662306a36Sopenharmony_ci return 0; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci/* this function moves the usb stream read pipe data 168062306a36Sopenharmony_ci * into the system buffers. 168162306a36Sopenharmony_ci * returns 0 on success, EAGAIN if more data to process( call this 168262306a36Sopenharmony_ci * function again). 168362306a36Sopenharmony_ci * 168462306a36Sopenharmony_ci * Received frame structure: 168562306a36Sopenharmony_ci * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME) 168662306a36Sopenharmony_ci * bytes 4-7: channel: 0-3 168762306a36Sopenharmony_ci * bytes 8-11: payload size: size of the frame 168862306a36Sopenharmony_ci * bytes 12-payloadsize+12: frame data 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_cistatic int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci char *pdest; 169362306a36Sopenharmony_ci u32 offset = 0; 169462306a36Sopenharmony_ci int bframe = 0; 169562306a36Sopenharmony_ci char *psrc; 169662306a36Sopenharmony_ci unsigned long copy_size; 169762306a36Sopenharmony_ci unsigned long size; 169862306a36Sopenharmony_ci s32 idx = -1; 169962306a36Sopenharmony_ci struct s2255_framei *frm; 170062306a36Sopenharmony_ci unsigned char *pdata; 170162306a36Sopenharmony_ci struct s2255_vc *vc; 170262306a36Sopenharmony_ci dprintk(dev, 100, "buffer to user\n"); 170362306a36Sopenharmony_ci vc = &dev->vc[dev->cc]; 170462306a36Sopenharmony_ci idx = vc->cur_frame; 170562306a36Sopenharmony_ci frm = &vc->buffer.frame[idx]; 170662306a36Sopenharmony_ci if (frm->ulState == S2255_READ_IDLE) { 170762306a36Sopenharmony_ci int jj; 170862306a36Sopenharmony_ci unsigned int cc; 170962306a36Sopenharmony_ci __le32 *pdword; /*data from dsp is little endian */ 171062306a36Sopenharmony_ci int payload; 171162306a36Sopenharmony_ci /* search for marker codes */ 171262306a36Sopenharmony_ci pdata = (unsigned char *)pipe_info->transfer_buffer; 171362306a36Sopenharmony_ci pdword = (__le32 *)pdata; 171462306a36Sopenharmony_ci for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { 171562306a36Sopenharmony_ci switch (*pdword) { 171662306a36Sopenharmony_ci case S2255_MARKER_FRAME: 171762306a36Sopenharmony_ci dprintk(dev, 4, "marker @ offset: %d [%x %x]\n", 171862306a36Sopenharmony_ci jj, pdata[0], pdata[1]); 171962306a36Sopenharmony_ci offset = jj + PREFIX_SIZE; 172062306a36Sopenharmony_ci bframe = 1; 172162306a36Sopenharmony_ci cc = le32_to_cpu(pdword[1]); 172262306a36Sopenharmony_ci if (cc >= MAX_CHANNELS) { 172362306a36Sopenharmony_ci dprintk(dev, 0, 172462306a36Sopenharmony_ci "bad channel\n"); 172562306a36Sopenharmony_ci return -EINVAL; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci /* reverse it */ 172862306a36Sopenharmony_ci dev->cc = G_chnmap[cc]; 172962306a36Sopenharmony_ci vc = &dev->vc[dev->cc]; 173062306a36Sopenharmony_ci payload = le32_to_cpu(pdword[3]); 173162306a36Sopenharmony_ci if (payload > vc->req_image_size) { 173262306a36Sopenharmony_ci vc->bad_payload++; 173362306a36Sopenharmony_ci /* discard the bad frame */ 173462306a36Sopenharmony_ci return -EINVAL; 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci vc->pkt_size = payload; 173762306a36Sopenharmony_ci vc->jpg_size = le32_to_cpu(pdword[4]); 173862306a36Sopenharmony_ci break; 173962306a36Sopenharmony_ci case S2255_MARKER_RESPONSE: 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci pdata += DEF_USB_BLOCK; 174262306a36Sopenharmony_ci jj += DEF_USB_BLOCK; 174362306a36Sopenharmony_ci if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS) 174462306a36Sopenharmony_ci break; 174562306a36Sopenharmony_ci cc = G_chnmap[le32_to_cpu(pdword[1])]; 174662306a36Sopenharmony_ci if (cc >= MAX_CHANNELS) 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci vc = &dev->vc[cc]; 174962306a36Sopenharmony_ci switch (pdword[2]) { 175062306a36Sopenharmony_ci case S2255_RESPONSE_SETMODE: 175162306a36Sopenharmony_ci /* check if channel valid */ 175262306a36Sopenharmony_ci /* set mode ready */ 175362306a36Sopenharmony_ci vc->setmode_ready = 1; 175462306a36Sopenharmony_ci wake_up(&vc->wait_setmode); 175562306a36Sopenharmony_ci dprintk(dev, 5, "setmode rdy %d\n", cc); 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case S2255_RESPONSE_FW: 175862306a36Sopenharmony_ci dev->chn_ready |= (1 << cc); 175962306a36Sopenharmony_ci if ((dev->chn_ready & 0x0f) != 0x0f) 176062306a36Sopenharmony_ci break; 176162306a36Sopenharmony_ci /* all channels ready */ 176262306a36Sopenharmony_ci pr_info("s2255: fw loaded\n"); 176362306a36Sopenharmony_ci atomic_set(&dev->fw_data->fw_state, 176462306a36Sopenharmony_ci S2255_FW_SUCCESS); 176562306a36Sopenharmony_ci wake_up(&dev->fw_data->wait_fw); 176662306a36Sopenharmony_ci break; 176762306a36Sopenharmony_ci case S2255_RESPONSE_STATUS: 176862306a36Sopenharmony_ci vc->vidstatus = le32_to_cpu(pdword[3]); 176962306a36Sopenharmony_ci vc->vidstatus_ready = 1; 177062306a36Sopenharmony_ci wake_up(&vc->wait_vidstatus); 177162306a36Sopenharmony_ci dprintk(dev, 5, "vstat %x chan %d\n", 177262306a36Sopenharmony_ci le32_to_cpu(pdword[3]), cc); 177362306a36Sopenharmony_ci break; 177462306a36Sopenharmony_ci default: 177562306a36Sopenharmony_ci pr_info("s2255 unknown resp\n"); 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci pdata++; 177862306a36Sopenharmony_ci break; 177962306a36Sopenharmony_ci default: 178062306a36Sopenharmony_ci pdata++; 178162306a36Sopenharmony_ci break; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci if (bframe) 178462306a36Sopenharmony_ci break; 178562306a36Sopenharmony_ci } /* for */ 178662306a36Sopenharmony_ci if (!bframe) 178762306a36Sopenharmony_ci return -EINVAL; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci vc = &dev->vc[dev->cc]; 179062306a36Sopenharmony_ci idx = vc->cur_frame; 179162306a36Sopenharmony_ci frm = &vc->buffer.frame[idx]; 179262306a36Sopenharmony_ci /* search done. now find out if should be acquiring on this channel */ 179362306a36Sopenharmony_ci if (!vb2_is_streaming(&vc->vb_vidq)) { 179462306a36Sopenharmony_ci /* we found a frame, but this channel is turned off */ 179562306a36Sopenharmony_ci frm->ulState = S2255_READ_IDLE; 179662306a36Sopenharmony_ci return -EINVAL; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (frm->ulState == S2255_READ_IDLE) { 180062306a36Sopenharmony_ci frm->ulState = S2255_READ_FRAME; 180162306a36Sopenharmony_ci frm->cur_size = 0; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci /* skip the marker 512 bytes (and offset if out of sync) */ 180562306a36Sopenharmony_ci psrc = (u8 *)pipe_info->transfer_buffer + offset; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (frm->lpvbits == NULL) { 180962306a36Sopenharmony_ci dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d", 181062306a36Sopenharmony_ci frm, dev, dev->cc, idx); 181162306a36Sopenharmony_ci return -ENOMEM; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci pdest = frm->lpvbits + frm->cur_size; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci copy_size = (pipe_info->cur_transfer_size - offset); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci size = vc->pkt_size - PREFIX_SIZE; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* sanity check on pdest */ 182162306a36Sopenharmony_ci if ((copy_size + frm->cur_size) < vc->req_image_size) 182262306a36Sopenharmony_ci memcpy(pdest, psrc, copy_size); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci frm->cur_size += copy_size; 182562306a36Sopenharmony_ci dprintk(dev, 4, "cur_size: %lu, size: %lu\n", frm->cur_size, size); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (frm->cur_size >= size) { 182862306a36Sopenharmony_ci dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n", 182962306a36Sopenharmony_ci dev->cc, idx); 183062306a36Sopenharmony_ci vc->last_frame = vc->cur_frame; 183162306a36Sopenharmony_ci vc->cur_frame++; 183262306a36Sopenharmony_ci /* end of system frame ring buffer, start at zero */ 183362306a36Sopenharmony_ci if ((vc->cur_frame == SYS_FRAMES) || 183462306a36Sopenharmony_ci (vc->cur_frame == vc->buffer.dwFrames)) 183562306a36Sopenharmony_ci vc->cur_frame = 0; 183662306a36Sopenharmony_ci /* frame ready */ 183762306a36Sopenharmony_ci if (vb2_is_streaming(&vc->vb_vidq)) 183862306a36Sopenharmony_ci s2255_got_frame(vc, vc->jpg_size); 183962306a36Sopenharmony_ci vc->frame_count++; 184062306a36Sopenharmony_ci frm->ulState = S2255_READ_IDLE; 184162306a36Sopenharmony_ci frm->cur_size = 0; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci /* done successfully */ 184562306a36Sopenharmony_ci return 0; 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic void s2255_read_video_callback(struct s2255_dev *dev, 184962306a36Sopenharmony_ci struct s2255_pipeinfo *pipe_info) 185062306a36Sopenharmony_ci{ 185162306a36Sopenharmony_ci int res; 185262306a36Sopenharmony_ci dprintk(dev, 50, "callback read video\n"); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (dev->cc >= MAX_CHANNELS) { 185562306a36Sopenharmony_ci dev->cc = 0; 185662306a36Sopenharmony_ci dev_err(&dev->udev->dev, "invalid channel\n"); 185762306a36Sopenharmony_ci return; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci /* otherwise copy to the system buffers */ 186062306a36Sopenharmony_ci res = save_frame(dev, pipe_info); 186162306a36Sopenharmony_ci if (res != 0) 186262306a36Sopenharmony_ci dprintk(dev, 4, "s2255: read callback failed\n"); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci dprintk(dev, 50, "callback read video done\n"); 186562306a36Sopenharmony_ci return; 186662306a36Sopenharmony_ci} 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_cistatic long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, 186962306a36Sopenharmony_ci u16 Index, u16 Value, void *TransferBuffer, 187062306a36Sopenharmony_ci s32 TransferBufferLength, int bOut) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci int r; 187362306a36Sopenharmony_ci unsigned char *buf; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci buf = kmalloc(TransferBufferLength, GFP_KERNEL); 187662306a36Sopenharmony_ci if (!buf) 187762306a36Sopenharmony_ci return -ENOMEM; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci if (!bOut) { 188062306a36Sopenharmony_ci r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), 188162306a36Sopenharmony_ci Request, 188262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | 188362306a36Sopenharmony_ci USB_DIR_IN, 188462306a36Sopenharmony_ci Value, Index, buf, 188562306a36Sopenharmony_ci TransferBufferLength, USB_CTRL_SET_TIMEOUT); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (r >= 0) 188862306a36Sopenharmony_ci memcpy(TransferBuffer, buf, TransferBufferLength); 188962306a36Sopenharmony_ci } else { 189062306a36Sopenharmony_ci memcpy(buf, TransferBuffer, TransferBufferLength); 189162306a36Sopenharmony_ci r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 189262306a36Sopenharmony_ci Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 189362306a36Sopenharmony_ci Value, Index, buf, 189462306a36Sopenharmony_ci TransferBufferLength, USB_CTRL_SET_TIMEOUT); 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci kfree(buf); 189762306a36Sopenharmony_ci return r; 189862306a36Sopenharmony_ci} 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci/* 190162306a36Sopenharmony_ci * retrieve FX2 firmware version. future use. 190262306a36Sopenharmony_ci * @param dev pointer to device extension 190362306a36Sopenharmony_ci * @return -1 for fail, else returns firmware version as an int(16 bits) 190462306a36Sopenharmony_ci */ 190562306a36Sopenharmony_cistatic int s2255_get_fx2fw(struct s2255_dev *dev) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci int fw; 190862306a36Sopenharmony_ci int ret; 190962306a36Sopenharmony_ci unsigned char transBuffer[64]; 191062306a36Sopenharmony_ci ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, 191162306a36Sopenharmony_ci S2255_VR_IN); 191262306a36Sopenharmony_ci if (ret < 0) 191362306a36Sopenharmony_ci dprintk(dev, 2, "get fw error: %x\n", ret); 191462306a36Sopenharmony_ci fw = transBuffer[0] + (transBuffer[1] << 8); 191562306a36Sopenharmony_ci dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); 191662306a36Sopenharmony_ci return fw; 191762306a36Sopenharmony_ci} 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci/* 192062306a36Sopenharmony_ci * Create the system ring buffer to copy frames into from the 192162306a36Sopenharmony_ci * usb read pipe. 192262306a36Sopenharmony_ci */ 192362306a36Sopenharmony_cistatic int s2255_create_sys_buffers(struct s2255_vc *vc) 192462306a36Sopenharmony_ci{ 192562306a36Sopenharmony_ci unsigned long i; 192662306a36Sopenharmony_ci unsigned long reqsize; 192762306a36Sopenharmony_ci vc->buffer.dwFrames = SYS_FRAMES; 192862306a36Sopenharmony_ci /* always allocate maximum size(PAL) for system buffers */ 192962306a36Sopenharmony_ci reqsize = SYS_FRAMES_MAXSIZE; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci if (reqsize > SYS_FRAMES_MAXSIZE) 193262306a36Sopenharmony_ci reqsize = SYS_FRAMES_MAXSIZE; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci for (i = 0; i < SYS_FRAMES; i++) { 193562306a36Sopenharmony_ci /* allocate the frames */ 193662306a36Sopenharmony_ci vc->buffer.frame[i].lpvbits = vmalloc(reqsize); 193762306a36Sopenharmony_ci vc->buffer.frame[i].size = reqsize; 193862306a36Sopenharmony_ci if (vc->buffer.frame[i].lpvbits == NULL) { 193962306a36Sopenharmony_ci pr_info("out of memory. using less frames\n"); 194062306a36Sopenharmony_ci vc->buffer.dwFrames = i; 194162306a36Sopenharmony_ci break; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* make sure internal states are set */ 194662306a36Sopenharmony_ci for (i = 0; i < SYS_FRAMES; i++) { 194762306a36Sopenharmony_ci vc->buffer.frame[i].ulState = 0; 194862306a36Sopenharmony_ci vc->buffer.frame[i].cur_size = 0; 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci vc->cur_frame = 0; 195262306a36Sopenharmony_ci vc->last_frame = -1; 195362306a36Sopenharmony_ci return 0; 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic int s2255_release_sys_buffers(struct s2255_vc *vc) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci unsigned long i; 195962306a36Sopenharmony_ci for (i = 0; i < SYS_FRAMES; i++) { 196062306a36Sopenharmony_ci vfree(vc->buffer.frame[i].lpvbits); 196162306a36Sopenharmony_ci vc->buffer.frame[i].lpvbits = NULL; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci return 0; 196462306a36Sopenharmony_ci} 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_cistatic int s2255_board_init(struct s2255_dev *dev) 196762306a36Sopenharmony_ci{ 196862306a36Sopenharmony_ci struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT; 196962306a36Sopenharmony_ci int fw_ver; 197062306a36Sopenharmony_ci int j; 197162306a36Sopenharmony_ci struct s2255_pipeinfo *pipe = &dev->pipe; 197262306a36Sopenharmony_ci dprintk(dev, 4, "board init: %p", dev); 197362306a36Sopenharmony_ci memset(pipe, 0, sizeof(*pipe)); 197462306a36Sopenharmony_ci pipe->dev = dev; 197562306a36Sopenharmony_ci pipe->cur_transfer_size = S2255_USB_XFER_SIZE; 197662306a36Sopenharmony_ci pipe->max_transfer_size = S2255_USB_XFER_SIZE; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, 197962306a36Sopenharmony_ci GFP_KERNEL); 198062306a36Sopenharmony_ci if (pipe->transfer_buffer == NULL) { 198162306a36Sopenharmony_ci dprintk(dev, 1, "out of memory!\n"); 198262306a36Sopenharmony_ci return -ENOMEM; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci /* query the firmware */ 198562306a36Sopenharmony_ci fw_ver = s2255_get_fx2fw(dev); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci pr_info("s2255: usb firmware version %d.%d\n", 198862306a36Sopenharmony_ci (fw_ver >> 8) & 0xff, 198962306a36Sopenharmony_ci fw_ver & 0xff); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci if (fw_ver < S2255_CUR_USB_FWVER) 199262306a36Sopenharmony_ci pr_info("s2255: newer USB firmware available\n"); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci for (j = 0; j < MAX_CHANNELS; j++) { 199562306a36Sopenharmony_ci struct s2255_vc *vc = &dev->vc[j]; 199662306a36Sopenharmony_ci vc->mode = mode_def; 199762306a36Sopenharmony_ci if (dev->pid == 0x2257 && j > 1) 199862306a36Sopenharmony_ci vc->mode.color |= (1 << 16); 199962306a36Sopenharmony_ci vc->jpegqual = S2255_DEF_JPEG_QUAL; 200062306a36Sopenharmony_ci vc->width = LINE_SZ_4CIFS_NTSC; 200162306a36Sopenharmony_ci vc->height = NUM_LINES_4CIFS_NTSC * 2; 200262306a36Sopenharmony_ci vc->std = V4L2_STD_NTSC_M; 200362306a36Sopenharmony_ci vc->fmt = &formats[0]; 200462306a36Sopenharmony_ci vc->mode.restart = 1; 200562306a36Sopenharmony_ci vc->req_image_size = get_transfer_size(&mode_def); 200662306a36Sopenharmony_ci vc->frame_count = 0; 200762306a36Sopenharmony_ci /* create the system buffers */ 200862306a36Sopenharmony_ci s2255_create_sys_buffers(vc); 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci /* start read pipe */ 201162306a36Sopenharmony_ci s2255_start_readpipe(dev); 201262306a36Sopenharmony_ci dprintk(dev, 1, "%s: success\n", __func__); 201362306a36Sopenharmony_ci return 0; 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic int s2255_board_shutdown(struct s2255_dev *dev) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci u32 i; 201962306a36Sopenharmony_ci dprintk(dev, 1, "%s: dev: %p", __func__, dev); 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) { 202262306a36Sopenharmony_ci if (vb2_is_streaming(&dev->vc[i].vb_vidq)) 202362306a36Sopenharmony_ci s2255_stop_acquire(&dev->vc[i]); 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci s2255_stop_readpipe(dev); 202662306a36Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) 202762306a36Sopenharmony_ci s2255_release_sys_buffers(&dev->vc[i]); 202862306a36Sopenharmony_ci /* release transfer buffer */ 202962306a36Sopenharmony_ci kfree(dev->pipe.transfer_buffer); 203062306a36Sopenharmony_ci return 0; 203162306a36Sopenharmony_ci} 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cistatic void read_pipe_completion(struct urb *purb) 203462306a36Sopenharmony_ci{ 203562306a36Sopenharmony_ci struct s2255_pipeinfo *pipe_info; 203662306a36Sopenharmony_ci struct s2255_dev *dev; 203762306a36Sopenharmony_ci int status; 203862306a36Sopenharmony_ci int pipe; 203962306a36Sopenharmony_ci pipe_info = purb->context; 204062306a36Sopenharmony_ci if (pipe_info == NULL) { 204162306a36Sopenharmony_ci dev_err(&purb->dev->dev, "no context!\n"); 204262306a36Sopenharmony_ci return; 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci dev = pipe_info->dev; 204562306a36Sopenharmony_ci if (dev == NULL) { 204662306a36Sopenharmony_ci dev_err(&purb->dev->dev, "no context!\n"); 204762306a36Sopenharmony_ci return; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci status = purb->status; 205062306a36Sopenharmony_ci /* if shutting down, do not resubmit, exit immediately */ 205162306a36Sopenharmony_ci if (status == -ESHUTDOWN) { 205262306a36Sopenharmony_ci dprintk(dev, 2, "%s: err shutdown\n", __func__); 205362306a36Sopenharmony_ci pipe_info->err_count++; 205462306a36Sopenharmony_ci return; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci if (pipe_info->state == 0) { 205862306a36Sopenharmony_ci dprintk(dev, 2, "%s: exiting USB pipe", __func__); 205962306a36Sopenharmony_ci return; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci if (status == 0) 206362306a36Sopenharmony_ci s2255_read_video_callback(dev, pipe_info); 206462306a36Sopenharmony_ci else { 206562306a36Sopenharmony_ci pipe_info->err_count++; 206662306a36Sopenharmony_ci dprintk(dev, 1, "%s: failed URB %d\n", __func__, status); 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); 207062306a36Sopenharmony_ci /* reuse urb */ 207162306a36Sopenharmony_ci usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, 207262306a36Sopenharmony_ci pipe, 207362306a36Sopenharmony_ci pipe_info->transfer_buffer, 207462306a36Sopenharmony_ci pipe_info->cur_transfer_size, 207562306a36Sopenharmony_ci read_pipe_completion, pipe_info); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci if (pipe_info->state != 0) { 207862306a36Sopenharmony_ci if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) 207962306a36Sopenharmony_ci dev_err(&dev->udev->dev, "error submitting urb\n"); 208062306a36Sopenharmony_ci } else { 208162306a36Sopenharmony_ci dprintk(dev, 2, "%s :complete state 0\n", __func__); 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci return; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_cistatic int s2255_start_readpipe(struct s2255_dev *dev) 208762306a36Sopenharmony_ci{ 208862306a36Sopenharmony_ci int pipe; 208962306a36Sopenharmony_ci int retval; 209062306a36Sopenharmony_ci struct s2255_pipeinfo *pipe_info = &dev->pipe; 209162306a36Sopenharmony_ci pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); 209262306a36Sopenharmony_ci dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint); 209362306a36Sopenharmony_ci pipe_info->state = 1; 209462306a36Sopenharmony_ci pipe_info->err_count = 0; 209562306a36Sopenharmony_ci pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); 209662306a36Sopenharmony_ci if (!pipe_info->stream_urb) 209762306a36Sopenharmony_ci return -ENOMEM; 209862306a36Sopenharmony_ci /* transfer buffer allocated in board_init */ 209962306a36Sopenharmony_ci usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, 210062306a36Sopenharmony_ci pipe, 210162306a36Sopenharmony_ci pipe_info->transfer_buffer, 210262306a36Sopenharmony_ci pipe_info->cur_transfer_size, 210362306a36Sopenharmony_ci read_pipe_completion, pipe_info); 210462306a36Sopenharmony_ci retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); 210562306a36Sopenharmony_ci if (retval) { 210662306a36Sopenharmony_ci pr_err("s2255: start read pipe failed\n"); 210762306a36Sopenharmony_ci return retval; 210862306a36Sopenharmony_ci } 210962306a36Sopenharmony_ci return 0; 211062306a36Sopenharmony_ci} 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci/* starts acquisition process */ 211362306a36Sopenharmony_cistatic int s2255_start_acquire(struct s2255_vc *vc) 211462306a36Sopenharmony_ci{ 211562306a36Sopenharmony_ci int res; 211662306a36Sopenharmony_ci unsigned long chn_rev; 211762306a36Sopenharmony_ci int j; 211862306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); 211962306a36Sopenharmony_ci __le32 *buffer = dev->cmdbuf; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci mutex_lock(&dev->cmdlock); 212262306a36Sopenharmony_ci chn_rev = G_chnmap[vc->idx]; 212362306a36Sopenharmony_ci vc->last_frame = -1; 212462306a36Sopenharmony_ci vc->bad_payload = 0; 212562306a36Sopenharmony_ci vc->cur_frame = 0; 212662306a36Sopenharmony_ci for (j = 0; j < SYS_FRAMES; j++) { 212762306a36Sopenharmony_ci vc->buffer.frame[j].ulState = 0; 212862306a36Sopenharmony_ci vc->buffer.frame[j].cur_size = 0; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci /* send the start command */ 213262306a36Sopenharmony_ci buffer[0] = IN_DATA_TOKEN; 213362306a36Sopenharmony_ci buffer[1] = (__le32) cpu_to_le32(chn_rev); 213462306a36Sopenharmony_ci buffer[2] = CMD_START; 213562306a36Sopenharmony_ci res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 213662306a36Sopenharmony_ci if (res != 0) 213762306a36Sopenharmony_ci dev_err(&dev->udev->dev, "CMD_START error\n"); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res); 214062306a36Sopenharmony_ci mutex_unlock(&dev->cmdlock); 214162306a36Sopenharmony_ci return res; 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_cistatic int s2255_stop_acquire(struct s2255_vc *vc) 214562306a36Sopenharmony_ci{ 214662306a36Sopenharmony_ci int res; 214762306a36Sopenharmony_ci unsigned long chn_rev; 214862306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); 214962306a36Sopenharmony_ci __le32 *buffer = dev->cmdbuf; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci mutex_lock(&dev->cmdlock); 215262306a36Sopenharmony_ci chn_rev = G_chnmap[vc->idx]; 215362306a36Sopenharmony_ci /* send the stop command */ 215462306a36Sopenharmony_ci buffer[0] = IN_DATA_TOKEN; 215562306a36Sopenharmony_ci buffer[1] = (__le32) cpu_to_le32(chn_rev); 215662306a36Sopenharmony_ci buffer[2] = CMD_STOP; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); 215962306a36Sopenharmony_ci if (res != 0) 216062306a36Sopenharmony_ci dev_err(&dev->udev->dev, "CMD_STOP error\n"); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res); 216362306a36Sopenharmony_ci mutex_unlock(&dev->cmdlock); 216462306a36Sopenharmony_ci return res; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic void s2255_stop_readpipe(struct s2255_dev *dev) 216862306a36Sopenharmony_ci{ 216962306a36Sopenharmony_ci struct s2255_pipeinfo *pipe = &dev->pipe; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci pipe->state = 0; 217262306a36Sopenharmony_ci if (pipe->stream_urb) { 217362306a36Sopenharmony_ci /* cancel urb */ 217462306a36Sopenharmony_ci usb_kill_urb(pipe->stream_urb); 217562306a36Sopenharmony_ci usb_free_urb(pipe->stream_urb); 217662306a36Sopenharmony_ci pipe->stream_urb = NULL; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci dprintk(dev, 4, "%s", __func__); 217962306a36Sopenharmony_ci return; 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_cistatic void s2255_fwload_start(struct s2255_dev *dev) 218362306a36Sopenharmony_ci{ 218462306a36Sopenharmony_ci s2255_reset_dsppower(dev); 218562306a36Sopenharmony_ci dev->fw_data->fw_size = dev->fw_data->fw->size; 218662306a36Sopenharmony_ci atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED); 218762306a36Sopenharmony_ci memcpy(dev->fw_data->pfw_data, 218862306a36Sopenharmony_ci dev->fw_data->fw->data, CHUNK_SIZE); 218962306a36Sopenharmony_ci dev->fw_data->fw_loaded = CHUNK_SIZE; 219062306a36Sopenharmony_ci usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, 219162306a36Sopenharmony_ci usb_sndbulkpipe(dev->udev, 2), 219262306a36Sopenharmony_ci dev->fw_data->pfw_data, 219362306a36Sopenharmony_ci CHUNK_SIZE, s2255_fwchunk_complete, 219462306a36Sopenharmony_ci dev->fw_data); 219562306a36Sopenharmony_ci mod_timer(&dev->timer, jiffies + HZ); 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci/* standard usb probe function */ 219962306a36Sopenharmony_cistatic int s2255_probe(struct usb_interface *interface, 220062306a36Sopenharmony_ci const struct usb_device_id *id) 220162306a36Sopenharmony_ci{ 220262306a36Sopenharmony_ci struct s2255_dev *dev = NULL; 220362306a36Sopenharmony_ci struct usb_host_interface *iface_desc; 220462306a36Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 220562306a36Sopenharmony_ci int i; 220662306a36Sopenharmony_ci int retval = -ENOMEM; 220762306a36Sopenharmony_ci __le32 *pdata; 220862306a36Sopenharmony_ci int fw_size; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci /* allocate memory for our device state and initialize it to zero */ 221162306a36Sopenharmony_ci dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); 221262306a36Sopenharmony_ci if (dev == NULL) { 221362306a36Sopenharmony_ci s2255_dev_err(&interface->dev, "out of memory\n"); 221462306a36Sopenharmony_ci return -ENOMEM; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL); 221862306a36Sopenharmony_ci if (dev->cmdbuf == NULL) { 221962306a36Sopenharmony_ci s2255_dev_err(&interface->dev, "out of memory\n"); 222062306a36Sopenharmony_ci goto errorFWDATA1; 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci atomic_set(&dev->num_channels, 0); 222462306a36Sopenharmony_ci dev->pid = id->idProduct; 222562306a36Sopenharmony_ci dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); 222662306a36Sopenharmony_ci if (!dev->fw_data) 222762306a36Sopenharmony_ci goto errorFWDATA1; 222862306a36Sopenharmony_ci mutex_init(&dev->lock); 222962306a36Sopenharmony_ci mutex_init(&dev->cmdlock); 223062306a36Sopenharmony_ci /* grab usb_device and save it */ 223162306a36Sopenharmony_ci dev->udev = usb_get_dev(interface_to_usbdev(interface)); 223262306a36Sopenharmony_ci if (dev->udev == NULL) { 223362306a36Sopenharmony_ci dev_err(&interface->dev, "null usb device\n"); 223462306a36Sopenharmony_ci retval = -ENODEV; 223562306a36Sopenharmony_ci goto errorUDEV; 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n", 223862306a36Sopenharmony_ci dev, dev->udev, interface); 223962306a36Sopenharmony_ci dev->interface = interface; 224062306a36Sopenharmony_ci /* set up the endpoint information */ 224162306a36Sopenharmony_ci iface_desc = interface->cur_altsetting; 224262306a36Sopenharmony_ci dev_dbg(&interface->dev, "num EP: %d\n", 224362306a36Sopenharmony_ci iface_desc->desc.bNumEndpoints); 224462306a36Sopenharmony_ci for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 224562306a36Sopenharmony_ci endpoint = &iface_desc->endpoint[i].desc; 224662306a36Sopenharmony_ci if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { 224762306a36Sopenharmony_ci /* we found the bulk in endpoint */ 224862306a36Sopenharmony_ci dev->read_endpoint = endpoint->bEndpointAddress; 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci if (!dev->read_endpoint) { 225362306a36Sopenharmony_ci dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); 225462306a36Sopenharmony_ci goto errorEP; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci timer_setup(&dev->timer, s2255_timer, 0); 225762306a36Sopenharmony_ci init_waitqueue_head(&dev->fw_data->wait_fw); 225862306a36Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) { 225962306a36Sopenharmony_ci struct s2255_vc *vc = &dev->vc[i]; 226062306a36Sopenharmony_ci vc->idx = i; 226162306a36Sopenharmony_ci vc->dev = dev; 226262306a36Sopenharmony_ci init_waitqueue_head(&vc->wait_setmode); 226362306a36Sopenharmony_ci init_waitqueue_head(&vc->wait_vidstatus); 226462306a36Sopenharmony_ci spin_lock_init(&vc->qlock); 226562306a36Sopenharmony_ci mutex_init(&vc->vb_lock); 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); 226962306a36Sopenharmony_ci if (!dev->fw_data->fw_urb) 227062306a36Sopenharmony_ci goto errorFWURB; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); 227362306a36Sopenharmony_ci if (!dev->fw_data->pfw_data) { 227462306a36Sopenharmony_ci dev_err(&interface->dev, "out of memory!\n"); 227562306a36Sopenharmony_ci goto errorFWDATA2; 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci /* load the first chunk */ 227862306a36Sopenharmony_ci if (request_firmware(&dev->fw_data->fw, 227962306a36Sopenharmony_ci FIRMWARE_FILE_NAME, &dev->udev->dev)) { 228062306a36Sopenharmony_ci dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n"); 228162306a36Sopenharmony_ci goto errorREQFW; 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci /* check the firmware is valid */ 228462306a36Sopenharmony_ci fw_size = dev->fw_data->fw->size; 228562306a36Sopenharmony_ci pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci if (*pdata != S2255_FW_MARKER) { 228862306a36Sopenharmony_ci dev_err(&interface->dev, "Firmware invalid.\n"); 228962306a36Sopenharmony_ci retval = -ENODEV; 229062306a36Sopenharmony_ci goto errorFWMARKER; 229162306a36Sopenharmony_ci } else { 229262306a36Sopenharmony_ci /* make sure firmware is the latest */ 229362306a36Sopenharmony_ci __le32 *pRel; 229462306a36Sopenharmony_ci pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; 229562306a36Sopenharmony_ci pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); 229662306a36Sopenharmony_ci dev->dsp_fw_ver = le32_to_cpu(*pRel); 229762306a36Sopenharmony_ci if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) 229862306a36Sopenharmony_ci pr_info("s2255: f2255usb.bin out of date.\n"); 229962306a36Sopenharmony_ci if (dev->pid == 0x2257 && 230062306a36Sopenharmony_ci dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) 230162306a36Sopenharmony_ci pr_warn("2257 needs firmware %d or above.\n", 230262306a36Sopenharmony_ci S2255_MIN_DSP_COLORFILTER); 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci usb_reset_device(dev->udev); 230562306a36Sopenharmony_ci /* load 2255 board specific */ 230662306a36Sopenharmony_ci retval = s2255_board_init(dev); 230762306a36Sopenharmony_ci if (retval) 230862306a36Sopenharmony_ci goto errorBOARDINIT; 230962306a36Sopenharmony_ci s2255_fwload_start(dev); 231062306a36Sopenharmony_ci /* loads v4l specific */ 231162306a36Sopenharmony_ci retval = s2255_probe_v4l(dev); 231262306a36Sopenharmony_ci if (retval) 231362306a36Sopenharmony_ci goto errorBOARDINIT; 231462306a36Sopenharmony_ci dev_info(&interface->dev, "Sensoray 2255 detected\n"); 231562306a36Sopenharmony_ci return 0; 231662306a36Sopenharmony_cierrorBOARDINIT: 231762306a36Sopenharmony_ci s2255_board_shutdown(dev); 231862306a36Sopenharmony_cierrorFWMARKER: 231962306a36Sopenharmony_ci release_firmware(dev->fw_data->fw); 232062306a36Sopenharmony_cierrorREQFW: 232162306a36Sopenharmony_ci kfree(dev->fw_data->pfw_data); 232262306a36Sopenharmony_cierrorFWDATA2: 232362306a36Sopenharmony_ci usb_free_urb(dev->fw_data->fw_urb); 232462306a36Sopenharmony_cierrorFWURB: 232562306a36Sopenharmony_ci timer_shutdown_sync(&dev->timer); 232662306a36Sopenharmony_cierrorEP: 232762306a36Sopenharmony_ci usb_put_dev(dev->udev); 232862306a36Sopenharmony_cierrorUDEV: 232962306a36Sopenharmony_ci kfree(dev->fw_data); 233062306a36Sopenharmony_ci mutex_destroy(&dev->lock); 233162306a36Sopenharmony_cierrorFWDATA1: 233262306a36Sopenharmony_ci kfree(dev->cmdbuf); 233362306a36Sopenharmony_ci kfree(dev); 233462306a36Sopenharmony_ci pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval); 233562306a36Sopenharmony_ci return retval; 233662306a36Sopenharmony_ci} 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci/* disconnect routine. when board is removed physically or with rmmod */ 233962306a36Sopenharmony_cistatic void s2255_disconnect(struct usb_interface *interface) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); 234262306a36Sopenharmony_ci int i; 234362306a36Sopenharmony_ci int channels = atomic_read(&dev->num_channels); 234462306a36Sopenharmony_ci mutex_lock(&dev->lock); 234562306a36Sopenharmony_ci v4l2_device_disconnect(&dev->v4l2_dev); 234662306a36Sopenharmony_ci mutex_unlock(&dev->lock); 234762306a36Sopenharmony_ci /*see comments in the uvc_driver.c usb disconnect function */ 234862306a36Sopenharmony_ci atomic_inc(&dev->num_channels); 234962306a36Sopenharmony_ci /* unregister each video device. */ 235062306a36Sopenharmony_ci for (i = 0; i < channels; i++) 235162306a36Sopenharmony_ci video_unregister_device(&dev->vc[i].vdev); 235262306a36Sopenharmony_ci /* wake up any of our timers */ 235362306a36Sopenharmony_ci atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); 235462306a36Sopenharmony_ci wake_up(&dev->fw_data->wait_fw); 235562306a36Sopenharmony_ci for (i = 0; i < MAX_CHANNELS; i++) { 235662306a36Sopenharmony_ci dev->vc[i].setmode_ready = 1; 235762306a36Sopenharmony_ci wake_up(&dev->vc[i].wait_setmode); 235862306a36Sopenharmony_ci dev->vc[i].vidstatus_ready = 1; 235962306a36Sopenharmony_ci wake_up(&dev->vc[i].wait_vidstatus); 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci if (atomic_dec_and_test(&dev->num_channels)) 236262306a36Sopenharmony_ci s2255_destroy(dev); 236362306a36Sopenharmony_ci dev_info(&interface->dev, "%s\n", __func__); 236462306a36Sopenharmony_ci} 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_cistatic struct usb_driver s2255_driver = { 236762306a36Sopenharmony_ci .name = S2255_DRIVER_NAME, 236862306a36Sopenharmony_ci .probe = s2255_probe, 236962306a36Sopenharmony_ci .disconnect = s2255_disconnect, 237062306a36Sopenharmony_ci .id_table = s2255_table, 237162306a36Sopenharmony_ci}; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_cimodule_usb_driver(s2255_driver); 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ciMODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); 237662306a36Sopenharmony_ciMODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)"); 237762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 237862306a36Sopenharmony_ciMODULE_VERSION(S2255_VERSION); 237962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_FILE_NAME); 2380