X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fmedia%2Fsn9c102_core.c;h=9f775f74002c1603aa820a6216648fecc2ef3cb9;hb=a9fdee76789476a10f923f9fb3c84993042da3ac;hp=e4c44fa873f4ce55955d70fc18ba60d225fee886;hpb=8d40237c730b8be87c1b80a5d96b9c603fefa829;p=linux-2.6.git diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index e4c44fa87..9f775f740 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -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 * * * @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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;