/***************************************************************************
- * 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> *
* *
#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>
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)"
/*****************************************************************************/
+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;
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;
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)
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)
/*****************************************************************************/
-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;
}
-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))
*/
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;
(*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;
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;
}
}
}
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;
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)
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;
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;
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)
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);
}
/*****************************************************************************/
-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;
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;
}
}
- 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")
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)
}
}
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));
}
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;
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);
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;
}
}
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);
.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;
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;
}
} 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;
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;
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;
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));
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) {
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;
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);
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));
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;
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);
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);
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:
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);
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;