diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-21 12:25:51 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-21 12:25:51 -0800 |
| commit | 61837aa7b275148a00752dea585c940b0326d101 (patch) | |
| tree | b490fcbad586bfca8dce3a0ddaf1f67c88284eab /usb | |
| parent | 441cac6a419fe351440200bed8b7f7f8805096d2 (diff) | |
| download | patches-61837aa7b275148a00752dea585c940b0326d101.tar.gz | |
usb sensoray driver update
Diffstat (limited to 'usb')
| -rw-r--r-- | usb/usb-add-sensoray-2255-v4l-driver.patch | 2203 |
1 files changed, 1054 insertions, 1149 deletions
diff --git a/usb/usb-add-sensoray-2255-v4l-driver.patch b/usb/usb-add-sensoray-2255-v4l-driver.patch index 8fdc8fe06a392c..a63ac132ad8f44 100644 --- a/usb/usb-add-sensoray-2255-v4l-driver.patch +++ b/usb/usb-add-sensoray-2255-v4l-driver.patch @@ -15,36 +15,13 @@ Cc: Dean Anderson <dean@sensoray.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- + +--- drivers/usb/image/Kconfig | 9 drivers/usb/image/Makefile | 1 drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/Kconfig | 9 - drivers/usb/image/Makefile | 1 - drivers/usb/image/f2255usb.h |40334 +++++++++++++++++++++++++++++++++++++++++++ - drivers/usb/image/s2255drv.c | 2638 ++ - drivers/usb/image/s2255drv.h | 235 - 5 files changed, 43217 insertions(+) + drivers/usb/image/s2255drv.c | 2804 ++ + 4 files changed, 43148 insertions(+) --- a/drivers/usb/image/Kconfig +++ b/drivers/usb/image/Kconfig @@ -40407,7 +40384,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +}; --- /dev/null +++ b/drivers/usb/image/s2255drv.c -@@ -0,0 +1,2638 @@ +@@ -0,0 +1,2804 @@ +/* + * Sensoray 2255 USB Video for Linux driver + * @@ -40453,11 +40430,6 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +#include <linux/mutex.h> +#include <linux/videodev2.h> +#include <linux/dma-mapping.h> -+#ifdef CONFIG_VIDEO_V4L1_COMPAT -+/* Include V4L1 specific functions. Should be removed soon */ -+#include <linux/videodev.h> -+#endif -+#include <linux/proc_fs.h> +#include <linux/interrupt.h> +#include <media/videobuf-vmalloc.h> +#include <media/v4l2-common.h> @@ -40466,11 +40438,235 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +#include <linux/freezer.h> +#include <linux/vmalloc.h> +#include <linux/usb.h> -+#include "s2255drv.h" ++ ++#ifdef CONFIG_VIDEO_V4L1_COMPAT ++/* Include V4L1 specific functions. Should be removed soon */ ++#include <linux/videodev.h> ++#endif ++ +#include "f2255usb.h" /* firmware in header file */ + ++ ++#define DIR_IN 0 ++#define DIR_OUT 1 ++ ++/* firmware query */ ++#define VX_FW 0x30 ++ ++#define MAX_CHANNELS 4 ++#define FRAME_MARKER 0x2255DA4AL ++#define MAX_PIPE_USBBLOCK (40*1024) ++#define DEFAULT_PIPE_USBBLOCK (16*1024) ++#define MAX_CHANNELS 4 ++#define MAX_PIPE_BUFFERS 1 ++#define SYS_FRAMES 4 ++/* maximum size is PAL full size plus room for the marker header(s) */ ++#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) ++#define DEF_USB_BLOCK (4096) ++#define LINE_SZ_4CIFS_NTSC 640 ++#define LINE_SZ_2CIFS_NTSC 640 ++#define LINE_SZ_1CIFS_NTSC 320 ++#define LINE_SZ_4CIFS_PAL 704 ++#define LINE_SZ_2CIFS_PAL 704 ++#define LINE_SZ_1CIFS_PAL 352 ++#define NUM_LINES_4CIFS_NTSC 240 ++#define NUM_LINES_2CIFS_NTSC 240 ++#define NUM_LINES_1CIFS_NTSC 240 ++#define NUM_LINES_4CIFS_PAL 288 ++#define NUM_LINES_2CIFS_PAL 288 ++#define NUM_LINES_1CIFS_PAL 288 ++#define LINE_SZ_DEF 640 ++#define NUM_LINES_DEF 240 ++ ++ ++/* predefined settings */ ++#define FORMAT_NTSC 1 ++#define FORMAT_PAL 2 ++ ++#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ ++#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ ++#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ ++ ++#define COLOR_YUVPL 1 /* YUV planar */ ++#define COLOR_YUVPK 2 /* YUV packed */ ++#define COLOR_RGB 3 /* RGB */ ++#define COLOR_Y8 4 /* monochrome */ ++ ++/* frame decimation. Not implemented by V4L yet(experimental in V4L) */ ++#define FDEC_1 1 /* capture every frame. default */ ++#define FDEC_2 2 /* capture every 2nd frame */ ++#define FDEC_3 3 /* capture every 3rd frame */ ++#define FDEC_5 5 /* capture every 5th frame */ ++ ++/*------------------------------------------------------- ++ * Default mode parameters. ++ *-------------------------------------------------------*/ ++#define DEF_SCALE SCALE_4CIFS ++#define DEF_COLOR COLOR_YUVPL ++#define DEF_FDEC FDEC_1 ++#define DEF_BRIGHT 0 ++#define DEF_CONTRAST 0x5c ++#define DEF_SATURATION 0x80 ++#define DEF_HUE 0 ++ ++/* usb config commands */ ++#define IN_DATA_TOKEN 0x2255c0de ++#define CMD_2255 0xc2255000 ++#define CMD_SET_MODE (CMD_2255 | 0x10) ++#define CMD_START (CMD_2255 | 0x20) ++#define CMD_STOP (CMD_2255 | 0x30) ++#define CMD_STATUS (CMD_2255 | 0x40) ++ ++struct mode2255i { ++ u32 format; /* input video format (NTSC, PAL) */ ++ u32 scale; /* output video scale */ ++ u32 color; /* output video color format */ ++ u32 fdec; /* frame decimation */ ++ u32 bright; /* brightness */ ++ u32 contrast; /* contrast */ ++ u32 saturation; /* saturation */ ++ u32 hue; /* hue (NTSC only)*/ ++ u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ ++ u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ ++ u32 restart; /* if DSP requires restart */ ++}; ++ ++/* frame structure */ ++#define FRAME_STATE_UNUSED 0 ++#define FRAME_STATE_FILLING 1 ++#define FRAME_STATE_FULL 2 ++ ++ ++struct framei { ++ unsigned long size; ++ ++ unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */ ++ void *lpvbits; /* image data */ ++ unsigned long cur_size; /* current data copied to it */ ++}; ++ ++/* image buffer structure */ ++struct bufferi { ++ unsigned long dwFrames; /* number of frames in buffer */ ++ struct framei frame[SYS_FRAMES]; /* array of FRAME structures */ ++}; ++ ++#define DEF_MODEI_NTSC_CONT FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ ++ DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ ++ DEF_HUE, 0, DEF_USB_BLOCK, 0 ++ ++#define DEF_MODEI_PAL_CONT FORMAT_PAL, DEF_SCALE, DEF_COLOR, DEF_FDEC,\ ++ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 0, \ ++ DEF_USB_BLOCK, 0 ++ ++#define DEF_MODEI_NTSC_SING FORMAT_NTSC, DEF_SCALE, DEF_COLOR, DEF_FDEC,\ ++ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 1,\ ++ DEF_USB_BLOCK, 0 ++ ++#define DEF_MODEI_PAL_SING FORMAT_PAL, DEF_SCALE, DEF_COLOR, DEF_FDEC, \ ++ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 1,\ ++ DEF_USB_BLOCK, 0 ++ ++struct s2255_dmaqueue { ++ struct list_head active; ++ struct list_head queued; ++ struct timer_list timeout; ++ /* thread for acquisition */ ++ struct task_struct *kthread; ++ wait_queue_head_t wq; ++ int frame; ++ struct s2255_dev *dev; ++ int channel; ++}; ++ ++/* for firmware loading */ ++#define FWSTATE_NOTLOADED 0 ++#define FWSTATE_SUCCESS 1 ++#define FWSTATE_FAILED 2 ++ ++struct complete_data { ++ int fw_loaded; ++ int fw_size; ++ struct urb *fw_urb; ++ int fw_state; ++ void *pfw_data; ++}; ++ ++struct s2255_pipeinfo { ++ u32 max_transfer_size; ++ u32 cur_transfer_size; ++ u8 *transfer_buffer; ++ u32 transfer_flags;; ++ u32 state; ++ u32 prev_state; ++ u32 urb_size; ++ void *stream_urb; ++ void *dev; /* back pointer to s2255_dev struct*/ ++ u32 err_count; ++ u32 buf_index; ++ u32 idx; ++ u32 priority_set; ++}; ++ ++struct s2255_dev { ++ int frames; ++ int users[MAX_CHANNELS]; ++ struct mutex lock; ++ int resources[MAX_CHANNELS]; ++ struct usb_device *udev; ++ struct usb_interface *interface; ++ u8 read_endpoint; ++ struct semaphore sem_frms[MAX_CHANNELS]; /* frames ready */ ++ struct s2255_dmaqueue vidq[MAX_CHANNELS]; ++ struct video_device *vdev[MAX_CHANNELS]; ++ struct list_head s2255_devlist; ++ struct timer_list timer; ++ struct complete_data *fw_data; ++ int board_num; ++ int is_open; ++ struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; ++ struct bufferi buffer[MAX_CHANNELS]; ++ struct mode2255i mode[MAX_CHANNELS]; ++ int cur_frame[MAX_CHANNELS]; ++ int last_frame[MAX_CHANNELS]; ++ u32 cc; /* current channel */ ++ int b_acquire[MAX_CHANNELS]; ++ unsigned long req_image_size[MAX_CHANNELS]; ++ int bad_payload[MAX_CHANNELS]; ++ unsigned long frame_count[MAX_CHANNELS]; ++ int frame_ready; ++ struct kref kref; ++}; ++#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref) ++ ++struct s2255_fmt { ++ char *name; ++ u32 fourcc; ++ int depth; ++}; ++ ++/* buffer for one video frame */ ++struct s2255_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct videobuf_buffer vb; ++ const struct s2255_fmt *fmt; ++ /* future use */ ++ int reserved[32]; ++}; ++ ++struct s2255_fh { ++ struct s2255_dev *dev; ++ unsigned int resources; ++ const struct s2255_fmt *fmt; ++ unsigned int width; ++ unsigned int height; ++ struct videobuf_queue vb_vidq; ++ enum v4l2_buf_type type; ++ int channel; ++}; ++ ++ +#define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ -+static char MODULE_REVISION[] = "Ver.1.0.1"; +#define S2255_MAJOR_VERSION 1 +#define S2255_MINOR_VERSION 1 +#define S2255_RELEASE 0 @@ -40491,46 +40687,25 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +static LIST_HEAD(s2255_devlist); + -+static int s2255_probe_v4l(struct s2255_dev *dev); -+static void s2255_exit_v4l(struct s2255_dev *dev); -+static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pPipeInfo); -+ -+static int s2255_wait_frame_block(struct s2255_dev *dev, int chn); -+static int s2255_wait_frame_noblock(struct s2255_dev *dev, int chn); ++static int debug; ++static int *s2255_debug = &debug; + -+static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, -+ int size); +static int s2255_start_readpipe(struct s2255_dev *dev); +static void s2255_stop_readpipe(struct s2255_dev *dev); -+static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn); -+static int s2255_release_sys_buffers(struct s2255_dev *dev, unsigned long chn); -+static int s2255_board_init(struct s2255_dev *dev); -+static int s2255_board_shutdown(struct s2255_dev *dev); -+ -+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, -+ u16 index, -+ u16 val, void *buffer, s32 buf_len, int bOut); -+static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, -+ struct mode2255i *mode); -+ +static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn); +static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn); -+static int restart_video_queue(struct s2255_dmaqueue *dma_q); -+static void s2255_sleep(int ms); -+static void planar422p_to_yuy2(const unsigned char *in, unsigned char *out, -+ int width, int height); + -+static void planar422p_to_rgb32(const unsigned char *in, unsigned char *out, -+ int width, int height, int rev_order); -+static void planar422p_to_rgb24(const unsigned char *in, unsigned char *out, -+ int width, int height, int rev_order); -+static void planar422p_to_rgb565(unsigned char const *in, unsigned char *out, -+ int width, int height, int rev_order); -+static u32 get_transfer_size(struct mode2255i *mode); -+static int s2255_get_fx2fw(struct s2255_dev *dev); ++#define dprintk(level, fmt, arg...) \ ++ do { \ ++ if (*s2255_debug >= (level)) { \ ++ printk(KERN_DEBUG "s2255: " fmt, ##arg); \ ++ } \ ++ } while (0) ++ ++ ++static DEFINE_MUTEX(usb_s2255_open_mutex); ++static struct usb_driver s2255_driver; + -+static int debug; -+static int *s2255_debug = &debug; +/* Declare static vars that will be used as parameters */ +static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ + @@ -40544,13 +40719,119 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); + -+/* device table */ ++/* USB device table */ +static struct usb_device_id s2255_table[] = { + {USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)}, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, s2255_table); + ++/* buffer timeout. Do not make this smaller than ++ 300ms. The long timeout is required because the hardware ++ internally restartswhen a new video source is plugged in. ++ */ ++#define BUFFER_TIMEOUT msecs_to_jiffies(300) ++/* initial startup timeout*/ ++#define BUFFER_TIMEOUT_INIT msecs_to_jiffies(900) ++ ++/* supported controls */ ++static struct v4l2_queryctrl s2255_qctrl[] = { ++ { ++ .id = V4L2_CID_BRIGHTNESS, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Brightness", ++ .minimum = -127, ++ .maximum = 128, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, ++ { ++ .id = V4L2_CID_CONTRAST, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Contrast", ++ .minimum = 0, ++ .maximum = 255, ++ .step = 0x1, ++ .default_value = DEF_CONTRAST, ++ .flags = 0, ++ }, ++ { ++ .id = V4L2_CID_SATURATION, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Saturation", ++ .minimum = 0, ++ .maximum = 255, ++ .step = 0x1, ++ .default_value = DEF_SATURATION, ++ .flags = 0, ++ }, ++ { ++ .id = V4L2_CID_HUE, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Hue", ++ .minimum = 0, ++ .maximum = 255, ++ .step = 0x1, ++ .default_value = DEF_HUE, ++ .flags = 0, ++ } ++}; ++ ++static int qctl_regs[ARRAY_SIZE(s2255_qctrl)]; ++ ++/* image formats. Note RGB formats are software converted. ++ * because the 2255 transfers in YUV for maximum USB efficiency ++ * in order to allow 2 full size color channels at full frame rate ++ */ ++static const struct s2255_fmt formats[] = { ++ { ++ .name = "4:2:2, planar, YUV422P", ++ .fourcc = V4L2_PIX_FMT_YUV422P, ++ .depth = 16 ++ }, ++ { ++ .name = "4:2:2, packed, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16 ++ }, ++ { ++ .name = "BGR24", ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .depth = 24 ++ }, ++ { ++ .name = "RGB24", ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .depth = 24 ++ }, ++ { ++ .name = "BGR32", ++ .fourcc = V4L2_PIX_FMT_BGR32, ++ .depth = 32 ++ }, ++ { ++ .name = "RGB24", ++ .fourcc = V4L2_PIX_FMT_RGB32, ++ .depth = 32 ++ }, ++ { ++ .name = "RGB565", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16 ++ }, ++ { ++ .name = "RGB565 big endian", ++ .fourcc = V4L2_PIX_FMT_RGB565X, ++ .depth = 16 ++ }, ++ { ++ .name = "8bpp GREY", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = 8 ++ }, ++}; ++ +static int norm_maxw(struct video_device *vdev) +{ + return (vdev->current_norm != V4L2_STD_PAL_B) ? @@ -40575,17 +40856,185 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); +} + -+#define dprintk(level, fmt, arg...) \ -+ do { \ -+ if (*s2255_debug >= (level)) { \ -+ printk(KERN_DEBUG "s2255: " fmt, ##arg); \ -+ } \ -+ } while (0) ++/* ++ * convert from YUV(YCrCb) to RGB ++ * 65536 R = 76533(Y-16) + 104936 * (Cr-128) ++ * 65536 G = 76533(Y-16) - 53451(Cr-128) - 25703(Cb -128) ++ * 65536 B = 76533(Y-16) + 132677(Cb-128) ++ */ ++static void YCrCb2RGB(int Y, int Cr, int Cb, unsigned char *pR, ++ unsigned char *pG, unsigned char *pB) ++{ ++ int R, G, B; + -+#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref) ++ Y = Y - 16; ++ Cr = Cr - 128; ++ Cb = Cb - 128; + -+static DEFINE_MUTEX(usb_s2255_open_mutex); -+static struct usb_driver s2255_driver; ++ R = (76533 * Y + 104936 * Cr) >> 16; ++ G = ((76533 * Y) - (53451 * Cr) - (25703 * Cb)) >> 16; ++ B = ((76533 * Y) + (132677 * Cb)) >> 16; ++ /* even with proper conversion, some values still need clipping. */ ++ if (R > 255) ++ R = 255; ++ if (G > 255) ++ G = 255; ++ if (B > 255) ++ B = 255; ++ if (R < 0) ++ R = 0; ++ if (G < 0) ++ G = 0; ++ if (B < 0) ++ B = 0; ++ *pR = R; ++ *pG = G; ++ *pB = B; ++ return; ++} ++ ++/* converts 2255 planar format to yuyv */ ++static void planar422p_to_yuy2(const unsigned char *in, unsigned char *out, ++ int width, int height) ++{ ++ unsigned char *pY; ++ unsigned char *pCb; ++ unsigned char *pCr; ++ unsigned long size = height * width; ++ unsigned int i; ++ pY = (unsigned char *)in; ++ pCr = (unsigned char *)in + height * width; ++ pCb = (unsigned char *)in + height * width + (height * width / 2); ++ for (i = 0; i < size * 2; i += 4) { ++ out[i] = *pY++; ++ out[i + 1] = *pCr++; ++ out[i + 2] = *pY++; ++ out[i + 3] = *pCb++; ++ } ++ return; ++} ++ ++/* ++ * basic 422 planar to RGB24 or BGR24 software conversion. ++ * This is best done with MMX. Update to kernel function ++ * when image conversion functions added to kernel. ++ */ ++static void planar422p_to_rgb24(const unsigned char *in, ++ unsigned char *out, int width, ++ int height, int rev_order) ++{ ++ unsigned char *pY; ++ unsigned char *pYEND; ++ unsigned char *pCb; ++ unsigned char *pCr; ++ unsigned char Cr, Cb, Y, r, g, b; ++ unsigned long k = 0; ++ pY = (unsigned char *)in; ++ pCb = (unsigned char *)in + (height * width); ++ pCr = (unsigned char *)in + (height * width) + (height * width / 2); ++ pYEND = pCb; ++ while (pY < pYEND) { ++ Y = *pY++; ++ Cr = *pCr; ++ Cb = *pCb; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ out[k++] = !rev_order ? b : r; ++ out[k++] = g; ++ out[k++] = !rev_order ? r : b; ++ if (pY >= pYEND) ++ break; ++ Y = *pY++; ++ Cr = *pCr++; ++ Cb = *pCb++; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ out[k++] = !rev_order ? b : r; ++ out[k++] = g; ++ out[k++] = !rev_order ? r : b; ++ } ++ return; ++} ++ ++static void planar422p_to_rgb32(const unsigned char *in, unsigned char *out, ++ int width, int height, int rev_order) ++{ ++ unsigned char *pY; ++ unsigned char *pYEND; ++ unsigned char *pCb; ++ unsigned char *pCr; ++ unsigned char Cr, Cb, Y, r, g, b; ++ unsigned long k = 0; ++ pY = (unsigned char *)in; ++ pCb = (unsigned char *)in + (height * width); ++ pCr = (unsigned char *)in + (height * width) + (height * width / 2); ++ pYEND = pCb; ++ while (pY < pYEND) { ++ Y = *pY++; ++ Cr = *pCr; ++ Cb = *pCb; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ out[k++] = rev_order ? b : r; ++ out[k++] = g; ++ out[k++] = rev_order ? r : b; ++ out[k++] = 0; ++ if (pY >= pYEND) ++ break; ++ Y = *pY++; ++ Cr = *pCr++; ++ Cb = *pCb++; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ out[k++] = rev_order ? b : r; ++ out[k++] = g; ++ out[k++] = rev_order ? r : b; ++ out[k++] = 0; ++ } ++ ++ return; ++} ++ ++static void planar422p_to_rgb565(unsigned char const *in, unsigned char *out, ++ int width, int height, int rev_order) ++{ ++ unsigned char *pY; ++ unsigned char *pYEND; ++ unsigned char *pCb; ++ unsigned char *pCr; ++ unsigned char Cr, Cb, Y, r, g, b; ++ unsigned long k = 0; ++ unsigned short rgbbytes; ++ pY = (unsigned char *)in; ++ pCb = (unsigned char *)in + (height * width); ++ pCr = (unsigned char *)in + (height * width) + (height * width / 2); ++ pYEND = pCb; ++ while (pY < pYEND) { ++ Y = *pY++; ++ Cr = *pCr; ++ Cb = *pCb; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ r = r >> 3; ++ g = g >> 2; ++ b = b >> 3; ++ if (rev_order) ++ rgbbytes = b + (g << 5) + (r << (5 + 6)); ++ else ++ rgbbytes = r + (g << 5) + (b << (5 + 6)); ++ out[k++] = rgbbytes & 0xff; ++ out[k++] = (rgbbytes >> 8) & 0xff; ++ Y = *pY++; ++ Cr = *pCr++; ++ Cb = *pCb++; ++ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); ++ r = r >> 3; ++ g = g >> 2; ++ b = b >> 3; ++ if (rev_order) ++ rgbbytes = b + (g << 5) + (r << (5 + 6)); ++ else ++ rgbbytes = r + (g << 5) + (b << (5 + 6)); ++ out[k++] = rgbbytes & 0xff; ++ out[k++] = (rgbbytes >> 8) & 0xff; ++ } ++ return; ++} + +/* kickstarts the firmware loading. from probe + */ @@ -40612,11 +41061,11 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + int len; + dprintk(100, "udev %p urb %p", udev, urb); + if (urb->status) { -+ printk("URB failed with status %d", urb->status); ++ dev_err(&udev->dev, "URB failed with status %d", urb->status); + return; + } + if (data->fw_urb == NULL) { -+ printk("early disconncect\n"); ++ dev_err(&udev->dev, "early disconncect\n"); + return; + } +#define CHUNK_SIZE 512 @@ -40636,14 +41085,14 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + s2255_fwchunk_complete, data); + + if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { -+ printk("failed submit URB\n"); ++ dev_err(&udev->dev, "failed submit URB\n"); + data->fw_state = FWSTATE_FAILED; + return; + } + data->fw_loaded += len; + } else { + data->fw_state = FWSTATE_SUCCESS; -+ printk(KERN_INFO "2255 firmware loaded successfully\n"); ++ dev_info(&udev->dev, "firmware loaded successfully\n"); + } + + dprintk(100, "2255 complete done\n"); @@ -40651,194 +41100,6 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +} + -+/* standard usb probe function */ -+static int s2255_probe -+ (struct usb_interface *interface, const struct usb_device_id *id) { -+ struct s2255_dev *dev = NULL; -+ struct usb_host_interface *iface_desc; -+ struct usb_endpoint_descriptor *endpoint; -+ int i; -+ int retval = -ENOMEM; -+ printk(KERN_INFO "s2255: probe\n"); -+ /* allocate memory for our device state and initialize it to zero */ -+ dev = (struct s2255_dev *)kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); -+ -+ if (dev == NULL) { -+ err("s2255: out of memory"); -+ goto error; -+ } -+ -+ /* grab usb_device and save it */ -+ dev->udev = usb_get_dev(interface_to_usbdev(interface)); -+ if (dev->udev == NULL) { -+ printk("null usb device\n"); -+ goto error; -+ } -+ -+ kref_init(&dev->kref); -+ dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref, -+ dev->udev, interface); -+ dev->interface = interface; -+ /* set up the endpoint information */ -+ iface_desc = interface->cur_altsetting; -+ printk("num endpoints %d\n", iface_desc->desc.bNumEndpoints); -+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { -+ endpoint = &iface_desc->endpoint[i].desc; -+ if (!dev->read_endpoint && -+ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_IN) && -+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK)) { -+ /* we found the bulk in endpoint */ -+ dev->read_endpoint = endpoint->bEndpointAddress; -+ } -+ } -+ -+ if (!dev->read_endpoint) { -+ err("Could not find both bulk-in endpoint"); -+ goto error; -+ } -+ -+ /* set intfdata */ -+ usb_set_intfdata(interface, dev); -+ -+ dprintk(100, "after intfdata %p\n", dev); -+ -+ /* initialize COUNTING semaphores */ -+ for (i = 0; i < MAX_CHANNELS; i++) { -+ sema_init(&dev->sem_frms[i], 0); -+ } -+ -+ /* initialize device mutex */ -+ mutex_init(&dev->lock); -+ -+ init_timer(&dev->timer); -+ dev->timer.function = s2255_timer; -+ dev->fw_data = kzalloc(sizeof(struct complete_data), GFP_KERNEL); -+ if (!dev->fw_data) { -+ goto error; -+ } -+ -+ dev->timer.data = (unsigned long)dev->fw_data; -+ -+ dev->fw_data->fw_size = sizeof(G_f2255usb) / sizeof(unsigned char); -+ dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); -+ -+ if (!dev->fw_data->fw_urb) { -+ printk("out of memory!\n"); -+ goto error; -+ } -+ dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); -+ if (!dev->fw_data->pfw_data) { -+ printk("out of mem\n"); -+ goto error; -+ } -+ -+ /* load the first chunk */ -+ memcpy(dev->fw_data->pfw_data, G_f2255usb, CHUNK_SIZE); -+ dev->fw_data->fw_loaded = CHUNK_SIZE; -+ usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, -+ usb_sndbulkpipe(dev->udev, 2), dev->fw_data->pfw_data, -+ CHUNK_SIZE, s2255_fwchunk_complete, dev->fw_data); -+ /* loads v4l specific */ -+ s2255_probe_v4l(dev); -+ /* load 2255 board specific */ -+ s2255_board_init(dev); -+ -+ printk("Sensoray 2255 successfully loaded\n"); -+ dprintk(4, "before probe done %p\n", dev); -+ -+ mod_timer(&dev->timer, jiffies + HZ); -+ -+ kref_get(&dev->kref); -+ return 0; -+error: -+ return retval; -+} -+ -+static void s2255_destroy(struct kref *kref) -+{ -+ struct s2255_dev *dev = to_s2255_dev(kref); -+ -+ usb_put_dev(dev->udev); -+ dprintk(1, "s2255_destroy\n"); -+ kfree(dev); -+} -+ -+/* disconnect routine. when board is removed physically or with rmmod */ -+static void s2255_disconnect(struct usb_interface *interface) -+{ -+ struct s2255_dev *dev = NULL; -+ -+ /* lock to prevent s2255_open() from racing s2255_disconnect() */ -+ mutex_lock(&usb_s2255_open_mutex); -+ printk(KERN_INFO "s2255: disconnect interface %p\n", interface); -+ dev = usb_get_intfdata(interface); -+ s2255_board_shutdown(dev); -+ if (dev->fw_data->fw_urb) { -+ dprintk(2, "kill URB\n"); -+ usb_kill_urb(dev->fw_data->fw_urb); -+ usb_free_urb(dev->fw_data->fw_urb); -+ -+ } -+ s2255_exit_v4l(dev); -+ if (dev->fw_data) { -+ if (dev->fw_data->pfw_data) -+ kfree(dev->fw_data->pfw_data); -+ kfree(dev->fw_data); -+ } -+ usb_set_intfdata(interface, NULL); -+ kref_put(&dev->kref, s2255_destroy); -+ mutex_unlock(&usb_s2255_open_mutex); -+ info("s2255usb now disconnected\n"); -+} -+ -+/* Generate proc info. -+ */ -+static int s2255_read_procmem(char *buf, char **start, off_t offset, int count, -+ int *eof, void *data) -+{ -+ int len = 0; -+ /* Generate report heading. */ -+ len += sprintf(buf + len, "Sensoray 2255 drvr, version %s\n", -+ MODULE_REVISION); -+ -+ len += sprintf(buf + len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static struct usb_driver s2255_driver = { -+ .name = "s2255", -+ .probe = s2255_probe, -+ .disconnect = s2255_disconnect, -+ .id_table = s2255_table, -+}; -+ -+static int __init usb_s2255_init(void) -+{ -+ int result; -+ -+ /* Make public the function that supplies "proc" info to the system. -+ */ -+ create_proc_read_entry("s2255", 0, NULL, s2255_read_procmem, NULL); -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&s2255_driver); -+ -+ if (result) -+ err("usb_register failed. Error number %d", result); -+ -+ dprintk(2, "s2255_init: done\n"); -+ return result; -+} -+ -+static void __exit usb_s2255_exit(void) -+{ -+ usb_deregister(&s2255_driver); -+} -+ +static int s2255_got_frame(struct s2255_dev *dev, int chn) +{ + dprintk(2, "wakeup: %p channel: %d\n", &dev->sem_frms[chn], chn); @@ -40848,13 +41109,13 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +static int s2255_wait_frame_noblock(struct s2255_dev *dev, int chn) +{ -+ if (dev == NULL) { -+ return -1; -+ } ++ if (dev == NULL) ++ return -EINVAL; ++ + dprintk(2, "wait frame: %p channel: %d\n", &dev->sem_frms[chn], chn); + if (down_trylock(&dev->sem_frms[chn])) { + dprintk(4, "wait_event: would block\n"); -+ return -1; ++ return -EINVAL; + } + + return 0; @@ -40863,109 +41124,16 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +static int s2255_wait_frame_block(struct s2255_dev *dev, int chn) +{ + int res; -+ if (dev == NULL) { -+ return -1; -+ } ++ ++ if (dev == NULL) ++ return -EINVAL; ++ + dprintk(2, "wait frame: %p channel: %d\n", &dev->sem_frms[chn], chn); + res = down_interruptible(&dev->sem_frms[chn]); + + return res; +} + -+/* buffer timeout. Do not make this smaller than -+ 300ms. The long timeout is required because the hardware -+ internally restartswhen a new video source is plugged in. -+ */ -+#define BUFFER_TIMEOUT msecs_to_jiffies(300) -+/* initial startup timeout*/ -+#define BUFFER_TIMEOUT_INIT msecs_to_jiffies(900) -+ -+/* supported controls */ -+static struct v4l2_queryctrl s2255_qctrl[] = { -+ { -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .minimum = -127, -+ .maximum = 128, -+ .step = 1, -+ .default_value = 0, -+ .flags = 0, -+ }, { -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .minimum = 0, -+ .maximum = 255, -+ .step = 0x1, -+ .default_value = DEF_CONTRAST, -+ .flags = 0, -+ }, { -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .minimum = 0, -+ .maximum = 255, -+ .step = 0x1, -+ .default_value = DEF_SATURATION, -+ .flags = 0, -+ }, { -+ .id = V4L2_CID_HUE, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Hue", -+ .minimum = 0, -+ .maximum = 255, -+ .step = 0x1, -+ .default_value = DEF_HUE, -+ .flags = 0, -+ } -+}; -+ -+static int qctl_regs[ARRAY_SIZE(s2255_qctrl)]; -+ -+/* image formats. Note RGB formats are software converted. -+ * because the 2255 transfers in YUV for maximum USB efficiency -+ * in order to allow 2 full size color channels at full frame rate -+ */ -+static const struct s2255_fmt formats[] = { -+ { -+ .name = "4:2:2, planar, YUV422P", -+ .fourcc = V4L2_PIX_FMT_YUV422P, -+ .depth = 16}, -+ { -+ .name = "4:2:2, packed, YUYV", -+ .fourcc = V4L2_PIX_FMT_YUYV, -+ .depth = 16}, -+ { -+ .name = "BGR24", -+ .fourcc = V4L2_PIX_FMT_BGR24, -+ .depth = 24}, -+ { -+ .name = "RGB24", -+ .fourcc = V4L2_PIX_FMT_RGB24, -+ .depth = 24}, -+ { -+ .name = "BGR32", -+ .fourcc = V4L2_PIX_FMT_BGR32, -+ .depth = 32}, -+ { -+ .name = "RGB24", -+ .fourcc = V4L2_PIX_FMT_RGB32, -+ .depth = 32}, -+ { -+ .name = "RGB565", -+ .fourcc = V4L2_PIX_FMT_RGB565, -+ .depth = 16}, -+ { -+ .name = "RGB565 big endian", -+ .fourcc = V4L2_PIX_FMT_RGB565X, -+ .depth = 16}, -+ { -+ .name = "8bpp GREY", -+ .fourcc = V4L2_PIX_FMT_GREY, -+ .depth = 8}, -+}; -+ +static const struct s2255_fmt *format_by_fourcc(int fourcc) +{ + unsigned int i; @@ -41064,9 +41232,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + when acquisition restarted. + */ + tmp = s2255_wait_frame_noblock(dev, chn); -+ while (tmp == 0) { ++ while (tmp == 0) + tmp = s2255_wait_frame_noblock(dev, chn); -+ } + + /* initialize the states */ + dev->b_acquire[chn] = 1; @@ -41096,18 +41263,16 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + if (!waitqueue_active(&buf->vb.done)) { + /* no one active */ + mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); -+ if (kthread_should_stop()) { ++ if (kthread_should_stop()) + break; -+ } + continue; + } + do_gettimeofday(&buf->vb.ts); + dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i); + s2255_fillbuff(dev, buf, dma_q->channel); + mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); -+ if (kthread_should_stop()) { ++ if (kthread_should_stop()) + break; -+ } + dprintk(3, "thread tick \n"); + } + dprintk(1, "thread: exit %d\n", dma_q->channel); @@ -41120,7 +41285,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +static int s2255_start_thread(struct s2255_dmaqueue *dma_q) +{ + dma_q->frame = 0; -+ dprintk(1, "%s[%d]\n", __FUNCTION__, dma_q->channel); ++ dprintk(1, "%s[%d]\n", __func__, dma_q->channel); + dma_q->kthread = kthread_run(s2255_thread, dma_q, "s2255"); + if (IS_ERR(dma_q->kthread)) { + printk(KERN_ERR "s2255: kernel_thread() failed\n"); @@ -41129,13 +41294,13 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + /* Wakes thread */ + wake_up_interruptible(&dma_q->wq); + -+ dprintk(1, "returning from %s\n", __FUNCTION__); ++ dprintk(1, "returning from %s\n", __func__); + return 0; +} + +static void s2255_stop_thread(struct s2255_dmaqueue *dma_q) +{ -+ dprintk(1, "%s[%d]\n", __FUNCTION__, dma_q->channel); ++ dprintk(1, "%s[%d]\n", __func__, dma_q->channel); + /* unblock the kthread */ + dprintk(1, "stop thread channel %d\n", dma_q->channel); + /* wakeup the thread in case it's waiting */ @@ -41146,7 +41311,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + dma_q->kthread = NULL; + } + -+ dprintk(1, "%s exiting\n", __FUNCTION__); ++ dprintk(1, "%s exiting\n", __func__); + return; +} + @@ -41155,7 +41320,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + struct s2255_buffer *buf, *prev; + struct list_head *item; + -+ dprintk(1, "%s dma_q=0x%08lx chan %d\n", __FUNCTION__, ++ dprintk(1, "%s dma_q=0x%08lx chan %d\n", __func__, + (unsigned long)dma_q, dma_q->channel); + + if (!list_empty(&dma_q->active)) { @@ -41242,16 +41407,15 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ -+static int -+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) ++static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, ++ unsigned int *size) +{ + struct s2255_fh *fh = vq->priv_data; + + *size = fh->width * fh->height * (fh->fmt->depth >> 3); + -+ if (0 == *count) { ++ if (0 == *count) + *count = 32; -+ } + + while (*size * *count > vid_limit * 1024 * 1024) + (*count)--; @@ -41261,7 +41425,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) +{ -+ dprintk(4, "%s\n", __FUNCTION__); ++ dprintk(4, "%s\n", __func__); + + if (vq == NULL) { + dprintk(4, "null vq\n"); @@ -41281,17 +41445,15 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + -+static int -+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, -+ enum v4l2_field field) ++static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, ++ enum v4l2_field field) +{ + struct s2255_fh *fh = vq->priv_data; + struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); + int rc, init_buffer = 0; -+ dprintk(4, "%s, field=%d\n", __FUNCTION__, field); -+ if (fh->fmt == NULL) { ++ dprintk(4, "%s, field=%d\n", __func__, field); ++ if (fh->fmt == NULL) + return -EINVAL; -+ } + if ((fh->width < norm_minw(fh->dev->vdev[fh->channel])) || + (fh->width > norm_maxw(fh->dev->vdev[fh->channel])) || + (fh->height < norm_minh(fh->dev->vdev[fh->channel])) || @@ -41318,13 +41480,14 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { -+ if (0 != (rc = videobuf_iolock(vq, &buf->vb, NULL))) ++ rc = videobuf_iolock(vq, &buf->vb, NULL); ++ if (rc) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; -+ fail: ++fail: + free_buffer(vq, buf); + return rc; +} @@ -41381,7 +41544,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + struct s2255_dev *dev = (struct s2255_dev *)fh->dev; + struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel]; + -+ dprintk(1, "%s\n", __FUNCTION__); ++ dprintk(1, "%s\n", __func__); + s2255_stop_thread(vidq); + free_buffer(vq, buf); +} @@ -41442,13 +41605,11 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + struct v4l2_fmtdesc *f) +{ + int index = 0; -+ if (f) { ++ if (f) + index = f->index; -+ } + -+ if (index >= ARRAY_SIZE(formats)) { ++ if (index >= ARRAY_SIZE(formats)) + return -EINVAL; -+ } + + dprintk(4, "name %s\n", formats[index].name); + strlcpy(f->description, formats[index].name, sizeof(f->description)); @@ -41484,9 +41645,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + (dev->vdev[fh->channel]->current_norm != V4L2_STD_PAL_B) ? 1 : 0; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); -+ if (fmt == NULL) { ++ if (fmt == NULL) + return -EINVAL; -+ } + + field = f->fmt.pix.field; + @@ -41551,21 +41711,22 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return 0; +} + -+/*FIXME: This seems to be generic enough to be at videodev2 */ ++/* FIXME: This seems to be generic enough to be at videodev2 */ +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s2255_fh *fh = priv; + const struct s2255_fmt *fmt; -+ int ret = vidioc_try_fmt_cap(file, fh, f); ++ int ret; + int norm; -+ if (ret < 0) { ++ ++ ret = vidioc_try_fmt_cap(file, fh, f); ++ if (ret < 0) + return (ret); -+ } ++ + fmt = format_by_fourcc(f->fmt.pix.pixelformat); -+ if (fmt == NULL) { ++ if (fmt == NULL) + return -EINVAL; -+ } + + fh->fmt = fmt; + fh->width = f->fmt.pix.width; @@ -41574,15 +41735,13 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + fh->type = f->type; + + norm = norm_minw(fh->dev->vdev[fh->channel]); -+ if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) { -+ if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) { ++ if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) ++ if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) + fh->dev->mode[fh->channel].scale = SCALE_4CIFS; -+ } else { ++ else + fh->dev->mode[fh->channel].scale = SCALE_2CIFS; -+ } -+ } else { ++ else + fh->dev->mode[fh->channel].scale = SCALE_1CIFS; -+ } + + /* color mode */ + if (fh->fmt->fourcc == V4L2_PIX_FMT_GREY) { @@ -41663,6 +41822,166 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +} +#endif + ++static void s2255_sleep(int ms) ++{ ++ wait_queue_head_t sleep_q; ++ DEFINE_WAIT(wait); ++ if (ms == 0) { ++ schedule(); ++ return; ++ } ++ init_waitqueue_head(&sleep_q); ++ prepare_to_wait(&sleep_q, &wait, TASK_INTERRUPTIBLE); ++ schedule_timeout((ms * HZ) / 1000); ++ finish_wait(&sleep_q, &wait); ++} ++ ++#define EP_NUM_CONFIG 2 ++/* write to the configuration pipe, synchronously */ ++static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, ++ int size) ++{ ++ int pipe; ++ int done; ++ long retval = -1; ++ if (udev) { ++ pipe = usb_sndbulkpipe(udev, EP_NUM_CONFIG); ++ retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); ++ } ++ return retval; ++} ++ ++static u32 get_transfer_size(struct mode2255i *mode) ++{ ++ int linesPerFrame = LINE_SZ_DEF; ++ int pixelsPerLine = NUM_LINES_DEF; ++ u32 outImageSize; ++ u32 usbInSize; ++ unsigned int mask_mult; ++ ++ if (mode == NULL) ++ return 0; ++ ++ if (mode->format == FORMAT_NTSC) { ++ switch (mode->scale) { ++ case SCALE_4CIFS: ++ linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; ++ pixelsPerLine = LINE_SZ_4CIFS_NTSC; ++ break; ++ case SCALE_2CIFS: ++ linesPerFrame = NUM_LINES_2CIFS_NTSC; ++ pixelsPerLine = LINE_SZ_2CIFS_NTSC; ++ break; ++ case SCALE_1CIFS: ++ linesPerFrame = NUM_LINES_1CIFS_NTSC; ++ pixelsPerLine = LINE_SZ_1CIFS_NTSC; ++ break; ++ default: ++ break; ++ } ++ } else if (mode->format == FORMAT_PAL) { ++ switch (mode->scale) { ++ case SCALE_4CIFS: ++ linesPerFrame = NUM_LINES_4CIFS_PAL * 2; ++ pixelsPerLine = LINE_SZ_4CIFS_PAL; ++ break; ++ case SCALE_2CIFS: ++ linesPerFrame = NUM_LINES_2CIFS_PAL; ++ pixelsPerLine = LINE_SZ_2CIFS_PAL; ++ break; ++ case SCALE_1CIFS: ++ linesPerFrame = NUM_LINES_1CIFS_PAL; ++ pixelsPerLine = LINE_SZ_1CIFS_PAL; ++ break; ++ default: ++ break; ++ } ++ } ++ outImageSize = linesPerFrame * pixelsPerLine; ++ if (mode->color != COLOR_Y8) { ++ /* 2 bytes/pixel if not monochrome */ ++ outImageSize *= 2; ++ } ++ ++ /* total bytes to send including prefix and 4K padding; ++ must be a multiple of USB_READ_SIZE */ ++ usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ ++ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; ++ /* if size not a multiple of USB_READ_SIZE */ ++ if (usbInSize & ~mask_mult) ++ usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); ++ return usbInSize; ++} ++ ++static void dump_verify_mode(struct s2255_dev *sdev, struct mode2255i *mode) ++{ ++ struct device *dev = &sdev->udev->dev; ++ dev_info(dev, "------------------------------------------------\n"); ++ dev_info(dev, "verify mode\n"); ++ dev_info(dev, "format: %d\n", mode->format); ++ dev_info(dev, "scale: %d\n", mode->scale); ++ dev_info(dev, "fdec: %d\n", mode->fdec); ++ dev_info(dev, "color: %d\n", mode->color); ++ dev_info(dev, "bright: 0x%x\n", mode->bright); ++ dev_info(dev, "restart: 0x%x\n", mode->restart); ++ dev_info(dev, "usb_block: 0x%x\n", mode->usb_block); ++ dev_info(dev, "single: 0x%x\n", mode->single); ++ dev_info(dev, "------------------------------------------------\n"); ++} ++ ++/* ++ * set mode is the function which controls the DSP. ++ * the restart parameter in struct mode2255i should be set whenever ++ * the image size could change via color format, video system or image ++ * size. ++ * When the restart parameter is set, we sleep for ONE frame to allow the ++ * DSP time to get the new frame ++ */ ++static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, ++ struct mode2255i *mode) ++{ ++ int res; ++ u32 *buffer; ++ unsigned long chn_rev; ++ ++ chn_rev = G_chnmap[chn]; ++ dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale); ++ dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn], ++ dev->mode[chn].scale); ++ dprintk(2, "mode contrast %x\n", mode->contrast); ++ ++ /* save the mode */ ++ dev->mode[chn] = *mode; ++ dev->req_image_size[chn] = get_transfer_size(mode); ++ dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]); ++ ++ buffer = kzalloc(512, GFP_KERNEL); ++ if (buffer == NULL) { ++ dev_err(&dev->udev->dev, "out of mem\n"); ++ return -ENOMEM; ++ } ++ ++ /* set the mode */ ++ buffer[0] = IN_DATA_TOKEN; ++ buffer[1] = (u32) chn_rev; ++ buffer[2] = CMD_SET_MODE; ++ memcpy(&buffer[3], &dev->mode[chn], sizeof(struct mode2255i)); ++ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); ++ if (debug) ++ dump_verify_mode(dev, mode); ++ kfree(buffer); ++ dprintk(1, "set mode done chn %lu, %d\n", chn, res); ++ ++ /* wait at least one frame before continuing */ ++ ++ s2255_sleep(40); ++ ++ /* clear the restart flag */ ++ dev->mode[chn].restart = 0; ++ ++ return res; ++} ++ +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + int res; @@ -41671,17 +41990,17 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + struct mode2255i *mode; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { -+ printk("invalid fh type0\n"); ++ dev_err(&dev->udev->dev, "invalid fh type0\n"); + return -EINVAL; + } + + if (i != fh->type) { -+ printk("invalid fh type1\n"); ++ dev_err(&dev->udev->dev, "invalid fh type1\n"); + return -EINVAL; + } + + if (!res_get(dev, fh)) { -+ printk("res get busy\n"); ++ dev_err(&dev->udev->dev, "res get busy\n"); + return -EBUSY; + } + /* send a set mode command everytime with restart. @@ -41701,15 +42020,16 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + int res; + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; ++ + dprintk(1, "[%d]videobuf stream off\n", fh->channel); + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { -+ printk("invalid fh type0\n"); ++ dev_err(&dev->udev->dev, "invalid fh type0\n"); + return -EINVAL; + } + + if (i != fh->type) { -+ printk("invalid fh type1\n"); ++ dev_err(&dev->udev->dev, "invalid fh type1\n"); + return -EINVAL; + } + @@ -41880,7 +42200,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + if (dev->users[cur_channel] > 1) { + dev->users[cur_channel]--; -+ printk("one user at a time\n"); ++ dev_err(&dev->udev->dev, "one user at a time\n"); + mutex_unlock(&usb_s2255_open_mutex); + return -EAGAIN; + } @@ -41950,7 +42270,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + struct s2255_fh *fh = file->private_data; + struct s2255_buffer *buf; + -+ dprintk(100, "%s\n", __FUNCTION__); ++ dprintk(100, "%s\n", __func__); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) + return POLLERR; @@ -41975,6 +42295,15 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return 0; +} + ++static void s2255_destroy(struct kref *kref) ++{ ++ struct s2255_dev *dev = to_s2255_dev(kref); ++ ++ usb_put_dev(dev->udev); ++ dprintk(1, "s2255_destroy\n"); ++ kfree(dev); ++} ++ +static int s2255_release_v4l(struct inode *inode, struct file *file) +{ + struct s2255_fh *fh = file->private_data; @@ -42086,7 +42415,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + dev->vdev[i]->priv = dev; + + if (ret != 0) { -+ printk("failed register video device!\n"); ++ dev_err(&dev->udev->dev, ++ "failed to register video device!\n"); + return ret; + } + } @@ -42110,21 +42440,6 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + } +} + -+#define EP_NUM_CONFIG 2 -+/* write to the configuration pipe, synchronously */ -+static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, -+ int size) -+{ -+ int pipe; -+ int done; -+ long retval = -1; -+ if (udev) { -+ pipe = usb_sndbulkpipe(udev, EP_NUM_CONFIG); -+ retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); -+ } -+ return retval; -+} -+ +/* this function moves the usb stream read pipe data + * into the system buffers. + * returns 0 on success, EAGAIN if more data to process( call this @@ -42136,7 +42451,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + * bytes 8-11: payload size: size of the frame + * bytes 12-payloadsize+12: frame data + */ -+static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pPipeInfo) ++static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) +{ + static int dbgsync; /* = 0; */ + char *pdest; @@ -42171,7 +42486,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + } + + if (bsearch) { -+ if (*(s32 *) pPipeInfo->pTransferBuffer != FRAME_MARKER) { ++ if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) { + u32 jj; + if (dbgsync == 0) { + dprintk(3, "not synched, discarding all packets" @@ -42179,8 +42494,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + dbgsync++; + } -+ pdata = (unsigned char *)pPipeInfo->pTransferBuffer; -+ for (jj = 0; jj < (pPipeInfo->cur_transfer_size - 12); ++ pdata = (unsigned char *)pipe_info->transfer_buffer; ++ for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); + jj++) { + if (*(s32 *) pdata == FRAME_MARKER) { + int cc; @@ -42210,7 +42525,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + int cc; + dbgsync = 0; + bsync = 1; -+ pword = (u32 *) pPipeInfo->pTransferBuffer; ++ pword = (u32 *) pipe_info->transfer_buffer; + cc = pword[1]; + + if (cc >= MAX_CHANNELS) { @@ -42252,9 +42567,9 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + if (bsync) { + /* skip the marker 512 bytes (and offset if out of sync) */ -+ psrc = (u8 *)pPipeInfo->pTransferBuffer + offset + PREFIX_SIZE; ++ psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE; + } else { -+ psrc = (u8 *)pPipeInfo->pTransferBuffer; ++ psrc = (u8 *)pipe_info->transfer_buffer; + } + + if (frm->lpvbits == NULL) { @@ -42267,13 +42582,13 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + if (bsync) { + copy_size = -+ (pPipeInfo->cur_transfer_size - offset) - PREFIX_SIZE; -+ if (copy_size > pPipeInfo->cur_transfer_size) { ++ (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE; ++ if (copy_size > pipe_info->cur_transfer_size) { + printk("invalid copy size, overflow!\n"); + return -ENOMEM; + } + } else { -+ copy_size = pPipeInfo->cur_transfer_size; ++ copy_size = pipe_info->cur_transfer_size; + } + + cur_size = frm->cur_size; @@ -42297,10 +42612,10 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + dev->last_frame[cc] = dev->cur_frame[cc]; + dev->cur_frame[cc]++; + /* end of system frame ring buffer, start at zero */ -+ if ((dev->cur_frame[cc] == SYS_FRAMES) -+ || (dev->cur_frame[cc] == dev->buffer[cc].dwFrames)) { ++ if ((dev->cur_frame[cc] == SYS_FRAMES) || ++ (dev->cur_frame[cc] == dev->buffer[cc].dwFrames)) + dev->cur_frame[cc] = 0; -+ } ++ + /* signal the semaphore for this channel */ + s2255_got_frame(dev, cc); + dev->frame_count[cc]++; @@ -42315,7 +42630,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +} + +static void s2255_read_video_callback(struct s2255_dev *dev, -+ struct s2255_pipeinfo *pPipeInfo) ++ struct s2255_pipeinfo *pipe_info) +{ + int res; + int b_acq = 0; @@ -42324,7 +42639,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + if (dev->cc >= MAX_CHANNELS) { + dev->cc = 0; -+ printk("invalid channel\n"); ++ dev_err(&dev->udev->dev, "invalid channel\n"); + return; + } + @@ -42340,70 +42655,51 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return; + + /* otherwise copy to the system buffers */ -+ res = save_frame(dev, pPipeInfo); ++ res = save_frame(dev, pipe_info); + if (res == EAGAIN) -+ save_frame(dev, pPipeInfo); ++ save_frame(dev, pipe_info); + + dprintk(50, "callback read video done\n"); + return; +} + -+static int s2255_board_init(struct s2255_dev *dev) ++static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, ++ u16 Index, u16 Value, void *TransferBuffer, ++ s32 TransferBufferLength, int bOut) +{ -+ int j; -+ struct mode2255i mode_def = { DEF_MODEI_NTSC_CONT }; -+ int fw_ver; -+ dprintk(4, "board init: %p", dev); -+ -+ for (j = 0; j < MAX_CHANNELS; j++) { -+ dev->b_acquire[j] = 0; -+ dev->mode[j] = mode_def; -+ dev->req_image_size[j] = get_transfer_size(&mode_def); -+ } -+ -+ for (j = 0; j < MAX_PIPE_BUFFERS; j++) { -+ struct s2255_pipeinfo *pPipeInfo = &dev->UsbPipes[j]; -+ memset(pPipeInfo, sizeof(struct s2255_pipeinfo), 0); -+ pPipeInfo->state = 0; -+ pPipeInfo->prev_state = 0; -+ pPipeInfo->dev = dev; -+ pPipeInfo->cur_transfer_size = DEFAULT_PIPE_USBBLOCK; -+ pPipeInfo->max_transfer_size = MAX_PIPE_USBBLOCK; -+ -+ if (pPipeInfo->cur_transfer_size > pPipeInfo->max_transfer_size) { -+ pPipeInfo->cur_transfer_size = -+ pPipeInfo->max_transfer_size; -+ } -+ pPipeInfo->pTransferBuffer = -+ (unsigned char *)kzalloc(pPipeInfo->max_transfer_size, -+ GFP_KERNEL); -+ if (pPipeInfo->pTransferBuffer == NULL) { -+ dprintk(1, "out of memory!\n"); -+ return -ENOMEM; -+ } -+ -+ } -+ -+ /* query the firmware */ -+ fw_ver = s2255_get_fx2fw(dev); -+ -+ printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver); -+ if (fw_ver < CUR_USB_FWVER) -+ err("usb firmware not up to date %d\n", fw_ver); -+ -+ for (j = 0; j < MAX_CHANNELS; j++) { -+ dev->b_acquire[j] = 0; -+ dev->mode[j] = mode_def; -+ dev->req_image_size[j] = get_transfer_size(&mode_def); -+ dev->frame_count[j] = 0; -+ /* create the system buffers */ -+ s2255_create_sys_buffers(dev, j); ++ int r; ++ if (!bOut) { ++ r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), ++ Request, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE | ++ USB_DIR_IN, ++ Value, Index, TransferBuffer, ++ TransferBufferLength, HZ * 5); ++ } else { ++ r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), ++ Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, ++ Value, Index, TransferBuffer, ++ TransferBufferLength, HZ * 5); + } -+ /* start read pipe */ -+ s2255_start_readpipe(dev); ++ return r; ++} + -+ dprintk(1, "S2255: board initialized\n"); -+ return 0; ++/* ++ * retrieve FX2 firmware version. future use. ++ * @param dev pointer to device extension ++ * @return -1 for fail, else returns firmware version as an int(16 bits) ++ */ ++static int s2255_get_fx2fw(struct s2255_dev *dev) ++{ ++ int fw; ++ int ret; ++ unsigned char transBuffer[64]; ++ ret = s2255_vendor_req(dev, VX_FW, 0, 0, transBuffer, 2, DIR_IN); ++ if (ret < 0) ++ dprintk(2, "get fw error: %x\n", ret); ++ fw = transBuffer[0] + (transBuffer[1] << 8); ++ dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); ++ return fw; +} + +/* @@ -42468,6 +42764,62 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return 0; +} + ++static int s2255_board_init(struct s2255_dev *dev) ++{ ++ int j; ++ struct mode2255i mode_def = { DEF_MODEI_NTSC_CONT }; ++ int fw_ver; ++ dprintk(4, "board init: %p", dev); ++ ++ for (j = 0; j < MAX_CHANNELS; j++) { ++ dev->b_acquire[j] = 0; ++ dev->mode[j] = mode_def; ++ dev->req_image_size[j] = get_transfer_size(&mode_def); ++ } ++ ++ for (j = 0; j < MAX_PIPE_BUFFERS; j++) { ++ struct s2255_pipeinfo *pipe = &dev->pipes[j]; ++ ++ memset(pipe, sizeof(struct s2255_pipeinfo), 0); ++ pipe->state = 0; ++ pipe->prev_state = 0; ++ pipe->dev = dev; ++ pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK; ++ pipe->max_transfer_size = MAX_PIPE_USBBLOCK; ++ ++ if (pipe->cur_transfer_size > pipe->max_transfer_size) ++ pipe->cur_transfer_size = pipe->max_transfer_size; ++ pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, ++ GFP_KERNEL); ++ if (pipe->transfer_buffer == NULL) { ++ dprintk(1, "out of memory!\n"); ++ return -ENOMEM; ++ } ++ ++ } ++ ++ /* query the firmware */ ++ fw_ver = s2255_get_fx2fw(dev); ++ ++ printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver); ++ if (fw_ver < CUR_USB_FWVER) ++ err("usb firmware not up to date %d\n", fw_ver); ++ ++ for (j = 0; j < MAX_CHANNELS; j++) { ++ dev->b_acquire[j] = 0; ++ dev->mode[j] = mode_def; ++ dev->req_image_size[j] = get_transfer_size(&mode_def); ++ dev->frame_count[j] = 0; ++ /* create the system buffers */ ++ s2255_create_sys_buffers(dev, j); ++ } ++ /* start read pipe */ ++ s2255_start_readpipe(dev); ++ ++ dprintk(1, "S2255: board initialized\n"); ++ return 0; ++} ++ +static int s2255_board_shutdown(struct s2255_dev *dev) +{ + u32 i; @@ -42483,33 +42835,30 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + /* release transfer buffers */ + for (i = 0; i < MAX_PIPE_BUFFERS; i++) { -+ struct s2255_pipeinfo *pPipeInfo = &dev->UsbPipes[i]; -+ if (pPipeInfo->pTransferBuffer) { -+ kfree(pPipeInfo->pTransferBuffer); -+ } ++ struct s2255_pipeinfo *pipe = &dev->pipes[i]; ++ kfree(pipe->transfer_buffer); + } + return 0; +} + +static void read_pipe_completion(struct urb *purb) +{ -+ struct s2255_pipeinfo *pPipeInfo; ++ struct s2255_pipeinfo *pipe_info; + struct s2255_dev *dev; + int status; + int pipe; + -+ pPipeInfo = (struct s2255_pipeinfo *)purb->context; ++ pipe_info = purb->context; + dprintk(100, "read pipe completion %p, status %d\n", purb, + purb->status); -+ if (pPipeInfo == NULL) { -+ printk("no context !\n"); ++ if (pipe_info == NULL) { ++ err("no context !"); + return; + } + -+ dev = (struct s2255_dev *)pPipeInfo->dev; -+ ++ dev = pipe_info->dev; + if (dev == NULL) { -+ printk("no context !\n"); ++ err("no context !"); + return; + } + status = purb->status; @@ -42518,26 +42867,26 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return; + } + -+ if (pPipeInfo->state == 0) { ++ if (pipe_info->state == 0) { + dprintk(2, "exiting USB pipe"); + return; + } + -+ s2255_read_video_callback(dev, pPipeInfo); ++ s2255_read_video_callback(dev, pipe_info); + -+ pPipeInfo->err_count = 0; ++ pipe_info->err_count = 0; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); + /* reuse urb */ -+ usb_fill_bulk_urb(pPipeInfo->pStreamUrb, dev->udev, ++ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, + pipe, -+ pPipeInfo->pTransferBuffer, -+ pPipeInfo->cur_transfer_size, -+ read_pipe_completion, pPipeInfo); -+ -+ if (pPipeInfo->state != 0) { -+ if (usb_submit_urb(pPipeInfo->pStreamUrb, GFP_KERNEL)) { -+ printk("error submitting urb\n"); -+ usb_free_urb(pPipeInfo->pStreamUrb); ++ pipe_info->transfer_buffer, ++ pipe_info->cur_transfer_size, ++ read_pipe_completion, pipe_info); ++ ++ if (pipe_info->state != 0) { ++ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) { ++ dev_err(&dev->udev->dev, "error submitting urb\n"); ++ usb_free_urb(pipe_info->stream_urb); + } + } + return; @@ -42548,29 +42897,30 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + int pipe; + int retval; + int i; -+ struct s2255_pipeinfo *pPipeInfo = dev->UsbPipes; ++ struct s2255_pipeinfo *pipe_info = dev->pipes; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); + dprintk(2, "start pipe IN %d\n", dev->read_endpoint); + + for (i = 0; i < MAX_PIPE_BUFFERS; i++) { -+ pPipeInfo->state = 1; -+ pPipeInfo->buf_index = (u32) i; -+ pPipeInfo->priority_set = 0; -+ pPipeInfo->pStreamUrb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!pPipeInfo->pStreamUrb) { -+ printk("ReadStream : Unable to alloc URB"); ++ pipe_info->state = 1; ++ pipe_info->buf_index = (u32) i; ++ pipe_info->priority_set = 0; ++ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!pipe_info->stream_urb) { ++ dev_err(&dev->udev->dev, ++ "ReadStream: Unable to alloc URB"); + return -ENOMEM; + } + /* transfer buffer allocated in board_init */ -+ usb_fill_bulk_urb(pPipeInfo->pStreamUrb, dev->udev, ++ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, + pipe, -+ pPipeInfo->pTransferBuffer, -+ pPipeInfo->cur_transfer_size, -+ read_pipe_completion, pPipeInfo); ++ pipe_info->transfer_buffer, ++ pipe_info->cur_transfer_size, ++ read_pipe_completion, pipe_info); + -+ pPipeInfo->urb_size = sizeof(pPipeInfo->pStreamUrb); -+ dprintk(4, "submitting URB %p\n", pPipeInfo->pStreamUrb); -+ retval = usb_submit_urb(pPipeInfo->pStreamUrb, GFP_KERNEL); ++ pipe_info->urb_size = sizeof(pipe_info->stream_urb); ++ dprintk(4, "submitting URB %p\n", pipe_info->stream_urb); ++ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); + if (retval) { + printk(KERN_ERR "s2255: start read pipe failed\n"); + return retval; @@ -42580,92 +42930,10 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + return 0; +} + -+static void s2255_sleep(int ms) -+{ -+ wait_queue_head_t sleep_q; -+ DEFINE_WAIT(wait); -+ if (ms == 0) { -+ schedule(); -+ return; -+ } -+ init_waitqueue_head(&sleep_q); -+ prepare_to_wait(&sleep_q, &wait, TASK_INTERRUPTIBLE); -+ schedule_timeout((ms * HZ) / 1000); -+ finish_wait(&sleep_q, &wait); -+} -+ -+static void dump_verify_mode(struct mode2255i *mode) -+{ -+ printk("-------------------------------------------------------\n"); -+ printk("verify mode\n"); -+ printk("format: %d\n", mode->format); -+ printk("scale: %d\n", mode->scale); -+ printk("fdec: %d\n", mode->fdec); -+ printk("color: %d\n", mode->color); -+ printk("bright: 0x%x\n", mode->bright); -+ printk("restart: 0x%x\n", mode->restart); -+ printk("Usbblock: 0x%x\n", mode->usb_block); -+ printk("single: 0x%x\n", mode->single); -+ printk("-------------------------------------------------------\n"); -+} -+ -+/* -+ * set mode is the function which controls the DSP. -+ * the restart parameter in struct mode2255i should be set whenever -+ * the image size could change via color format, video system or image -+ * size. -+ * When the restart parameter is set, we sleep for ONE frame to allow the -+ * DSP time to get the new frame -+ */ -+static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, -+ struct mode2255i *mode) -+{ -+ int res; -+ u32 *pBuf; -+ unsigned long chn_rev; -+ -+ chn_rev = G_chnmap[chn]; -+ dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale); -+ dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn], -+ dev->mode[chn].scale); -+ dprintk(2, "mode contrast %x\n", mode->contrast); -+ -+ /* save the mode */ -+ dev->mode[chn] = *mode; -+ dev->req_image_size[chn] = get_transfer_size(mode); -+ dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]); -+ -+ pBuf = (u32 *) kzalloc(512, GFP_KERNEL); -+ if (pBuf == NULL) { -+ printk("out of mem\n"); -+ return -1; -+ } -+ -+ /* set the mode */ -+ pBuf[0] = IN_DATA_TOKEN; -+ pBuf[1] = (u32) chn_rev; -+ pBuf[2] = CMD_SET_MODE; -+ memcpy(&pBuf[3], &dev->mode[chn], sizeof(struct mode2255i)); -+ res = s2255_write_config(dev->udev, (unsigned char *)pBuf, 512); -+ if (debug) -+ dump_verify_mode(mode); -+ kfree(pBuf); -+ dprintk(1, "set mode done chn %lu, %d\n", chn, res); -+ -+ /* wait at least one frame before continuing */ -+ -+ s2255_sleep(40); -+ -+ /* clear the restart flag */ -+ dev->mode[chn].restart = 0; -+ -+ return res; -+} -+ +/* starts acquisition process */ +static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn) +{ -+ unsigned char *pBuf; ++ unsigned char *buffer; + int res; + unsigned long chn_rev; + @@ -42676,27 +42944,27 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + chn_rev = G_chnmap[chn]; + dprintk(1, "S2255: start acquire %lu \n", chn); + -+ pBuf = (unsigned char *)kzalloc(512, GFP_KERNEL); -+ if (pBuf == NULL) { -+ printk("out of mem\n"); -+ return -1; ++ buffer = kzalloc(512, GFP_KERNEL); ++ if (buffer == NULL) { ++ dev_err(&dev->udev->dev, "out of mem\n"); ++ return -ENOMEM; + } + /* send the start command */ -+ *(u32 *) pBuf = IN_DATA_TOKEN; -+ *((u32 *) pBuf + 1) = (u32) chn_rev; -+ *((u32 *) pBuf + 2) = (u32) CMD_START; -+ res = s2255_write_config(dev->udev, (unsigned char *)pBuf, 512); ++ *(u32 *) buffer = IN_DATA_TOKEN; ++ *((u32 *) buffer + 1) = (u32) chn_rev; ++ *((u32 *) buffer + 2) = (u32) CMD_START; ++ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); + if (res != 0) -+ printk("S2255: CMD_START error\n"); ++ dev_err(&dev->udev->dev, "CMD_START error\n"); + + dprintk(2, "start acquire exit[%lu] %d \n", chn, res); -+ kfree(pBuf); ++ kfree(buffer); + return 0; +} + +static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn) +{ -+ unsigned char *pBuf; ++ unsigned char *buffer; + int res; + unsigned long chn_rev; + @@ -42706,25 +42974,25 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + } + chn_rev = G_chnmap[chn]; + -+ pBuf = (unsigned char *)kzalloc(512, GFP_KERNEL); -+ if (pBuf == NULL) { -+ printk("out of mem\n"); -+ return -1; ++ buffer = kzalloc(512, GFP_KERNEL); ++ if (buffer == NULL) { ++ dev_err(&dev->udev->dev, "out of mem\n"); ++ return -ENOMEM; + } + + /* send the stop command */ + dprintk(1, "stop acquire %lu\n", chn); -+ *(u32 *) pBuf = IN_DATA_TOKEN; -+ *((u32 *) pBuf + 1) = (u32) chn_rev; -+ *((u32 *) pBuf + 2) = CMD_STOP; -+ res = s2255_write_config(dev->udev, (unsigned char *)pBuf, 512); ++ *(u32 *) buffer = IN_DATA_TOKEN; ++ *((u32 *) buffer + 1) = (u32) chn_rev; ++ *((u32 *) buffer + 2) = CMD_STOP; ++ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); + + if (res != 0) -+ printk("CMD_STOP error\n"); ++ dev_err(&dev->udev->dev, "CMD_STOP error\n"); + + dprintk(4, "stop acquire: releasing states \n"); + -+ kfree(pBuf); ++ kfree(buffer); + + return 0; +} @@ -42732,555 +43000,192 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +static void s2255_stop_readpipe(struct s2255_dev *dev) +{ + int j; ++ + if (dev == NULL) { -+ printk("s2255: invalid device\n"); ++ err("s2255: invalid device"); + return; + } + dprintk(4, "stop read pipe\n"); + for (j = 0; j < MAX_PIPE_BUFFERS; j++) { -+ struct s2255_pipeinfo *pPipeInfo = &dev->UsbPipes[j]; -+ if (pPipeInfo) { -+ if (pPipeInfo->state == 0) ++ struct s2255_pipeinfo *pipe_info = &dev->pipes[j]; ++ if (pipe_info) { ++ if (pipe_info->state == 0) + continue; -+ pPipeInfo->state = 0; -+ pPipeInfo->prev_state = 1; ++ pipe_info->state = 0; ++ pipe_info->prev_state = 1; + + } + } + + for (j = 0; j < MAX_PIPE_BUFFERS; j++) { -+ struct s2255_pipeinfo *pPipeInfo = &dev->UsbPipes[j]; -+ if (pPipeInfo->pStreamUrb) { ++ struct s2255_pipeinfo *pipe_info = &dev->pipes[j]; ++ if (pipe_info->stream_urb) { + /* cancel urb */ -+ usb_kill_urb(pPipeInfo->pStreamUrb); -+ usb_free_urb(pPipeInfo->pStreamUrb); -+ pPipeInfo->pStreamUrb = NULL; ++ usb_kill_urb(pipe_info->stream_urb); ++ usb_free_urb(pipe_info->stream_urb); ++ pipe_info->stream_urb = NULL; + } + } + dprintk(2, "s2255 stop read pipe: %d\n", j); + return; +} + -+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, -+ u16 Index, u16 Value, void *TransferBuffer, -+ s32 TransferBufferLength, int bOut) -+{ -+ int r; -+ if (!bOut) { -+ r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), -+ Request, -+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | -+ USB_DIR_IN, -+ Value, Index, TransferBuffer, -+ TransferBufferLength, HZ * 5); -+ } else { -+ r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), -+ Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, -+ Value, Index, TransferBuffer, -+ TransferBufferLength, HZ * 5); -+ } -+ return r; -+} -+ -+static u32 get_transfer_size(struct mode2255i *mode) -+{ -+ int linesPerFrame = LINE_SZ_DEF; -+ int pixelsPerLine = NUM_LINES_DEF; -+ u32 outImageSize; -+ u32 usbInSize; -+ unsigned int mask_mult; -+ -+ if (mode == NULL) -+ return 0; -+ -+ if (mode->format == FORMAT_NTSC) { -+ switch (mode->scale) { -+ case SCALE_4CIFS: -+ linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; -+ pixelsPerLine = LINE_SZ_4CIFS_NTSC; -+ break; -+ case SCALE_2CIFS: -+ linesPerFrame = NUM_LINES_2CIFS_NTSC; -+ pixelsPerLine = LINE_SZ_2CIFS_NTSC; -+ break; -+ case SCALE_1CIFS: -+ linesPerFrame = NUM_LINES_1CIFS_NTSC; -+ pixelsPerLine = LINE_SZ_1CIFS_NTSC; -+ break; -+ default: -+ break; -+ } -+ } else if (mode->format == FORMAT_PAL) { -+ switch (mode->scale) { -+ case SCALE_4CIFS: -+ linesPerFrame = NUM_LINES_4CIFS_PAL * 2; -+ pixelsPerLine = LINE_SZ_4CIFS_PAL; -+ break; -+ case SCALE_2CIFS: -+ linesPerFrame = NUM_LINES_2CIFS_PAL; -+ pixelsPerLine = LINE_SZ_2CIFS_PAL; -+ break; -+ case SCALE_1CIFS: -+ linesPerFrame = NUM_LINES_1CIFS_PAL; -+ pixelsPerLine = LINE_SZ_1CIFS_PAL; -+ break; -+ default: -+ break; -+ } -+ } -+ outImageSize = linesPerFrame * pixelsPerLine; -+ if (mode->color != COLOR_Y8) { -+ /* 2 bytes/pixel if not monochrome */ -+ outImageSize *= 2; -+ } -+ -+ /* total bytes to send including prefix and 4K padding; -+ must be a multiple of USB_READ_SIZE */ -+ usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ -+ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; -+ /* if size not a multiple of USB_READ_SIZE */ -+ if (usbInSize & ~mask_mult) -+ usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); -+ return usbInSize; -+} -+ -+/* -+ * convert from YUV(YCrCb) to RGB -+ * 65536 R = 76533(Y-16) + 104936 * (Cr-128) -+ * 65536 G = 76533(Y-16) - 53451(Cr-128) - 25703(Cb -128) -+ * 65536 B = 76533(Y-16) + 132677(Cb-128) -+ */ -+static void YCrCb2RGB(int Y, int Cr, int Cb, unsigned char *pR, -+ unsigned char *pG, unsigned char *pB) ++/* standard usb probe function */ ++static int s2255_probe(struct usb_interface *interface, ++ const struct usb_device_id *id) +{ -+ int R, G, B; -+ -+ Y = Y - 16; -+ Cr = Cr - 128; -+ Cb = Cb - 128; ++ struct s2255_dev *dev = NULL; ++ struct usb_host_interface *iface_desc; ++ struct usb_endpoint_descriptor *endpoint; ++ int i; ++ int retval = -ENOMEM; + -+ R = (76533 * Y + 104936 * Cr) >> 16; -+ G = ((76533 * Y) - (53451 * Cr) - (25703 * Cb)) >> 16; -+ B = ((76533 * Y) + (132677 * Cb)) >> 16; -+ /* even with proper conversion, some values still need clipping. */ -+ if (R > 255) -+ R = 255; -+ if (G > 255) -+ G = 255; -+ if (B > 255) -+ B = 255; -+ if (R < 0) -+ R = 0; -+ if (G < 0) -+ G = 0; -+ if (B < 0) -+ B = 0; -+ *pR = R; -+ *pG = G; -+ *pB = B; -+ return; -+} ++ dprintk(100, "s2255: probe\n"); + -+/* converts 2255 planar format to yuyv */ -+static void planar422p_to_yuy2(const unsigned char *in, unsigned char *out, -+ int width, int height) -+{ -+ unsigned char *pY; -+ unsigned char *pCb; -+ unsigned char *pCr; -+ unsigned long size = height * width; -+ unsigned int i; -+ pY = (unsigned char *)in; -+ pCr = (unsigned char *)in + height * width; -+ pCb = (unsigned char *)in + height * width + (height * width / 2); -+ for (i = 0; i < size * 2; i += 4) { -+ out[i] = *pY++; -+ out[i + 1] = *pCr++; -+ out[i + 2] = *pY++; -+ out[i + 3] = *pCb++; ++ /* allocate memory for our device state and initialize it to zero */ ++ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); ++ if (dev == NULL) { ++ err("s2255: out of memory"); ++ goto error; + } -+ return; -+} + -+/* -+ * basic 422 planar to RGB24 or BGR24 software conversion. -+ * This is best done with MMX. Update to kernel function -+ * when image conversion functions added to kernel. -+ */ -+static void planar422p_to_rgb24(const unsigned char *in, -+ unsigned char *out, int width, -+ int height, int rev_order) -+{ -+ unsigned char *pY; -+ unsigned char *pYEND; -+ unsigned char *pCb; -+ unsigned char *pCr; -+ unsigned char Cr, Cb, Y, r, g, b; -+ unsigned long k = 0; -+ pY = (unsigned char *)in; -+ pCb = (unsigned char *)in + (height * width); -+ pCr = (unsigned char *)in + (height * width) + (height * width / 2); -+ pYEND = pCb; -+ while (pY < pYEND) { -+ Y = *pY++; -+ Cr = *pCr; -+ Cb = *pCb; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ out[k++] = !rev_order ? b : r; -+ out[k++] = g; -+ out[k++] = !rev_order ? r : b; -+ if (pY >= pYEND) -+ break; -+ Y = *pY++; -+ Cr = *pCr++; -+ Cb = *pCb++; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ out[k++] = !rev_order ? b : r; -+ out[k++] = g; -+ out[k++] = !rev_order ? r : b; ++ /* grab usb_device and save it */ ++ dev->udev = usb_get_dev(interface_to_usbdev(interface)); ++ if (dev->udev == NULL) { ++ dev_err(&interface->dev, "null usb device\n"); ++ goto error; + } -+ return; -+} + -+static void planar422p_to_rgb32(const unsigned char *in, unsigned char *out, -+ int width, int height, int rev_order) -+{ -+ unsigned char *pY; -+ unsigned char *pYEND; -+ unsigned char *pCb; -+ unsigned char *pCr; -+ unsigned char Cr, Cb, Y, r, g, b; -+ unsigned long k = 0; -+ pY = (unsigned char *)in; -+ pCb = (unsigned char *)in + (height * width); -+ pCr = (unsigned char *)in + (height * width) + (height * width / 2); -+ pYEND = pCb; -+ while (pY < pYEND) { -+ Y = *pY++; -+ Cr = *pCr; -+ Cb = *pCb; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ out[k++] = rev_order ? b : r; -+ out[k++] = g; -+ out[k++] = rev_order ? r : b; -+ out[k++] = 0; -+ if (pY >= pYEND) -+ break; -+ Y = *pY++; -+ Cr = *pCr++; -+ Cb = *pCb++; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ out[k++] = rev_order ? b : r; -+ out[k++] = g; -+ out[k++] = rev_order ? r : b; -+ out[k++] = 0; ++ kref_init(&dev->kref); ++ dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref, ++ dev->udev, interface); ++ dev->interface = interface; ++ /* set up the endpoint information */ ++ iface_desc = interface->cur_altsetting; ++ dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { ++ endpoint = &iface_desc->endpoint[i].desc; ++ if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { ++ /* we found the bulk in endpoint */ ++ dev->read_endpoint = endpoint->bEndpointAddress; ++ } + } + -+ return; -+} -+ -+static void planar422p_to_rgb565(unsigned char const *in, unsigned char *out, -+ int width, int height, int rev_order) -+{ -+ unsigned char *pY; -+ unsigned char *pYEND; -+ unsigned char *pCb; -+ unsigned char *pCr; -+ unsigned char Cr, Cb, Y, r, g, b; -+ unsigned long k = 0; -+ unsigned short rgbbytes; -+ pY = (unsigned char *)in; -+ pCb = (unsigned char *)in + (height * width); -+ pCr = (unsigned char *)in + (height * width) + (height * width / 2); -+ pYEND = pCb; -+ while (pY < pYEND) { -+ Y = *pY++; -+ Cr = *pCr; -+ Cb = *pCb; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ r = r >> 3; -+ g = g >> 2; -+ b = b >> 3; -+ if (rev_order) -+ rgbbytes = b + (g << 5) + (r << (5 + 6)); -+ else -+ rgbbytes = r + (g << 5) + (b << (5 + 6)); -+ out[k++] = rgbbytes & 0xff; -+ out[k++] = (rgbbytes >> 8) & 0xff; -+ Y = *pY++; -+ Cr = *pCr++; -+ Cb = *pCb++; -+ YCrCb2RGB(Y, Cr, Cb, &r, &g, &b); -+ r = r >> 3; -+ g = g >> 2; -+ b = b >> 3; -+ if (rev_order) -+ rgbbytes = b + (g << 5) + (r << (5 + 6)); -+ else -+ rgbbytes = r + (g << 5) + (b << (5 + 6)); -+ out[k++] = rgbbytes & 0xff; -+ out[k++] = (rgbbytes >> 8) & 0xff; ++ if (!dev->read_endpoint) { ++ dev_err(&interface->dev, "Could not find bulk-in endpoint"); ++ goto error; + } -+ return; -+} -+ -+/** retrieve FX2 firmware version. future use. -+ * @param dev pointer to device extension -+ * @return -1 for fail, else returns firmware version as an int(16 bits) -+ */ -+static int s2255_get_fx2fw(struct s2255_dev *dev) -+{ -+ int fw; -+ int ret; -+ unsigned char transBuffer[64]; -+ ret = s2255_vendor_req(dev, VX_FW, 0, 0, transBuffer, 2, DIR_IN); -+ if (ret < 0) -+ dprintk(2, "get fw error: %x\n", ret); -+ fw = transBuffer[0] + (transBuffer[1] << 8); -+ dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); -+ return fw; -+} -+ -+module_init(usb_s2255_init); -+module_exit(usb_s2255_exit); -+MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); -+MODULE_AUTHOR("D.A.(Sensoray)"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/usb/image/s2255drv.h -@@ -0,0 +1,235 @@ -+/* -+ * Sensoray 2255 USB Linux driver -+ * -+ * Copyright (C) 2007-2008 by Sensoray Company Inc. -+ * Dean Anderson -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation, version 2. -+ */ -+ -+#ifndef S2255DRIVER_H -+#define S2255DRIVER_H -+ -+ -+#define DIR_IN 0 -+#define DIR_OUT 1 -+/* firmware query */ -+#define VX_FW 0x30 -+ -+#define MAX_CHANNELS 4 -+#define FRAME_MARKER 0x2255DA4AL -+#define MAX_PIPE_USBBLOCK (40*1024) -+#define DEFAULT_PIPE_USBBLOCK (16*1024) -+#define MAX_CHANNELS 4 -+#define MAX_PIPE_BUFFERS 1 -+#define SYS_FRAMES 4 -+/* maximum size is PAL full size plus room for the marker header(s) */ -+#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) -+#define DEF_USB_BLOCK (4096) -+#define LINE_SZ_4CIFS_NTSC 640 -+#define LINE_SZ_2CIFS_NTSC 640 -+#define LINE_SZ_1CIFS_NTSC 320 -+#define LINE_SZ_4CIFS_PAL 704 -+#define LINE_SZ_2CIFS_PAL 704 -+#define LINE_SZ_1CIFS_PAL 352 -+#define NUM_LINES_4CIFS_NTSC 240 -+#define NUM_LINES_2CIFS_NTSC 240 -+#define NUM_LINES_1CIFS_NTSC 240 -+#define NUM_LINES_4CIFS_PAL 288 -+#define NUM_LINES_2CIFS_PAL 288 -+#define NUM_LINES_1CIFS_PAL 288 -+#define LINE_SZ_DEF 640 -+#define NUM_LINES_DEF 240 -+ -+ -+/* predefined settings */ -+#define FORMAT_NTSC 1 -+#define FORMAT_PAL 2 + -+#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ -+#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ -+#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ ++ /* set intfdata */ ++ usb_set_intfdata(interface, dev); + -+#define COLOR_YUVPL 1 /* YUV planar */ -+#define COLOR_YUVPK 2 /* YUV packed */ -+#define COLOR_RGB 3 /* RGB */ -+#define COLOR_Y8 4 /* monochrome */ ++ dprintk(100, "after intfdata %p\n", dev); + -+/* frame decimation. Not implemented by V4L yet(experimental in V4L) */ -+#define FDEC_1 1 /* capture every frame. default */ -+#define FDEC_2 2 /* capture every 2nd frame */ -+#define FDEC_3 3 /* capture every 3rd frame */ -+#define FDEC_5 5 /* capture every 5th frame */ ++ /* initialize COUNTING semaphores */ ++ for (i = 0; i < MAX_CHANNELS; i++) ++ sema_init(&dev->sem_frms[i], 0); + -+/*------------------------------------------------------- -+ * Default mode parameters. -+ *-------------------------------------------------------*/ -+#define DEF_SCALE SCALE_4CIFS -+#define DEF_COLOR COLOR_YUVPL -+#define DEF_FDEC FDEC_1 -+#define DEF_BRIGHT 0 -+#define DEF_CONTRAST 0x5c -+#define DEF_SATURATION 0x80 -+#define DEF_HUE 0 ++ /* initialize device mutex */ ++ mutex_init(&dev->lock); + -+/* usb config commands */ -+#define IN_DATA_TOKEN 0x2255c0de -+#define CMD_2255 0xc2255000 -+#define CMD_SET_MODE (CMD_2255 | 0x10) -+#define CMD_START (CMD_2255 | 0x20) -+#define CMD_STOP (CMD_2255 | 0x30) -+#define CMD_STATUS (CMD_2255 | 0x40) ++ init_timer(&dev->timer); ++ dev->timer.function = s2255_timer; ++ dev->fw_data = kzalloc(sizeof(struct complete_data), GFP_KERNEL); ++ if (!dev->fw_data) ++ goto error; + -+struct mode2255i { -+ u32 format; /* input video format (NTSC, PAL) */ -+ u32 scale; /* output video scale */ -+ u32 color; /* output video color format */ -+ u32 fdec; /* frame decimation */ -+ u32 bright; /* brightness */ -+ u32 contrast; /* contrast */ -+ u32 saturation; /* saturation */ -+ u32 hue; /* hue (NTSC only)*/ -+ u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ -+ u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ -+ u32 restart; /* if DSP requires restart */ -+}; ++ dev->timer.data = (unsigned long)dev->fw_data; + -+/* frame structure */ -+#define FRAME_STATE_UNUSED 0 -+#define FRAME_STATE_FILLING 1 -+#define FRAME_STATE_FULL 2 ++ dev->fw_data->fw_size = sizeof(G_f2255usb) / sizeof(unsigned char); ++ dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); + ++ if (!dev->fw_data->fw_urb) { ++ dev_err(&interface->dev, "out of memory!\n"); ++ goto error; ++ } ++ dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); ++ if (!dev->fw_data->pfw_data) { ++ dev_err(&interface->dev, "out of memory!\n"); ++ goto error; ++ } + -+struct framei { -+ unsigned long size; ++ /* load the first chunk */ ++ memcpy(dev->fw_data->pfw_data, G_f2255usb, CHUNK_SIZE); ++ dev->fw_data->fw_loaded = CHUNK_SIZE; ++ usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, ++ usb_sndbulkpipe(dev->udev, 2), dev->fw_data->pfw_data, ++ CHUNK_SIZE, s2255_fwchunk_complete, dev->fw_data); ++ /* loads v4l specific */ ++ s2255_probe_v4l(dev); ++ /* load 2255 board specific */ ++ s2255_board_init(dev); + -+ unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */ -+ void *lpvbits; /* image data */ -+ unsigned long cur_size; /* current data copied to it */ -+}; ++ dev_info(&interface->dev, "Sensoray 2255 successfully loaded\n"); ++ dprintk(4, "before probe done %p\n", dev); + -+/* image buffer structure */ -+struct bufferi { -+ unsigned long dwFrames; /* number of frames in buffer */ -+ struct framei frame[SYS_FRAMES]; /* array of FRAME structures */ -+}; ++ mod_timer(&dev->timer, jiffies + HZ); + -+#define DEF_MODEI_NTSC_CONT FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ -+ DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ -+ DEF_HUE, 0, DEF_USB_BLOCK, 0 ++ kref_get(&dev->kref); ++ return 0; ++error: ++ return retval; ++} + -+#define DEF_MODEI_PAL_CONT FORMAT_PAL, DEF_SCALE, DEF_COLOR, DEF_FDEC,\ -+ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 0, \ -+ DEF_USB_BLOCK, 0 ++/* disconnect routine. when board is removed physically or with rmmod */ ++static void s2255_disconnect(struct usb_interface *interface) ++{ ++ struct s2255_dev *dev = NULL; + -+#define DEF_MODEI_NTSC_SING FORMAT_NTSC, DEF_SCALE, DEF_COLOR, DEF_FDEC,\ -+ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 1,\ -+ DEF_USB_BLOCK, 0 ++ /* lock to prevent s2255_open() from racing s2255_disconnect() */ ++ mutex_lock(&usb_s2255_open_mutex); ++ dprintk(1, "s2255: disconnect interface %p\n", interface); ++ dev = usb_get_intfdata(interface); ++ s2255_board_shutdown(dev); ++ if (dev->fw_data->fw_urb) { ++ dprintk(2, "kill URB\n"); ++ usb_kill_urb(dev->fw_data->fw_urb); ++ usb_free_urb(dev->fw_data->fw_urb); + -+#define DEF_MODEI_PAL_SING FORMAT_PAL, DEF_SCALE, DEF_COLOR, DEF_FDEC, \ -+ DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, DEF_HUE, 1,\ -+ DEF_USB_BLOCK, 0 ++ } ++ s2255_exit_v4l(dev); ++ if (dev->fw_data) { ++ kfree(dev->fw_data->pfw_data); ++ kfree(dev->fw_data); ++ } ++ usb_set_intfdata(interface, NULL); ++ kref_put(&dev->kref, s2255_destroy); ++ mutex_unlock(&usb_s2255_open_mutex); ++ dev_info(&interface->dev, "s2255usb now disconnected\n"); ++} + -+struct s2255_dmaqueue { -+ struct list_head active; -+ struct list_head queued; -+ struct timer_list timeout; -+ /* thread for acquisition */ -+ struct task_struct *kthread; -+ wait_queue_head_t wq; -+ int frame; -+ struct s2255_dev *dev; -+ int channel; ++static struct usb_driver s2255_driver = { ++ .name = "s2255", ++ .probe = s2255_probe, ++ .disconnect = s2255_disconnect, ++ .id_table = s2255_table, +}; + -+/* for firmware loading */ -+#define FWSTATE_NOTLOADED 0 -+#define FWSTATE_SUCCESS 1 -+#define FWSTATE_FAILED 2 -+ -+typedef struct complete_data { -+ int fw_loaded; -+ int fw_size; -+ struct urb *fw_urb; -+ int fw_state; -+ void *pfw_data; -+} complete_data_t; -+ -+struct s2255_pipeinfo; -+ -+typedef struct s2255_pipeinfo { -+ u32 max_transfer_size; -+ u32 cur_transfer_size; -+ u8 *pTransferBuffer; -+ u32 transfer_flags;; -+ u32 state; -+ u32 prev_state; -+ u32 urb_size; -+ void *pStreamUrb; -+ void *dev; /* back pointer to s2255_dev struct*/ -+ u32 err_count; -+ u32 buf_index; -+ u32 idx; -+ u32 priority_set; -+} s2255_pipeinfo_t; -+ -+struct s2255_dev { -+ int frames; -+ int users[MAX_CHANNELS]; -+ struct mutex lock; -+ int resources[MAX_CHANNELS]; -+ struct usb_device *udev; -+ struct usb_interface *interface; -+ u8 read_endpoint; -+ struct semaphore sem_frms[MAX_CHANNELS]; /* frames ready */ -+ struct s2255_dmaqueue vidq[MAX_CHANNELS]; -+ struct video_device *vdev[MAX_CHANNELS]; -+ struct list_head s2255_devlist; -+ struct timer_list timer; -+ struct complete_data *fw_data; -+ int board_num; -+ int is_open; -+ struct s2255_pipeinfo UsbPipes[MAX_PIPE_BUFFERS]; -+ struct bufferi buffer[MAX_CHANNELS]; -+ struct mode2255i mode[MAX_CHANNELS]; -+ int cur_frame[MAX_CHANNELS]; -+ int last_frame[MAX_CHANNELS]; -+ u32 cc; /* current channel */ -+ int b_acquire[MAX_CHANNELS]; -+ unsigned long req_image_size[MAX_CHANNELS]; -+ int bad_payload[MAX_CHANNELS]; -+ unsigned long frame_count[MAX_CHANNELS]; -+ int frame_ready; -+ struct kref kref; -+}; ++static int __init usb_s2255_init(void) ++{ ++ int result; + -+struct s2255_fmt { -+ char *name; -+ u32 fourcc; -+ int depth; -+}; ++ /* register this driver with the USB subsystem */ ++ result = usb_register(&s2255_driver); + -+/* buffer for one video frame */ -+struct s2255_buffer { -+ /* common v4l buffer stuff -- must be first */ -+ struct videobuf_buffer vb; -+ const struct s2255_fmt *fmt; -+ /* future use */ -+ int reserved[32]; -+}; ++ if (result) ++ err("usb_register failed. Error number %d", result); + -+struct s2255_fh { -+ struct s2255_dev *dev; -+ unsigned int resources; -+ const struct s2255_fmt *fmt; -+ unsigned int width; -+ unsigned int height; -+ struct videobuf_queue vb_vidq; -+ enum v4l2_buf_type type; -+ int channel; -+}; ++ dprintk(2, "s2255_init: done\n"); ++ return result; ++} + ++static void __exit usb_s2255_exit(void) ++{ ++ usb_deregister(&s2255_driver); ++} + -+#endif ++module_init(usb_s2255_init); ++module_exit(usb_s2255_exit); ++MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); ++MODULE_AUTHOR("D.A.(Sensoray)"); ++MODULE_LICENSE("GPL"); |
