📄 sn9c102_core.c
字号:
SN9C102_Y_QTABLE1[i], 0x100 + i); err += sn9c102_write_reg(cam, SN9C102_UV_QTABLE1[i], 0x140 + i); } err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, 0x18); } else if (compression->quality == 1) { for (i = 0; i <= 63; i++) { err += sn9c102_write_reg(cam, SN9C102_Y_QTABLE1[i], 0x100 + i); err += sn9c102_write_reg(cam, SN9C102_UV_QTABLE1[i], 0x140 + i); } err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40, 0x18); } break; } return err ? -EIO : 0;}static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale){ u8 r = 0; int err = 0; if (scale == 1) r = cam->reg[0x18] & 0xcf; else if (scale == 2) { r = cam->reg[0x18] & 0xcf; r |= 0x10; } else if (scale == 4) r = cam->reg[0x18] | 0x20; err += sn9c102_write_reg(cam, r, 0x18); if (err) return -EIO; PDBGG("Scaling factor: %u", scale); return 0;}static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect){ struct sn9c102_sensor* s = &cam->sensor; 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); 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); if (err) return -EIO; PDBGG("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;}static int sn9c102_init(struct sn9c102_device* cam){ struct sn9c102_sensor* s = &cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; u8 i = 0; int err = 0; if (!(cam->state & DEV_INITIALIZED)) { mutex_init(&cam->open_mutex); init_waitqueue_head(&cam->wait_open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); } else { /* use current values */ qctrl = s->_qctrl; rect = &(s->_rect); } err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); err += sn9c102_set_crop(cam, rect); if (err) return err; if (s->init) { err = s->init(cam); if (err) { DBG(3, "Sensor initialization failed"); return err; } } if (!(cam->state & DEV_INITIALIZED)) 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); } else err += sn9c102_set_compression(cam, &cam->compression); err += sn9c102_set_pix_format(cam, &s->pix_format); if (s->set_pix_format) err += s->set_pix_format(cam, &s->pix_format); if (err) return err; if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) 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"); return err; } if (s->set_ctrl) { for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) if (s->qctrl[i].id != 0 && !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { ctrl.id = s->qctrl[i].id; ctrl.value = qctrl[i].default_value; err = s->set_ctrl(cam, &ctrl); if (err) { DBG(3, "Set %s control failed", s->qctrl[i].name); return err; } DBG(3, "Image sensor supports '%s' control", s->qctrl[i].name); } } if (!(cam->state & DEV_INITIALIZED)) { mutex_init(&cam->fileop_mutex); 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)); cam->state |= DEV_INITIALIZED; } DBG(2, "Initialization succeeded"); return 0;}/*****************************************************************************/static void sn9c102_release_resources(struct kref *kref){ struct sn9c102_device *cam; mutex_lock(&sn9c102_sysfs_lock); cam = container_of(kref, struct sn9c102_device, kref); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); kfree(cam->control_buffer); kfree(cam); mutex_unlock(&sn9c102_sysfs_lock);}static int sn9c102_open(struct inode* inode, struct file* filp){ struct sn9c102_device* cam; int err = 0; /* A read_trylock() in open() is the only safe way to prevent race conditions with disconnect(), one close() and multiple (not necessarily simultaneous) attempts to open(). For example, it prevents from waiting for a second access, while the device structure is being deallocated, after a possible disconnect() and during a following close() holding the write lock: given that, after this deallocation, no access will be possible anymore, using the non-trylock version would have let open() gain the access to the device structure improperly. For this reason the lock must also not be per-device. */ if (!down_read_trylock(&sn9c102_dev_lock)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); if (wait_for_completion_interruptible(&cam->probe)) { up_read(&sn9c102_dev_lock); return -ERESTARTSYS; } kref_get(&cam->kref); /* Make sure to isolate all the simultaneous opens. */ if (mutex_lock_interruptible(&cam->open_mutex)) { kref_put(&cam->kref, sn9c102_release_resources); up_read(&sn9c102_dev_lock); return -ERESTARTSYS; } if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); err = -ENODEV; goto out; } if (cam->users) { DBG(2, "Device /dev/video%d is already in use", cam->v4ldev->minor); DBG(3, "Simultaneous opens are not supported"); /* open() must follow the open flags and should block eventually while the device is in use. */ if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { err = -EWOULDBLOCK; goto out; } DBG(2, "A blocking open() has been requested. Wait for the " "device to be released..."); up_read(&sn9c102_dev_lock); /* We will not release the "open_mutex" lock, so that only one process can be in the wait queue below. This way the process will be sleeping while holding the lock, without loosing its priority after any wake_up(). */ err = wait_event_interruptible_exclusive(cam->wait_open, (cam->state & DEV_DISCONNECTED) || !cam->users); down_read(&sn9c102_dev_lock); if (err) goto out; if (cam->state & DEV_DISCONNECTED) { err = -ENODEV; goto out; } } if (cam->state & DEV_MISCONFIGURED) { err = sn9c102_init(cam); if (err) { DBG(1, "Initialization failed again. " "I will retry on next open()."); goto out; } cam->state &= ~DEV_MISCONFIGURED; } if ((err = sn9c102_start_transfer(cam))) goto out; filp->private_data = cam; cam->users++; cam->io = IO_NONE; cam->stream = STREAM_OFF; cam->nbuffers = 0; cam->frame_count = 0; sn9c102_empty_framequeues(cam); DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);out: mutex_unlock(&cam->open_mutex); if (err) kref_put(&cam->kref, sn9c102_release_resources); up_read(&sn9c102_dev_lock); return err;}static int sn9c102_release(struct inode* inode, struct file* filp){ struct sn9c102_device* cam; down_write(&sn9c102_dev_lock); cam = video_get_drvdata(video_devdata(filp)); sn9c102_stop_transfer(cam); sn9c102_release_buffers(cam); cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); kref_put(&cam->kref, sn9c102_release_resources); up_write(&sn9c102_dev_lock); return 0;}static ssize_tsn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); struct sn9c102_frame_t* f, * i; unsigned long lock_flags; long timeout; int err = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io == IO_MMAP) { DBG(3, "Close and open the device again to choose " "the read method"); mutex_unlock(&cam->fileop_mutex); return -EBUSY; } if (cam->io == IO_NONE) { if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory"); mutex_unlock(&cam->fileop_mutex); return -ENOMEM; } cam->io = IO_READ; cam->stream = STREAM_ON; } if (list_empty(&cam->inqueue)) { if (!list_empty(&cam->outqueue)) sn9c102_empty_framequeues(cam); sn9c102_queue_unusedframes(cam); } if (!count) { mutex_unlock(&cam->fileop_mutex); return 0; } if (list_empty(&cam->outqueue)) { if (filp->f_flags & O_NONBLOCK) { mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } if (!cam->module_param.frame_timeout) { err = wait_event_interruptible ( cam->wait_frame, (!list_empty(&cam->outqueue)) || (cam->state & DEV_DISCONNECTED) || (cam->state & DEV_MISCONFIGURED) ); if (err) { mutex_unlock(&cam->fileop_mutex); 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; } else if (timeout == 0 && !(cam->state & DEV_DISCONNECTED)) { DBG(1, "Video frame timeout elapsed"); mutex_unlock(&cam->fileop_mutex); return -EIO; } } if (cam->state & DEV_DISCONNECTED) { mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { mutex_unlock(&cam->fileop_mutex); return -EIO; } } f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); if (count > f->buf.bytesused) count = f->buf.bytesused; if (copy_to_user(buf, f->bufmem, count)) { err = -EFAULT; goto exit; } *f_pos += count;exit: spin_lock_irqsave(&cam->queue_lock, lock_flags); list_for_each_entry(i, &cam->outqueue, frame) i->state = F_UNUSED; INIT_LIST_HEAD(&cam->outqueue); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); sn9c102_queue_unusedframes(cam); PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index, count); mutex_unlock(&cam->fileop_mutex); return count;}static unsigned int sn9c102_poll(struct file *filp, poll_table *wait){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); struct sn9c102_frame_t* f; unsigned long lock_flags; unsigned int mask = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) return POLLERR; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); goto error; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); goto error; } if (cam->io == IO_NONE) { if (!sn9c102_request_buffers(cam, cam->nreadbuffers, IO_READ)) { DBG(1, "poll() failed, not enough memory"); goto error; } cam->io = IO_READ; cam->stream = STREAM_ON; } if (cam->io == IO_READ) { spin_lock_irqsave(&cam->queue_lock, lock_flags); list_for_each_entry(f, &cam->outqueue, frame) f->state = F_UNUSED; INIT_LIST_HEAD(&cam->outqueue); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); sn9c102_queue_unusedframes(cam); } poll_wait(filp, &cam->wait_frame, wait); if (!list_empty(&cam->outqueue)) mask |= POLLIN | POLLRDNORM; mutex_unlock(&cam->fileop_mutex); return mask;error: mutex_unlock(&cam->fileop_mutex); return POLLERR;}static void sn9c102_vm_open(struct vm_area_struct* vma){ struct sn9c102_frame_t* f = vma->vm_private_data; f->vma_use_count++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -