📄 bttv-driver.c
字号:
case VIDIOCGTUNER: { struct video_tuner *v = arg; if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (v->tuner) /* Only tuner 0 */ return -EINVAL; strcpy(v->name, "Television"); v->rangelow = 0; v->rangehigh = 0x7FFFFFFF; v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; v->mode = btv->tvnorm; v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; bttv_call_i2c_clients(btv,cmd,v); return 0; } case VIDIOCSTUNER: { struct video_tuner *v = arg; if (v->tuner) /* Only tuner 0 */ return -EINVAL; if (v->mode >= BTTV_TVNORMS) return -EINVAL; down(&btv->lock); set_tvnorm(btv,v->mode); bttv_call_i2c_clients(btv,cmd,v); up(&btv->lock); return 0; } case VIDIOCGCHAN: { struct video_channel *v = arg; unsigned int channel = v->channel; if (channel >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; v->tuners=0; v->flags = VIDEO_VC_AUDIO; v->type = VIDEO_TYPE_CAMERA; v->norm = btv->tvnorm; if (channel == bttv_tvcards[btv->c.type].tuner) { strcpy(v->name,"Television"); v->flags|=VIDEO_VC_TUNER; v->type=VIDEO_TYPE_TV; v->tuners=1; } else if (channel == btv->svhs) { strcpy(v->name,"S-Video"); } else { sprintf(v->name,"Composite%d",channel); } return 0; } case VIDIOCSCHAN: { struct video_channel *v = arg; unsigned int channel = v->channel; if (channel >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; if (v->norm >= BTTV_TVNORMS) return -EINVAL; down(&btv->lock); if (channel == btv->input && v->norm == btv->tvnorm) { /* nothing to do */ up(&btv->lock); return 0; } btv->tvnorm = v->norm; set_input(btv,v->channel); up(&btv->lock); return 0; } case VIDIOCGAUDIO: { struct video_audio *v = arg; memset(v,0,sizeof(*v)); strcpy(v->name,"Television"); v->flags |= VIDEO_AUDIO_MUTABLE; v->mode = VIDEO_SOUND_MONO; down(&btv->lock); bttv_call_i2c_clients(btv,cmd,v); /* card specific hooks */ if (btv->audio_hook) btv->audio_hook(btv,v,0); up(&btv->lock); return 0; } case VIDIOCSAUDIO: { struct video_audio *v = arg; unsigned int audio = v->audio; if (audio >= bttv_tvcards[btv->c.type].audio_inputs) return -EINVAL; down(&btv->lock); audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE); bttv_call_i2c_clients(btv,cmd,v); /* card specific hooks */ if (btv->audio_hook) btv->audio_hook(btv,v,1); up(&btv->lock); return 0; } /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; unsigned int index = e->index; if (index >= BTTV_TVNORMS) return -EINVAL; v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, bttv_tvnorms[e->index].name); e->index = index; return 0; } case VIDIOC_G_STD: { v4l2_std_id *id = arg; *id = bttv_tvnorms[btv->tvnorm].v4l2_id; return 0; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; unsigned int i; for (i = 0; i < BTTV_TVNORMS; i++) if (*id & bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) return -EINVAL; down(&btv->lock); set_tvnorm(btv,i); i2c_vidiocschan(btv); up(&btv->lock); return 0; } case VIDIOC_QUERYSTD: { v4l2_std_id *id = arg; if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) *id = V4L2_STD_625_50; else *id = V4L2_STD_525_60; return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; unsigned int n; n = i->index; if (n >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; i->audioset = 0; if (i->index == bttv_tvcards[btv->c.type].tuner) { sprintf(i->name, "Television"); i->type = V4L2_INPUT_TYPE_TUNER; i->tuner = 0; } else if (i->index == btv->svhs) { sprintf(i->name, "S-Video"); } else { sprintf(i->name,"Composite%d",i->index); } if (i->index == btv->input) { __u32 dstatus = btread(BT848_DSTATUS); if (0 == (dstatus & BT848_DSTATUS_PRES)) i->status |= V4L2_IN_ST_NO_SIGNAL; if (0 == (dstatus & BT848_DSTATUS_HLOC)) i->status |= V4L2_IN_ST_NO_H_LOCK; } for (n = 0; n < BTTV_TVNORMS; n++) i->std |= bttv_tvnorms[n].v4l2_id; return 0; } case VIDIOC_G_INPUT: { int *i = arg; *i = btv->input; return 0; } case VIDIOC_S_INPUT: { unsigned int *i = arg; if (*i > bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; down(&btv->lock); set_input(btv,*i); up(&btv->lock); return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; down(&btv->lock); memset(t,0,sizeof(*t)); strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rxsubchans = V4L2_TUNER_SUB_MONO; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; { struct video_tuner tuner; memset(&tuner, 0, sizeof (tuner)); tuner.rangehigh = 0xffffffffUL; bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner); t->rangelow = tuner.rangelow; t->rangehigh = tuner.rangehigh; } { /* Hmmm ... */ struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,0); if(va.mode & VIDEO_SOUND_STEREO) { t->audmode = V4L2_TUNER_MODE_STEREO; t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } if(va.mode & VIDEO_SOUND_LANG1) { t->audmode = V4L2_TUNER_MODE_LANG1; t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } } /* FIXME: fill capability+audmode */ up(&btv->lock); return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; down(&btv->lock); { struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); 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 (btv->audio_hook) btv->audio_hook(btv,&va,1); } up(&btv->lock); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; memset(f,0,sizeof(*f)); f->type = V4L2_TUNER_ANALOG_TV; f->frequency = btv->freq; return 0; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; if (unlikely(f->tuner != 0)) return -EINVAL; if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) return -EINVAL; down(&btv->lock); btv->freq = f->frequency; bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv,btv->freq); up(&btv->lock); return 0; } case VIDIOC_LOG_STATUS: { bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); return 0; } default: return -ENOIOCTLCMD; } return 0;}static int verify_window(const struct bttv_tvnorm *tvn, struct v4l2_window *win, int fixup){ enum v4l2_field field; int maxw, maxh; if (win->w.width < 48 || win->w.height < 32) return -EINVAL; if (win->clipcount > 2048) return -EINVAL; field = win->field; maxw = tvn->swidth; maxh = tvn->sheight; if (V4L2_FIELD_ANY == field) { field = (win->w.height > maxh/2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; } switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: break; default: return -EINVAL; } if (!fixup && (win->w.width > maxw || win->w.height > maxh)) return -EINVAL; if (win->w.width > maxw) win->w.width = maxw; if (win->w.height > maxh) win->w.height = maxh; win->field = field; return 0;}static int setup_window(struct bttv_fh *fh, struct bttv *btv, struct v4l2_window *win, int fixup){ struct v4l2_clip *clips = NULL; int n,size,retval = 0; if (NULL == fh->ovfmt) return -EINVAL; if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) return -EINVAL; retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup); if (0 != retval) return retval; /* copy clips -- luckily v4l1 + v4l2 are binary compatible here ...*/ n = win->clipcount; size = sizeof(*clips)*(n+4); clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; if (n > 0) { if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { kfree(clips); return -EFAULT; } } /* clip against screen */ 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(); } down(&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); } up(&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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -