📄 em28xx-video.c
字号:
static int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cc){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; cc->bounds.left = 0; cc->bounds.top = 0; cc->bounds.width = dev->width; cc->bounds.height = dev->height; cc->defrect = cc->bounds; cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ cc->pixelaspect.denominator = 59; return 0;}static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (unlikely(res_get(fh) < 0)) return -EBUSY; return (videobuf_streamon(&fh->vb_vidq));}static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (type != fh->type) return -EINVAL; videobuf_streamoff(&fh->vb_vidq); res_free(fh); return 0;}static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); cap->version = EM28XX_VERSION_CODE; cap->capabilities =#if 0 V4L2_CAP_VBI_CAPTURE |#endif V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (dev->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; return 0;}static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fmtd){ if (fmtd->index != 0) return -EINVAL; fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; strcpy(fmtd->description, "Packed YUY2"); fmtd->pixelformat = V4L2_PIX_FMT_YUYV; memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); return 0;}/* Sliced VBI ioctls */static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; mutex_lock(&dev->lock); f->fmt.sliced.service_set = 0; em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); if (f->fmt.sliced.service_set == 0) rc = -EINVAL; mutex_unlock(&dev->lock); return rc;}static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); mutex_unlock(&dev->lock); if (f->fmt.sliced.service_set == 0) return -EINVAL; return 0;}#if 0/* RAW VBI ioctls */static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f){ format->fmt.vbi.sampling_rate = 6750000 * 4; format->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; format->fmt.vbi.offset = 64 * 4; format->fmt.vbi.start[0] = norm->vbi_v_start_0; format->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; format->fmt.vbi.start[1] = norm->vbi_v_start_1; format->fmt.vbi.count[1] = format->fmt.vbi.count[0]; format->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ return 0;}static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f){ format->type = V4L2_BUF_TYPE_VBI_CAPTURE; format->fmt.vbi.sampling_rate = HZ; format->fmt.vbi.samples_per_line = 2048; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; format->fmt.vbi.offset = 244; format->fmt.vbi.flags = 0; format->fmt.vbi.start[0] = 0; format->fmt.vbi.start[1] = 0; return 0;}#endifstatic int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; return (videobuf_reqbufs(&fh->vb_vidq, rb));}static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; return (videobuf_querybuf(&fh->vb_vidq, b));}static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; return (videobuf_qbuf(&fh->vb_vidq, b));}static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; return (videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK));}#ifdef CONFIG_VIDEO_V4L1_COMPATstatic int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf){ struct em28xx_fh *fh = priv; return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);}#endif/* ----------------------------------------------------------- *//* RADIO ESPECIFIC IOCTLS *//* ----------------------------------------------------------- */static int radio_querycap(struct file *file, void *priv, struct v4l2_capability *cap){ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); cap->version = EM28XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0;}static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t){ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; if (unlikely(t->index > 0)) return -EINVAL; strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); return 0;}static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i){ if (i->index != 0) return -EINVAL; strcpy(i->name, "Radio"); i->type = V4L2_INPUT_TYPE_TUNER; return 0;}static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a){ if (unlikely(a->index)) return -EINVAL; strcpy(a->name, "Radio"); return 0;}static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t){ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; if (0 != t->index) return -EINVAL; em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); return 0;}static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a){ return 0;}static int radio_s_input(struct file *file, void *fh, unsigned int i){ return 0;}static int radio_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc){ int i; if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1) return -EINVAL; for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { if (qc->id && qc->id == em28xx_qctrl[i].id) { memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); return 0; } } return -EINVAL;}/* * em28xx_v4l2_open() * inits the device and starts isoc transfer */static int em28xx_v4l2_open(struct inode *inode, struct file *filp){ int minor = iminor(inode); int errCode = 0, radio = 0; struct em28xx *h, *dev = NULL; struct em28xx_fh *fh; enum v4l2_buf_type fh_type = 0; lock_kernel(); list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; } if (h->vbi_dev->minor == minor) { dev = h; fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; } if (h->radio_dev && h->radio_dev->minor == minor) { radio = 1; dev = h; } } if (NULL == dev) { unlock_kernel(); return -ENODEV; } em28xx_videodbg("open minor=%d type=%s users=%d\n", minor, v4l2_type_names[fh_type], dev->users);#if 0 errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE); if (errCode < 0) { em28xx_errdev("Device locked on digital mode. Can't open analog\n"); return -EBUSY; }#endif fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); unlock_kernel(); return -ENOMEM; } mutex_lock(&dev->lock); fh->dev = dev; fh->radio = radio; fh->type = fh_type; filp->private_data = fh; if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { dev->width = norm_maxw(dev); dev->height = norm_maxh(dev); dev->hscale = 0; dev->vscale = 0; em28xx_set_mode(dev, EM28XX_ANALOG_MODE); em28xx_set_alternate(dev); em28xx_resolution_set(dev); /* Needed, since GPIO might have disabled power of some i2c device */ em28xx_config_i2c(dev);#if 0 /* device needs to be initialized before isoc transfer */ video_mux(dev, 0);#endif } if (fh->radio) { em28xx_videodbg("video_open: setting radio device\n");#if 0 em28xx_start_radio(dev);#endif em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); } dev->users++; videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); unlock_kernel(); return errCode;}/* * em28xx_realease_resources() * unregisters the v4l2,i2c and usb devices * called when the device gets disconected or at module unload*/static void em28xx_release_resources(struct em28xx *dev){ /*FIXME: I2C IR should be disconnected */ em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", dev->vdev->num, dev->vbi_dev->num); list_del(&dev->devlist); if (dev->sbutton_input_dev) em28xx_deregister_snapshot_button(dev); if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; } if (dev->vbi_dev) { if (-1 != dev->vbi_dev->minor) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->vdev) { if (-1 != dev->vdev->minor) video_unregister_device(dev->vdev); else video_device_release(dev->vdev); dev->vdev = NULL; } em28xx_i2c_unregister(dev); usb_put_dev(dev->udev); /* Mark device as unused */ em28xx_devused &= ~(1<<dev->devno);}/* * em28xx_v4l2_close() * stops streaming and deallocates all resources allocated by the v4l2 * calls and ioctls */static int em28xx_v4l2_close(struct inode *inode, struct file *filp){ struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; int errCode; em28xx_videodbg("users=%d\n", dev->users); if (res_check(fh)) res_free(fh); mutex_lock(&dev->lock); if (dev->users == 1) { videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); /* the device is already disconnect, free the remaining resources */ if (dev->state & DEV_DISCONNECTED) { em28xx_release_resources(dev); mutex_unlock(&dev->lock); kfree(dev); return 0; } /* do this before setting alternate! */ em28xx_uninit_isoc(dev); em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); /* set alternate 0 */ dev->alt = 0; em28xx_videodbg("setting alternate 0\n"); errCode = usb_set_interface(dev->udev, 0, 0); if (errCode < 0) { em28xx_errdev("cannot change alternate number to " "0 (error=%i)\n", errCode); } } kfree(fh); dev->users--; wake_up_interruptible_nr(&dev->open, 1); mutex_unlock(&dev->lock); return 0;}/* * em28xx_v4l2_read() * will allocate buffers when called for the first time */static ssize_tem28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, loff_t *pos){ struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; /* FIXME: read() is not prepared to allow changing the video resolution while streaming. Seems a bug at em28xx_set_fmt */ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (unlikely(res_get(fh))) return -EBUSY; return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, filp->f_flags & O_NONBLOCK); } return 0;}/* * em28xx_v4l2_poll() * will allocate buffers when called for the first time */static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait){ struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (unlikely(res_get(fh) < 0)) return POLLERR; if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; return videobuf_poll_stream(filp, &fh->vb_vidq, wait);}/* * em28xx_v4l2_mmap() */static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma){ struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; int rc; if (unlikely(res_get(fh) < 0)) return -EBUSY; rc = check_dev(dev); if (rc < 0) return rc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -