📄 em28xx-video.c
字号:
dev->stream_on = 1; fh->stream_on = 1; mutex_unlock(&dev->lock); return rc;}static int res_check(struct em28xx_fh *fh){ return (fh->stream_on);}static void res_free(struct em28xx_fh *fh){ struct em28xx *dev = fh->dev; mutex_lock(&dev->lock); fh->stream_on = 0; dev->stream_on = 0; mutex_unlock(&dev->lock);}/* * em28xx_get_ctrl() * return the current saturation, brightness or contrast, mute state */static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl){ switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = dev->mute; return 0; case V4L2_CID_AUDIO_VOLUME: ctrl->value = dev->volume; return 0; default: return -EINVAL; }}/* * em28xx_set_ctrl() * mute or set new saturation, brightness or contrast */static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl){ switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value != dev->mute) { dev->mute = ctrl->value; return em28xx_audio_analog_set(dev); } return 0; case V4L2_CID_AUDIO_VOLUME: dev->volume = ctrl->value; return em28xx_audio_analog_set(dev); default: return -EINVAL; }}static int check_dev(struct em28xx *dev){ if (dev->state & DEV_DISCONNECTED) { em28xx_errdev("v4l2 ioctl: device not present\n"); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_errdev("v4l2 ioctl: device is misconfigured; " "close and open it again\n"); return -EIO; } return 0;}static void get_scale(struct em28xx *dev, unsigned int width, unsigned int height, unsigned int *hscale, unsigned int *vscale){ unsigned int maxw = norm_maxw(dev); unsigned int maxh = norm_maxh(dev); *hscale = (((unsigned long)maxw) << 12) / width - 4096L; if (*hscale >= 0x4000) *hscale = 0x3fff; *vscale = (((unsigned long)maxh) << 12) / height - 4096L; if (*vscale >= 0x4000) *vscale = 0x3fff;}/* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; mutex_lock(&dev->lock); f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; f->fmt.pix.bytesperline = dev->width * 2; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ f->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; mutex_unlock(&dev->lock); return 0;}static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int width = f->fmt.pix.width; int height = f->fmt.pix.height; unsigned int maxw = norm_maxw(dev); unsigned int maxh = norm_maxh(dev); unsigned int hscale, vscale; /* width must even because of the YUYV format height must be even because of interlacing */ height &= 0xfffe; width &= 0xfffe; if (height < 32) height = 32; if (height > maxh) height = maxh; if (width < 48) width = 48; if (width > maxw) width = maxw; mutex_lock(&dev->lock); if (dev->is_em2800) { /* the em2800 can only scale down to 50% */ if (height % (maxh / 2)) height = maxh; if (width % (maxw / 2)) width = maxw; /* according to empiatech support */ /* the MaxPacketSize is to small to support */ /* framesizes larger than 640x480 @ 30 fps */ /* or 640x576 @ 25 fps. As this would cut */ /* of a part of the image we prefer */ /* 360x576 or 360x480 for now */ if (width == maxw && height == maxh) width /= 2; } get_scale(dev, width, height, &hscale, &vscale); width = (((unsigned long)maxw) << 12) / (hscale + 4096L); height = (((unsigned long)maxh) << 12) / (vscale + 4096L); f->fmt.pix.width = width; f->fmt.pix.height = height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; f->fmt.pix.bytesperline = width * 2; f->fmt.pix.sizeimage = width * 2 * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; mutex_unlock(&dev->lock); return 0;}static int vidioc_s_fmt_vid_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; vidioc_try_fmt_vid_cap(file, priv, f); mutex_lock(&dev->lock); if (videobuf_queue_is_busy(&fh->vb_vidq)) { em28xx_errdev("%s queue busy\n", __func__); rc = -EBUSY; goto out; } if (dev->stream_on && !fh->stream_on) { em28xx_errdev("%s device in use by another fh\n", __func__); rc = -EBUSY; goto out; } /* set new image size */ dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_set_alternate(dev); em28xx_resolution_set(dev); rc = 0;out: mutex_unlock(&dev->lock); return rc;}static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; struct v4l2_format f; int rc; rc = check_dev(dev); if (rc < 0) return rc; mutex_lock(&dev->lock); dev->norm = *norm; mutex_unlock(&dev->lock); /* Adjusts width/height, if needed */ f.fmt.pix.width = dev->width; f.fmt.pix.height = dev->height; vidioc_try_fmt_vid_cap(file, priv, &f); mutex_lock(&dev->lock); /* set new image size */ dev->width = f.fmt.pix.width; dev->height = f.fmt.pix.height; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_resolution_set(dev); em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); mutex_unlock(&dev->lock); return 0;}static const char *iname[] = { [EM28XX_VMUX_COMPOSITE1] = "Composite1", [EM28XX_VMUX_COMPOSITE2] = "Composite2", [EM28XX_VMUX_COMPOSITE3] = "Composite3", [EM28XX_VMUX_COMPOSITE4] = "Composite4", [EM28XX_VMUX_SVIDEO] = "S-Video", [EM28XX_VMUX_TELEVISION] = "Television", [EM28XX_VMUX_CABLE] = "Cable TV", [EM28XX_VMUX_DVB] = "DVB", [EM28XX_VMUX_DEBUG] = "for debug only",};static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; unsigned int n; n = i->index; if (n >= MAX_EM28XX_INPUT) return -EINVAL; if (0 == INPUT(n)->type) return -EINVAL; i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || (EM28XX_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; i->std = dev->vdev->tvnorms; return 0;}static int vidioc_g_input(struct file *file, void *priv, unsigned int *i){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; *i = dev->ctl_input; return 0;}static int vidioc_s_input(struct file *file, void *priv, unsigned int i){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (i >= MAX_EM28XX_INPUT) return -EINVAL; if (0 == INPUT(i)->type) return -EINVAL; mutex_lock(&dev->lock); video_mux(dev, i); mutex_unlock(&dev->lock); return 0;}static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; unsigned int index = a->index; if (a->index > 1) return -EINVAL; index = dev->ctl_ainput; if (index == 0) strcpy(a->name, "Television"); else strcpy(a->name, "Line In"); a->capability = V4L2_AUDCAP_STEREO; a->index = index; return 0;}static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; if (a->index != dev->ctl_ainput) return -EINVAL; return 0;}static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int id = qc->id; int i; int rc; rc = check_dev(dev); if (rc < 0) return rc; memset(qc, 0, sizeof(*qc)); qc->id = id; if (!dev->has_msp34xx) { 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; } } } mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); mutex_unlock(&dev->lock); if (qc->type) return 0; else return -EINVAL;}static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ 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); if (!dev->has_msp34xx) rc = em28xx_get_ctrl(dev, ctrl); else rc = -EINVAL; if (rc == -EINVAL) { em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); rc = 0; } mutex_unlock(&dev->lock); return rc;}static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; u8 i; int rc; rc = check_dev(dev); if (rc < 0) return rc; mutex_lock(&dev->lock); if (dev->has_msp34xx) em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); else { rc = 1; for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { if (ctrl->id == em28xx_qctrl[i].id) { if (ctrl->value < em28xx_qctrl[i].minimum || ctrl->value > em28xx_qctrl[i].maximum) { rc = -ERANGE; break; } rc = em28xx_set_ctrl(dev, ctrl); break; } } } /* Control not found - try to send it to the attached devices */ if (rc == 1) { em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); rc = 0; } mutex_unlock(&dev->lock); return rc;}static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (0 != t->index) return -EINVAL; strcpy(t->name, "Tuner"); mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); mutex_unlock(&dev->lock); return 0;}static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (0 != t->index) return -EINVAL; mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); mutex_unlock(&dev->lock); return 0;}static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0;}static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; rc = check_dev(dev); if (rc < 0) return rc; if (0 != f->tuner) return -EINVAL; if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) return -EINVAL; if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) return -EINVAL; mutex_lock(&dev->lock); dev->ctl_freq = f->frequency; em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); mutex_unlock(&dev->lock); return 0;}#ifdef CONFIG_VIDEO_ADV_DEBUGstatic int em28xx_reg_len(int reg){ switch (reg) { case EM28XX_R40_AC97LSB: case EM28XX_R30_HSCALELOW: case EM28XX_R32_VSCALELOW: return 2; default: return 1; }}static int vidioc_g_register(struct file *file, void *priv, struct v4l2_register *reg){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int ret; if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; if (em28xx_reg_len(reg->reg) == 1) { ret = em28xx_read_reg(dev, reg->reg); if (ret < 0) return ret; reg->val = ret; } else { __le64 val = 0; ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, reg->reg, (char *)&val, 2); if (ret < 0) return ret; reg->val = le64_to_cpu(val); } return 0;}static int vidioc_s_register(struct file *file, void *priv, struct v4l2_register *reg){ struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; __le64 buf; buf = cpu_to_le64(reg->val); return em28xx_write_regs(dev, reg->reg, (char *)&buf, em28xx_reg_len(reg->reg));}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -