📄 em28xx-video.c
字号:
strcpy(a->name, "Television"); } else { strcpy(a->name, "Line In"); } a->capability = V4L2_AUDCAP_STEREO; a->index = index; return 0; } case VIDIOC_S_AUDIO: { struct v4l2_audio *a = arg; if (a->index != dev->ctl_ainput) return -EINVAL; return 0; } /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; int i, id=qc->id; 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; } } } if (dev->decoder == EM28XX_TVP5150) { em28xx_i2c_call_clients(dev,cmd,qc); if (qc->type) return 0; else return -EINVAL; } for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { if (qc->id && qc->id == saa711x_qctrl[i].id) { memcpy(qc, &(saa711x_qctrl[i]), sizeof(*qc)); return 0; } } return -EINVAL; } case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; int retval=-EINVAL; if (!dev->has_msp34xx) retval=em28xx_get_ctrl(dev, ctrl); if (retval==-EINVAL) { if (dev->decoder == EM28XX_TVP5150) { em28xx_i2c_call_clients(dev,cmd,arg); return 0; } return saa711x_get_ctrl(dev, ctrl); } else return retval; } case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; u8 i; if (!dev->has_msp34xx){ 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) return -ERANGE; return em28xx_set_ctrl(dev, ctrl); } } } if (dev->decoder == EM28XX_TVP5150) { em28xx_i2c_call_clients(dev,cmd,arg); return 0; } else if (!dev->has_msp34xx) { 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) return -ERANGE; return em28xx_set_ctrl(dev, ctrl); } } for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { if (ctrl->id == saa711x_qctrl[i].id) { if (ctrl->value < saa711x_qctrl[i].minimum || ctrl->value > saa711x_qctrl[i].maximum) return -ERANGE; return saa711x_set_ctrl(dev, ctrl); } } } return -EINVAL; } /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; int status = 0; if (0 != t->index) return -EINVAL; memset(t, 0, sizeof(*t)); strcpy(t->name, "Tuner"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; /* FIXME: set correct range *//* t->signal = 0xffff;*//* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/ /* No way to get signal strength? */ down(&dev->lock); em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, &status); up(&dev->lock); t->signal = (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, t->afc); return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; int status = 0; if (0 != t->index) return -EINVAL; memset(t, 0, sizeof(*t)); strcpy(t->name, "Tuner"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; /* FIXME: set correct range *//* t->signal = 0xffff; */ /* No way to get signal strength? */ down(&dev->lock); em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, &status); up(&dev->lock); t->signal = (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n", t->signal, t->afc); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; memset(f, 0, sizeof(*f)); f->type = V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; if (0 != f->tuner) return -EINVAL; if (V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; down(&dev->lock); dev->ctl_freq = f->frequency; em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); up(&dev->lock); return 0; } case VIDIOC_CROPCAP: { struct v4l2_cropcap *cc = arg; 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; } case VIDIOC_STREAMON: { int *type = arg; if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) return -EINVAL; if (list_empty(&dev->inqueue)) return -EINVAL; dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); return 0; } case VIDIOC_STREAMOFF: { int *type = arg; int ret; if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) return -EINVAL; if (dev->stream == STREAM_ON) { em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); if ((ret = em28xx_stream_interrupt(dev))) return ret; } em28xx_empty_framequeues(dev); return 0; } default: return v4l_compat_translate_ioctl(inode, filp, cmd, arg, driver_ioctl); } return 0;}/* * em28xx_v4l2_do_ioctl() * This function is _not_ called directly, but from * em28xx_v4l2_ioctl. Userspace * copying is done already, arg is a kernel pointer. */static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, void *arg){ struct em28xx *dev = filp->private_data; if (!dev) return -ENODEV; if (video_debug > 1) v4l_print_ioctl(dev->name,cmd); switch (cmd) { /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap, 0, sizeof(*cap)); 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_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (dev->has_tuner) cap->capabilities |= V4L2_CAP_TUNER; return 0; } /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *fmtd = arg; if (fmtd->index != 0) return -EINVAL; memset(fmtd, 0, sizeof(*fmtd)); 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; } case VIDIOC_G_FMT: { struct v4l2_format *format = arg; em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? "V4L2_BUF_TYPE_VBI_CAPTURE " : "not supported"); if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; format->fmt.pix.width = dev->width; format->fmt.pix.height = dev->height; format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; format->fmt.pix.bytesperline = dev->bytesperline; format->fmt.pix.sizeimage = dev->frame_size; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, dev->height); return 0; } case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: { struct v4l2_format *format = arg; u32 i; int ret = 0; int width = format->fmt.pix.width; int height = format->fmt.pix.height; unsigned int hscale, vscale; unsigned int maxh, maxw; maxw = norm_maxw(dev); maxh = norm_maxh(dev);/* int both_fields; */ em28xx_videodbg("%s: type=%s\n", cmd == VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? "V4L2_BUF_TYPE_VBI_CAPTURE " : "not supported"); if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; em28xx_videodbg("%s: requested %dx%d\n", cmd == VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", format->fmt.pix.width, format->fmt.pix.height); /* FIXME: Move some code away from here */ /* 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; 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; } if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) hscale = 0x3fff; width = (((unsigned long)maxw) << 12) / (hscale + 4096L); if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) vscale = 0x3fff; height = (((unsigned long)maxh) << 12) / (vscale + 4096L); format->fmt.pix.width = width; format->fmt.pix.height = height; format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; format->fmt.pix.bytesperline = width * 2; format->fmt.pix.sizeimage = width * 2 * height; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.field = V4L2_FIELD_INTERLACED; em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", cmd == VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); if (cmd == VIDIOC_TRY_FMT) return 0; for (i = 0; i < dev->num_frames; i++) if (dev->frame[i].vma_use_count) { em28xx_videodbg("VIDIOC_S_FMT failed. " "Unmap the buffers first.\n"); return -EINVAL; } /* stop io in case it is already in progress */ if (dev->stream == STREAM_ON) { em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n"); if ((ret = em28xx_stream_interrupt(dev))) return ret; } em28xx_release_buffers(dev); dev->io = IO_NONE; /* set new image size */ dev->width = width; dev->height = height; dev->frame_size = dev->width * dev->height * 2; dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ dev->bytesperline = dev->width * 2; dev->hscale = hscale; dev->vscale = vscale;/* dev->both_fileds = both_fileds; */ em28xx_uninit_isoc(dev); em28xx_set_alternate(dev); em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); em28xx_init_isoc(dev); return 0; } /* --- streaming capture ------------------------------------- */ case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *rb = arg; u32 i; int ret; if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || rb->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (dev->io == IO_READ) { em28xx_videodbg ("method is set to read;" " close and open the device again to" " choose the mmap I/O method\n"); return -EINVAL; } for (i = 0; i < dev->num_frames; i++) if (dev->frame[i].vma_use_count) { em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); return -EINVAL; } if (dev->stream == STREAM_ON) { em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); if ((ret = em28xx_stream_interrupt(dev))) return ret; } em28xx_empty_framequeues(dev); em28xx_release_buffers(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -