btext.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 908 行 · 第 1/3 页
C
908 行
/* * Procedures for drawing on the screen early on in the boot process. * * Benjamin Herrenschmidt <benh@kernel.crashing.org> */#include <linux/config.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/init.h>#include <linux/module.h>#include <asm/sections.h>#include <asm/prom.h>#include <asm/btext.h>#include <asm/prom.h>#include <asm/page.h>#include <asm/mmu.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/lmb.h>#include <asm/processor.h>#define NO_SCROLL#ifndef NO_SCROLLstatic void scrollscreen(void);#endifstatic void draw_byte(unsigned char c, long locX, long locY);static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);#define __force_data __attribute__((__section__(".data")))static int g_loc_X __force_data;static int g_loc_Y __force_data;static int g_max_loc_X __force_data;static int g_max_loc_Y __force_data;static int dispDeviceRowBytes __force_data;static int dispDeviceDepth __force_data;static int dispDeviceRect[4] __force_data;static unsigned char *dispDeviceBase __force_data;static unsigned char *logicalDisplayBase __force_data;unsigned long disp_BAT[2] __initdata = {0, 0};#define cmapsz (16*256)static unsigned char vga_font[cmapsz];int boot_text_mapped __force_data = 0;int force_printk_to_btext = 0;#ifdef CONFIG_PPC32/* Calc BAT values for mapping the display and store them * in disp_BAT. Those values are then used from head.S to map * the display during identify_machine() and MMU_Init() * * The display is mapped to virtual address 0xD0000000, rather * than 1:1, because some some CHRP machines put the frame buffer * in the region starting at 0xC0000000 (PAGE_OFFSET). * This mapping is temporary and will disappear as soon as the * setup done by MMU_Init() is applied. * * For now, we align the BAT and then map 8Mb on 601 and 16Mb * on other PPCs. This may cause trouble if the framebuffer * is really badly aligned, but I didn't encounter this case * yet. */void __init btext_prepare_BAT(void){ unsigned long vaddr = PAGE_OFFSET + 0x10000000; unsigned long addr; unsigned long lowbits; addr = (unsigned long)dispDeviceBase; if (!addr) { boot_text_mapped = 0; return; } if (PVR_VER(mfspr(SPRN_PVR)) != 1) { /* 603, 604, G3, G4, ... */ lowbits = addr & ~0xFF000000UL; addr &= 0xFF000000UL; disp_BAT[0] = vaddr | (BL_16M<<2) | 2; disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ lowbits = addr & ~0xFF800000UL; addr &= 0xFF800000UL; disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; disp_BAT[1] = addr | BL_8M | 0x40; } logicalDisplayBase = (void *) (vaddr + lowbits);}#endif/* This function can be used to enable the early boot text when doing * OF booting or within bootx init. It must be followed by a btext_unmap() * call before the logical address becomes unuseable */void __init btext_setup_display(int width, int height, int depth, int pitch, unsigned long address){ g_loc_X = 0; g_loc_Y = 0; g_max_loc_X = width / 8; g_max_loc_Y = height / 16; logicalDisplayBase = (unsigned char *)address; dispDeviceBase = (unsigned char *)address; dispDeviceRowBytes = pitch; dispDeviceDepth = depth; dispDeviceRect[0] = dispDeviceRect[1] = 0; dispDeviceRect[2] = width; dispDeviceRect[3] = height; boot_text_mapped = 1;}void __init btext_unmap(void){ boot_text_mapped = 0;}/* Here's a small text engine to use during early boot * or for debugging purposes * * todo: * * - build some kind of vgacon with it to enable early printk * - move to a separate file * - add a few video driver hooks to keep in sync with display * changes. */static void map_boot_text(void){ unsigned long base, offset, size; unsigned char *vbase; /* By default, we are no longer mapped */ boot_text_mapped = 0; if (dispDeviceBase == 0) return; base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; offset = ((unsigned long) dispDeviceBase) - base; size = dispDeviceRowBytes * dispDeviceRect[3] + offset + dispDeviceRect[0]; vbase = __ioremap(base, size, _PAGE_NO_CACHE); if (vbase == 0) return; logicalDisplayBase = vbase + offset; boot_text_mapped = 1;}int btext_initialize(struct device_node *np){ unsigned int width, height, depth, pitch; unsigned long address = 0; u32 *prop; prop = (u32 *)get_property(np, "width", NULL); if (prop == NULL) return -EINVAL; width = *prop; prop = (u32 *)get_property(np, "height", NULL); if (prop == NULL) return -EINVAL; height = *prop; prop = (u32 *)get_property(np, "depth", NULL); if (prop == NULL) return -EINVAL; depth = *prop; pitch = width * ((depth + 7) / 8); prop = (u32 *)get_property(np, "linebytes", NULL); if (prop) pitch = *prop; if (pitch == 1) pitch = 0x1000; prop = (u32 *)get_property(np, "address", NULL); if (prop) address = *prop; /* FIXME: Add support for PCI reg properties. Right now, only * reliable on macs */ if (address == 0) return -EINVAL; g_loc_X = 0; g_loc_Y = 0; g_max_loc_X = width / 8; g_max_loc_Y = height / 16; dispDeviceBase = (unsigned char *)address; dispDeviceRowBytes = pitch; dispDeviceDepth = depth; dispDeviceRect[0] = dispDeviceRect[1] = 0; dispDeviceRect[2] = width; dispDeviceRect[3] = height; map_boot_text(); return 0;}int __init btext_find_display(int allow_nonstdout){ char *name; struct device_node *np = NULL; int rc = -ENODEV; name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); if (name != NULL) { np = of_find_node_by_path(name); if (np != NULL) { if (strcmp(np->type, "display") != 0) { printk("boot stdout isn't a display !\n"); of_node_put(np); np = NULL; } } } if (np) rc = btext_initialize(np); if (rc == 0 || !allow_nonstdout) return rc; for (np = NULL; (np = of_find_node_by_type(np, "display"));) { if (get_property(np, "linux,opened", NULL)) { printk("trying %s ...\n", np->full_name); rc = btext_initialize(np); printk("result: %d\n", rc); } if (rc == 0) break; } return rc;}/* Calc the base address of a given point (x,y) */static unsigned char * calc_base(int x, int y){ unsigned char *base; base = logicalDisplayBase; if (base == 0) base = dispDeviceBase; base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; return base;}/* Adjust the display to a new resolution */void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch){ if (dispDeviceBase == 0) return; /* check it's the same frame buffer (within 256MB) */ if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) return; dispDeviceBase = (__u8 *) phys; dispDeviceRect[0] = 0; dispDeviceRect[1] = 0; dispDeviceRect[2] = width; dispDeviceRect[3] = height; dispDeviceDepth = depth; dispDeviceRowBytes = pitch; if (boot_text_mapped) { iounmap(logicalDisplayBase); boot_text_mapped = 0; } map_boot_text(); g_loc_X = 0; g_loc_Y = 0; g_max_loc_X = width / 8; g_max_loc_Y = height / 16;}EXPORT_SYMBOL(btext_update_display);void btext_clearscreen(void){ unsigned int *base = (unsigned int *)calc_base(0, 0); unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * (dispDeviceDepth >> 3)) >> 2; int i,j; for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) { unsigned int *ptr = base; for(j=width; j; --j) *(ptr++) = 0; base += (dispDeviceRowBytes >> 2); }}void btext_flushscreen(void){ unsigned int *base = (unsigned int *)calc_base(0, 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?