📄 sn9c102_core.c
字号:
if (!count) { up(&sn9c102_sysfs_lock); return -EINVAL; } err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); if (err) { up(&sn9c102_sysfs_lock); return -EIO; } DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", cam->sysfs.i2c_reg, value) DBG(3, "Written bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_tsn9c102_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) 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_tsn9c102_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_tsn9c102_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) res = sn9c102_store_val(cd, buf, len); return res;}static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf){ struct sn9c102_device* cam; ssize_t count; cam = video_get_drvdata(to_video_device(cd)); if (!cam) return -ENODEV; count = sizeof(cam->sysfs.frame_header); memcpy(buf, cam->sysfs.frame_header, count); DBG(3, "Frame header, read bytes: %zd", count) return count;} static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);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(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 CLASS_DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);static void sn9c102_create_sysfs(struct sn9c102_device* cam){ struct video_device *v4ldev = cam->v4ldev; 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_frame_header); 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->sysfs_ops) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); }}/*****************************************************************************/static intsn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix){ int err = 0; if (pix->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 intsn9c102_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; 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, n = 0; int err = 0; if (!(cam->state & DEV_INITIALIZED)) { init_waitqueue_head(&cam->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)) cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; 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) 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) { n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); for (i = 0; i < n; 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)) { init_MUTEX(&cam->fileop_sem); 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 sn9c102_device* cam){ down(&sn9c102_sysfs_lock); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor) video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); up(&sn9c102_sysfs_lock); kfree(cam->control_buffer);}/*****************************************************************************/static int sn9c102_open(struct inode* inode, struct file* filp){ struct sn9c102_device* cam; int err = 0; /* This is the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&sn9c102_disconnect)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); if (down_interruptible(&cam->dev_sem)) { up_read(&sn9c102_disconnect); return -ERESTARTSYS; } if (cam->users) { DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor) if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { err = -EWOULDBLOCK; goto out; } up(&cam->dev_sem); err = wait_event_interruptible_exclusive(cam->open, cam->state & DEV_DISCONNECTED || !cam->users); if (err) { up_read(&sn9c102_disconnect); return err; } if (cam->state & DEV_DISCONNECTED) { up_read(&sn9c102_disconnect); return -ENODEV; } down(&cam->dev_sem); } 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: up(&cam->dev_sem); up_read(&sn9c102_disconnect); return err;}static int sn9c102_release(struct inode* inode, struct file* filp){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); down(&cam->dev_sem); /* prevent disconnect() to be called */ sn9c102_stop_transfer(cam); sn9c102_release_buffers(cam); if (cam->state & DEV_DISCONNECTED) { sn9c102_release_resources(cam); up(&cam->dev_sem); kfree(cam); return 0; } cam->users--; wake_up_interruptible_nr(&cam->open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor) up(&cam->dev_sem); 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; int err = 0; if (down_interruptible(&cam->fileop_sem)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present") up(&cam->fileop_sem); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it again.") up(&cam->fileop_sem); return -EIO; } if (cam->io == IO_MMAP) { DBG(3, "Close and open the device again to choose " "the read method") up(&cam->fileop_sem); return -EINVAL; } if (cam->io == IO_NONE) { if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory") up(&cam->fileop_sem); return -ENOMEM; } cam->io = IO_READ; cam->stream = STREAM_ON; sn9c102_queue_unusedframes(cam); } if (!count) { up(&cam->fileop_sem); return 0; } if (list_empty(&cam->outqueue)) { if (filp->f_flags & O_NONBLOCK) { up(&cam->fileop_sem); return -EAGAIN; } err = wait_event_interruptible ( cam->wait_frame, (!list_empty(&cam->outqueue)) || (cam->state & DEV_DISCONNECTED) || (cam->state & DEV_MISCONFIGURED) ); if (err) { up(&cam->fileop_sem); return err; } if (cam->state & DEV_DISCONNECTED) { up(&cam->fileop_sem); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { up(&cam->fileop_sem); return -EIO; } } f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); 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); if (count > f->buf.bytesused) count = f->buf.bytesused; if (copy_to_user(buf, f->bufmem, count)) { up(&cam->fileop_sem); return -EFAULT; } *f_pos += count; PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count) up(&cam->fileop_sem); return count;}static unsigned int sn9c102_poll(struct file *filp, poll_table *wait){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); unsigned int mask = 0; if (down_interruptible(&cam->fileop_sem)) return POLLERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -