📄 tgafb.c
字号:
tgafb_imageblit(struct fb_info *info, const struct fb_image *image){ unsigned int is8bpp = info->var.bits_per_pixel == 8; /* If a mono image, regardless of FB depth, go do it. */ if (image->depth == 1) { tgafb_mono_imageblit(info, image); return; } /* For copies that aren't pixel expansion, there's little we can do better than the generic code. */ /* ??? There is a DMA write mode; I wonder if that could be made to pull the data from the image buffer... */ if (image->depth == info->var.bits_per_pixel) { cfb_imageblit(info, image); return; } /* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */ if (!is8bpp && image->depth == 8) { tgafb_clut_imageblit(info, image); return; } /* Silently return... */}/** * tgafb_fillrect - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer * @rect: structure defining the rectagle and operation. */static voidtgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect){ struct tga_par *par = (struct tga_par *) info->par; int is8bpp = info->var.bits_per_pixel == 8; u32 dx, dy, width, height, vxres, vyres, color; unsigned long pos, align, line_length, i, j; void __iomem *regs_base; void __iomem *fb_base; dx = rect->dx; dy = rect->dy; width = rect->width; height = rect->height; vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; line_length = info->fix.line_length; regs_base = par->tga_regs_base; fb_base = par->tga_fb_base; /* Crop the rectangle to the screen. */ if (dx > vxres || dy > vyres || !width || !height) return; if (dx + width > vxres) width = vxres - dx; if (dy + height > vyres) height = vyres - dy; pos = dy * line_length + dx * (is8bpp ? 1 : 4); /* ??? We could implement ROP_XOR with opaque fill mode and a RasterOp setting of GXxor, but as far as I can tell, this mode is not actually used in the kernel. Thus I am ignoring it for now. */ if (rect->rop != ROP_COPY) { cfb_fillrect(info, rect); return; } /* Expand the color value to fill 8 pixels. */ color = rect->color; if (is8bpp) { color |= color << 8; color |= color << 16; __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG); } else { if (color < 16) color = ((u32 *)info->pseudo_palette)[color]; __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR2_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR3_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR4_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR5_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR6_REG); __raw_writel(color, regs_base + TGA_BLOCK_COLOR7_REG); } /* The DATA register holds the fill mask for block fill mode. Since we're not stippling, this is all ones. */ __raw_writel(0xffffffff, regs_base + TGA_DATA_REG); /* Enable block fill mode. */ __raw_writel((is8bpp ? TGA_MODE_SBM_8BPP | TGA_MODE_BLOCK_FILL : TGA_MODE_SBM_24BPP | TGA_MODE_BLOCK_FILL), regs_base + TGA_MODE_REG); wmb(); /* We can fill 2k pixels per operation. Notice blocks that fit the width of the screen so that we can take advantage of this and fill more than one line per write. */ if (width == line_length) width *= height, height = 1; /* The write into the frame buffer must be aligned to 4 bytes, but we are allowed to encode the offset within the word in the data word written. */ align = (pos & 3) << 16; pos &= -4; if (width <= 2048) { u32 data; data = (width - 1) | align; for (i = 0; i < height; ++i) { __raw_writel(data, fb_base + pos); pos += line_length; } } else { unsigned long Bpp = (is8bpp ? 1 : 4); unsigned long nwidth = width & -2048; u32 fdata, ldata; fdata = (2048 - 1) | align; ldata = ((width & 2047) - 1) | align; for (i = 0; i < height; ++i) { for (j = 0; j < nwidth; j += 2048) __raw_writel(fdata, fb_base + pos + j*Bpp); if (j < width) __raw_writel(ldata, fb_base + pos + j*Bpp); pos += line_length; } } wmb(); /* Disable block fill mode. */ __raw_writel((is8bpp ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE), regs_base + TGA_MODE_REG);}/** * tgafb_copyarea - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Copies on area of the screen to another area. * * @info: frame buffer structure that represents a single frame buffer * @area: structure defining the source and destination. *//* Handle the special case of copying entire lines, e.g. during scrolling. We can avoid a lot of needless computation in this case. In the 8bpp case we need to use the COPY64 registers instead of mask writes into the frame buffer to achieve maximum performance. */static inline voidcopyarea_line_8bpp(struct fb_info *info, u32 dy, u32 sy, u32 height, u32 width){ struct tga_par *par = (struct tga_par *) info->par; void __iomem *tga_regs = par->tga_regs_base; unsigned long dpos, spos, i, n64; /* Set up the MODE and PIXELSHIFT registers. */ __raw_writel(TGA_MODE_SBM_8BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG); __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); wmb(); n64 = (height * width) / 64; if (sy < dy) { spos = (sy + height) * width; dpos = (dy + height) * width; for (i = 0; i < n64; ++i) { spos -= 64; dpos -= 64; __raw_writel(spos, tga_regs+TGA_COPY64_SRC); wmb(); __raw_writel(dpos, tga_regs+TGA_COPY64_DST); wmb(); } } else { spos = sy * width; dpos = dy * width; for (i = 0; i < n64; ++i) { __raw_writel(spos, tga_regs+TGA_COPY64_SRC); wmb(); __raw_writel(dpos, tga_regs+TGA_COPY64_DST); wmb(); spos += 64; dpos += 64; } } /* Reset the MODE register to normal. */ __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);}static inline voidcopyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy, u32 height, u32 width){ struct tga_par *par = (struct tga_par *) info->par; void __iomem *tga_regs = par->tga_regs_base; void __iomem *tga_fb = par->tga_fb_base; void __iomem *src; void __iomem *dst; unsigned long i, n16; /* Set up the MODE and PIXELSHIFT registers. */ __raw_writel(TGA_MODE_SBM_24BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG); __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); wmb(); n16 = (height * width) / 16; if (sy < dy) { src = tga_fb + (sy + height) * width * 4; dst = tga_fb + (dy + height) * width * 4; for (i = 0; i < n16; ++i) { src -= 64; dst -= 64; __raw_writel(0xffff, src); wmb(); __raw_writel(0xffff, dst); wmb(); } } else { src = tga_fb + sy * width * 4; dst = tga_fb + dy * width * 4; for (i = 0; i < n16; ++i) { __raw_writel(0xffff, src); wmb(); __raw_writel(0xffff, dst); wmb(); src += 64; dst += 64; } } /* Reset the MODE register to normal. */ __raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);}/* The general case of forward copy in 8bpp mode. */static inline voidcopyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, u32 height, u32 width, u32 line_length){ struct tga_par *par = (struct tga_par *) info->par; unsigned long i, copied, left; unsigned long dpos, spos, dalign, salign, yincr; u32 smask_first, dmask_first, dmask_last; int pixel_shift, need_prime, need_second; unsigned long n64, n32, xincr_first; void __iomem *tga_regs; void __iomem *tga_fb; yincr = line_length; if (dy > sy) { dy += height - 1; sy += height - 1; yincr = -yincr; } /* Compute the offsets and alignments in the frame buffer. More than anything else, these control how we do copies. */ dpos = dy * line_length + dx; spos = sy * line_length + sx; dalign = dpos & 7; salign = spos & 7; dpos &= -8; spos &= -8; /* Compute the value for the PIXELSHIFT register. This controls both non-co-aligned source and destination and copy direction. */ if (dalign >= salign) pixel_shift = dalign - salign; else pixel_shift = 8 - (salign - dalign); /* Figure out if we need an additional priming step for the residue register. */ need_prime = (salign > dalign); if (need_prime) dpos -= 8; /* Begin by copying the leading unaligned destination. Copy enough to make the next destination address 32-byte aligned. */ copied = 32 - (dalign + (dpos & 31)); if (copied == 32) copied = 0; xincr_first = (copied + 7) & -8; smask_first = dmask_first = (1ul << copied) - 1; smask_first <<= salign; dmask_first <<= dalign + need_prime*8; if (need_prime && copied > 24) copied -= 8; left = width - copied; /* Care for small copies. */ if (copied > width) { u32 t; t = (1ul << width) - 1; t <<= dalign + need_prime*8; dmask_first &= t; left = 0; } /* Attempt to use 64-byte copies. This is only possible if the source and destination are co-aligned at 64 bytes. */ n64 = need_second = 0; if ((dpos & 63) == (spos & 63) && (height == 1 || line_length % 64 == 0)) { /* We may need a 32-byte copy to ensure 64 byte alignment. */ need_second = (dpos + xincr_first) & 63; if ((need_second & 32) != need_second) printk(KERN_ERR "tgafb: need_second wrong\n"); if (left >= need_second + 64) { left -= need_second; n64 = left / 64; left %= 64; } else need_second = 0; } /* Copy trailing full 32-byte sections. This will be the main loop if the 64 byte loop can't be used. */ n32 = left / 32; left %= 32; /* Copy the trailing unaligned destination. */ dmask_last = (1ul << left) - 1; tga_regs = par->tga_regs_base; tga_fb = par->tga_fb_base; /* Set up the MODE and PIXELSHIFT registers. */ __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG); __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG); wmb(); for (i = 0; i < height; ++i) { unsigned long j; void __iomem *sfb; void __iomem *dfb; sfb = tga_fb + spos; dfb = tga_fb + dpos; if (dmask_first) { __raw_writel(smask_first, sfb); wmb(); __raw_writel(dmask_first, dfb); wmb(); sfb += xincr_first; dfb += xincr_first; } if (need_second) { __raw_writel(0xffffffff, sfb); wmb(); __raw_writel(0xffffffff, dfb); wmb(); sfb += 32; dfb += 32; } if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63)) printk(KERN_ERR "tgafb: misaligned copy64 (s:%p, d:%p)\n", sfb, dfb); for (j = 0; j < n64; ++j) { __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC); wmb(); __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST); wmb(); sfb += 64; dfb += 64; } for (j = 0; j < n32; ++j) { __raw_writel(0xffffffff, sfb); wmb(); __raw_writel(0xffffffff, dfb); wmb(); sfb += 32; dfb += 32; } if (dmask_last) { __raw_writel(0xffffffff, sfb); wmb(); __raw_writel(dmask_last, dfb); wmb(); } spos += yincr; dpos += yincr; } /* Reset the MODE register to normal. */ __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);}/* The (almost) general case of backward copy in 8bpp mode. */static inline voidcopyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, u32 height, u32 width, u32 line_length, const struct fb_copyarea *area){ struct tga_par *par = (struct tga_par *) info->par; unsigned long i, left, yincr; unsigned long depos, sepos, dealign, sealign; u32 mask_first, mask_last; unsigned long n32; void __iomem *tga_regs; void __iomem *tga_fb; yincr = line_length; if (dy > sy) { dy += height - 1; sy += height - 1; yincr = -yincr; } /* Compute the offsets and alignments in the frame buffer. More than anything else, these control how we do copies. */ depos = dy * line_length + dx + width; sepos = sy * line_length + sx + width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -