tree-wide: fix assorted typos all over the place
[safe/jmp/linux-2.6] / drivers / media / video / s2255drv.c
index de39cf0..a4c8436 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
@@ -58,6 +59,8 @@
 
 
 
+/* default JPEG quality */
+#define S2255_DEF_JPEG_QUAL     50
 /* vendor request in */
 #define S2255_VR_IN            0
 /* vendor request out */
 /* USB endpoint number for configuring the device */
 #define S2255_CONFIG_EP         2
 /* maximum time for DSP to start responding after last FW word loaded(ms) */
-#define S2255_DSP_BOOTTIME      400
+#define S2255_DSP_BOOTTIME      800
 /* maximum time to wait for firmware to load (ms) */
 #define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
 #define S2255_DEF_BUFS          16
+#define S2255_SETMODE_TIMEOUT   500
 #define MAX_CHANNELS           4
-#define FRAME_MARKER           0x2255DA4AL
-#define MAX_PIPE_USBBLOCK      (40 * 1024)
-#define DEFAULT_PIPE_USBBLOCK  (16 * 1024)
+#define S2255_MARKER_FRAME     0x2255DA4AL
+#define S2255_MARKER_RESPONSE  0x2255ACACL
+#define S2255_RESPONSE_SETMODE  0x01
+#define S2255_RESPONSE_FW       0x10
+#define S2255_USB_XFER_SIZE    (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 SYS_FRAMES_MAXSIZE     (720*288*2*2 + 4096)
+#define DEF_USB_BLOCK          S2255_USB_XFER_SIZE
 #define LINE_SZ_4CIFS_NTSC     640
 #define LINE_SZ_2CIFS_NTSC     640
 #define LINE_SZ_1CIFS_NTSC     320
 #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) */
+/* SCALE_4CIFSI is the 2 fields interpolated into one */
+#define SCALE_4CIFSI   4       /* 640x480(NTSC) or 704x576(PAL) high quality */
 
 #define COLOR_YUVPL    1       /* YUV planar */
 #define COLOR_YUVPK    2       /* YUV packed */
 #define COLOR_Y8       4       /* monochrome */
+#define COLOR_JPG       5       /* JPEG */
+#define MASK_COLOR      0xff
+#define MASK_JPG_QUALITY 0xff00
 
 /* frame decimation. Not implemented by V4L yet(experimental in V4L) */
 #define FDEC_1         1       /* capture every frame. default */
@@ -148,16 +159,14 @@ struct s2255_mode {
        u32 restart;    /* if DSP requires restart */
 };
 
-/* frame structure */
-#define FRAME_STATE_UNUSED     0
-#define FRAME_STATE_FILLING    1
-#define FRAME_STATE_FULL       2
 
+#define S2255_READ_IDLE                0
+#define S2255_READ_FRAME       1
 
+/* frame structure */
 struct s2255_framei {
        unsigned long size;
-
-       unsigned long ulState;  /* ulState ==0 unused, 1 being filled, 2 full */
+       unsigned long ulState;  /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
        void *lpvbits;          /* image data */
        unsigned long cur_size; /* current data copied to it */
 };
@@ -174,9 +183,6 @@ struct s2255_bufferi {
 
 struct s2255_dmaqueue {
        struct list_head        active;
-       /* thread for acquisition */
-       struct task_struct      *kthread;
-       int                     frame;
        struct s2255_dev        *dev;
        int                     channel;
 };
@@ -188,6 +194,10 @@ struct s2255_dmaqueue {
 #define S2255_FW_FAILED                3
 #define S2255_FW_DISCONNECTING  4
 
+#define S2255_FW_MARKER                cpu_to_le32(0x22552f2f)
+/* 2255 read states */
+#define S2255_READ_IDLE         0
+#define S2255_READ_FRAME        1
 struct s2255_fw {
        int                   fw_loaded;
        int                   fw_size;
@@ -195,7 +205,6 @@ struct s2255_fw {
        atomic_t              fw_state;
        void                  *pfw_data;
        wait_queue_head_t     wait_fw;
-       struct timer_list     dsp_wait;
        const struct firmware *fw;
 };
 
@@ -203,16 +212,11 @@ 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_fmt; /*forward declaration */
@@ -232,20 +236,32 @@ struct s2255_dev {
        struct list_head        s2255_devlist;
        struct timer_list       timer;
        struct s2255_fw *fw_data;
-       int                     board_num;
-       int                     is_open;
        struct s2255_pipeinfo   pipes[MAX_PIPE_BUFFERS];
        struct s2255_bufferi            buffer[MAX_CHANNELS];
        struct s2255_mode       mode[MAX_CHANNELS];
+       /* jpeg compression */
+       struct v4l2_jpegcompression jc[MAX_CHANNELS];
+       /* capture parameters (for high quality mode full size) */
+       struct v4l2_captureparm cap_parm[MAX_CHANNELS];
        const struct s2255_fmt  *cur_fmt[MAX_CHANNELS];
        int                     cur_frame[MAX_CHANNELS];
        int                     last_frame[MAX_CHANNELS];
        u32                     cc;     /* current channel */
        int                     b_acquire[MAX_CHANNELS];
+       /* allocated image size */
        unsigned long           req_image_size[MAX_CHANNELS];
+       /* received packet size */
+       unsigned long           pkt_size[MAX_CHANNELS];
        int                     bad_payload[MAX_CHANNELS];
        unsigned long           frame_count[MAX_CHANNELS];
        int                     frame_ready;
+       /* if JPEG image */
+       int                     jpg_size[MAX_CHANNELS];
+       /* if channel configured to default state */
+       int                     chn_configured[MAX_CHANNELS];
+       wait_queue_head_t       wait_setmode[MAX_CHANNELS];
+       int                     setmode_ready[MAX_CHANNELS];
+       int                     chn_ready;
        struct kref             kref;
        spinlock_t              slock;
 };
@@ -278,9 +294,10 @@ struct s2255_fh {
        int                     resources[MAX_CHANNELS];
 };
 
-#define CUR_USB_FWVER  774     /* current cypress EEPROM firmware version */
+/* current cypress EEPROM firmware version */
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 6)
 #define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    13
+#define S2255_MINOR_VERSION    14
 #define S2255_RELEASE          0
 #define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
                                               S2255_MINOR_VERSION, \
@@ -306,21 +323,30 @@ static void s2255_stop_readpipe(struct s2255_dev *dev);
 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 void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn);
+                          int chn, int jpgsize);
 static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
                          struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_exit_v4l(struct s2255_dev *dev);
-static void s2255_fwload_start(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev, int reset);
+static void s2255_destroy(struct kref *kref);
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+                            u16 index, u16 value, void *buf,
+                            s32 buf_len, int bOut);
+
+/* dev_err macro with driver name */
+#define S2255_DRIVER_NAME "s2255"
+#define s2255_dev_err(dev, fmt, arg...)                                        \
+               dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
 
 #define dprintk(level, fmt, arg...)                                    \
        do {                                                            \
                if (*s2255_debug >= (level)) {                          \
-                       printk(KERN_DEBUG "s2255: " fmt, ##arg);        \
+                       printk(KERN_DEBUG S2255_DRIVER_NAME             \
+                               ": " fmt, ##arg);                       \
                }                                                       \
        } while (0)
 
-
 static struct usb_driver s2255_driver;
 
 
@@ -407,6 +433,10 @@ static const struct s2255_fmt formats[] = {
                .fourcc = V4L2_PIX_FMT_UYVY,
                .depth = 16
        }, {
+               .name = "JPG",
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .depth = 24
+       }, {
                .name = "8bpp GREY",
                .fourcc = V4L2_PIX_FMT_GREY,
                .depth = 8
@@ -464,6 +494,13 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
        return;
 }
 
+static void s2255_reset_dsppower(struct s2255_dev *dev)
+{
+       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+       msleep(10);
+       s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+       return;
+}
 
 /* kickstarts the firmware loading. from probe
  */
@@ -480,18 +517,6 @@ static void s2255_timer(unsigned long user_data)
        }
 }
 
-/* called when DSP is up and running.  DSP is guaranteed to
-   be running after S2255_DSP_BOOTTIME */
-static void s2255_dsp_running(unsigned long user_data)
-{
-       struct s2255_fw *data = (struct s2255_fw *)user_data;
-       dprintk(1, "dsp running\n");
-       atomic_set(&data->fw_state, S2255_FW_SUCCESS);
-       wake_up(&data->wait_fw);
-       printk(KERN_INFO "s2255: firmware loaded successfully\n");
-       return;
-}
-
 
 /* this loads the firmware asynchronously.
    Originally this was done synchroously in probe.
@@ -506,14 +531,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
        int len;
        dprintk(100, "udev %p urb %p", udev, urb);
        if (urb->status) {
-               dev_err(&udev->dev, "URB failed with status %d", urb->status);
+               dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
                atomic_set(&data->fw_state, S2255_FW_FAILED);
                /* wake up anything waiting for the firmware */
                wake_up(&data->wait_fw);
                return;
        }
        if (data->fw_urb == NULL) {
-               dev_err(&udev->dev, "s2255 disconnected\n");
+               s2255_dev_err(&udev->dev, "disconnected\n");
                atomic_set(&data->fw_state, S2255_FW_FAILED);
                /* wake up anything waiting for the firmware */
                wake_up(&data->wait_fw);
@@ -549,19 +574,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
                }
                data->fw_loaded += len;
        } else {
-               init_timer(&data->dsp_wait);
-               data->dsp_wait.function = s2255_dsp_running;
-               data->dsp_wait.data = (unsigned long)data;
                atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
-               mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
-                         + jiffies);
        }
        dprintk(100, "2255 complete done\n");
        return;
 
 }
 
-static int s2255_got_frame(struct s2255_dev *dev, int chn)
+static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
 {
        struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
        struct s2255_buffer *buf;
@@ -586,8 +606,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn)
        list_del(&buf->vb.queue);
        do_gettimeofday(&buf->vb.ts);
        dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
-
-       s2255_fillbuff(dev, buf, dma_q->channel);
+       s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
        wake_up(&buf->vb.done);
        dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
 unlock:
@@ -621,7 +640,7 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
  *
  */
 static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn)
+                          int chn, int jpgsize)
 {
        int pos = 0;
        struct timeval ts;
@@ -649,6 +668,10 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                case V4L2_PIX_FMT_GREY:
                        memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
                        break;
+               case V4L2_PIX_FMT_JPEG:
+                       buf->vb.size = jpgsize;
+                       memcpy(vbuf, tmpbuf, buf->vb.size);
+                       break;
                case V4L2_PIX_FMT_YUV422P:
                        memcpy(vbuf, tmpbuf,
                               buf->vb.width * buf->vb.height * 2);
@@ -657,9 +680,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                        printk(KERN_DEBUG "s2255: unknown format?\n");
                }
                dev->last_frame[chn] = -1;
-               /* done with the frame, free it */
-               frm->ulState = 0;
-               dprintk(4, "freeing buffer\n");
        } else {
                printk(KERN_ERR "s2255: =======no frame\n");
                return;
@@ -700,7 +720,6 @@ static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
 {
        dprintk(4, "%s\n", __func__);
 
-       videobuf_waiton(&buf->vb, 0, 0);
        videobuf_vmalloc_free(&buf->vb);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
@@ -824,8 +843,7 @@ static int vidioc_querycap(struct file *file, void *priv,
        struct s2255_dev *dev = fh->dev;
        strlcpy(cap->driver, "s2255", sizeof(cap->driver));
        strlcpy(cap->card, "s2255", sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev),
-               sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
        cap->version = S2255_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
@@ -1007,9 +1025,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        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]))
-                       fh->mode.scale = SCALE_4CIFS;
-               else
+               if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) {
+                       if (fh->dev->cap_parm[fh->channel].capturemode &
+                           V4L2_MODE_HIGHQUALITY) {
+                               fh->mode.scale = SCALE_4CIFSI;
+                               dprintk(2, "scale 4CIFSI\n");
+                       } else {
+                               fh->mode.scale = SCALE_4CIFS;
+                               dprintk(2, "scale 4CIFS\n");
+                       }
+               } else
                        fh->mode.scale = SCALE_2CIFS;
 
        } else {
@@ -1021,6 +1046,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        case V4L2_PIX_FMT_GREY:
                fh->mode.color = COLOR_Y8;
                break;
+       case V4L2_PIX_FMT_JPEG:
+               fh->mode.color = COLOR_JPG |
+                       (fh->dev->jc[fh->channel].quality << 8);
+               break;
        case V4L2_PIX_FMT_YUV422P:
                fh->mode.color = COLOR_YUVPL;
                break;
@@ -1106,6 +1135,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        if (mode->format == FORMAT_NTSC) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_NTSC;
                        break;
@@ -1123,6 +1153,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        } else if (mode->format == FORMAT_PAL) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_PAL;
                        break;
@@ -1139,7 +1170,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
                }
        }
        outImageSize = linesPerFrame * pixelsPerLine;
-       if (mode->color != COLOR_Y8) {
+       if ((mode->color & MASK_COLOR) != COLOR_Y8) {
                /* 2 bytes/pixel if not monochrome */
                outImageSize *= 2;
        }
@@ -1185,12 +1216,17 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        u32 *buffer;
        unsigned long chn_rev;
 
+       mutex_lock(&dev->lock);
        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);
 
+       /* if JPEG, set the quality */
+       if ((mode->color & MASK_COLOR) == COLOR_JPG)
+               mode->color = (dev->jc[chn].quality << 8) | COLOR_JPG;
+
        /* save the mode */
        dev->mode[chn] = *mode;
        dev->req_image_size[chn] = get_transfer_size(mode);
@@ -1199,6 +1235,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
+               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
 
@@ -1207,6 +1244,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        buffer[1] = (u32) chn_rev;
        buffer[2] = CMD_SET_MODE;
        memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
+       dev->setmode_ready[chn] = 0;
        res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
        if (debug)
                dump_verify_mode(dev, mode);
@@ -1214,12 +1252,19 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        dprintk(1, "set mode done chn %lu, %d\n", chn, res);
 
        /* wait at least 3 frames before continuing */
-       if (mode->restart)
-               msleep(125);
+       if (mode->restart) {
+               wait_event_timeout(dev->wait_setmode[chn],
+                                  (dev->setmode_ready[chn] != 0),
+                                  msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
+               if (dev->setmode_ready[chn] != 1) {
+                       printk(KERN_DEBUG "s2255: no set mode response\n");
+                       res = -EFAULT;
+               }
+       }
 
        /* clear the restart flag */
        dev->mode[chn].restart = 0;
-
+       mutex_unlock(&dev->lock);
        return res;
 }
 
@@ -1243,7 +1288,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        }
 
        if (!res_get(dev, fh)) {
-               dev_err(&dev->udev->dev, "s2255: stream busy\n");
+               s2255_dev_err(&dev->udev->dev, "stream busy\n");
                return -EBUSY;
        }
 
@@ -1270,7 +1315,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        dev->cur_frame[chn] = 0;
        dev->frame_count[chn] = 0;
        for (j = 0; j < SYS_FRAMES; j++) {
-               dev->buffer[chn].frame[j].ulState = 0;
+               dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
                dev->buffer[chn].frame[j].cur_size = 0;
        }
        res = videobuf_streamon(&fh->vb_vidq);
@@ -1285,7 +1330,6 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       int res;
        struct s2255_fh *fh = priv;
        struct s2255_dev *dev = fh->dev;
 
@@ -1299,9 +1343,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
                return -EINVAL;
        }
        s2255_stop_acquire(dev, fh->channel);
-       res = videobuf_streamoff(&fh->vb_vidq);
-       if (res < 0)
-               return res;
+       videobuf_streamoff(&fh->vb_vidq);
        res_free(dev, fh);
        return 0;
 }
@@ -1446,15 +1488,64 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int s2255_open(struct inode *inode, struct file *file)
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *jc)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       *jc = dev->jc[fh->channel];
+       dprintk(2, "getting jpegcompression, quality %d\n", jc->quality);
+       return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *jc)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       if (jc->quality < 0 || jc->quality > 100)
+               return -EINVAL;
+       dev->jc[fh->channel].quality = jc->quality;
+       dprintk(2, "setting jpeg quality %d\n", jc->quality);
+       return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
+       dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+       return 0;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
+       dprintk(2, "setting param capture mode %d\n",
+               sp->parm.capture.capturemode);
+       return 0;
+}
+static int s2255_open(struct file *file)
 {
-       int minor = iminor(inode);
+       int minor = video_devdata(file)->minor;
        struct s2255_dev *h, *dev = NULL;
        struct s2255_fh *fh;
        struct list_head *list;
        enum v4l2_buf_type type = 0;
        int i = 0;
        int cur_channel = -1;
+       int state;
        dprintk(1, "s2255: open called (minor=%d)\n", minor);
 
        lock_kernel();
@@ -1471,47 +1562,78 @@ static int s2255_open(struct inode *inode, struct file *file)
 
        if ((NULL == dev) || (cur_channel == -1)) {
                unlock_kernel();
-               dprintk(1, "s2255: openv4l no dev\n");
+               printk(KERN_INFO "s2255: openv4l no dev\n");
                return -ENODEV;
        }
 
+       if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) {
+               unlock_kernel();
+               printk(KERN_INFO "disconnecting\n");
+               return -ENODEV;
+       }
+       kref_get(&dev->kref);
        mutex_lock(&dev->open_lock);
 
        dev->users[cur_channel]++;
        dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
 
-       if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
-               err("2255 firmware load failed. retrying.\n");
-               s2255_fwload_start(dev);
+       switch (atomic_read(&dev->fw_data->fw_state)) {
+       case S2255_FW_FAILED:
+               s2255_dev_err(&dev->udev->dev,
+                       "firmware load failed. retrying.\n");
+               s2255_fwload_start(dev, 1);
                wait_event_timeout(dev->fw_data->wait_fw,
-                                  (atomic_read(&dev->fw_data->fw_state)
-                                   != S2255_FW_NOTLOADED),
+                                  ((atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_SUCCESS) ||
+                                   (atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_DISCONNECTING)),
                                   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-               if (atomic_read(&dev->fw_data->fw_state)
-                   != S2255_FW_SUCCESS) {
-                       printk(KERN_INFO "2255 FW load failed.\n");
-                       dev->users[cur_channel]--;
-                       mutex_unlock(&dev->open_lock);
-                       unlock_kernel();
-                       return -EFAULT;
-               }
-       } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+               break;
+       case S2255_FW_NOTLOADED:
+       case S2255_FW_LOADED_DSPWAIT:
                /* give S2255_LOAD_TIMEOUT time for firmware to load in case
                   driver loaded and then device immediately opened */
                printk(KERN_INFO "%s waiting for firmware load\n", __func__);
                wait_event_timeout(dev->fw_data->wait_fw,
-                                  (atomic_read(&dev->fw_data->fw_state)
-                                  != S2255_FW_NOTLOADED),
-                                  msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-               if (atomic_read(&dev->fw_data->fw_state)
-                   != S2255_FW_SUCCESS) {
-                       printk(KERN_INFO "2255 firmware not loaded"
-                              "try again\n");
-                       dev->users[cur_channel]--;
-                       mutex_unlock(&dev->open_lock);
-                       unlock_kernel();
-                       return -EBUSY;
+                                  ((atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_SUCCESS) ||
+                                   (atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_DISCONNECTING)),
+                       msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+               break;
+       case S2255_FW_SUCCESS:
+       default:
+               break;
+       }
+       state = atomic_read(&dev->fw_data->fw_state);
+       if (state != S2255_FW_SUCCESS) {
+               int rc;
+               switch (state) {
+               case S2255_FW_FAILED:
+                       printk(KERN_INFO "2255 FW load failed. %d\n", state);
+                       rc = -ENODEV;
+                       break;
+               case S2255_FW_DISCONNECTING:
+                       printk(KERN_INFO "%s: disconnecting\n", __func__);
+                       rc = -ENODEV;
+                       break;
+               case S2255_FW_LOADED_DSPWAIT:
+               case S2255_FW_NOTLOADED:
+                       printk(KERN_INFO "%s: firmware not loaded yet"
+                              "please try again later\n",
+                              __func__);
+                       rc = -EAGAIN;
+                       break;
+               default:
+                       printk(KERN_INFO "%s: unknown state\n", __func__);
+                       rc = -EFAULT;
+                       break;
                }
+               dev->users[cur_channel]--;
+               mutex_unlock(&dev->open_lock);
+               kref_put(&dev->kref, s2255_destroy);
+               unlock_kernel();
+               return rc;
        }
 
        /* allocate + initialize per filehandle data */
@@ -1519,6 +1641,7 @@ static int s2255_open(struct inode *inode, struct file *file)
        if (NULL == fh) {
                dev->users[cur_channel]--;
                mutex_unlock(&dev->open_lock);
+               kref_put(&dev->kref, s2255_destroy);
                unlock_kernel();
                return -ENOMEM;
        }
@@ -1533,6 +1656,13 @@ static int s2255_open(struct inode *inode, struct file *file)
        fh->height = NUM_LINES_4CIFS_NTSC * 2;
        fh->channel = cur_channel;
 
+       /* configure channel to default state */
+       if (!dev->chn_configured[cur_channel]) {
+               s2255_set_mode(dev, cur_channel, &fh->mode);
+               dev->chn_configured[cur_channel] = 1;
+       }
+
+
        /* Put all controls at a sane state */
        for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
                qctl_regs[i] = s2255_qctrl[i].default_value;
@@ -1551,7 +1681,6 @@ static int s2255_open(struct inode *inode, struct file *file)
                                    V4L2_FIELD_INTERLACED,
                                    sizeof(struct s2255_buffer), fh);
 
-       kref_get(&dev->kref);
        mutex_unlock(&dev->open_lock);
        unlock_kernel();
        return 0;
@@ -1575,30 +1704,24 @@ static unsigned int s2255_poll(struct file *file,
 static void s2255_destroy(struct kref *kref)
 {
        struct s2255_dev *dev = to_s2255_dev(kref);
+       struct list_head *list;
+       int i;
        if (!dev) {
                printk(KERN_ERR "s2255drv: kref problem\n");
                return;
        }
-
-       /*
-        * Wake up any firmware load waiting (only done in .open,
-        * which holds the open_lock mutex)
-        */
        atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
        wake_up(&dev->fw_data->wait_fw);
-
-       /* prevent s2255_disconnect from racing s2255_open */
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               dev->setmode_ready[i] = 1;
+               wake_up(&dev->wait_setmode[i]);
+       }
        mutex_lock(&dev->open_lock);
+       /* reset the DSP so firmware can be reload next time */
+       s2255_reset_dsppower(dev);
        s2255_exit_v4l(dev);
-       /*
-        * device unregistered so no longer possible to open. open_mutex
-        *  can be unlocked and timers deleted afterwards.
-        */
-       mutex_unlock(&dev->open_lock);
-
        /* board shutdown stops the read pipe if it is running */
        s2255_board_shutdown(dev);
-
        /* make sure firmware still not trying to load */
        del_timer(&dev->timer);  /* only started in .probe and .open */
 
@@ -1608,30 +1731,26 @@ static void s2255_destroy(struct kref *kref)
                usb_free_urb(dev->fw_data->fw_urb);
                dev->fw_data->fw_urb = NULL;
        }
-
-       /*
-        * delete the dsp_wait timer, which sets the firmware
-        * state on completion.  This is done before fw_data
-        * is freed below.
-        */
-
-       del_timer(&dev->fw_data->dsp_wait); /* only started in .open */
-
        if (dev->fw_data->fw)
                release_firmware(dev->fw_data->fw);
        kfree(dev->fw_data->pfw_data);
        kfree(dev->fw_data);
-
        usb_put_dev(dev->udev);
        dprintk(1, "%s", __func__);
+
+       while (!list_empty(&s2255_devlist)) {
+               list = s2255_devlist.next;
+               list_del(list);
+       }
+       mutex_unlock(&dev->open_lock);
        kfree(dev);
 }
 
-static int s2255_close(struct inode *inode, struct file *file)
+static int s2255_close(struct file *file)
 {
        struct s2255_fh *fh = file->private_data;
        struct s2255_dev *dev = fh->dev;
-       int minor = iminor(inode);
+       int minor = video_devdata(file)->minor;
        if (!dev)
                return -ENODEV;
 
@@ -1675,15 +1794,13 @@ static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
        return ret;
 }
 
-static const struct file_operations s2255_fops_v4l = {
+static const struct v4l2_file_operations s2255_fops_v4l = {
        .owner = THIS_MODULE,
        .open = s2255_open,
        .release = s2255_close,
        .poll = s2255_poll,
        .ioctl = video_ioctl2,  /* V4L2 ioctl handler */
-       .compat_ioctl = v4l_compat_ioctl32,
        .mmap = s2255_mmap_v4l,
-       .llseek = no_llseek,
 };
 
 static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
@@ -1708,6 +1825,10 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf = vidioc_cgmbuf,
 #endif
+       .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+       .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+       .vidioc_s_parm = vidioc_s_parm,
+       .vidioc_g_parm = vidioc_g_parm,
 };
 
 static struct video_device template = {
@@ -1733,7 +1854,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                INIT_LIST_HEAD(&dev->vidq[i].active);
                dev->vidq[i].dev = dev;
                dev->vidq[i].channel = i;
-               dev->vidq[i].kthread = NULL;
                /* register 4 video devices */
                dev->vdev[i] = video_device_alloc();
                memcpy(dev->vdev[i], &template, sizeof(struct video_device));
@@ -1746,7 +1866,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                        ret = video_register_device(dev->vdev[i],
                                                    VFL_TYPE_GRABBER,
                                                    cur_nr + i);
-               dev->vdev[i]->priv = dev;
+               video_set_drvdata(dev->vdev[i], dev);
 
                if (ret != 0) {
                        dev_err(&dev->udev->dev,
@@ -1754,24 +1874,24 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                        return ret;
                }
        }
-       printk(KERN_INFO "Sensoray 2255 V4L driver\n");
+       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
+              S2255_MAJOR_VERSION,
+              S2255_MINOR_VERSION);
        return ret;
 }
 
 static void s2255_exit_v4l(struct s2255_dev *dev)
 {
-       struct list_head *list;
+
        int i;
-       /* unregister the video devices */
-       while (!list_empty(&s2255_devlist)) {
-               list = s2255_devlist.next;
-               list_del(list);
-       }
        for (i = 0; i < MAX_CHANNELS; i++) {
-               if (-1 != dev->vdev[i]->minor)
+               if (-1 != dev->vdev[i]->minor) {
                        video_unregister_device(dev->vdev[i]);
-               else
+                       printk(KERN_INFO "s2255 unregistered\n");
+               } else {
                        video_device_release(dev->vdev[i]);
+                       printk(KERN_INFO "s2255 released\n");
+               }
        }
 }
 
@@ -1781,134 +1901,123 @@ static void s2255_exit_v4l(struct s2255_dev *dev)
  * function again).
  *
  * Received frame structure:
- * bytes 0-3:  marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 0-3:  marker : 0x2255DA4AL (S2255_MARKER_FRAME)
  * bytes 4-7:  channel: 0-3
  * 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 *pipe_info)
 {
-       static int dbgsync; /* = 0; */
        char *pdest;
        u32 offset = 0;
-       int bsync = 0;
-       int btrunc = 0;
+       int bframe = 0;
        char *psrc;
        unsigned long copy_size;
        unsigned long size;
        s32 idx = -1;
        struct s2255_framei *frm;
        unsigned char *pdata;
-       unsigned long cur_size;
-       int bsearch = 0;
-       struct s2255_bufferi *buf;
+
        dprintk(100, "buffer to user\n");
 
        idx = dev->cur_frame[dev->cc];
-       buf = &dev->buffer[dev->cc];
-       frm = &buf->frame[idx];
-
-       if (frm->ulState == 0) {
-               frm->ulState = 1;
-               frm->cur_size = 0;
-               bsearch = 1;
-       } else if (frm->ulState == 2) {
-               /* system frame was not freed */
-               dprintk(2, "sys frame not free.  overrun ringbuf\n");
-               bsearch = 1;
-               frm->ulState = 1;
-               frm->cur_size = 0;
-       }
-
-       if (bsearch) {
-               if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
-                       u32 jj;
-                       if (dbgsync == 0) {
-                               dprintk(3, "not synched, discarding all packets"
-                                       "until marker\n");
+       frm = &dev->buffer[dev->cc].frame[idx];
 
-                               dbgsync++;
-                       }
-                       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;
-                                       dprintk(3,
-                                               "found frame marker at offset:"
-                                               " %d [%x %x]\n", jj, pdata[0],
-                                               pdata[1]);
-                                       offset = jj;
-                                       bsync = 1;
-                                       cc = *(u32 *) (pdata + sizeof(u32));
-                                       if (cc >= MAX_CHANNELS) {
-                                               printk(KERN_ERR
-                                                      "bad channel\n");
-                                               return -EINVAL;
-                                       }
-                                       /* reverse it */
-                                       dev->cc = G_chnmap[cc];
+       if (frm->ulState == S2255_READ_IDLE) {
+               int jj;
+               unsigned int cc;
+               s32 *pdword;
+               int payload;
+               /* search for marker codes */
+               pdata = (unsigned char *)pipe_info->transfer_buffer;
+               for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
+                       switch (*(s32 *) pdata) {
+                       case S2255_MARKER_FRAME:
+                               pdword = (s32 *)pdata;
+                               dprintk(4, "found frame marker at offset:"
+                                       " %d [%x %x]\n", jj, pdata[0],
+                                       pdata[1]);
+                               offset = jj + PREFIX_SIZE;
+                               bframe = 1;
+                               cc = pdword[1];
+                               if (cc >= MAX_CHANNELS) {
+                                       printk(KERN_ERR
+                                              "bad channel\n");
+                                       return -EINVAL;
+                               }
+                               /* reverse it */
+                               dev->cc = G_chnmap[cc];
+                               payload =  pdword[3];
+                               if (payload > dev->req_image_size[dev->cc]) {
+                                       dev->bad_payload[dev->cc]++;
+                                       /* discard the bad frame */
+                                       return -EINVAL;
+                               }
+                               dev->pkt_size[dev->cc] = payload;
+                               dev->jpg_size[dev->cc] = pdword[4];
+                               break;
+                       case S2255_MARKER_RESPONSE:
+                               pdword = (s32 *)pdata;
+                               pdata += DEF_USB_BLOCK;
+                               jj += DEF_USB_BLOCK;
+                               if (pdword[1] >= MAX_CHANNELS)
+                                       break;
+                               cc = G_chnmap[pdword[1]];
+                               if (!(cc >= 0 && cc < MAX_CHANNELS))
                                        break;
+                               switch (pdword[2]) {
+                               case S2255_RESPONSE_SETMODE:
+                                       /* check if channel valid */
+                                       /* set mode ready */
+                                       dev->setmode_ready[cc] = 1;
+                                       wake_up(&dev->wait_setmode[cc]);
+                                       dprintk(5, "setmode ready %d\n", cc);
+                                       break;
+                               case S2255_RESPONSE_FW:
+
+                                       dev->chn_ready |= (1 << cc);
+                                       if ((dev->chn_ready & 0x0f) != 0x0f)
+                                               break;
+                                       /* all channels ready */
+                                       printk(KERN_INFO "s2255: fw loaded\n");
+                                       atomic_set(&dev->fw_data->fw_state,
+                                                  S2255_FW_SUCCESS);
+                                       wake_up(&dev->fw_data->wait_fw);
+                                       break;
+                               default:
+                                       printk(KERN_INFO "s2255 unknown resp\n");
                                }
+                       default:
                                pdata++;
+                               break;
                        }
-                       if (bsync == 0)
-                               return -EINVAL;
-               } else {
-                       u32 *pword;
-                       u32 payload;
-                       int cc;
-                       dbgsync = 0;
-                       bsync = 1;
-                       pword = (u32 *) pipe_info->transfer_buffer;
-                       cc = pword[1];
-
-                       if (cc >= MAX_CHANNELS) {
-                               printk("invalid channel found. "
-                                       "throwing out data!\n");
-                               return -EINVAL;
-                       }
-                       dev->cc = G_chnmap[cc];
-                       payload = pword[2];
-                       if (payload != dev->req_image_size[dev->cc]) {
-                               dprintk(1, "[%d][%d]unexpected payload: %d"
-                                       "required: %lu \n", cc, dev->cc,
-                                       payload, dev->req_image_size[dev->cc]);
-                               dev->bad_payload[dev->cc]++;
-                               /* discard the bad frame */
-                               return -EINVAL;
-                       }
-
-               }
-       }
-       /* search done.  now find out if should be acquiring
-          on this channel */
-       if (!dev->b_acquire[dev->cc]) {
-               frm->ulState = 0;
-               return -EINVAL;
+                       if (bframe)
+                               break;
+               } /* for */
+               if (!bframe)
+                       return -EINVAL;
        }
 
+
        idx = dev->cur_frame[dev->cc];
        frm = &dev->buffer[dev->cc].frame[idx];
 
-       if (frm->ulState == 0) {
-               frm->ulState = 1;
-               frm->cur_size = 0;
-       } else if (frm->ulState == 2) {
-               /* system frame ring buffer overrun */
-               dprintk(2, "sys frame overrun.  overwriting frame %d %d\n",
-                       dev->cc, idx);
-               frm->ulState = 1;
-               frm->cur_size = 0;
+       /* search done.  now find out if should be acquiring on this channel */
+       if (!dev->b_acquire[dev->cc]) {
+               /* we found a frame, but this channel is turned off */
+               frm->ulState = S2255_READ_IDLE;
+               return -EINVAL;
        }
 
-       if (bsync) {
-               /* skip the marker 512 bytes (and offset if out of sync) */
-               psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
-       } else {
-               psrc = (u8 *)pipe_info->transfer_buffer;
+       if (frm->ulState == S2255_READ_IDLE) {
+               frm->ulState = S2255_READ_FRAME;
+               frm->cur_size = 0;
        }
 
+       /* skip the marker 512 bytes (and offset if out of sync) */
+       psrc = (u8 *)pipe_info->transfer_buffer + offset;
+
+
        if (frm->lpvbits == NULL) {
                dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
                        frm, dev, dev->cc, idx);
@@ -1917,33 +2026,20 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 
        pdest = frm->lpvbits + frm->cur_size;
 
-       if (bsync) {
-               copy_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 = pipe_info->cur_transfer_size;
-       }
+       copy_size = (pipe_info->cur_transfer_size - offset);
 
-       cur_size = frm->cur_size;
-       size = dev->req_image_size[dev->cc];
+       size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
 
-       if ((copy_size + cur_size) > size) {
-               copy_size = size - cur_size;
-               btrunc = 1;
-       }
+       /* sanity check on pdest */
+       if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+               memcpy(pdest, psrc, copy_size);
 
-       memcpy(pdest, psrc, copy_size);
-       cur_size += copy_size;
        frm->cur_size += copy_size;
-       dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+       dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+
+       if (frm->cur_size >= size) {
 
-       if (cur_size >= (size - PREFIX_SIZE)) {
                u32 cc = dev->cc;
-               frm->ulState = 2;
                dprintk(2, "****************[%d]Buffer[%d]full*************\n",
                        cc, idx);
                dev->last_frame[cc] = dev->cur_frame[cc];
@@ -1952,16 +2048,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                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 */
+               /* frame ready */
                if (dev->b_acquire[cc])
-                       s2255_got_frame(dev, cc);
+                       s2255_got_frame(dev, cc, dev->jpg_size[cc]);
                dev->frame_count[cc]++;
-       }
-       /* frame was truncated */
-       if (btrunc) {
-               /* return more data to process */
-               return EAGAIN;
+               frm->ulState = S2255_READ_IDLE;
+               frm->cur_size = 0;
+
        }
        /* done successfully */
        return 0;
@@ -1980,8 +2073,8 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
        }
        /* otherwise copy to the system buffers */
        res = save_frame(dev, pipe_info);
-       if (res == EAGAIN)
-               save_frame(dev, pipe_info);
+       if (res != 0)
+               dprintk(4, "s2255: read callback failed\n");
 
        dprintk(50, "callback read video done\n");
        return;
@@ -2101,11 +2194,9 @@ static int s2255_board_init(struct s2255_dev *dev)
 
                memset(pipe, 0, sizeof(*pipe));
                pipe->dev = dev;
-               pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
-               pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+               pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+               pipe->max_transfer_size = S2255_USB_XFER_SIZE;
 
-               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) {
@@ -2118,13 +2209,20 @@ static int s2255_board_init(struct s2255_dev *dev)
        /* 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);
+       printk(KERN_INFO "2255 usb firmware version %d.%d\n",
+              (fw_ver >> 8) & 0xff,
+              fw_ver & 0xff);
+
+       if (fw_ver < S2255_CUR_USB_FWVER)
+               dev_err(&dev->udev->dev,
+                       "usb firmware not up to date %d.%d\n",
+                       (fw_ver >> 8) & 0xff,
+                       fw_ver & 0xff);
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                dev->b_acquire[j] = 0;
                dev->mode[j] = mode_def;
+               dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
                dev->cur_fmt[j] = &formats[0];
                dev->mode[j].restart = 1;
                dev->req_image_size[j] = get_transfer_size(&mode_def);
@@ -2174,18 +2272,20 @@ static void read_pipe_completion(struct urb *purb)
        dprintk(100, "read pipe completion %p, status %d\n", purb,
                purb->status);
        if (pipe_info == NULL) {
-               err("no context !");
+               dev_err(&purb->dev->dev, "no context!\n");
                return;
        }
 
        dev = pipe_info->dev;
        if (dev == NULL) {
-               err("no context !");
+               dev_err(&purb->dev->dev, "no context!\n");
                return;
        }
        status = purb->status;
-       if (status != 0) {
-               dprintk(2, "read_pipe_completion: err\n");
+       /* if shutting down, do not resubmit, exit immediately */
+       if (status == -ESHUTDOWN) {
+               dprintk(2, "read_pipe_completion: err shutdown\n");
+               pipe_info->err_count++;
                return;
        }
 
@@ -2194,9 +2294,13 @@ static void read_pipe_completion(struct urb *purb)
                return;
        }
 
-       s2255_read_video_callback(dev, pipe_info);
+       if (status == 0)
+               s2255_read_video_callback(dev, pipe_info);
+       else {
+               pipe_info->err_count++;
+               dprintk(1, "s2255drv: failed URB %d\n", status);
+       }
 
-       pipe_info->err_count = 0;
        pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
        /* reuse urb */
        usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
@@ -2208,7 +2312,6 @@ static void read_pipe_completion(struct urb *purb)
        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);
                }
        } else {
                dprintk(2, "read pipe complete state 0\n");
@@ -2227,12 +2330,11 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
 
        for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
                pipe_info->state = 1;
-               pipe_info->buf_index = (u32) i;
-               pipe_info->priority_set = 0;
+               pipe_info->err_count = 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");
+                               "ReadStream: Unable to alloc URB\n");
                        return -ENOMEM;
                }
                /* transfer buffer allocated in board_init */
@@ -2242,7 +2344,6 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
                                  pipe_info->cur_transfer_size,
                                  read_pipe_completion, pipe_info);
 
-               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) {
@@ -2329,7 +2430,7 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
        kfree(buffer);
        dev->b_acquire[chn] = 0;
 
-       return 0;
+       return res;
 }
 
 static void s2255_stop_readpipe(struct s2255_dev *dev)
@@ -2337,7 +2438,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
        int j;
 
        if (dev == NULL) {
-               err("s2255: invalid device");
+               s2255_dev_err(&dev->udev->dev, "invalid device\n");
                return;
        }
        dprintk(4, "stop read pipe\n");
@@ -2347,8 +2448,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
                        if (pipe_info->state == 0)
                                continue;
                        pipe_info->state = 0;
-                       pipe_info->prev_state = 1;
-
                }
        }
 
@@ -2365,8 +2464,10 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
        return;
 }
 
-static void s2255_fwload_start(struct s2255_dev *dev)
+static void s2255_fwload_start(struct s2255_dev *dev, int reset)
 {
+       if (reset)
+               s2255_reset_dsppower(dev);
        dev->fw_data->fw_size = dev->fw_data->fw->size;
        atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
        memcpy(dev->fw_data->pfw_data,
@@ -2389,13 +2490,15 @@ static int s2255_probe(struct usb_interface *interface,
        struct usb_endpoint_descriptor *endpoint;
        int i;
        int retval = -ENOMEM;
+       __le32 *pdata;
+       int fw_size;
 
        dprintk(2, "s2255: probe\n");
 
        /* 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");
+               s2255_dev_err(&interface->dev, "out of memory\n");
                goto error;
        }
 
@@ -2429,7 +2532,7 @@ static int s2255_probe(struct usb_interface *interface,
        }
 
        if (!dev->read_endpoint) {
-               dev_err(&interface->dev, "Could not find bulk-in endpoint");
+               dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
                goto error;
        }
 
@@ -2443,6 +2546,8 @@ static int s2255_probe(struct usb_interface *interface,
        dev->timer.data = (unsigned long)dev->fw_data;
 
        init_waitqueue_head(&dev->fw_data->wait_fw);
+       for (i = 0; i < MAX_CHANNELS; i++)
+               init_waitqueue_head(&dev->wait_setmode[i]);
 
 
        dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2462,16 +2567,32 @@ static int s2255_probe(struct usb_interface *interface,
                printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
                goto error;
        }
+       /* check the firmware is valid */
+       fw_size = dev->fw_data->fw->size;
+       pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
 
+       if (*pdata != S2255_FW_MARKER) {
+               printk(KERN_INFO "Firmware invalid.\n");
+               retval = -ENODEV;
+               goto error;
+       } else {
+               /* make sure firmware is the latest */
+               __le32 *pRel;
+               pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
+               printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+       }
        /* loads v4l specific */
        s2255_probe_v4l(dev);
+       usb_reset_device(dev->udev);
        /* load 2255 board specific */
-       s2255_board_init(dev);
+       retval = s2255_board_init(dev);
+       if (retval)
+               goto error;
 
        dprintk(4, "before probe done %p\n", dev);
        spin_lock_init(&dev->slock);
 
-       s2255_fwload_start(dev);
+       s2255_fwload_start(dev, 0);
        dev_info(&interface->dev, "Sensoray 2255 detected\n");
        return 0;
 error:
@@ -2482,18 +2603,34 @@ error:
 static void s2255_disconnect(struct usb_interface *interface)
 {
        struct s2255_dev *dev = NULL;
+       int i;
        dprintk(1, "s2255: disconnect interface %p\n", interface);
        dev = usb_get_intfdata(interface);
+
+       /*
+        * wake up any of the timers to allow open_lock to be
+        * acquired sooner
+        */
+       atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
+       wake_up(&dev->fw_data->wait_fw);
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               dev->setmode_ready[i] = 1;
+               wake_up(&dev->wait_setmode[i]);
+       }
+
+       mutex_lock(&dev->open_lock);
+       usb_set_intfdata(interface, NULL);
+       mutex_unlock(&dev->open_lock);
+
        if (dev) {
                kref_put(&dev->kref, s2255_destroy);
                dprintk(1, "s2255drv: disconnect\n");
                dev_info(&interface->dev, "s2255usb now disconnected\n");
        }
-       usb_set_intfdata(interface, NULL);
 }
 
 static struct usb_driver s2255_driver = {
-       .name = "s2255",
+       .name = S2255_DRIVER_NAME,
        .probe = s2255_probe,
        .disconnect = s2255_disconnect,
        .id_table = s2255_table,
@@ -2507,7 +2644,8 @@ static int __init usb_s2255_init(void)
        result = usb_register(&s2255_driver);
 
        if (result)
-               err("usb_register failed. Error number %d", result);
+               pr_err(KBUILD_MODNAME
+                       ": usb_register failed. Error number %d\n", result);
 
        dprintk(2, "s2255_init: done\n");
        return result;