Merge to kernel-2.6.20-1.2949.fc6.vs2.2.0.1
[linux-2.6.git] / drivers / media / video / sn9c102 / sn9c102_core.c
similarity index 82%
rename from drivers/usb/media/sn9c102_core.c
rename to drivers/media/video/sn9c102/sn9c102_core.c
index c81397e..18458d4 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/stddef.h>
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -49,8 +47,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.26"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
+#define SN9C102_MODULE_VERSION  "1:1.27"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
 
 /*****************************************************************************/
 
@@ -64,44 +62,53 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
 module_param_array(video_nr, short, NULL, 0444);
 MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
-                 " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = 
-                               SN9C102_FORCE_MUNMAP};
+                "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                "\n -1 = use next available (default)"
+                "\n  n = use minor number n (integer >= 0)"
+                "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
+                " cameras this way."
+                "\nFor example:"
+                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                "\nthe second camera and use auto for the first"
+                "\none and for every other camera."
+                "\n");
+
+static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                              SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
+                "\n<0|1[,...]> Force the application to unmap previously"
+                "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                "\nthis feature. This parameter is specific for each"
+                "\ndetected camera."
+                "\n 0 = do not force memory unmapping"
+                "\n 1 = force memory unmapping (save memory)"
+                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\n");
+
+static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                                      SN9C102_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                "\n<n[,...]> Timeout for a video frame in seconds."
+                "\nThis parameter is specific for each detected camera."
+                "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
+                "\n");
 
 #ifdef SN9C102_DEBUG
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
 MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
-                 "\n");
+                "\n<n> Debugging information level, from 0 to 3:"
+                "\n0 = none (use carefully)"
+                "\n1 = critical errors"
+                "\n2 = significant informations"
+                "\n3 = more verbose messages"
+                "\nLevel 3 is useful for testing only, when only "
+                "one device is used."
+                "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
+                "\n");
 #endif
 
 /*****************************************************************************/
@@ -124,16 +131,16 @@ static sn9c102_eof_header_t sn9c102_eof_header[] = {
 
 /*****************************************************************************/
 
-static u32 
-sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
-                        enum sn9c102_io_method io)
+static u32
+sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
+                       enum sn9c102_io_method io)
 {
-       struct v4l2_pix_format* p = &(cam->sensor->pix_format);
-       struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
        const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
        void* buff = NULL;
        u32 i;
 
@@ -225,8 +232,8 @@ int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
                return -1;
 
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, sizeof(buff),
-                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
+                             index, 0, buff, sizeof(buff),
+                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
        if (res < 0) {
                DBG(3, "Failed to write registers (index 0x%02X, error %d)",
                    index, res);
@@ -252,7 +259,7 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
        *buff = value;
 
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
        if (res < 0) {
                DBG(3, "Failed to write a register (value 0x%02X, index "
                       "0x%02X, error %d)", value, index, res);
@@ -273,7 +280,7 @@ static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
        int res;
 
        res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                DBG(3, "Failed to read a register (index 0x%02X, error %d)",
                    index, res);
@@ -312,8 +319,8 @@ sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
 
 
 static int
-sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, 
-                              struct sn9c102_sensor* sensor)
+sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
+                             struct sn9c102_sensor* sensor)
 {
        int r;
        r = sn9c102_read_reg(cam, 0x08);
@@ -322,8 +329,8 @@ sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
 
 
 static int
-sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, 
-                               struct sn9c102_sensor* sensor)
+sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
+                              struct sn9c102_sensor* sensor)
 {
        int r;
        r = sn9c102_read_reg(cam, 0x08);
@@ -331,10 +338,10 @@ sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
 }
 
 
-int 
+int
 sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
-                         struct sn9c102_sensor* sensor, u8 data0, u8 data1,
-                         u8 n, u8 buffer[])
+                        struct sn9c102_sensor* sensor, u8 data0, u8 data1,
+                        u8 n, u8 buffer[])
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -342,12 +349,12 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
 
        /* Write cycle */
        data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
        data[1] = data0; /* I2C slave id */
        data[2] = data1; /* address */
        data[7] = 0x10;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                err += res;
 
@@ -355,12 +362,12 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
 
        /* Read cycle - n bytes */
        data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
-                 (n << 4) | 0x02;
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
+                 (n << 4) | 0x02;
        data[1] = data0;
        data[7] = 0x10;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                err += res;
 
@@ -368,7 +375,7 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
 
        /* The first read byte will be placed in data[4] */
        res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
+                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                err += res;
 
@@ -389,10 +396,10 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
 }
 
 
-int 
+int
 sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
-                          struct sn9c102_sensor* sensor, u8 n, u8 data0,
-                          u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
+                         struct sn9c102_sensor* sensor, u8 n, u8 data0,
+                         u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -400,8 +407,8 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
 
        /* Write cycle. It usually is address + value */
        data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
-                 | ((n - 1) << 4);
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
+                 | ((n - 1) << 4);
        data[1] = data0;
        data[2] = data1;
        data[3] = data2;
@@ -410,7 +417,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        data[6] = data5;
        data[7] = 0x14;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                err += res;
 
@@ -430,38 +437,32 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
 
 int
 sn9c102_i2c_try_read(struct sn9c102_device* cam,
-                     struct sn9c102_sensor* sensor, u8 address)
+                    struct sn9c102_sensor* sensor, u8 address)
 {
        return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
-                                       address, 1, NULL);
+                                       address, 1, NULL);
 }
 
 
 int
 sn9c102_i2c_try_write(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor, u8 address, u8 value)
+                     struct sn9c102_sensor* sensor, u8 address, u8 value)
 {
-       return sn9c102_i2c_try_raw_write(cam, sensor, 3, 
-                                        sensor->i2c_slave_id, address,
-                                        value, 0, 0, 0);
+       return sn9c102_i2c_try_raw_write(cam, sensor, 3,
+                                        sensor->i2c_slave_id, address,
+                                        value, 0, 0, 0);
 }
 
 
 int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return sn9c102_i2c_try_read(cam, cam->sensor, address);
+       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
 }
 
 
 int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
+       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
 }
 
 /*****************************************************************************/
@@ -483,7 +484,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
                n = sizeof(sn9c103_sof_header) / soflen;
        }
 
-       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
                for (j = 0; j < n; j++)
                        /* The invariable part of the header is 6 bytes long */
                        if ((cam->bridge != BRIDGE_SN9C103 &&
@@ -505,7 +506,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
        size_t eoflen = sizeof(sn9c102_eof_header_t), i;
        unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
 
-       if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
                return NULL; /* EOF header does not exist in compressed data */
 
        for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
@@ -517,7 +518,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
 }
 
 
-static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
+static void sn9c102_urb_complete(struct urb *urb)
 {
        struct sn9c102_device* cam = urb->context;
        struct sn9c102_frame_t** f;
@@ -535,7 +536,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                if ((*f))
                        (*f)->state = F_QUEUED;
                DBG(3, "Stream interrupted");
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
        }
 
        if (cam->state & DEV_DISCONNECTED)
@@ -551,15 +552,15 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 
        if (!(*f))
                (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
-                                 frame);
+                                 frame);
 
-       imagesize = (cam->sensor->pix_format.width *
-                    cam->sensor->pix_format.height *
-                    cam->sensor->pix_format.priv) / 8;
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
 
        soflen = (cam->bridge) == BRIDGE_SN9C103 ?
-                                 sizeof(sn9c103_sof_header_t) :
-                                 sizeof(sn9c102_sof_header_t);
+                                 sizeof(sn9c103_sof_header_t) :
+                                 sizeof(sn9c102_sof_header_t);
 
        for (i = 0; i < urb->number_of_packets; i++) {
                unsigned int img, len, status;
@@ -579,7 +580,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 
 redo:
                sof = sn9c102_find_sof_header(cam, pos, len);
-               if (!sof) {
+               if (likely(!sof)) {
                        eof = sn9c102_find_eof_header(cam, pos, len);
                        if ((*f)->state == F_GRABBING) {
 end_of_frame:
@@ -589,8 +590,9 @@ end_of_frame:
                                        img = (eof > pos) ? eof - pos - 1 : 0;
 
                                if ((*f)->buf.bytesused+img > imagesize) {
-                                       u32 b = (*f)->buf.bytesused + img -
-                                               imagesize;
+                                       u32 b;
+                                       b = (*f)->buf.bytesused + img -
+                                           imagesize;
                                        img = imagesize - (*f)->buf.bytesused;
                                        DBG(3, "Expected EOF not found: "
                                               "video frame cut");
@@ -608,19 +610,20 @@ end_of_frame:
                                (*f)->buf.bytesused += img;
 
                                if ((*f)->buf.bytesused == imagesize ||
-                                   (cam->sensor->pix_format.pixelformat ==
-                                               V4L2_PIX_FMT_SN9C10X && eof)) {
-                                       u32 b = (*f)->buf.bytesused;
+                                   (cam->sensor.pix_format.pixelformat ==
+                                               V4L2_PIX_FMT_SN9C10X && eof)) {
+                                       u32 b;
+                                       b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
                                        spin_lock(&cam->queue_lock);
                                        list_move_tail(&(*f)->frame,
-                                                      &cam->outqueue);
+                                                      &cam->outqueue);
                                        if (!list_empty(&cam->inqueue))
                                                (*f) = list_entry(
-                                                       cam->inqueue.next,
-                                                       struct sn9c102_frame_t,
-                                                       frame );
+                                                       cam->inqueue.next,
+                                                       struct sn9c102_frame_t,
+                                                       frame );
                                        else
                                                (*f) = NULL;
                                        spin_unlock(&cam->queue_lock);
@@ -635,7 +638,7 @@ end_of_frame:
                                } else if (eof) {
                                        (*f)->state = F_ERROR;
                                        DBG(3, "Not expected EOF after %lu "
-                                              "bytes of image data", 
+                                              "bytes of image data",
                                            (unsigned long)
                                            ((*f)->buf.bytesused));
                                }
@@ -667,13 +670,13 @@ start_of_frame:
                        if (eof && eof < sof)
                                goto end_of_frame; /* (1) */
                        else {
-                               if (cam->sensor->pix_format.pixelformat ==
+                               if (cam->sensor.pix_format.pixelformat ==
                                    V4L2_PIX_FMT_SN9C10X) {
                                        eof = sof - soflen;
                                        goto end_of_frame;
                                } else {
                                        DBG(3, "SOF before expected EOF after "
-                                              "%lu bytes of image data", 
+                                              "%lu bytes of image data",
                                            (unsigned long)
                                            ((*f)->buf.bytesused));
                                        goto start_of_frame;
@@ -699,18 +702,18 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
        const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1023};
+                                                      680, 800, 900, 1023};
        const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1003};
+                                                      680, 800, 900, 1003};
        const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
-                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
-                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
+                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
        s8 i, j;
        int err = 0;
 
        for (i = 0; i < SN9C102_URBS; i++) {
                cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
+                                                 GFP_KERNEL);
                if (!cam->transfer_buffer[i]) {
                        err = -ENOMEM;
                        DBG(1, "Not enough memory");
@@ -772,7 +775,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
        return 0;
 
 free_urbs:
-       for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
+       for (i = 0; i < SN9C102_URBS; i++)
                usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -808,20 +811,21 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
 
 static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 {
-       int err = 0;
+       long timeout;
 
        cam->stream = STREAM_INTERRUPT;
-       err = wait_event_timeout(cam->wait_stream,
-                                (cam->stream == STREAM_OFF) ||
-                                (cam->state & DEV_DISCONNECTED),
-                                SN9C102_URB_TIMEOUT);
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    SN9C102_URB_TIMEOUT);
        if (cam->state & DEV_DISCONNECTED)
                return -ENODEV;
-       else if (err) {
+       else if (cam->stream != STREAM_OFF) {
                cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "The camera is misconfigured. To use it, close and "
-                      "open /dev/video%d again.", cam->v4ldev->minor);
-               return err;
+               DBG(1, "URB timeout reached. The camera is misconfigured. "
+                      "To use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
        }
 
        return 0;
@@ -857,7 +861,7 @@ static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
 
 /*
    NOTE 1: being inside one of the following methods implies that the v4l
-           device exists for sure (see kobjects and reference counters)
+          device exists for sure (see kobjects and reference counters)
    NOTE 2: buffers are PAGE_SIZE long
 */
 
@@ -866,42 +870,42 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
        struct sn9c102_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        count = sprintf(buf, "%u\n", cam->sysfs.reg);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
-} 
+}
 
 
-static ssize_t 
+static ssize_t
 sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        index = sn9c102_strtou8(buf, len, &count);
        if (index > 0x1f || !count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
@@ -910,7 +914,7 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -922,17 +926,17 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -940,10 +944,10 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
-} 
+}
 
 
 static ssize_t
@@ -954,24 +958,24 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
        err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
        if (err) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -979,7 +983,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -990,12 +994,12 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
        struct sn9c102_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
@@ -1003,31 +1007,31 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
 
 
-static ssize_t 
+static ssize_t
 sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        index = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
@@ -1036,7 +1040,7 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -1048,22 +1052,22 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) {
-               up(&sn9c102_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENOSYS;
        }
 
        if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -1071,10 +1075,10 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
-} 
+}
 
 
 static ssize_t
@@ -1085,29 +1089,29 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
-               up(&sn9c102_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENOSYS;
        }
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
        err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
        if (err) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -1115,7 +1119,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.i2c_reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -1130,18 +1134,18 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
        u8 value;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        bridge = cam->bridge;
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count)
@@ -1218,41 +1222,71 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
        DBG(3, "Frame header, read bytes: %zd", count);
 
        return count;
-} 
+}
 
 
 static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_reg, sn9c102_store_reg);
+                        sn9c102_show_reg, sn9c102_store_reg);
 static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_val, sn9c102_store_val);
+                        sn9c102_show_val, sn9c102_store_val);
 static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+                        sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
 static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+                        sn9c102_show_i2c_val, sn9c102_store_i2c_val);
 static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
 static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
 static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
 static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
-                         sn9c102_show_frame_header, NULL);
+                        sn9c102_show_frame_header, NULL);
 
 
-static void sn9c102_create_sysfs(struct sn9c102_device* cam)
+static int sn9c102_create_sysfs(struct sn9c102_device* cam)
 {
        struct video_device *v4ldev = cam->v4ldev;
+       int rc;
 
-       video_device_create_file(v4ldev, &class_device_attr_reg);
-       video_device_create_file(v4ldev, &class_device_attr_val);
-       video_device_create_file(v4ldev, &class_device_attr_frame_header);
-       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
-               video_device_create_file(v4ldev, &class_device_attr_green);
-       else if (cam->bridge == BRIDGE_SN9C103) {
-               video_device_create_file(v4ldev, &class_device_attr_blue);
-               video_device_create_file(v4ldev, &class_device_attr_red);
+       rc = video_device_create_file(v4ldev, &class_device_attr_reg);
+       if (rc) goto err;
+       rc = video_device_create_file(v4ldev, &class_device_attr_val);
+       if (rc) goto err_reg;
+       rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
+       if (rc) goto err_val;
+
+       if (cam->sensor.sysfs_ops) {
+               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               if (rc) goto err_frhead;
+               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+               if (rc) goto err_i2c_reg;
        }
-       if (cam->sensor && cam->sensor->sysfs_ops) {
-               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
+               rc = video_device_create_file(v4ldev, &class_device_attr_green);
+               if (rc) goto err_i2c_val;
+       } else if (cam->bridge == BRIDGE_SN9C103) {
+               rc = video_device_create_file(v4ldev, &class_device_attr_blue);
+               if (rc) goto err_i2c_val;
+               rc = video_device_create_file(v4ldev, &class_device_attr_red);
+               if (rc) goto err_blue;
        }
+
+       return 0;
+
+err_blue:
+       video_device_remove_file(v4ldev, &class_device_attr_blue);
+err_i2c_val:
+       if (cam->sensor.sysfs_ops)
+               video_device_remove_file(v4ldev, &class_device_attr_i2c_val);
+err_i2c_reg:
+       if (cam->sensor.sysfs_ops)
+               video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+err_frhead:
+       video_device_remove_file(v4ldev, &class_device_attr_frame_header);
+err_val:
+       video_device_remove_file(v4ldev, &class_device_attr_val);
+err_reg:
+       video_device_remove_file(v4ldev, &class_device_attr_reg);
+err:
+       return rc;
 }
 #endif /* CONFIG_VIDEO_ADV_DEBUG */
 
@@ -1274,7 +1308,7 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
 
 static int
 sn9c102_set_compression(struct sn9c102_device* cam,
-                        struct v4l2_jpegcompression* compression)
+                       struct v4l2_jpegcompression* compression)
 {
        int err = 0;
 
@@ -1312,7 +1346,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
 
 static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
           v_start = (u8)(rect->top - s->cropcap.bounds.top),
           h_size = (u8)(rect->width / 16),
@@ -1335,7 +1369,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 
 static int sn9c102_init(struct sn9c102_device* cam)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        struct v4l2_queryctrl *qctrl;
        struct v4l2_rect* rect;
@@ -1404,7 +1438,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
        }
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_MUTEX(&cam->fileop_sem);
+               mutex_init(&cam->fileop_mutex);
                spin_lock_init(&cam->queue_lock);
                init_waitqueue_head(&cam->wait_frame);
                init_waitqueue_head(&cam->wait_stream);
@@ -1422,13 +1456,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
 
 static void sn9c102_release_resources(struct sn9c102_device* cam)
 {
-       down(&sn9c102_sysfs_lock);
+       mutex_lock(&sn9c102_sysfs_lock);
 
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        kfree(cam->control_buffer);
 }
@@ -1449,7 +1483,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (down_interruptible(&cam->dev_sem)) {
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
                up_read(&sn9c102_disconnect);
                return -ERESTARTSYS;
        }
@@ -1461,10 +1495,10 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
                if (err) {
                        up_read(&sn9c102_disconnect);
                        return err;
@@ -1473,7 +1507,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
                        up_read(&sn9c102_disconnect);
                        return -ENODEV;
                }
-               down(&cam->dev_sem);
+               mutex_lock(&cam->dev_mutex);
        }
 
 
@@ -1501,7 +1535,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        up_read(&sn9c102_disconnect);
        return err;
 }
@@ -1511,7 +1545,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 
-       down(&cam->dev_sem); /* prevent disconnect() to be called */
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
        sn9c102_stop_transfer(cam);
 
@@ -1519,7 +1553,8 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 
        if (cam->state & DEV_DISCONNECTED) {
                sn9c102_release_resources(cam);
-               up(&cam->dev_sem);
+               usb_put_dev(cam->usbdev);
+               mutex_unlock(&cam->dev_mutex);
                kfree(cam);
                return 0;
        }
@@ -1529,7 +1564,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 }
@@ -1541,35 +1576,36 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        struct sn9c102_frame_t* f, * i;
        unsigned long lock_flags;
+       long timeout;
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io == IO_MMAP) {
                DBG(3, "Close and open the device again to choose "
                       "the read method");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
        if (cam->io == IO_NONE) {
                if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
                        DBG(1, "read() failed, not enough memory");
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENOMEM;
                }
                cam->io = IO_READ;
@@ -1583,30 +1619,32 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        }
 
        if (!count) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return 0;
        }
 
        if (list_empty(&cam->outqueue)) {
                if (filp->f_flags & O_NONBLOCK) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
-               err = wait_event_interruptible
-                     ( cam->wait_frame, 
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err) {
-                       up(&cam->fileop_sem);
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
                }
                if (cam->state & DEV_DISCONNECTED) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENODEV;
                }
-               if (cam->state & DEV_MISCONFIGURED) {
-                       up(&cam->fileop_sem);
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EIO;
                }
        }
@@ -1634,7 +1672,7 @@ exit:
        PDBGG("Frame #%lu, bytes read: %zu",
              (unsigned long)f->buf.index, count);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return count;
 }
@@ -1647,7 +1685,7 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
        unsigned long lock_flags;
        unsigned int mask = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return POLLERR;
 
        if (cam->state & DEV_DISCONNECTED) {
@@ -1663,7 +1701,7 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
 
        if (cam->io == IO_NONE) {
                if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
-                                            IO_READ)) {
+                                            IO_READ)) {
                        DBG(1, "poll() failed, not enough memory");
                        goto error;
                }
@@ -1685,12 +1723,12 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
        if (!list_empty(&cam->outqueue))
                mask |= POLLIN | POLLRDNORM;
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return mask;
 
 error:
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
        return POLLERR;
 }
 
@@ -1720,29 +1758,29 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
+                     start = vma->vm_start;
        void *pos;
        u32 i;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1751,7 +1789,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
                        break;
        }
        if (i == cam->nbuffers) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1761,7 +1799,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        pos = cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
                if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1774,7 +1812,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 
        sn9c102_vm_open(vma);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return 0;
 }
@@ -1788,13 +1826,13 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
                .driver = "sn9c102",
                .version = SN9C102_MODULE_VERSION_CODE,
                .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
+                               V4L2_CAP_STREAMING,
        };
 
        strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
        if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
                strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
+                       sizeof(cap.bus_info));
 
        if (copy_to_user(arg, &cap, sizeof(cap)))
                return -EFAULT;
@@ -1816,6 +1854,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
 
        memset(&i, 0, sizeof(i));
        strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
 
        if (copy_to_user(arg, &i, sizeof(i)))
                return -EFAULT;
@@ -1825,7 +1864,19 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
 
 
 static int
-sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
 {
        int index;
 
@@ -1842,7 +1893,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_queryctrl qc;
        u8 i;
 
@@ -1864,7 +1915,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        int err = 0;
        u8 i;
@@ -1896,7 +1947,7 @@ exit:
 static int
 sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        u8 i;
        int err = 0;
@@ -1909,6 +1960,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 
        for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
                if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
                        if (ctrl.value < s->qctrl[i].minimum ||
                            ctrl.value > s->qctrl[i].maximum)
                                return -ERANGE;
@@ -1931,7 +1984,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
 {
-       struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
 
        cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        cc->pixelaspect.numerator = 1;
@@ -1947,7 +2000,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_crop crop = {
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
        };
@@ -1964,7 +2017,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_crop crop;
        struct v4l2_rect* rect;
        struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -2105,7 +2158,7 @@ static int
 sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
 {
        struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
 
        if (copy_from_user(&format, arg, sizeof(format)))
                return -EFAULT;
@@ -2114,7 +2167,7 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
                return -EINVAL;
 
        pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
        pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
        pfmt->field = V4L2_FIELD_NONE;
        memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
@@ -2128,9 +2181,9 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
 
 static int
 sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
-                         void __user * arg)
+                        void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_format format;
        struct v4l2_pix_format* pix;
        struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2190,7 +2243,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
        pix->priv = pfmt->priv; /* bpp */
        pix->colorspace = pfmt->colorspace;
        pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-                           ? 0 : (pix->width * pix->priv) / 8;
+                           ? 0 : (pix->width * pix->priv) / 8;
        pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
        pix->field = V4L2_FIELD_NONE;
 
@@ -2263,7 +2316,7 @@ static int
 sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
 {
        if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
+                        sizeof(cam->compression)))
                return -EFAULT;
 
        return 0;
@@ -2412,12 +2465,12 @@ sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
 
 static int
 sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
-                     void __user * arg)
+                    void __user * arg)
 {
        struct v4l2_buffer b;
        struct sn9c102_frame_t *f;
        unsigned long lock_flags;
-       int err = 0;
+       long timeout;
 
        if (copy_from_user(&b, arg, sizeof(b)))
                return -EFAULT;
@@ -2430,16 +2483,18 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
                        return -EINVAL;
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               err = wait_event_interruptible
-                     ( cam->wait_frame,
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err)
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
                if (cam->state & DEV_DISCONNECTED)
                        return -ENODEV;
-               if (cam->state & DEV_MISCONFIGURED)
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
                        return -EIO;
        }
 
@@ -2558,7 +2613,7 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
 
 
 static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
-                              unsigned int cmd, void __user * arg)
+                             unsigned int cmd, void __user * arg)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 
@@ -2571,8 +2626,10 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
                return sn9c102_vidioc_enuminput(cam, arg);
 
        case VIDIOC_G_INPUT:
+               return sn9c102_vidioc_g_input(cam, arg);
+
        case VIDIOC_S_INPUT:
-               return sn9c102_vidioc_gs_input(cam, arg);
+               return sn9c102_vidioc_s_input(cam, arg);
 
        case VIDIOC_QUERYCTRL:
                return sn9c102_vidioc_query_ctrl(cam, arg);
@@ -2580,11 +2637,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_G_CTRL:
                return sn9c102_vidioc_g_ctrl(cam, arg);
 
-       case VIDIOC_S_CTRL_OLD:
        case VIDIOC_S_CTRL:
                return sn9c102_vidioc_s_ctrl(cam, arg);
 
-       case VIDIOC_CROPCAP_OLD:
        case VIDIOC_CROPCAP:
                return sn9c102_vidioc_cropcap(cam, arg);
 
@@ -2631,7 +2686,6 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_G_PARM:
                return sn9c102_vidioc_g_parm(cam, arg);
 
-       case VIDIOC_S_PARM_OLD:
        case VIDIOC_S_PARM:
                return sn9c102_vidioc_s_parm(cam, arg);
 
@@ -2650,24 +2704,24 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
 
 
 static int sn9c102_ioctl(struct inode* inode, struct file* filp,
-                         unsigned int cmd, unsigned long arg)
+                        unsigned int cmd, unsigned long arg)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
@@ -2675,7 +2729,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
 
        err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return err;
 }
@@ -2722,7 +2776,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       init_MUTEX(&cam->dev_sem);
+       mutex_init(&cam->dev_mutex);
 
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || r != 0x10) {
@@ -2733,7 +2787,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        }
 
        cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
-                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
+                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
        switch (cam->bridge) {
        case BRIDGE_SN9C101:
        case BRIDGE_SN9C102:
@@ -2752,10 +2806,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        break;
        }
 
-       if (!err && cam->sensor) {
-               DBG(2, "%s image sensor detected", cam->sensor->name);
+       if (!err) {
+               DBG(2, "%s image sensor detected", cam->sensor.name);
                DBG(3, "Support for %s maintained by %s",
-                   cam->sensor->name, cam->sensor->maintainer);
+                   cam->sensor.name, cam->sensor.maintainer);
        } else {
                DBG(1, "No supported image sensor detected");
                err = -ENODEV;
@@ -2776,37 +2830,45 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       down(&cam->dev_sem);
+       mutex_lock(&cam->dev_mutex);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
+                                   video_nr[dev_nr]);
        if (err) {
                DBG(1, "V4L2 device registration failed");
                if (err == -ENFILE && video_nr[dev_nr] == -1)
                        DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               up(&cam->dev_sem);
-               goto fail;
+               goto fail2;
        }
 
        DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
        cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
        dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       sn9c102_create_sysfs(cam);
+       err = sn9c102_create_sysfs(cam);
+       if (err)
+               goto fail3;
        DBG(2, "Optional device control through 'sysfs' interface ready");
 #endif
 
        usb_set_intfdata(intf, cam);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+fail3:
+       video_unregister_device(cam->v4ldev);
+#endif
+fail2:
+       video_nr[dev_nr] = -1;
+       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+       mutex_unlock(&cam->dev_mutex);
 fail:
        if (cam) {
                kfree(cam->control_buffer);
@@ -2827,7 +2889,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
 
        down_write(&sn9c102_disconnect);
 
-       down(&cam->dev_sem); 
+       mutex_lock(&cam->dev_mutex);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
@@ -2841,13 +2903,14 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
                sn9c102_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
        } else {
                cam->state |= DEV_DISCONNECTED;
                sn9c102_release_resources(cam);
        }
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        if (!cam->users)
                kfree(cam);