📄 acornfb.c
字号:
printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize);#endif}/* * We have to take note of the VIDC20's 16-bit palette here. * The VIDC20 looks up a 16 bit pixel as follows: * * bits 111111 * 5432109876543210 * red ++++++++ (8 bits, 7 to 0) * green ++++++++ (8 bits, 11 to 4) * blue ++++++++ (8 bits, 15 to 8) * * We use a pixel which looks like: * * bits 111111 * 5432109876543210 * red +++++ (5 bits, 4 to 0) * green +++++ (5 bits, 9 to 5) * blue +++++ (5 bits, 14 to 10) */static intacornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ union palette pal; if (regno >= current_par.palette_size) return 1; if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { u32 pseudo_val; pseudo_val = regno << info->var.red.offset; pseudo_val |= regno << info->var.green.offset; pseudo_val |= regno << info->var.blue.offset; ((u32 *)info->pseudo_palette)[regno] = pseudo_val; } pal.p = 0; pal.vidc20.red = red >> 8; pal.vidc20.green = green >> 8; pal.vidc20.blue = blue >> 8; current_par.palette[regno] = pal; if (info->var.bits_per_pixel == 16) { int i; pal.p = 0; vidc_writel(0x10000000); for (i = 0; i < 256; i += 1) { pal.vidc20.red = current_par.palette[ i & 31].vidc20.red; pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; vidc_writel(pal.p); /* Palette register pointer auto-increments */ } } else { vidc_writel(0x10000000 | regno); vidc_writel(pal.p); } return 0;}#endif/* * Before selecting the timing parameters, adjust * the resolution to fit the rules. */static intacornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht){ u_int font_line_len, sam_size, min_size, size, nr_y; /* xres must be even */ var->xres = (var->xres + 1) & ~1; /* * We don't allow xres_virtual to differ from xres */ var->xres_virtual = var->xres; var->xoffset = 0; if (current_par.using_vram) sam_size = current_par.vram_half_sam * 2; else sam_size = 16; /* * Now, find a value for yres_virtual which allows * us to do ywrap scrolling. The value of * yres_virtual must be such that the end of the * displayable frame buffer must be aligned with * the start of a font line. */ font_line_len = var->xres * var->bits_per_pixel * fontht / 8; min_size = var->xres * var->yres * var->bits_per_pixel / 8; /* * If minimum screen size is greater than that we have * available, reject it. */ if (min_size > info->fix.smem_len) return -EINVAL; /* Find int 'y', such that y * fll == s * sam < maxsize * y = s * sam / fll; s = maxsize / sam */ for (size = info->fix.smem_len; nr_y = size / font_line_len, min_size <= size; size -= sam_size) { if (nr_y * font_line_len == size) break; } nr_y *= fontht; if (var->accel_flags & FB_ACCELF_TEXT) { if (min_size > size) { /* * failed, use ypan */ size = info->fix.smem_len; var->yres_virtual = size / (font_line_len / fontht); } else var->yres_virtual = nr_y; } else if (var->yres_virtual > nr_y) var->yres_virtual = nr_y; current_par.screen_end = info->fix.smem_start + size; /* * Fix yres & yoffset if needed. */ if (var->yres > var->yres_virtual) var->yres = var->yres_virtual; if (var->vmode & FB_VMODE_YWRAP) { if (var->yoffset > var->yres_virtual) var->yoffset = var->yres_virtual; } else { if (var->yoffset + var->yres > var->yres_virtual) var->yoffset = var->yres_virtual - var->yres; } /* hsync_len must be even */ var->hsync_len = (var->hsync_len + 1) & ~1;#ifdef HAS_VIDC /* left_margin must be odd */ if ((var->left_margin & 1) == 0) { var->left_margin -= 1; var->right_margin += 1; } /* right_margin must be odd */ var->right_margin |= 1;#elif defined(HAS_VIDC20) /* left_margin must be even */ if (var->left_margin & 1) { var->left_margin += 1; var->right_margin -= 1; } /* right_margin must be even */ if (var->right_margin & 1) var->right_margin += 1;#endif if (var->vsync_len < 1) var->vsync_len = 1; return 0;}static intacornfb_validate_timing(struct fb_var_screeninfo *var, struct fb_monspecs *monspecs){ unsigned long hs, vs; /* * hs(Hz) = 10^12 / (pixclock * xtotal) * vs(Hz) = hs(Hz) / ytotal * * No need to do long long divisions or anything * like that if you factor it correctly */ hs = 1953125000 / var->pixclock; hs = hs * 512 / (var->xres + var->left_margin + var->right_margin + var->hsync_len); vs = hs / (var->yres + var->upper_margin + var->lower_margin + var->vsync_len); return (vs >= monspecs->vfmin && vs <= monspecs->vfmax && hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;}static inline voidacornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var){ u_int off = var->yoffset * info->fix.line_length;#if defined(HAS_MEMC) memc_write(VDMA_INIT, off >> 2);#elif defined(HAS_IOMD) iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT);#endif}static intacornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ u_int fontht; int err; /* * FIXME: Find the font height */ fontht = 8; var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; switch (var->bits_per_pixel) { case 1: case 2: case 4: case 8: var->red.offset = 0; var->red.length = var->bits_per_pixel; var->green = var->red; var->blue = var->red; var->transp.offset = 0; var->transp.length = 0; break;#ifdef HAS_VIDC20 case 16: var->red.offset = 0; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 10; var->blue.length = 5; var->transp.offset = 15; var->transp.length = 1; break; case 32: var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 4; break;#endif default: return -EINVAL; } /* * Check to see if the pixel rate is valid. */ if (!acornfb_valid_pixrate(var)) return -EINVAL; /* * Validate and adjust the resolution to * match the video generator hardware. */ err = acornfb_adjust_timing(info, var, fontht); if (err) return err; /* * Validate the timing against the * monitor hardware. */ return acornfb_validate_timing(var, &info->monspecs);}static int acornfb_set_par(struct fb_info *info){ switch (info->var.bits_per_pixel) { case 1: current_par.palette_size = 2; info->fix.visual = FB_VISUAL_MONO10; break; case 2: current_par.palette_size = 4; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 4: current_par.palette_size = 16; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 8: current_par.palette_size = VIDC_PALETTE_SIZE;#ifdef HAS_VIDC info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;#else info->fix.visual = FB_VISUAL_PSEUDOCOLOR;#endif break;#ifdef HAS_VIDC20 case 16: current_par.palette_size = 32; info->fix.visual = FB_VISUAL_DIRECTCOLOR; break; case 32: current_par.palette_size = VIDC_PALETTE_SIZE; info->fix.visual = FB_VISUAL_DIRECTCOLOR; break;#endif default: BUG(); } info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8;#if defined(HAS_MEMC) { unsigned long size = info->fix.smem_len - VDMA_XFERSIZE; memc_write(VDMA_START, 0); memc_write(VDMA_END, size >> 2); }#elif defined(HAS_IOMD) { unsigned long start, size; u_int control; start = info->fix.smem_start; size = current_par.screen_end; if (current_par.using_vram) { size -= current_par.vram_half_sam; control = DMA_CR_E | (current_par.vram_half_sam / 256); } else { size -= 16; control = DMA_CR_E | DMA_CR_D | 16; } iomd_writel(start, IOMD_VIDSTART); iomd_writel(size, IOMD_VIDEND); iomd_writel(control, IOMD_VIDCR); }#endif acornfb_update_dma(info, &info->var); acornfb_set_timing(info); return 0;}static intacornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ u_int y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) y_bottom += var->yres; BUG_ON(y_bottom > var->yres_virtual); acornfb_update_dma(info, var); return 0;}/* * Note that we are entered with the kernel locked. */static intacornfb_mmap(struct fb_info *info, struct vm_area_struct *vma){ unsigned long off, start; u32 len; off = vma->vm_pgoff << PAGE_SHIFT; start = info->fix.smem_start; len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT; /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO; vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* * Don't alter the page protection flags; we want to keep the area * cached for better performance. This does mean that we may miss * some updates to the screen occasionally, but process switches * should cause the caches and buffers to be flushed often enough. */ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0;}static struct fb_ops acornfb_ops = { .owner = THIS_MODULE, .fb_check_var = acornfb_check_var, .fb_set_par = acornfb_set_par, .fb_setcolreg = acornfb_setcolreg, .fb_pan_display = acornfb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_mmap = acornfb_mmap,};/* * Everything after here is initialisation!!! */static struct fb_videomode modedb[] __initdata = { { /* 320x256 @ 50Hz */ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */ NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3, 0, FB_VMODE_NONINTERLACED }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */ NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3, 0, FB_VMODE_NONINTERLACED }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */ NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3, 0, FB_VMODE_NONINTERLACED }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */ NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2, 0, FB_VMODE_NONINTERLACED }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */ NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2, 0, FB_VMODE_NONINTERLACED }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */ NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2, 0, FB_VMODE_NONINTERLACED }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */ NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */ NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2, 0, FB_VMODE_NONINTERLACED }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */ NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3, 0, FB_VMODE_NONINTERLACED }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 0, FB_VMODE_NONINTERLACED }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */ NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3, 0, FB_VMODE_NONINTERLACED }};static struct fb_videomode __initdataacornfb_default_mode = { .name = NULL, .refresh = 60, .xres = 640,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -