📄 tgafb.c
字号:
dealign = depos & 7; sealign = sepos & 7; /* ??? The documentation appears to be incorrect (or very misleading) wrt how pixel shifting works in backward copy mode, i.e. when PIXELSHIFT is negative. I give up for now. Do handle the common case of co-aligned backward copies, but frob everything else back on generic code. */ if (dealign != sealign) { cfb_copyarea(info, area); return; } /* We begin the copy with the trailing pixels of the unaligned destination. */ mask_first = (1ul << dealign) - 1; left = width - dealign; /* Care for small copies. */ if (dealign > width) { mask_first ^= (1ul << (dealign - width)) - 1; left = 0; } /* Next copy full words at a time. */ n32 = left / 32; left %= 32; /* Finally copy the unaligned head of the span. */ mask_last = -1 << (32 - left); tga_regs = par->tga_regs_base; tga_fb = par->tga_fb_base; /* Set up the MODE and PIXELSHIFT registers. */ __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG); __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); wmb(); for (i = 0; i < height; ++i) { unsigned long j; void __iomem *sfb; void __iomem *dfb; sfb = tga_fb + sepos; dfb = tga_fb + depos; if (mask_first) { __raw_writel(mask_first, sfb); wmb(); __raw_writel(mask_first, dfb); wmb(); } for (j = 0; j < n32; ++j) { sfb -= 32; dfb -= 32; __raw_writel(0xffffffff, sfb); wmb(); __raw_writel(0xffffffff, dfb); wmb(); } if (mask_last) { sfb -= 32; dfb -= 32; __raw_writel(mask_last, sfb); wmb(); __raw_writel(mask_last, dfb); wmb(); } sepos += yincr; depos += yincr; } /* Reset the MODE register to normal. */ __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);}static voidtgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { unsigned long dx, dy, width, height, sx, sy, vxres, vyres; unsigned long line_length, bpp; dx = area->dx; dy = area->dy; width = area->width; height = area->height; sx = area->sx; sy = area->sy; vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; line_length = info->fix.line_length; /* The top left corners must be in the virtual screen. */ if (dx > vxres || sx > vxres || dy > vyres || sy > vyres) return; /* Clip the destination. */ if (dx + width > vxres) width = vxres - dx; if (dy + height > vyres) height = vyres - dy; /* The source must be completely inside the virtual screen. */ if (sx + width > vxres || sy + height > vyres) return; bpp = info->var.bits_per_pixel; /* Detect copies of the entire line. */ if (width * (bpp >> 3) == line_length) { if (bpp == 8) copyarea_line_8bpp(info, dy, sy, height, width); else copyarea_line_32bpp(info, dy, sy, height, width); } /* ??? The documentation is unclear to me exactly how the pixelshift register works in 32bpp mode. Since I don't have hardware to test, give up for now and fall back on the generic routines. */ else if (bpp == 32) cfb_copyarea(info, area); /* Detect overlapping source and destination that requires a backward copy. */ else if (dy == sy && dx > sx && dx < sx + width) copyarea_backward_8bpp(info, dx, dy, sx, sy, height, width, line_length, area); else copyarea_foreward_8bpp(info, dx, dy, sx, sy, height, width, line_length);}/* * Initialisation */static voidtgafb_init_fix(struct fb_info *info){ struct tga_par *par = (struct tga_par *)info->par; int tga_bus_pci = TGA_BUS_PCI(par->dev); int tga_bus_tc = TGA_BUS_TC(par->dev); u8 tga_type = par->tga_type; const char *tga_type_name = NULL; switch (tga_type) { case TGA_TYPE_8PLANE: if (tga_bus_pci) tga_type_name = "Digital ZLXp-E1"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E1"; break; case TGA_TYPE_24PLANE: if (tga_bus_pci) tga_type_name = "Digital ZLXp-E2"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E2"; break; case TGA_TYPE_24PLUSZ: if (tga_bus_pci) tga_type_name = "Digital ZLXp-E3"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E3"; break; default: tga_type_name = "Unknown"; break; } strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type_aux = 0; info->fix.visual = (tga_type == TGA_TYPE_8PLANE ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR); info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); info->fix.smem_start = (size_t) par->tga_fb_base; info->fix.smem_len = info->fix.line_length * par->yres; info->fix.mmio_start = (size_t) par->tga_regs_base; info->fix.mmio_len = 512; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_DEC_TGA; /* * These are needed by fb_set_logo_truepalette(), so we * set them here for 24-plane cards. */ if (tga_type != TGA_TYPE_8PLANE) { info->var.red.length = 8; info->var.green.length = 8; info->var.blue.length = 8; info->var.red.offset = 16; info->var.green.offset = 8; info->var.blue.offset = 0; }}static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ /* We just use this to catch switches out of graphics mode. */ tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */ return 0;}static int __devinittgafb_register(struct device *dev){ static const struct fb_videomode modedb_tc = { /* 1280x1024 @ 72 Hz, 76.8 kHz hsync */ "1280x1024@72", 0, 1280, 1024, 7645, 224, 28, 33, 3, 160, 3, FB_SYNC_ON_GREEN, FB_VMODE_NONINTERLACED }; static unsigned int const fb_offset_presets[4] = { TGA_8PLANE_FB_OFFSET, TGA_24PLANE_FB_OFFSET, 0xffffffff, TGA_24PLUSZ_FB_OFFSET }; const struct fb_videomode *modedb_tga = NULL; resource_size_t bar0_start = 0, bar0_len = 0; const char *mode_option_tga = NULL; int tga_bus_pci = TGA_BUS_PCI(dev); int tga_bus_tc = TGA_BUS_TC(dev); unsigned int modedbsize_tga = 0; void __iomem *mem_base; struct fb_info *info; struct tga_par *par; u8 tga_type; int ret = 0; /* Enable device in PCI config. */ if (tga_bus_pci && pci_enable_device(to_pci_dev(dev))) { printk(KERN_ERR "tgafb: Cannot enable PCI device\n"); return -ENODEV; } /* Allocate the fb and par structures. */ info = framebuffer_alloc(sizeof(struct tga_par), dev); if (!info) { printk(KERN_ERR "tgafb: Cannot allocate memory\n"); return -ENOMEM; } par = info->par; dev_set_drvdata(dev, info); /* Request the mem regions. */ ret = -ENODEV; if (tga_bus_pci) { bar0_start = pci_resource_start(to_pci_dev(dev), 0); bar0_len = pci_resource_len(to_pci_dev(dev), 0); } if (tga_bus_tc) { bar0_start = to_tc_dev(dev)->resource.start; bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1; } if (!request_mem_region (bar0_start, bar0_len, "tgafb")) { printk(KERN_ERR "tgafb: cannot reserve FB region\n"); goto err0; } /* Map the framebuffer. */ mem_base = ioremap_nocache(bar0_start, bar0_len); if (!mem_base) { printk(KERN_ERR "tgafb: Cannot map MMIO\n"); goto err1; } /* Grab info about the card. */ tga_type = (readl(mem_base) >> 12) & 0x0f; par->dev = dev; par->tga_mem_base = mem_base; par->tga_fb_base = mem_base + fb_offset_presets[tga_type]; par->tga_regs_base = mem_base + TGA_REGS_OFFSET; par->tga_type = tga_type; if (tga_bus_pci) par->tga_chip_rev = (to_pci_dev(dev))->revision; if (tga_bus_tc) par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff; /* Setup framebuffer. */ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; info->fbops = &tgafb_ops; info->screen_base = par->tga_fb_base; info->pseudo_palette = par->palette; /* This should give a reasonable default video mode. */ if (tga_bus_pci) { mode_option_tga = mode_option_pci; } if (tga_bus_tc) { mode_option_tga = mode_option_tc; modedb_tga = &modedb_tc; modedbsize_tga = 1; } ret = fb_find_mode(&info->var, info, mode_option ? mode_option : mode_option_tga, modedb_tga, modedbsize_tga, NULL, tga_type == TGA_TYPE_8PLANE ? 8 : 32); if (ret == 0 || ret == 4) { printk(KERN_ERR "tgafb: Could not find valid video mode\n"); ret = -EINVAL; goto err1; } if (fb_alloc_cmap(&info->cmap, 256, 0)) { printk(KERN_ERR "tgafb: Could not allocate color map\n"); ret = -ENOMEM; goto err1; } tgafb_set_par(info); tgafb_init_fix(info); if (register_framebuffer(info) < 0) { printk(KERN_ERR "tgafb: Could not register framebuffer\n"); ret = -EINVAL; goto err1; } if (tga_bus_pci) { pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n", par->tga_chip_rev); pr_info("tgafb: at PCI bus %d, device %d, function %d\n", to_pci_dev(dev)->bus->number, PCI_SLOT(to_pci_dev(dev)->devfn), PCI_FUNC(to_pci_dev(dev)->devfn)); } if (tga_bus_tc) pr_info("tgafb: SFB+ detected, rev=0x%02x\n", par->tga_chip_rev); pr_info("fb%d: %s frame buffer device at 0x%lx\n", info->node, info->fix.id, (long)bar0_start); return 0; err1: if (mem_base) iounmap(mem_base); release_mem_region(bar0_start, bar0_len); err0: framebuffer_release(info); return ret;}static void __devexittgafb_unregister(struct device *dev){ resource_size_t bar0_start = 0, bar0_len = 0; int tga_bus_pci = TGA_BUS_PCI(dev); int tga_bus_tc = TGA_BUS_TC(dev); struct fb_info *info = NULL; struct tga_par *par; info = dev_get_drvdata(dev); if (!info) return; par = info->par; unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); iounmap(par->tga_mem_base); if (tga_bus_pci) { bar0_start = pci_resource_start(to_pci_dev(dev), 0); bar0_len = pci_resource_len(to_pci_dev(dev), 0); } if (tga_bus_tc) { bar0_start = to_tc_dev(dev)->resource.start; bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1; } release_mem_region(bar0_start, bar0_len); framebuffer_release(info);}static void __devexittgafb_exit(void){ tc_unregister_driver(&tgafb_tc_driver); pci_unregister_driver(&tgafb_pci_driver);}#ifndef MODULEstatic int __devinittgafb_setup(char *arg){ char *this_opt; if (arg && *arg) { while ((this_opt = strsep(&arg, ","))) { if (!*this_opt) continue; if (!strncmp(this_opt, "mode:", 5)) mode_option = this_opt+5; else printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt); } } return 0;}#endif /* !MODULE */static int __devinittgafb_init(void){ int status;#ifndef MODULE char *option = NULL; if (fb_get_options("tgafb", &option)) return -ENODEV; tgafb_setup(option);#endif status = pci_register_driver(&tgafb_pci_driver); if (!status) status = tc_register_driver(&tgafb_tc_driver); return status;}/* * Modularisation */module_init(tgafb_init);module_exit(tgafb_exit);MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -