📄 planb.c
字号:
/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(DMA_ABORT)); /* this points to pos. B */ jump = virt_to_bus(c2 + nlines / 2); base = virt_to_bus(pb->mask); for (i=1; i < nlines; i += 2, c2++) /* abort if set */ tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, base + i * 96, jump); /* Inform channel 1 and jump back to start */cmd_tab_mask_end: /* ok, I just realized this is kind of flawed. */ /* this part is reached only after odd field clipmasking. */ /* wanna clean up? */ /* wait for field sync to be set */ /* corresponds to fsync (1) of ch1 *//* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); /* restart ch1, meant to clear any dead bit or something */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control), PLANB_CLR(RUN)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control), PLANB_SET(RUN)); pb->overlay_last2 = c2; /* keep a pointer to the last command */ /* start over even field clipmasking */ tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, pb->clip_cbo.bus); eieio(); return;}/*********************************//* grabdisplay support functions *//*********************************/static inline int overlay_is_active(struct planb *pb){ unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); unsigned int caddr = (unsigned)readl(&pb->planb_base->ch1.cmdptr); return (readl(&pb->overlay_last1->cmd_dep) == pb->vid_cbo.bus) && (caddr < (pb->vid_cbo.bus + size)) && (caddr >= (unsigned)pb->vid_cbo.bus);}static int vgrab(struct planb *pb, struct video_mmap *mp){ unsigned int fr = mp->frame; unsigned int fmt = mp->format; unsigned int bpp = palette2fmt[fmt].bpp; gbuf_ptr gbuf = &pb->gbuf[fr]; if(pb->rawbuf==NULL) { int err; if((err=grabbuf_alloc(pb))) return err; } DBG("PlanB: grab %d: %dx%d fmt %d (%u)\n", pb->grabbing, mp->width, mp->height, fmt, fr); if(pb->grabbing >= MAX_GBUFFERS) { DBG(" no buffer\n"); return -ENOBUFS; } if(fr > (MAX_GBUFFERS - 1) || fr < 0) { DBG(" invalid buffer\n"); return -EINVAL; } if(mp->height <= 0 || mp->width <= 0) { DBG(" negative height or width\n"); return -EINVAL; } if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) { DBG(" format out of range\n"); return -EINVAL; } if(bpp == 0) { DBG(" unsupported format %d\n", mp->format); return -EINVAL; } if (mp->height * mp->width * bpp > PLANB_MAX_FBUF) { DBG(" grab bigger than buffer\n"); return -EINVAL; } planb_lock(pb); if(mp->width != gbuf->width || mp->height != gbuf->height || fmt != gbuf->fmt || (gbuf->norm_switch)) { int i;#ifndef PLANB_GSCANLINE unsigned int osize = gbuf->width * gbuf->height * palette2fmt[gbuf->fmt].bpp; unsigned int nsize = mp->width * mp->height * bpp;#endif DBG("PlanB: changed gwidth = %d, gheight = %d, format = %u, " "osize = %d, nsize = %d\n", mp->width, mp->height, fmt, osize, nsize);/* Do we _really_ need to clear the grab buffers?? */#if 0#ifndef PLANB_GSCANLINE if(gbuf->norm_switch) nsize = 0; if (nsize < osize) { for(i = gbuf->idx; osize > 0; i++) { memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); osize -= PAGE_SIZE; } } for(i = gbuf->l_fr_addr_idx; i < gbuf->l_fr_addr_idx + gbuf->lnum; i++) memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);#else/* XXX TODO *//* if(gbuf->norm_switch) memset((void *)pb->gbuffer[fr], 0, pb->gbytes_per_line * gbuf->height); else { if(mp-> for(i = 0; i < gbuf->height; i++) { memset((void *)(pb->gbuffer[fr] + pb->gbytes_per_line * i } }*/#endif#endif /* if 0 */ gbuf->width = mp->width; gbuf->height = mp->height; gbuf->fmt = fmt; gbuf->last_cmd = setup_grab_cmd(fr, pb); planb_pre_capture(fr, pb); gbuf->need_pre_capture = 1; gbuf->norm_switch = 0; } else gbuf->need_pre_capture = 0; *gbuf->status = GBUFFER_GRABBING; if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { IDBG("PlanB: ch1 inactive, initiating grabbing\n"); planb_dbdma_stop(&pb->planb_base->ch1); if(gbuf->need_pre_capture) { DBG("PlanB: padding pre-capture sequence\n"); writel(virt_to_bus(gbuf->pre_cmd), &pb->planb_base->ch1.cmdptr); } else { tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0); tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); /* let's be on the safe side. here is not timing critical. */ tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); writel(virt_to_bus(gbuf->cap_cmd), &pb->planb_base->ch1.cmdptr); } planb_dbdma_restart(&pb->planb_base->ch1); pb->last_fr = fr; } else { int i; DBG("PlanB: ch1 active, grabbing being queued\n"); if((pb->last_fr == -1) || ((pb->last_fr == -2) && overlay_is_active(pb))) { DBG("PlanB: overlay is active, grabbing defered\n"); tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); if(gbuf->need_pre_capture) { DBG("PlanB: padding pre-capture sequence\n"); tab_cmd_store(gbuf->pre_cmd, virt_to_bus(&pb->overlay_last1->cmd_dep), pb->vid_cbo.bus); eieio(); writel(virt_to_bus(gbuf->pre_cmd), &pb->overlay_last1->cmd_dep); } else { tab_cmd_store(gbuf->cap_cmd, virt_to_bus(&pb->overlay_last1->cmd_dep), pb->vid_cbo.bus); tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); eieio(); writel(virt_to_bus(gbuf->cap_cmd), &pb->overlay_last1->cmd_dep); } for(i = 0; overlay_is_active(pb) && i < 999; i++) DBG("PlanB: waiting for overlay done\n"); tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0); pb->prev_last_fr = fr; pb->last_fr = -2; } else if(pb->last_fr == -2) { DBG("PlanB: mixed mode detected, grabbing" " will be done before activating overlay\n"); tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0); if(gbuf->need_pre_capture) { DBG("PlanB: padding pre-capture sequence\n"); tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->pre_cmd)); eieio(); } else { tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); if(pb->gbuf[pb->prev_last_fr].width != gbuf->width || pb->gbuf[pb->prev_last_fr].height != gbuf->height || pb->gbuf[pb->prev_last_fr].fmt != gbuf->fmt) tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); else tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd + 16)); tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd)); eieio(); } tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); eieio(); pb->prev_last_fr = fr; pb->last_fr = -2; } else { gbuf_ptr lastgbuf = &pb->gbuf[pb->last_fr]; DBG("PlanB: active grabbing session detected\n"); if(gbuf->need_pre_capture) { DBG("PlanB: padding pre-capture sequence\n"); tab_cmd_dbdma(lastgbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->pre_cmd)); eieio(); } else { tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0); tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0); if(lastgbuf->width != gbuf->width || lastgbuf->height != gbuf->height || lastgbuf->fmt != gbuf->fmt) tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0); else tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd + 16)); tab_cmd_dbdma(lastgbuf->last_cmd, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd)); eieio(); } pb->last_fr = fr; } if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { DBG("PlanB: became inactive in the mean time... " "reactivating\n"); planb_dbdma_stop(&pb->planb_base->ch1); writel(virt_to_bus(gbuf->cap_cmd), &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } pb->grabbing++; planb_unlock(pb); return 0;}static void planb_pre_capture(int fr, struct planb *pb){ gbuf_ptr gbuf = &pb->gbuf[fr]; dbdma_cmd_ptr c1 = gbuf->pre_cmd; int height = gbuf->height; int interlace = (height > pb->maxlines/2)? 1: 0; tab_cmd_dbdma(c1++, DBDMA_NOP, 0); c1 = cmd_geo_setup(c1, gbuf->width, height, interlace, gbuf->fmt, 0, pb); /* Sync to even field */ tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), PLANB_SET(FIELD_SYNC)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); /* For non-interlaced, we use even fields only */ if (interlace == 0) goto cmd_tab_data_end; /* Sync to odd field */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT));cmd_tab_data_end: tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd)); eieio();}/* This needs some explanation. * What we do here is write the DBDMA commands to fill the grab buffer. * Since the grab buffer is made up of physically non-contiguous chunks, * we need to make sure to not make the DMA engine write across a chunk * boundary: the DMA engine needs a physically contiguous memory chunk for * a single scan line. * So all those scan lines that cross a chunk boundary are written do spare * scratch buffers, and we keep track of this fact. * Later, in the interrupt routine, we copy those scan lines (in two pieces) * back to where they belong in the right sequence in the grab buffer. */static dbdma_cmd_ptr setup_grab_cmd(int fr, struct planb *pb){ int i, count, nlines, stepsize, interlace;#ifdef PLANB_GSCANLINE int scanline;#else int nlpp, leftover1; unsigned long base;#endif unsigned long jump; int pagei; dbdma_cmd_ptr c1; dbdma_cmd_ptr jump_addr; gbuf_ptr gbuf = &pb->gbuf[fr]; int fmt = gbuf->fmt; c1 = gbuf->cap_cmd; nlines = gbuf->height; interlace = (nlines > pb->maxlines/2) ? 1 : 0; count = palette2fmt[fmt].bpp * gbuf->width;#ifdef PLANB_GSCANLINE scanline = pb->gbytes_per_line;#else gbuf->lsize = count; gbuf->lnum = 0;#endif /* Do video in: */ /* Preamble commands: */ tab_cmd_dbdma(c1++, DBDMA_NOP, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; c1 = cmd_geo_setup(c1, gbuf->width, nlines, interlace, fmt, 0, pb); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), PLANB_SET(FIELD_SYNC)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); if (interlace) { stepsize = 2; jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; } else { stepsize = 1; jump_addr = c1 + TAB_FACTOR * nlines; } jump = virt_to_bus(jump_addr); /* even field data: */ pagei = gbuf->idx;#ifdef PLANB_GSCANLINE for (i = 0; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, virt_to_bus(pb->rawbuf[pagei + i * scanline / PAGE_SIZE]), jump); }#else i = 0; leftover1 = 0; do { int j; base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, base + count * j * stepsize + leftover1, jump); if(i < nlines) { int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; if(lov0 == 0) leftover1 = 0; else { if(lov0 >= count) { /* can happen only when interlacing; then other field * uses up leftover space (lov0 - count). */ tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + count * nlpp * stepsize + leftover1, jump); } else { /* start of free space at end of page: */ pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei] + count * nlpp * stepsize + leftover1; /* index where continuation is: */ pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1; /* How much is left to do in next page: */ pb->l_to_next_size[fr][gbuf->lnum] = count - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx + gbuf->lnum]), jump); if(++gbuf->lnum > MAX_LNUM) { /* FIXME: error condition! */ gbuf->lnum--; } } leftover1 = count * stepsize - lov0; i += stepsize; } } pagei++; } while(i < nlines); tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); c1 = jump_addr;#endif /* PLANB_GSCANLINE */ /* For non-interlaced, we use even fields only */ if (!interlace) goto cmd_tab_data_end; /* Sync to odd field */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(ODD_FIELD)); tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); /* odd field data: */ jump_addr = c1 + TAB_FACTOR * nlines / 2; jump = virt_to_bus(jump_addr);#ifdef PLANB_GSCANLINE for (i = 1; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, virt_to_bus(pb->rawbuf[pagei + i * scanline / PAGE_SIZE]), jump); }#else i = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -