📄 planb.c
字号:
pb->mask = (unsigned char *)(pb->gbuf[MAX_GBUFFERS-1].status + 1); pb->rawbuf = NULL; pb->rawbuf_nchunks = 0; pb->grabbing = 0; for (i = 0; i < MAX_GBUFFERS; i++) { gbuf_ptr gbuf = &pb->gbuf[i]; *gbuf->status = GBUFFER_UNUSED; gbuf->width = 0; gbuf->height = 0; gbuf->fmt = 0; gbuf->norm_switch = 0;#ifndef PLANB_GSCANLINE gbuf->lsize = 0; gbuf->lnum = 0;#endif } pb->gcount = 0; pb->suspend = 0; pb->last_fr = -999; pb->prev_last_fr = -999; /* Reset DMA controllers */ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); DBG("PlanB: planb_prepare_video, dbdma cmd_buf at 0x%08x, " "length %d.\n", (unsigned int)pb->vid_cbo.start, 2*size); return 0;}static void planb_prepare_close(struct planb *pb){ /* make sure the dma's are idle */ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); if(pb->jump_raw != 0) { kfree(pb->jump_raw); pb->jump_raw = 0; } return;}static void planb_close_vbi(struct planb *pb){ /* FIXME: stop running DMA */ /* Make sure the DMA controller doesn't jump here anymore */ tab_cmd_dbdma(pb->vbi_cbo.jumpaddr, DBDMA_NOP, 0); tab_cmd_dbdma(pb->vbi_cbe.jumpaddr, DBDMA_NOP, 0); if(pb->vbi_raw != 0) { kfree (pb->vbi_raw); pb->vbi_raw = 0; } /* FIXME: deallocate VBI data buffer */ /* FIXME: restart running DMA if app. */ return;}static void planb_close_video(struct planb *pb){ int i; /* FIXME: stop running DMA */ /* Make sure the DMA controller doesn't jump here anymore */ tab_cmd_dbdma(pb->vid_cbo.jumpaddr, DBDMA_NOP, 0); tab_cmd_dbdma(pb->vid_cbe.jumpaddr, DBDMA_NOP, 0);/* No clipmask jumpbuffer yet */#if 0 tab_cmd_dbdma(pb->clip_cbo.jumpaddr, DBDMA_NOP, 0); tab_cmd_dbdma(pb->clip_cbe.jumpaddr, DBDMA_NOP, 0);#endif if(pb->vid_raw != 0) { kfree (pb->vid_raw); pb->vid_raw = 0; pb->cmd_buff_inited = 0; } if(pb->rawbuf) { for (i = 0; i < pb->rawbuf_nchunks; i++) { mem_map_unreserve(virt_to_page(pb->rawbuf[i])); free_pages((unsigned long)pb->rawbuf[i], 0); } kfree(pb->rawbuf); } pb->rawbuf = NULL; /* FIXME: restart running DMA if app. */ return;}/*****************************//* overlay support functions *//*****************************/static void overlay_start(struct planb *pb){ DBG("PlanB: overlay_start()\n"); if(ACTIVE & readl(&pb->planb_base->ch1.status)) { DBG("PlanB: presumably, grabbing is in progress...\n"); planb_dbdma_stop(&pb->planb_base->ch2); writel(pb->clip_cbo.bus, &pb->planb_base->ch2.cmdptr); planb_dbdma_restart(&pb->planb_base->ch2); st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP); tab_cmd_dbdma(pb->gbuf[pb->last_fr].last_cmd, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); eieio(); pb->prev_last_fr = pb->last_fr; pb->last_fr = -2; if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) { IDBG("PlanB: became inactive " "in the mean time... reactivating\n"); planb_dbdma_stop(&pb->planb_base->ch1); writel(pb->vid_cbo.bus, &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } else { DBG("PlanB: currently idle, so can do whatever\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); st_le32(&pb->planb_base->ch2.cmdptr, pb->clip_cbo.bus); st_le32(&pb->planb_base->ch1.cmdptr, pb->vid_cbo.bus); writew(DBDMA_NOP, &pb->vid_cbo.start->command); planb_dbdma_restart(&pb->planb_base->ch2); planb_dbdma_restart(&pb->planb_base->ch1); pb->last_fr = -1; } return;}static void overlay_stop(struct planb *pb){ DBG("PlanB: overlay_stop()\n"); if(pb->last_fr == -1) { DBG("PlanB: no grabbing, it seems...\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); pb->last_fr = -999; } else if(pb->last_fr == -2) { unsigned int cmd_dep; tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].cap_cmd, DBDMA_STOP, 0); eieio(); cmd_dep = (unsigned int)readl(&pb->overlay_last1->cmd_dep); if(overlay_is_active(pb)) { DBG("PlanB: overlay is currently active\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); if(cmd_dep != pb->vid_cbo.bus) { writel(virt_to_bus(pb->overlay_last1), &pb->planb_base->ch1.cmdptr); planb_dbdma_restart(&pb->planb_base->ch1); } } pb->last_fr = pb->prev_last_fr; pb->prev_last_fr = -999; } return;}static void suspend_overlay(struct planb *pb){ int fr = -1; struct dbdma_cmd last; DBG("PlanB: suspend_overlay: %d\n", pb->suspend); if(pb->suspend++) return; if(ACTIVE & readl(&pb->planb_base->ch1.status)) { if(pb->last_fr == -2) { fr = pb->prev_last_fr; memcpy(&last, (void*)pb->gbuf[fr].last_cmd, sizeof(last)); tab_cmd_dbdma(pb->gbuf[fr].last_cmd, DBDMA_STOP, 0); } if(overlay_is_active(pb)) { planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); pb->suspended.overlay = 1; pb->suspended.frame = fr; memcpy(&pb->suspended.cmd, &last, sizeof(last)); return; } } pb->suspended.overlay = 0; pb->suspended.frame = fr; memcpy(&pb->suspended.cmd, &last, sizeof(last)); return;}static void resume_overlay(struct planb *pb){ DBG("PlanB: resume_overlay: %d\n", pb->suspend); if(pb->suspend > 1) return; if(pb->suspended.frame != -1) { memcpy((void*)pb->gbuf[pb->suspended.frame].last_cmd, &pb->suspended.cmd, sizeof(pb->suspended.cmd)); } if(ACTIVE & readl(&pb->planb_base->ch1.status)) { goto finish; } if(pb->suspended.overlay) { DBG("PlanB: overlay being resumed\n"); st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP); st_le16 (&pb->clip_cbo.start->command, DBDMA_NOP); /* Set command buffer addresses */ writel(virt_to_bus(pb->overlay_last1), &pb->planb_base->ch1.cmdptr); writel(virt_to_bus(pb->overlay_last2), &pb->planb_base->ch2.cmdptr); /* Start the DMA controller */ writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), &pb->planb_base->ch2.control); writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), &pb->planb_base->ch1.control); } else if(pb->suspended.frame != -1) { writel(virt_to_bus(pb->gbuf[pb->suspended.frame].last_cmd), &pb->planb_base->ch1.cmdptr); writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE), &pb->planb_base->ch1.control); }finish: pb->suspend--; wake_up_interruptible(&pb->suspendq);}static void add_clip(struct planb *pb, struct video_clip *clip) { volatile unsigned char *base; int xc = clip->x, yc = clip->y; int wc = clip->width, hc = clip->height; int ww = pb->win.width, hw = pb->win.height; int x, y, xtmp1, xtmp2; DBG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); if(xc < 0) { wc += xc; xc = 0; } if(yc < 0) { hc += yc; yc = 0; } if(xc + wc > ww) wc = ww - xc; if(wc <= 0) /* Nothing to do */ return; if(yc + hc > hw) hc = hw - yc; for (y = yc; y < yc+hc; y++) { xtmp1=xc>>3; xtmp2=(xc+wc)>>3; base = pb->mask + y*96; if(xc != 0 || wc >= 8) *(base + xtmp1) &= (unsigned char)(0x00ff & (0xff00 >> (xc&7))); for (x = xtmp1 + 1; x < xtmp2; x++) { *(base + x) = 0; } if(xc < (ww & ~0x7)) *(base + xtmp2) &= (unsigned char)(0x00ff >> ((xc+wc) & 7)); } return;}static void fill_cmd_buff(struct planb *pb){ int restore = 0; dbdma_cmd_t last; DBG("PlanB: fill_cmd_buff()\n"); if(pb->overlay_last1 != pb->vid_cbo.start) { restore = 1; last = *(pb->overlay_last1); } memset ((void *) pb->vid_cbo.start, 0, 2 * pb->tab_size * sizeof(struct dbdma_cmd)); cmd_buff (pb); if(restore) *(pb->overlay_last1) = last; if(pb->suspended.overlay) { unsigned long jump_addr = readl(&pb->overlay_last1->cmd_dep); if(jump_addr != pb->vid_cbo.bus) { int i; DBG("PlanB: adjusting ch1's jump address\n"); for(i = 0; i < MAX_GBUFFERS; i++) { if(pb->gbuf[i].need_pre_capture) { if(jump_addr == virt_to_bus(pb->gbuf[i].pre_cmd)) goto found; } else { if(jump_addr == virt_to_bus(pb->gbuf[i].cap_cmd)) goto found; } } DBG(" not found!\n"); goto out;found: if(pb->gbuf[i].need_pre_capture) writel(virt_to_bus(pb->overlay_last1), &pb->gbuf[i].pre_cmd->phy_addr); else writel(virt_to_bus(pb->overlay_last1), &pb->gbuf[i].cap_cmd->phy_addr); } }out: pb->cmd_buff_inited = 1; return;}static void cmd_buff(struct planb *pb){ int i, bpp, count, nlines, stepsize, interlace; unsigned long base, jump, addr_com, addr_dep; dbdma_cmd_ptr c1 = pb->vid_cbo.start; dbdma_cmd_ptr c2 = pb->clip_cbo.start; interlace = pb->win.interlace; bpp = pb->win.bpp; count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? (pb->win.swidth - pb->win.x) : pb->win.width)); nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? (pb->win.sheight - pb->win.y) : pb->win.height); /* Do video in: */ /* Preamble commands: */ addr_com = virt_to_bus(c1); addr_dep = virt_to_bus(&c1->cmd_dep); tab_cmd_dbdma(c1++, DBDMA_NOP, 0); jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, pb->win.color_fmt, 1, pb); tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); tab_cmd_store(c1++, addr_dep, jump); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel), PLANB_SET(FIELD_SYNC)); /* (1) wait for field sync to be set */ 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)); /* wait for field sync to be cleared */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); /* if not odd field, wait until field sync is set again */ tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; /* assert ch_sync to ch2 */ tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_SET(CH_SYNC)); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); base = (pb->fb.phys + pb->fb.offset + pb->win.y * (pb->win.bpl + pb->win.pad) + pb->win.x * bpp); if (interlace) { stepsize = 2; jump = virt_to_bus(c1 + (nlines + 1) / 2); } else { stepsize = 1; jump = virt_to_bus(c1 + nlines); } /* even field data: */ for (i=0; i < nlines; i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, base + i * (pb->win.bpl + pb->win.pad), jump); /* For non-interlaced, we use even fields only */ if (!interlace) goto cmd_tab_data_end; /* Resync to odd field */ /* (2) wait for field sync to be set */ 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)); /* wait for field sync to be cleared */ tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); /* if not odd field, wait until field sync is set again */ tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; /* assert ch_sync to ch2 */ tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_SET(CH_SYNC)); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel), PLANB_SET(DMA_ABORT)); /* odd field data: */ jump = virt_to_bus(c1 + nlines / 2); for (i=1; i < nlines; i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, base + i * (pb->win.bpl + pb->win.pad), jump); /* And jump back to the start */cmd_tab_data_end: pb->overlay_last1 = c1; /* keep a pointer to the last command */ tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus); /* Clipmask command buffer */ /* Preamble commands: */ tab_cmd_dbdma(c2++, DBDMA_NOP, 0); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel), PLANB_SET(CH_SYNC)); /* wait until ch1 asserts ch_sync */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); /* clear ch_sync asserted by ch1 */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.control), PLANB_CLR(CH_SYNC)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel), PLANB_SET(FIELD_SYNC)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(ODD_FIELD)); /* jump to end of even field if appropriate */ /* this points to (interlace)? pos. C: pos. B */ jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): virt_to_bus(c2 + nlines + 2); /* if odd field, skip over to odd field clipmasking */ tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); /* even field mask: */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel), PLANB_SET(DMA_ABORT)); /* this points to pos. B */ jump = (interlace) ? virt_to_bus(c2 + nlines + 1): virt_to_bus(c2 + nlines); base = virt_to_bus(pb->mask); for (i=0; i < nlines; i += stepsize, c2++) tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, base + i * 96, jump); /* For non-interlaced, we use only even fields */ if(!interlace) goto cmd_tab_mask_end; /* odd field mask: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -