📄 vivi.c
字号:
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p){ struct vivi_fh *fh = priv; return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK));}#ifdef CONFIG_VIDEO_V4L1_COMPATstatic int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf){ struct vivi_fh *fh = priv; return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);}#endifstatic int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){ struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (i != fh->type) return -EINVAL; return videobuf_streamon(&fh->vb_vidq);}static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i){ struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (i != fh->type) return -EINVAL; return videobuf_streamoff(&fh->vb_vidq);}static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i){ return 0;}/* only one input in this sample driver */static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp){ if (inp->index != 0) return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; inp->std = V4L2_STD_525_60; strcpy(inp->name, "Camera"); return (0);}static int vidioc_g_input(struct file *file, void *priv, unsigned int *i){ *i = 0; return (0);}static int vidioc_s_input(struct file *file, void *priv, unsigned int i){ if (i > 0) return -EINVAL; return (0);} /* --- controls ---------------------------------------------- */static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc){ int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (qc->id && qc->id == vivi_qctrl[i].id) { memcpy(qc, &(vivi_qctrl[i]), sizeof(*qc)); return (0); } return -EINVAL;}static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { ctrl->value = qctl_regs[i]; return (0); } return -EINVAL;}static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { if (ctrl->value < vivi_qctrl[i].minimum || ctrl->value > vivi_qctrl[i].maximum) { return (-ERANGE); } qctl_regs[i] = ctrl->value; return (0); } return -EINVAL;}/* ------------------------------------------------------------------ File operations for the device ------------------------------------------------------------------*/static int vivi_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct vivi_dev *dev; struct vivi_fh *fh = NULL; int i; int retval = 0; printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor); lock_kernel(); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) if (dev->vfd->minor == minor) goto found; unlock_kernel(); return -ENODEV;found: mutex_lock(&dev->mutex); dev->users++; if (dev->users > 1) { dev->users--; retval = -EBUSY; goto unlock; } dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor, v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { dev->users--; retval = -ENOMEM; goto unlock; }unlock: mutex_unlock(&dev->mutex); if (retval) { unlock_kernel(); return retval; } file->private_data = fh; fh->dev = dev; fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fh->fmt = &formats[0]; fh->width = 640; fh->height = 480; /* Put all controls at a sane state */ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) qctl_regs[i] = vivi_qctrl[i].default_value; /* Resets frame counters */ dev->h = 0; dev->m = 0; dev->s = 0; dev->ms = 0; dev->mv_count = 0; dev->jiffies = jiffies; sprintf(dev->timestr, "%02d:%02d:%02d:%03d", dev->h, dev->m, dev->s, dev->ms); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer), fh); vivi_start_thread(fh); unlock_kernel(); return 0;}static ssize_tvivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos){ struct vivi_fh *fh = file->private_data; if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } return 0;}static unsigned intvivi_poll(struct file *file, struct poll_table_struct *wait){ struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; struct videobuf_queue *q = &fh->vb_vidq; dprintk(dev, 1, "%s\n", __func__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; return videobuf_poll_stream(file, q, wait);}static int vivi_close(struct inode *inode, struct file *file){ struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; int minor = iminor(inode); vivi_stop_thread(vidq); videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); kfree(fh); mutex_lock(&dev->mutex); dev->users--; mutex_unlock(&dev->mutex); dprintk(dev, 1, "close called (minor=%d, users=%d)\n", minor, dev->users); return 0;}static int vivi_release(void){ struct vivi_dev *dev; struct list_head *list; while (!list_empty(&vivi_devlist)) { list = vivi_devlist.next; list_del(list); dev = list_entry(list, struct vivi_dev, vivi_devlist); if (-1 != dev->vfd->minor) { printk(KERN_INFO "%s: unregistering /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->num); video_unregister_device(dev->vfd); } else { printk(KERN_INFO "%s: releasing /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->num); video_device_release(dev->vfd); } kfree(dev); } return 0;}static int vivi_mmap(struct file *file, struct vm_area_struct *vma){ struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; int ret; dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ret); return ret;}static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, .release = vivi_close, .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ .compat_ioctl = v4l_compat_ioctl32, .mmap = vivi_mmap, .llseek = no_llseek,};static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff,#ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf,#endif};static struct video_device vivi_template = { .name = "vivi", .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M,};/* ----------------------------------------------------------------- Initialization and module stuff ------------------------------------------------------------------*//* This routine allocates from 1 to n_devs virtual drivers. The real maximum number of virtual drivers will depend on how many drivers will succeed. This is limited to the maximum number of devices that videodev supports. Since there are 64 minors for video grabbers, this is currently the theoretical maximum limit. However, a further limit does exist at videodev that forbids any driver to register more than 32 video grabbers. */static int __init vivi_init(void){ int ret = -ENOMEM, i; struct vivi_dev *dev; struct video_device *vfd; if (n_devs <= 0) n_devs = 1; for (i = 0; i < n_devs; i++) { dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) break; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); init_waitqueue_head(&dev->vidq.wq); /* initialize locks */ spin_lock_init(&dev->slock); mutex_init(&dev->mutex); vfd = video_device_alloc(); if (!vfd) { kfree(dev); break; } *vfd = vivi_template; ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); if (ret < 0) { video_device_release(vfd); kfree(dev); /* If some registers succeeded, keep driver */ if (i) ret = 0; break; } /* Now that everything is fine, let's add it to device list */ list_add_tail(&dev->vivi_devlist, &vivi_devlist); snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", vivi_template.name, vfd->minor); if (video_nr >= 0) video_nr++; dev->vfd = vfd; printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n", VIVI_MODULE_NAME, vfd->num); } if (ret < 0) { vivi_release(); printk(KERN_INFO "Error %d while loading vivi driver\n", ret); } else { printk(KERN_INFO "Video Technology Magazine Virtual Video " "Capture Board ver %u.%u.%u successfully loaded.\n", (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, VIVI_VERSION & 0xFF); /* n_devs will reflect the actual number of allocated devices */ n_devs = i; } return ret;}static void __exit vivi_exit(void){ vivi_release();}module_init(vivi_init);module_exit(vivi_exit);MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");MODULE_LICENSE("Dual BSD/GPL");module_param(video_nr, uint, 0444);MODULE_PARM_DESC(video_nr, "video iminor start number");module_param(n_devs, uint, 0444);MODULE_PARM_DESC(n_devs, "number of video devices to create");module_param_named(debug, vivi_template.debug, int, 0444);MODULE_PARM_DESC(debug, "activates debug info");module_param(vid_limit, int, 0644);MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -