📄 vga16fb.c
字号:
dx = area->dx / 4; width = area->width / 4; if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) { line_ofs = info->fix.line_length - width; dest = info->screen_base + dx + area->dy * info->fix.line_length; src = info->screen_base + sx + area->sy * info->fix.line_length; while (height--) { for (x = 0; x < width; x++) { readb(src); writeb(0, dest); src++; dest++; } src += line_ofs; dest += line_ofs; } } else { line_ofs = info->fix.line_length - width; dest = info->screen_base + dx + width + (area->dy + height - 1) * info->fix.line_length; src = info->screen_base + sx + width + (area->sy + height - 1) * info->fix.line_length; while (height--) { for (x = 0; x < width; x++) { --src; --dest; readb(src); writeb(0, dest); } src -= line_ofs; dest -= line_ofs; } } setsr(oldsr); setop(oldop); setmode(oldmode); setindex(oldindex);}static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area){ u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; int x, x2, y2, old_dx, old_dy, vxres, vyres; int height, width, line_ofs; char __iomem *dst = NULL; char __iomem *src = NULL; vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; if (area->dx > vxres || area->sx > vxres || area->dy > vyres || area->sy > vyres) return; /* clip the destination */ old_dx = area->dx; old_dy = area->dy; /* * We could use hardware clipping but on many cards you get around * hardware clipping by writing to framebuffer directly. */ x2 = area->dx + area->width; y2 = area->dy + area->height; dx = area->dx > 0 ? area->dx : 0; dy = area->dy > 0 ? area->dy : 0; x2 = x2 < vxres ? x2 : vxres; y2 = y2 < vyres ? y2 : vyres; width = x2 - dx; height = y2 - dy; if (sx + dx < old_dx || sy + dy < old_dy) return; /* update sx1,sy1 */ sx += (dx - old_dx); sy += (dy - old_dy); /* the source must be completely inside the virtual screen */ if (sx + width > vxres || sy + height > vyres) return; switch (info->fix.type) { case FB_TYPE_VGA_PLANES: if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { width = width/8; height = height; line_ofs = info->fix.line_length - width; setmode(1); setop(0); setsr(0xf); if (dy < sy || (dy == sy && dx < sx)) { dst = info->screen_base + (dx/8) + dy * info->fix.line_length; src = info->screen_base + (sx/8) + sy * info->fix.line_length; while (height--) { for (x = 0; x < width; x++) { readb(src); writeb(0, dst); dst++; src++; } src += line_ofs; dst += line_ofs; } } else { dst = info->screen_base + (dx/8) + width + (dy + height - 1) * info->fix.line_length; src = info->screen_base + (sx/8) + width + (sy + height - 1) * info->fix.line_length; while (height--) { for (x = 0; x < width; x++) { dst--; src--; readb(src); writeb(0, dst); } src -= line_ofs; dst -= line_ofs; } } } else vga_8planes_copyarea(info, area); break; case FB_TYPE_PACKED_PIXELS: default: cfb_copyarea(info, area); break; }}#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \ 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}#if defined(__LITTLE_ENDIAN)static const u16 transl_l[] = TRANS_MASK_LOW;static const u16 transl_h[] = TRANS_MASK_HIGH;#elif defined(__BIG_ENDIAN)static const u16 transl_l[] = TRANS_MASK_HIGH;static const u16 transl_h[] = TRANS_MASK_LOW;#else#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"#endifstatic void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image){ char oldindex = getindex(); char oldmode = setmode(0x40); char oldop = setop(0); char oldsr = setsr(0); char oldmask = selectmask(); const char *cdat = image->data; u32 dx = image->dx; char __iomem *where; int y; dx /= 4; where = info->screen_base + dx + image->dy * info->fix.line_length; setmask(0xff); writeb(image->bg_color, where); readb(where); selectmask(); setmask(image->fg_color ^ image->bg_color); setmode(0x42); setop(0x18); for (y = 0; y < image->height; y++, where += info->fix.line_length) writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where); setmask(oldmask); setsr(oldsr); setop(oldop); setmode(oldmode); setindex(oldindex);}static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image){ char __iomem *where = info->screen_base + (image->dx/8) + image->dy * info->fix.line_length; struct vga16fb_par *par = info->par; char *cdat = (char *) image->data; char __iomem *dst; int x, y; switch (info->fix.type) { case FB_TYPE_VGA_PLANES: if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { if (par->isVGA) { setmode(2); setop(0); setsr(0xf); setcolor(image->fg_color); selectmask(); setmask(0xff); writeb(image->bg_color, where); rmb(); readb(where); /* fill latches */ setmode(3); wmb(); for (y = 0; y < image->height; y++) { dst = where; for (x = image->width/8; x--;) writeb(*cdat++, dst++); where += info->fix.line_length; } wmb(); } else { setmode(0); setop(0); setsr(0xf); setcolor(image->bg_color); selectmask(); setmask(0xff); for (y = 0; y < image->height; y++) { dst = where; for (x=image->width/8; x--;){ rmw(dst); setcolor(image->fg_color); selectmask(); if (*cdat) { setmask(*cdat++); rmw(dst++); } } where += info->fix.line_length; } } } else vga_8planes_imageblit(info, image); break; case FB_TYPE_PACKED_PIXELS: default: cfb_imageblit(info, image); break; }}static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image){ /* * Draw logo */ struct vga16fb_par *par = info->par; char __iomem *where = info->screen_base + image->dy * info->fix.line_length + image->dx/8; const char *cdat = image->data; char __iomem *dst; int x, y; switch (info->fix.type) { case FB_TYPE_VGA_PLANES: if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 && par->isVGA) { setsr(0xf); setop(0); setmode(0); for (y = 0; y < image->height; y++) { for (x = 0; x < image->width; x++) { dst = where + x/8; setcolor(*cdat); selectmask(); setmask(1 << (7 - (x % 8))); fb_readb(dst); fb_writeb(0, dst); cdat++; } where += info->fix.line_length; } } break; case FB_TYPE_PACKED_PIXELS: cfb_imageblit(info, image); break; default: break; }} static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image){ if (image->depth == 1) vga_imageblit_expand(info, image); else vga_imageblit_color(info, image);}static struct fb_ops vga16fb_ops = { .owner = THIS_MODULE, .fb_open = vga16fb_open, .fb_release = vga16fb_release, .fb_check_var = vga16fb_check_var, .fb_set_par = vga16fb_set_par, .fb_setcolreg = vga16fb_setcolreg, .fb_pan_display = vga16fb_pan_display, .fb_blank = vga16fb_blank, .fb_fillrect = vga16fb_fillrect, .fb_copyarea = vga16fb_copyarea, .fb_imageblit = vga16fb_imageblit,};#ifndef MODULEstatic int vga16fb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; } return 0;}#endifstatic int __init vga16fb_probe(struct platform_device *dev){ struct fb_info *info; struct vga16fb_par *par; int i; int ret = 0; printk(KERN_DEBUG "vga16fb: initializing\n"); info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev); if (!info) { ret = -ENOMEM; goto err_fb_alloc; } /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); if (!info->screen_base) { printk(KERN_ERR "vga16fb: unable to map device\n"); ret = -ENOMEM; goto err_ioremap; } printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); par = info->par; par->isVGA = screen_info.orig_video_isVGA; par->palette_blanked = 0; par->vesa_blanked = 0; i = par->isVGA? 6 : 2; vga16fb_defined.red.length = i; vga16fb_defined.green.length = i; vga16fb_defined.blue.length = i; /* name should not depend on EGA/VGA */ info->fbops = &vga16fb_ops; info->var = vga16fb_defined; info->fix = vga16fb_fix; /* supports rectangles with widths of multiples of 8 */ info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_YPAN; i = (info->var.bits_per_pixel == 8) ? 256 : 16; ret = fb_alloc_cmap(&info->cmap, i, 0); if (ret) { printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); ret = -ENOMEM; goto err_alloc_cmap; } if (vga16fb_check_var(&info->var, info)) { printk(KERN_ERR "vga16fb: unable to validate variable\n"); ret = -EINVAL; goto err_check_var; } vga16fb_update_fix(info); if (register_framebuffer(info) < 0) { printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); ret = -EINVAL; goto err_check_var; } printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); platform_set_drvdata(dev, info); return 0; err_check_var: fb_dealloc_cmap(&info->cmap); err_alloc_cmap: iounmap(info->screen_base); err_ioremap: framebuffer_release(info); err_fb_alloc: return ret;}static int vga16fb_remove(struct platform_device *dev){ struct fb_info *info = platform_get_drvdata(dev); if (info) { unregister_framebuffer(info); iounmap(info->screen_base); fb_dealloc_cmap(&info->cmap); /* XXX unshare VGA regions */ framebuffer_release(info); } return 0;}static struct platform_driver vga16fb_driver = { .probe = vga16fb_probe, .remove = vga16fb_remove, .driver = { .name = "vga16fb", },};static struct platform_device *vga16fb_device;static int __init vga16fb_init(void){ int ret;#ifndef MODULE char *option = NULL; if (fb_get_options("vga16fb", &option)) return -ENODEV; vga16fb_setup(option);#endif ret = platform_driver_register(&vga16fb_driver); if (!ret) { vga16fb_device = platform_device_alloc("vga16fb", 0); if (vga16fb_device) ret = platform_device_add(vga16fb_device); else ret = -ENOMEM; if (ret) { platform_device_put(vga16fb_device); platform_driver_unregister(&vga16fb_driver); } } return ret;}static void __exit vga16fb_exit(void){ platform_device_unregister(vga16fb_device); platform_driver_unregister(&vga16fb_driver);}MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");MODULE_LICENSE("GPL");module_init(vga16fb_init);module_exit(vga16fb_exit);/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -