📄 acornfb.c
字号:
cmap = &fb_display[current_par.currcon].cmap; if (cmap->len) fb_get_cmap(cmap, 1, acornfb_getcolreg, info); } current_par.currcon = con; fb_display[con].var.activate = FB_ACTIVATE_NOW; acornfb_set_var(&fb_display[con].var, con, info); return 0;}static voidacornfb_blank(int blank, struct fb_info *info){ union palette p; int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;#ifdef FBCON_HAS_CFB16 if (bpp == 16) { p.p = 0; for (i = 0; i < 256; i++) { if (blank) p = acornfb_palette_encode(i, 0, 0, 0, 0); else { p.vidc20.red = current_par.palette[ i & 31].vidc20.red; p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; p.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; } acornfb_palette_write(i, current_par.palette[i]); } } else#endif { for (i = 0; i < current_par.palette_size; i++) { if (blank) p = acornfb_palette_encode(i, 0, 0, 0, 0); else p = current_par.palette[i]; acornfb_palette_write(i, p); } }}/* * 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, yres: 480, pixclock: 39722, left_margin: 56, right_margin: 16, upper_margin: 34, lower_margin: 9, hsync_len: 88, vsync_len: 2, sync: 0, vmode: FB_VMODE_NONINTERLACED};static void __initacornfb_init_fbinfo(void){ static int first = 1; if (!first) return; first = 0; strcpy(fb_info.modename, "Acorn"); strcpy(fb_info.fontname, "Acorn8x8"); fb_info.node = -1; fb_info.fbops = &acornfb_ops; fb_info.disp = &global_disp; fb_info.changevar = NULL; fb_info.switch_con = acornfb_switch; fb_info.updatevar = acornfb_updatevar; fb_info.blank = acornfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; global_disp.dispsw = &fbcon_dummy; /* * setup initial parameters */ memset(&init_var, 0, sizeof(init_var));#if defined(HAS_VIDC20) init_var.red.length = 8; init_var.transp.length = 4;#elif defined(HAS_VIDC) init_var.red.length = 4; init_var.transp.length = 1;#endif init_var.green = init_var.red; init_var.blue = init_var.red; init_var.nonstd = 0; init_var.activate = FB_ACTIVATE_NOW; init_var.height = -1; init_var.width = -1; init_var.vmode = FB_VMODE_NONINTERLACED; init_var.accel_flags = FB_ACCELF_TEXT; current_par.dram_size = 0; current_par.montype = -1; current_par.dpms = 0;}/* * setup acornfb options: * * font:fontname * Set fontname * * mon:hmin-hmax:vmin-vmax:dpms:width:height * Set monitor parameters: * hmin = horizontal minimum frequency (Hz) * hmax = horizontal maximum frequency (Hz) (optional) * vmin = vertical minimum frequency (Hz) * vmax = vertical maximum frequency (Hz) (optional) * dpms = DPMS supported? (optional) * width = width of picture in mm. (optional) * height = height of picture in mm. (optional) * * montype:type * Set RISC-OS style monitor type: * 0 (or tv) - TV frequency * 1 (or multi) - Multi frequency * 2 (or hires) - Hi-res monochrome * 3 (or vga) - VGA * 4 (or svga) - SVGA * auto, or option missing * - try hardware detect * * dram:size * Set the amount of DRAM to use for the frame buffer * (even if you have VRAM). * size can optionally be followed by 'M' or 'K' for * MB or KB respectively. */static void __initacornfb_parse_font(char *opt){ strcpy(fb_info.fontname, opt);}static void __initacornfb_parse_mon(char *opt){ char *p = opt; current_par.montype = -2; fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0); if (*p == '-') fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0); else fb_info.monspecs.hfmax = fb_info.monspecs.hfmin; if (*p != ':') goto bad; fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0); if (*p == '-') fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0); else fb_info.monspecs.vfmax = fb_info.monspecs.vfmin; if (*p != ':') goto check_values; fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0); if (*p != ':') goto check_values; init_var.width = simple_strtoul(p + 1, &p, 0); if (*p != ':') goto check_values; init_var.height = simple_strtoul(p + 1, NULL, 0);check_values: if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin || fb_info.monspecs.vfmax < fb_info.monspecs.vfmin) goto bad; return;bad: printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt); current_par.montype = -1;}static void __initacornfb_parse_montype(char *opt){ current_par.montype = -2; if (strncmp(opt, "tv", 2) == 0) { opt += 2; current_par.montype = 0; } else if (strncmp(opt, "multi", 5) == 0) { opt += 5; current_par.montype = 1; } else if (strncmp(opt, "hires", 5) == 0) { opt += 5; current_par.montype = 2; } else if (strncmp(opt, "vga", 3) == 0) { opt += 3; current_par.montype = 3; } else if (strncmp(opt, "svga", 4) == 0) { opt += 4; current_par.montype = 4; } else if (strncmp(opt, "auto", 4) == 0) { opt += 4; current_par.montype = -1; } else if (isdigit(*opt)) current_par.montype = simple_strtoul(opt, &opt, 0); if (current_par.montype == -2 || current_par.montype > NR_MONTYPES) { printk(KERN_ERR "acornfb: unknown monitor type: %s\n", opt); current_par.montype = -1; } else if (opt && *opt) { if (strcmp(opt, ",dpms") == 0) current_par.dpms = 1; else printk(KERN_ERR "acornfb: unknown monitor option: %s\n", opt); }}static void __initacornfb_parse_dram(char *opt){ unsigned int size; size = simple_strtoul(opt, &opt, 0); if (opt) { switch (*opt) { case 'M': case 'm': size *= 1024; case 'K': case 'k': size *= 1024; default: break; } } current_par.dram_size = size;}static struct options { char *name; void (*parse)(char *opt);} opt_table[] __initdata = { { "font", acornfb_parse_font }, { "mon", acornfb_parse_mon }, { "montype", acornfb_parse_montype }, { "dram", acornfb_parse_dram }, { NULL, NULL }};int __initacornfb_setup(char *options){ struct options *optp; char *opt; if (!options || !*options) return 0; acornfb_init_fbinfo(); while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; for (optp = opt_table; optp->name; optp++) { int optlen; optlen = strlen(optp->name); if (strncmp(opt, optp->name, optlen) == 0 && opt[optlen] == ':') { optp->parse(opt + optlen + 1); break; } } if (!optp->name) printk(KERN_ERR "acornfb: unknown parameter: %s\n", opt); } return 0;}/* * Detect type of monitor connected * For now, we just assume SVGA */static int __initacornfb_detect_monitortype(void){ return 4;}/* * This enables the unused memory to be freed on older Acorn machines. */static inline voidfree_unused_pages(unsigned int virtual_start, unsigned int virtual_end){ int mb_freed = 0; /* * Align addresses */ virtual_start = PAGE_ALIGN(virtual_start); virtual_end = PAGE_ALIGN(virtual_end); while (virtual_start < virtual_end) { struct page *page; /* * Clear page reserved bit, * set count to 1, and free * the page. */ page = virt_to_page(virtual_start); ClearPageReserved(page); atomic_set(&page->count, 1); free_page(virtual_start); virtual_start += PAGE_SIZE; mb_freed += PAGE_SIZE / 1024; } printk("acornfb: freed %dK memory\n", mb_freed);}int __initacornfb_init(void){ unsigned long size; u_int h_sync, v_sync; int rc, i; acornfb_init_fbinfo(); if (current_par.montype == -1) current_par.montype = acornfb_detect_monitortype(); if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) current_par.montype = 4; if (current_par.montype >= 0) { fb_info.monspecs = monspecs[current_par.montype]; fb_info.monspecs.dpms = current_par.dpms; } /* * Try to select a suitable default mode */ for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) { unsigned long hs; hs = modedb[i].refresh * (modedb[i].yres + modedb[i].upper_margin + modedb[i].lower_margin + modedb[i].vsync_len); if (modedb[i].xres == DEFAULT_XRES && modedb[i].yres == DEFAULT_YRES && modedb[i].refresh >= fb_info.monspecs.vfmin && modedb[i].refresh <= fb_info.monspecs.vfmax && hs >= fb_info.monspecs.hfmin && hs <= fb_info.monspecs.hfmax) { acornfb_default_mode = modedb[i]; break; } } current_par.currcon = -1; current_par.screen_base = SCREEN_BASE; current_par.screen_base_p = SCREEN_START; current_par.using_vram = 0; /* * If vram_size is set, we are using VRAM in * a Risc PC. However, if the user has specified * an amount of DRAM then use that instead. */ if (vram_size && !current_par.dram_size) { size = vram_size; current_par.vram_half_sam = vram_size / 1024; current_par.using_vram = 1; } else if (current_par.dram_size) size = current_par.dram_size; else size = MAX_SIZE; /* * Limit maximum screen size. */ if (size > MAX_SIZE) size = MAX_SIZE; size = PAGE_ALIGN(size);#if defined(HAS_VIDC20) if (!current_par.using_vram) { /* * RiscPC needs to allocate the DRAM memory * for the framebuffer if we are not using * VRAM. Archimedes/A5000 machines use a * fixed address for their framebuffers. */ int order = 0; unsigned long page, top; while (size > (PAGE_SIZE * (1 << order))) order++; current_par.screen_base = __get_free_pages(GFP_KERNEL, order); if (current_par.screen_base == 0) { printk(KERN_ERR "acornfb: unable to allocate screen " "memory\n"); return -ENOMEM; } top = current_par.screen_base + (PAGE_SIZE * (1 << order)); /* Mark the framebuffer pages as reserved so mmap will work. */ for (page = current_par.screen_base; page < PAGE_ALIGN(current_par.screen_base + size); page += PAGE_SIZE) SetPageReserved(virt_to_page(page)); /* Hand back any excess pages that we allocated. */ for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) free_page(page); current_par.screen_base_p = virt_to_phys((void *)current_par.screen_base); }#endif#if defined(HAS_VIDC) /* * Free unused pages */ free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);#endif current_par.screen_size = size; current_par.palette_size = VIDC_PALETTE_SIZE; /* * Lookup the timing for this resolution. If we can't * find it, then we can't restore it if we change * the resolution, so we disable this feature. */ do { rc = fb_find_mode(&init_var, &fb_info, NULL, modedb, sizeof(modedb) / sizeof(*modedb), &acornfb_default_mode, DEFAULT_BPP); /* * If we found an exact match, all ok. */ if (rc == 1) break; rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, &acornfb_default_mode, DEFAULT_BPP); /* * If we found an exact match, all ok. */ if (rc == 1) break; rc = fb_find_mode(&init_var, &fb_info, NULL, modedb, sizeof(modedb) / sizeof(*modedb), &acornfb_default_mode, DEFAULT_BPP); if (rc) break; rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, &acornfb_default_mode, DEFAULT_BPP); } while (0); /* * If we didn't find an exact match, try the * generic database. */ if (rc == 0) { printk("Acornfb: no valid mode found\n"); return -EINVAL; } h_sync = 1953125000 / init_var.pixclock; h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin + init_var.right_margin + init_var.hsync_len); v_sync = h_sync / (init_var.yres + init_var.upper_margin + init_var.lower_margin + init_var.vsync_len); printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, " "%d.%03dkHz, %dHz\n", current_par.screen_size / 1024, current_par.using_vram ? 'V' : 'D', VIDC_NAME, init_var.xres, init_var.yres, h_sync / 1000, h_sync % 1000, v_sync); printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n", fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000, fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000, fb_info.monspecs.vfmin, fb_info.monspecs.vfmax, fb_info.monspecs.dpms ? ", DPMS" : ""); if (acornfb_set_var(&init_var, -1, &fb_info)) printk(KERN_ERR "Acornfb: unable to set display parameters\n"); if (register_framebuffer(&fb_info) < 0) return -EINVAL; return 0;}MODULE_AUTHOR("Russell King");MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -