📄 buz.c
字号:
/* if window has more than half of active height, switch on interlacing - we want the full information */ zr->video_interlace = (video_height > Ha / 2);/**** zr36057 ****/ /* horizontal */ VidWinWid = video_width; X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; We = (VidWinWid * 64) / X; HorDcm = 64 - X; hcrop1 = 2 * ((tvn->Wa - We) / 4); hcrop2 = tvn->Wa - We - hcrop1; HStart = tvn->HStart | 1; HEnd = HStart + tvn->Wa - 1; HStart += hcrop1; HEnd -= hcrop2; reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); reg |= ZR36057_VFEHCR_HSPol; btwrite(reg, ZR36057_VFEHCR); /* Vertical */ DispMode = !zr->video_interlace; VidWinHt = DispMode ? video_height : video_height / 2; Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; He = (VidWinHt * 64) / Y; VerDcm = 64 - Y; vcrop1 = (tvn->Ha / 2 - He) / 2; vcrop2 = tvn->Ha / 2 - He - vcrop1; VStart = tvn->VStart; VEnd = VStart + tvn->Ha / 2 - 1; VStart += vcrop1; VEnd -= vcrop2; reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); reg |= ZR36057_VFEVCR_VSPol; btwrite(reg, ZR36057_VFEVCR); /* scaler and pixel format */ reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ | (HorDcm << ZR36057_VFESPFR_HorDcm) | (VerDcm << ZR36057_VFESPFR_VerDcm) | (DispMode << ZR36057_VFESPFR_DispMode) | ZR36057_VFESPFR_LittleEndian; /* RJ: I don't know, why the following has to be the opposite of the corresponding ZR36060 setting, but only this way we get the correct colors when uncompressing to the screen */ reg |= ZR36057_VFESPFR_VCLKPol; /* RJ: Don't know if that is needed for NTSC also */ reg |= ZR36057_VFESPFR_TopField; switch (video_format) { case VIDEO_PALETTE_YUV422: reg |= ZR36057_VFESPFR_YUV422; break; case VIDEO_PALETTE_RGB555: reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; break; case VIDEO_PALETTE_RGB565: reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; break; case VIDEO_PALETTE_RGB24: reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; break; case VIDEO_PALETTE_RGB32: reg |= ZR36057_VFESPFR_RGB888; break; default: printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); return; } if (HorDcm >= 48) { reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ } else if (HorDcm >= 32) { reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ } else if (HorDcm >= 16) { reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ } btwrite(reg, ZR36057_VFESPFR); /* display configuration */ reg = (16 << ZR36057_VDCR_MinPix) | (VidWinHt << ZR36057_VDCR_VidWinHt) | (VidWinWid << ZR36057_VDCR_VidWinWid); if (triton) reg &= ~ZR36057_VDCR_Triton; else reg |= ZR36057_VDCR_Triton; btwrite(reg, ZR36057_VDCR); /* Write overlay clipping mask data, but don't enable overlay clipping */ /* RJ: since this makes only sense on the screen, we use zr->window.width instead of video_width */ mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; reg = virt_to_bus(zr->overlay_mask); btwrite(reg, ZR36057_MMTR); reg = virt_to_bus(zr->overlay_mask + mask_line_size); btwrite(reg, ZR36057_MMBR); reg = mask_line_size - (zr->window.width + 31) / 32; if (DispMode == 0) reg += mask_line_size; reg <<= ZR36057_OCR_MaskStride; btwrite(reg, ZR36057_OCR);}/* * Switch overlay on or off */static void zr36057_overlay(struct zoran *zr, int on){ int fmt, bpp; u32 reg; if (on) { /* do the necessary settings ... */ btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ switch (zr->buffer.depth) { case 15: fmt = VIDEO_PALETTE_RGB555; bpp = 2; break; case 16: fmt = VIDEO_PALETTE_RGB565; bpp = 2; break; case 24: fmt = VIDEO_PALETTE_RGB24; bpp = 3; break; case 32: fmt = VIDEO_PALETTE_RGB32; bpp = 4; break; default: fmt = 0; bpp = 0; } zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); /* Start and length of each line MUST be 4-byte aligned. This should be allready checked before the call to this routine. All error messages are internal driver checking only! */ /* video display top and bottom registers */ reg = (u32) zr->buffer.base + zr->window.x * bpp + zr->window.y * zr->buffer.bytesperline; btwrite(reg, ZR36057_VDTR); if (reg & 3) printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); if (zr->video_interlace) reg += zr->buffer.bytesperline; btwrite(reg, ZR36057_VDBR); /* video stride, status, and frame grab register */ reg = zr->buffer.bytesperline - zr->window.width * bpp; if (zr->video_interlace) reg += zr->buffer.bytesperline; if (reg & 3) printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); reg = (reg << ZR36057_VSSFGR_DispStride); reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ btwrite(reg, ZR36057_VSSFGR); /* Set overlay clipping */ if (zr->window.clipcount) btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); /* ... and switch it on */ btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); } else { /* Switch it off */ btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); }}/* * The overlay mask has one bit for each pixel on a scan line, * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. */static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count){ unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; u32 *mask; int x, y, width, height; unsigned i, j, k; u32 reg; /* fill mask with one bits */ memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); reg = 0; for (i = 0; i < count; ++i) { /* pick up local copy of clip */ x = vp[i].x; y = vp[i].y; width = vp[i].width; height = vp[i].height; /* trim clips that extend beyond the window */ if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (x + width > zr->window.width) { width = zr->window.width - x; } if (y + height > zr->window.height) { height = zr->window.height - y; } /* ignore degenerate clips */ if (height <= 0) { continue; } if (width <= 0) { continue; } /* apply clip for each scan line */ for (j = 0; j < height; ++j) { /* reset bit for each pixel */ /* this can be optimized later if need be */ mask = zr->overlay_mask + (y + j) * mask_line_size; for (k = 0; k < width; ++k) { mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); } } }}/* Enable/Disable uncompressed memory grabbing of the 36057 */static void zr36057_set_memgrab(struct zoran *zr, int mode){ if (mode) { if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); /* switch on VSync interrupts */ btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); /* enable SnapShot */ btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); /* Set zr36057 video front end and enable video */#ifdef XAWTV_HACK zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat);#else zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);#endif zr->v4l_memgrab_active = 1; } else { zr->v4l_memgrab_active = 0; /* switch off VSync interrupts */ btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); /* reenable grabbing to screen if it was running */ if (zr->v4l_overlay_active) { zr36057_overlay(zr, 1); } else { btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); } }}static int wait_grab_pending(struct zoran *zr){ unsigned long flags; /* wait until all pending grabs are finished */ if (!zr->v4l_memgrab_active) return 0; while (zr->v4l_pend_tail != zr->v4l_pend_head) { interruptible_sleep_on(&zr->v4l_capq); if (signal_pending(current)) return -ERESTARTSYS; } spin_lock_irqsave(&zr->lock, flags); zr36057_set_memgrab(zr, 0); spin_unlock_irqrestore(&zr->lock, flags); return 0;}/* * V4L Buffer grabbing */static int v4l_grab(struct zoran *zr, struct video_mmap *mp){ unsigned long flags; int res, bpp; /* * There is a long list of limitations to what is allowed to be grabbed * We don't output error messages her, since some programs (e.g. xawtv) * just try several settings to find out what is valid or not. */ /* No grabbing outside the buffer range! */ if (mp->frame >= v4l_nbufs || mp->frame < 0) return -EINVAL; /* Check size and format of the grab wanted */ if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) return -EINVAL; if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) return -EINVAL; bpp = format2bpp(mp->format); if (bpp == 0) return -EINVAL; /* Check against available buffer size */ if (mp->height * mp->width * bpp > v4l_bufsize) return -EINVAL; /* The video front end needs 4-byte alinged line sizes */ if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) return -EINVAL; /* * To minimize the time spent in the IRQ routine, we avoid setting up * the video front end there. * If this grab has different parameters from a running streaming capture * we stop the streaming capture and start it over again. */ if (zr->v4l_memgrab_active && (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { res = wait_grab_pending(zr); if (res) return res; } zr->gwidth = mp->width; zr->gheight = mp->height; zr->gformat = mp->format; zr->gbpl = bpp * zr->gwidth; spin_lock_irqsave(&zr->lock, flags); /* make sure a grab isn't going on currently with this buffer */ switch (zr->v4l_gbuf[mp->frame].state) { default: case BUZ_STATE_PEND: res = -EBUSY; /* what are you doing? */ break; case BUZ_STATE_USER: case BUZ_STATE_DONE: /* since there is at least one unused buffer there's room for at least one more pend[] entry */ zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; res = 0; break; } /* put the 36057 into frame grabbing mode */ if (!res && !zr->v4l_memgrab_active) zr36057_set_memgrab(zr, 1); spin_unlock_irqrestore(&zr->lock, flags); return res;}/* * Sync on a V4L buffer */static int v4l_sync(struct zoran *zr, int frame){ unsigned long flags; /* check passed-in frame number */ if (frame >= v4l_nbufs || frame < 0) { printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); return -EINVAL; } /* Check if is buffer was queued at all */ if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); return -EINVAL; } /* wait on this buffer to get ready */ while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { interruptible_sleep_on(&zr->v4l_capq); if (signal_pending(current)) return -ERESTARTSYS; } /* buffer should now be in BUZ_STATE_DONE */ if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); /* Check if streaming capture has finished */ spin_lock_irqsave(&zr->lock, flags); if (zr->v4l_pend_tail == zr->v4l_pend_head) zr36057_set_memgrab(zr, 0); spin_unlock_irqrestore(&zr->lock, flags); return 0;}/***************************************************************************** * * * Set up the Buz-specific MJPEG part * * * *****************************************************************************//* * Wait til post office is no longer busy */ static int post_office_wait(struct zoran *zr){ u32 por; u32 ct=0; while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { ct++; if(ct>100000) { printk(KERN_ERR "%s: timeout on post office.\n", zr->name); return -1; } /* wait for something to happen */ } if ((por & ZR36057_POR_POPen) != 0) { printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); return -1; } if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); return -1; } return 0;}static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value){ u32 por; post_office_wait(zr); por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); btwrite(por, ZR36057_POR); return post_office_wait(zr);}static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg){ u32 por; post_office_wait(zr); por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); btwrite(por, ZR36057_POR); if (post_office_wait(zr) < 0) { return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -