summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/sn9c102
diff options
context:
space:
mode:
authorLuca Risolia <luca.risolia@studio.unibo.it>2007-03-26 16:12:04 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-04-27 15:45:08 -0300
commitf423b9a86a6dd3d2bc08d78f4d21525a14c40a6b (patch)
treecac9dcd72bd298478559cdae7061b1a942cb4b0f /drivers/media/video/sn9c102
parent9ab7e323af9f9efad3e20a14faa4d947adfac381 (diff)
V4L/DVB (5474): SN9C1xx driver updates
@ Don't assume that SOF headers can't cross packets boundaries @ Fix compression quality selection + Add support for MI-0360 image sensor * Documentation updates @ Fix sysfs @ MI0343 rewritten * HV7131R color fixes and add new ABLC control * Rename the archive from "sn9c102" to "sn9c1xx" * fix typos * better support for TAS5110D @ fix OV7630 wrong colors @ Don't return an error if no input buffers are enqueued yet on VIDIOC_STREAMON * Add informations about colorspaces * More appropriate error codes in case of failure of some system calls * More precise hardware detection * Add more informations about supported hardware in the documentation + More supported devices + Add support for HV7131R image sensor Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/sn9c102')
-rw-r--r--drivers/media/video/sn9c102/Makefile17
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h17
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c199
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h14
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131d.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131r.c458
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0343.c111
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0360.c353
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c63
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c3
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas106b.c5
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c15
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110c1b.c6
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110d.c121
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5130d1b.c5
15 files changed, 1184 insertions, 210 deletions
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
index 30e3dfe537fe..a56d16f69c71 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/video/sn9c102/Makefile
@@ -1,7 +1,14 @@
-sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
- sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
- sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
- sn9c102_tas5130d1b.o
+sn9c102-objs := sn9c102_core.o \
+ sn9c102_hv7131d.o \
+ sn9c102_hv7131r.o \
+ sn9c102_mi0343.o \
+ sn9c102_mi0360.o \
+ sn9c102_ov7630.o \
+ sn9c102_ov7660.o \
+ sn9c102_pas106b.o \
+ sn9c102_pas202bcb.o \
+ sn9c102_tas5110c1b.o \
+ sn9c102_tas5110d.o \
+ sn9c102_tas5130d1b.o
obj-$(CONFIG_USB_SN9C102) += sn9c102.o
-
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 5428f34e7c5b..680e74634527 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -78,8 +78,13 @@ enum sn9c102_stream_state {
typedef char sn9c102_sof_header_t[62];
+struct sn9c102_sof_t {
+ sn9c102_sof_header_t header;
+ u16 bytesread;
+};
+
struct sn9c102_sysfs_attr {
- u8 reg, i2c_reg;
+ u16 reg, i2c_reg;
sn9c102_sof_header_t frame_header;
};
@@ -112,7 +117,7 @@ struct sn9c102_device {
struct v4l2_jpegcompression compression;
struct sn9c102_sysfs_attr sysfs;
- sn9c102_sof_header_t sof_header;
+ struct sn9c102_sof_t sof;
u16 reg[384];
struct sn9c102_module_param module_param;
@@ -182,8 +187,8 @@ do { \
if ((level) == 1 || (level) == 2) \
pr_info("sn9c102: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%d] " fmt "\n", \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
#else
@@ -194,8 +199,8 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index d0e2b40a7725..f09caf2b6e75 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -44,11 +44,12 @@
/*****************************************************************************/
#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
+#define SN9C102_MODULE_ALIAS "sn9c1xx"
+#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.34"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34)
+#define SN9C102_MODULE_VERSION "1:1.39"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39)
/*****************************************************************************/
@@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
+MODULE_ALIAS(SN9C102_MODULE_ALIAS);
MODULE_VERSION(SN9C102_MODULE_VERSION);
MODULE_LICENSE(SN9C102_MODULE_LICENSE);
@@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug,
"\n1 = critical errors"
"\n2 = significant informations"
"\n3 = more verbose messages"
- "\nLevel 3 is useful for testing only, when only "
- "one device is used."
+ "\nLevel 3 is useful for testing only."
"\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
"\n");
#endif
@@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
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;
+ (p->width * p->height * p->priv) / 8 :
+ (r->width * r->height * p->priv) / 8;
void* buff = NULL;
u32 i;
@@ -485,18 +486,43 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam)
static void*
sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
- char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
- size_t soflen = 0, i;
+ const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+ const char *m = mem;
+ size_t soflen = 0, i, j;
soflen = sn9c102_sof_length(cam);
- for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
- if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
- memcpy(cam->sof_header, mem + i,
- sizeof(sn9c102_sof_header_t));
- /* Skip the header */
- return mem + i + soflen;
+ for (i = 0; i < len; i++) {
+ size_t b;
+
+ /* Read the variable part of the header */
+ if (unlikely(cam->sof.bytesread >= sizeof(marker))) {
+ cam->sof.header[cam->sof.bytesread] = *(m+i);
+ if (++cam->sof.bytesread == soflen) {
+ cam->sof.bytesread = 0;
+ return mem + i;
+ }
+ continue;
+ }
+
+ /* Search for the SOF marker (fixed part) in the header */
+ for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
+ if (unlikely(i+j) == len)
+ return NULL;
+ if (*(m+i+j) == marker[cam->sof.bytesread]) {
+ cam->sof.header[cam->sof.bytesread] = *(m+i+j);
+ if (++cam->sof.bytesread == sizeof(marker)) {
+ PDBGG("Bytes to analyze: %zd. SOF "
+ "starts at byte #%zd", len, i);
+ i += j+1;
+ break;
+ }
+ } else {
+ cam->sof.bytesread = 0;
+ break;
}
+ }
+ }
return NULL;
}
@@ -513,10 +539,16 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
};
size_t i, j;
+ /* The EOF header does not exist in compressed data */
if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- return NULL; /* EOF header does not exist in compressed data */
+ return NULL;
+ /*
+ The EOF header might cross the packet boundary, but this is not a
+ problem, since the end of a frame is determined by checking its size
+ in the first place.
+ */
for (i = 0; (len >= 4) && (i <= len - 4); i++)
for (j = 0; j < ARRAY_SIZE(eof_header); j++)
if (!memcmp(mem + i, eof_header[j], 4))
@@ -639,6 +671,7 @@ static void sn9c102_urb_complete(struct urb *urb)
cam->stream = STREAM_OFF;
if ((*f))
(*f)->state = F_QUEUED;
+ cam->sof.bytesread = 0;
DBG(3, "Stream interrupted by application");
wake_up(&cam->wait_stream);
}
@@ -676,6 +709,7 @@ static void sn9c102_urb_complete(struct urb *urb)
if (status) {
DBG(3, "Error in isochronous frame");
(*f)->state = F_ERROR;
+ cam->sof.bytesread = 0;
continue;
}
@@ -692,13 +726,13 @@ end_of_frame:
if (eof)
img = (eof > pos) ? eof - pos - 1 : 0;
- if ((*f)->buf.bytesused+img > imagesize) {
+ if ((*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");
+ PDBGG("Expected EOF not found: video "
+ "frame cut");
if (eof)
DBG(3, "Exceeded limit: +%u "
"bytes", (unsigned)(b));
@@ -719,11 +753,6 @@ end_of_frame:
V4L2_PIX_FMT_JPEG) && eof)) {
u32 b;
- if (cam->sensor.pix_format.pixelformat
- == V4L2_PIX_FMT_JPEG)
- sn9c102_write_eoimarker(cam,
- (*f));
-
b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
(*f)->buf.sequence= ++cam->frame_count;
@@ -741,7 +770,7 @@ end_of_frame:
spin_unlock(&cam->queue_lock);
memcpy(cam->sysfs.frame_header,
- cam->sof_header, soflen);
+ cam->sof.header, soflen);
DBG(3, "Video frame captured: %lu "
"bytes", (unsigned long)(b));
@@ -791,7 +820,13 @@ start_of_frame:
V4L2_PIX_FMT_SN9C10X ||
cam->sensor.pix_format.pixelformat ==
V4L2_PIX_FMT_JPEG) {
- eof = sof - soflen;
+ if (sof - pos >= soflen) {
+ eof = sof - soflen;
+ } else { /* remove header */
+ eof = pos;
+ (*f)->buf.bytesused -=
+ (soflen - (sof - pos));
+ }
goto end_of_frame;
} else {
DBG(3, "SOF before expected EOF after "
@@ -878,6 +913,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
}
cam->frame_current = NULL;
+ cam->sof.bytesread = 0;
for (i = 0; i < SN9C102_URBS; i++) {
err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
@@ -959,9 +995,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
if (len < 6) {
strncpy(str, buff, len);
- str[len+1] = '\0';
+ str[len] = '\0';
} else {
- strncpy(str, buff, 4);
+ strncpy(str, buff, 6);
str[6] = '\0';
}
@@ -1062,7 +1098,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
count = sprintf(buf, "%d\n", val);
- DBG(3, "Read bytes: %zd", count);
+ DBG(3, "Read bytes: %zd, value: %d", count, val);
mutex_unlock(&sn9c102_sysfs_lock);
@@ -1197,7 +1233,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
count = sprintf(buf, "%d\n", val);
- DBG(3, "Read bytes: %zd", count);
+ DBG(3, "Read bytes: %zd, value: %d", count, val);
mutex_unlock(&sn9c102_sysfs_lock);
@@ -1477,10 +1513,10 @@ sn9c102_set_compression(struct sn9c102_device* cam,
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
case BRIDGE_SN9C103:
- if (compression->quality == 0)
+ if (compression->quality == 0)
err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
0x17);
- else if (compression->quality == 1)
+ else if (compression->quality == 1)
err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
0x17);
break;
@@ -1489,10 +1525,10 @@ sn9c102_set_compression(struct sn9c102_device* cam,
if (compression->quality == 0) {
for (i = 0; i <= 63; i++) {
err += sn9c102_write_reg(cam,
- SN9C102_Y_QTABLE0[i],
+ SN9C102_Y_QTABLE1[i],
0x100 + i);
err += sn9c102_write_reg(cam,
- SN9C102_UV_QTABLE0[i],
+ SN9C102_UV_QTABLE1[i],
0x140 + i);
}
err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
@@ -1597,9 +1633,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
if (cam->bridge == BRIDGE_SN9C101 ||
cam->bridge == BRIDGE_SN9C102 ||
cam->bridge == BRIDGE_SN9C103) {
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
+ s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
cam->compression.quality = cam->reg[0x17] & 0x01 ?
0 : 1;
} else {
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG;
cam->compression.quality = cam->reg[0x18] & 0x40 ?
0 : 1;
err += sn9c102_set_compression(cam, &cam->compression);
@@ -1805,7 +1845,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
DBG(3, "Close and open the device again to choose "
"the read method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -1845,16 +1885,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
return err;
}
} else {
- 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;
+ 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;
} else if (timeout == 0 &&
!(cam->state & DEV_DISCONNECTED)) {
DBG(1, "Video frame timeout elapsed");
@@ -2001,7 +2041,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -2267,7 +2312,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
/* Preserve R,G or B origin */
@@ -2410,8 +2455,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
case BRIDGE_SN9C103:
- strcpy(fmtd.description, "compressed");
- fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+ strcpy(fmtd.description, "compressed");
+ fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
break;
case BRIDGE_SN9C105:
case BRIDGE_SN9C120:
@@ -2445,8 +2490,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
- pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
+ pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ?
+ V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
+ pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ pfmt->pixelformat == V4L2_PIX_FMT_JPEG)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
pfmt->field = V4L2_FIELD_NONE;
@@ -2521,9 +2568,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
case BRIDGE_SN9C103:
- if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
- pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
- pix->pixelformat = pfmt->pixelformat;
+ if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+ pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+ pix->pixelformat = pfmt->pixelformat;
break;
case BRIDGE_SN9C105:
case BRIDGE_SN9C120:
@@ -2533,7 +2580,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
break;
}
pix->priv = pfmt->priv; /* bpp */
- pix->colorspace = pfmt->colorspace;
+ pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ?
+ V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
pix->pixelformat == V4L2_PIX_FMT_JPEG)
? 0 : (pix->width * pix->priv) / 8;
@@ -2551,7 +2599,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. Unmap the "
"buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2666,14 +2714,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
"still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2785,15 +2833,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
if (err)
return err;
} else {
- 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;
+ 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;
else if (timeout == 0 &&
!(cam->state & DEV_DISCONNECTED)) {
DBG(1, "Video frame timeout elapsed");
@@ -2837,9 +2885,6 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -3166,8 +3211,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
r = sn9c102_read_reg(cam, 0x00);
if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
- DBG(1, "Sorry, this is not a SN9C1xx based camera "
- "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ DBG(1, "Sorry, this is not a SN9C1xx-based camera "
+ "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
err = -ENODEV;
goto fail;
}
@@ -3177,19 +3222,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
DBG(2, "SN9C10[12] PC Camera Controller detected "
- "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
case BRIDGE_SN9C103:
DBG(2, "SN9C103 PC Camera Controller detected "
- "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
case BRIDGE_SN9C105:
DBG(2, "SN9C105 PC Camera Controller detected "
- "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
case BRIDGE_SN9C120:
DBG(2, "SN9C120 PC Camera Controller detected "
- "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
}
@@ -3260,6 +3305,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
"device controlling. Error #%d", err);
#else
DBG(2, "Optional device control through 'sysfs' interface disabled");
+ DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+ "configuration option to enable it.");
#endif
usb_set_intfdata(intf, cam);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 3a682eca6c65..f49bd8c5b86e 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -89,16 +89,22 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
/* SN9C120 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
@@ -114,12 +120,15 @@ static const struct usb_device_id sn9c102_id_table[] = {
Functions must return 0 on success, the appropriate error otherwise.
*/
extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
/*
@@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
the order of the list below, from top to bottom.
*/
static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
- &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
&sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+ &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
NULL,
};
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index 7ae368f60d89..9b2e2d68c739 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -22,9 +22,6 @@
#include "sn9c102_sensor.h"
-static struct sn9c102_sensor hv7131d;
-
-
static int hv7131d_init(struct sn9c102_device* cam)
{
int err = 0;
@@ -153,7 +150,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor hv7131d = {
.name = "HV7131D",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -263,7 +260,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
if (r0 < 0 || r1 < 0)
return -EIO;
- if (r0 != 0x00 && r1 != 0x04)
+ if (r0 != 0x00 || r1 != 0x04)
return -ENODEV;
sn9c102_attach_sensor(cam, &hv7131d);
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
new file mode 100644
index 000000000000..c4a3e3991e88
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
@@ -0,0 +1,458 @@
+/***************************************************************************
+ * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera *
+ * Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static int hv7131r_init(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x20, 0x05);
+ err += sn9c102_write_reg(cam, 0x20, 0x06);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x00, 0x14);
+ err += sn9c102_write_reg(cam, 0x60, 0x17);
+ err += sn9c102_write_reg(cam, 0x0a, 0x18);
+ err += sn9c102_write_reg(cam, 0xf0, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x10, 0x21);
+ err += sn9c102_write_reg(cam, 0x20, 0x22);
+ err += sn9c102_write_reg(cam, 0x30, 0x23);
+ err += sn9c102_write_reg(cam, 0x40, 0x24);
+ err += sn9c102_write_reg(cam, 0x50, 0x25);
+ err += sn9c102_write_reg(cam, 0x60, 0x26);
+ err += sn9c102_write_reg(cam, 0x70, 0x27);
+ err += sn9c102_write_reg(cam, 0x80, 0x28);
+ err += sn9c102_write_reg(cam, 0x90, 0x29);
+ err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+ err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+ err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+ err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+ err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err += sn9c102_write_reg(cam, 0x44, 0x01);
+ err += sn9c102_write_reg(cam, 0x40, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x44, 0x05);
+ err += sn9c102_write_reg(cam, 0x3e, 0x06);
+ err += sn9c102_write_reg(cam, 0x1a, 0x07);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x08, 0x14);
+ err += sn9c102_write_reg(cam, 0xa3, 0x17);
+ err += sn9c102_write_reg(cam, 0x4b, 0x18);
+ err += sn9c102_write_reg(cam, 0x00, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x29, 0x21);
+ err += sn9c102_write_reg(cam, 0x40, 0x22);
+ err += sn9c102_write_reg(cam, 0x54, 0x23);
+ err += sn9c102_write_reg(cam, 0x66, 0x24);
+ err += sn9c102_write_reg(cam, 0x76, 0x25);
+ err += sn9c102_write_reg(cam, 0x85, 0x26);
+ err += sn9c102_write_reg(cam, 0x94, 0x27);
+ err += sn9c102_write_reg(cam, 0xa1, 0x28);
+ err += sn9c102_write_reg(cam, 0xae, 0x29);
+ err += sn9c102_write_reg(cam, 0xbb, 0x2a);
+ err += sn9c102_write_reg(cam, 0xc7, 0x2b);
+ err += sn9c102_write_reg(cam, 0xd3, 0x2c);
+ err += sn9c102_write_reg(cam, 0xde, 0x2d);
+ err += sn9c102_write_reg(cam, 0xea, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf4, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ err += sn9c102_write_reg(cam, 0x00, 0x3F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x40);
+ err += sn9c102_write_reg(cam, 0x01, 0x41);
+ err += sn9c102_write_reg(cam, 0x44, 0x42);
+ err += sn9c102_write_reg(cam, 0x00, 0x43);
+ err += sn9c102_write_reg(cam, 0x44, 0x44);
+ err += sn9c102_write_reg(cam, 0x00, 0x45);
+ err += sn9c102_write_reg(cam, 0x44, 0x46);
+ err += sn9c102_write_reg(cam, 0x00, 0x47);
+ err += sn9c102_write_reg(cam, 0xC7, 0x48);
+ err += sn9c102_write_reg(cam, 0x01, 0x49);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4A);
+ err += sn9c102_write_reg(cam, 0x01, 0x4B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4C);
+ err += sn9c102_write_reg(cam, 0x01, 0x4D);
+ err += sn9c102_write_reg(cam, 0x44, 0x4E);
+ err += sn9c102_write_reg(cam, 0x00, 0x4F);
+ err += sn9c102_write_reg(cam, 0x44, 0x50);
+ err += sn9c102_write_reg(cam, 0x00, 0x51);
+ err += sn9c102_write_reg(cam, 0x44, 0x52);
+ err += sn9c102_write_reg(cam, 0x00, 0x53);
+ err += sn9c102_write_reg(cam, 0xC7, 0x54);
+ err += sn9c102_write_reg(cam, 0x01, 0x55);
+ err += sn9c102_write_reg(cam, 0xC7, 0x56);
+ err += sn9c102_write_reg(cam, 0x01, 0x57);
+ err += sn9c102_write_reg(cam, 0xC7, 0x58);
+ err += sn9c102_write_reg(cam, 0x01, 0x59);
+ err += sn9c102_write_reg(cam, 0x44, 0x5A);
+ err += sn9c102_write_reg(cam, 0x00, 0x5B);
+ err += sn9c102_write_reg(cam, 0x44, 0x5C);
+ err += sn9c102_write_reg(cam, 0x00, 0x5D);
+ err += sn9c102_write_reg(cam, 0x44, 0x5E);
+ err += sn9c102_write_reg(cam, 0x00, 0x5F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x60);
+ err += sn9c102_write_reg(cam, 0x01, 0x61);
+ err += sn9c102_write_reg(cam, 0xC7, 0x62);
+ err += sn9c102_write_reg(cam, 0x01, 0x63);
+ err += sn9c102_write_reg(cam, 0xC7, 0x64);
+ err += sn9c102_write_reg(cam, 0x01, 0x65);
+ err += sn9c102_write_reg(cam, 0x44, 0x66);
+ err += sn9c102_write_reg(cam, 0x00, 0x67);
+ err += sn9c102_write_reg(cam, 0x44, 0x68);
+ err += sn9c102_write_reg(cam, 0x00, 0x69);
+ err += sn9c102_write_reg(cam, 0x44, 0x6A);
+ err += sn9c102_write_reg(cam, 0x00, 0x6B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6C);
+ err += sn9c102_write_reg(cam, 0x01, 0x6D);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6E);
+ err += sn9c102_write_reg(cam, 0x01, 0x6F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x70);
+ err += sn9c102_write_reg(cam, 0x01, 0x71);
+ err += sn9c102_write_reg(cam, 0x44, 0x72);
+ err += sn9c102_write_reg(cam, 0x00, 0x73);
+ err += sn9c102_write_reg(cam, 0x44, 0x74);
+ err += sn9c102_write_reg(cam, 0x00, 0x75);
+ err += sn9c102_write_reg(cam, 0x44, 0x76);
+ err += sn9c102_write_reg(cam, 0x00, 0x77);
+ err += sn9c102_write_reg(cam, 0xC7, 0x78);
+ err += sn9c102_write_reg(cam, 0x01, 0x79);
+ err += sn9c102_write_reg(cam, 0xC7, 0x7A);
+ err += sn9c102_write_reg(cam, 0x01, 0x7B);
+ err += sn9c102_write_reg(cam,