📄 lxfb_core.c
字号:
static int __init lxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev){ struct lxfb_par *par = info->par; int ret; ret = pci_enable_device(dev); if (ret) return ret; ret = pci_request_region(dev, 0, "lxfb-framebuffer"); if (ret) return ret; ret = pci_request_region(dev, 1, "lxfb-gp"); if (ret) return ret; ret = pci_request_region(dev, 2, "lxfb-vg"); if (ret) return ret; ret = pci_request_region(dev, 3, "lxfb-vip"); if (ret) return ret; info->fix.smem_start = pci_resource_start(dev, 0); info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); ret = -ENOMEM; if (info->screen_base == NULL) return ret; par->gp_regs = ioremap(pci_resource_start(dev, 1), pci_resource_len(dev, 1)); if (par->gp_regs == NULL) return ret; par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2)); if (par->dc_regs == NULL) return ret; par->df_regs = ioremap(pci_resource_start(dev, 3), pci_resource_len(dev, 3)); if (par->df_regs == NULL) return ret; writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); writel(info->fix.smem_start & 0xFF000000, par->dc_regs + DC_PHY_MEM_OFFSET); writel(0, par->dc_regs + DC_UNLOCK); dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); return 0;}static struct fb_ops lxfb_ops = { .owner = THIS_MODULE, .fb_check_var = lxfb_check_var, .fb_set_par = lxfb_set_par, .fb_setcolreg = lxfb_setcolreg, .fb_blank = lxfb_blank, /* No HW acceleration for now. */ .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit,};static struct fb_info * __init lxfb_init_fbinfo(struct device *dev){ struct lxfb_par *par; struct fb_info *info; /* Alloc enough space for the pseudo palette. */ info = framebuffer_alloc(sizeof(struct lxfb_par) + sizeof(u32) * 16, dev); if (!info) return NULL; par = info->par; strcpy(info->fix.id, "Geode LX"); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type_aux = 0; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_NONE; info->var.nonstd = 0; info->var.activate = FB_ACTIVATE_NOW; info->var.height = -1; info->var.width = -1; info->var.accel_flags = 0; info->var.vmode = FB_VMODE_NONINTERLACED; info->fbops = &lxfb_ops; info->flags = FBINFO_DEFAULT; info->node = -1; info->pseudo_palette = (void *)par + sizeof(struct lxfb_par); info->var.grayscale = 0; return info;}static int __init lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct lxfb_par *par; struct fb_info *info; int ret; struct fb_videomode *modedb_ptr; int modedb_size; info = lxfb_init_fbinfo(&pdev->dev); if (info == NULL) return -ENOMEM; par = info->par; ret = lxfb_map_video_memory(info, pdev); if (ret < 0) { dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); goto err; } /* Set up the desired outputs */ par->output = 0; par->output |= (nopanel) ? 0 : OUTPUT_PANEL; par->output |= (nocrt) ? 0 : OUTPUT_CRT; /* Set up the mode database */ modedb_ptr = (struct fb_videomode *) geode_modedb; modedb_size = ARRAY_SIZE(geode_modedb); ret = fb_find_mode(&info->var, info, mode_option, modedb_ptr, modedb_size, NULL, 16); if (ret == 0 || ret == 4) { dev_err(&pdev->dev, "could not find valid video mode\n"); ret = -EINVAL; goto err; } /* Clear the screen of garbage, unless noclear was specified, * in which case we assume the user knows what he is doing */ if (!noclear) memset_io(info->screen_base, 0, info->fix.smem_len); /* Set the mode */ lxfb_check_var(&info->var, info); lxfb_set_par(info); if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; } pci_set_drvdata(pdev, info); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0;err: if (info->screen_base) { iounmap(info->screen_base); pci_release_region(pdev, 0); } if (par->gp_regs) { iounmap(par->gp_regs); pci_release_region(pdev, 1); } if (par->dc_regs) { iounmap(par->dc_regs); pci_release_region(pdev, 2); } if (par->df_regs) { iounmap(par->df_regs); pci_release_region(pdev, 3); } if (info) framebuffer_release(info); return ret;}static void lxfb_remove(struct pci_dev *pdev){ struct fb_info *info = pci_get_drvdata(pdev); struct lxfb_par *par = info->par; unregister_framebuffer(info); iounmap(info->screen_base); pci_release_region(pdev, 0); iounmap(par->gp_regs); pci_release_region(pdev, 1); iounmap(par->dc_regs); pci_release_region(pdev, 2); iounmap(par->df_regs); pci_release_region(pdev, 3); pci_set_drvdata(pdev, NULL); framebuffer_release(info);}static struct pci_device_id lxfb_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_VIDEO) }, { 0, }};MODULE_DEVICE_TABLE(pci, lxfb_id_table);static struct pci_driver lxfb_driver = { .name = "lxfb", .id_table = lxfb_id_table, .probe = lxfb_probe, .remove = lxfb_remove,};#ifndef MODULEstatic int __init lxfb_setup(char *options){ char *opt; if (!options || !*options) return 0; while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; if (!strncmp(opt, "fbsize:", 7)) fbsize = simple_strtoul(opt+7, NULL, 0); else if (!strcmp(opt, "noclear")) noclear = 1; else if (!strcmp(opt, "nopanel")) nopanel = 1; else if (!strcmp(opt, "nocrt")) nocrt = 1; else mode_option = opt; } return 0;}#endifstatic int __init lxfb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("lxfb", &option)) return -ENODEV; lxfb_setup(option);#endif return pci_register_driver(&lxfb_driver);}static void __exit lxfb_cleanup(void){ pci_unregister_driver(&lxfb_driver);}module_init(lxfb_init);module_exit(lxfb_cleanup);module_param(mode_option, charp, 0);MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");module_param(fbsize, int, 0);MODULE_PARM_DESC(fbsize, "video memory size");MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -