📄 saa7134-video.c
字号:
BUG(); down(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk("res: put %d\n",bits); up(&dev->lock);}/* ------------------------------------------------------------------ */static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm){ int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; sync_control = norm->sync_control; if (mux > 5) luma_control |= 0x80; /* svideo */ if (noninterlaced || dev->nosignal) sync_control |= 0x20; /* setup cropping */ dev->crop_bounds.left = norm->h_start; dev->crop_defrect.left = norm->h_start; dev->crop_bounds.width = norm->h_stop - norm->h_start +1; dev->crop_defrect.width = norm->h_stop - norm->h_start +1; dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; dev->crop_defrect.top = norm->video_v_start*2; dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) - dev->crop_bounds.top; dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; dev->crop_current = dev->crop_defrect; /* setup video decoder */ saa_writeb(SAA7134_INCR_DELAY, 0x08); saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); saa_writeb(SAA7134_HSYNC_START, 0xeb); saa_writeb(SAA7134_HSYNC_STOP, 0xe0); saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); saa_writeb(SAA7134_SYNC_CTRL, sync_control); saa_writeb(SAA7134_LUMA_CTRL, luma_control); saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); saa_writeb(SAA7134_ANALOG_ADC, 0x01); saa_writeb(SAA7134_VGATE_START, 0x11); saa_writeb(SAA7134_VGATE_STOP, 0xfe); saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);}static void video_mux(struct saa7134_dev *dev, int input){ dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); dev->ctl_input = input; set_tvnorm(dev,dev->tvnorm); saa7134_tvaudio_setinput(dev,&card_in(dev,input));}static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale){ static const struct { int xpsc; int xacl; int xc2_1; int xdcg; int vpfy; } vals[] = { /* XPSC XACL XC2_1 XDCG VPFY */ { 1, 0, 0, 0, 0 }, { 2, 2, 1, 2, 2 }, { 3, 4, 1, 3, 2 }, { 4, 8, 1, 4, 2 }, { 5, 8, 1, 4, 2 }, { 6, 8, 1, 4, 3 }, { 7, 8, 1, 4, 3 }, { 8, 15, 0, 4, 3 }, { 9, 15, 0, 4, 3 }, { 10, 16, 1, 5, 3 }, }; static const int count = ARRAY_SIZE(vals); int i; for (i = 0; i < count; i++) if (vals[i].xpsc == prescale) break; if (i == count) return; saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); saa_writeb(SAA7134_LEVEL_CTRL(task), (vals[i].xc2_1 << 3) | (vals[i].xdcg)); saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, (vals[i].vpfy << 2) | vals[i].vpfy);}static void set_v_scale(struct saa7134_dev *dev, int task, int yscale){ int val,mirror; saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); mirror = (dev->ctl_mirror) ? 0x02 : 0x00; if (yscale < 2048) { /* LPI */ dprintk("yscale LPI yscale=%d\n",yscale); saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); } else { /* ACM */ val = 0x40 * 1024 / yscale; dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), val); saa_writeb(SAA7134_CHROMA_SATURATION(task), val); } saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80);}static void set_size(struct saa7134_dev *dev, int task, int width, int height, int interlace){ int prescale,xscale,yscale,y_even,y_odd; int h_start, h_stop, v_start, v_stop; int div = interlace ? 2 : 1; /* setup video scaler */ h_start = dev->crop_current.left; v_start = dev->crop_current.top/2; h_stop = (dev->crop_current.left + dev->crop_current.width -1); v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); prescale = dev->crop_current.width / width; if (0 == prescale) prescale = 1; xscale = 1024 * dev->crop_current.width / prescale / width; yscale = 512 * div * dev->crop_current.height / height; dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); set_h_prescale(dev,task,prescale); saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); set_v_scale(dev,task,yscale); saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); /* deinterlace y offsets */ y_odd = dev->ctl_y_odd; y_even = dev->ctl_y_even; saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);}/* ------------------------------------------------------------------ */struct cliplist { __u16 position; __u8 enable; __u8 disable;};static void sort_cliplist(struct cliplist *cl, int entries){ struct cliplist swap; int i,j,n; for (i = entries-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (cl[j].position > cl[j+1].position) { swap = cl[j]; cl[j] = cl[j+1]; cl[j+1] = swap; n++; } } if (0 == n) break; }}static void set_cliplist(struct saa7134_dev *dev, int reg, struct cliplist *cl, int entries, char *name){ __u8 winbits = 0; int i; for (i = 0; i < entries; i++) { winbits |= cl[i].enable; winbits &= ~cl[i].disable; if (i < 15 && cl[i].position == cl[i+1].position) continue; saa_writeb(reg + 0, winbits); saa_writeb(reg + 2, cl[i].position & 0xff); saa_writeb(reg + 3, cl[i].position >> 8); dprintk("clip: %s winbits=%02x pos=%d\n", name,winbits,cl[i].position); reg += 8; } for (; reg < 0x400; reg += 8) { saa_writeb(reg+ 0, 0); saa_writeb(reg + 1, 0); saa_writeb(reg + 2, 0); saa_writeb(reg + 3, 0); }}static int clip_range(int val){ if (val < 0) val = 0; return val;}static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, int nclips, int interlace){ struct cliplist col[16], row[16]; int cols, rows, i; int div = interlace ? 2 : 1; memset(col,0,sizeof(col)); cols = 0; memset(row,0,sizeof(row)); rows = 0; for (i = 0; i < nclips && i < 8; i++) { col[cols].position = clip_range(clips[i].c.left); col[cols].enable = (1 << i); cols++; col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); col[cols].disable = (1 << i); cols++; row[rows].position = clip_range(clips[i].c.top / div); row[rows].enable = (1 << i); rows++; row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) / div); row[rows].disable = (1 << i); rows++; } sort_cliplist(col,cols); sort_cliplist(row,rows); set_cliplist(dev,0x380,col,cols,"cols"); set_cliplist(dev,0x384,row,rows,"rows"); return 0;}static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win){ enum v4l2_field field; int maxw, maxh; if (NULL == dev->ovbuf.base) return -EINVAL; if (NULL == dev->ovfmt) return -EINVAL; if (win->w.width < 48 || win->w.height < 32) return -EINVAL; if (win->clipcount > 2048) return -EINVAL; field = win->field; maxw = dev->crop_current.width; maxh = dev->crop_current.height; 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; } win->field = field; if (win->w.width > maxw) win->w.width = maxw; if (win->w.height > maxh) win->w.height = maxh; return 0;}static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh){ unsigned long base,control,bpl; int err; err = verify_preview(dev,&fh->win); if (0 != err) return err; dev->ovfield = fh->win.field; dprintk("start_preview %dx%d+%d+%d %s field=%s\n", fh->win.w.width,fh->win.w.height, fh->win.w.left,fh->win.w.top, dev->ovfmt->name,v4l2_field_names[dev->ovfield]); /* setup window + clipping */ set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, V4L2_FIELD_HAS_BOTH(dev->ovfield)); setup_clipping(dev,fh->clips,fh->nclips, V4L2_FIELD_HAS_BOTH(dev->ovfield)); if (dev->ovfmt->yuv) saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); else saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); /* dma: setup channel 1 (= Video Task B) */ base = (unsigned long)dev->ovbuf.base; base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; base += dev->ovfmt->depth/8 * fh->win.w.left; bpl = dev->ovbuf.fmt.bytesperline; control = SAA7134_RS_CONTROL_BURST_16; if (dev->ovfmt->bswap) control |= SAA7134_RS_CONTROL_BSWAP; if (dev->ovfmt->wswap) control |= SAA7134_RS_CONTROL_WSWAP; if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { saa_writel(SAA7134_RS_BA1(1),base); saa_writel(SAA7134_RS_BA2(1),base+bpl); saa_writel(SAA7134_RS_PITCH(1),bpl*2); saa_writel(SAA7134_RS_CONTROL(1),control); } else { saa_writel(SAA7134_RS_BA1(1),base); saa_writel(SAA7134_RS_BA2(1),base); saa_writel(SAA7134_RS_PITCH(1),bpl); saa_writel(SAA7134_RS_CONTROL(1),control); } /* start dma */ dev->ovenable = 1; saa7134_set_dmabits(dev); return 0;}static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh){ dev->ovenable = 0; saa7134_set_dmabits(dev); return 0;}/* ------------------------------------------------------------------ */static int buffer_activate(struct saa7134_dev *dev, struct saa7134_buf *buf, struct saa7134_buf *next){ unsigned long base,control,bpl; unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; set_size(dev,TASK_A,buf->vb.width,buf->vb.height, V4L2_FIELD_HAS_BOTH(buf->vb.field)); if (buf->fmt->yuv) saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); else saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); /* DMA: setup channel 0 (= Video Task A0) */ base = saa7134_buffer_base(buf); if (buf->fmt->planar) bpl = buf->vb.width; else bpl = (buf->vb.width * buf->fmt->depth) / 8; control = SAA7134_RS_CONTROL_BURST_16 | SAA7134_RS_CONTROL_ME | (buf->pt->dma >> 12); if (buf->fmt->bswap) control |= SAA7134_RS_CONTROL_BSWAP; if (buf->fmt->wswap) control |= SAA7134_RS_CONTROL_WSWAP; if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { /* interlaced */ saa_writel(SAA7134_RS_BA1(0),base); saa_writel(SAA7134_RS_BA2(0),base+bpl); saa_writel(SAA7134_RS_PITCH(0),bpl*2); } else { /* non-interlaced */ saa_writel(SAA7134_RS_BA1(0),base); saa_writel(SAA7134_RS_BA2(0),base); saa_writel(SAA7134_RS_PITCH(0),bpl); } saa_writel(SAA7134_RS_CONTROL(0),control); if (buf->fmt->planar) { /* DMA: setup channel 4+5 (= planar task A) */ bpl_uv = bpl >> buf->fmt->hshift; lines_uv = buf->vb.height >> buf->fmt->vshift; base2 = base + bpl * buf->vb.height; base3 = base2 + bpl_uv * lines_uv; if (buf->fmt->uvswap) tmp = base2, base2 = base3, base3 = tmp; dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", bpl_uv,lines_uv,base2,base3); if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { /* interlaced */ saa_writel(SAA7134_RS_BA1(4),base2); saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); saa_writel(SAA7134_RS_BA1(5),base3); saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); } else { /* non-interlaced */ saa_writel(SAA7134_RS_BA1(4),base2); saa_writel(SAA7134_RS_BA2(4),base2); saa_writel(SAA7134_RS_PITCH(4),bpl_uv); saa_writel(SAA7134_RS_BA1(5),base3); saa_writel(SAA7134_RS_BA2(5),base3); saa_writel(SAA7134_RS_PITCH(5),bpl_uv); } saa_writel(SAA7134_RS_CONTROL(4),control); saa_writel(SAA7134_RS_CONTROL(5),control); } /* start DMA */ saa7134_set_dmabits(dev); mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); return 0;}static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct saa7134_fh *fh = q->priv_data; struct saa7134_dev *dev = fh->dev; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); unsigned int size; int err; /* sanity checks */ if (NULL == fh->fmt) return -EINVAL; if (fh->width < 48 || fh->height < 32 || fh->width/4 > dev->crop_current.width || fh->height/4 > dev->crop_current.height || fh->width > dev->crop_bounds.width || fh->height > dev->crop_bounds.height)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -