bttv-driver.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页
C
2,527 行
struct v4l2_tuner *t = arg; down(&btv->lock); memset(t,0,sizeof(*t)); t->input = bttv_tvcards[btv->type].tuner; strcpy(t->name, "Television"); v4l2_video_std_construct(&t->std, bttv_tvnorms[btv->tvnorm].v4l2_id, 0); t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; t->rxsubchans = V4L2_TUNER_SUB_MONO; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; { /* Hmmm ... */ struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (bttv_tvcards[btv->type].audio_hook) bttv_tvcards[btv->type].audio_hook(btv,&va,0); if(va.mode & VIDEO_SOUND_STEREO) t->rxsubchans |= V4L2_TUNER_SUB_STEREO; if(va.mode & VIDEO_SOUND_LANG1) t->rxsubchans |= V4L2_TUNER_SUB_LANG1; if(va.mode & VIDEO_SOUND_LANG2) t->rxsubchans |= V4L2_TUNER_SUB_LANG2; } /* FIXME: fill capability+audmode */ up(&btv->lock); return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; if(t->input!=bttv_tvcards[btv->type].tuner) return -EINVAL; down(&btv->lock); { struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); if (t->audmode == V4L2_TUNER_MODE_MONO) va.mode = VIDEO_SOUND_MONO; else if (t->audmode == V4L2_TUNER_MODE_STEREO) va.mode = VIDEO_SOUND_STEREO; else if (t->audmode == V4L2_TUNER_MODE_LANG1) va.mode = VIDEO_SOUND_LANG1; else if (t->audmode == V4L2_TUNER_MODE_LANG2) va.mode = VIDEO_SOUND_LANG2; bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); if (bttv_tvcards[btv->type].audio_hook) bttv_tvcards[btv->type].audio_hook(btv,&va,1); } up(&btv->lock); return 0; }#endif /* HAVE_V4L2 */ default: return -ENOIOCTLCMD; } return 0;}static int setup_window(struct bttv_fh *fh, struct bttv *btv, int x, int y, int width, int height, struct video_clip *user_clips, int nclips){ struct video_clip *clips = NULL; int n,size,retval = 0; if (width < 48 || height < 32 || width > bttv_tvnorms[btv->tvnorm].swidth || height > bttv_tvnorms[btv->tvnorm].sheight || NULL == fh->ovfmt) return -EINVAL; if (nclips > 2048) return -EINVAL; /* copy clips -- luckily v4l1 + v4l2 are binary compatible here ...*/ n = nclips; size = sizeof(struct video_clip)*(n+4); clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; if (n > 0) { if (copy_from_user(clips,user_clips, sizeof(struct video_clip)*nclips)) { kfree(clips); return -EFAULT; } } /* clip against screen */ if (NULL != btv->fbuf.base) n = bttv_screen_clips(&btv->fbuf, x, y, width, height, clips, n); bttv_sort_clips(clips,nclips); down(&fh->lock); if (fh->ov.clips) kfree(fh->ov.clips); fh->ov.clips = clips; fh->ov.nclips = nclips; fh->ov.x = x; fh->ov.y = y; fh->ov.width = width; fh->ov.height = height; btv->init.ov.width = width; btv->init.ov.height = height; /* update overlay if needed */ retval = 0; if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; new = videobuf_alloc(sizeof(*new),V4L2_BUF_TYPE_CAPTURE); bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } up(&fh->lock); return retval;}static void release_buffer(struct file *file, struct videobuf_buffer *vb){ struct bttv_buffer *buf = (struct bttv_buffer*)vb; struct bttv_fh *fh = file->private_data; bttv_dma_free(fh->btv,buf);}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; int retval; if (bttv_debug > 1) { switch (_IOC_TYPE(cmd)) { case 'v': printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n", btv->nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ? v4l1_ioctls[_IOC_NR(cmd)] : "???"); break; case 'V': printk("bttv%d: ioctl 0x%x (v4l2, VIDIOC_%s)\n", btv->nr, cmd, (_IOC_NR(cmd) < V4L2_IOCTLS) ? v4l2_ioctls[_IOC_NR(cmd)] : "???"); break; default: printk("bttv%d: ioctl 0x%x (???)\n", btv->nr, cmd); } } if (btv->errors) bttv_reinit_bt848(btv); switch (cmd) { /* *** v4l1 *** ************************************************ */ case VIDIOCGCAP: { struct video_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->name,btv->video_dev.name); cap->type = VID_TYPE_CAPTURE| VID_TYPE_TUNER| VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_SCALES; cap->channels = bttv_tvcards[btv->type].video_inputs; cap->audios = bttv_tvcards[btv->type].audio_inputs; cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; cap->minwidth = 48; cap->minheight = 32; 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->buf.fmt) { pic->depth = fh->buf.fmt->depth; pic->palette = fh->buf.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->lock); retval = -EINVAL; if (fmt->depth != pic->depth && !sloppy) goto fh_unlock_and_return; fh->ovfmt = fmt; fh->buf.fmt = fmt; btv->init.ovfmt = fmt; btv->init.buf.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->lock); return 0; } case VIDIOCGWIN: { struct video_window *win = arg; memset(win,0,sizeof(*win)); win->x = fh->ov.x; win->y = fh->ov.y; win->width = fh->ov.width; win->height = fh->ov.height; return 0; } case VIDIOCSWIN: { struct video_window *win = arg; retval = setup_window(fh,btv,win->x,win->y, win->width,win->height, win->clips, win->clipcount); if (0 == retval) { /* on v4l1 this ioctl affects the read() size too */ fh->buf.vb.width = fh->ov.width; fh->buf.vb.height = fh->ov.height; btv->init.buf.vb.width = fh->ov.width; btv->init.buf.vb.height = fh->ov.height; } return retval; } case VIDIOCGFBUF: { struct video_buffer *fbuf = arg; *fbuf = btv->fbuf; 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; if (0 == find_videomem((unsigned long)fbuf->base,end)) return -EINVAL; down(&fh->lock); retval = -EINVAL; if (sloppy) { /* also set the default palette -- for backward compatibility with older versions */ 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->buf.fmt = fmt; btv->init.ovfmt = fmt; btv->init.buf.fmt = fmt; } else { if (15 == fbuf->depth) fbuf->depth = 16; if (fbuf->depth != 8 && fbuf->depth != 16 && fbuf->depth != 24 && fbuf->depth != 32) goto fh_unlock_and_return; } btv->fbuf = *fbuf; up(&fh->lock); return 0; } case VIDIOCCAPTURE:#ifdef HAVE_V4L2 case VIDIOC_PREVIEW:#endif { struct bttv_buffer *new; int *on = arg; if (*on) { /* verify args */ if (NULL == btv->fbuf.base) return -EINVAL; if (fh->ov.width <48 || fh->ov.height<32 || fh->ov.width >bttv_tvnorms[btv->tvnorm].swidth || fh->ov.height>bttv_tvnorms[btv->tvnorm].sheight || NULL == fh->ovfmt) return -EINVAL; } if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) return -EBUSY; down(&fh->lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_alloc(sizeof(*new), V4L2_BUF_TYPE_CAPTURE); bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { new = NULL; } /* switch over */ retval = bttv_switch_overlay(btv,fh,new); up(&fh->lock); return retval; } case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; int i; if (!mmap) return -EINVAL; down(&fh->lock); retval = videobuf_mmap_setup (file,(struct videobuf_buffer**)fh->bufs, sizeof(struct bttv_buffer), gbuffers,gbufsize,V4L2_BUF_TYPE_CAPTURE, release_buffer); 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->lock); return 0; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; struct bttv_buffer *buf; if (vm->frame >= VIDEO_MAX_FRAME) return -EINVAL; down(&fh->lock); retval = -EINVAL; buf = fh->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; retval = bttv_prepare_buffer(btv,buf, format_by_palette(vm->format), vm->width,vm->height,0); if (0 != retval) goto fh_unlock_and_return; bttv_queue_buffer(btv,buf); up(&fh->lock); return 0; } case VIDIOCSYNC: { int *frame = arg; struct bttv_buffer *buf; if (*frame >= VIDEO_MAX_FRAME) return -EINVAL; down(&fh->lock); retval = -EINVAL; buf = fh->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->dev,&buf->vb.dma); bttv_dma_free(btv,buf); break; default: retval = -EINVAL; break; } up(&fh->lock); return retval; } case BTTV_VERSION: case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGTUNER: case VIDIOCSTUNER: case VIDIOCGCHAN: case VIDIOCSCHAN: case VIDIOCGAUDIO: case VIDIOCSAUDIO: return bttv_common_ioctls(btv,cmd,arg);#ifdef HAVE_V4L2 /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; if (0 == v4l2) return -EINVAL; strcpy(cap->name,btv->video_dev.name); cap->type = V4L2_TYPE_CAPTURE; cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_PREVIEW | V4L2_FLAG_READ | V4L2_FLAG_SELECT; if (mmap) cap->flags |= V4L2_FLAG_STREAMING; cap->inputs = bttv_tvcards[btv->type].video_inputs; cap->outputs = 0; cap->audios = bttv_tvcards[btv->type].audio_inputs; cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; cap->minwidth = 48; cap->minheight = 32; cap->maxframerate = 30; return 0; } case VIDIOC_ENUM_PIXFMT: case VIDIOC_ENUM_FBUFFMT: { struct v4l2_fmtdesc *f = arg; int i, index; index = -1; for (i = 0; i < BTTV_FORMATS; i++) { if (bttv_formats[i].fourcc != -1) index++; if (index == f->index) break; } if (BTTV_FORMATS == i) return -EINVAL; if (cmd == VIDIOC_ENUM_FBUFFMT && 0 == (bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) return -EINVAL; memset(f,0,sizeof(*f)); f->index = index; strncpy(f->description,bttv_formats[i].name,31); f->pixelformat = bttv_formats[i].fourcc; f->depth = bttv_formats[i].depth;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?