📄 gbefb.c
字号:
} return 0;}static void gbefb_encode_fix(struct fb_fix_screeninfo *fix, struct fb_var_screeninfo *var){ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "SGI GBE"); fix->smem_start = (unsigned long) gbe_mem; fix->smem_len = gbe_mem_size; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->accel = FB_ACCEL_NONE; switch (var->bits_per_pixel) { case 8: fix->visual = FB_VISUAL_PSEUDOCOLOR; break; default: fix->visual = FB_VISUAL_TRUECOLOR; break; } fix->ywrapstep = 0; fix->xpanstep = 0; fix->ypanstep = 0; fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; fix->mmio_start = GBE_BASE; fix->mmio_len = sizeof(struct sgi_gbe);}/* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ int i; if (regno > 255) return 1; red >>= 8; green >>= 8; blue >>= 8; switch (info->var.bits_per_pixel) { case 8: /* wait for the color map FIFO to have a free entry */ for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) udelay(10); if (i == 1000) { printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); return 1; } gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); break; case 15: case 16: red >>= 3; green >>= 3; blue >>= 3; pseudo_palette[regno] = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset); break; case 32: pseudo_palette[regno] = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset); break; } return 0;}/* * Check video mode validity, eventually modify var to best match. */static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ unsigned int line_length; struct gbe_timing_info timing; /* Limit bpp to 8, 16, and 32 */ if (var->bits_per_pixel <= 8) var->bits_per_pixel = 8; else if (var->bits_per_pixel <= 16) var->bits_per_pixel = 16; else if (var->bits_per_pixel <= 32) var->bits_per_pixel = 32; else return -EINVAL; /* Check the mode can be mapped linearly with the tile table trick. */ /* This requires width x height x bytes/pixel be a multiple of 512 */ if ((var->xres * var->yres * var->bits_per_pixel) & 4095) return -EINVAL; var->grayscale = 0; /* No grayscale for now */ if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0) return(-EINVAL); /* Adjust virtual resolution, if necessary */ if (var->xres > var->xres_virtual || (!ywrap && !ypan)) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual || (!ywrap && !ypan)) var->yres_virtual = var->yres; if (var->vmode & FB_VMODE_CONUPDATE) { var->vmode |= FB_VMODE_YWRAP; var->xoffset = info->var.xoffset; var->yoffset = info->var.yoffset; } /* No grayscale for now */ var->grayscale = 0; /* Memory limit */ line_length = var->xres_virtual * var->bits_per_pixel / 8; if (line_length * var->yres_virtual > gbe_mem_size) return -ENOMEM; /* Virtual resolution too high */ switch (var->bits_per_pixel) { case 8: var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case 16: /* RGB 1555 */ var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break; case 32: /* RGB 8888 */ var->red.offset = 24; var->red.length = 8; var->green.offset = 16; var->green.length = 8; var->blue.offset = 8; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 8; break; } var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; var->left_margin = timing.htotal - timing.hsync_end; var->right_margin = timing.hsync_start - timing.width; var->upper_margin = timing.vtotal - timing.vsync_end; var->lower_margin = timing.vsync_start - timing.height; var->hsync_len = timing.hsync_end - timing.hsync_start; var->vsync_len = timing.vsync_end - timing.vsync_start; return 0;}static int gbefb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ unsigned long size = vma->vm_end - vma->vm_start; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long addr; unsigned long phys_addr, phys_size; u16 *tile; /* check range */ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (offset + size > gbe_mem_size) return -EINVAL; /* remap using the fastest write-through mode on architecture */ /* try not polluting the cache when possible */ pgprot_val(vma->vm_page_prot) = pgprot_fb(pgprot_val(vma->vm_page_prot)); vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_file = file; /* look for the starting tile */ tile = &gbe_tiles.cpu[offset >> TILE_SHIFT]; addr = vma->vm_start; offset &= TILE_MASK; /* remap each tile separately */ do { phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset; if ((offset + size) < TILE_SIZE) phys_size = size; else phys_size = TILE_SIZE - offset; if (remap_page_range (vma, addr, phys_addr, phys_size, vma->vm_page_prot)) return -EAGAIN; offset = 0; size -= phys_size; addr += phys_size; tile++; } while (size); return 0;}static struct fb_ops gbefb_ops = { .owner = THIS_MODULE, .fb_check_var = gbefb_check_var, .fb_set_par = gbefb_set_par, .fb_setcolreg = gbefb_setcolreg, .fb_mmap = gbefb_mmap, .fb_blank = gbefb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_cursor = soft_cursor,};/* * Initialization */int __init gbefb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "monitor:", 8)) { if (!strncmp(this_opt + 8, "crt", 3)) { flat_panel_enabled = 0; default_var = &default_var_CRT; default_mode = &default_mode_CRT; } else if (!strncmp(this_opt + 8, "1600sw", 6) || !strncmp(this_opt + 8, "lcd", 3)) { flat_panel_enabled = 1; default_var = &default_var_LCD; default_mode = &default_mode_LCD; } } else if (!strncmp(this_opt, "mem:", 4)) { gbe_mem_size = memparse(this_opt + 4, &this_opt); if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024) gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024; if (gbe_mem_size < TILE_SIZE) gbe_mem_size = TILE_SIZE; } else mode_option = this_opt; } return 0;}int __init gbefb_init(void){ int i, ret = 0;#ifndef MODULE char *option = NULL; if (fb_get_options("gbefb", &option)) return -ENODEV; gbefb_setup(options);#endif if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { printk(KERN_ERR "gbefb: couldn't reserve mmio region\n"); return -EBUSY; } gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe)); if (!gbe) { printk(KERN_ERR "gbefb: couldn't map mmio region\n"); ret = -ENXIO; goto out_release_mem_region; } gbe_revision = gbe->ctrlstat & 15; gbe_tiles.cpu = dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), &gbe_tiles.dma, GFP_KERNEL); if (!gbe_tiles.cpu) { printk(KERN_ERR "gbefb: couldn't allocate tiles table\n"); ret = -ENOMEM; goto out_unmap; } if (gbe_mem_phys) { /* memory was allocated at boot time */ gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size); gbe_dma_addr = 0; } else { /* try to allocate memory with the classical allocator * this has high chance to fail on low memory machines */ gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr, GFP_KERNEL); gbe_mem_phys = (unsigned long) gbe_dma_addr; }#ifdef CONFIG_X86 mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);#endif if (!gbe_mem) { printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); ret = -ENXIO; goto out_tiles_free; } /* map framebuffer memory into tiles table */ for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++) gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i; fb_info.currcon = -1; fb_info.fbops = &gbefb_ops; fb_info.pseudo_palette = pseudo_palette; fb_info.flags = FBINFO_DEFAULT; fb_info.screen_base = gbe_mem; fb_alloc_cmap(&fb_info.cmap, 256, 0); /* reset GBE */ gbe_reset(); /* turn on default video mode */ if (fb_find_mode(&par_current.var, &fb_info, mode_option, NULL, 0, default_mode, 8) == 0) par_current.var = *default_var; fb_info.var = par_current.var; gbefb_check_var(&par_current.var, &fb_info); gbefb_encode_fix(&fb_info.fix, &fb_info.var); fb_info.par = &par_current; if (register_framebuffer(&fb_info) < 0) { ret = -ENXIO; printk(KERN_ERR "gbefb: couldn't register framebuffer\n"); goto out_gbe_unmap; } printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n", fb_info.node, fb_info.fix.id, gbe_revision, (unsigned) GBE_BASE, gbe_mem_size >> 10); return 0;out_gbe_unmap: if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); else iounmap(gbe_mem);out_tiles_free: dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma);out_unmap: iounmap(gbe);out_release_mem_region: release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); return ret;}void __exit gbefb_exit(void){ unregister_framebuffer(&fb_info); gbe_turn_off(); if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); else iounmap(gbe_mem); dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma); release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); iounmap(gbe);}module_init(gbefb_init);#ifdef MODULEmodule_exit(gbefb_exit);#endifMODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -