📄 et61x251_core.c
字号:
fmw_length = (u16)(rect->width), fmw_height = (u16)(rect->height); int err = 0; err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) | ((fmw_length & 0x300) >> 4) | ((fmw_height & 0x300) >> 2), 0x6d); if (err) return -EIO; PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", fmw_sx, fmw_sy, fmw_length, fmw_height); return 0;}static int et61x251_init(struct et61x251_device* cam){ struct et61x251_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)) { init_waitqueue_head(&cam->open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); cam->compression.quality = ET61X251_COMPRESSION_QUALITY; } else { /* use current values */ qctrl = s->_qctrl; rect = &(s->_rect); } err += et61x251_set_scale(cam, rect->width / s->pix_format.width); err += et61x251_set_crop(cam, rect); if (err) return err; if (s->init) { err = s->init(cam); if (err) { DBG(3, "Sensor initialization failed"); return err; } } err += et61x251_set_compression(cam, &cam->compression); err += et61x251_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_ET61X251) 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 et61x251_release_resources(struct et61x251_device* cam){ mutex_lock(&et61x251_sysfs_lock); 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); mutex_unlock(&et61x251_sysfs_lock); kfree(cam->control_buffer);}/*****************************************************************************/static int et61x251_open(struct inode* inode, struct file* filp){ struct et61x251_device* cam; int err = 0; /* This is the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&et61x251_disconnect)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); if (mutex_lock_interruptible(&cam->dev_mutex)) { up_read(&et61x251_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; } mutex_unlock(&cam->dev_mutex); err = wait_event_interruptible_exclusive(cam->open, cam->state & DEV_DISCONNECTED || !cam->users); if (err) { up_read(&et61x251_disconnect); return err; } if (cam->state & DEV_DISCONNECTED) { up_read(&et61x251_disconnect); return -ENODEV; } mutex_lock(&cam->dev_mutex); } if (cam->state & DEV_MISCONFIGURED) { err = et61x251_init(cam); if (err) { DBG(1, "Initialization failed again. " "I will retry on next open()."); goto out; } cam->state &= ~DEV_MISCONFIGURED; } if ((err = et61x251_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; et61x251_empty_framequeues(cam); DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);out: mutex_unlock(&cam->dev_mutex); up_read(&et61x251_disconnect); return err;}static int et61x251_release(struct inode* inode, struct file* filp){ struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ et61x251_stop_transfer(cam); et61x251_release_buffers(cam); if (cam->state & DEV_DISCONNECTED) { et61x251_release_resources(cam); mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; } cam->users--; wake_up_interruptible_nr(&cam->open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); mutex_unlock(&cam->dev_mutex); return 0;}static ssize_tet61x251_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos){ struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); struct et61x251_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 -EINVAL; } if (cam->io == IO_NONE) { if (!et61x251_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)) et61x251_empty_framequeues(cam); et61x251_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; } 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; } if (cam->state & DEV_DISCONNECTED) { mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (!timeout || (cam->state & DEV_MISCONFIGURED)) { mutex_unlock(&cam->fileop_mutex); return -EIO; } } f = list_entry(cam->outqueue.prev, struct et61x251_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); et61x251_queue_unusedframes(cam); PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index, count); mutex_unlock(&cam->fileop_mutex); return err ? err : count;}static unsigned int et61x251_poll(struct file *filp, poll_table *wait){ struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); struct et61x251_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 (!et61x251_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); et61x251_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 et61x251_vm_open(struct vm_area_struct* vma){ struct et61x251_frame_t* f = vma->vm_private_data; f->vma_use_count++;}static void et61x251_vm_close(struct vm_area_struct* vma){ /* NOTE: buffers are not freed here */ struct et61x251_frame_t* f = vma->vm_private_data; f->vma_use_count--;}static struct vm_operations_struct et61x251_vm_ops = { .open = et61x251_vm_open, .close = et61x251_vm_close,};static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma){ struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start; void *pos; u32 i; 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 || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(cam->frame[0].buf.length)) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; } for (i = 0; i < cam->nbuffers; i++) { if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) break; } if (i == cam->nbuffers) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; } vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; pos = cam->frame[i].bufmem; while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; size -= PAGE_SIZE; } vma->vm_ops = &et61x251_vm_ops; vma->vm_private_data = &cam->frame[i]; et61x251_vm_open(vma); mutex_unlock(&cam->fileop_mutex); return 0;}/*****************************************************************************/static intet61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg){ struct v4l2_capability cap = { .driver = "et61x251", .version = ET61X251_MODULE_VERSION_CODE, .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 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->usbdev->dev.bus_id, sizeof(cap.bus_info)); if (copy_to_user(arg, &cap, sizeof(cap))) return -EFAULT; return 0;}static intet61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg){ struct v4l2_input i; if (copy_from_user(&i, arg, sizeof(i))) return -EFAULT; if (i.index) return -EINVAL; memset(&i, 0, sizeof(i)); strcpy(i.name, "Camera"); i.type = V4L2_INPUT_TYPE_CAMERA; if (copy_to_user(arg, &i, sizeof(i))) return -EFAULT; return 0;}static intet61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg){ int index = 0; if (copy_to_user(arg, &index, sizeof(index))) return -EFAULT; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -