bttv-vbi.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 664 行 · 第 1/2 页
C
664 行
/* bttv - Bt848 frame grabber driver vbi interface (c) 2002 Gerd Knorr <kraxel@bytesex.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/version.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/kdev_t.h>#include <asm/io.h>#include "bttvp.h"#define VBI_DEFLINES 16#define VBI_MAXLINES 32static unsigned int vbibufs = 4;static unsigned int vbi_debug = 0;MODULE_PARM(vbibufs,"i");MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");MODULE_PARM(vbi_debug,"i");MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");#ifdef dprintk# undef dprintk#endif#define dprintk(fmt, arg...) if (vbi_debug) \ printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg)#ifndef HAVE_V4L2/* some dummy defines to avoid cluttering up the source code with a huge number of ifdef's for V4L2 */# define V4L2_BUF_TYPE_CAPTURE -1# define V4L2_BUF_TYPE_VBI -1#endif/* ----------------------------------------------------------------------- *//* vbi risc code + mm */static intvbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf){ int bpl = 2048; bttv_risc_packed(btv, &buf->odd, buf->vb.dma.sglist, 0, bpl-4, 4, btv->vbi.lines); bttv_risc_packed(btv, &buf->even, buf->vb.dma.sglist, btv->vbi.lines * bpl, bpl-4, 4, btv->vbi.lines); return 0;}static int vbi_buffer_prepare(struct bttv *btv, struct bttv_buffer *buf){ int rc; buf->vb.size = btv->vbi.lines * 2 * 2048; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb))) goto fail; if (0 != (rc = vbi_buffer_risc(btv,buf))) goto fail; } buf->vb.state = STATE_PREPARED; dprintk("buf prepare ok: odd=%p even=%p\n",&buf->odd,&buf->even); return 0; fail: bttv_dma_free(btv,buf); return rc;}static voidvbi_buffer_queue(struct bttv *btv, struct bttv_buffer *buf){ unsigned long flags; buf->vb.state = STATE_QUEUED; spin_lock_irqsave(&btv->s_lock,flags); list_add_tail(&buf->vb.queue,&btv->vcapture); bttv_set_dma(btv,0x0c,1); spin_unlock_irqrestore(&btv->s_lock,flags);}static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb){ struct bttv *btv = file->private_data; struct bttv_buffer *buf = (struct bttv_buffer*)vb; bttv_dma_free(btv,buf);}static voidvbi_cancel_all(struct bttv *btv){ unsigned long flags; int i; /* remove queued buffers from list */ spin_lock_irqsave(&btv->s_lock,flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == btv->vbi.bufs[i]) continue; if (btv->vbi.bufs[i]->vb.state == STATE_QUEUED) { list_del(&btv->vbi.bufs[i]->vb.queue); btv->vbi.bufs[i]->vb.state = STATE_ERROR; } } spin_unlock_irqrestore(&btv->s_lock,flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == btv->vbi.bufs[i]) continue; bttv_dma_free(btv,btv->vbi.bufs[i]); } INIT_LIST_HEAD(&btv->vbi.stream);}/* ----------------------------------------------------------------------- */static int vbi_read_start(struct file *file, struct bttv *btv){ int err,size,count,i; if (vbibufs < 2 || vbibufs > VIDEO_MAX_FRAME) vbibufs = 2; count = vbibufs; size = btv->vbi.lines * 2 * 2048; err = videobuf_mmap_setup(file, (struct videobuf_buffer**)btv->vbi.bufs, sizeof(struct bttv_buffer), count,size,V4L2_BUF_TYPE_VBI, vbi_buffer_release); if (err) return err; for (i = 0; i < count; i++) { err = vbi_buffer_prepare(btv,btv->vbi.bufs[i]); if (err) return err; list_add_tail(&btv->vbi.bufs[i]->vb.stream,&btv->vbi.stream); vbi_buffer_queue(btv,btv->vbi.bufs[i]); } btv->vbi.reading = 1; return 0;}static void vbi_read_stop(struct bttv *btv){ int i; vbi_cancel_all(btv); INIT_LIST_HEAD(&btv->vbi.stream); for (i = 0; i < vbibufs; i++) { kfree(btv->vbi.bufs[i]); btv->vbi.bufs[i] = NULL; } btv->vbi.reading = 0;}static void vbi_setlines(struct bttv *btv, int lines){ int vdelay; if (lines < 1) lines = 1; if (lines > VBI_MAXLINES) lines = VBI_MAXLINES; btv->vbi.lines = lines; vdelay = btread(BT848_E_VDELAY_LO); if (vdelay < lines*2) { vdelay = lines*2; btwrite(vdelay,BT848_E_VDELAY_LO); btwrite(vdelay,BT848_O_VDELAY_LO); }}#ifdef HAVE_V4L2static void vbi_fmt(struct bttv *btv, struct v4l2_format *f){ memset(f,0,sizeof(*f)); f->type = V4L2_BUF_TYPE_VBI; f->fmt.vbi.sampling_rate = 35468950; f->fmt.vbi.samples_per_line = 2048; f->fmt.vbi.sample_format = V4L2_VBI_SF_UBYTE; f->fmt.vbi.offset = 244; f->fmt.vbi.count[0] = btv->vbi.lines; f->fmt.vbi.count[1] = btv->vbi.lines; f->fmt.vbi.flags = 0; switch (btv->tvnorm) { case 1: /* NTSC */ f->fmt.vbi.start[0] = 10; f->fmt.vbi.start[1] = 273; break; case 0: /* PAL */ case 2: /* SECAM */ default: f->fmt.vbi.start[0] = 7; f->fmt.vbi.start[1] = 319; }}#endif/* ----------------------------------------------------------------------- *//* vbi interface */static int vbi_open(struct inode *inode, struct file *file){ unsigned int minor = minor(inode->i_rdev); struct bttv *btv = NULL; int i; for (i = 0; i < bttv_num; i++) { if (bttvs[i].vbi_dev.minor == minor) { btv = &bttvs[i]; break; } } if (NULL == btv) return -ENODEV; down(&btv->vbi.lock); if (btv->vbi.users) { up(&btv->vbi.lock); return -EBUSY; } dprintk("open minor=%d\n",minor); file->private_data = btv; btv->vbi.users++; bttv_field_count(btv); vbi_setlines(btv,VBI_DEFLINES); up(&btv->vbi.lock); return 0;}static int vbi_release(struct inode *inode, struct file *file){ struct bttv *btv = file->private_data; down(&btv->vbi.lock); if (btv->vbi.reading) { vbi_read_stop(btv); btv->vbi.read_buf = NULL; } btv->vbi.users--; bttv_field_count(btv); vbi_setlines(btv,0); up(&btv->vbi.lock); return 0;}static int vbi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct bttv *btv = file->private_data;#ifdef HAVE_V4L2 unsigned long flags; int err;#endif if (btv->errors) bttv_reinit_bt848(btv); switch (cmd) { case VIDIOCGCAP: { struct video_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->name,btv->vbi_dev.name); cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; return 0; } /* vbi/teletext ioctls */ case BTTV_VBISIZE: return btv->vbi.lines * 2 * 2048; case BTTV_VERSION: case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGTUNER: case VIDIOCSTUNER: case VIDIOCGCHAN: case VIDIOCSCHAN: return bttv_common_ioctls(btv,cmd,arg);#ifdef HAVE_V4L2 case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->name, btv->name); cap->type = V4L2_TYPE_VBI; cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_READ | V4L2_FLAG_STREAMING | V4L2_FLAG_SELECT; return 0; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; vbi_fmt(btv,f); return 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?