📄 acornfb.c
字号:
/* * If minimum screen size is greater than that we have * available, reject it. */ if (min_size > current_par.screen_size) return -EINVAL; /* Find int 'y', such that y * fll == s * sam < maxsize * y = s * sam / fll; s = maxsize / sam */ for (size = current_par.screen_size; min_size <= size; size -= sam_size) { nr_y = size / font_line_len; if (nr_y * font_line_len == size) break; } if (var->accel_flags & FB_ACCELF_TEXT) { if (min_size > size) { /* * failed, use ypan */ size = current_par.screen_size; var->yres_virtual = size / (font_line_len / fontht); } else var->yres_virtual = nr_y * fontht; } current_par.screen_end = current_par.screen_base_p + 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_var_screeninfo *var){ int off = (var->yoffset * var->xres_virtual * var->bits_per_pixel) >> 3;#if defined(HAS_MEMC) memc_write(VDMA_INIT, off >> 2);#elif defined(HAS_IOMD) iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);#endif}static intacornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info){ if (regno >= current_par.palette_size) return 1; acornfb_palette_decode(regno, red, green, blue, trans); return 0;}/* * 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; int bpp = fb_display[current_par.currcon].var.bits_per_pixel; if (regno >= current_par.palette_size) return 1; pal = acornfb_palette_encode(regno, red, green, blue, trans); current_par.palette[regno] = pal;#ifdef FBCON_HAS_CFB32 if (bpp == 32 && regno < 16) { current_par.cmap.cfb32[regno] = regno | regno << 8 | regno << 16; }#endif#ifdef FBCON_HAS_CFB16 if (bpp == 16 && regno < 16) { int i; current_par.cmap.cfb16[regno] = regno | regno << 5 | regno << 10; 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#endif acornfb_palette_write(regno, pal); return 0;}static intacornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; if (con == current_par.currcon) err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(current_par.palette_size), cmap, kspc ? 0 : 2); return err;}static intacornfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; if (!fb_display[con].cmap.len) err = fb_alloc_cmap(&fb_display[con].cmap, current_par.palette_size, 0); if (!err) { if (con == current_par.currcon) err = fb_set_cmap(cmap, kspc, acornfb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); } return err;}static intacornfb_decode_var(struct fb_var_screeninfo *var, int con){ int err;#if defined(HAS_VIDC20) var->red.offset = 0; var->red.length = 8; var->green = var->red; var->blue = var->red; var->transp.offset = 0; var->transp.length = 4;#elif defined(HAS_VIDC) var->red.length = 4; var->green = var->red; var->blue = var->red; var->transp.length = 1;#endif switch (var->bits_per_pixel) {#ifdef FBCON_HAS_MFB case 1: break;#endif#ifdef FBCON_HAS_CFB2 case 2: break;#endif#ifdef FBCON_HAS_CFB4 case 4: break;#endif#ifdef FBCON_HAS_CFB8 case 8: break;#endif#ifdef FBCON_HAS_CFB16 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;#endif#ifdef FBCON_HAS_CFB32 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 (!var->pixclock || !acornfb_valid_pixrate(var->pixclock)) return -EINVAL; /* * Validate and adjust the resolution to * match the video generator hardware. */ err = acornfb_adjust_timing(var, con); if (err) return err; /* * Validate the timing against the * monitor hardware. */ return acornfb_validate_timing(var, &fb_info.monspecs);}static intacornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct display *display; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "Acorn"); if (con >= 0) display = fb_display + con; else display = &global_disp; fix->smem_start = current_par.screen_base_p; fix->smem_len = current_par.screen_size; fix->type = display->type; fix->type_aux = display->type_aux; fix->xpanstep = 0; fix->ypanstep = display->ypanstep; fix->ywrapstep = display->ywrapstep; fix->visual = display->visual; fix->line_length = display->line_length; fix->accel = FB_ACCEL_NONE; return 0;}static intacornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ if (con == -1) { *var = global_disp.var; } else *var = fb_display[con].var; return 0;}static intacornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct display *display; int err, chgvar = 0; if (con >= 0) display = fb_display + con; else display = &global_disp; err = acornfb_decode_var(var, con); if (err) return err; switch (var->activate & FB_ACTIVATE_MASK) { case FB_ACTIVATE_TEST: return 0; case FB_ACTIVATE_NXTOPEN: case FB_ACTIVATE_NOW: break; default: return -EINVAL; } if (con >= 0) { if (display->var.xres != var->xres) chgvar = 1; if (display->var.yres != var->yres) chgvar = 1; if (display->var.xres_virtual != var->xres_virtual) chgvar = 1; if (display->var.yres_virtual != var->yres_virtual) chgvar = 1; if (memcmp(&display->var.red, &var->red, sizeof(var->red))) chgvar = 1; if (memcmp(&display->var.green, &var->green, sizeof(var->green))) chgvar = 1; if (memcmp(&display->var.blue, &var->blue, sizeof(var->blue))) chgvar = 1; } display->var = *var; display->var.activate &= ~FB_ACTIVATE_ALL; if (var->activate & FB_ACTIVATE_ALL) global_disp.var = display->var; switch (display->var.bits_per_pixel) {#ifdef FBCON_HAS_MFB case 1: current_par.palette_size = 2; display->dispsw = &fbcon_mfb; display->visual = FB_VISUAL_MONO10; break;#endif#ifdef FBCON_HAS_CFB2 case 2: current_par.palette_size = 4; display->dispsw = &fbcon_cfb2; display->visual = FB_VISUAL_PSEUDOCOLOR; break;#endif#ifdef FBCON_HAS_CFB4 case 4: current_par.palette_size = 16; display->dispsw = &fbcon_cfb4; display->visual = FB_VISUAL_PSEUDOCOLOR; break;#endif#ifdef FBCON_HAS_CFB8 case 8: current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb8;#ifdef HAS_VIDC display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;#else display->visual = FB_VISUAL_PSEUDOCOLOR;#endif break;#endif#ifdef FBCON_HAS_CFB16 case 16: current_par.palette_size = 32; display->dispsw = &fbcon_cfb16; display->dispsw_data = current_par.cmap.cfb16; display->visual = FB_VISUAL_DIRECTCOLOR; break;#endif#ifdef FBCON_HAS_CFB32 case 32: current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb32; display->dispsw_data = current_par.cmap.cfb32; display->visual = FB_VISUAL_TRUECOLOR; break;#endif default: display->dispsw = &fbcon_dummy; break; } display->screen_base = (char *)current_par.screen_base; display->type = FB_TYPE_PACKED_PIXELS; display->type_aux = 0; display->ypanstep = 1; display->ywrapstep = 1; display->line_length = display->next_line = (var->xres * var->bits_per_pixel) / 8; display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0; display->inverse = 0; if (chgvar && info && info->changevar) info->changevar(con); if (con == current_par.currcon) { struct fb_cmap *cmap; unsigned long start, size; int control;#if defined(HAS_MEMC) start = 0; size = current_par.screen_size - VDMA_XFERSIZE; control = 0; memc_write(VDMA_START, start); memc_write(VDMA_END, size >> 2);#elif defined(HAS_IOMD) start = current_par.screen_base_p; 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(var); acornfb_set_timing(var); if (display->cmap.len) cmap = &display->cmap; else cmap = fb_default_cmap(current_par.palette_size); fb_set_cmap(cmap, 1, acornfb_setcolreg, info); } return 0;}static intacornfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info){ u_int y_bottom; if (var->xoffset) return -EINVAL; y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) y_bottom += var->yres; if (y_bottom > fb_display[con].var.yres_virtual) return -EINVAL; acornfb_update_dma(var); fb_display[con].var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) fb_display[con].var.vmode |= FB_VMODE_YWRAP; else fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; return 0;}/* * Note that we are entered with the kernel locked. */static intacornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ unsigned long off, start; u32 len; off = vma->vm_pgoff << PAGE_SHIFT; start = current_par.screen_base_p; len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size; start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT;#ifdef CONFIG_CPU_32 pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;#endif /* * 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_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0;}static struct fb_ops acornfb_ops = { owner: THIS_MODULE, fb_get_fix: acornfb_get_fix, fb_get_var: acornfb_get_var, fb_set_var: acornfb_set_var, fb_get_cmap: acornfb_get_cmap, fb_set_cmap: acornfb_set_cmap, fb_pan_display: acornfb_pan_display, fb_mmap: acornfb_mmap,};static intacornfb_updatevar(int con, struct fb_info *info){ if (con == current_par.currcon) acornfb_update_dma(&fb_display[con].var); return 0;}static intacornfb_switch(int con, struct fb_info *info){ struct fb_cmap *cmap; if (current_par.currcon >= 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -