📄 bttv-driver.c
字号:
} else { for (i=0; i<h; i++, p+=128) p[0]|=lmask&rmask; } }static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr){ u32 line, x, y, bpl, width, height, inter, maxw; u32 bpp, dx, sx, **rp, *ro, *re, flags, len; u32 adr; int i; unsigned char *clipmap, *clipline, cbit, lastbit, outofmem; /* take care: bpp != btv->win.bpp is allowed here */ bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; bpl=btv->win.bpl; adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; if (bttv_debug > 1) printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) width = 1023; /* sanity check */ if(height > 625) height = 625; /* sanity check */ ro=btv->risc_scr_odd; re=btv->risc_scr_even; if (bttv_debug) printk("bttv%d: clip: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); *(ro++)=cpu_to_le32(btv->bus_vbi_even); *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); } if (ncr < 0) { /* bitmap was pased */ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); } else { /* convert rectangular clips to a bitmap */ memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ for (i=0; i<ncr; i++) clip_draw_rectangle(clipmap, cr[i].x, cr[i].y, cr[i].width, cr[i].height); } /* clip against viewing window AND screen so we do not have to rely on the user program */ maxw = (bpl - btv->win.x * btv->win.bpp) / bpp; clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, 0, 1024, 768); clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? (btv->win.sheight-btv->win.y) : height,1024,768); if (btv->win.x<0) clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); if (btv->win.y<0) clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=cpu_to_le32(0); *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=cpu_to_le32(0); /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<<inter) && !outofmem; line++) { y = line>>inter; rp= (line&1) ? &re : &ro; clipline = clipmap + (y<<7); /* running pointers ... */ lastbit = *clipline & 1; for(x=dx=0,sx=0; x<=width && !outofmem;) { if (0 == (x&7)) { /* check bytes not bits if we can ... */ if (lastbit) { while (0xff==*clipline && x<width-8) { x += 8; dx += 8; clipline++; } } else { while (0x00==*clipline && x<width-8) { x += 8; dx += 8; clipline++; } } } cbit = *clipline & (1<<(x&7)); if (x < width && !lastbit == !cbit) { dx++; } else { /* generate the dma controller code */ len = dx * bpp; flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); flags |= ((!sx) ? BT848_RISC_SOL : 0); flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0); if (!lastbit) { *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len); *((*rp)++)=cpu_to_le32(adr + bpp * sx); } else { *((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len); } lastbit=cbit; sx += dx; dx = 1; if (ro - btv->risc_scr_odd>(RISCMEM_LEN>>3) - 16) outofmem++; if (re - btv->risc_scr_even>(RISCMEM_LEN>>3) - 16) outofmem++; } x++; if (0 == (x&7)) clipline++; } if ((!inter)||(line&1)) adr+=bpl; } vfree(clipmap); /* outofmem flag relies on the following code to discard extra data */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); *(ro++)=cpu_to_le32(btv->bus_vbi_even); *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); if (bttv_debug > 1) printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp);}/* * Set the registers for the size we have specified. Don't bother * trying to understand this without the BT848 manual in front of * you [AC]. * * PS: The manual is free for download in .pdf format from * www.brooktree.com - nicely done those folks. */ static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, int odd, int width, int height){ u16 vscale, hscale; u32 xsf, sr; u16 hdelay; u8 crop, vtc; int inter = (height>tvn->sheight/2) ? 0 : 1; int off = odd ? 0x80 : 0x00; int swidth = tvn->swidth; int totalwidth = tvn->totalwidth; int scaledtwidth = tvn->scaledtwidth; if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0) { dprintk("bttv%d: DIGITAL_MODE_VIDEO override width\n",btv->nr); swidth = 720; totalwidth = 858; scaledtwidth = 858; } xsf = (width*scaledtwidth)/swidth; hscale = ((totalwidth*4096UL)/xsf-4096); hdelay = tvn->hdelayx1; hdelay = (hdelay*width)/swidth; hdelay &= 0x3fe; sr=((tvn->sheight>>inter)*512)/height-512; vscale=(0x10000UL-sr)&0x1fff; crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; if (combfilter) { /* Some people say interpolation looks bad ... */ vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); if (width < 769) btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); else btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); } else { vtc = 0; btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); } btwrite(vtc, BT848_E_VTC+off); btwrite(hscale>>8, BT848_E_HSCALE_HI+off); btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); btwrite(width&0xff, BT848_E_HACTIVE_LO+off); btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); btwrite(crop, BT848_E_CROP+off);}static void bt848_set_geo(struct bttv *btv){ u16 ewidth, eheight, owidth, oheight; u16 format, bswap; struct tvnorm *tvn; tvn=&tvnorms[btv->win.norm]; btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0) btwrite(0x39, BT848_VBI_PACK_DEL); else btwrite(0x01, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; if (!in_interrupt()) set_pll(btv); btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; if (0 == btv->risc_cap_odd && 0 == btv->risc_cap_even) { /* overlay only */ owidth = btv->win.width; oheight = btv->win.height; ewidth = btv->win.width; eheight = btv->win.height; format = btv->win.color_fmt; bswap = btv->fb_color_ctl; } else if (-1 != btv->gq_grab && 0 == btv->risc_cap_odd && !btv->win.interlace && btv->scr_on) { /* odd field -> overlay, even field -> capture */ owidth = btv->win.width; oheight = btv->win.height; ewidth = btv->gbuf[btv->gq_grab].width; eheight = btv->gbuf[btv->gq_grab].height; format = (btv->win.color_fmt & 0xf0) | (btv->gbuf[btv->gq_grab].fmt & 0x0f); bswap = btv->fb_color_ctl & 0x0a; } else { /* capture only */ owidth = btv->gbuf[btv->gq_grab].width; oheight = btv->gbuf[btv->gq_grab].height; ewidth = btv->gbuf[btv->gq_grab].width; eheight = btv->gbuf[btv->gq_grab].height; format = btv->gbuf[btv->gq_grab].fmt; bswap = 0; } /* program odd + even fields */ bt848_set_eogeo(btv, tvn, 1, owidth, oheight); bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); btwrite(format, BT848_COLOR_FMT); btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);}static int bpp2fmt[4] = { BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 };static void bt848_set_winsize(struct bttv *btv){ unsigned short format; if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { /* format set by VIDIOCSPICT */ format = palette2fmt[btv->picture.palette]; } else { /* use default for the given color depth */ format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; } btv->win.color_fmt = format; if (bigendian && format == BT848_COLOR_FMT_RGB32) { btv->fb_color_ctl = BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN | BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN; } else if (bigendian && (format == BT848_COLOR_FMT_RGB16 || format == BT848_COLOR_FMT_RGB15)) { btv->fb_color_ctl = BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN; } else { btv->fb_color_ctl = 0; } /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the * data sheet? [AC - because it's a standard format so I guess * it never occurred to them] * Enable dithering in this mode. */ if (format==BT848_COLOR_FMT_RGB8) btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); bt848_set_geo(btv);}/* * Grab into virtual memory. */static int vgrab(struct bttv *btv, struct video_mmap *mp){ u32 *ro, *re; u32 *vbuf; unsigned long flags; if(btv->fbuffer==NULL) { if(fbuffer_alloc(btv)) return -ENOBUFS; } if(mp->frame >= gbuffers || mp->frame < 0) return -EINVAL; if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) return -EBUSY; if(mp->height < 32 || mp->width < 48) return -EINVAL; if (mp->format >= PALETTEFMT_MAX) return -EINVAL; if ((unsigned int)mp->height * mp->width * fmtbppx2[palette2fmt[mp->format]&0x0f]/2 > gbufsize) return -EINVAL; if (UNSET == palette2fmt[mp->format]) return -EINVAL; /* * Ok load up the BT848 */ vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); ro=btv->gbuf[mp->frame].risc; re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); if (bttv_debug) printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", btv->nr,mp->frame,mp->format,mp->width,mp->height); spin_lock_irqsave(&btv->s_lock, flags); btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; btv->gbuf[mp->frame].width = mp->width; btv->gbuf[mp->frame].height = mp->height; btv->gbuf[mp->frame].ro = virt_to_bus(ro); btv->gbuf[mp->frame].re = virt_to_bus(re);#if 1 if (mp->height <= tvnorms[btv->win.norm].sheight/2 && mp->format != VIDEO_PALETTE_RAW) btv->gbuf[mp->frame].ro = 0;#endif if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { btv->gq_start = 1; btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btv->gqueue[btv->gq_in++] = mp->frame; btv->gq_in = btv->gq_in % MAX_GBUFFERS; btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); spin_unlock_irqrestore(&btv->s_lock, flags); return 0;}static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock){ return -EINVAL;}static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock){ /* use bttv 0.9.x if you need capture via read() */ return -EINVAL;}static inline void burst(int on){ tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);}/* * called from irq handler on fatal errors. Takes the grabber chip * offline, flag it needs a reinitialization (which can't be done * from irq context) and wake up all sleeping proccesses. They would * block forever else. We also need someone who actually does the * reinitialization from process context... */static void bt848_offline(struct bttv *btv){ unsigned int i; spin_lock(&btv->s_lock); /* cancel all outstanding grab requests */ btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; for (i = 0; i < gbuffers; i++) if (btv->gbuf[i].stat == GBUFFER_GRABBING) btv->gbuf[i].stat = GBUFFER_ERROR; /* disable screen overlay and DMA */ btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,0); /* flag the chip needs a restart */ btv->needs_restart = 1; spin_unlock(&btv->s_lock); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq);}static void bt848_restart(struct bttv *btv){ unsigned long irq_flags; if (bttv_verbose) printk("bttv%d: resetting chip\n",btv->nr); btwrite(0xfffffUL, BT848_INT_STAT); btand(~15, BT848_GPIO_DMA_CTL); btwrite(0, BT848_SRESET); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); /* enforce pll reprogramming */ btv->pll.pll_current = -1; set_pll(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); btv->errors = 0; btv->needs_restart = 0; bt848_set_geo(btv); bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags);}/* * Open a bttv card. Right now the flags stuff is just playing */static int bttv_open(struct video_device *dev, int flags){ struct bttv *btv = (struct bttv *)dev; unsigned int i; int ret; ret = -EBUSY; if (bttv_debug) printk("bttv%d: open called\n",btv->nr); down(&btv->lock); if (btv->user) goto out_unlock; btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); ret = -ENOMEM; if (!btv->fbuffer) goto out_unlock; btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; for (i = 0; i < gbuffers; i++) btv->gbuf[i].stat = GBUFFER_UNUSED; if (btv->needs_restart) bt848_restart(btv); burst(0); set_pll(btv); btv->user++; up(&btv->lock); return 0; out_unlock: up(&btv->lock); return ret;}static void bttv_close(struct video_device *dev)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -