📄 planb.c
字号:
} } else { DEBUG("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, virt_to_bus(pb->ch2_cmd)); st_le32 (&pb->planb_base->ch1.cmdptr, virt_to_bus(pb->ch1_cmd)); out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); 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){ DEBUG("PlanB: overlay_stop()\n"); if(pb->last_fr == -1) { DEBUG("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->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); eieio(); cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); if(overlay_is_active(pb)) { DEBUG("PlanB: overlay is currently active\n"); planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); if(cmd_dep != pb->ch1_cmd_phys) { out_le32(&pb->planb_base->ch1.cmdptr, virt_to_bus(pb->overlay_last1)); 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; DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); if(pb->suspend++) return; if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { if(pb->last_fr == -2) { fr = pb->prev_last_fr; memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); tab_cmd_dbdma(pb->last_cmd[fr], 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){ DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); if(pb->suspend > 1) return; if(pb->suspended.frame != -1) { memcpy((void*)pb->last_cmd[pb->suspended.frame], &pb->suspended.cmd, sizeof(pb->suspended.cmd)); } if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { goto finish; } if(pb->suspended.overlay) { DEBUG("PlanB: overlay being resumed\n"); st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); /* Set command buffer addresses */ st_le32(&pb->planb_base->ch1.cmdptr, virt_to_bus(pb->overlay_last1)); out_le32(&pb->planb_base->ch2.cmdptr, virt_to_bus(pb->overlay_last2)); /* Start the DMA controller */ out_le32 (&pb->planb_base->ch2.control, PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); out_le32 (&pb->planb_base->ch1.control, PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); } else if(pb->suspended.frame != -1) { out_le32(&pb->planb_base->ch1.cmdptr, virt_to_bus(pb->last_cmd[pb->suspended.frame])); out_le32 (&pb->planb_base->ch1.control, PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); }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; DEBUG("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; volatile struct dbdma_cmd last; DEBUG("PlanB: fill_cmd_buff()\n"); if(pb->overlay_last1 != pb->ch1_cmd) { restore = 1; last = *(pb->overlay_last1); } memset ((void *) pb->ch1_cmd, 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 = in_le32(&pb->overlay_last1->cmd_dep); if(jump_addr != pb->ch1_cmd_phys) { int i; DEBUG("PlanB: adjusting ch1's jump address\n"); for(i = 0; i < MAX_GBUFFERS; i++) { if(pb->need_pre_capture[i]) { if(jump_addr == virt_to_bus(pb->pre_cmd[i])) goto found; } else { if(jump_addr == virt_to_bus(pb->cap_cmd[i])) goto found; } } DEBUG("PlanB: not found...\n"); goto out;found: if(pb->need_pre_capture[i]) out_le32(&pb->pre_cmd[i]->phy_addr, virt_to_bus(pb->overlay_last1)); else out_le32(&pb->cap_cmd[i]->phy_addr, virt_to_bus(pb->overlay_last1)); } }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; volatile struct dbdma_cmd *c1 = pb->ch1_cmd; volatile struct dbdma_cmd *c2 = pb->ch2_cmd; 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 */ if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, bpp, 1, pb)) == NULL) { printk(KERN_WARNING "PlanB: encountered serious problems\n"); tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); return; } 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_phys->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_phys->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_phys->ch2.control), PLANB_SET(CH_SYNC)); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), PLANB_SET(DMA_ABORT)); base = (pb->frame_buffer_phys + pb->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_phys->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_phys->ch2.control), PLANB_SET(CH_SYNC)); tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->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, virt_to_bus(pb->ch1_cmd)); /* Clipmask command buffer */ /* Preamble commands: */ tab_cmd_dbdma(c2++, DBDMA_NOP, 0); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->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_phys->ch2.control), PLANB_CLR(CH_SYNC)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), PLANB_SET(FIELD_SYNC)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->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_phys->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: *//* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->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_phys->ch1.control), PLANB_CLR(RUN)); tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->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, virt_to_bus(pb->ch2_cmd)); eieio(); return;}/*********************************//* grabdisplay support functions *//*********************************/static int palette2fmt[] = { 0, PLANB_GRAY, 0, 0, 0, PLANB_COLOUR32, PLANB_COLOUR15, 0, 0, 0, 0, 0, 0, 0, 0,};#define PLANB_PALETTE_MAX 15static int vgrab(struct planb *pb, struct video_mmap *mp){ unsigned int fr = mp->frame; unsigned int format; if(pb->rawbuf==NULL) { int err; if((err=grabbuf_alloc(pb))) return err; } IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, mp->width, mp->height, fr); if(pb->grabbing >= MAX_GBUFFERS) return -ENOBUFS; if(fr > (MAX_GBUFFERS - 1) || fr < 0) return -EINVAL; if(mp->height <= 0 || mp->width <= 0) return -EINVAL; if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) return -EINVAL; if((format = palette2fmt[mp->format]) == 0) return -EINVAL; if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ return -EINVAL; planb_lock(pb); if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { int i;#ifndef PLANB_GSCANLINE unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] * pb->gfmt[fr]; unsigned int nsize = mp->width * mp->height * format;#endif IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", mp->width, mp->height, mp->format);#ifndef PLANB_GSCANLINE if(pb->gnorm_switch[fr]) nsize = 0; if (nsize < osize) { for(i = pb->gbuf_idx[fr]; osize > 0; i++) { memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); osize -= PAGE_SIZE; } } for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] + pb->lnum[fr]; i++) memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);#else/* XXX TODO *//* if(pb->gnorm_switch[fr]) memset((void *)pb->gbuffer[fr], 0,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -