📄 saa7134-video.c
字号:
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_defrect.width / width; if (0 == prescale) prescale = 1; xscale = 1024 * dev->crop_defrect.width / prescale / width; yscale = 512 * div * dev->crop_defrect.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 file *file, struct videobuf_buffer *vb, enum v4l2_field field){ struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; struct saa7134_buf *buf = (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 > dev->crop_current.width || fh->height > dev->crop_current.height) return -EINVAL; size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", vb->i,fh->width,fh->height,size,v4l2_field_names[field], fh->fmt->name); if (buf->vb.width != fh->width || buf->vb.height != fh->height || buf->vb.size != size || buf->vb.field != field || buf->fmt != fh->fmt) { saa7134_dma_free(dev,buf); } if (STATE_NEEDS_INIT == buf->vb.state) { buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; buf->vb.field = field; buf->fmt = fh->fmt; buf->pt = &fh->pt_cap; err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf); if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, buf->vb.dma.sglist, buf->vb.dma.sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; } buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; oops: saa7134_dma_free(dev,buf); return err;}static intbuffer_setup(struct file *file, unsigned int *count, unsigned int *size){ struct saa7134_fh *fh = file->private_data; *size = fh->fmt->depth * fh->width * fh->height >> 3; if (0 == *count) *count = gbuffers; *count = saa7134_buffer_count(*size,*count); return 0;}static void buffer_queue(struct file *file, struct videobuf_buffer *vb){ struct saa7134_fh *fh = file->private_data; struct saa7134_buf *buf = (struct saa7134_buf *)vb; saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);}static void buffer_release(struct file *file, struct videobuf_buffer *vb){ struct saa7134_fh *fh = file->private_data; struct saa7134_buf *buf = (struct saa7134_buf *)vb; saa7134_dma_free(fh->dev,buf);}static struct videobuf_queue_ops video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};/* ------------------------------------------------------------------ */static int get_control(struct saa7134_dev *dev, struct v4l2_control *c){ const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); if (NULL == ctrl) return -EINVAL; switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = dev->ctl_bright; break; case V4L2_CID_HUE: c->value = dev->ctl_hue; break; case V4L2_CID_CONTRAST: c->value = dev->ctl_contrast; break; case V4L2_CID_SATURATION: c->value = dev->ctl_saturation; break; case V4L2_CID_AUDIO_MUTE: c->value = dev->ctl_mute; break; case V4L2_CID_AUDIO_VOLUME: c->value = dev->ctl_volume; break; case V4L2_CID_PRIVATE_INVERT: c->value = dev->ctl_invert; break; case V4L2_CID_VFLIP: c->value = dev->ctl_mirror; break; case V4L2_CID_PRIVATE_Y_EVEN: c->value = dev->ctl_y_even; break; case V4L2_CID_PRIVATE_Y_ODD: c->value = dev->ctl_y_odd; break; default: return -EINVAL; } return 0;}static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c){ const struct v4l2_queryctrl* ctrl; unsigned long flags; int restart_overlay = 0; ctrl = ctrl_by_id(c->id); if (NULL == ctrl) return -EINVAL; dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_INTEGER: if (c->value < ctrl->minimum) c->value = ctrl->minimum; if (c->value > ctrl->maximum) c->value = ctrl->maximum; break; default: /* nothing */; }; switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->ctl_bright = c->value; saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); break; case V4L2_CID_HUE: dev->ctl_hue = c->value; saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); break; case V4L2_CID_CONTRAST: dev->ctl_contrast = c->value; saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); break; case V4L2_CID_SATURATION: dev->ctl_saturation = c->value; saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); break; case V4L2_CID_AUDIO_MUTE: dev->ctl_mute = c->value; saa7134_tvaudio_setmute(dev); break; case V4L2_CID_AUDIO_VOLUME: dev->ctl_volume = c->value; saa7134_tvaudio_setvolume(dev,dev->ctl_volume); break; case V4L2_CID_PRIVATE_INVERT: dev->ctl_invert = c->value; saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); break; case V4L2_CID_VFLIP: dev->ctl_mirror = c->value; restart_overlay = 1; break; case V4L2_CID_PRIVATE_Y_EVEN: dev->ctl_y_even = c->value; restart_overlay = 1; break; case V4L2_CID_PRIVATE_Y_ODD: dev->ctl_y_odd = c->value; restart_overlay = 1; break; default: return -EINVAL; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } return 0;}/* ------------------------------------------------------------------ */static struct videobuf_queue* saa7134_queue(struct saa7134_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 saa7134_resource(struct saa7134_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 video_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct saa7134_dev *h,*dev = NULL; struct saa7134_fh *fh; struct list_head *list;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -