📄 sn9c102_core.c
字号:
rect.width = scale * pix->width; rect.height = scale * pix->height; if (rect.width < 16) rect.width = 16; if (rect.height < 16) rect.height = 16; if (rect.width > bounds->left + bounds->width - rect.left) rect.width = bounds->left + bounds->width - rect.left; if (rect.height > bounds->top + bounds->height - rect.top) rect.height = bounds->top + bounds->height - rect.top; rect.width &= ~15L; rect.height &= ~15L; { /* adjust the scaling factor */ u32 a, b; a = rect.width * rect.height; b = pix->width * pix->height; scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; } 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->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->field = V4L2_FIELD_NONE; if (cmd == VIDIOC_TRY_FMT) { if (copy_to_user(arg, &format, sizeof(format))) return -EFAULT; return 0; } if (cam->module_param.force_munmap) for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. Unmap the " "buffers first."); return -EINVAL; } if (cam->stream == STREAM_ON) if ((err = sn9c102_stream_interrupt(cam))) return err; if (copy_to_user(arg, &format, sizeof(format))) { cam->stream = stream; return -EFAULT; } if (cam->module_param.force_munmap || cam->io == IO_READ) sn9c102_release_buffers(cam); err += sn9c102_set_pix_format(cam, pix); err += sn9c102_set_crop(cam, &rect); if (s->set_pix_format) err += s->set_pix_format(cam, pix); if (s->set_crop) err += s->set_crop(cam, &rect); err += sn9c102_set_scale(cam, scale); if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; 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; } memcpy(pfmt, pix, sizeof(*pix)); memcpy(&(s->_rect), &rect, sizeof(rect)); if ((cam->module_param.force_munmap || cam->io == IO_READ) && nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", cam->v4ldev->minor); return -ENOMEM; } if (cam->io == IO_READ) sn9c102_empty_framequeues(cam); else if (cam->module_param.force_munmap) sn9c102_requeue_outqueue(cam); cam->stream = stream; return 0;}static intsn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg){ if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) return -EFAULT; return 0;}static intsn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg){ 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;}static intsn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg){ struct v4l2_requestbuffers rb; u32 i; int err; if (copy_from_user(&rb, arg, sizeof(rb))) return -EFAULT; if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || rb.memory != V4L2_MEMORY_MMAP) return -EINVAL; if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose the mmap " "I/O method"); return -EINVAL; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " "still mapped."); return -EINVAL; } if (cam->stream == STREAM_ON) if ((err = sn9c102_stream_interrupt(cam))) return err; sn9c102_empty_framequeues(cam); sn9c102_release_buffers(cam); if (rb.count) rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); if (copy_to_user(arg, &rb, sizeof(rb))) { sn9c102_release_buffers(cam); cam->io = IO_NONE; return -EFAULT; } cam->io = rb.count ? IO_MMAP : IO_NONE; return 0;}static intsn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg){ struct v4l2_buffer b; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || b.index >= cam->nbuffers || cam->io != IO_MMAP) return -EINVAL; memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); if (cam->frame[b.index].vma_use_count) b.flags |= V4L2_BUF_FLAG_MAPPED; if (cam->frame[b.index].state == F_DONE) b.flags |= V4L2_BUF_FLAG_DONE; else if (cam->frame[b.index].state != F_UNUSED) b.flags |= V4L2_BUF_FLAG_QUEUED; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; return 0;}static intsn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg){ struct v4l2_buffer b; unsigned long lock_flags; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || b.index >= cam->nbuffers || cam->io != IO_MMAP) return -EINVAL; if (cam->frame[b.index].state != F_UNUSED) return -EINVAL; cam->frame[b.index].state = F_QUEUED; spin_lock_irqsave(&cam->queue_lock, lock_flags); list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); PDBGG("Frame #%lu queued", (unsigned long)b.index); return 0;}static intsn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, void __user * arg){ struct v4l2_buffer b; struct sn9c102_frame_t *f; unsigned long lock_flags; long timeout; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; if (list_empty(&cam->outqueue)) { if (cam->stream == STREAM_OFF) return -EINVAL; if (filp->f_flags & O_NONBLOCK) 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) return timeout; if (cam->state & DEV_DISCONNECTED) return -ENODEV; if (!timeout || (cam->state & DEV_MISCONFIGURED)) return -EIO; } spin_lock_irqsave(&cam->queue_lock, lock_flags); f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); list_del(cam->outqueue.next); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); f->state = F_UNUSED; memcpy(&b, &f->buf, sizeof(b)); if (f->vma_use_count) b.flags |= V4L2_BUF_FLAG_MAPPED; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); return 0;}static intsn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg){ int type; if (copy_from_user(&type, arg, sizeof(type))) return -EFAULT; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; if (list_empty(&cam->inqueue)) return -EINVAL; cam->stream = STREAM_ON; DBG(3, "Stream on"); return 0;}static intsn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg){ int type, err; if (copy_from_user(&type, arg, sizeof(type))) return -EFAULT; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; if (cam->stream == STREAM_ON) if ((err = sn9c102_stream_interrupt(cam))) return err; sn9c102_empty_framequeues(cam); DBG(3, "Stream off"); return 0;}static intsn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg){ 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;}static intsn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg){ 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;}static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, unsigned int cmd, void __user * arg){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); switch (cmd) { case VIDIOC_QUERYCAP: return sn9c102_vidioc_querycap(cam, arg); case VIDIOC_ENUMINPUT: return sn9c102_vidioc_enuminput(cam, arg); case VIDIOC_G_INPUT: return sn9c102_vidioc_g_input(cam, arg); case VIDIOC_S_INPUT: return sn9c102_vidioc_s_input(cam, arg); case VIDIOC_QUERYCTRL: return sn9c102_vidioc_query_ctrl(cam, arg); case VIDIOC_G_CTRL: return sn9c102_vidioc_g_ctrl(cam, arg); case VIDIOC_S_CTRL_OLD: case VIDIOC_S_CTRL: return sn9c102_vidioc_s_ctrl(cam, arg); case VIDIOC_CROPCAP_OLD: case VIDIOC_CROPCAP: return sn9c102_vidioc_cropcap(cam, arg); case VIDIOC_G_CROP: return sn9c102_vidioc_g_crop(cam, arg); case VIDIOC_S_CROP: return sn9c102_vidioc_s_crop(cam, arg); case VIDIOC_ENUM_FMT: return sn9c102_vidioc_enum_fmt(cam, arg); case VIDIOC_G_FMT: return sn9c102_vidioc_g_fmt(cam, arg); case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); case VIDIOC_G_JPEGCOMP: return sn9c102_vidioc_g_jpegcomp(cam, arg); case VIDIOC_S_JPEGCOMP: return sn9c102_vidioc_s_jpegcomp(cam, arg); case VIDIOC_REQBUFS: return sn9c102_vidioc_reqbufs(cam, arg); case VIDIOC_QUERYBUF: return sn9c102_vidioc_querybuf(cam, arg); case VIDIOC_QBUF: return sn9c102_vidioc_qbuf(cam, arg); case VIDIOC_DQBUF: return sn9c102_vidioc_dqbuf(cam, filp, arg); case VIDIOC_STREAMON: return sn9c102_vidioc_streamon(cam, arg); case VIDIOC_STREAMOFF: return sn9c102_vidioc_streamoff(cam, arg); case VIDIOC_G_PARM: return sn9c102_vidioc_g_parm(cam, arg); case VIDIOC_S_PARM_OLD: case VIDIOC_S_PARM: return sn9c102_vidioc_s_parm(cam, arg); case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_QUERYSTD: case VIDIOC_ENUMSTD: case VIDIOC_QUERYMENU: return -EINVAL; default: return -EINVAL; }}static int sn9c102_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); 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; } V4LDBG(3, "sn9c102", cmd); err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); mutex_unlock(&cam->fileop_mutex); return err;}/*****************************************************************************/static struct file_operations sn9c102_fops = { .owner = THIS_MODULE, .open = sn9c102_open, .release = sn9c102_release, .ioctl = sn9c102_ioctl, .read = sn9c102_read, .poll = sn9c102_poll, .mmap = sn9c102_mmap, .llseek = no_llseek,};/*****************************************************************************//* It
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -