📄 bttv-risc.c
字号:
/* bttv-risc.c -- interfaces to other kernel modules bttv risc code handling - memory management - generation (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/interrupt.h>#include <asm/page.h>#include <asm/pgtable.h>#include "bttvp.h"#define VCR_HACK_LINES 4/* ---------------------------------------------------------- *//* risc code generators */intbttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int offset, unsigned int bpl, unsigned int padding, unsigned int lines){ u32 instructions,line,todo; struct scatterlist *sg; u32 *rp; int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + sync + jump (all 2 dwords) */ instructions = (bpl * lines) / PAGE_SIZE + lines; instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) return rc; /* sync instruction */ rp = risc->cpu; *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(rp++) = cpu_to_le32(0); /* scan lines */ sg = sglist; for (line = 0; line < lines; line++) { if ((btv->opt_vcr_hack) && (line >= (lines - VCR_HACK_LINES))) continue; while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); sg++; } if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| BT848_RISC_EOL|bpl); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); offset+=bpl; } else { /* scanline needs to be splitted */ todo = bpl; *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| (sg_dma_len(sg)-offset)); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); todo -= (sg_dma_len(sg)-offset); offset = 0; sg++; while (todo > sg_dma_len(sg)) { *(rp++)=cpu_to_le32(BT848_RISC_WRITE| sg_dma_len(sg)); *(rp++)=cpu_to_le32(sg_dma_address(sg)); todo -= sg_dma_len(sg); sg++; } *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| todo); *(rp++)=cpu_to_le32(sg_dma_address(sg)); offset += todo; } offset += padding; } /* save pointer to jmp instruction address */ risc->jmp = rp; BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); return 0;}static intbttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int yoffset, unsigned int ybpl, unsigned int ypadding, unsigned int ylines, unsigned int uoffset, unsigned int voffset, unsigned int hshift, unsigned int vshift, unsigned int cpadding){ unsigned int instructions,line,todo,ylen,chroma; u32 *rp,ri; struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; int topfield = (0 == yoffset); int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line (5 dwords) plus sync + jump (2 dwords) */ instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines; instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) return rc; /* sync instruction */ rp = risc->cpu; *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(rp++) = cpu_to_le32(0); /* scan lines */ ysg = sglist; usg = sglist; vsg = sglist; for (line = 0; line < ylines; line++) { if ((btv->opt_vcr_hack) && (line >= (ylines - VCR_HACK_LINES))) continue; switch (vshift) { case 0: chroma = 1; break; case 1: if (topfield) chroma = ((line & 1) == 0); else chroma = ((line & 1) == 1); break; case 2: if (topfield) chroma = ((line & 3) == 0); else chroma = ((line & 3) == 2); break; default: chroma = 0; break; } for (todo = ybpl; todo > 0; todo -= ylen) { /* go to next sg entry if needed */ while (yoffset && yoffset >= sg_dma_len(ysg)) { yoffset -= sg_dma_len(ysg); ysg++; } while (uoffset && uoffset >= sg_dma_len(usg)) { uoffset -= sg_dma_len(usg); usg++; } while (voffset && voffset >= sg_dma_len(vsg)) { voffset -= sg_dma_len(vsg); vsg++; } /* calculate max number of bytes we can write */ ylen = todo; if (yoffset + ylen > sg_dma_len(ysg)) ylen = sg_dma_len(ysg) - yoffset; if (chroma) { if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) ylen = (sg_dma_len(usg) - uoffset) << hshift; if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) ylen = (sg_dma_len(vsg) - voffset) << hshift; ri = BT848_RISC_WRITE123; } else { ri = BT848_RISC_WRITE1S23; } if (ybpl == todo) ri |= BT848_RISC_SOL; if (ylen == todo) ri |= BT848_RISC_EOL; /* write risc instruction */ *(rp++)=cpu_to_le32(ri | ylen); *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | (ylen >> hshift)); *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); yoffset += ylen; if (chroma) { *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); uoffset += ylen >> hshift; *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); voffset += ylen >> hshift; } } yoffset += ypadding; if (chroma) { uoffset += cpadding; voffset += cpadding; } } /* save pointer to jmp instruction address */ risc->jmp = rp; BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); return 0;}static intbttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int skip_even, int skip_odd){ int instructions,rc,line,maxy,start,end,skip,nskips; struct btcx_skiplist *skips; u32 *rp,ri,ra; u32 addr; /* skip list for window clipping */ if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) return -ENOMEM; /* estimate risc mem: worst case is (clip+1) * lines instructions + sync + jump (all 2 dwords) */ instructions = (ov->nclips + 1) * ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height); instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) { kfree(skips); return rc; } /* sync instruction */ rp = risc->cpu; *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(rp++) = cpu_to_le32(0); addr = (unsigned long)btv->fbuf.base; addr += btv->fbuf.fmt.bytesperline * ov->w.top; addr += (fmt->depth >> 3) * ov->w.left; /* scan lines */ for (maxy = -1, line = 0; line < ov->w.height; line++, addr += btv->fbuf.fmt.bytesperline) { if ((btv->opt_vcr_hack) && (line >= (ov->w.height - VCR_HACK_LINES))) continue; if ((line%2) == 0 && skip_even) continue; if ((line%2) == 1 && skip_odd) continue; /* calculate clipping */ if (line > maxy) btcx_calc_skips(line, ov->w.width, &maxy, skips, &nskips, ov->clips, ov->nclips); /* write out risc code */ for (start = 0, skip = 0; start < ov->w.width; start = end) { if (skip >= nskips) { ri = BT848_RISC_WRITE; end = ov->w.width; } else if (start < skips[skip].start) { ri = BT848_RISC_WRITE; end = skips[skip].start; } else { ri = BT848_RISC_SKIP; end = skips[skip].end; skip++; } if (BT848_RISC_WRITE == ri) ra = addr + (fmt->depth>>3)*start; else ra = 0; if (0 == start) ri |= BT848_RISC_SOL; if (ov->w.width == end) ri |= BT848_RISC_EOL; ri |= (fmt->depth>>3) * (end-start); *(rp++)=cpu_to_le32(ri); if (0 != ra) *(rp++)=cpu_to_le32(ra); } } /* save pointer to jmp instruction address */ risc->jmp = rp; BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); kfree(skips); return 0;}/* ---------------------------------------------------------- */static voidbttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, int width, int height, int interleaved, int norm){ const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm]; u32 xsf, sr; int vdelay; int swidth = tvnorm->swidth; int totalwidth = tvnorm->totalwidth; int scaledtwidth = tvnorm->scaledtwidth; if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) { swidth = 720; totalwidth = 858; scaledtwidth = 858; } vdelay = tvnorm->vdelay; xsf = (width*scaledtwidth)/swidth; geo->hscale = ((totalwidth*4096UL)/xsf-4096); geo->hdelay = tvnorm->hdelayx1; geo->hdelay = (geo->hdelay*width)/swidth; geo->hdelay &= 0x3fe; sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; geo->vscale = (0x10000UL-sr) & 0x1fff; geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; geo->vdelay = vdelay; geo->width = width; geo->sheight = tvnorm->sheight; geo->vtotal = tvnorm->vtotal; if (btv->opt_combfilter) { geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); geo->comb = (width < 769) ? 1 : 0; } else { geo->vtc = 0; geo->comb = 0; }}static voidbttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd){ int off = odd ? 0x80 : 0x00; if (geo->comb) btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); else btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); btwrite(geo->vtc, BT848_E_VTC+off); btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off); btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off); btwrite(geo->crop, BT848_E_CROP+off); btwrite(geo->vtotal>>8, BT848_VTOTAL_HI); btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);}/* ---------------------------------------------------------- *//* risc group / risc main loop / dma management */voidbttv_set_dma(struct bttv *btv, int override){ unsigned long cmd; int capctl; btv->cap_ctl = 0; if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -