?? bttv-risc.c
字號:
/* bttv-risc.c -- interfaces to other kernel modules bttv risc code handling - memory management - generation (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> 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.*/#define __NO_VERSION__ 1#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/iobuf.h>#include <linux/vmalloc.h>#include <linux/interrupt.h>#include <asm/page.h>#include <asm/pgtable.h>#include "bttvp.h"/* ---------------------------------------------------------- *//* allocate/free risc memory */int bttv_riscmem_alloc(struct pci_dev *pci, struct bttv_riscmem *risc, unsigned int size){ unsigned long *cpu; dma_addr_t dma; cpu = pci_alloc_consistent(pci, size, &dma); if (NULL == cpu) return -ENOMEM; memset(cpu,0,size); if (risc->cpu && risc->size < size) { /* realloc (enlarge buffer) -- copy old stuff */ memcpy(cpu,risc->cpu,risc->size); bttv_riscmem_free(pci,risc); } risc->cpu = cpu; risc->dma = dma; risc->size = size; return 0;}void bttv_riscmem_free(struct pci_dev *pci, struct bttv_riscmem *risc){ if (NULL == risc->cpu) return; pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); memset(risc,0,sizeof(*risc));}/* ---------------------------------------------------------- *//* risc code generators */intbttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc, struct scatterlist *sglist, int offset, int bpl, int padding, int lines){ int instructions,rc,line,todo; struct scatterlist *sg; unsigned long *rp; /* 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 = bttv_riscmem_alloc(btv->dev,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++) { while (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; return 0;}intbttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc, struct scatterlist *sglist, int yoffset, int ybpl, int ypadding, int ylines, int uoffset, int voffset, int hshift, int vshift, int cpadding){ int instructions,rc,line,todo,ylen,chroma; unsigned long *rp,ri; struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; /* 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 = bttv_riscmem_alloc(btv->dev,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++) { switch (vshift) { case 0: chroma = 1; break; case 1: chroma = !(line & 1); break; case 2: chroma = !(line & 3); break; default: chroma = 0; } for (todo = ybpl; todo > 0; todo -= ylen) { /* go to next sg entry if needed */ while (yoffset >= sg_dma_len(ysg)) { yoffset -= sg_dma_len(ysg); ysg++; } while (uoffset >= sg_dma_len(usg)) { uoffset -= sg_dma_len(usg); usg++; } while (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; return 0;}/* ---------------------------------------------------------- */struct SKIPLIST { int start; int end;};intbttv_screen_clips(struct video_buffer *fbuf, int x, int y, int width, int height, struct video_clip *clips, int n){ if (x < 0) { /* left */ clips[n].x = 0; clips[n].y = 0; clips[n].width = -x; clips[n].height = height; n++; } if (x+width > fbuf->width) { /* right */ clips[n].x = fbuf->width - x; clips[n].y = 0; clips[n].width = width - clips[n].x; clips[n].height = height; n++; } if (y < 0) { /* top */ clips[n].x = 0; clips[n].y = 0; clips[n].width = width; clips[n].height = -y; n++; } if (y+height > fbuf->height) { /* bottom */ clips[n].x = 0; clips[n].y = fbuf->height - y; clips[n].width = width; clips[n].height = height - clips[n].y; n++; } return n;}voidbttv_sort_clips(struct video_clip *clips, int nclips){ struct video_clip swap; int i,j,n; for (i = nclips-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (clips[j].x > clips[j+1].x) { swap = clips[j]; clips[j] = clips[j+1]; clips[j+1] = swap; n++; } } if (0 == n) break; }}static voidcalc_skips(int line, int width, int *maxy, struct SKIPLIST *skips, int *nskips, const struct video_clip *clips, int nclips){ int clip,skip,maxline,end; skip=0; maxline = 9999; for (clip = 0; clip < nclips; clip++) { /* sanity checks */ if (clips[clip].x + clips[clip].width <= 0) continue; if (clips[clip].x > width) break; /* vertical range */ if (line > clips[clip].y+clips[clip].height-1) continue; if (line < clips[clip].y) { if (maxline > clips[clip].y-1) maxline = clips[clip].y-1; continue; } if (maxline > clips[clip].y+clips[clip].height-1) maxline = clips[clip].y+clips[clip].height-1; /* horizontal range */ if (0 == skip || clips[clip].x > skips[skip-1].end) { /* new one */ skips[skip].start = clips[clip].x; if (skips[skip].start < 0) skips[skip].start = 0; skips[skip].end = clips[clip].x + clips[clip].width; if (skips[skip].end > width) skips[skip].end = width; skip++; } else { /* overlaps -- expand last one */ end = clips[clip].x + clips[clip].width; if (skips[skip-1].end < end) skips[skip-1].end = end; if (skips[skip-1].end > width) skips[skip-1].end = width; } } *nskips = skip; *maxy = maxline; if (bttv_debug) { printk(KERN_DEBUG "bttv: skips line %d-%d:",line,maxline); for (skip = 0; skip < *nskips; skip++) { printk(" %d-%d",skips[skip].start,skips[skip].end); } printk("\n"); }}intbttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int fields){ int instructions,rc,line,maxy,start,end,skip,nskips; struct SKIPLIST *skips; unsigned long *rp,ri,ra; unsigned long 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) * ((fields & VBUF_FIELD_INTER) ? ov->height>>1 : ov->height); instructions += 2; if ((rc = bttv_riscmem_alloc(btv->dev,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); addr = (unsigned long)btv->fbuf.base; addr += btv->fbuf.bytesperline * ov->y; addr += ((btv->fbuf.depth+7) >> 3) * ov->x; /* scan lines */ for (maxy = -1, line = 0; line < ov->height; line++, addr += btv->fbuf.bytesperline) { if (fields & VBUF_FIELD_INTER) { if ((line%2) != 0 && (fields & VBUF_FIELD_ODD)) continue; if ((line%2) != 1 && (fields & VBUF_FIELD_EVEN)) continue; } /* calculate clipping */ if (line > maxy) calc_skips(line, ov->width, &maxy, skips, &nskips, ov->clips, ov->nclips); /* write out risc code */ for (start = 0, skip = 0; start < ov->width; start = end) { if (skip >= nskips) { ri = BT848_RISC_WRITE; end = ov->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->width == end) ri |= BT848_RISC_EOL; ri |= (fmt->depth>>3) * (end-start);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -