vserver 1.9.3
[linux-2.6.git] / drivers / usb / media / sn9c102_core.c
index bcd9fbd..9f775f7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/stddef.h>
+#include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
 #include <linux/stat.h>
@@ -83,7 +84,7 @@ MODULE_PARM_DESC(debug,
 
 /*****************************************************************************/
 
-typedef char sn9c102_sof_header_t[7];
+typedef char sn9c102_sof_header_t[12];
 typedef char sn9c102_eof_header_t[4];
 
 static sn9c102_sof_header_t sn9c102_sof_header[] = {
@@ -91,8 +92,6 @@ static sn9c102_sof_header_t sn9c102_sof_header[] = {
        {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
 };
 
-/* Number of random bytes that complete the SOF above headers */
-#define SN9C102_SOFLEN 5
 
 static sn9c102_eof_header_t sn9c102_eof_header[] = {
        {0x00, 0x00, 0x00, 0x00},
@@ -237,9 +236,6 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
        u8* buff = cam->control_buffer;
        int res;
 
-       if (index == 0x18)
-               value = (value & 0xcf) | (cam->reg[0x18] & 0x30);
-
        *buff = value;
 
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
@@ -443,14 +439,15 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 
 static void* sn9c102_find_sof_header(void* mem, size_t len)
 {
-       size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i;
+       size_t soflen = sizeof(sn9c102_sof_header_t), i;
        u8 j, n = sizeof(sn9c102_sof_header) / soflen;
 
-       for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++)
+       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
                for (j = 0; j < n; j++)
-                       if (!memcmp(mem + i, sn9c102_sof_header[j], soflen))
+                       /* It's enough to compare 7 bytes */
+                       if (!memcmp(mem + i, sn9c102_sof_header[j], 7))
                                /* Skips the header */
-                               return mem + i + soflen + SOFLEN;
+                               return mem + i + soflen;
 
        return NULL;
 }
@@ -517,10 +514,12 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 
                PDBGG("Isochrnous frame: length %u, #%u i", len, i)
 
-               /* NOTE: It is probably correct to assume that SOF and EOF
+               /*
+                  NOTE: It is probably correct to assume that SOF and EOF
                         headers do not occur between two consecutive packets,
                         but who knows..Whatever is the truth, this assumption
-                        doesn't introduce bugs. */
+                        doesn't introduce bugs.
+               */
 
 redo:
                sof = sn9c102_find_sof_header(pos, len);
@@ -764,9 +763,11 @@ static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
        return (u8)val;
 }
 
-/* NOTE 1: being inside one of the following methods implies that the v4l
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
            device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long */
+   NOTE 2: buffers are PAGE_SIZE long
+*/
 
 static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
 {
@@ -1018,24 +1019,6 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
 }
 
 
-static ssize_t
-sn9c102_store_redblue(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)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
 static ssize_t
 sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
 {
@@ -1062,7 +1045,6 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
                          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);
-static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue);
 static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
 
 
@@ -1072,7 +1054,6 @@ 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);
-       video_device_create_file(v4ldev, &class_device_attr_redblue);
        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);
@@ -1118,10 +1099,6 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
           ae_endy = v_size / 2;
        int err = 0;
 
-       /* These are a sort of stroboscopic signal for some sensors */
-       err += sn9c102_write_reg(cam, h_size, 0x1a);
-       err += sn9c102_write_reg(cam, v_size, 0x1b);
-
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
        err += sn9c102_write_reg(cam, h_size, 0x15);
@@ -1134,8 +1111,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
                return -EIO;
 
        PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
-             "%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size,
-             vo_size)
+             "%u %u %u %u", h_start, v_start, h_size, v_size)
 
        return 0;
 }
@@ -1229,7 +1205,10 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        struct sn9c102_device* cam;
        int err = 0;
 
-       /* This the only safe way to prevent race conditions with disconnect */
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
        if (!down_read_trylock(&sn9c102_disconnect))
                return -ERESTARTSYS;
 
@@ -1727,6 +1706,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                                return -EINVAL;
                        }
 
+               /* Preserve R,G or B origin */
+               rect->left = (s->_rect.left & 1L) ?
+                            rect->left | 1L : rect->left & ~1L;
+               rect->top = (s->_rect.top & 1L) ?
+                           rect->top | 1L : rect->top & ~1L;
+
                if (rect->width < 16)
                        rect->width = 16;
                if (rect->height < 16)
@@ -1747,13 +1732,15 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                rect->width &= ~15L;
                rect->height &= ~15L;
 
-               { /* calculate the scaling factor */
+               if (SN9C102_PRESERVE_IMGSCALE) {
+                       /* Calculate the actual scaling factor */
                        u32 a, b;
                        a = rect->width * rect->height;
                        b = pix_format->width * pix_format->height;
-                       scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 :
-                                   ((a / b) > 4 ? 4 : (a / b)))) : 1;
-               }
+                       scale = b ? (u8)((a / b) < 4 ? 1 :
+                                       ((a / b) < 16 ? 2 : 4)) : 1;
+               } else
+                       scale = 1;
 
                if (cam->stream == STREAM_ON) {
                        cam->stream = STREAM_INTERRUPT;
@@ -1879,12 +1866,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
 
                memcpy(&rect, &(s->_rect), sizeof(rect));
 
-               { /* calculate the scaling factor */
+               { /* calculate the actual scaling factor */
                        u32 a, b;
                        a = rect.width * rect.height;
                        b = pix->width * pix->height;
-                       scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 :
-                                   ((a / b) > 4 ? 4 : (a / b)))) : 1;
+                       scale = b ? (u8)((a / b) < 4 ? 1 :
+                                       ((a / b) < 16 ? 2 : 4)) : 1;
                }
 
                rect.width = scale * pix->width;
@@ -1895,13 +1882,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (rect.height < 16)
                        rect.height = 16;
                if (rect.width > bounds->left + bounds->width - rect.left)
-                       rect.width = bounds->left+bounds->width - rect.left;
+                       rect.width = bounds->left + bounds->width - rect.left;
                if (rect.height > bounds->top + bounds->height - rect.top)
                        rect.height = bounds->top + bounds->height - rect.top;
 
                rect.width &= ~15L;
                rect.height &= ~15L;
 
+               { /* adjust the scaling factor */
+                       u32 a, b;
+                       a = rect.width * rect.height;
+                       b = pix->width * pix->height;
+                       scale = b ? (u8)((a / b) < 4 ? 1 :
+                                       ((a / b) < 16 ? 2 : 4)) : 1;
+               }
+
                pix->width = rect.width / scale;
                pix->height = rect.height / scale;
 
@@ -2119,7 +2114,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                spin_lock_irqsave(&cam->queue_lock, lock_flags);
                f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
                               frame);
-               list_del(&cam->outqueue);
+               list_del(cam->outqueue.next);
                spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 
                f->state = F_UNUSED;