📄 bttv-driver.c
字号:
case V4L2_BUF_TYPE_VIDEO_CAPTURE: memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); pix_format_set_size (&f->fmt.pix, fh->fmt, fh->width, fh->height); f->fmt.pix.field = fh->cap.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: memset(&f->fmt.win,0,sizeof(struct v4l2_window)); f->fmt.win.w = fh->ov.w; f->fmt.win.field = fh->ov.field; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: bttv_vbi_get_fmt(fh,f); return 0; default: return -EINVAL; }}static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, struct v4l2_format *f){ switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { const struct bttv_format *fmt; enum v4l2_field field; unsigned int maxw,maxh; fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; /* fixup format */ maxw = bttv_tvnorms[btv->tvnorm].swidth; maxh = bttv_tvnorms[btv->tvnorm].sheight; field = f->fmt.pix.field; if (V4L2_FIELD_ANY == field) field = (f->fmt.pix.height > maxh/2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_BOTTOM; if (V4L2_FIELD_SEQ_BT == field) field = V4L2_FIELD_SEQ_TB; switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_ALTERNATE: maxh = maxh/2; break; case V4L2_FIELD_INTERLACED: break; case V4L2_FIELD_SEQ_TB: if (fmt->flags & FORMAT_FLAGS_PLANAR) return -EINVAL; break; default: return -EINVAL; } /* update data for the application */ f->fmt.pix.field = field; if (f->fmt.pix.width < 48) f->fmt.pix.width = 48; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; if (f->fmt.pix.width > maxw) f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; pix_format_set_size (&f->fmt.pix, fmt, f->fmt.pix.width & ~3, f->fmt.pix.height); return 0; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: return verify_window(&bttv_tvnorms[btv->tvnorm], &f->fmt.win, 1); case V4L2_BUF_TYPE_VBI_CAPTURE: bttv_vbi_try_fmt(fh,f); return 0; default: return -EINVAL; }}static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, struct v4l2_format *f){ int retval; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { const struct bttv_format *fmt; retval = bttv_switch_type(fh,f->type); if (0 != retval) return retval; retval = bttv_try_fmt(fh,btv,f); if (0 != retval) return retval; fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ down(&fh->cap.lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; up(&fh->cap.lock); return 0; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (no_overlay > 0) { printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } return setup_window(fh, btv, &f->fmt.win, 1); case V4L2_BUF_TYPE_VBI_CAPTURE: retval = bttv_switch_type(fh,f->type); if (0 != retval) return retval; if (locked_btres(fh->btv, RESOURCE_VBI)) return -EBUSY; bttv_vbi_try_fmt(fh,f); bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]); bttv_vbi_get_fmt(fh,f); return 0; default: return -EINVAL; }}static int bttv_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; unsigned long flags; int retval = 0; if (bttv_debug > 1) { switch (_IOC_TYPE(cmd)) { case 'v': printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n", btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ? v4l1_ioctls[_IOC_NR(cmd)] : "???"); break; case 'V': printk("bttv%d: ioctl 0x%x (v4l2, %s)\n", btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); break; default: printk("bttv%d: ioctl 0x%x (???)\n", btv->c.nr, cmd); } } if (btv->errors) bttv_reinit_bt848(btv); switch (cmd) { case VIDIOCSFREQ: case VIDIOCSTUNER: case VIDIOCSCHAN: case VIDIOC_S_CTRL: case VIDIOC_S_STD: case VIDIOC_S_INPUT: case VIDIOC_S_TUNER: case VIDIOC_S_FREQUENCY: retval = v4l2_prio_check(&btv->prio,&fh->prio); if (0 != retval) return retval; }; switch (cmd) { /* *** v4l1 *** ************************************************ */ case VIDIOCGCAP: { struct video_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->name,btv->video_dev->name); if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { /* vbi */ cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; } else { /* others */ cap->type = VID_TYPE_CAPTURE| VID_TYPE_TUNER| VID_TYPE_CLIPPING| VID_TYPE_SCALES; if (no_overlay <= 0) cap->type |= VID_TYPE_OVERLAY; cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; cap->minwidth = 48; cap->minheight = 32; } cap->channels = bttv_tvcards[btv->c.type].video_inputs; cap->audios = bttv_tvcards[btv->c.type].audio_inputs; return 0; } case VIDIOCGPICT: { struct video_picture *pic = arg; memset(pic,0,sizeof(*pic)); pic->brightness = btv->bright; pic->contrast = btv->contrast; pic->hue = btv->hue; pic->colour = btv->saturation; if (fh->fmt) { pic->depth = fh->fmt->depth; pic->palette = fh->fmt->palette; } return 0; } case VIDIOCSPICT: { struct video_picture *pic = arg; const struct bttv_format *fmt; fmt = format_by_palette(pic->palette); if (NULL == fmt) return -EINVAL; down(&fh->cap.lock); if (fmt->depth != pic->depth) { retval = -EINVAL; goto fh_unlock_and_return; } if (fmt->flags & FORMAT_FLAGS_RAW) { /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * RAW_LINES * 2. F1 is stored at offset 0, F2 at buffer size / 2. */ fh->width = RAW_BPL; fh->height = gbufsize / RAW_BPL; btv->init.width = RAW_BPL; btv->init.height = gbufsize / RAW_BPL; } fh->ovfmt = fmt; fh->fmt = fmt; btv->init.ovfmt = fmt; btv->init.fmt = fmt; if (bigendian) { /* dirty hack time: swap bytes for overlay if the display adaptor is big endian (insmod option) */ if (fmt->palette == VIDEO_PALETTE_RGB555 || fmt->palette == VIDEO_PALETTE_RGB565 || fmt->palette == VIDEO_PALETTE_RGB32) { fh->ovfmt = fmt+1; } } bt848_bright(btv,pic->brightness); bt848_contrast(btv,pic->contrast); bt848_hue(btv,pic->hue); bt848_sat(btv,pic->colour); up(&fh->cap.lock); return 0; } case VIDIOCGWIN: { struct video_window *win = arg; memset(win,0,sizeof(*win)); win->x = fh->ov.w.left; win->y = fh->ov.w.top; win->width = fh->ov.w.width; win->height = fh->ov.w.height; return 0; } case VIDIOCSWIN: { struct video_window *win = arg; struct v4l2_window w2; if (no_overlay > 0) { printk ("VIDIOCSWIN: no_overlay\n"); return -EINVAL; } w2.field = V4L2_FIELD_ANY; w2.w.left = win->x; w2.w.top = win->y; w2.w.width = win->width; w2.w.height = win->height; w2.clipcount = win->clipcount; w2.clips = (struct v4l2_clip __user *)win->clips; retval = setup_window(fh, btv, &w2, 0); if (0 == retval) { /* on v4l1 this ioctl affects the read() size too */ fh->width = fh->ov.w.width; fh->height = fh->ov.w.height; btv->init.width = fh->ov.w.width; btv->init.height = fh->ov.w.height; } return retval; } case VIDIOCGFBUF: { struct video_buffer *fbuf = arg; fbuf->base = btv->fbuf.base; fbuf->width = btv->fbuf.fmt.width; fbuf->height = btv->fbuf.fmt.height; fbuf->bytesperline = btv->fbuf.fmt.bytesperline; if (fh->ovfmt) fbuf->depth = fh->ovfmt->depth; return 0; } case VIDIOCSFBUF: { struct video_buffer *fbuf = arg; const struct bttv_format *fmt; unsigned long end; if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; end = (unsigned long)fbuf->base + fbuf->height * fbuf->bytesperline; down(&fh->cap.lock); retval = -EINVAL; switch (fbuf->depth) { case 8: fmt = format_by_palette(VIDEO_PALETTE_HI240); break; case 16: fmt = format_by_palette(VIDEO_PALETTE_RGB565); break; case 24: fmt = format_by_palette(VIDEO_PALETTE_RGB24); break; case 32: fmt = format_by_palette(VIDEO_PALETTE_RGB32); break; case 15: fbuf->depth = 16; fmt = format_by_palette(VIDEO_PALETTE_RGB555); break; default: fmt = NULL; break; } if (NULL == fmt) goto fh_unlock_and_return; fh->ovfmt = fmt; fh->fmt = fmt; btv->init.ovfmt = fmt; btv->init.fmt = fmt; btv->fbuf.base = fbuf->base; btv->fbuf.fmt.width = fbuf->width; btv->fbuf.fmt.height = fbuf->height; if (fbuf->bytesperline) btv->fbuf.fmt.bytesperline = fbuf->bytesperline; else btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; up(&fh->cap.lock); return 0; } case VIDIOCCAPTURE: case VIDIOC_OVERLAY: { struct bttv_buffer *new; int *on = arg; if (*on) { /* verify args */ if (NULL == btv->fbuf.base) return -EINVAL; if (!fh->ov.setup_ok) { dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); return -EINVAL; } } if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) return -EBUSY; down(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_alloc(sizeof(*new)); bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { new = NULL; } /* switch over */ retval = bttv_switch_overlay(btv,fh,new); up(&fh->cap.lock); return retval; } case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; unsigned int i; down(&fh->cap.lock); retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) goto fh_unlock_and_return; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; up(&fh->cap.lock); return 0; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; struct bttv_buffer *buf; enum v4l2_field field; if (vm->frame >= VIDEO_MAX_FRAME) return -EINVAL; down(&fh->cap.lock); retval = -EINVAL; buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; if (NULL == buf) goto fh_unlock_and_return; if (0 == buf->vb.baddr) goto fh_unlock_and_return; if (buf->vb.state == STATE_QUEUED || buf->vb.state == STATE_ACTIVE) goto fh_unlock_and_return; field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_BOTTOM; retval = bttv_prepare_buffer(btv,buf, format_by_palette(vm->format), vm->width,vm->height,field); if (0 != retval) goto fh_unlock_and_return; spin_lock_irqsave(&btv->s_lock,flags); buffer_queue(&fh->cap,&buf->vb); spin_unlock_irqrestore(&btv->s_lock,flags); up(&fh->cap.lock); return 0; } case VIDIOCSYNC: { int *frame = arg; struct bttv_buffer *buf; if (*frame >= VIDEO_MAX_FRAME) return -EINVAL; down(&fh->cap.lock); retval = -EINVAL; buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; if (NULL == buf) goto fh_unlock_and_return; retval = videobuf_waiton(&buf->vb,0,1); if (0 != retval) goto fh_unlock_and_return; switch (buf->vb.state) { case STATE_ERROR: retval = -EIO; /* fall through */ case STATE_DONE: videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma); bttv_dma_free(btv,buf); break; default: retval = -EINVAL; break; } up(&fh->cap.lock); return retval; } case VIDIOCGVBIFMT: { struct vbi_format *fmt = (void *) arg; struct v4l2_format fmt2; if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) { retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); if (0 != retval) return retval; } bttv_vbi_get_fmt(fh, &fmt2); memset(fmt,0,sizeof(*fmt)); fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate; fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line; fmt->sample_format = VIDEO_PALETTE_RAW; fmt->start[0] = fmt2.fmt.vbi.start[0]; fmt->count[0] = fmt2.fmt.vbi.count[0]; fmt->start[1] = fmt2.fmt.vbi.start[1]; fmt->count[1] = fmt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -