📄 bttv-driver.c
字号:
} /* alloc + fill struct bttv_buffer (if changed) */ if (buf->vb.width != width || buf->vb.height != height || buf->vb.field != field || buf->tvnorm != btv->tvnorm || buf->fmt != fmt) { buf->vb.width = width; buf->vb.height = height; buf->vb.field = field; buf->tvnorm = btv->tvnorm; buf->fmt = fmt; redo_dma_risc = 1; } /* alloc risc memory */ if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) goto fail; } if (redo_dma_risc) if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; buf->vb.state = STATE_PREPARED; return 0; fail: bttv_dma_free(q,btv,buf); return rc;}static intbuffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct bttv_fh *fh = q->priv_data; *size = fh->fmt->depth*fh->width*fh->height >> 3; if (0 == *count) *count = gbuffers; while (*size * *count > gbuffers * gbufsize) (*count)--; return 0;}static intbuffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, fh->width, fh->height, field);}static voidbuffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; buf->vb.state = STATE_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; bttv_set_dma(btv, 0x03); }}static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; bttv_dma_free(&fh->cap,fh->btv,buf);}static struct videobuf_queue_ops bttv_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg){ switch (cmd) { case BTTV_VERSION: return BTTV_VERSION_CODE; /* *** v4l1 *** ************************************************ */ case VIDIOCGFREQ: { unsigned long *freq = arg; *freq = btv->freq; return 0; } case VIDIOCSFREQ: { struct v4l2_frequency freq; memset(&freq, 0, sizeof(freq)); freq.frequency = *(unsigned long *)arg; mutex_lock(&btv->lock); freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; btv->freq = *(unsigned long *)arg; bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv,*(unsigned long *)arg); mutex_unlock(&btv->lock); return 0; } 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; mutex_lock(&btv->lock); set_tvnorm(btv,v->mode); bttv_call_i2c_clients(btv,cmd,v); mutex_unlock(&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; mutex_lock(&btv->lock); if (channel == btv->input && v->norm == btv->tvnorm) { /* nothing to do */ mutex_unlock(&btv->lock); return 0; } btv->tvnorm = v->norm; set_input(btv,v->channel); mutex_unlock(&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; mutex_lock(&btv->lock); bttv_call_i2c_clients(btv,cmd,v); /* card specific hooks */ if (btv->audio_hook) btv->audio_hook(btv,v,0); mutex_unlock(&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; mutex_lock(&btv->lock); audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0); bttv_call_i2c_clients(btv,cmd,v); /* card specific hooks */ if (btv->audio_hook) btv->audio_hook(btv,v,1); mutex_unlock(&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; mutex_lock(&btv->lock); set_tvnorm(btv,i); i2c_vidiocschan(btv); mutex_unlock(&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; mutex_lock(&btv->lock); set_input(btv,*i); mutex_unlock(&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; mutex_lock(&btv->lock); memset(t,0,sizeof(*t)); t->rxsubchans = V4L2_TUNER_SUB_MONO; bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); strcpy(t->name, "Television"); t->capability = V4L2_TUNER_CAP_NORM; t->type = V4L2_TUNER_ANALOG_TV; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; if (btv->audio_hook) { /* Hmmm ... */ struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); btv->audio_hook(btv,&va,0); t->audmode = V4L2_TUNER_MODE_MONO; t->rxsubchans = V4L2_TUNER_SUB_MONO; if(va.mode & VIDEO_SOUND_STEREO) { t->audmode = V4L2_TUNER_MODE_STEREO; t->rxsubchans = V4L2_TUNER_SUB_STEREO; } if(va.mode & VIDEO_SOUND_LANG2) { t->audmode = V4L2_TUNER_MODE_LANG1; t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } } /* FIXME: fill capability+audmode */ mutex_unlock(&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; mutex_lock(&btv->lock); bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); if (btv->audio_hook) { 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 || t->audmode == V4L2_TUNER_MODE_LANG1_LANG2) 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; btv->audio_hook(btv,&va,1); } mutex_unlock(&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; mutex_lock(&btv->lock); btv->freq = f->frequency; bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv,btv->freq); mutex_unlock(&btv->lock); return 0; } case VIDIOC_LOG_STATUS: { printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr); bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -