This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / usb / media / sn9c102_core.c
index e4c44fa..9f775f7 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ * V4L2 driver for SN9C10[12] PC Camera Controllers                        *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -28,6 +28,7 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
+#include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/stddef.h>
 #include <linux/compiler.h>
@@ -52,7 +53,8 @@ MODULE_VERSION(SN9C102_MODULE_VERSION);
 MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
+static unsigned int nv;
+module_param_array(video_nr, short, nv, 0444);
 MODULE_PARM_DESC(video_nr,
                  "\n<-1|n[,...]> Specify V4L2 minor mode number."
                  "\n -1 = use next available (default)"
@@ -100,6 +102,17 @@ static sn9c102_eof_header_t sn9c102_eof_header[] = {
 
 /*****************************************************************************/
 
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long kva, ret;
+
+       kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+       kva |= adr & (PAGE_SIZE-1);
+       ret = __pa(kva);
+       return ret;
+}
+
+
 static void* rvmalloc(size_t size)
 {
        void* mem;
@@ -156,15 +169,15 @@ static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count)
 
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize))))
+               if ((buff = rvmalloc(cam->nbuffers * imagesize)))
                        break;
                cam->nbuffers--;
        }
 
        for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].bufmem = buff + i*imagesize;
                cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.m.offset = i*imagesize;
                cam->frame[i].buf.length = imagesize;
                cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                cam->frame[i].buf.sequence = 0;
@@ -375,7 +388,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        data[4] = data3;
        data[5] = data4;
        data[6] = data5;
-       data[7] = 0x14;
+       data[7] = 0x10;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
                              0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
@@ -387,7 +400,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        if (err)
                DBG(3, "I2C write failed for %s image sensor", sensor->name)
 
-       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
+       PDBGG("I2C write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
              "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
              n, data0, data1, data2, data3, data4, data5)
 
@@ -424,8 +437,7 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 
 /*****************************************************************************/
 
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+static void* sn9c102_find_sof_header(void* mem, size_t len)
 {
        size_t soflen = sizeof(sn9c102_sof_header_t), i;
        u8 j, n = sizeof(sn9c102_sof_header) / soflen;
@@ -441,15 +453,11 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 }
 
 
-static void*
-sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
+static void* sn9c102_find_eof_header(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)
-               return NULL; /* EOF header does not exist in compressed data */
-
        for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
                for (j = 0; j < n; j++)
                        if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
@@ -514,9 +522,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                */
 
 redo:
-               sof = sn9c102_find_sof_header(cam, pos, len);
+               sof = sn9c102_find_sof_header(pos, len);
                if (!sof) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       eof = sn9c102_find_eof_header(pos, len);
                        if ((*f)->state == F_GRABBING) {
 end_of_frame:
                                img = len;
@@ -544,9 +552,7 @@ end_of_frame:
 
                                (*f)->buf.bytesused += img;
 
-                               if ((*f)->buf.bytesused == (*f)->buf.length ||
-                                   (cam->sensor->pix_format.pixelformat ==
-                                               V4L2_PIX_FMT_SN9C10X && eof)) {
+                               if ((*f)->buf.bytesused == (*f)->buf.length) {
                                        u32 b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
@@ -599,20 +605,14 @@ start_of_frame:
                                goto redo;
 
                } else if ((*f)->state == F_GRABBING) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       eof = sn9c102_find_eof_header(pos, len);
                        if (eof && eof < sof)
                                goto end_of_frame; /* (1) */
                        else {
-                               if (cam->sensor->pix_format.pixelformat ==
-                                   V4L2_PIX_FMT_SN9C10X) {
-                                       eof = sof-sizeof(sn9c102_sof_header_t);
-                                       goto end_of_frame;
-                               } else {
-                                       DBG(3, "SOF before expected EOF after "
-                                              "%lu bytes of image data", 
-                                         (unsigned long)((*f)->buf.bytesused))
-                                       goto start_of_frame;
-                               }
+                               DBG(3, "SOF before expected EOF after %lu "
+                                      "bytes of image data", 
+                                   (unsigned long)((*f)->buf.bytesused))
+                               goto start_of_frame;
                        }
                }
        }
@@ -634,7 +634,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
        const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                              680, 800, 900, 1023};
+                                               680, 800, 900, 1023};
        const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
        s8 i, j;
        int err = 0;
@@ -736,29 +736,6 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
        return err;
 }
 
-
-int sn9c102_stream_interrupt(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       cam->stream = STREAM_INTERRUPT;
-       err = wait_event_timeout(cam->wait_stream,
-                                (cam->stream == STREAM_OFF) ||
-                                (cam->state & DEV_DISCONNECTED),
-                                SN9C102_URB_TIMEOUT);
-       if (err) {
-               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;
-       }
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-
-       return 0;
-}
-
 /*****************************************************************************/
 
 static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
@@ -988,11 +965,6 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
                return -ENODEV;
        }
 
-       if (cam->sensor->slave_read_id == SN9C102_I2C_SLAVEID_UNAVAILABLE) {
-               up(&sn9c102_sysfs_lock);
-               return -ENOSYS;
-       }
-
        if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
                up(&sn9c102_sysfs_lock);
                return -EIO;
@@ -1050,79 +1022,15 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
 static ssize_t
 sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
 {
-       struct sn9c102_device* cam;
-       enum sn9c102_bridge bridge;
        ssize_t res = 0;
        u8 value;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               up(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       bridge = cam->bridge;
-
-       up(&sn9c102_sysfs_lock);
-
        value = sn9c102_strtou8(buf, len, &count);
-       if (!count)
+       if (!count || value > 0x0f)
                return -EINVAL;
 
-       switch (bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               if (value > 0x0f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       case BRIDGE_SN9C103:
-               if (value > 0x7f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       }
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
+       if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
                res = sn9c102_store_val(cd, buf, len);
 
        return res;
@@ -1138,8 +1046,6 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
 static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
                          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 void sn9c102_create_sysfs(struct sn9c102_device* cam)
@@ -1148,14 +1054,8 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
 
        video_device_create_file(v4ldev, &class_device_attr_reg);
        video_device_create_file(v4ldev, &class_device_attr_val);
-       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);
-       }
-       if (cam->sensor->slave_write_id != SN9C102_I2C_SLAVEID_UNAVAILABLE ||
-           cam->sensor->slave_read_id != SN9C102_I2C_SLAVEID_UNAVAILABLE) {
+       video_device_create_file(v4ldev, &class_device_attr_green);
+       if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) {
                video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
                video_device_create_file(v4ldev, &class_device_attr_i2c_val);
        }
@@ -1163,35 +1063,6 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
 
 /*****************************************************************************/
 
-static int
-sn9c102_set_format(struct sn9c102_device* cam, struct v4l2_pix_format* fmt)
-{
-       int err = 0;
-
-       if (fmt->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
-       else
-               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
-
-       return err ? -EIO : 0;
-}
-
-
-static int
-sn9c102_set_compression(struct sn9c102_device* cam,
-                        struct v4l2_jpegcompression* compression)
-{
-       int err = 0;
-
-       if (compression->quality == 0)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
-       else if (compression->quality == 1)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
-
-       return err ? -EIO : 0;
-}
-
-
 static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
 {
        u8 r = 0;
@@ -1221,13 +1092,21 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
        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),
-          v_size = (u8)(rect->height / 16);
+          v_size = (u8)(rect->height / 16),
+          ae_strx = 0x00,
+          ae_stry = 0x00,
+          ae_endx = h_size / 2,
+          ae_endy = v_size / 2;
        int err = 0;
 
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
        err += sn9c102_write_reg(cam, h_size, 0x15);
        err += sn9c102_write_reg(cam, v_size, 0x16);
+       err += sn9c102_write_reg(cam, ae_strx, 0x1c);
+       err += sn9c102_write_reg(cam, ae_stry, 0x1d);
+       err += sn9c102_write_reg(cam, ae_endx, 0x1e);
+       err += sn9c102_write_reg(cam, ae_endy, 0x1f);
        if (err)
                return -EIO;
 
@@ -1269,20 +1148,6 @@ static int sn9c102_init(struct sn9c102_device* cam)
                }
        }
 
-       if (!(cam->state & DEV_INITIALIZED))
-               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
-       else
-               err += sn9c102_set_compression(cam, &cam->compression);
-       err += sn9c102_set_format(cam, &s->pix_format);
-       if (err)
-               return err;
-
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
-               DBG(3, "Compressed video format is active, quality %d", 
-                   cam->compression.quality)
-       else
-               DBG(3, "Uncompressed video format is active")
-
        if (s->set_crop)
                if ((err = s->set_crop(cam, rect))) {
                        DBG(3, "set_crop() failed")
@@ -1298,12 +1163,9 @@ static int sn9c102_init(struct sn9c102_device* cam)
                                ctrl.value = qctrl[i].default_value;
                                err = s->set_ctrl(cam, &ctrl);
                                if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name)
+                                       DBG(3, "Set control failed")
                                        return err;
                                }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name)
                        }
        }
 
@@ -1312,7 +1174,6 @@ static int sn9c102_init(struct sn9c102_device* cam)
                spin_lock_init(&cam->queue_lock);
                init_waitqueue_head(&cam->wait_frame);
                init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
                memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
                memcpy(&(s->_rect), &(s->cropcap.defrect), 
                       sizeof(struct v4l2_rect));
@@ -1470,7 +1331,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        }
 
        if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam, cam->nreadbuffers)) {
+               if (!sn9c102_request_buffers(cam, 2)) {
                        DBG(1, "read() failed, not enough memory")
                        up(&cam->fileop_sem);
                        return -ENOMEM;
@@ -1514,8 +1375,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        sn9c102_queue_unusedframes(cam);
 
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
+       if (count > f->buf.length)
+               count = f->buf.length;
 
        if (copy_to_user(buf, f->bufmem, count)) {
                up(&cam->fileop_sem);
@@ -1636,15 +1497,11 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
-       /* VM_IO is eventually going to replace PageReserved altogether */
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
-
        pos = (unsigned long)cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE,
-                                   vma->vm_page_prot)) {
+               page = kvirt_to_pa(pos);
+               if (remap_page_range(vma, start, page, PAGE_SIZE, 
+                                    vma->vm_page_prot)) {
                        up(&cam->fileop_sem);
                        return -EAGAIN;
                }
@@ -1654,6 +1511,8 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        }
 
        vma->vm_ops = &sn9c102_vm_ops;
+       vma->vm_flags &= ~VM_IO; /* not I/O memory */
+       vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
        vma->vm_private_data = &cam->frame[i];
 
        sn9c102_vm_open(vma);
@@ -1678,14 +1537,11 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        .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->dev.bus_id,
-                               sizeof(cap.bus_info));
+               strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));
 
                if (copy_to_user(arg, &cap, sizeof(cap)))
                        return -EFAULT;
@@ -1780,24 +1636,16 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                        return -EFAULT;
 
+               if ((err = s->set_ctrl(cam, &ctrl)))
+                       return err;
+
                n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);
                for (i = 0; i < n; i++)
                        if (ctrl.id == s->qctrl[i].id) {
-                               if (ctrl.value < s->qctrl[i].minimum ||
-                                   ctrl.value > s->qctrl[i].maximum)
-                                       return -ERANGE;
-                               ctrl.value -= ctrl.value % s->qctrl[i].step;
+                               s->_qctrl[i].default_value = ctrl.value;
                                break;
                        }
 
-               if ((err = s->set_ctrl(cam, &ctrl)))
-                       return err;
-
-               s->_qctrl[i].default_value = ctrl.value;
-
-               PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
-                     (unsigned long)ctrl.id, (unsigned long)ctrl.value)
-
                return 0;
        }
 
@@ -1894,9 +1742,22 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                } else
                        scale = 1;
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
+               if (cam->stream == STREAM_ON) {
+                       cam->stream = STREAM_INTERRUPT;
+                       err = wait_event_interruptible
+                             ( cam->wait_stream, 
+                               (cam->stream == STREAM_OFF) ||
+                               (cam->state & DEV_DISCONNECTED) );
+                       if (err) {
+                               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;
+                       }
+                       if (cam->state & DEV_DISCONNECTED)
+                               return -ENODEV;
+               }
 
                if (copy_to_user(arg, &crop, sizeof(crop))) {
                        cam->stream = stream;
@@ -1915,7 +1776,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        DBG(1, "VIDIOC_S_CROP failed because of hardware "
                               "problems. To use the camera, close and open "
                               "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
+                       return err;
                }
 
                s->pix_format.width = rect->width/scale;
@@ -1937,23 +1798,20 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
 
        case VIDIOC_ENUM_FMT:
        {
+               struct sn9c102_sensor* s = cam->sensor;
                struct v4l2_fmtdesc fmtd;
 
                if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
                        return -EFAULT;
 
-               if (fmtd.index == 0) {
-                       strcpy(fmtd.description, "bayer rgb");
-                       fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-               } else if (fmtd.index == 1) {
-                       strcpy(fmtd.description, "compressed");
-                       fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
-                       fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-               } else
+               if (fmtd.index != 0)
                        return -EINVAL;
 
+               memset(&fmtd, 0, sizeof(fmtd));
+
                fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = s->pix_format.pixelformat;
 
                if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
                        return -EFAULT;
@@ -1972,9 +1830,8 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        return -EINVAL;
 
-               pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-                                    ? 0 : (pfmt->width * pfmt->priv) / 8;
-               pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+               pfmt->bytesperline = (pfmt->width * pfmt->priv) / 8;
+               pfmt->sizeimage = pfmt->height * pfmt->bytesperline;
                pfmt->field = V4L2_FIELD_NONE;
                memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
 
@@ -2043,21 +1900,15 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                pix->width = rect.width / scale;
                pix->height = rect.height / scale;
 
-               if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-                   pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-                       pix->pixelformat = pfmt->pixelformat;
+               pix->pixelformat = pfmt->pixelformat;
                pix->priv = pfmt->priv; /* bpp */
                pix->colorspace = pfmt->colorspace;
-               pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-                                   ? 0 : (pix->width * pix->priv) / 8;
-               pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+               pix->bytesperline = (pix->width * pix->priv) / 8;
+               pix->sizeimage = pix->height * pix->bytesperline;
                pix->field = V4L2_FIELD_NONE;
 
-               if (cmd == VIDIOC_TRY_FMT) {
-                       if (copy_to_user(arg, &format, sizeof(format)))
-                               return -EFAULT;
+               if (cmd == VIDIOC_TRY_FMT)
                        return 0;
-               }
 
                for (i = 0; i < cam->nbuffers; i++)
                        if (cam->frame[i].vma_use_count) {
@@ -2066,9 +1917,22 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                                return -EINVAL;
                        }
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
+               if (cam->stream == STREAM_ON) {
+                       cam->stream = STREAM_INTERRUPT;
+                       err = wait_event_interruptible
+                             ( cam->wait_stream, 
+                               (cam->stream == STREAM_OFF) ||
+                               (cam->state & DEV_DISCONNECTED) );
+                       if (err) {
+                               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;
+                       }
+                       if (cam->state & DEV_DISCONNECTED)
+                               return -ENODEV;
+               }
 
                if (copy_to_user(arg, &format, sizeof(format))) {
                        cam->stream = stream;
@@ -2077,8 +1941,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
 
                sn9c102_release_buffers(cam);
 
-               err += sn9c102_set_format(cam, pix);
-               err += sn9c102_set_crop(cam, &rect);
+               err = sn9c102_set_crop(cam, &rect);
                if (s->set_crop)
                        err += s->set_crop(cam, &rect);
                err += sn9c102_set_scale(cam, scale);
@@ -2088,7 +1951,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        DBG(1, "VIDIOC_S_FMT failed because of hardware "
                               "problems. To use the camera, close and open "
                               "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
+                       return err;
                }
 
                memcpy(pfmt, pix, sizeof(*pix));
@@ -2107,47 +1970,6 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                return 0;
        }
 
-       case VIDIOC_G_JPEGCOMP:
-       {
-               if (copy_to_user(arg, &cam->compression,
-                                sizeof(cam->compression)))
-                       return -EFAULT;
-
-               return 0;
-       }
-
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression jc;
-               const enum sn9c102_stream_state stream = cam->stream;
-               int err = 0;
-
-               if (copy_from_user(&jc, arg, sizeof(jc)))
-                       return -EFAULT;
-
-               if (jc.quality != 0 && jc.quality != 1)
-                       return -EINVAL;
-
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
-
-               err += sn9c102_set_compression(cam, &jc);
-               if (err) { /* atomic, no rollback in ioctl() */
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                              "problems. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
-               }
-
-               cam->compression.quality = jc.quality;
-
-               cam->stream = stream;
-
-               return 0;
-       }
-
        case VIDIOC_REQBUFS:
        {
                struct v4l2_requestbuffers rb;
@@ -2174,9 +1996,22 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                                return -EINVAL;
                        }
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
+               if (cam->stream == STREAM_ON) {
+                       cam->stream = STREAM_INTERRUPT;
+                       err = wait_event_interruptible
+                             ( cam->wait_stream, 
+                               (cam->stream == STREAM_OFF) ||
+                               (cam->state & DEV_DISCONNECTED) );
+                       if (err) {
+                               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;
+                       }
+                       if (cam->state & DEV_DISCONNECTED)
+                               return -ENODEV;
+               }
 
                sn9c102_empty_framequeues(cam);
 
@@ -2326,9 +2161,22 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                        return -EINVAL;
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
+               if (cam->stream == STREAM_ON) {
+                       cam->stream = STREAM_INTERRUPT;
+                       err = wait_event_interruptible
+                             ( cam->wait_stream, 
+                               (cam->stream == STREAM_OFF) ||
+                               (cam->state & DEV_DISCONNECTED) );
+                       if (err) {
+                               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;
+                       }
+                       if (cam->state & DEV_DISCONNECTED)
+                               return -ENODEV;
+               }
 
                sn9c102_empty_framequeues(cam);
 
@@ -2337,56 +2185,13 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                return 0;
        }
 
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm sp;
-
-               if (copy_from_user(&sp, arg, sizeof(sp)))
-                       return -EFAULT;
-
-               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-
-               sp.parm.capture.extendedmode = 0;
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-               if (copy_to_user(arg, &sp, sizeof(sp)))
-                       return -EFAULT;
-
-               return 0;
-       }
-
-       case VIDIOC_S_PARM:
-       {
-               struct v4l2_streamparm sp;
-
-               if (copy_from_user(&sp, arg, sizeof(sp)))
-                       return -EFAULT;
-
-               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-
-               sp.parm.capture.extendedmode = 0;
-
-               if (sp.parm.capture.readbuffers == 0)
-                       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-               if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
-                       sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
-
-               if (copy_to_user(arg, &sp, sizeof(sp)))
-                       return -EFAULT;
-
-               cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-               return 0;
-       }
-
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
        case VIDIOC_QUERYSTD:
        case VIDIOC_ENUMSTD:
        case VIDIOC_QUERYMENU:
+       case VIDIOC_G_PARM:
+       case VIDIOC_S_PARM:
                return -EINVAL;
 
        default:
@@ -2481,28 +2286,16 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || r != 0x10) {
-               DBG(1, "Sorry, this is not a SN9C10x based camera "
+               DBG(1, "Sorry, this is not a SN9C10[12] based camera "
                       "(vid/pid 0x%04X/0x%04X)",
                    sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
                err = -ENODEV;
                goto fail;
        }
 
-       cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
-                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
-       switch (cam->bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               DBG(2, "SN9C10[12] PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-                   sn9c102_id_table[i].idProduct)
-               break;
-       case BRIDGE_SN9C103:
-               DBG(2, "SN9C103 PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-                   sn9c102_id_table[i].idProduct)
-               break;
-       }
+       DBG(2, "SN9C10[12] PC Camera Controller detected "
+              "(vid/pid 0x%04X/0x%04X)",
+           sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct)
 
        for  (i = 0; sn9c102_sensor_table[i]; i++) {
                err = sn9c102_sensor_table[i](cam);
@@ -2525,7 +2318,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                cam->state |= DEV_MISCONFIGURED;
        }
 
-       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+       strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
        cam->v4ldev->hardware = VID_HARDWARE_SN9C102;