📄 bttv-driver.c
字号:
if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, &win->w, clips, n); btcx_sort_clips(clips,n); /* 4-byte alignments */ switch (fh->ovfmt->depth) { case 8: case 24: btcx_align(&win->w, clips, n, 3); break; case 16: btcx_align(&win->w, clips, n, 1); break; case 32: /* no alignment fixups needed */ break; default: BUG(); } mutex_lock(&fh->cap.lock); kfree(fh->ov.clips); fh->ov.clips = clips; fh->ov.nclips = n; fh->ov.w = win->w; fh->ov.field = win->field; fh->ov.setup_ok = 1; btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; /* update overlay if needed */ retval = 0; if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; new = videobuf_alloc(sizeof(*new)); bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } mutex_unlock(&fh->cap.lock); return retval;}/* ----------------------------------------------------------------------- */static struct videobuf_queue* bttv_queue(struct bttv_fh *fh){ struct videobuf_queue* q = NULL; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: q = &fh->cap; break; case V4L2_BUF_TYPE_VBI_CAPTURE: q = &fh->vbi; break; default: BUG(); } return q;}static int bttv_resource(struct bttv_fh *fh){ int res = 0; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: res = RESOURCE_VIDEO; break; case V4L2_BUF_TYPE_VBI_CAPTURE: res = RESOURCE_VBI; break; default: BUG(); } return res;}static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type){ struct videobuf_queue *q = bttv_queue(fh); int res = bttv_resource(fh); if (check_btres(fh,res)) return -EBUSY; if (videobuf_queue_is_busy(q)) return -EBUSY; fh->type = type; return 0;}static voidpix_format_set_size (struct v4l2_pix_format * f, const struct bttv_format * fmt, unsigned int width, unsigned int height){ f->width = width; f->height = height; if (fmt->flags & FORMAT_FLAGS_PLANAR) { f->bytesperline = width; /* Y plane */ f->sizeimage = (width * height * fmt->depth) >> 3; } else { f->bytesperline = (width * fmt->depth) >> 3; f->sizeimage = height * f->bytesperline; }}static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f){ switch (f->type) { 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 */ mutex_lock(&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; mutex_unlock(&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) v4l_print_ioctl(btv->c.name, 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; mutex_lock(&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); mutex_unlock(&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; mutex_lock(&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; mutex_unlock(&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; mutex_lock(&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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -